Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 Hannes Janetzek
* Copyright 2017 Longri
* Copyright 2017 devemux86
* Copyright 2018-2019 Gustl22
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.theme;
import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.theme.rule.Rule;
import org.oscim.theme.rule.Rule.Element;
import org.oscim.theme.rule.Rule.RuleVisitor;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.utils.ArrayUtils;
import org.oscim.utils.LRUCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class RenderTheme implements IRenderTheme {
static final Logger log = LoggerFactory.getLogger(RenderTheme.class);
private static final int MATCHING_CACHE_SIZE = 512;
private final float mBaseTextSize;
private final int mMapBackground;
private final int mLevels;
private final Rule[] mRules;
private final boolean mMapsforgeTheme;
private final Map mTransformBackwardKeyMap, mTransformForwardKeyMap;
private final Map mTransformBackwardTagMap, mTransformForwardTagMap;
class RenderStyleCache {
final int matchType;
final LRUCache cache;
final MatchingCacheKey cacheKey;
/* temporary matching instructions list */
final ArrayList instructionList;
RenderStyleItem prevItem;
public RenderStyleCache(int type) {
cache = new LRUCache(MATCHING_CACHE_SIZE);
instructionList = new ArrayList(4);
cacheKey = new MatchingCacheKey();
matchType = type;
}
RenderStyleItem getRenderInstructions() {
return cache.get(cacheKey);
}
}
class RenderStyleItem {
RenderStyleItem next;
int zoom;
RenderStyle[] list;
MatchingCacheKey key;
}
private final RenderStyleCache[] mStyleCache;
public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels) {
this(mapBackground, baseTextSize, rules, levels, false);
}
public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels,
Map transformKeyMap, Map transformTagMap) {
this(mapBackground, baseTextSize, rules, levels, transformKeyMap, transformTagMap, false);
}
public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels, boolean mapsforgeTheme) {
this(mapBackground, baseTextSize, rules, levels, null, null, mapsforgeTheme);
}
public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels,
Map transformKeyMap, Map transformTagMap, boolean mapsforgeTheme) {
if (rules == null)
throw new IllegalArgumentException("rules missing");
mMapBackground = mapBackground;
mBaseTextSize = baseTextSize;
mLevels = levels;
mRules = rules;
mMapsforgeTheme = mapsforgeTheme;
mTransformForwardKeyMap = transformKeyMap;
mTransformBackwardKeyMap = ArrayUtils.swap(transformKeyMap);
mTransformForwardTagMap = transformTagMap;
mTransformBackwardTagMap = ArrayUtils.swap(transformTagMap);
mStyleCache = new RenderStyleCache[3];
mStyleCache[0] = new RenderStyleCache(Element.NODE);
mStyleCache[1] = new RenderStyleCache(Element.LINE);
mStyleCache[2] = new RenderStyleCache(Element.POLY);
}
@Override
public void dispose() {
for (int i = 0; i < 3; i++)
mStyleCache[i].cache.clear();
for (Rule rule : mRules)
rule.dispose();
}
@Override
public int getLevels() {
return mLevels;
}
@Override
public int getMapBackground() {
return mMapBackground;
}
Rule[] getRules() {
return mRules;
}
@Override
public boolean isMapsforgeTheme() {
return mMapsforgeTheme;
}
//AtomicInteger hitCount = new AtomicInteger(0);
//AtomicInteger missCount = new AtomicInteger(0);
//AtomicInteger sameCount = new AtomicInteger(0);
@Override
public RenderStyle[] matchElement(GeometryType geometryType, TagSet tags, int zoomLevel) {
/* list of items in cache */
RenderStyleItem ris = null;
/* the item matching tags and zoomlevel */
RenderStyleItem ri = null;
int type = geometryType.nativeInt;
if (type < 1 || type > 3) {
log.debug("invalid geometry type for RenderTheme " + geometryType.name());
return null;
}
RenderStyleCache cache = mStyleCache[type - 1];
/* NOTE: maximum zoom level supported is 32 */
int zoomMask = 1 << zoomLevel;
synchronized (cache) {
if ((cache.prevItem == null) || (cache.prevItem.zoom & zoomMask) == 0) {
/* previous instructions zoom does not match */
cache.cacheKey.set(tags, null);
} else {
/* compare if tags match previous instructions */
if (cache.cacheKey.set(tags, cache.prevItem.key)) {
ri = cache.prevItem;
//log.debug(hitCount + "/" + sameCount.incrementAndGet()
// + "/" + missCount + "same hit " + tags);
}
}
if (ri == null) {
/* get instruction for current cacheKey */
ris = cache.getRenderInstructions();
for (ri = ris; ri != null; ri = ri.next) {
if ((ri.zoom & zoomMask) != 0) {
/* cache hit */
//log.debug(hitCount.incrementAndGet()
// + "/" + sameCount + "/" + missCount
// + " cache hit " + tags);
break;
}
}
}
if (ri == null) {
/* cache miss */
//missCount.incrementAndGet();
List matches = cache.instructionList;
matches.clear();
for (Rule rule : mRules)
rule.matchElement(cache.matchType, cache.cacheKey.mTags, zoomMask, matches);
int size = matches.size();
if (size > 1) {
for (int i = 0; i < size - 1; i++) {
RenderStyle r = matches.get(i);
for (int j = i + 1; j < size; j++) {
if (matches.get(j) == r) {
log.debug("fix duplicate instruction! "
+ Arrays.deepToString(cache.cacheKey.mTags)
+ " zoom:" + zoomLevel + " "
+ r.getClass().getName());
matches.remove(j--);
size--;
}
}
}
}
/* check if same instructions are used in another level */
for (ri = ris; ri != null; ri = ri.next) {
if (size == 0) {
if (ri.list != null)
continue;
/* both matchinglists are empty */
break;
}
if (ri.list == null)
continue;
if (ri.list.length != size)
continue;
int i = 0;
for (RenderStyle r : ri.list) {
if (r != matches.get(i))
break;
i++;
}
if (i == size)
/* both matching lists contain the same items */
break;
}
if (ri != null) {
/* we found a same matchting list on another zoomlevel add
* this zoom level to the existing RenderInstructionItem. */
ri.zoom |= zoomMask;
//log.debug(zoomLevel + " same instructions " + size + " "
// + Arrays.deepToString(tags));
} else {
//log.debug(zoomLevel + " new instructions " + size + " "
// + Arrays.deepToString(tags));
ri = new RenderStyleItem();
ri.zoom = zoomMask;
if (size > 0) {
ri.list = new RenderStyle[size];
matches.toArray(ri.list);
}
/* attach this list to the one found for MatchingKey */
if (ris != null) {
ri.next = ris.next;
ri.key = ris.key;
ris.next = ri;
} else {
ri.key = new MatchingCacheKey(cache.cacheKey);
cache.cache.put(ri.key, ri);
}
}
}
cache.prevItem = ri;
}
return ri.list;
}
@Override
public void scaleTextSize(float scaleFactor) {
for (Rule rule : mRules)
rule.scaleTextSize(scaleFactor * mBaseTextSize);
}
@Override
public String transformBackwardKey(String key) {
if (mTransformBackwardKeyMap != null)
return mTransformBackwardKeyMap.get(key);
return null;
}
@Override
public String transformForwardKey(String key) {
if (mTransformForwardKeyMap != null)
return mTransformForwardKeyMap.get(key);
return null;
}
@Override
public Tag transformBackwardTag(Tag tag) {
if (mTransformBackwardTagMap != null)
return mTransformBackwardTagMap.get(tag);
return null;
}
@Override
public Tag transformForwardTag(Tag tag) {
if (mTransformForwardTagMap != null)
return mTransformForwardTagMap.get(tag);
return null;
}
@Override
public void updateStyles() {
for (Rule rule : mRules)
rule.updateStyles();
}
public void traverseRules(RuleVisitor visitor) {
for (Rule rule : mRules)
rule.apply(visitor);
}
}