diff --git a/docs/Changelog.md b/docs/Changelog.md index fac7570f..7d126fe7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -2,6 +2,7 @@ ## New since 0.8.0 +- Mapsforge themes compatibility [#100](https://github.com/mapsforge/vtm/issues/100) - vtm-theme-comparator module [#387](https://github.com/mapsforge/vtm/issues/387) - Many other minor improvements and bug fixes - [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.9.0) diff --git a/vtm-android-example/res/menu/theme_menu.xml b/vtm-android-example/res/menu/theme_menu.xml index 319b5428..7a93959d 100644 --- a/vtm-android-example/res/menu/theme_menu.xml +++ b/vtm-android-example/res/menu/theme_menu.xml @@ -21,8 +21,8 @@ android:id="@+id/theme_newtron" android:title="@string/theme_newtron" /> + android:id="@+id/theme_external" + android:title="@string/theme_external" /> Osmagray Tubes NewTron + External theme OK Cancel Error @@ -17,6 +18,5 @@ Show nature Hide nature Grid - load theme extern diff --git a/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java b/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java index ca88d0c4..87df685e 100644 --- a/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java +++ b/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java @@ -43,11 +43,10 @@ public final class ValidRenderTheme implements ValidFileFilter { try { ThemeFile theme = new ExternalRenderTheme(file.getAbsolutePath()); DefaultHandler renderThemeHandler; - if(ThemeUtils.isMapsforgeTheme(new FileInputStream(file))) { + if (ThemeUtils.isMapsforgeTheme(new FileInputStream(file))) renderThemeHandler = new XmlMapsforgeThemeBuilder(theme); - }else{ + else renderThemeHandler = new XmlThemeBuilder(theme); - } XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); xmlReader.setContentHandler(renderThemeHandler); xmlReader.parse(new InputSource(theme.getRenderThemeAsStream())); diff --git a/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java b/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java index 74a4c458..b4e44ae5 100644 --- a/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java +++ b/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java @@ -51,6 +51,7 @@ public class MapsforgeMapActivity extends MapActivity { private TileGridLayer mGridLayer; private DefaultMapScaleBar mMapScaleBar; + private Menu mMenu; @Override protected void onCreate(Bundle savedInstanceState) { @@ -85,6 +86,7 @@ public class MapsforgeMapActivity extends MapActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.theme_menu, menu); + mMenu = menu; return true; } @@ -117,8 +119,8 @@ public class MapsforgeMapActivity extends MapActivity { item.setChecked(true); return true; - case R.id.theme_load: - startActivityForResult(new Intent(MapsforgeMapActivity.this, ThemeFilePicker.class), + case R.id.theme_external: + startActivityForResult(new Intent(this, ThemeFilePicker.class), SELECT_THEME_FILE); return true; @@ -181,18 +183,13 @@ public class MapsforgeMapActivity extends MapActivity { } } else if (requestCode == SELECT_THEME_FILE) { if (resultCode != RESULT_OK || intent == null || intent.getStringExtra(FilePicker.SELECTED_FILE) == null) { - finish(); return; } - String themePath = intent.getStringExtra(FilePicker.SELECTED_FILE); - - ExternalRenderTheme externalRenderTheme = new ExternalRenderTheme(themePath); - try { - mMap.setTheme(externalRenderTheme, true); - } catch (Exception e) { - e.printStackTrace(); - } + String file = intent.getStringExtra(FilePicker.SELECTED_FILE); + ExternalRenderTheme externalRenderTheme = new ExternalRenderTheme(file); + mMap.setTheme(externalRenderTheme); + mMenu.findItem(R.id.theme_external).setChecked(true); } } diff --git a/vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java b/vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java index 2151233a..78392b21 100644 --- a/vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java +++ b/vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java @@ -88,6 +88,14 @@ public class AndroidCanvas implements Canvas { canvas.drawColor(color, color == Color.TRANSPARENT ? PorterDuff.Mode.CLEAR : PorterDuff.Mode.SRC_OVER); } + @Override + public void fillRectangle(float x, float y, float width, float height, int color) { + RectF rect = new RectF(x, y, x + width, y + height); + android.graphics.Paint paint = new android.graphics.Paint(); + paint.setColor(color); + canvas.drawRect(rect, paint); + } + @Override public int getHeight() { return canvas.getHeight(); @@ -97,12 +105,4 @@ public class AndroidCanvas implements Canvas { public int getWidth() { return canvas.getWidth(); } - - @Override - public void fillRectangle(int x, int y, int width, int height, int color) { - RectF rec = new RectF(x, y, x + width, y + height); - android.graphics.Paint paint = new android.graphics.Paint(); - paint.setColor(color); - canvas.drawRect(rec, paint); - } } diff --git a/vtm-desktop/src/org/oscim/awt/AwtCanvas.java b/vtm-desktop/src/org/oscim/awt/AwtCanvas.java index 57502a9a..a00aec32 100644 --- a/vtm-desktop/src/org/oscim/awt/AwtCanvas.java +++ b/vtm-desktop/src/org/oscim/awt/AwtCanvas.java @@ -186,6 +186,16 @@ public class AwtCanvas implements Canvas { fillRectangle(0, 0, getWidth(), getHeight(), color); } + @Override + public void fillRectangle(float x, float y, float width, float height, int color) { + java.awt.Color awtColor = color == Color.TRANSPARENT ? TRANSPARENT : new java.awt.Color(color); + Composite originalComposite = this.canvas.getComposite(); + this.canvas.setComposite(AlphaComposite.getInstance(color == Color.TRANSPARENT ? AlphaComposite.CLEAR : AlphaComposite.SRC_OVER)); + this.canvas.setColor(awtColor); + this.canvas.fillRect((int) x, (int) y, (int) width, (int) height); + this.canvas.setComposite(originalComposite); + } + @Override public int getHeight() { return this.bitmap != null ? this.bitmap.getHeight() : 0; @@ -195,14 +205,4 @@ public class AwtCanvas implements Canvas { public int getWidth() { return this.bitmap != null ? this.bitmap.getWidth() : 0; } - - @Override - public void fillRectangle(int x, int y, int width, int height, int color) { - java.awt.Color awtColor = color == Color.TRANSPARENT ? TRANSPARENT : new java.awt.Color(color); - Composite originalComposite = this.canvas.getComposite(); - this.canvas.setComposite(AlphaComposite.getInstance(color == Color.TRANSPARENT ? AlphaComposite.CLEAR : AlphaComposite.SRC_OVER)); - this.canvas.setColor(awtColor); - this.canvas.fillRect(x, y, width, height); - this.canvas.setComposite(originalComposite); - } } diff --git a/vtm-ios/src/org/oscim/ios/backend/IosCanvas.java b/vtm-ios/src/org/oscim/ios/backend/IosCanvas.java index 6a8c3fae..45da0d63 100644 --- a/vtm-ios/src/org/oscim/ios/backend/IosCanvas.java +++ b/vtm-ios/src/org/oscim/ios/backend/IosCanvas.java @@ -150,6 +150,14 @@ public class IosCanvas implements Canvas { this.cgBitmapContext.fillRect(rect); } + @Override + public void fillRectangle(float x, float y, float width, float height, int color) { + CGRect rect = new CGRect(x, y, width, height); + setFillColor(this.cgBitmapContext, (color)); + this.cgBitmapContext.setBlendMode(CGBlendMode.Normal); + this.cgBitmapContext.fillRect(rect); + } + @Override public int getHeight() { return this.cgBitmapContext != null ? (int) this.cgBitmapContext.getHeight() : 0; @@ -159,12 +167,4 @@ public class IosCanvas implements Canvas { public int getWidth() { return this.cgBitmapContext != null ? (int) this.cgBitmapContext.getWidth() : 0; } - - @Override - public void fillRectangle(int x, int y, int width, int height, int color) { - CGRect rect = new CGRect(x, y, width, height); - setFillColor(this.cgBitmapContext, (color)); - this.cgBitmapContext.setBlendMode(CGBlendMode.Normal); - this.cgBitmapContext.fillRect(rect); - } } diff --git a/vtm-playground/src/org/oscim/test/LineRenderTest.java b/vtm-playground/src/org/oscim/test/LineRenderTest.java index 317fa03e..fa956089 100644 --- a/vtm-playground/src/org/oscim/test/LineRenderTest.java +++ b/vtm-playground/src/org/oscim/test/LineRenderTest.java @@ -72,9 +72,9 @@ public class LineRenderTest extends GdxMap { line2 = new LineStyle(Color.GREEN, 1); line4 = new LineStyle(Color.LTGRAY, 3); } else { - line1 = new LineStyle(0, null, Color.fade(Color.RED, 0.5f), 4.0f, Cap.BUTT, false, 0, 0, 0, 0, 1f, false, null, true); - line2 = new LineStyle(0, null, Color.GREEN, 6.0f, Cap.BUTT, false, 0, 0, 0, 0, 1f, false, null, true); - line4 = new LineStyle(0, null, Color.LTGRAY, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 1f, false, null, true); + line1 = new LineStyle(0, null, Color.fade(Color.RED, 0.5f), 4.0f, Cap.BUTT, false, 0, 0, 0, 0, 1f, false, null, true, null); + line2 = new LineStyle(0, null, Color.GREEN, 6.0f, Cap.BUTT, false, 0, 0, 0, 0, 1f, false, null, true, null); + line4 = new LineStyle(0, null, Color.LTGRAY, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 1f, false, null, true, null); } TextureItem tex = new TextureItem(CanvasAdapter.getBitmapAsset("", "patterns/dot.png")); @@ -90,8 +90,8 @@ public class LineRenderTest extends GdxMap { .randomOffset(true) .build(); - LineStyle outline = new LineStyle(0, null, Color.BLUE, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 1f, true, null, true); - LineStyle outline2 = new LineStyle(0, null, Color.RED, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 0, true, null, true); + LineStyle outline = new LineStyle(0, null, Color.BLUE, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 1f, true, null, true, null); + LineStyle outline2 = new LineStyle(0, null, Color.RED, 2.0f, Cap.ROUND, false, 0, 0, 0, 0, 0, true, null, true, null); LineBucket ol = l.buckets.addLineBucket(0, outline); LineBucket ol2 = l.buckets.addLineBucket(5, outline2); diff --git a/vtm-web/src/org/oscim/gdx/client/GwtCanvas.java b/vtm-web/src/org/oscim/gdx/client/GwtCanvas.java index c3425aa4..179b0bcc 100644 --- a/vtm-web/src/org/oscim/gdx/client/GwtCanvas.java +++ b/vtm-web/src/org/oscim/gdx/client/GwtCanvas.java @@ -116,6 +116,11 @@ public class GwtCanvas implements org.oscim.backend.canvas.Canvas { // TODO } + @Override + public void fillRectangle(float x, float y, float width, float height, int color) { + // TODO + } + @Override public int getHeight() { return this.bitmap != null ? this.bitmap.getHeight() : 0; @@ -125,9 +130,4 @@ public class GwtCanvas implements org.oscim.backend.canvas.Canvas { public int getWidth() { return this.bitmap != null ? this.bitmap.getWidth() : 0; } - - @Override - public void fillRectangle(int x, int y, int width, int height, int color) { - // TODO - } } diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/theme/ThemeUtils.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/theme/ThemeUtils.java new file mode 100644 index 00000000..98c7c185 --- /dev/null +++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/theme/ThemeUtils.java @@ -0,0 +1,35 @@ +/* + * 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 + * 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 java.io.InputStream; + +/** + * A utility class with theme specific helper methods. + */ +public final class ThemeUtils { + + /** + * Check if the given InputStream is a Mapsforge render theme. + */ + public static boolean isMapsforgeTheme(InputStream is) { + // TODO + return false; + } + + private ThemeUtils() { + } +} diff --git a/vtm/resources/assets/shaders/linetex_layer_tex.glsl b/vtm/resources/assets/shaders/linetex_layer_tex.glsl index 98a400dc..0ca64261 100644 --- a/vtm/resources/assets/shaders/linetex_layer_tex.glsl +++ b/vtm/resources/assets/shaders/linetex_layer_tex.glsl @@ -44,10 +44,9 @@ uniform float u_mode; void main(){ if (u_mode >= 1.0) { - - float step= 2.0; - if (u_mode == 3.0){// dashed texture - step =1.0; + float step = 2.0; + if (u_mode == 2.0) { // dashed texture + step = 1.0; } vec4 c=texture2D(tex,vec2(abs(mod(v_st.s+1.0,step)),(v_st.t+1.0)*0.5)); float fuzz=fwidth(c.a); diff --git a/vtm/src/org/oscim/backend/canvas/Canvas.java b/vtm/src/org/oscim/backend/canvas/Canvas.java index c74eb39e..f8a9a64c 100644 --- a/vtm/src/org/oscim/backend/canvas/Canvas.java +++ b/vtm/src/org/oscim/backend/canvas/Canvas.java @@ -55,9 +55,9 @@ public interface Canvas { void fillColor(int color); + void fillRectangle(float x, float y, float width, float height, int color); + int getHeight(); int getWidth(); - - void fillRectangle(int x, int y, int width, int height, int color); } diff --git a/vtm/src/org/oscim/renderer/bucket/LineTexBucket.java b/vtm/src/org/oscim/renderer/bucket/LineTexBucket.java index 42fddf70..e5000614 100644 --- a/vtm/src/org/oscim/renderer/bucket/LineTexBucket.java +++ b/vtm/src/org/oscim/renderer/bucket/LineTexBucket.java @@ -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). @@ -359,7 +359,7 @@ public final class LineTexBucket extends LineBucket { LineTexBucket lb = (LineTexBucket) b; LineStyle line = lb.line.current(); - gl.uniform1f(shader.uMode, line.dashTexture? 3 : line.texture != null ? 1 : 0); + gl.uniform1f(shader.uMode, line.dashArray != null ? 2 : (line.texture != null ? 1 : 0)); if (line.texture != null) line.texture.bind(); diff --git a/vtm/src/org/oscim/theme/SAXTerminationException.java b/vtm/src/org/oscim/theme/SAXTerminationException.java new file mode 100644 index 00000000..b0463512 --- /dev/null +++ b/vtm/src/org/oscim/theme/SAXTerminationException.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Longri + * + * 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.xml.sax.SAXException; + +public class SAXTerminationException extends SAXException { + public SAXTerminationException() { + super(); + } +} diff --git a/vtm/src/org/oscim/theme/ThemeLoader.java b/vtm/src/org/oscim/theme/ThemeLoader.java index 88347c0c..a999d98d 100644 --- a/vtm/src/org/oscim/theme/ThemeLoader.java +++ b/vtm/src/org/oscim/theme/ThemeLoader.java @@ -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). @@ -18,21 +18,11 @@ */ package org.oscim.theme; - import org.oscim.backend.CanvasAdapter; import org.oscim.theme.IRenderTheme.ThemeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; - -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; public class ThemeLoader { - private static final Logger log = LoggerFactory.getLogger(ThemeLoader.class); - public static boolean USE_ATLAS; public static boolean POT_TEXTURES; @@ -56,21 +46,12 @@ public class ThemeLoader { return load(theme, null); } - - public static IRenderTheme load(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException { - IRenderTheme t = null; - - try { - if(ThemeUtils.isMapsforgeTheme(theme.getRenderThemeAsStream())){ - t = USE_ATLAS ? XmlMapsforgeAtlasThemeBuilder.read(theme, themeCallback) : XmlMapsforgeThemeBuilder.read(theme, themeCallback); - }else{ - t = USE_ATLAS ? XmlAtlasThemeBuilder.read(theme, themeCallback) : XmlThemeBuilder.read(theme, themeCallback); - } - } catch (IOException | ParserConfigurationException | SAXException e) { - e.printStackTrace(); - } - + IRenderTheme t; + if (ThemeUtils.isMapsforgeTheme(theme.getRenderThemeAsStream())) + t = USE_ATLAS ? XmlMapsforgeAtlasThemeBuilder.read(theme, themeCallback) : XmlMapsforgeThemeBuilder.read(theme, themeCallback); + else + t = USE_ATLAS ? XmlAtlasThemeBuilder.read(theme, themeCallback) : XmlThemeBuilder.read(theme, themeCallback); if (t != null) t.scaleTextSize(CanvasAdapter.textScale + (CanvasAdapter.dpi / CanvasAdapter.DEFAULT_DPI - 1)); return t; diff --git a/vtm/src/org/oscim/theme/ThemeUtils.java b/vtm/src/org/oscim/theme/ThemeUtils.java index 75d227ca..e5b9d5d1 100644 --- a/vtm/src/org/oscim/theme/ThemeUtils.java +++ b/vtm/src/org/oscim/theme/ThemeUtils.java @@ -1,7 +1,6 @@ /* * Copyright 2017 Longri - * - * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). + * 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 @@ -16,63 +15,59 @@ */ package org.oscim.theme; +import org.oscim.utils.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; -import java.io.IOException; import java.io.InputStream; import java.util.concurrent.atomic.AtomicBoolean; -import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; /** - * Created by Longri on 30.08.2017. + * A utility class with theme specific helper methods. */ +public final class ThemeUtils { -public class ThemeUtils { - - public static class SAXTerminatorException extends SAXException { - public SAXTerminatorException() { - super(); - } - } - + private static final Logger log = LoggerFactory.getLogger(ThemeUtils.class); /** - * Return true, if the given InputStream a Mapsforge render theme! - * - * @param stream - * @return TRUE or FALSE - * @throws IOException - * @throws SAXException - * @throws ParserConfigurationException + * Check if the given InputStream is a Mapsforge render theme. */ - public static boolean isMapsforgeTheme(InputStream stream) throws IOException, SAXException, ParserConfigurationException { - final AtomicBoolean isMapsforgeTheme = new AtomicBoolean(false); - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - - XMLReader xmlReader = factory.newSAXParser().getXMLReader(); - xmlReader.setContentHandler(new DefaultHandler() { - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - if (localName.equals("rendertheme")) { - isMapsforgeTheme.set(uri.equals("http://mapsforge.org/renderTheme")); - //we have all info's, break parsing - throw new SAXTerminatorException(); - } - } - }); + public static boolean isMapsforgeTheme(InputStream is) { try { - xmlReader.parse(new InputSource(stream)); - } catch (SAXTerminatorException e) { - // do nothing + final AtomicBoolean isMapsforgeTheme = new AtomicBoolean(false); + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + XMLReader xmlReader = factory.newSAXParser().getXMLReader(); + xmlReader.setContentHandler(new DefaultHandler() { + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (localName.equals("rendertheme")) { + isMapsforgeTheme.set(uri.equals("http://mapsforge.org/renderTheme")); + // We have all info, break parsing + throw new SAXTerminationException(); + } + } + }); + try { + xmlReader.parse(new InputSource(is)); + } catch (SAXTerminationException e) { + // Do nothing + } + return isMapsforgeTheme.get(); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } finally { + IOUtils.closeQuietly(is); } - stream.close(); - return isMapsforgeTheme.get(); } + private ThemeUtils() { + } } diff --git a/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java b/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java index 22aae9ad..714b6a53 100644 --- a/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java +++ b/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java @@ -25,7 +25,6 @@ import org.oscim.backend.XMLReaderAdapter; import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Canvas; import org.oscim.backend.canvas.Color; -import org.oscim.backend.canvas.Paint; import org.oscim.backend.canvas.Paint.Cap; import org.oscim.backend.canvas.Paint.FontFamily; import org.oscim.backend.canvas.Paint.FontStyle; @@ -65,7 +64,6 @@ import java.util.HashMap; import java.util.Locale; import java.util.Set; import java.util.Stack; -import java.util.regex.Pattern; import static java.lang.Boolean.parseBoolean; import static java.lang.Float.parseFloat; @@ -74,11 +72,7 @@ import static java.lang.Integer.parseInt; public class XmlMapsforgeThemeBuilder extends DefaultHandler { private static final Logger log = LoggerFactory.getLogger(XmlMapsforgeThemeBuilder.class); - private static final int RENDER_THEME_VERSION = 4; - private static final Pattern SPLIT_PATTERN = Pattern.compile(","); - private static final float REPEAT_GAP_DEFAULT = 200f; - private static final float REPEAT_START_DEFAULT = 30f; - + private static final int RENDER_THEME_VERSION = 6; private enum Element { RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS, RENDERING_STYLE @@ -93,6 +87,9 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { private static final String OUTLINE_STYLE = "O"; private static final String AREA_STYLE = "A"; + private static final float REPEAT_GAP_DEFAULT = 200f; + private static final float REPEAT_START_DEFAULT = 30f; + /** * @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. @@ -139,7 +136,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { private final Stack mRuleStack = new Stack<>(); private final HashMap mStyles = new HashMap<>(10); - private final HashMap> mTextStyles = new HashMap<>(10); + private final HashMap> mTextStyles = new HashMap<>(10); private final AreaBuilder mAreaBuilder = AreaStyle.builder(); private final CircleBuilder mCircleBuilder = CircleStyle.builder(); @@ -415,7 +412,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { if ("when-matched".equals(value)) selector |= Selector.WHEN_MATCHED; } else { - XmlMapsforgeThemeBuilder.logUnknownAttribute(localName, name, value, i); + logUnknownAttribute(localName, name, value, i); } } @@ -424,8 +421,8 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if (closed == Closed.NO) element = Rule.Element.LINE; - XmlMapsforgeThemeBuilder.validateNonNegative("zoom-min", zoomMin); - XmlMapsforgeThemeBuilder.validateNonNegative("zoom-max", zoomMax); + validateNonNegative("zoom-min", zoomMin); + validateNonNegative("zoom-max", zoomMax); if (zoomMin > zoomMax) throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin); @@ -449,7 +446,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { return texture; } - private void handleLineElement(String localName, Attributes attributes, boolean isStyle, boolean symbolLine) + private void handleLineElement(String localName, Attributes attributes, boolean isStyle, boolean hasSymbol) throws SAXException { String use = attributes.getValue("use"); @@ -463,7 +460,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { } } - LineStyle line = createLine(style, localName, attributes, mLevels++, false, symbolLine); + LineStyle line = createLine(style, localName, attributes, mLevels++, false, hasSymbol); if (isStyle) { mStyles.put(LINE_STYLE + line.style, line); @@ -489,7 +486,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { * @return a new Line with the given rendering attributes. */ private LineStyle createLine(LineStyle line, String elementName, Attributes attributes, - int level, boolean isOutline, boolean symbolLine) { + int level, boolean isOutline, boolean hasSymbol) { LineBuilder b = mLineBuilder.set(line); b.isOutline(isOutline); b.level(level); @@ -556,10 +553,13 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("style".equals(name)) ; // ignore - else if ("dasharray".equals(name)) - ; // TBD + else if ("stroke-dasharray".equals(name)) { + b.dashArray = parseFloatArray(value); + for (int j = 0; j < b.dashArray.length; ++j) { + b.dashArray[j] = b.dashArray[j] * mScale; + } - else if ("symbol-width".equals(name)) + } else if ("symbol-width".equals(name)) b.symbolWidth = (int) (Integer.parseInt(value) * mScale); else if ("symbol-height".equals(name)) @@ -568,31 +568,22 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); - else if ("stroke-dasharray".equals(name)) { - b.strokeDasharray = parseFloatArray(value); - for (int j = 0; j < b.strokeDasharray.length; ++j) { - b.strokeDasharray[j] = b.strokeDasharray[j] * mScale; - } - } else if ("dy".equals(name)) { - // NB: minus.. - //TODO b.dy = -Float.parseFloat(value) * mScale; - } else if ("align-center".equals(name)) { - //TODO handle align-center - } else if ("repeat".equals(name)) { - //TODO handle repeat - } else if ("display".equals(name)) { - //TODO handle display - } else + else if ("symbol-scaling".equals(name)) + ; // no-op + + else logUnknownAttribute(elementName, name, value, i); } - - if (b.strokeDasharray != null) {//create a dashed texture + if (b.dashArray != null) { + // Create a dashed texture int bmpWidth = 0; int bmpHeight = (int) (b.strokeWidth); - if (bmpHeight < 1) bmpHeight = 2; - for (float f : b.strokeDasharray) { - if (f < 1) f = 1; + if (bmpHeight < 1) + bmpHeight = 2; + for (float f : b.dashArray) { + if (f < 1) + f = 1; bmpWidth += f; } @@ -603,9 +594,10 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { boolean bw = false; int x = 0; - for (float f : b.strokeDasharray) { - if (f < 1) f = 1; - canvas.fillRectangle(x * factor, 0, (int) f * factor, bmpHeight * factor, (bw ? Color.TRANSPARENT : Color.WHITE)); + for (float f : b.dashArray) { + if (f < 1) + f = 1; + canvas.fillRectangle(x * factor, 0, f * factor, bmpHeight * factor, (bw ? Color.TRANSPARENT : Color.WHITE)); x += f; bw = !bw; } @@ -619,13 +611,12 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { b.stippleColor = b.fillColor; b.fillColor = Color.TRANSPARENT; b.strokeColor = Color.TRANSPARENT; - } else { b.texture = Utils.loadTexture(mTheme.getRelativePathPrefix(), src, b.symbolWidth, b.symbolHeight, b.symbolPercent); - if (symbolLine) { - // we have no way to set a repeatGap for the renderer, - // so we create a texture that already contains this repeatGap. + if (hasSymbol) { + // We have no way to set a repeat gap for the renderer, + // so we create a texture that already contains this repeat gap. float repeatGap = REPEAT_GAP_DEFAULT * mScale; float repeatStart = REPEAT_START_DEFAULT * mScale; int width = (int) (b.texture.width + repeatGap); @@ -636,13 +627,13 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { canvas.drawBitmap(b.texture.bitmap, repeatStart, 0); b.texture = new TextureItem(bmp); - // we must set stipple values + // We must set stipple values // The multipliers are determined empirically to - // correspond to the representation at Mapsforge! + // correspond to the representation at Mapsforge. b.stipple = b.texture.width * 3; b.strokeWidth *= 2 * mScale; - // use texture color + // Use texture color b.stippleColor = Color.WHITE; b.fillColor = Color.TRANSPARENT; b.strokeColor = Color.TRANSPARENT; @@ -736,9 +727,10 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); - else if ("symbol-scaling".equals(name)) { - // no-op - } else + else if ("symbol-scaling".equals(name)) + ; // no-op + + else logUnknownAttribute(elementName, name, value, i); } @@ -781,7 +773,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { if ("img".equals(name)) { img = value; } else { - XmlMapsforgeThemeBuilder.logUnknownAttribute(elementName, name, value, i); + logUnknownAttribute(elementName, name, value, i); } } validateExists("img", img, elementName); @@ -813,7 +805,7 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { Integer.parseInt(pos[3])); } } else { - XmlMapsforgeThemeBuilder.logUnknownAttribute(elementName, name, value, i); + logUnknownAttribute(elementName, name, value, i); } } validateExists("id", regionName, elementName); @@ -899,18 +891,15 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("base-text-scale".equals(name)) baseTextScale = Float.parseFloat(value); - else if ("map-background-outside".equals(name)) { - //TODO handle map-background-outside - } else - XmlMapsforgeThemeBuilder.logUnknownAttribute(elementName, name, value, i); + else + logUnknownAttribute(elementName, name, value, i); } validateExists("version", version, elementName); - if (version != RENDER_THEME_VERSION) - throw new ThemeException("invalid render theme version:" - + version); + if (version > RENDER_THEME_VERSION) + throw new ThemeException("invalid render theme version:" + version); validateNonNegative("base-stroke-width", baseStrokeWidth); validateNonNegative("base-text-scale", baseTextScale); @@ -1018,12 +1007,17 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); - else if ("display".equals(name)) { - //TODO Handle display attribute NEVER, ALWAYS, IFSPACE; - } else if ("symbol-id".equals(name)) { - //TODO Handle symbol-id; - } else if ("position".equals(name)) { - //TODO Handle position: AUTO, CENTER, BELOW, BELOW_LEFT, BELOW_RIGHT, ABOVE, ABOVE_LEFT, ABOVE_RIGHT, LEFT, RIGHT + else if ("symbol-scaling".equals(name)) + ; // no-op + + else if ("position".equals(name)) { + // Until implement position.. + if (b.dy == 0) { + value = "below".equals(value) ? "-20" : "20"; + // NB: minus.. + b.dy = -Float.parseFloat(value) * mScale; + } + } else logUnknownAttribute(elementName, name, value, i); } @@ -1115,15 +1109,10 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); - else if ("symbol-scaling".equals(name)) { - // no-op - } else if ("display".equals(name)) { - //TODO Handle display attribute NEVER, ALWAYS, IFSPACE; - } else if ("id".equals(name)) { - //TODO Handle 'id' - } else if ("priority".equals(name)) { - //TODO Handle 'priority' - } else + else if ("symbol-scaling".equals(name)) + ; // no-op + + else logUnknownAttribute(elementName, name, value, i); } @@ -1203,6 +1192,15 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { return mCategories == null || rule.cat == null || mCategories.contains(rule.cat); } + private static float[] parseFloatArray(String dashString) { + String[] dashEntries = dashString.split(","); + float[] dashIntervals = new float[dashEntries.length]; + for (int i = 0; i < dashEntries.length; ++i) { + dashIntervals[i] = Float.parseFloat(dashEntries[i]); + } + return dashIntervals; + } + private static void validateNonNegative(String name, float value) { if (value < 0) throw new ThemeException(name + " must not be negative: " @@ -1214,13 +1212,4 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { throw new ThemeException("missing attribute " + name + " for element: " + elementName); } - - private static float[] parseFloatArray(String dashString) { - String[] dashEntries = SPLIT_PATTERN.split(dashString); - float[] dashIntervals = new float[dashEntries.length]; - for (int i = 0; i < dashEntries.length; ++i) { - dashIntervals[i] = Float.parseFloat(dashEntries[i]); - } - return dashIntervals; - } } diff --git a/vtm/src/org/oscim/theme/XmlThemeBuilder.java b/vtm/src/org/oscim/theme/XmlThemeBuilder.java index c5f9cb9c..3b93f684 100644 --- a/vtm/src/org/oscim/theme/XmlThemeBuilder.java +++ b/vtm/src/org/oscim/theme/XmlThemeBuilder.java @@ -405,7 +405,7 @@ public class XmlThemeBuilder extends DefaultHandler { if ("when-matched".equals(value)) selector |= Selector.WHEN_MATCHED; } else { - XmlThemeBuilder.logUnknownAttribute(localName, name, value, i); + logUnknownAttribute(localName, name, value, i); } } @@ -414,8 +414,8 @@ public class XmlThemeBuilder extends DefaultHandler { else if (closed == Closed.NO) element = Rule.Element.LINE; - XmlThemeBuilder.validateNonNegative("zoom-min", zoomMin); - XmlThemeBuilder.validateNonNegative("zoom-max", zoomMax); + validateNonNegative("zoom-min", zoomMin); + validateNonNegative("zoom-max", zoomMax); if (zoomMin > zoomMax) throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin); @@ -462,9 +462,12 @@ public class XmlThemeBuilder extends DefaultHandler { mCurrentRule.addStyle(line); /* Note 'outline' will not be inherited, it's just a * shortcut to add the outline RenderInstruction. */ - LineStyle outline = createOutline(attributes.getValue("outline"), attributes); - if (outline != null) - mCurrentRule.addStyle(outline); + String outlineValue = attributes.getValue("outline"); + if (outlineValue != null) { + LineStyle outline = createOutline(outlineValue, attributes); + if (outline != null) + mCurrentRule.addStyle(outline); + } } } } @@ -555,6 +558,9 @@ public class XmlThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); + else if ("symbol-scaling".equals(name)) + ; // no-op + else logUnknownAttribute(elementName, name, value, i); } @@ -648,6 +654,9 @@ public class XmlThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); + else if ("symbol-scaling".equals(name)) + ; // no-op + else logUnknownAttribute(elementName, name, value, i); } @@ -691,7 +700,7 @@ public class XmlThemeBuilder extends DefaultHandler { if ("img".equals(name)) { img = value; } else { - XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); + logUnknownAttribute(elementName, name, value, i); } } validateExists("img", img, elementName); @@ -723,7 +732,7 @@ public class XmlThemeBuilder extends DefaultHandler { Integer.parseInt(pos[3])); } } else { - XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); + logUnknownAttribute(elementName, name, value, i); } } validateExists("id", regionName, elementName); @@ -810,15 +819,14 @@ public class XmlThemeBuilder extends DefaultHandler { baseTextScale = Float.parseFloat(value); else - XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); + logUnknownAttribute(elementName, name, value, i); } validateExists("version", version, elementName); - if (version != RENDER_THEME_VERSION) - throw new ThemeException("invalid render theme version:" - + version); + if (version > RENDER_THEME_VERSION) + throw new ThemeException("invalid render theme version:" + version); validateNonNegative("base-stroke-width", baseStrokeWidth); validateNonNegative("base-text-scale", baseTextScale); @@ -926,6 +934,9 @@ public class XmlThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); + else if ("symbol-scaling".equals(name)) + ; // no-op + else logUnknownAttribute(elementName, name, value, i); } @@ -1017,6 +1028,9 @@ public class XmlThemeBuilder extends DefaultHandler { else if ("symbol-percent".equals(name)) b.symbolPercent = Integer.parseInt(value); + else if ("symbol-scaling".equals(name)) + ; // no-op + else logUnknownAttribute(elementName, name, value, i); } diff --git a/vtm/src/org/oscim/theme/styles/LineStyle.java b/vtm/src/org/oscim/theme/styles/LineStyle.java index 0021c560..162b80dc 100644 --- a/vtm/src/org/oscim/theme/styles/LineStyle.java +++ b/vtm/src/org/oscim/theme/styles/LineStyle.java @@ -48,25 +48,26 @@ public final class LineStyle extends RenderStyle { public final int symbolWidth; public final int symbolHeight; public final int symbolPercent; - public boolean dashTexture; + + public final float[] dashArray; public LineStyle(int stroke, float width) { - this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false, null, true); + this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false, null, true, null); } public LineStyle(int level, int stroke, float width) { - this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false, null, true); + this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false, null, true, null); } public LineStyle(int stroke, float width, Cap cap) { - this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false, null, true); + this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false, null, true, null); } public LineStyle(int level, String style, int color, float width, Cap cap, boolean fixed, int stipple, int stippleColor, float stippleWidth, int fadeScale, float blur, boolean isOutline, TextureItem texture, - boolean randomOffset) { + boolean randomOffset, float[] dashArray) { this.level = level; this.style = style; @@ -91,6 +92,8 @@ public final class LineStyle extends RenderStyle { this.symbolWidth = 0; this.symbolHeight = 0; this.symbolPercent = 100; + + this.dashArray = dashArray; } private LineStyle(LineBuilder b) { @@ -114,7 +117,8 @@ public final class LineStyle extends RenderStyle { this.symbolWidth = b.symbolWidth; this.symbolHeight = b.symbolHeight; this.symbolPercent = b.symbolPercent; - this.dashTexture = b.strokeDasharray != null; + + this.dashArray = b.dashArray; } @Override @@ -146,7 +150,8 @@ public final class LineStyle extends RenderStyle { public int symbolWidth; public int symbolHeight; public int symbolPercent; - public float[] strokeDasharray; + + public float[] dashArray; public LineBuilder() { } @@ -176,6 +181,8 @@ public final class LineStyle extends RenderStyle { this.symbolHeight = line.symbolHeight; this.symbolPercent = line.symbolPercent; + this.dashArray = line.dashArray; + return self(); } @@ -254,6 +261,11 @@ public final class LineStyle extends RenderStyle { return self(); } + public T dashArray(float[] dashArray) { + this.dashArray = dashArray; + return self(); + } + public T reset() { level = -1; style = null; @@ -277,7 +289,9 @@ public final class LineStyle extends RenderStyle { symbolWidth = 0; symbolHeight = 0; symbolPercent = 100; - strokeDasharray = null; + + dashArray = null; + return self(); }