- 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;
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];

View File

@ -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;
}
}

View File

@ -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;
}