- reuse element Tag arrays

- use previous elements' RenderInstructions when tags and zoom match
This commit is contained in:
Hannes Janetzek 2013-02-01 01:37:46 +01:00
parent e99a4279bf
commit 8a5ec974a1
3 changed files with 145 additions and 80 deletions

View File

@ -226,6 +226,8 @@ public class MapDatabase implements IMapDatabase {
mOpenFile = true; mOpenFile = true;
initDecorder();
return OpenResult.SUCCESS; return OpenResult.SUCCESS;
} }
@ -305,7 +307,19 @@ public class MapDatabase implements IMapDatabase {
private short[] mIndices = new short[10]; private short[] mIndices = new short[10];
private Tag[] mTmpTags = new Tag[20]; 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 { private boolean decode() throws IOException {
@ -503,8 +517,13 @@ public class MapDatabase implements IMapDatabase {
if (cnt == 0) { if (cnt == 0) {
Log.d(TAG, "got no TAG!"); 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++) for (int i = 0; i < cnt; i++)
tags[i] = tmp[i]; tags[i] = tmp[i];

View File

@ -17,84 +17,73 @@ package org.oscim.theme;
import org.oscim.core.Tag; import org.oscim.core.Tag;
class MatchingCacheKey { class MatchingCacheKey {
int mHashCodeValue; int mHash;
Tag[] mTags; Tag[] mTags;
MatchingCacheKey() { MatchingCacheKey() {
} }
MatchingCacheKey(Tag[] tags) {
mTags = tags;
mHashCodeValue = calculateHashCode();
}
MatchingCacheKey(MatchingCacheKey key) { MatchingCacheKey(MatchingCacheKey key) {
mTags = key.mTags; // need to clone tags as they belong to MapDatabase
mHashCodeValue = key.mHashCodeValue; mTags = key.mTags.clone();
mHash = key.mHash;
} }
void set(Tag[] tags) { // set temporary values for comparison
mTags = tags; 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; 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++) { mHash = 31 * result;
if (mTags[i] == null) mTags = tags;
break;
result = 31 * result + mTags[i].hashCode();
}
result = 31 * result;
mHashCodeValue = result; return false;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj)
return true; return true;
}
MatchingCacheKey other = (MatchingCacheKey) obj; MatchingCacheKey other = (MatchingCacheKey) obj;
if (mTags == null) { // if (mTags == null) {
return (other.mTags == null); // return (other.mTags == null);
} else if (other.mTags == null) // } else if (other.mTags == null)
return false; // return false;
int length = mTags.length; int length = mTags.length;
if (length != other.mTags.length) { if (length != other.mTags.length)
return false; return false;
}
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
if (mTags[i] == other.mTags[i]) Tag t1 = mTags[i];
continue; Tag t2 = other.mTags[i];
if (mTags[i].key == other.mTags[i].key && mTags[i].value == other.mTags[i].value)
continue;
return false; if (!(t1 == t2 || (t1.key == t2.key && t1.value == t2.value)))
return false;
} }
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return mHashCodeValue; return mHash;
}
/**
* @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;
} }
} }

View File

@ -28,7 +28,7 @@ import android.graphics.Color;
* A RenderTheme defines how ways and nodes are drawn. * A RenderTheme defines how ways and nodes are drawn.
*/ */
public class RenderTheme { 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 MATCHING_CACHE_SIZE = 512;
private static final int RENDER_THEME_VERSION = 1; 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> mAreaInstructionList = new ArrayList<RenderInstruction>(4);
private ArrayList<RenderInstruction> mNodeInstructionList = new ArrayList<RenderInstruction>(4); private ArrayList<RenderInstruction> mNodeInstructionList = new ArrayList<RenderInstruction>(4);
private RenderInstructionItem mPrevAreaItem;
private RenderInstructionItem mPrevWayItem;
private RenderInstructionItem mPrevNodeItem;
class RenderInstructionItem { class RenderInstructionItem {
RenderInstructionItem next; RenderInstructionItem next;
int zoom; int zoom;
RenderInstruction[] list; RenderInstruction[] list;
MatchingCacheKey key;
} }
RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) { RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
@ -171,18 +176,29 @@ public class RenderTheme {
RenderInstructionItem ri = null; RenderInstructionItem ri = null;
synchronized (mNodesCache) { synchronized (mNodesCache) {
MatchingCacheKey cacheKey = mNodeCacheKey; //new MatchingCacheKey(tags);
cacheKey.set(tags);
boolean found = mNodesCache.containsKey(cacheKey);
int zoomMask = 1 << zoomLevel; int zoomMask = 1 << zoomLevel;
if (found) { MatchingCacheKey cacheKey = mNodeCacheKey;
ris = mNodesCache.get(cacheKey); 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 == null) {
if ((ri.zoom & zoomMask) != 0) boolean found = mNodesCache.containsKey(cacheKey);
// cache hit
break; 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) { if (ri == null) {
@ -234,16 +250,23 @@ public class RenderTheme {
matches.toArray(ri.list); matches.toArray(ri.list);
} }
// attach this list to the one found for MatchingKey // 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; ris.next = ri;
else } else {
mNodesCache.put(new MatchingCacheKey(cacheKey), ri); ri.key = new MatchingCacheKey(cacheKey);
mNodesCache.put(ri.key, ri);
}
} }
} }
} }
if (ri.list != null) if (ri.list != null)
render(renderCallback, ri.list, tags); render(renderCallback, ri.list, tags);
mPrevNodeItem = ri;
return ri.list; return ri.list;
} }
@ -272,32 +295,54 @@ public class RenderTheme {
// list of renderinsctruction items in cache // list of renderinsctruction items in cache
RenderInstructionItem ris = null; RenderInstructionItem ris = null;
RenderInstructionItem prevInstructions = null;
// the item matching tags and zoomlevel // the item matching tags and zoomlevel
RenderInstructionItem ri = null; RenderInstructionItem ri = null;
// temporary matching instructions list
List<RenderInstruction> matches; List<RenderInstruction> matches;
LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache; LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache;
MatchingCacheKey cacheKey; MatchingCacheKey cacheKey;
if (closed) { if (closed)
matchingCache = mAreaCache; matchingCache = mAreaCache;
cacheKey = mAreaCacheKey; else
matches = mAreaInstructionList;
} else {
matchingCache = mWayCache; matchingCache = mWayCache;
cacheKey = mWayCacheKey;
matches = mWayInstructionList;
}
int zoomMask = 1 << zoomLevel; int zoomMask = 1 << zoomLevel;
synchronized (matchingCache) { synchronized (matchingCache) {
cacheKey.set(tags); if (closed) {
ris = matchingCache.get(cacheKey); cacheKey = mAreaCacheKey;
matches = mAreaInstructionList;
prevInstructions = mPrevAreaItem;
} else {
cacheKey = mWayCacheKey;
matches = mWayInstructionList;
prevInstructions = mPrevWayItem;
}
for (ri = ris; ri != null; ri = ri.next) if (prevInstructions == null || (prevInstructions.zoom & zoomMask) == 0) {
if ((ri.zoom & zoomMask) != 0) // previous instructions zoom does not match
// cache hit cacheKey.set(tags, null);
break; } 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) { if (ri == null) {
// cache miss // cache miss
@ -341,10 +386,14 @@ public class RenderTheme {
if (ri != null) { if (ri != null) {
// we found a same matchting list on another zoomlevel // we found a same matchting list on another zoomlevel
ri.zoom |= zoomMask; ri.zoom |= zoomMask;
//Log.d(TAG, " same instructions " + size + " " + Arrays.deepToString(tags)); //Log.d(TAG,
// zoomLevel + " same instructions " + size + " "
// + Arrays.deepToString(tags));
} else { } else {
//Log.d(TAG, " new instructions " + size + " " + Arrays.deepToString(tags)); //Log.d(TAG,
// zoomLevel + " new instructions " + size + " "
// + Arrays.deepToString(tags));
ri = new RenderInstructionItem(); ri = new RenderInstructionItem();
ri.zoom = zoomMask; ri.zoom = zoomMask;
@ -356,18 +405,26 @@ public class RenderTheme {
// attach this list to the one found for MatchingKey // 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; ris.next = ri;
} } else {
else { ri.key = new MatchingCacheKey(cacheKey);
matchingCache.put(new MatchingCacheKey(cacheKey), ri); matchingCache.put(ri.key, ri);
} }
} }
} }
if (closed)
mPrevAreaItem = ri;
else
mPrevWayItem = ri;
} }
if (render && ri.list != null) { if (render && ri.list != null) {
for (int i = 0, n = ri.list.length; i < n; i++) for (int i = 0, n = ri.list.length; i < n; i++)
ri.list[i].renderWay(renderCallback, tags); ri.list[i].renderWay(renderCallback, tags);
} }
return ri.list; return ri.list;
} }