Mapsforge themes parser united with VTM #100
This commit is contained in:
parent
40f2910991
commit
f2bf6cd6ee
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2016-2017 devemux86
|
||||
* Copyright 2016-2018 devemux86
|
||||
* Copyright 2017 Longri
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
@ -18,8 +18,6 @@ package org.oscim.android.filepicker;
|
||||
|
||||
import org.oscim.theme.ExternalRenderTheme;
|
||||
import org.oscim.theme.ThemeFile;
|
||||
import org.oscim.theme.ThemeUtils;
|
||||
import org.oscim.theme.XmlMapsforgeThemeBuilder;
|
||||
import org.oscim.theme.XmlThemeBuilder;
|
||||
import org.oscim.tiling.TileSource.OpenResult;
|
||||
import org.xml.sax.InputSource;
|
||||
@ -41,11 +39,7 @@ public final class ValidRenderTheme implements ValidFileFilter {
|
||||
|
||||
try {
|
||||
ThemeFile theme = new ExternalRenderTheme(file.getAbsolutePath());
|
||||
DefaultHandler renderThemeHandler;
|
||||
if (ThemeUtils.isMapsforgeTheme(theme))
|
||||
renderThemeHandler = new XmlMapsforgeThemeBuilder(theme);
|
||||
else
|
||||
renderThemeHandler = new XmlThemeBuilder(theme);
|
||||
DefaultHandler renderThemeHandler = new XmlThemeBuilder(theme);
|
||||
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
||||
xmlReader.setContentHandler(renderThemeHandler);
|
||||
xmlReader.parse(new InputSource(theme.getRenderThemeAsStream()));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013 Hannes Janetzek
|
||||
* Copyright 2016-2017 devemux86
|
||||
* Copyright 2016-2018 devemux86
|
||||
* Copyright 2017 Longri
|
||||
* Copyright 2017 Andrey Novikov
|
||||
*
|
||||
@ -46,11 +46,7 @@ public class ThemeLoader {
|
||||
}
|
||||
|
||||
public static IRenderTheme load(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException {
|
||||
IRenderTheme t;
|
||||
if (theme.isMapsforgeTheme())
|
||||
t = Parameters.TEXTURE_ATLAS ? XmlMapsforgeAtlasThemeBuilder.read(theme, themeCallback) : XmlMapsforgeThemeBuilder.read(theme, themeCallback);
|
||||
else
|
||||
t = Parameters.TEXTURE_ATLAS ? XmlAtlasThemeBuilder.read(theme, themeCallback) : XmlThemeBuilder.read(theme, themeCallback);
|
||||
IRenderTheme t = Parameters.TEXTURE_ATLAS ? XmlAtlasThemeBuilder.read(theme, themeCallback) : XmlThemeBuilder.read(theme, themeCallback);
|
||||
if (t != null)
|
||||
t.scaleTextSize(CanvasAdapter.getScale() * CanvasAdapter.textScale);
|
||||
return t;
|
||||
|
@ -112,7 +112,7 @@ public class XmlAtlasThemeBuilder extends XmlThemeBuilder {
|
||||
|
||||
@Override
|
||||
RenderTheme createTheme(Rule[] rules) {
|
||||
return new AtlasRenderTheme(mMapBackground, mTextScale, rules, mLevels, regionMap, atlasList);
|
||||
return new AtlasRenderTheme(mMapBackground, mTextScale, rules, mLevels, mMapsforgeTheme, regionMap, atlasList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Longri
|
||||
* Copyright 2017-2018 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
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.theme;
|
||||
|
||||
import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.backend.Platform;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class XmlMapsforgeAtlasThemeBuilder extends XmlMapsforgeThemeBuilder {
|
||||
|
||||
/**
|
||||
* @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 ThemeException if an error occurs while parsing the render theme XML.
|
||||
*/
|
||||
public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException {
|
||||
Map<Object, TextureRegion> outputMap = new HashMap<>();
|
||||
List<TextureAtlas> atlasList = new ArrayList<>();
|
||||
XmlMapsforgeAtlasThemeBuilder renderThemeHandler = new XmlMapsforgeAtlasThemeBuilder(theme, themeCallback, outputMap, atlasList);
|
||||
|
||||
try {
|
||||
new XMLReaderAdapter().parse(renderThemeHandler, theme.getRenderThemeAsStream());
|
||||
} catch (Exception e) {
|
||||
throw new ThemeException(e.getMessage());
|
||||
}
|
||||
|
||||
TextureAtlasUtils.createTextureRegions(renderThemeHandler.bitmapMap, outputMap, atlasList,
|
||||
true, CanvasAdapter.platform == Platform.IOS);
|
||||
|
||||
return replaceThemeSymbols(renderThemeHandler.mRenderTheme, outputMap);
|
||||
}
|
||||
|
||||
private static IRenderTheme replaceThemeSymbols(RenderTheme renderTheme, Map<Object, TextureRegion> regionMap) {
|
||||
SymbolBuilder<?> symbolBuilder = SymbolStyle.builder();
|
||||
for (Rule rule : renderTheme.getRules()) {
|
||||
replaceRuleSymbols(rule, regionMap, symbolBuilder);
|
||||
}
|
||||
return renderTheme;
|
||||
}
|
||||
|
||||
private static void replaceRuleSymbols(Rule rule, Map<Object, TextureRegion> regionMap, SymbolBuilder<?> b) {
|
||||
for (int i = 0, n = rule.styles.length; i < n; i++) {
|
||||
RenderStyle style = rule.styles[i];
|
||||
if (style instanceof SymbolStyle) {
|
||||
SymbolStyle symbol = (SymbolStyle) style;
|
||||
TextureRegion region = regionMap.get(symbol.hash);
|
||||
if (region != null)
|
||||
rule.styles[i] = b.set(symbol)
|
||||
.bitmap(null)
|
||||
.texture(region)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
for (Rule subRule : rule.subRules) {
|
||||
replaceRuleSymbols(subRule, regionMap, b);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<Object, TextureRegion> regionMap;
|
||||
private final List<TextureAtlas> atlasList;
|
||||
|
||||
private final Map<Object, Bitmap> bitmapMap = new HashMap<>();
|
||||
|
||||
public XmlMapsforgeAtlasThemeBuilder(ThemeFile theme,
|
||||
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
|
||||
this(theme, null, regionMap, atlasList);
|
||||
}
|
||||
|
||||
public XmlMapsforgeAtlasThemeBuilder(ThemeFile theme, ThemeCallback themeCallback,
|
||||
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
|
||||
super(theme, themeCallback);
|
||||
this.regionMap = regionMap;
|
||||
this.atlasList = atlasList;
|
||||
}
|
||||
|
||||
@Override
|
||||
RenderTheme createTheme(Rule[] rules) {
|
||||
return new AtlasRenderTheme(mMapBackground, mTextScale, rules, mLevels, true, regionMap, atlasList);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,7 @@ import org.oscim.backend.canvas.Color;
|
||||
import org.oscim.backend.canvas.Paint.Cap;
|
||||
import org.oscim.backend.canvas.Paint.FontFamily;
|
||||
import org.oscim.backend.canvas.Paint.FontStyle;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.renderer.atlas.TextureAtlas;
|
||||
import org.oscim.renderer.atlas.TextureAtlas.Rect;
|
||||
import org.oscim.renderer.atlas.TextureRegion;
|
||||
@ -50,6 +51,7 @@ import org.oscim.theme.styles.SymbolStyle;
|
||||
import org.oscim.theme.styles.SymbolStyle.SymbolBuilder;
|
||||
import org.oscim.theme.styles.TextStyle;
|
||||
import org.oscim.theme.styles.TextStyle.TextBuilder;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -73,7 +75,8 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(XmlThemeBuilder.class);
|
||||
|
||||
private static final int RENDER_THEME_VERSION = 1;
|
||||
private static final int RENDER_THEME_VERSION_MAPSFORGE = 6;
|
||||
private static final int RENDER_THEME_VERSION_VTM = 1;
|
||||
|
||||
private enum Element {
|
||||
RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS, RENDERING_STYLE
|
||||
@ -81,13 +84,16 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
|
||||
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
|
||||
private static final String ELEMENT_NAME_STYLE_MENU = "stylemenu";
|
||||
private static final String ELEMENT_NAME_MATCH = "m";
|
||||
private static final String ELEMENT_NAME_MATCH_MAPSFORGE = "rule";
|
||||
private static final String ELEMENT_NAME_MATCH_VTM = "m";
|
||||
private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
|
||||
|
||||
private static final String LINE_STYLE = "L";
|
||||
private static final String OUTLINE_STYLE = "O";
|
||||
private static final String AREA_STYLE = "A";
|
||||
|
||||
private static final int DEFAULT_PRIORITY = Integer.MAX_VALUE / 2;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
@ -155,6 +161,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
private final ThemeCallback mThemeCallback;
|
||||
RenderTheme mRenderTheme;
|
||||
|
||||
final boolean mMapsforgeTheme;
|
||||
private final float mScale, mScale2;
|
||||
|
||||
private Set<String> mCategories;
|
||||
@ -168,15 +175,21 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
public XmlThemeBuilder(ThemeFile theme, ThemeCallback themeCallback) {
|
||||
mTheme = theme;
|
||||
mThemeCallback = themeCallback;
|
||||
mMapsforgeTheme = theme.isMapsforgeTheme();
|
||||
mScale = CanvasAdapter.getScale();
|
||||
mScale2 = CanvasAdapter.getScale() * 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() {
|
||||
if (mMapsforgeTheme) {
|
||||
// Building rule for Mapsforge themes
|
||||
mRulesList.add(buildingRule());
|
||||
}
|
||||
|
||||
Rule[] rules = new Rule[mRulesList.size()];
|
||||
for (int i = 0, n = rules.length; i < n; i++)
|
||||
rules[i] = mRulesList.get(i).onComplete(null);
|
||||
rules[i] = mRulesList.get(i).onComplete(mMapsforgeTheme ? new int[1] : null);
|
||||
|
||||
mRenderTheme = createTheme(rules);
|
||||
|
||||
@ -189,14 +202,14 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
}
|
||||
|
||||
RenderTheme createTheme(Rule[] rules) {
|
||||
return new RenderTheme(mMapBackground, mTextScale, rules, mLevels);
|
||||
return new RenderTheme(mMapBackground, mTextScale, rules, mLevels, mMapsforgeTheme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
mElementStack.pop();
|
||||
|
||||
if (ELEMENT_NAME_MATCH.equals(localName)) {
|
||||
if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(localName) || ELEMENT_NAME_MATCH_VTM.equals(localName)) {
|
||||
mRuleStack.pop();
|
||||
if (mRuleStack.empty()) {
|
||||
if (isVisible(mCurrentRule)) {
|
||||
@ -234,7 +247,7 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
checkState(localName, Element.RENDER_THEME);
|
||||
createRenderTheme(localName, attributes);
|
||||
|
||||
} else if (ELEMENT_NAME_MATCH.equals(localName)) {
|
||||
} else if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(localName) || ELEMENT_NAME_MATCH_VTM.equals(localName)) {
|
||||
checkState(localName, Element.RULE);
|
||||
RuleBuilder rule = createRule(localName, attributes);
|
||||
if (!mRuleStack.empty() && isVisible(rule)) {
|
||||
@ -388,9 +401,17 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
else if ("NODE".equals(val))
|
||||
element = Rule.Element.NODE;
|
||||
} else if ("k".equals(name)) {
|
||||
keys = value;
|
||||
if (mMapsforgeTheme) {
|
||||
if (!"*".equals(value))
|
||||
keys = value;
|
||||
} else
|
||||
keys = value;
|
||||
} else if ("v".equals(name)) {
|
||||
values = value;
|
||||
if (mMapsforgeTheme) {
|
||||
if (!"*".equals(value))
|
||||
values = value;
|
||||
} else
|
||||
values = value;
|
||||
} else if ("cat".equals(name)) {
|
||||
cat = value;
|
||||
} else if ("closed".equals(name)) {
|
||||
@ -893,7 +914,8 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
|
||||
validateExists("version", version, elementName);
|
||||
|
||||
if (version > RENDER_THEME_VERSION)
|
||||
int renderThemeVersion = mMapsforgeTheme ? RENDER_THEME_VERSION_MAPSFORGE : RENDER_THEME_VERSION_VTM;
|
||||
if (version > renderThemeVersion)
|
||||
throw new ThemeException("invalid render theme version:" + version);
|
||||
|
||||
validateNonNegative("base-stroke-width", baseStrokeWidth);
|
||||
@ -944,6 +966,11 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
b.themeCallback(mThemeCallback);
|
||||
String symbol = null;
|
||||
|
||||
if (mMapsforgeTheme) {
|
||||
// Reset default priority
|
||||
b.priority = DEFAULT_PRIORITY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String name = attributes.getLocalName(i);
|
||||
String value = attributes.getValue(i);
|
||||
@ -978,10 +1005,16 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
else if ("caption".equals(name))
|
||||
b.caption = Boolean.parseBoolean(value);
|
||||
|
||||
else if ("priority".equals(name))
|
||||
else if ("priority".equals(name)) {
|
||||
b.priority = Integer.parseInt(value);
|
||||
|
||||
else if ("area-size".equals(name))
|
||||
if (mMapsforgeTheme) {
|
||||
// Mapsforge: higher priorities are drawn first (0 = default priority)
|
||||
// VTM: lower priorities are drawn first (0 = highest priority)
|
||||
b.priority = FastMath.clamp(DEFAULT_PRIORITY - b.priority, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
} else if ("area-size".equals(name))
|
||||
b.areaSize = Float.parseFloat(value);
|
||||
|
||||
else if ("dy".equals(name))
|
||||
@ -1006,7 +1039,15 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
else if ("symbol-scaling".equals(name))
|
||||
; // no-op
|
||||
|
||||
else
|
||||
else if ("position".equals(name)) {
|
||||
// Until implement position..
|
||||
if (b.dy == 0) {
|
||||
value = "above".equals(value) ? "20" : "-20";
|
||||
// NB: minus..
|
||||
b.dy = -Float.parseFloat(value) * mScale;
|
||||
}
|
||||
|
||||
} else
|
||||
logUnknownAttribute(elementName, name, value, i);
|
||||
}
|
||||
|
||||
@ -1209,4 +1250,19 @@ public class XmlThemeBuilder extends DefaultHandler {
|
||||
throw new ThemeException("missing attribute " + name
|
||||
+ " for element: " + elementName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building rule for Mapsforge themes.
|
||||
*/
|
||||
private RuleBuilder buildingRule() {
|
||||
ExtrusionBuilder<?> b = mExtrusionBuilder.reset();
|
||||
b.level(mLevels++);
|
||||
b.themeCallback(mThemeCallback);
|
||||
b.colorLine(0xffd9d8d6);
|
||||
b.colorSide(0xeaecebe9);
|
||||
b.colorTop(0xeaf9f8f6);
|
||||
RuleBuilder rule = new RuleBuilder(RuleBuilder.RuleType.POSITIVE, new String[]{Tag.KEY_BUILDING, Tag.KEY_BUILDING_PART}, new String[]{});
|
||||
rule.element(Rule.Element.WAY).zoom((byte) 17, Byte.MAX_VALUE).style(b);
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user