- 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;
|
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];
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user