- reuse element Tag arrays
- use previous elements' RenderInstructions when tags and zoom match
This commit is contained in:
parent
e99a4279bf
commit
8a5ec974a1
@ -226,6 +226,8 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
mOpenFile = true;
|
||||
|
||||
initDecorder();
|
||||
|
||||
return OpenResult.SUCCESS;
|
||||
}
|
||||
|
||||
@ -305,7 +307,19 @@ public class MapDatabase implements IMapDatabase {
|
||||
private short[] mIndices = new short[10];
|
||||
private Tag[] mTmpTags = new Tag[20];
|
||||
|
||||
private float[] mTmpCoords = new float[MAX_WAY_COORDS];
|
||||
private float[] mTmpCoords;
|
||||
|
||||
private Tag[][] mElementTags;
|
||||
|
||||
private void initDecorder() {
|
||||
// reusable tag set
|
||||
Tag[][] tags = new Tag[10][];
|
||||
for (int i = 0; i < 10; i++)
|
||||
tags[i] = new Tag[i + 1];
|
||||
mElementTags = tags;
|
||||
|
||||
mTmpCoords = new float[MAX_WAY_COORDS];
|
||||
}
|
||||
|
||||
private boolean decode() throws IOException {
|
||||
|
||||
@ -503,8 +517,13 @@ public class MapDatabase implements IMapDatabase {
|
||||
if (cnt == 0) {
|
||||
Log.d(TAG, "got no TAG!");
|
||||
}
|
||||
Tag[] tags;
|
||||
|
||||
if (cnt < 11)
|
||||
tags = mElementTags[cnt - 1];
|
||||
else
|
||||
tags = new Tag[cnt];
|
||||
|
||||
Tag[] tags = new Tag[cnt];
|
||||
for (int i = 0; i < cnt; i++)
|
||||
tags[i] = tmp[i];
|
||||
|
||||
|
@ -17,84 +17,73 @@ package org.oscim.theme;
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
class MatchingCacheKey {
|
||||
int mHashCodeValue;
|
||||
int mHash;
|
||||
Tag[] mTags;
|
||||
|
||||
MatchingCacheKey() {
|
||||
}
|
||||
|
||||
MatchingCacheKey(Tag[] tags) {
|
||||
mTags = tags;
|
||||
mHashCodeValue = calculateHashCode();
|
||||
}
|
||||
|
||||
MatchingCacheKey(MatchingCacheKey key) {
|
||||
mTags = key.mTags;
|
||||
mHashCodeValue = key.mHashCodeValue;
|
||||
// need to clone tags as they belong to MapDatabase
|
||||
mTags = key.mTags.clone();
|
||||
mHash = key.mHash;
|
||||
}
|
||||
|
||||
void set(Tag[] tags) {
|
||||
mTags = tags;
|
||||
// set temporary values for comparison
|
||||
boolean set(Tag[] tags, MatchingCacheKey compare) {
|
||||
int length = tags.length;
|
||||
|
||||
if (compare != null && length == mTags.length) {
|
||||
int i = 0;
|
||||
for (; i < length; i++) {
|
||||
Tag t1 = tags[i];
|
||||
Tag t2 = compare.mTags[i];
|
||||
|
||||
if (!(t1 == t2 || (t1.key == t2.key && t1.value == t2.value)))
|
||||
break;
|
||||
}
|
||||
if (i == length)
|
||||
return true;
|
||||
}
|
||||
|
||||
int result = 7;
|
||||
for (int i = 0; i < length; i++)
|
||||
result = 31 * result + tags[i].hashCode();
|
||||
|
||||
for (int i = 0, n = mTags.length; i < n; i++) {
|
||||
if (mTags[i] == null)
|
||||
break;
|
||||
result = 31 * result + mTags[i].hashCode();
|
||||
}
|
||||
result = 31 * result;
|
||||
mHash = 31 * result;
|
||||
mTags = tags;
|
||||
|
||||
mHashCodeValue = result;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
}
|
||||
|
||||
MatchingCacheKey other = (MatchingCacheKey) obj;
|
||||
|
||||
if (mTags == null) {
|
||||
return (other.mTags == null);
|
||||
} else if (other.mTags == null)
|
||||
return false;
|
||||
// if (mTags == null) {
|
||||
// return (other.mTags == null);
|
||||
// } else if (other.mTags == null)
|
||||
// return false;
|
||||
|
||||
int length = mTags.length;
|
||||
if (length != other.mTags.length) {
|
||||
if (length != other.mTags.length)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (mTags[i] == other.mTags[i])
|
||||
continue;
|
||||
if (mTags[i].key == other.mTags[i].key && mTags[i].value == other.mTags[i].value)
|
||||
continue;
|
||||
Tag t1 = mTags[i];
|
||||
Tag t2 = other.mTags[i];
|
||||
|
||||
return false;
|
||||
if (!(t1 == t2 || (t1.key == t2.key && t1.value == t2.value)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mHashCodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hash code of this object.
|
||||
*/
|
||||
private int calculateHashCode() {
|
||||
int result = 7;
|
||||
|
||||
for (int i = 0, n = mTags.length; i < n; i++) {
|
||||
if (mTags[i] == null) // FIXME
|
||||
break;
|
||||
result = 31 * result + mTags[i].hashCode();
|
||||
}
|
||||
result = 31 * result;
|
||||
|
||||
return result;
|
||||
return mHash;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import android.graphics.Color;
|
||||
* A RenderTheme defines how ways and nodes are drawn.
|
||||
*/
|
||||
public class RenderTheme {
|
||||
//private final static String TAG = RenderTheme.class.getName();
|
||||
private final static String TAG = RenderTheme.class.getName();
|
||||
|
||||
private static final int MATCHING_CACHE_SIZE = 512;
|
||||
private static final int RENDER_THEME_VERSION = 1;
|
||||
@ -96,10 +96,15 @@ public class RenderTheme {
|
||||
private ArrayList<RenderInstruction> mAreaInstructionList = new ArrayList<RenderInstruction>(4);
|
||||
private ArrayList<RenderInstruction> mNodeInstructionList = new ArrayList<RenderInstruction>(4);
|
||||
|
||||
private RenderInstructionItem mPrevAreaItem;
|
||||
private RenderInstructionItem mPrevWayItem;
|
||||
private RenderInstructionItem mPrevNodeItem;
|
||||
|
||||
class RenderInstructionItem {
|
||||
RenderInstructionItem next;
|
||||
int zoom;
|
||||
RenderInstruction[] list;
|
||||
MatchingCacheKey key;
|
||||
}
|
||||
|
||||
RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
|
||||
@ -171,18 +176,29 @@ public class RenderTheme {
|
||||
RenderInstructionItem ri = null;
|
||||
|
||||
synchronized (mNodesCache) {
|
||||
MatchingCacheKey cacheKey = mNodeCacheKey; //new MatchingCacheKey(tags);
|
||||
cacheKey.set(tags);
|
||||
boolean found = mNodesCache.containsKey(cacheKey);
|
||||
int zoomMask = 1 << zoomLevel;
|
||||
|
||||
if (found) {
|
||||
ris = mNodesCache.get(cacheKey);
|
||||
MatchingCacheKey cacheKey = mNodeCacheKey;
|
||||
if (mPrevNodeItem == null || (mPrevNodeItem.zoom & zoomMask) == 0) {
|
||||
// previous instructions zoom does not match
|
||||
cacheKey.set(tags, null);
|
||||
} else {
|
||||
// compare if tags match previous instructions
|
||||
if (cacheKey.set(tags, mPrevNodeItem.key))
|
||||
ri = mPrevNodeItem;
|
||||
}
|
||||
|
||||
for (ri = ris; ri != null; ri = ri.next)
|
||||
if ((ri.zoom & zoomMask) != 0)
|
||||
// cache hit
|
||||
break;
|
||||
if (ri == null) {
|
||||
boolean found = mNodesCache.containsKey(cacheKey);
|
||||
|
||||
if (found) {
|
||||
ris = mNodesCache.get(cacheKey);
|
||||
|
||||
for (ri = ris; ri != null; ri = ri.next)
|
||||
if ((ri.zoom & zoomMask) != 0)
|
||||
// cache hit
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ri == null) {
|
||||
@ -234,16 +250,23 @@ public class RenderTheme {
|
||||
matches.toArray(ri.list);
|
||||
}
|
||||
// attach this list to the one found for MatchingKey
|
||||
if (ris != null)
|
||||
if (ris != null) {
|
||||
ri.next = ris.next;
|
||||
ri.key = ris.key;
|
||||
ris.next = ri;
|
||||
else
|
||||
mNodesCache.put(new MatchingCacheKey(cacheKey), ri);
|
||||
} else {
|
||||
ri.key = new MatchingCacheKey(cacheKey);
|
||||
mNodesCache.put(ri.key, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ri.list != null)
|
||||
render(renderCallback, ri.list, tags);
|
||||
|
||||
mPrevNodeItem = ri;
|
||||
|
||||
return ri.list;
|
||||
|
||||
}
|
||||
@ -272,32 +295,54 @@ public class RenderTheme {
|
||||
// list of renderinsctruction items in cache
|
||||
RenderInstructionItem ris = null;
|
||||
|
||||
RenderInstructionItem prevInstructions = null;
|
||||
|
||||
// the item matching tags and zoomlevel
|
||||
RenderInstructionItem ri = null;
|
||||
|
||||
// temporary matching instructions list
|
||||
List<RenderInstruction> matches;
|
||||
|
||||
LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache;
|
||||
MatchingCacheKey cacheKey;
|
||||
|
||||
if (closed) {
|
||||
if (closed)
|
||||
matchingCache = mAreaCache;
|
||||
cacheKey = mAreaCacheKey;
|
||||
matches = mAreaInstructionList;
|
||||
} else {
|
||||
else
|
||||
matchingCache = mWayCache;
|
||||
cacheKey = mWayCacheKey;
|
||||
matches = mWayInstructionList;
|
||||
}
|
||||
|
||||
int zoomMask = 1 << zoomLevel;
|
||||
|
||||
synchronized (matchingCache) {
|
||||
cacheKey.set(tags);
|
||||
ris = matchingCache.get(cacheKey);
|
||||
if (closed) {
|
||||
cacheKey = mAreaCacheKey;
|
||||
matches = mAreaInstructionList;
|
||||
prevInstructions = mPrevAreaItem;
|
||||
} else {
|
||||
cacheKey = mWayCacheKey;
|
||||
matches = mWayInstructionList;
|
||||
prevInstructions = mPrevWayItem;
|
||||
}
|
||||
|
||||
for (ri = ris; ri != null; ri = ri.next)
|
||||
if ((ri.zoom & zoomMask) != 0)
|
||||
// cache hit
|
||||
break;
|
||||
if (prevInstructions == null || (prevInstructions.zoom & zoomMask) == 0) {
|
||||
// previous instructions zoom does not match
|
||||
cacheKey.set(tags, null);
|
||||
} else {
|
||||
// compare if tags match previous instructions
|
||||
if (cacheKey.set(tags, prevInstructions.key)) {
|
||||
//Log.d(TAG, "same as previous " + Arrays.deepToString(tags));
|
||||
ri = prevInstructions;
|
||||
}
|
||||
}
|
||||
|
||||
if (ri == null) {
|
||||
ris = matchingCache.get(cacheKey);
|
||||
|
||||
for (ri = ris; ri != null; ri = ri.next)
|
||||
if ((ri.zoom & zoomMask) != 0)
|
||||
// cache hit
|
||||
break;
|
||||
}
|
||||
|
||||
if (ri == null) {
|
||||
// cache miss
|
||||
@ -341,10 +386,14 @@ public class RenderTheme {
|
||||
if (ri != null) {
|
||||
// we found a same matchting list on another zoomlevel
|
||||
ri.zoom |= zoomMask;
|
||||
//Log.d(TAG, " same instructions " + size + " " + Arrays.deepToString(tags));
|
||||
//Log.d(TAG,
|
||||
// zoomLevel + " same instructions " + size + " "
|
||||
// + Arrays.deepToString(tags));
|
||||
|
||||
} else {
|
||||
//Log.d(TAG, " new instructions " + size + " " + Arrays.deepToString(tags));
|
||||
//Log.d(TAG,
|
||||
// zoomLevel + " new instructions " + size + " "
|
||||
// + Arrays.deepToString(tags));
|
||||
|
||||
ri = new RenderInstructionItem();
|
||||
ri.zoom = zoomMask;
|
||||
@ -356,18 +405,26 @@ public class RenderTheme {
|
||||
|
||||
// attach this list to the one found for MatchingKey
|
||||
if (ris != null) {
|
||||
ri.next = ris.next;
|
||||
ri.key = ris.key;
|
||||
ris.next = ri;
|
||||
}
|
||||
else {
|
||||
matchingCache.put(new MatchingCacheKey(cacheKey), ri);
|
||||
} else {
|
||||
ri.key = new MatchingCacheKey(cacheKey);
|
||||
matchingCache.put(ri.key, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closed)
|
||||
mPrevAreaItem = ri;
|
||||
else
|
||||
mPrevWayItem = ri;
|
||||
}
|
||||
|
||||
if (render && ri.list != null) {
|
||||
for (int i = 0, n = ri.list.length; i < n; i++)
|
||||
ri.list[i].renderWay(renderCallback, tags);
|
||||
}
|
||||
|
||||
return ri.list;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user