@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
* Copyright 2016 devemux86
|
||||
* Copyright 2016-2017 devemux86
|
||||
* Copyright 2017 Longri
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
@@ -186,10 +186,10 @@ public abstract class CanvasAdapter {
|
||||
}
|
||||
|
||||
private static InputStream inputStreamFromFile(String relativePathPrefix, String src) throws IOException {
|
||||
File file = getFile(relativePathPrefix, src);
|
||||
File file = getAbsoluteFile(relativePathPrefix, src);
|
||||
if (!file.exists()) {
|
||||
if (src.length() > 0 && src.charAt(0) == File.separatorChar) {
|
||||
file = getFile(relativePathPrefix, src.substring(1));
|
||||
file = getAbsoluteFile(relativePathPrefix, src.substring(1));
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file = null;
|
||||
@@ -203,7 +203,7 @@ public abstract class CanvasAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static File getFile(String parentPath, String pathName) {
|
||||
public static File getAbsoluteFile(String parentPath, String pathName) {
|
||||
if (pathName.charAt(0) == File.separatorChar) {
|
||||
return new File(pathName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2017 Longri
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
@@ -20,42 +21,36 @@ import org.oscim.backend.XMLReaderAdapter;
|
||||
import org.oscim.backend.canvas.Bitmap;
|
||||
import org.oscim.renderer.atlas.TextureAtlas;
|
||||
import org.oscim.renderer.atlas.TextureRegion;
|
||||
import org.oscim.theme.IRenderTheme.ThemeException;
|
||||
import org.oscim.theme.rule.Rule;
|
||||
import org.oscim.theme.styles.RenderStyle;
|
||||
import org.oscim.theme.styles.SymbolStyle;
|
||||
import org.oscim.theme.styles.SymbolStyle.SymbolBuilder;
|
||||
import org.oscim.utils.TextureAtlasUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class XmlAtlasThemeBuilder extends XmlThemeBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(XmlAtlasThemeBuilder.class);
|
||||
|
||||
private final Map<Object, Bitmap> bitmapMap = new HashMap<>();
|
||||
private final Map<Object, TextureRegion> outputMap;
|
||||
private final List<TextureAtlas> atlasList;
|
||||
|
||||
public XmlAtlasThemeBuilder(ThemeFile theme, ThemeCallback themeCallback,
|
||||
Map<Object, TextureRegion> outputMap, List<TextureAtlas> atlasList) {
|
||||
super(theme, themeCallback);
|
||||
this.outputMap = outputMap;
|
||||
this.atlasList = atlasList;
|
||||
/**
|
||||
* @param theme an input theme containing valid render theme XML data.
|
||||
* @return a new RenderTheme which is created by parsing the XML data from the input theme.
|
||||
* @throws ThemeException if an error occurs while parsing the render theme XML.
|
||||
*/
|
||||
public static IRenderTheme read(ThemeFile theme) throws ThemeException {
|
||||
return read(theme, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theme an input theme containing valid render theme XML data.
|
||||
* @param themeCallback the theme callback.
|
||||
* @return a new RenderTheme which is created by parsing the XML data from the input theme.
|
||||
* @throws IRenderTheme.ThemeException if an error occurs while parsing the render theme XML.
|
||||
* @throws ThemeException if an error occurs while parsing the render theme XML.
|
||||
*/
|
||||
public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws IRenderTheme.ThemeException {
|
||||
public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException {
|
||||
Map<Object, TextureRegion> outputMap = new HashMap<>();
|
||||
List<TextureAtlas> atlasList = new ArrayList<>();
|
||||
XmlAtlasThemeBuilder renderThemeHandler = new XmlAtlasThemeBuilder(theme, themeCallback, outputMap, atlasList);
|
||||
@@ -63,108 +58,69 @@ public class XmlAtlasThemeBuilder extends XmlThemeBuilder {
|
||||
try {
|
||||
new XMLReaderAdapter().parse(renderThemeHandler, theme.getRenderThemeAsStream());
|
||||
} catch (Exception e) {
|
||||
throw new IRenderTheme.ThemeException(e.getMessage());
|
||||
throw new ThemeException(e.getMessage());
|
||||
}
|
||||
|
||||
TextureAtlasUtils.createTextureRegions(renderThemeHandler.bitmapMap, outputMap, atlasList,
|
||||
true, CanvasAdapter.platform == Platform.IOS);
|
||||
|
||||
return replaceSymbolStylesOnTheme(outputMap, renderThemeHandler.mRenderTheme);
|
||||
return replaceThemeSymbols(renderThemeHandler.mRenderTheme, outputMap);
|
||||
}
|
||||
|
||||
private static IRenderTheme replaceSymbolStylesOnTheme(Map<Object, TextureRegion> regionMap, RenderTheme theme) {
|
||||
SymbolStyle.SymbolBuilder<?> symbolBuilder = new SymbolStyle.SymbolBuilder();
|
||||
Rule[] rules = theme.getRules();
|
||||
for (Rule rule : rules) {
|
||||
replaceSymbolStylesOnRules(regionMap, symbolBuilder, rule);
|
||||
private static IRenderTheme replaceThemeSymbols(RenderTheme renderTheme, Map<Object, TextureRegion> regionMap) {
|
||||
SymbolBuilder<?> symbolBuilder = SymbolStyle.builder();
|
||||
for (Rule rule : renderTheme.getRules()) {
|
||||
replaceRuleSymbols(rule, regionMap, symbolBuilder);
|
||||
}
|
||||
return theme;
|
||||
return renderTheme;
|
||||
}
|
||||
|
||||
private static void replaceSymbolStylesOnRules(Map<Object, TextureRegion> regionMap,
|
||||
SymbolStyle.SymbolBuilder<?> symbolBuilder, Rule rule) {
|
||||
private static void replaceRuleSymbols(Rule rule, Map<Object, TextureRegion> regionMap, SymbolBuilder<?> symbolBuilder) {
|
||||
for (int i = 0, n = rule.styles.length; i < n; i++) {
|
||||
RenderStyle style = rule.styles[i];
|
||||
if (style instanceof SymbolStyle) {
|
||||
String sourceName = ((SymbolStyle) style).sourceName;
|
||||
|
||||
TextureRegion region = regionMap.get(sourceName);
|
||||
int hash = ((SymbolStyle) style).hash;
|
||||
TextureRegion region = regionMap.get(hash);
|
||||
if (region != null) {
|
||||
symbolBuilder = symbolBuilder.reset();
|
||||
rule.styles[i] = symbolBuilder.texture(region).build();
|
||||
SymbolBuilder<?> b = symbolBuilder.reset();
|
||||
rule.styles[i] = b.texture(region).build();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for (Rule subRule : rule.subRules) {
|
||||
replaceSymbolStylesOnRules(regionMap, symbolBuilder, subRule);
|
||||
replaceRuleSymbols(subRule, regionMap, symbolBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new Symbol with the given rendering attributes.
|
||||
*/
|
||||
protected SymbolStyle createSymbol(String elementName, Attributes attributes) {
|
||||
SymbolStyle.SymbolBuilder<?> b = mSymbolBuilder.reset();
|
||||
String src = null;
|
||||
private final Map<Object, TextureRegion> regionMap;
|
||||
private final List<TextureAtlas> atlasList;
|
||||
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String name = attributes.getLocalName(i);
|
||||
String value = attributes.getValue(i);
|
||||
private final Map<Object, Bitmap> bitmapMap = new HashMap<>();
|
||||
|
||||
if ("src".equals(name))
|
||||
src = value;
|
||||
public XmlAtlasThemeBuilder(ThemeFile theme,
|
||||
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
|
||||
this(theme, null, regionMap, atlasList);
|
||||
}
|
||||
|
||||
else if ("cat".equals(name))
|
||||
b.cat(value);
|
||||
|
||||
else if ("symbol-width".equals(name))
|
||||
b.symbolWidth = (int) (Integer.parseInt(value) * mScale);
|
||||
|
||||
else if ("symbol-height".equals(name))
|
||||
b.symbolHeight = (int) (Integer.parseInt(value) * mScale);
|
||||
|
||||
else if ("symbol-percent".equals(name))
|
||||
b.symbolPercent = Integer.parseInt(value);
|
||||
|
||||
else
|
||||
logUnknownAttribute(elementName, name, value, i);
|
||||
}
|
||||
|
||||
validateExists("src", src, elementName);
|
||||
|
||||
String lowSrc = src.toLowerCase(Locale.ENGLISH);
|
||||
if (lowSrc.endsWith(".png") || lowSrc.endsWith(".svg")) {
|
||||
try {
|
||||
Bitmap bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), src, b.symbolWidth, b.symbolHeight, b.symbolPercent);
|
||||
if (bitmap != null) {
|
||||
//create a property depends name! (needed if the same image used with different sizes)
|
||||
String sourceName = lowSrc + b.symbolWidth + "/" + b.symbolHeight + "/" + b.symbolPercent;
|
||||
bitmapMap.put(sourceName, bitmap);
|
||||
return b.sourceName(sourceName).build();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.debug(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return b.texture(getAtlasRegion(src)).build();
|
||||
public XmlAtlasThemeBuilder(ThemeFile theme, ThemeCallback themeCallback,
|
||||
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
|
||||
super(theme, themeCallback);
|
||||
this.regionMap = regionMap;
|
||||
this.atlasList = atlasList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() {
|
||||
Rule[] rules = new Rule[mRulesList.size()];
|
||||
for (int i = 0, n = rules.length; i < n; i++)
|
||||
rules[i] = mRulesList.get(i).onComplete(null);
|
||||
RenderTheme createTheme(Rule[] rules) {
|
||||
return new AtlasRenderTheme(mMapBackground, mTextScale, rules, mLevels, regionMap, atlasList);
|
||||
}
|
||||
|
||||
mRenderTheme = new AtlasRenderTheme(mMapBackground, mTextScale, rules, mLevels, this.outputMap, this.atlasList);
|
||||
|
||||
mRulesList.clear();
|
||||
mStyles.clear();
|
||||
mRuleStack.clear();
|
||||
mElementStack.clear();
|
||||
|
||||
mTextureAtlas = null;
|
||||
@Override
|
||||
SymbolStyle buildSymbol(SymbolBuilder<?> b, String src, Bitmap bitmap) {
|
||||
// we need to hash with the width/height included as the same symbol could be required
|
||||
// in a different size and must be cached with a size-specific hash
|
||||
String absoluteName = CanvasAdapter.getAbsoluteFile(mTheme.getRelativePathPrefix(), src).getAbsolutePath();
|
||||
int hash = new StringBuilder().append(absoluteName).append(b.symbolWidth).append(b.symbolHeight).append(b.symbolPercent).toString().hashCode();
|
||||
bitmapMap.put(hash, bitmap);
|
||||
return b.hash(hash).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,16 +120,16 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
* @param value the XML attribute value.
|
||||
* @param attributeIndex the XML attribute index position.
|
||||
*/
|
||||
static void logUnknownAttribute(String element, String name,
|
||||
String value, int attributeIndex) {
|
||||
private static void logUnknownAttribute(String element, String name,
|
||||
String value, int attributeIndex) {
|
||||
log.debug("unknown attribute in element {} () : {} = {}",
|
||||
element, attributeIndex, name, value);
|
||||
}
|
||||
|
||||
final ArrayList<RuleBuilder> mRulesList = new ArrayList<>();
|
||||
final Stack<Element> mElementStack = new Stack<>();
|
||||
final Stack<RuleBuilder> mRuleStack = new Stack<>();
|
||||
final HashMap<String, RenderStyle> mStyles = new HashMap<>(10);
|
||||
private final ArrayList<RuleBuilder> mRulesList = new ArrayList<>();
|
||||
private final Stack<Element> mElementStack = new Stack<>();
|
||||
private final Stack<RuleBuilder> mRuleStack = new Stack<>();
|
||||
private final HashMap<String, RenderStyle> mStyles = new HashMap<>(10);
|
||||
|
||||
private final HashMap<String, TextStyle.TextBuilder<?>> mTextStyles = new HashMap<>(10);
|
||||
|
||||
@@ -137,11 +137,11 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
private final CircleBuilder<?> mCircleBuilder = CircleStyle.builder();
|
||||
private final ExtrusionBuilder<?> mExtrusionBuilder = ExtrusionStyle.builder();
|
||||
private final LineBuilder<?> mLineBuilder = LineStyle.builder();
|
||||
final SymbolBuilder<?> mSymbolBuilder = SymbolStyle.builder();
|
||||
private final SymbolBuilder<?> mSymbolBuilder = SymbolStyle.builder();
|
||||
private final TextBuilder<?> mTextBuilder = TextStyle.builder();
|
||||
|
||||
private RuleBuilder mCurrentRule;
|
||||
TextureAtlas mTextureAtlas;
|
||||
private TextureAtlas mTextureAtlas;
|
||||
|
||||
int mLevels = 0;
|
||||
int mMapBackground = 0xffffffff;
|
||||
@@ -151,8 +151,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
private final ThemeCallback mThemeCallback;
|
||||
RenderTheme mRenderTheme;
|
||||
|
||||
final float mScale;
|
||||
private final float mScale2;
|
||||
private final float mScale, mScale2;
|
||||
|
||||
private Set<String> mCategories;
|
||||
private XmlRenderThemeStyleLayer mCurrentLayer;
|
||||
@@ -171,12 +170,11 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
|
||||
@Override
|
||||
public void endDocument() {
|
||||
|
||||
Rule[] rules = new Rule[mRulesList.size()];
|
||||
for (int i = 0, n = rules.length; i < n; i++)
|
||||
rules[i] = mRulesList.get(i).onComplete(null);
|
||||
|
||||
mRenderTheme = new RenderTheme(mMapBackground, mTextScale, rules, mLevels);
|
||||
mRenderTheme = createTheme(rules);
|
||||
|
||||
mRulesList.clear();
|
||||
mStyles.clear();
|
||||
@@ -186,6 +184,10 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
mTextureAtlas = null;
|
||||
}
|
||||
|
||||
RenderTheme createTheme(Rule[] rules) {
|
||||
return new RenderTheme(mMapBackground, mTextScale, rules, mLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
mElementStack.pop();
|
||||
@@ -425,7 +427,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
return b;
|
||||
}
|
||||
|
||||
TextureRegion getAtlasRegion(String src) {
|
||||
private TextureRegion getAtlasRegion(String src) {
|
||||
if (mTextureAtlas == null)
|
||||
return null;
|
||||
|
||||
@@ -1008,7 +1010,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
/**
|
||||
* @return a new Symbol with the given rendering attributes.
|
||||
*/
|
||||
SymbolStyle createSymbol(String elementName, Attributes attributes) {
|
||||
private SymbolStyle createSymbol(String elementName, Attributes attributes) {
|
||||
SymbolBuilder<?> b = mSymbolBuilder.reset();
|
||||
String src = null;
|
||||
|
||||
@@ -1042,7 +1044,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
try {
|
||||
Bitmap bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), src, b.symbolWidth, b.symbolHeight, b.symbolPercent);
|
||||
if (bitmap != null)
|
||||
return b.bitmap(bitmap).build();
|
||||
return buildSymbol(b, src, bitmap);
|
||||
} catch (Exception e) {
|
||||
log.debug(e.getMessage());
|
||||
}
|
||||
@@ -1051,6 +1053,10 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
return b.texture(getAtlasRegion(src)).build();
|
||||
}
|
||||
|
||||
SymbolStyle buildSymbol(SymbolBuilder<?> b, String src, Bitmap bitmap) {
|
||||
return b.bitmap(bitmap).build();
|
||||
}
|
||||
|
||||
private ExtrusionStyle createExtrusion(String elementName, Attributes attributes, int level) {
|
||||
ExtrusionBuilder<?> b = mExtrusionBuilder.reset();
|
||||
b.level(level);
|
||||
@@ -1113,7 +1119,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
+ value);
|
||||
}
|
||||
|
||||
static void validateExists(String name, Object obj, String elementName) {
|
||||
private static void validateExists(String name, Object obj, String elementName) {
|
||||
if (obj == null)
|
||||
throw new ThemeException("missing attribute " + name
|
||||
+ " for element: " + elementName);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
* Copyright 2016 devemux86
|
||||
* Copyright 2016-2017 devemux86
|
||||
* Copyright 2017 Longri
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
@@ -27,38 +27,30 @@ import org.oscim.renderer.atlas.TextureRegion;
|
||||
*/
|
||||
public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
|
||||
public final String sourceName;
|
||||
public final Bitmap bitmap;
|
||||
public final TextureRegion texture;
|
||||
public final int hash;
|
||||
|
||||
public final int symbolWidth;
|
||||
public final int symbolHeight;
|
||||
public final int symbolPercent;
|
||||
|
||||
public SymbolStyle(Bitmap bitmap) {
|
||||
this.sourceName = null;
|
||||
this.bitmap = bitmap;
|
||||
this.texture = null;
|
||||
|
||||
this.symbolWidth = 0;
|
||||
this.symbolHeight = 0;
|
||||
this.symbolPercent = 100;
|
||||
this(bitmap, null, 0);
|
||||
}
|
||||
|
||||
public SymbolStyle(TextureRegion texture) {
|
||||
this.sourceName = null;
|
||||
this.bitmap = null;
|
||||
this.texture = texture;
|
||||
|
||||
this.symbolWidth = 0;
|
||||
this.symbolHeight = 0;
|
||||
this.symbolPercent = 100;
|
||||
this(null, texture, 0);
|
||||
}
|
||||
|
||||
public SymbolStyle(String sourceName) {
|
||||
this.sourceName = sourceName;
|
||||
this.bitmap = null;
|
||||
this.texture = null;
|
||||
public SymbolStyle(int hash) {
|
||||
this(null, null, hash);
|
||||
}
|
||||
|
||||
private SymbolStyle(Bitmap bitmap, TextureRegion texture, int hash) {
|
||||
this.bitmap = bitmap;
|
||||
this.texture = texture;
|
||||
this.hash = hash;
|
||||
|
||||
this.symbolWidth = 0;
|
||||
this.symbolHeight = 0;
|
||||
@@ -66,9 +58,9 @@ public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
}
|
||||
|
||||
public SymbolStyle(SymbolBuilder<?> b) {
|
||||
this.sourceName = b.sourceName;
|
||||
this.bitmap = b.bitmap;
|
||||
this.texture = b.texture;
|
||||
this.hash = b.hash;
|
||||
|
||||
this.symbolWidth = b.symbolWidth;
|
||||
this.symbolHeight = b.symbolHeight;
|
||||
@@ -98,9 +90,9 @@ public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
|
||||
public static class SymbolBuilder<T extends SymbolBuilder<T>> extends StyleBuilder<T> {
|
||||
|
||||
public String sourceName;
|
||||
public Bitmap bitmap;
|
||||
public TextureRegion texture;
|
||||
public int hash;
|
||||
|
||||
public int symbolWidth;
|
||||
public int symbolHeight;
|
||||
@@ -115,6 +107,7 @@ public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
|
||||
this.bitmap = symbol.bitmap;
|
||||
this.texture = symbol.texture;
|
||||
this.hash = symbol.hash;
|
||||
|
||||
this.symbolWidth = symbol.symbolWidth;
|
||||
this.symbolHeight = symbol.symbolHeight;
|
||||
@@ -133,8 +126,8 @@ public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
return self();
|
||||
}
|
||||
|
||||
public T sourceName(String sourceName) {
|
||||
this.sourceName = sourceName;
|
||||
public T hash(int hash) {
|
||||
this.hash = hash;
|
||||
return self();
|
||||
}
|
||||
|
||||
@@ -156,7 +149,7 @@ public final class SymbolStyle extends RenderStyle<SymbolStyle> {
|
||||
public T reset() {
|
||||
bitmap = null;
|
||||
texture = null;
|
||||
sourceName = null;
|
||||
hash = 0;
|
||||
|
||||
symbolWidth = 0;
|
||||
symbolHeight = 0;
|
||||
|
||||
Reference in New Issue
Block a user