diff --git a/vtm-android-app b/vtm-android-app index 43a6277c..7449e47e 160000 --- a/vtm-android-app +++ b/vtm-android-app @@ -1 +1 @@ -Subproject commit 43a6277c1aa089f778f10ec1f2fd9b7034e63f0a +Subproject commit 7449e47e8ec147c816eb3b8b77d07109035fab4d 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 93728447..08e5f616 100644 --- a/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java +++ b/vtm-android-example/src/org/oscim/android/filepicker/ValidRenderTheme.java @@ -22,7 +22,7 @@ import java.io.InputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; -import org.oscim.theme.RenderThemeHandler; +import org.oscim.theme.XmlThemeBuilder; import org.oscim.tiling.TileSource.OpenResult; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -40,7 +40,7 @@ public final class ValidRenderTheme implements ValidFileFilter { try { inputStream = new FileInputStream(file); - RenderThemeHandler renderThemeHandler = new RenderThemeHandler(); + XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder(); XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); xmlReader.setContentHandler(renderThemeHandler); xmlReader.parse(new InputSource(inputStream)); diff --git a/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java index 8f47e9ec..60a41530 100644 --- a/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java +++ b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java @@ -15,8 +15,8 @@ import org.oscim.jeo.JeoUtils; import org.oscim.map.Map; import org.oscim.renderer.elements.LineLayer; import org.oscim.renderer.elements.MeshLayer; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -117,7 +117,7 @@ public class JeoVectorLayer extends JtsLayer { if (ll.line == null) { RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); - ll.line = new Line(0, JeoUtils.color(color), width); + ll.line = new LineStyle(0, JeoUtils.color(color), width); ll.setDropDistance(0.5f); } @@ -131,14 +131,14 @@ public class JeoVectorLayer extends JtsLayer { if (ll.line == null) { float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); - ll.line = new Line(0, JeoUtils.color(color), width); + ll.line = new LineStyle(0, JeoUtils.color(color), width); ll.setDropDistance(0.5f); } MeshLayer mesh = t.layers.getMeshLayer(0); if (mesh.area == null) { int color = JeoUtils.color(rule.color(f, CartoCSS.POLYGON_FILL, RGB.red)); - mesh.area = new Area(color); + mesh.area = new AreaStyle(color); } addPolygon(t, g, mesh, ll); diff --git a/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java b/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java index 11139ea8..688145cb 100644 --- a/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java +++ b/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java @@ -15,9 +15,10 @@ import org.oscim.renderer.elements.LineLayer; import org.oscim.renderer.elements.MeshLayer; import org.oscim.renderer.elements.TextItem; import org.oscim.renderer.elements.TextLayer; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.TextStyle; +import org.oscim.theme.styles.TextStyle.TextBuilder; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; @@ -26,7 +27,10 @@ import com.vividsolutions.jts.geom.LineString; public class OSMIndoorLayer extends JeoVectorLayer { protected TextLayer mTextLayer; - protected Text mText = Text.createText(16, 2.2f, Color.BLACK, Color.WHITE, true); + protected TextStyle mText = new TextBuilder() + .setFontSize(16).setColor(Color.BLACK) + .setStrokeWidth(2.2f).setStroke(Color.WHITE) + .build(); public OSMIndoorLayer(Map map, VectorDataset data, Style style) { super(map, data, style); @@ -58,7 +62,7 @@ public class OSMIndoorLayer extends JeoVectorLayer { if (ll.line == null) { RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); - ll.line = new Line(0, JeoUtils.color(color), width); + ll.line = new LineStyle(0, JeoUtils.color(color), width); ll.heightOffset = level * 4; ll.setDropDistance(0); } @@ -80,7 +84,7 @@ public class OSMIndoorLayer extends JeoVectorLayer { if (level > -2 && !active) color = Color.fade(color, 0.1f); - ll.line = new Line(0, color, width); + ll.line = new LineStyle(0, color, width); ll.heightOffset = level * 4; ll.setDropDistance(0); } @@ -91,7 +95,7 @@ public class OSMIndoorLayer extends JeoVectorLayer { if (level > -2 && !active) color = Color.fade(color, 0.1f); - mesh.area = new Area(color); + mesh.area = new AreaStyle(color); //mesh.area = new Area(Color.fade(Color.DKGRAY, 0.1f)); mesh.heightOffset = level * 4f; } diff --git a/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java b/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java index 92c7f398..5fb4ea01 100644 --- a/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java +++ b/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java @@ -19,8 +19,8 @@ import org.oscim.core.MapElement; import org.oscim.core.Tag; import org.oscim.core.TagSet; import org.oscim.theme.IRenderTheme; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; import org.oscim.theme.styles.RenderStyle; public class RenderTheme implements IRenderTheme { @@ -147,11 +147,11 @@ public class RenderTheme implements IRenderTheme { } if (p != null) { - s.ri[0] = new Area(mCurLevel++, color(p)); + s.ri[0] = new AreaStyle(mCurLevel++, color(p)); } if (l != null) { - s.ri[1] = new Line(mCurLevel++, color(l), 1); + s.ri[1] = new LineStyle(mCurLevel++, color(l), 1); } if (p != null || l != null) { @@ -198,7 +198,7 @@ public class RenderTheme implements IRenderTheme { RGB c = r.color(f, CartoCSS.POLYGON_FILL, RGB.black); out.println(z + " " + c); return new RenderStyle[] { - new Area(z, color(c)) + new AreaStyle(z, color(c)) }; } else if (type == GeometryType.LINE) { @@ -207,7 +207,7 @@ public class RenderTheme implements IRenderTheme { //out.println(z + " " + c); return new RenderStyle[] { - new Line(100 + z, color(c), width) + new LineStyle(100 + z, color(c), width) }; } else if (type == GeometryType.POINT) { @@ -258,7 +258,7 @@ public class RenderTheme implements IRenderTheme { } @Override - public void updateInstructions() { + public void updateStyles() { // TODO Auto-generated method stub } diff --git a/vtm-themes/resources/assets/styles/default.xml b/vtm-themes/resources/assets/styles/default.xml index c2e33b93..9b40e02a 100644 --- a/vtm-themes/resources/assets/styles/default.xml +++ b/vtm-themes/resources/assets/styles/default.xml @@ -79,7 +79,7 @@ stipple-stroke="#be6253" /> - + @@ -143,7 +143,7 @@ - + @@ -151,11 +151,11 @@ - + - + @@ -1064,7 +1064,10 @@ - + + + + @@ -1089,7 +1092,9 @@ - + + + @@ -1152,7 +1157,9 @@ - + + + @@ -1176,17 +1183,18 @@ - + + - - - + + + + - @@ -1200,7 +1208,10 @@ - + + + + diff --git a/vtm-themes/resources/assets/styles/osmarender.xml b/vtm-themes/resources/assets/styles/osmarender.xml index 18ed3052..5ae034bc 100644 --- a/vtm-themes/resources/assets/styles/osmarender.xml +++ b/vtm-themes/resources/assets/styles/osmarender.xml @@ -779,19 +779,19 @@ - + - + - + @@ -803,69 +803,69 @@ - + - + - + - + - + - + - + - + - + - + - + diff --git a/vtm-themes/resources/assets/styles/tronrender.xml b/vtm-themes/resources/assets/styles/tronrender.xml index 9d3d007d..a37c8cb5 100644 --- a/vtm-themes/resources/assets/styles/tronrender.xml +++ b/vtm-themes/resources/assets/styles/tronrender.xml @@ -2,7 +2,7 @@ - + @@ -62,10 +62,10 @@ - - - + @@ -1312,7 +1312,7 @@ - + @@ -1332,7 +1332,7 @@ - + diff --git a/vtm/src/org/oscim/layers/PathLayer.java b/vtm/src/org/oscim/layers/PathLayer.java index 7f05b6be..d6aaf286 100644 --- a/vtm/src/org/oscim/layers/PathLayer.java +++ b/vtm/src/org/oscim/layers/PathLayer.java @@ -32,7 +32,7 @@ import org.oscim.renderer.ElementRenderer; import org.oscim.renderer.GLViewport; import org.oscim.renderer.elements.ElementLayers; import org.oscim.renderer.elements.LineLayer; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; import org.oscim.utils.FastMath; import org.oscim.utils.async.SimpleWorker; import org.oscim.utils.geom.LineClipper; @@ -45,14 +45,14 @@ public class PathLayer extends Layer { protected boolean mUpdatePoints; /** Line style */ - Line mLineStyle; + LineStyle mLineStyle; final Worker mWorker; public PathLayer(Map map, int lineColor, float lineWidth) { super(map); mWorker = new Worker(map); - mLineStyle = new Line(lineColor, lineWidth, Cap.BUTT); + mLineStyle = new LineStyle(lineColor, lineWidth, Cap.BUTT); mRenderer = new RenderPath(); mPoints = new ArrayList(); } diff --git a/vtm/src/org/oscim/layers/TileGridLayer.java b/vtm/src/org/oscim/layers/TileGridLayer.java index 7ab673a5..541521d9 100644 --- a/vtm/src/org/oscim/layers/TileGridLayer.java +++ b/vtm/src/org/oscim/layers/TileGridLayer.java @@ -3,8 +3,8 @@ package org.oscim.layers; import org.oscim.backend.canvas.Paint.Cap; import org.oscim.map.Map; import org.oscim.renderer.GridRenderer; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.TextStyle; public class TileGridLayer extends GenericLayer { @@ -13,10 +13,10 @@ public class TileGridLayer extends GenericLayer { } public TileGridLayer(Map map, int color, float width, int repeat) { - super(map, new GridRenderer(repeat, new Line(color, width, Cap.BUTT), null)); + super(map, new GridRenderer(repeat, new LineStyle(color, width, Cap.BUTT), null)); } - public TileGridLayer(Map map, int color, float width, Text text, int repeat) { - super(map, new GridRenderer(repeat, new Line(color, width, Cap.BUTT), text)); + public TileGridLayer(Map map, int color, float width, TextStyle text, int repeat) { + super(map, new GridRenderer(repeat, new LineStyle(color, width, Cap.BUTT), text)); } } diff --git a/vtm/src/org/oscim/layers/tile/example/TestTileLayer.java b/vtm/src/org/oscim/layers/tile/example/TestTileLayer.java index bb38c7af..154bc7da 100644 --- a/vtm/src/org/oscim/layers/tile/example/TestTileLayer.java +++ b/vtm/src/org/oscim/layers/tile/example/TestTileLayer.java @@ -28,7 +28,7 @@ import org.oscim.layers.tile.VectorTileRenderer; import org.oscim.map.Map; import org.oscim.renderer.elements.ElementLayers; import org.oscim.renderer.elements.LineLayer; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +52,7 @@ public class TestTileLayer extends TileLayer { } GeometryBuffer mGeom = new GeometryBuffer(128, 16); - Line mLineStyle = new Line(Color.BLUE, 2f, Cap.ROUND); + LineStyle mLineStyle = new LineStyle(Color.BLUE, 2f, Cap.ROUND); @Override public boolean loadTile(MapTile tile) { diff --git a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java index fd50be23..e2549e14 100644 --- a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java +++ b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java @@ -40,14 +40,13 @@ import org.oscim.renderer.elements.SymbolItem; import org.oscim.renderer.elements.TextItem; import org.oscim.theme.IRenderTheme; import org.oscim.theme.RenderTheme; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Circle; -import org.oscim.theme.styles.Extrusion; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.LineSymbol; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.CircleStyle; +import org.oscim.theme.styles.ExtrusionStyle; +import org.oscim.theme.styles.LineStyle; import org.oscim.theme.styles.RenderStyle; -import org.oscim.theme.styles.Symbol; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.SymbolStyle; +import org.oscim.theme.styles.TextStyle; import org.oscim.tiling.ITileDataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -248,7 +247,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac /*** RenderThemeCallback ***/ @Override - public void renderWay(Line line, int level) { + public void renderWay(LineStyle line, int level) { int numLayer = mCurLayer + level; if (line.stipple == 0) { @@ -297,7 +296,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac protected final static boolean USE_MESH_POLY = false; @Override - public void renderArea(Area area, int level) { + public void renderArea(AreaStyle area, int level) { int numLayer = mCurLayer + level; if (USE_MESH_POLY) { MeshLayer l = mTile.layers.getMeshLayer(numLayer); @@ -311,7 +310,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac } @Override - public void renderAreaText(Text text) { + public void renderAreaText(TextStyle text) { // TODO place somewhere on polygon String value = mElement.tags.getValue(text.textKey); if (value == null || value.length() == 0) @@ -332,7 +331,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac } @Override - public void renderPointText(Text text) { + public void renderPointText(TextStyle text) { String value = mElement.tags.getValue(text.textKey); if (value == null || value.length() == 0) return; @@ -344,7 +343,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac } @Override - public void renderWayText(Text text) { + public void renderWayText(TextStyle text) { String value = mElement.tags.getValue(text.textKey); if (value == null || value.length() == 0) return; @@ -362,11 +361,11 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac } @Override - public void renderPointCircle(Circle circle, int level) { + public void renderPointCircle(CircleStyle circle, int level) { } @Override - public void renderPointSymbol(Symbol symbol) { + public void renderPointSymbol(SymbolStyle symbol) { if (symbol.texture == null) return; @@ -380,16 +379,11 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac } @Override - public void renderAreaSymbol(Symbol symbol) { + public void renderAreaSymbol(SymbolStyle symbol) { } @Override - public void renderWaySymbol(LineSymbol symbol) { - - } - - @Override - public void renderExtrusion(Extrusion extrusion, int level) { + public void renderExtrusion(ExtrusionStyle extrusion, int level) { int height = 0; int minHeight = 0; diff --git a/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java b/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java index 89148307..0bbb7378 100644 --- a/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java +++ b/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java @@ -20,14 +20,14 @@ package org.oscim.layers.tile.vector; import org.oscim.core.Tile; import org.oscim.layers.tile.MapTile; import org.oscim.renderer.elements.TextItem; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.TextStyle; import org.oscim.utils.geom.GeometryUtils; import org.oscim.utils.geom.LineClipper; public final class WayDecorator { public static void renderText(LineClipper clipper, float[] coordinates, String string, - Text text, int pos, int len, MapTile tile) { + TextStyle text, int pos, int len, MapTile tile) { //TextItem items = textItems; TextItem t = null; diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java b/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java index 88c81cd1..fa8c69ca 100644 --- a/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java +++ b/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java @@ -22,7 +22,7 @@ import org.oscim.renderer.GLViewport; import org.oscim.renderer.elements.ElementLayers; import org.oscim.renderer.elements.LineLayer; import org.oscim.renderer.elements.TextItem; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; class Debug { @@ -71,12 +71,12 @@ class Debug { int alpha = 0xaaffffff; dbg.clear(); - dbg.addLineLayer(0, new Line((Color.BLUE & alpha), 2)); - dbg.addLineLayer(1, new Line((Color.RED & alpha), 2)); - dbg.addLineLayer(3, new Line((Color.YELLOW & alpha), 2)); - dbg.addLineLayer(2, new Line((Color.GREEN & alpha), 2)); - dbg.addLineLayer(4, new Line((Color.CYAN & alpha), 2)); - dbg.addLineLayer(5, new Line((Color.MAGENTA & alpha), 2)); + dbg.addLineLayer(0, new LineStyle((Color.BLUE & alpha), 2)); + dbg.addLineLayer(1, new LineStyle((Color.RED & alpha), 2)); + dbg.addLineLayer(3, new LineStyle((Color.YELLOW & alpha), 2)); + dbg.addLineLayer(2, new LineStyle((Color.GREEN & alpha), 2)); + dbg.addLineLayer(4, new LineStyle((Color.CYAN & alpha), 2)); + dbg.addLineLayer(5, new LineStyle((Color.MAGENTA & alpha), 2)); } public static void draw(MapPosition pos, GLViewport m, ElementLayers layers) { diff --git a/vtm/src/org/oscim/renderer/GridRenderer.java b/vtm/src/org/oscim/renderer/GridRenderer.java index b970c79b..93da94d9 100644 --- a/vtm/src/org/oscim/renderer/GridRenderer.java +++ b/vtm/src/org/oscim/renderer/GridRenderer.java @@ -23,12 +23,13 @@ import org.oscim.core.Tile; import org.oscim.renderer.elements.LineLayer; import org.oscim.renderer.elements.TextItem; import org.oscim.renderer.elements.TextLayer; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.TextStyle; +import org.oscim.theme.styles.TextStyle.TextBuilder; public class GridRenderer extends ElementRenderer { private final TextLayer mTextLayer; - private final Text mText; + private final TextStyle mText; private final LineLayer mLineLayer; private final GeometryBuffer mLines; private final StringBuffer mStringBuffer; @@ -36,11 +37,11 @@ public class GridRenderer extends ElementRenderer { private int mCurX, mCurY, mCurZ; public GridRenderer() { - this(1, new Line(Color.LTGRAY, 1.2f, Cap.BUTT), - Text.createText(22, 0, Color.RED, 0, false)); + this(1, new LineStyle(Color.LTGRAY, 1.2f, Cap.BUTT), + new TextBuilder().setFontSize(22).setColor(Color.RED).build()); } - public GridRenderer(int numLines, Line lineStyle, Text textStyle) { + public GridRenderer(int numLines, LineStyle lineStyle, TextStyle textStyle) { int size = Tile.SIZE; // not needed to set but we know: diff --git a/vtm/src/org/oscim/renderer/elements/ElementLayers.java b/vtm/src/org/oscim/renderer/elements/ElementLayers.java index 756daeee..7671973a 100644 --- a/vtm/src/org/oscim/renderer/elements/ElementLayers.java +++ b/vtm/src/org/oscim/renderer/elements/ElementLayers.java @@ -25,8 +25,8 @@ import java.nio.ShortBuffer; import org.oscim.backend.GL20; import org.oscim.renderer.BufferObject; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,7 +83,7 @@ public class ElementLayers { * add the LineLayer for a level with a given Line style. Levels are * ordered from bottom (0) to top */ - public LineLayer addLineLayer(int level, Line style) { + public LineLayer addLineLayer(int level, LineStyle style) { LineLayer l = (LineLayer) getLayer(level, LINE); if (l == null) return null; @@ -93,7 +93,7 @@ public class ElementLayers { return l; } - public PolygonLayer addPolygonLayer(int level, Area style) { + public PolygonLayer addPolygonLayer(int level, AreaStyle style) { PolygonLayer l = (PolygonLayer) getLayer(level, POLYGON); if (l == null) return null; @@ -101,7 +101,7 @@ public class ElementLayers { return l; } - public MeshLayer addMeshLayer(int level, Area style) { + public MeshLayer addMeshLayer(int level, AreaStyle style) { MeshLayer l = (MeshLayer) getLayer(level, MESH); if (l == null) return null; diff --git a/vtm/src/org/oscim/renderer/elements/LineLayer.java b/vtm/src/org/oscim/renderer/elements/LineLayer.java index 197944f1..796b4721 100644 --- a/vtm/src/org/oscim/renderer/elements/LineLayer.java +++ b/vtm/src/org/oscim/renderer/elements/LineLayer.java @@ -29,7 +29,7 @@ import org.oscim.renderer.GLState; import org.oscim.renderer.GLUtils; import org.oscim.renderer.GLViewport; import org.oscim.renderer.MapRenderer; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; import org.oscim.utils.pool.Inlist; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,7 +64,7 @@ public final class LineLayer extends RenderElement { /* lines referenced by this outline layer */ public LineLayer outlines; - public Line line; + public LineStyle line; public float scale = 1; public boolean roundCap; @@ -749,7 +749,7 @@ public final class LineLayer extends RenderElement { RenderElement l = curLayer; for (; l != null && l.type == RenderElement.LINE; l = l.next) { LineLayer ll = (LineLayer) l; - Line line = (Line) ll.line.getCurrent(); + LineStyle line = (LineStyle) ll.line.getCurrent(); if (ll.heightOffset != heightOffset) { heightOffset = ll.heightOffset; @@ -758,9 +758,9 @@ public final class LineLayer extends RenderElement { MercatorProjection.groundResolution(v.pos)); } - if (line.fade < v.pos.zoomLevel) { + if (line.fadeScale < v.pos.zoomLevel) { GLUtils.setColor(uLineColor, line.color, 1); - } else if (line.fade > v.pos.zoomLevel) { + } else if (line.fadeScale > v.pos.zoomLevel) { continue; } else { float alpha = (float) (scale > 1.2 ? scale : 1.2) - 1; @@ -820,7 +820,7 @@ public final class LineLayer extends RenderElement { /* draw LineLayers references by this outline */ for (LineLayer ref = ll.outlines; ref != null; ref = ref.outlines) { - Line core = (Line) ref.line.getCurrent(); + LineStyle core = (LineStyle) ref.line.getCurrent(); // core width if (core.fixed) { diff --git a/vtm/src/org/oscim/renderer/elements/LineTexLayer.java b/vtm/src/org/oscim/renderer/elements/LineTexLayer.java index d91cdcfa..c7c5fbb1 100644 --- a/vtm/src/org/oscim/renderer/elements/LineTexLayer.java +++ b/vtm/src/org/oscim/renderer/elements/LineTexLayer.java @@ -26,7 +26,7 @@ import org.oscim.renderer.GLState; import org.oscim.renderer.GLUtils; import org.oscim.renderer.GLViewport; import org.oscim.renderer.MapRenderer; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; import org.oscim.utils.pool.Inlist; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,7 +86,7 @@ public final class LineTexLayer extends RenderElement { /* lines referenced by this outline layer */ public LineLayer outlines; - public Line line; + public LineStyle line; public float width; //public boolean roundCap; @@ -362,7 +362,7 @@ public final class LineTexLayer extends RenderElement { RenderElement l = curLayer; for (; l != null && l.type == TEXLINE; l = l.next) { LineTexLayer ll = (LineTexLayer) l; - Line line = ll.line; + LineStyle line = ll.line; GLUtils.setColor(hTexColor, line.stippleColor, 1); GLUtils.setColor(hBgColor, line.color, 1); diff --git a/vtm/src/org/oscim/renderer/elements/MeshLayer.java b/vtm/src/org/oscim/renderer/elements/MeshLayer.java index 07cb80b0..59edce7c 100644 --- a/vtm/src/org/oscim/renderer/elements/MeshLayer.java +++ b/vtm/src/org/oscim/renderer/elements/MeshLayer.java @@ -27,7 +27,7 @@ import org.oscim.renderer.GLState; import org.oscim.renderer.GLUtils; import org.oscim.renderer.GLViewport; import org.oscim.renderer.MapRenderer; -import org.oscim.theme.styles.Area; +import org.oscim.theme.styles.AreaStyle; import org.oscim.utils.Tessellator; import org.oscim.utils.pool.Inlist; import org.slf4j.Logger; @@ -41,7 +41,7 @@ public class MeshLayer extends RenderElement { int numIndices; VertexItem indiceItems; - public Area area; + public AreaStyle area; public float heightOffset; public MeshLayer(int level) { diff --git a/vtm/src/org/oscim/renderer/elements/PolygonLayer.java b/vtm/src/org/oscim/renderer/elements/PolygonLayer.java index 6b5db5d5..fe40349a 100644 --- a/vtm/src/org/oscim/renderer/elements/PolygonLayer.java +++ b/vtm/src/org/oscim/renderer/elements/PolygonLayer.java @@ -29,7 +29,7 @@ import org.oscim.renderer.GLState; import org.oscim.renderer.GLUtils; import org.oscim.renderer.GLViewport; import org.oscim.renderer.MapRenderer; -import org.oscim.theme.styles.Area; +import org.oscim.theme.styles.AreaStyle; import org.oscim.utils.FastMath; import org.oscim.utils.math.Interpolation; import org.oscim.utils.pool.Inlist; @@ -46,7 +46,7 @@ public final class PolygonLayer extends RenderElement { private static final boolean enableTexture = true; - public Area area; + public AreaStyle area; PolygonLayer(int layer) { super(RenderElement.POLYGON); @@ -181,7 +181,7 @@ public final class PolygonLayer extends RenderElement { int shader = polyShader; for (int c = start; c < end; c++) { - Area a = (Area) mFillPolys[c].area.getCurrent(); + AreaStyle a = (AreaStyle) mFillPolys[c].area.getCurrent(); if (enableTexture && a.texture != null) { shader = texShader; @@ -194,10 +194,10 @@ public final class PolygonLayer extends RenderElement { GLState.blend(true); a.texture.bind(); - } else if (a.fade >= zoom) { + } else if (a.fadeScale >= zoom) { float f = 1.0f; /* fade in/out */ - if (a.fade >= zoom) { + if (a.fadeScale >= zoom) { if (scale > FADE_START) f = scale - 1; else @@ -207,11 +207,11 @@ public final class PolygonLayer extends RenderElement { GLUtils.setColor(hPolygonColor[shader], a.color, f); - } else if (a.blend > 0 && a.blend <= zoom) { + } else if (a.blendScale > 0 && a.blendScale <= zoom) { /* blend colors (not alpha) */ GLState.blend(false); - if (a.blend == zoom) + if (a.blendScale == zoom) GLUtils.setColorBlend(hPolygonColor[shader], a.color, a.blendColor, scale - 1.0f); else @@ -301,7 +301,7 @@ public final class PolygonLayer extends RenderElement { PolygonLayer pl = (PolygonLayer) l; // fade out polygon layers (set in RenderTheme) - if (pl.area.fade > 0 && pl.area.fade > zoom) + if (pl.area.fadeScale > 0 && pl.area.fadeScale > zoom) continue; if (cur == start) { diff --git a/vtm/src/org/oscim/renderer/elements/TextItem.java b/vtm/src/org/oscim/renderer/elements/TextItem.java index 1c48a99f..6185d6e2 100644 --- a/vtm/src/org/oscim/renderer/elements/TextItem.java +++ b/vtm/src/org/oscim/renderer/elements/TextItem.java @@ -16,7 +16,7 @@ */ package org.oscim.renderer.elements; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.TextStyle; import org.oscim.utils.pool.Inlist; import org.oscim.utils.pool.SyncPool; @@ -57,7 +57,7 @@ public class TextItem extends Inlist { return ti; } - public TextItem set(float x, float y, String string, Text text) { + public TextItem set(float x, float y, String string, TextStyle text) { this.x = x; this.y = y; this.string = string; @@ -77,7 +77,7 @@ public class TextItem extends Inlist { public String string; // text style - public Text text; + public TextStyle text; // label width public float width; diff --git a/vtm/src/org/oscim/renderer/test/AtlasRenderLayer.java b/vtm/src/org/oscim/renderer/test/AtlasRenderLayer.java index af99a791..efb10ee0 100644 --- a/vtm/src/org/oscim/renderer/test/AtlasRenderLayer.java +++ b/vtm/src/org/oscim/renderer/test/AtlasRenderLayer.java @@ -28,8 +28,9 @@ import org.oscim.renderer.atlas.TextureAtlas.Slot; import org.oscim.renderer.elements.LineLayer; import org.oscim.renderer.elements.TextItem; import org.oscim.renderer.elements.TextLayer; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.TextStyle; +import org.oscim.theme.styles.TextStyle.TextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,19 +43,19 @@ public class AtlasRenderLayer extends ElementRenderer { TextureAtlas mAtlas = TextureAtlas.create(2048, 2048, 1); LineLayer ll = layers.getLineLayer(0); - ll.line = new Line(Color.BLUE, 3, Cap.BUTT); + ll.line = new LineStyle(Color.BLUE, 3, Cap.BUTT); ll.scale = 1f; LineLayer ll2 = layers.getLineLayer(1); - ll2.line = new Line(Color.RED, 3, Cap.BUTT); + ll2.line = new LineStyle(Color.RED, 3, Cap.BUTT); ll2.scale = 1f; LineLayer ll3 = layers.getLineLayer(2); - ll3.line = new Line(Color.GREEN, 3, Cap.BUTT); + ll3.line = new LineStyle(Color.GREEN, 3, Cap.BUTT); ll3.scale = 1f; TextLayer tl = new TextLayer(); - Text t = Text.createText(20, 0, Color.BLACK, 0, false); + TextStyle t = new TextBuilder().setFontSize(20).setColor(Color.BLACK).build(); layers.setTextureLayers(tl); float[] points = new float[10]; diff --git a/vtm/src/org/oscim/renderer/test/BezierPathLayer.java b/vtm/src/org/oscim/renderer/test/BezierPathLayer.java index e5eb9f59..adbf422d 100644 --- a/vtm/src/org/oscim/renderer/test/BezierPathLayer.java +++ b/vtm/src/org/oscim/renderer/test/BezierPathLayer.java @@ -8,7 +8,7 @@ import org.oscim.core.Point; import org.oscim.renderer.ElementRenderer; import org.oscim.renderer.GLViewport; import org.oscim.renderer.elements.LineLayer; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.LineStyle; import org.oscim.utils.geom.BezierPath; public class BezierPathLayer extends ElementRenderer { @@ -27,7 +27,7 @@ public class BezierPathLayer extends ElementRenderer { // System.out.println(pts[i]); g.addPoint(pts[i]); } - LineLayer ll = layers.addLineLayer(0, new Line(Color.BLUE, 2f)); + LineLayer ll = layers.addLineLayer(0, new LineStyle(Color.BLUE, 2f)); ll.addLine(g); List ctrl = BezierPath.cubicSplineControlPoints(pts, 0.1f); @@ -49,7 +49,7 @@ public class BezierPathLayer extends ElementRenderer { } p0 = p3; } - ll = layers.addLineLayer(1, new Line(Color.CYAN, 2f)); + ll = layers.addLineLayer(1, new LineStyle(Color.CYAN, 2f)); ll.addLine(g); } diff --git a/vtm/src/org/oscim/theme/DebugTheme.java b/vtm/src/org/oscim/theme/DebugTheme.java index 9caaae8d..11998d2c 100644 --- a/vtm/src/org/oscim/theme/DebugTheme.java +++ b/vtm/src/org/oscim/theme/DebugTheme.java @@ -3,14 +3,14 @@ package org.oscim.theme; import org.oscim.backend.canvas.Color; import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.TagSet; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; import org.oscim.theme.styles.RenderStyle; public class DebugTheme implements IRenderTheme { - private final static Line[] line = { new Line(1, Color.MAGENTA, 2) }; - private final static Area[] area = { new Area(0, Color.CYAN) }; + private final static LineStyle[] line = { new LineStyle(1, Color.MAGENTA, 2) }; + private final static AreaStyle[] area = { new AreaStyle(0, Color.CYAN) }; @Override public RenderStyle[] matchElement(GeometryType type, TagSet tags, int zoomLevel) { @@ -41,7 +41,7 @@ public class DebugTheme implements IRenderTheme { } @Override - public void updateInstructions() { + public void updateStyles() { } diff --git a/vtm/src/org/oscim/theme/IRenderTheme.java b/vtm/src/org/oscim/theme/IRenderTheme.java index ce8de7e6..6b0ec196 100644 --- a/vtm/src/org/oscim/theme/IRenderTheme.java +++ b/vtm/src/org/oscim/theme/IRenderTheme.java @@ -19,14 +19,13 @@ package org.oscim.theme; import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.TagSet; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Circle; -import org.oscim.theme.styles.Extrusion; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.LineSymbol; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.CircleStyle; +import org.oscim.theme.styles.ExtrusionStyle; +import org.oscim.theme.styles.LineStyle; import org.oscim.theme.styles.RenderStyle; -import org.oscim.theme.styles.Symbol; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.SymbolStyle; +import org.oscim.theme.styles.TextStyle; public interface IRenderTheme { @@ -56,7 +55,7 @@ public interface IRenderTheme { */ public abstract int getMapBackground(); - public void updateInstructions(); + public void updateStyles(); /** * Scales the text size of this RenderTheme by the given factor. @@ -76,7 +75,7 @@ public interface IRenderTheme { * @param area * @param level */ - void renderArea(Area area, int level); + void renderArea(AreaStyle area, int level); /** * Renders an extrusion with the given parameters. @@ -84,7 +83,7 @@ public interface IRenderTheme { * @param extrusion * @param level */ - void renderExtrusion(Extrusion extrusion, int level); + void renderExtrusion(ExtrusionStyle extrusion, int level); /** * Renders an area symbol with the given bitmap. @@ -92,7 +91,7 @@ public interface IRenderTheme { * @param symbol * the symbol to be rendered. */ - void renderAreaSymbol(Symbol symbol); + void renderAreaSymbol(SymbolStyle symbol); /** * Renders an area caption with the given text. @@ -100,7 +99,7 @@ public interface IRenderTheme { * @param text * the text to be rendered. */ - void renderAreaText(Text text); + void renderAreaText(TextStyle text); /** * Renders a point of interest circle with the given parameters. @@ -110,7 +109,7 @@ public interface IRenderTheme { * @param level * the drawing level on which the circle should be rendered. */ - void renderPointCircle(Circle circle, int level); + void renderPointCircle(CircleStyle circle, int level); /** * Renders a point of interest symbol with the given bitmap. @@ -118,7 +117,7 @@ public interface IRenderTheme { * @param symbol * the symbol to be rendered. */ - void renderPointSymbol(Symbol symbol); + void renderPointSymbol(SymbolStyle symbol); /** * Renders a point of interest caption with the given text. @@ -126,7 +125,7 @@ public interface IRenderTheme { * @param text * the text to be rendered. */ - void renderPointText(Text text); + void renderPointText(TextStyle text); /** * Renders a way with the given parameters. @@ -134,22 +133,14 @@ public interface IRenderTheme { * @param line * @param level */ - void renderWay(Line line, int level); - - /** - * Renders a way with the given symbol along the way path. - * - * @param symbol - * the symbol to be rendered. - */ - void renderWaySymbol(LineSymbol symbol); + void renderWay(LineStyle line, int level); /** * Renders a way with the given text along the way path. * * @param text */ - void renderWayText(Text text); + void renderWayText(TextStyle text); } diff --git a/vtm/src/org/oscim/theme/RenderTheme.java b/vtm/src/org/oscim/theme/RenderTheme.java index 71e51ecd..f951d4c5 100644 --- a/vtm/src/org/oscim/theme/RenderTheme.java +++ b/vtm/src/org/oscim/theme/RenderTheme.java @@ -1,6 +1,5 @@ /* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek + * Copyright 2014 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -25,14 +24,12 @@ import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.TagSet; import org.oscim.theme.rule.Element; import org.oscim.theme.rule.Rule; +import org.oscim.theme.rule.Rule.RuleVisitor; import org.oscim.theme.styles.RenderStyle; import org.oscim.utils.LRUCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * A RenderTheme defines how map elements are drawn. - */ public class RenderTheme implements IRenderTheme { static final Logger log = LoggerFactory.getLogger(RenderTheme.class); @@ -41,8 +38,8 @@ public class RenderTheme implements IRenderTheme { private final float mBaseTextSize; private final int mMapBackground; - private int mLevels; - private Rule[] mRules; + private final int mLevels; + private final Rule[] mRules; class RenderStyleCache { final int matchType; @@ -75,9 +72,14 @@ public class RenderTheme implements IRenderTheme { private final RenderStyleCache[] mStyleCache; - public RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) { + public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels) { + if (rules == null) + throw new IllegalArgumentException("rules missing"); + mMapBackground = mapBackground; mBaseTextSize = baseTextSize; + mLevels = levels; + mRules = rules; mStyleCache = new RenderStyleCache[3]; mStyleCache[0] = new RenderStyleCache(Element.NODE); @@ -91,10 +93,8 @@ public class RenderTheme implements IRenderTheme { for (int i = 0; i < 3; i++) mStyleCache[i].cache.clear(); - if (mRules != null) { - for (int i = 0, n = mRules.length; i < n; i++) - mRules[i].onDestroy(); - } + for (Rule rule : mRules) + rule.dispose(); } @Override @@ -107,13 +107,17 @@ public class RenderTheme implements IRenderTheme { return mMapBackground; } + //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 renderinsctruction items in cache + /* list of items in cache */ RenderStyleItem ris = null; - // the item matching tags and zoomlevel + /* the item matching tags and zoomlevel */ RenderStyleItem ri = null; int type = geometryType.nativeInt; @@ -124,35 +128,42 @@ public class RenderTheme implements IRenderTheme { RenderStyleCache cache = mStyleCache[type - 1]; - // NOTE: maximum zoom level supported is 32 + /* 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 + /* previous instructions zoom does not match */ cache.cacheKey.set(tags, null); } else { - // compare if tags match previous instructions + /* compare if tags match previous instructions */ if (cache.cacheKey.set(tags, cache.prevItem.key)) { - //log.debug("same as previous " + Arrays.deepToString(tags)); ri = cache.prevItem; + //log.debug(hitCount + "/" + sameCount.incrementAndGet() + // + "/" + missCount + "same hit " + tags); } } if (ri == null) { - // get instruction for current cacheKey + /* get instruction for current cacheKey */ ris = cache.getRenderInstructions(); - for (ri = ris; ri != null; ri = ri.next) - if ((ri.zoom & zoomMask) != 0) - // cache hit + 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 - //log.debug(missCnt++ + " / " + hitCnt + " Cache Miss"); + /* cache miss */ + //missCount.incrementAndGet(); List matches = cache.instructionList; matches.clear(); @@ -176,13 +187,13 @@ public class RenderTheme implements IRenderTheme { } } } - // check if same instructions are used in another level + /* 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 + /* both matchinglists are empty */ break; } @@ -199,13 +210,13 @@ public class RenderTheme implements IRenderTheme { i++; } if (i == size) - // both matching lists contain the same items + /* 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. + /* 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 + " " @@ -222,7 +233,7 @@ public class RenderTheme implements IRenderTheme { 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) { ri.next = ris.next; ri.key = ris.key; @@ -233,34 +244,26 @@ public class RenderTheme implements IRenderTheme { } } } - cache.prevItem = ri; } - return ri.list; } - void complete(List rulesList, int levels) { - mLevels = levels; - - mRules = new Rule[rulesList.size()]; - rulesList.toArray(mRules); - - for (int i = 0, n = mRules.length; i < n; i++) { - mRules[i].onComplete(); - } - } - @Override public void scaleTextSize(float scaleFactor) { - - for (int i = 0, n = mRules.length; i < n; i++) - mRules[i].scaleTextSize(scaleFactor * mBaseTextSize); + for (Rule rule : mRules) + rule.scaleTextSize(scaleFactor * mBaseTextSize); } @Override - public void updateInstructions() { - for (int i = 0, n = mRules.length; i < n; i++) - mRules[i].updateInstructions(); + public void updateStyles() { + for (Rule rule : mRules) + rule.updateStyles(); } + + public void traverseRules(RuleVisitor visitor) { + for (Rule rule : mRules) + rule.apply(visitor); + } + } diff --git a/vtm/src/org/oscim/theme/ThemeBuilder.java b/vtm/src/org/oscim/theme/ThemeBuilder.java new file mode 100644 index 00000000..dd20f9ab --- /dev/null +++ b/vtm/src/org/oscim/theme/ThemeBuilder.java @@ -0,0 +1,125 @@ +package org.oscim.theme; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Stack; + +import org.oscim.core.GeometryBuffer.GeometryType; +import org.oscim.core.Tag; +import org.oscim.core.TagSet; +import org.oscim.theme.rule.Element; +import org.oscim.theme.rule.Rule; +import org.oscim.theme.rule.RuleBuilder; +import org.oscim.theme.rule.Selector; +import org.oscim.theme.rule.SingleKeyMatcher; +import org.oscim.theme.rule.SingleValueMatcher; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.RenderStyle; + +public class ThemeBuilder { + protected final ArrayList mRulesList = new ArrayList(); + protected final Stack mRuleStack = new Stack(); + + protected int mLevels = 0; + protected int mMapBackground = 0xffffffff; + protected float mBaseTextSize = 1; + + protected RuleBuilder mCurrentRule; + + protected RenderTheme build() { + + Rule[] rules = new Rule[mRulesList.size()]; + for (int i = 0, n = rules.length; i < n; i++) + rules[i] = mRulesList.get(i).onComplete(); + + RenderTheme theme = new RenderTheme(mMapBackground, mBaseTextSize, rules, mLevels); + + mRulesList.clear(); + mRuleStack.clear(); + + return theme; + } + + public ThemeBuilder pop() { + + mRuleStack.pop(); + if (mRuleStack.empty()) { + mRulesList.add(mCurrentRule); + } else { + mCurrentRule = mRuleStack.peek(); + } + return this; + } + + public ThemeBuilder push(RuleBuilder rule) { + if (!mRuleStack.empty()) + mCurrentRule.addSubRule(rule); + + mCurrentRule = rule; + mRuleStack.push(mCurrentRule); + + return this; + } + + public ThemeBuilder push(String key, String value) { + RuleBuilder b = new RuleBuilder(true, Element.ANY, ~0, 0, + key == null ? null : new SingleKeyMatcher(key), + value == null ? null : new SingleValueMatcher(value)); + push(b); + return this; + } + + public RuleBuilder pushParse(String keys, String values) { + + return RuleBuilder.create(mRuleStack, keys, values) + .zoom(~0) + .element(Element.ANY); + } + + public ThemeBuilder addStyle(RenderStyle style) { + mCurrentRule.addStyle(style); + return this; + } + + public static void main(String[] args) { + + ThemeBuilder b = new ThemeBuilder(); + + //b.pushParse("highway", "residential|primary|motorway") + + b.push(RuleBuilder.get().select(Selector.FIRST)) + .push("highway", null) + .addStyle(new LineStyle(1, 1, 1)) + .pop() + + .push(RuleBuilder.get().select(Selector.WHEN_MATCHED)) + .addStyle(new AreaStyle(1, 1)) + .pop() + .pop(); + + RenderTheme t = b.build(); + TagSet tags = new TagSet(1); + RenderStyle[] styles; + + tags.add(new Tag("ahighway", "residential")); + styles = t.matchElement(GeometryType.LINE, tags, 1); + System.out.println(Arrays.deepToString(styles)); + + // tags.clear(); + // tags.add(new Tag("highway", "motorway")); + // styles = t.matchElement(GeometryType.LINE, tags, 1); + // out.println(styles); + // + // tags.clear(); + // tags.add(new Tag("sup", "wup")); + // styles = t.matchElement(GeometryType.LINE, tags, 1); + // out.println(styles); + // + // tags.clear(); + // tags.add(new Tag("highway", "motorway")); + // styles = t.matchElement(GeometryType.LINE, tags, 1); + // out.println(styles); + + } +} diff --git a/vtm/src/org/oscim/theme/ThemeLoader.java b/vtm/src/org/oscim/theme/ThemeLoader.java index c49a9213..71b39fd6 100644 --- a/vtm/src/org/oscim/theme/ThemeLoader.java +++ b/vtm/src/org/oscim/theme/ThemeLoader.java @@ -45,7 +45,7 @@ public class ThemeLoader { InputStream inputStream = null; try { inputStream = theme.getRenderThemeAsStream(); - IRenderTheme t = RenderThemeHandler.getRenderTheme(inputStream); + IRenderTheme t = XmlThemeBuilder.read(inputStream); if (t != null) t.scaleTextSize(CanvasAdapter.textScale + (CanvasAdapter.dpi / 240 - 1) * 0.5f); diff --git a/vtm/src/org/oscim/theme/RenderThemeHandler.java b/vtm/src/org/oscim/theme/XmlThemeBuilder.java similarity index 59% rename from vtm/src/org/oscim/theme/RenderThemeHandler.java rename to vtm/src/org/oscim/theme/XmlThemeBuilder.java index 0c1363d5..4bbc5bb4 100644 --- a/vtm/src/org/oscim/theme/RenderThemeHandler.java +++ b/vtm/src/org/oscim/theme/XmlThemeBuilder.java @@ -17,6 +17,10 @@ */ package org.oscim.theme; +import static java.lang.Boolean.parseBoolean; +import static java.lang.Float.parseFloat; +import static java.lang.Integer.parseInt; + import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -36,14 +40,17 @@ import org.oscim.renderer.atlas.TextureRegion; import org.oscim.renderer.elements.TextureItem; import org.oscim.theme.IRenderTheme.ThemeException; import org.oscim.theme.rule.Rule; -import org.oscim.theme.styles.Area; -import org.oscim.theme.styles.Circle; -import org.oscim.theme.styles.Extrusion; -import org.oscim.theme.styles.Line; -import org.oscim.theme.styles.LineSymbol; +import org.oscim.theme.rule.RuleBuilder; +import org.oscim.theme.styles.AreaStyle; +import org.oscim.theme.styles.AreaStyle.AreaBuilder; +import org.oscim.theme.styles.CircleStyle; +import org.oscim.theme.styles.ExtrusionStyle; +import org.oscim.theme.styles.LineStyle; +import org.oscim.theme.styles.LineStyle.LineBuilder; import org.oscim.theme.styles.RenderStyle; -import org.oscim.theme.styles.Symbol; -import org.oscim.theme.styles.Text; +import org.oscim.theme.styles.SymbolStyle; +import org.oscim.theme.styles.TextStyle; +import org.oscim.theme.styles.TextStyle.TextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; @@ -51,8 +58,8 @@ import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; -public class RenderThemeHandler extends DefaultHandler { - static final Logger log = LoggerFactory.getLogger(RenderThemeHandler.class); +public class XmlThemeBuilder extends DefaultHandler { + static final Logger log = LoggerFactory.getLogger(XmlThemeBuilder.class); private static final int RENDER_THEME_VERSION = 1; @@ -60,7 +67,7 @@ public class RenderThemeHandler extends DefaultHandler { RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS; } - //private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme"; + private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme"; private static final String ELEMENT_NAME_MATCH = "m"; private static final String UNEXPECTED_ELEMENT = "unexpected element: "; @@ -82,10 +89,10 @@ public class RenderThemeHandler extends DefaultHandler { * @throws IOException * if an I/O error occurs while reading from the input stream. */ - public static IRenderTheme getRenderTheme(InputStream inputStream) + public static IRenderTheme read(InputStream inputStream) throws SAXException, IOException { - RenderThemeHandler renderThemeHandler = new RenderThemeHandler(); + XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder(); new XMLReaderAdapter().parse(renderThemeHandler, inputStream); @@ -118,36 +125,39 @@ public class RenderThemeHandler extends DefaultHandler { log.debug(sb.toString()); } - private ArrayList mRulesList = new ArrayList(); - private Rule mCurrentRule; - - private Stack mElementStack = new Stack(); - private Stack mRuleStack = new Stack(); - private HashMap mStyles = + private final ArrayList mRulesList = new ArrayList(); + private final Stack mElementStack = new Stack(); + private final Stack mRuleStack = new Stack(); + private final HashMap mStyles = new HashMap(10); + private final TextBuilder mTextBuilder = new TextBuilder(); + private final AreaBuilder mAreaBuilder = new AreaBuilder(); + private final LineBuilder mLineBuilder = new LineBuilder(); + + private RuleBuilder mCurrentRule; private TextureAtlas mTextureAtlas; - private int mLevel; + private int mLevels = 0; + private int mMapBackground = 0xffffffff; + private float mBaseTextSize = 1; + private RenderTheme mRenderTheme; @Override public void endDocument() { - if (mRenderTheme == null) { - throw new IllegalArgumentException("missing element: rules"); - } - mRenderTheme.complete(mRulesList, mLevel); + Rule[] rules = new Rule[mRulesList.size()]; + for (int i = 0, n = rules.length; i < n; i++) + rules[i] = mRulesList.get(i).onComplete(); + + mRenderTheme = new RenderTheme(mMapBackground, mBaseTextSize, rules, mLevels); mRulesList.clear(); mStyles.clear(); mRuleStack.clear(); mElementStack.clear(); - mStyles = null; - mRuleStack = null; - mRulesList = null; - mElementStack = null; mTextureAtlas = null; } @@ -179,13 +189,13 @@ public class RenderThemeHandler extends DefaultHandler { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { - if ("rendertheme".equals(localName)) { + if (ELEMENT_NAME_RENDER_THEME.equals(localName)) { checkState(localName, Element.RENDER_THEME); - mRenderTheme = createRenderTheme(localName, attributes); + createRenderTheme(localName, attributes); } else if (ELEMENT_NAME_MATCH.equals(localName)) { checkState(localName, Element.RULE); - Rule rule = Rule.create(localName, attributes, mRuleStack); + RuleBuilder rule = RuleBuilder.create(localName, attributes, mRuleStack); if (!mRuleStack.empty()) { mCurrentRule.addSubRule(rule); } @@ -194,7 +204,7 @@ public class RenderThemeHandler extends DefaultHandler { } else if ("style-text".equals(localName)) { checkState(localName, Element.STYLE); - Text text = createText(localName, attributes, false); + TextStyle text = createText(localName, attributes, false); mStyles.put(TEXT_STYLE + text.style, text); } else if ("style-area".equals(localName)) { @@ -207,7 +217,7 @@ public class RenderThemeHandler extends DefaultHandler { } else if ("outline-layer".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); - Line line = createLine(null, localName, attributes, mLevel++, true); + LineStyle line = createLine(null, localName, attributes, mLevels++, true); mStyles.put(OUTLINE_STYLE + line.style, line); } else if ("area".equals(localName)) { @@ -216,40 +226,35 @@ public class RenderThemeHandler extends DefaultHandler { } else if ("caption".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); - Text text = createText(localName, attributes, true); - mCurrentRule.addRenderingInstruction(text); + TextStyle text = createText(localName, attributes, true); + mCurrentRule.addStyle(text); } else if ("circle".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); - Circle circle = createCircle(localName, attributes, mLevel++); - mCurrentRule.addRenderingInstruction(circle); + CircleStyle circle = createCircle(localName, attributes, mLevels++); + mCurrentRule.addStyle(circle); } else if ("line".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); handleLineElement(localName, attributes, false); - } else if ("lineSymbol".equals(localName)) { - checkState(localName, Element.RENDERING_INSTRUCTION); - LineSymbol lineSymbol = createLineSymbol(localName, attributes); - mCurrentRule.addRenderingInstruction(lineSymbol); - } else if ("text".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); String style = attributes.getValue("use"); if (style == null) { - Text text = createText(localName, attributes, false); - mCurrentRule.addRenderingInstruction(text); + TextStyle text = createText(localName, attributes, false); + mCurrentRule.addStyle(text); } else { - Text pt = (Text) mStyles.get(TEXT_STYLE + style); + TextStyle pt = (TextStyle) mStyles.get(TEXT_STYLE + style); if (pt != null) - mCurrentRule.addRenderingInstruction(pt); + mCurrentRule.addStyle(pt); else log.debug("BUG not a path text style: " + style); } } else if ("symbol".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); - Symbol symbol = createSymbol(localName, attributes); - mCurrentRule.addRenderingInstruction(symbol); + SymbolStyle symbol = createSymbol(localName, attributes); + mCurrentRule.addStyle(symbol); } else if ("outline".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); @@ -257,8 +262,8 @@ public class RenderThemeHandler extends DefaultHandler { } else if ("extrusion".equals(localName)) { checkState(localName, Element.RENDERING_INSTRUCTION); - Extrusion extrusion = createExtrusion(localName, attributes, mLevel++); - mCurrentRule.addRenderingInstruction(extrusion); + ExtrusionStyle extrusion = createExtrusion(localName, attributes, mLevels++); + mCurrentRule.addStyle(extrusion); } else if ("atlas".equals(localName)) { checkState(localName, Element.ATLAS); @@ -295,22 +300,22 @@ public class RenderThemeHandler extends DefaultHandler { throws SAXException { String use = attributes.getValue("use"); - Line style = null; + LineStyle style = null; if (use != null) { - style = (Line) mStyles.get(LINE_STYLE + use); + style = (LineStyle) mStyles.get(LINE_STYLE + use); if (style == null) { log.debug("missing line style 'use': " + use); return; } } - Line line = createLine(style, localName, attributes, mLevel++, false); + LineStyle line = createLine(style, localName, attributes, mLevels++, false); if (isStyle) { mStyles.put(LINE_STYLE + line.style, line); } else { - mCurrentRule.addRenderingInstruction(line); + mCurrentRule.addStyle(line); // Note 'outline' will not be inherited, it's just a // shorcut to add the outline RenderInstruction. addOutline(attributes.getValue("outline")); @@ -320,53 +325,24 @@ public class RenderThemeHandler extends DefaultHandler { /** * @param line * optional: line style defaults - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. * @param level * the drawing level of this instruction. * @param isOutline * is outline layer * @return a new Line with the given rendering attributes. */ - private static Line createLine(Line line, String elementName, Attributes attributes, + private LineStyle createLine(LineStyle line, String elementName, Attributes attributes, int level, boolean isOutline) { - - // Style name - String style = null; - float width = 0; - Cap cap = Cap.ROUND; - - // Extras - int fade = -1; - boolean fixed = false; - float blur = 0; - - // Stipple - int stipple = 0; - float stippleWidth = 1; - - int color = Color.TRANSPARENT; - int stippleColor = Color.BLACK; - - if (line != null) { - color = line.color; - fixed = line.fixed; - fade = line.fade; - cap = line.cap; - blur = line.blur; - stipple = line.stipple; - stippleColor = line.stippleColor; - stippleWidth = line.stippleWidth; - } + LineBuilder b = mLineBuilder.set(line); + b.isOutline(isOutline); + b.level(level); for (int i = 0; i < attributes.getLength(); ++i) { String name = attributes.getLocalName(i); String value = attributes.getValue(i); if ("id".equals(name)) - style = value; + b.style = value; else if ("src".equals(name)) ;// src = value; @@ -378,34 +354,43 @@ public class RenderThemeHandler extends DefaultHandler { ;// ignore else if ("stroke".equals(name)) - color = Color.parseColor(value); - - else if ("width".equals(name) || "stroke-width".equals(name)) - width = Float.parseFloat(value); + b.color(value); + else if ("width".equals(name) || "stroke-width".equals(name)) { + float width = parseFloat(value); + if (line == null) { + validateNonNegative("width", width); + } else { + /* use stroke width relative to 'line' */ + width += line.width; + if (width <= 0) + width = 1; + } + b.width = width; + } else if ("cap".equals(name) || "stroke-linecap".equals(name)) - cap = Cap.valueOf(value.toUpperCase()); + b.cap = Cap.valueOf(value.toUpperCase()); else if ("fix".equals(name)) - fixed = Boolean.parseBoolean(value); + b.fixed = parseBoolean(value); else if ("stipple".equals(name)) - stipple = Integer.parseInt(value); + b.stipple = parseInt(value); else if ("stipple-stroke".equals(name)) - stippleColor = Color.parseColor(value); + b.stippleColor(value); else if ("stipple-width".equals(name)) - stippleWidth = Float.parseFloat(value); + b.stippleWidth = parseFloat(value); else if ("fade".equals(name)) - fade = Integer.parseInt(value); + b.fadeScale = Integer.parseInt(value); else if ("min".equals(name)) ; //min = Float.parseFloat(value); else if ("blur".equals(name)) - blur = Float.parseFloat(value); + b.blur = parseFloat(value); else if ("style".equals(name)) ; // ignore @@ -416,92 +401,49 @@ public class RenderThemeHandler extends DefaultHandler { else logUnknownAttribute(elementName, name, value, i); } - - // inherit properties from 'line' - if (line != null) { - // use stroke width relative to 'line' - width = line.width + width; - if (width <= 0) - width = 1; - - } else if (!isOutline) { - validateLine(width); - } - - return new Line(level, style, color, width, cap, fixed, - stipple, stippleColor, stippleWidth, - fade, blur, isOutline); - } - - private static void validateLine(float strokeWidth) { - if (strokeWidth < 0) - throw new ThemeException("width must not be negative: " + strokeWidth); + return b.build(); } private void handleAreaElement(String localName, Attributes attributes, boolean isStyle) throws SAXException { String use = attributes.getValue("use"); - Area style = null; + AreaStyle style = null; if (use != null) { - style = (Area) mStyles.get(AREA_STYLE + use); + style = (AreaStyle) mStyles.get(AREA_STYLE + use); if (style == null) { log.debug("missing area style 'use': " + use); return; } } - Area area = createArea(style, localName, attributes, mLevel); - mLevel += 2; + AreaStyle area = createArea(style, localName, attributes, mLevels); + mLevels += 2; if (isStyle) { mStyles.put(AREA_STYLE + area.style, area); } else { - mCurrentRule.addRenderingInstruction(area); + mCurrentRule.addStyle(area); } } /** - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. - * @param level - * the drawing level of this instruction. * @return a new Area with the given rendering attributes. */ - private static Area createArea(Area area, String elementName, Attributes attributes, int level) { + private AreaStyle createArea(AreaStyle area, String elementName, Attributes attributes, + int level) { + AreaBuilder b = mAreaBuilder.set(area); + b.level(level); + String src = null; - int fill = Color.BLACK; - int stroke = Color.TRANSPARENT; - float strokeWidth = 1; - int fade = -1; - int blend = -1; - int blendFill = Color.TRANSPARENT; - String style = null; - - TextureItem texture = null; - - if (area != null) { - fill = area.color; - blend = area.blend; - blendFill = area.blendColor; - fade = area.fade; - // TODO texture = area.texture - - if (area.outline != null) { - stroke = area.outline.color; - strokeWidth = area.outline.width; - } - } for (int i = 0; i < attributes.getLength(); ++i) { String name = attributes.getLocalName(i); String value = attributes.getValue(i); if ("id".equals(name)) - style = value; + b.style = value; else if ("use".equals(name)) ;// ignore @@ -510,47 +452,46 @@ public class RenderThemeHandler extends DefaultHandler { src = value; else if ("fill".equals(name)) - fill = Color.parseColor(value); + b.color(value); else if ("stroke".equals(name)) - stroke = Color.parseColor(value); + b.outlineColor(value); - else if ("stroke-width".equals(name)) - strokeWidth = Float.parseFloat(value); + else if ("stroke-width".equals(name)) { + float strokeWidth = Float.parseFloat(value); + validateNonNegative("stroke-width", strokeWidth); + b.outlineWidth = strokeWidth; - else if ("fade".equals(name)) - fade = Integer.parseInt(value); + } else if ("fade".equals(name)) + b.fadeScale = Integer.parseInt(value); else if ("blend".equals(name)) - blend = Integer.parseInt(value); + b.blendScale = Integer.parseInt(value); else if ("blend-fill".equals(name)) - blendFill = Color.parseColor(value); + b.blendColor(value); else logUnknownAttribute(elementName, name, value, i); } - validateLine(strokeWidth); - if (src != null) { try { - Bitmap b = CanvasAdapter.g.loadBitmapAsset(src); - if (b != null) - texture = new TextureItem(b, true); + Bitmap bitmap = CanvasAdapter.g.loadBitmapAsset(src); + if (bitmap != null) + b.texture = new TextureItem(bitmap, true); } catch (Exception e) { log.debug(e.getMessage()); } } - return new Area(style, fill, stroke, strokeWidth, fade, level, blend, - blendFill, texture); + return b.build(); } private void addOutline(String style) { if (style != null) { - Line line = (Line) mStyles.get(OUTLINE_STYLE + style); + LineStyle line = (LineStyle) mStyles.get(OUTLINE_STYLE + style); if (line != null && line.outline) - mCurrentRule.addRenderingInstruction(line); + mCurrentRule.addStyle(line); else log.debug("BUG not an outline style: " + style); } @@ -566,11 +507,10 @@ public class RenderThemeHandler extends DefaultHandler { if ("img".equals(name)) { img = value; } else { - RenderThemeHandler.logUnknownAttribute(elementName, name, value, i); + XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); } } - if (img == null) - throw new ThemeException("missing attribute 'img' for element: " + elementName); + validateExists("img", img, elementName); Bitmap bitmap = CanvasAdapter.g.loadBitmapAsset(IMG_PATH + img); mTextureAtlas = new TextureAtlas(bitmap); @@ -595,12 +535,11 @@ public class RenderThemeHandler extends DefaultHandler { Integer.parseInt(pos[3])); } } else { - RenderThemeHandler.logUnknownAttribute(elementName, name, value, i); + XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); } } - if (regionName == null || r == null) - throw new ThemeException("missing attribute 'id' or 'rect' for element: " - + elementName); + validateExists("id", regionName, elementName); + validateExists("pos", r, elementName); mTextureAtlas.addTextureRegion(regionName.intern(), r); } @@ -652,7 +591,7 @@ public class RenderThemeHandler extends DefaultHandler { mElementStack.push(element); } - static RenderTheme createRenderTheme(String elementName, Attributes attributes) { + private void createRenderTheme(String elementName, Attributes attributes) { Integer version = null; int mapBackground = Color.WHITE; float baseStrokeWidth = 1; @@ -678,115 +617,91 @@ public class RenderThemeHandler extends DefaultHandler { baseTextSize = Float.parseFloat(value); else - RenderThemeHandler.logUnknownAttribute(elementName, name, value, i); + XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); } - if (version == null) - throw new ThemeException("missing attribute version for element:" + elementName); - else if (version.intValue() != RENDER_THEME_VERSION) - throw new ThemeException("invalid render theme version:" + version); - else if (baseStrokeWidth < 0) - throw new ThemeException("base-stroke-width must not be negative: " + baseStrokeWidth); - else if (baseTextSize < 0) - throw new ThemeException("base-text-size must not be negative: " + baseTextSize); + validateExists("version", version, elementName); - return new RenderTheme(mapBackground, baseStrokeWidth, baseTextSize); + if (version.intValue() != RENDER_THEME_VERSION) + throw new ThemeException("invalid render theme version:" + + version); + + validateNonNegative("base-stroke-width", baseStrokeWidth); + validateNonNegative("base-test-size", baseTextSize); + + mMapBackground = mapBackground; + mBaseTextSize = baseTextSize; } /** - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. * @param caption * ... * @return a new Text with the given rendering attributes. */ - private Text createText(String elementName, Attributes attributes, boolean caption) { - String textKey = null; - FontFamily fontFamily = FontFamily.DEFAULT; - FontStyle fontStyle = FontStyle.NORMAL; - float fontSize = 0; - int fill = Color.BLACK; - int stroke = Color.BLACK; - float strokeWidth = 0; - String style = null; - float dy = 0; - int priority = Integer.MAX_VALUE; - TextureRegion symbol = null; + private TextStyle createText(String elementName, Attributes attributes, boolean caption) { + TextBuilder b = mTextBuilder.reset(); + + b.caption = caption; for (int i = 0; i < attributes.getLength(); ++i) { String name = attributes.getLocalName(i); String value = attributes.getValue(i); if ("id".equals(name)) - style = value; + b.style = value; else if ("k".equals(name)) - textKey = value.intern(); + b.textKey = value.intern(); else if ("font-family".equals(name)) - fontFamily = FontFamily.valueOf(value.toUpperCase()); + b.fontFamily = FontFamily.valueOf(value.toUpperCase()); else if ("style".equals(name)) - fontStyle = FontStyle.valueOf(value.toUpperCase()); + b.fontStyle = FontStyle.valueOf(value.toUpperCase()); else if ("size".equals(name)) - fontSize = Float.parseFloat(value); + b.fontSize = Float.parseFloat(value); else if ("fill".equals(name)) - fill = Color.parseColor(value); + b.color = Color.parseColor(value); else if ("stroke".equals(name)) - stroke = Color.parseColor(value); + b.stroke = Color.parseColor(value); else if ("stroke-width".equals(name)) - strokeWidth = Float.parseFloat(value); + b.strokeWidth = Float.parseFloat(value); else if ("caption".equals(name)) - caption = Boolean.parseBoolean(value); + b.caption = Boolean.parseBoolean(value); else if ("priority".equals(name)) - priority = Integer.parseInt(value); + b.priority = Integer.parseInt(value); else if ("dy".equals(name)) - dy = Float.parseFloat(value); + // NB: minus.. + b.dy = -Float.parseFloat(value); else if ("symbol".equals(name)) - symbol = getAtlasRegion(value); + b.texture = getAtlasRegion(value); else logUnknownAttribute(elementName, name, value, i); - } - validateText(elementName, textKey, fontSize, strokeWidth); + validateExists("k", b.textKey, elementName); + validateNonNegative("size", b.fontSize); + validateNonNegative("stroke-width", b.strokeWidth); - return new Text(style, textKey, fontFamily, fontStyle, fontSize, fill, stroke, strokeWidth, - dy, caption, symbol, priority); - } - - private static void validateText(String elementName, String textKey, float fontSize, - float strokeWidth) { - if (textKey == null) - throw new ThemeException("missing attribute k for element: " + elementName); - else if (fontSize < 0) - throw new ThemeException("font-size must not be negative: " + fontSize); - else if (strokeWidth < 0) - throw new ThemeException("stroke-width must not be negative: " + strokeWidth); + return b.buildInternal(); } /** - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. * @param level * the drawing level of this instruction. * @return a new Circle with the given rendering attributes. */ - private static Circle createCircle(String elementName, Attributes attributes, int level) { + private static CircleStyle createCircle(String elementName, Attributes attributes, int level) { Float radius = null; boolean scaleRadius = false; int fill = Color.TRANSPARENT; @@ -816,60 +731,17 @@ public class RenderThemeHandler extends DefaultHandler { logUnknownAttribute(elementName, name, value, i); } - validateCircle(elementName, radius, strokeWidth); - return new Circle(radius, scaleRadius, fill, stroke, strokeWidth, level); - } + validateExists("r", radius, elementName); + validateNonNegative("radius", radius); + validateNonNegative("stroke-width", strokeWidth); - private static void validateCircle(String elementName, Float radius, float strokeWidth) { - if (radius == null) - throw new ThemeException("missing attribute r for element: " + elementName); - else if (radius.floatValue() < 0) - throw new ThemeException("radius must not be negative: " + radius); - else if (strokeWidth < 0) - throw new ThemeException("stroke-width must not be negative: " + strokeWidth); + return new CircleStyle(radius, scaleRadius, fill, stroke, strokeWidth, level); } /** - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. - * @return a new LineSymbol with the given rendering attributes. - */ - private static LineSymbol createLineSymbol(String elementName, Attributes attributes) { - String src = null; - boolean alignCenter = false; - boolean repeat = false; - - for (int i = 0; i < attributes.getLength(); ++i) { - String name = attributes.getLocalName(i); - String value = attributes.getValue(i); - - if ("src".equals(name)) - src = value; - - else if ("align-center".equals(name)) - alignCenter = Boolean.parseBoolean(value); - - else if ("repeat".equals(name)) - repeat = Boolean.parseBoolean(value); - - else - logUnknownAttribute(elementName, name, value, i); - } - - validateSymbol(elementName, src); - return new LineSymbol(src, alignCenter, repeat); - } - - /** - * @param elementName - * the name of the XML element. - * @param attributes - * the attributes of the XML element. * @return a new Symbol with the given rendering attributes. */ - private Symbol createSymbol(String elementName, Attributes attributes) { + private SymbolStyle createSymbol(String elementName, Attributes attributes) { String src = null; for (int i = 0; i < attributes.getLength(); ++i) { @@ -882,17 +754,12 @@ public class RenderThemeHandler extends DefaultHandler { logUnknownAttribute(elementName, name, value, i); } - validateSymbol(elementName, src); + validateExists("src", src, elementName); - return new Symbol(getAtlasRegion(src)); + return new SymbolStyle(getAtlasRegion(src)); } - private static void validateSymbol(String elementName, String src) { - if (src == null) - throw new ThemeException("missing attribute src for element: " + elementName); - } - - private Extrusion createExtrusion(String elementName, Attributes attributes, int level) { + private ExtrusionStyle createExtrusion(String elementName, Attributes attributes, int level) { int colorSide = 0; int colorTop = 0; int colorLine = 0; @@ -918,6 +785,18 @@ public class RenderThemeHandler extends DefaultHandler { logUnknownAttribute(elementName, name, value, i); } - return new Extrusion(level, colorSide, colorTop, colorLine, defaultHeight); + return new ExtrusionStyle(level, colorSide, colorTop, colorLine, defaultHeight); + } + + public static void validateNonNegative(String name, float value) { + if (value < 0) + throw new ThemeException(name + " must not be negative: " + + value); + } + + public static void validateExists(String name, Object obj, String elementName) { + if (obj == null) + throw new ThemeException("missing attribute " + name + + " for element: " + elementName); } } diff --git a/vtm/src/org/oscim/theme/rule/Element.java b/vtm/src/org/oscim/theme/rule/Element.java index 5b961953..2a91a24d 100644 --- a/vtm/src/org/oscim/theme/rule/Element.java +++ b/vtm/src/org/oscim/theme/rule/Element.java @@ -1,6 +1,4 @@ -/* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek +/* Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * diff --git a/vtm/src/org/oscim/theme/rule/NegativeRule.java b/vtm/src/org/oscim/theme/rule/NegativeRule.java index 054575ef..ce750aaa 100644 --- a/vtm/src/org/oscim/theme/rule/NegativeRule.java +++ b/vtm/src/org/oscim/theme/rule/NegativeRule.java @@ -18,12 +18,14 @@ package org.oscim.theme.rule; import org.oscim.core.Tag; +import org.oscim.theme.styles.RenderStyle; class NegativeRule extends Rule { final AttributeMatcher mAttributeMatcher; - NegativeRule(int element, int zoom, boolean matchFirst, AttributeMatcher attributeMatcher) { - super(element, zoom, matchFirst); + NegativeRule(int element, int zoom, int selector, AttributeMatcher attributeMatcher, + Rule[] subRules, RenderStyle[] styles) { + super(element, zoom, selector, subRules, styles); mAttributeMatcher = attributeMatcher; } diff --git a/vtm/src/org/oscim/theme/rule/PositiveRule.java b/vtm/src/org/oscim/theme/rule/PositiveRule.java index fb6b15ff..370bcb24 100644 --- a/vtm/src/org/oscim/theme/rule/PositiveRule.java +++ b/vtm/src/org/oscim/theme/rule/PositiveRule.java @@ -18,14 +18,15 @@ package org.oscim.theme.rule; import org.oscim.core.Tag; +import org.oscim.theme.styles.RenderStyle; class PositiveRule extends Rule { final AttributeMatcher mKeyMatcher; final AttributeMatcher mValueMatcher; - PositiveRule(int element, int zoom, boolean matchFirst, AttributeMatcher keyMatcher, - AttributeMatcher valueMatcher) { - super(element, zoom, matchFirst); + PositiveRule(int element, int zoom, int selector, AttributeMatcher keyMatcher, + AttributeMatcher valueMatcher, Rule[] subRules, RenderStyle[] styles) { + super(element, zoom, selector, subRules, styles); if (keyMatcher instanceof AnyMatcher) mKeyMatcher = null; diff --git a/vtm/src/org/oscim/theme/rule/Rule.java b/vtm/src/org/oscim/theme/rule/Rule.java index 16902973..31756ca2 100644 --- a/vtm/src/org/oscim/theme/rule/Rule.java +++ b/vtm/src/org/oscim/theme/rule/Rule.java @@ -1,5 +1,4 @@ /* - * Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). @@ -17,305 +16,138 @@ */ package org.oscim.theme.rule; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Stack; import org.oscim.core.Tag; -import org.oscim.theme.IRenderTheme.ThemeException; -import org.oscim.theme.RenderThemeHandler; import org.oscim.theme.styles.RenderStyle; -import org.xml.sax.Attributes; public abstract class Rule { - private static final Map, AttributeMatcher> MATCHERS_CACHE_KEY = - new HashMap, AttributeMatcher>(); - private static final Map, AttributeMatcher> MATCHERS_CACHE_VALUE = - new HashMap, AttributeMatcher>(); + public final static RenderStyle[] EMPTY_STYLE = new RenderStyle[0]; + public final static Rule[] EMPTY_RULES = new Rule[0]; - private static final String STRING_NEGATION = "~"; - private static final String STRING_EXCLUSIVE = "-"; - private static final String STRING_WILDCARD = "*"; + private final Rule[] subRules; + public final RenderStyle[] styles; - private static Rule createRule(Stack ruleStack, int element, String keys, - String values, byte zoomMin, byte zoomMax, boolean matchFirst) { + private final int zoom; + private final int element; + private final boolean selectFirstMatch; + private final boolean selectWhenMatched; - // zoom-level bitmask - int zoom = 0; - for (int z = zoomMin; z <= zoomMax && z < 32; z++) - zoom |= (1 << z); + Rule(int element, int zoom, int selector, Rule[] subRules, RenderStyle[] styles) { + this.element = element; + this.zoom = zoom; - List keyList = null, valueList = null; - boolean negativeRule = false; - boolean exclusionRule = false; + this.subRules = (subRules == null) ? EMPTY_RULES : subRules; + this.styles = (styles == null) ? EMPTY_STYLE : styles; - AttributeMatcher keyMatcher, valueMatcher = null; - - if (values == null) { - valueMatcher = AnyMatcher.getInstance(); - } else { - valueList = new ArrayList(Arrays.asList(values.split("\\|"))); - if (valueList.remove(STRING_NEGATION)) - negativeRule = true; - else if (valueList.remove(STRING_EXCLUSIVE)) - exclusionRule = true; - else { - valueMatcher = getValueMatcher(valueList); - valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack); - } - } - - if (keys == null) { - if (negativeRule || exclusionRule) { - throw new ThemeException("negative rule requires key"); - } - keyMatcher = AnyMatcher.getInstance(); - } else { - keyList = new ArrayList(Arrays.asList(keys.split("\\|"))); - keyMatcher = getKeyMatcher(keyList); - - if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) { - throw new ThemeException("negative rule requires key"); - } - - if (negativeRule) { - AttributeMatcher m = new NegativeMatcher(keyList, valueList, false); - return new NegativeRule(element, zoom, matchFirst, m); - } else if (exclusionRule) { - AttributeMatcher m = new NegativeMatcher(keyList, valueList, true); - return new NegativeRule(element, zoom, matchFirst, m); - } - - keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack); - } - - return new PositiveRule(element, zoom, matchFirst, keyMatcher, valueMatcher); - } - - private static AttributeMatcher getKeyMatcher(List keyList) { - if (STRING_WILDCARD.equals(keyList.get(0))) { - return AnyMatcher.getInstance(); - } - - AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList); - if (attributeMatcher == null) { - if (keyList.size() == 1) { - attributeMatcher = new SingleKeyMatcher(keyList.get(0)); - } else { - attributeMatcher = new MultiKeyMatcher(keyList); - } - MATCHERS_CACHE_KEY.put(keyList, attributeMatcher); - } - return attributeMatcher; - } - - private static AttributeMatcher getValueMatcher(List valueList) { - if (STRING_WILDCARD.equals(valueList.get(0))) { - return AnyMatcher.getInstance(); - } - - AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList); - if (attributeMatcher == null) { - if (valueList.size() == 1) { - attributeMatcher = new SingleValueMatcher(valueList.get(0)); - } else { - attributeMatcher = new MultiValueMatcher(valueList); - } - MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher); - } - return attributeMatcher; - } - - private static void validate(byte zoomMin, byte zoomMax) { - if (zoomMin < 0) - throw new ThemeException("zoom-min must not be negative: " + zoomMin); - else if (zoomMax < 0) - throw new ThemeException("zoom-max must not be negative: " + zoomMax); - else if (zoomMin > zoomMax) - throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin); - } - - public static Rule create(String elementName, Attributes attributes, Stack ruleStack) { - int element = Element.ANY; - int closed = Closed.ANY; - String keys = null; - String values = null; - byte zoomMin = 0; - byte zoomMax = Byte.MAX_VALUE; - boolean matchFirst = false; - - for (int i = 0; i < attributes.getLength(); ++i) { - String name = attributes.getLocalName(i); - String value = attributes.getValue(i); - - if ("e".equals(name)) { - String val = value.toUpperCase(); - if ("WAY".equals(val)) - element = Element.WAY; - else if ("NODE".equals(val)) - element = Element.NODE; - } else if ("k".equals(name)) { - keys = value; - } else if ("v".equals(name)) { - values = value; - } else if ("closed".equals(name)) { - String val = value.toUpperCase(); - if ("YES".equals(val)) - closed = Closed.YES; - else if ("NO".equals(val)) - closed = Closed.NO; - } else if ("zoom-min".equals(name)) { - zoomMin = Byte.parseByte(value); - } else if ("zoom-max".equals(name)) { - zoomMax = Byte.parseByte(value); - } else if ("select".equals(name)) { - matchFirst = "first".equals(value); - } else { - RenderThemeHandler.logUnknownAttribute(elementName, name, value, i); - } - } - - if (closed == Closed.YES) - element = Element.POLY; - else if (closed == Closed.NO) - element = Element.LINE; - - validate(zoomMin, zoomMax); - - return createRule(ruleStack, element, keys, values, zoomMin, zoomMax, matchFirst); - } - - private Rule[] mSubRules; - private RenderStyle[] mRenderInstructions; - - final int mZoom; - final int mElement; - final boolean mMatchFirst; - - static class Builder { - ArrayList renderInstructions = new ArrayList(4); - ArrayList subRules = new ArrayList(4); - - public void clear() { - renderInstructions.clear(); - renderInstructions = null; - subRules.clear(); - subRules = null; - } - } - - private Builder builder; - - Rule(int type, int zoom, boolean matchFirst) { - builder = new Builder(); - mElement = type; - mZoom = zoom; - mMatchFirst = matchFirst; - } - - public void addRenderingInstruction(RenderStyle renderInstruction) { - builder.renderInstructions.add(renderInstruction); - } - - public void addSubRule(Rule rule) { - builder.subRules.add(rule); + selectFirstMatch = (selector & Selector.FIRST) != 0; + selectWhenMatched = (selector & Selector.WHEN_MATCHED) != 0; } abstract boolean matchesTags(Tag[] tags); - public boolean matchElement(int type, Tag[] tags, int zoomLevel, - List matchingList) { - - if (((mElement & type) != 0) && ((mZoom & zoomLevel) != 0) && (matchesTags(tags))) { + public boolean matchElement(int type, Tag[] tags, int zoomLevel, List result) { + if (((element & type) != 0) && ((zoom & zoomLevel) != 0) && (matchesTags(tags))) { boolean matched = false; - // check subrules - for (Rule subRule : mSubRules) { - if (subRule.matchElement(type, tags, zoomLevel, matchingList) && mMatchFirst) { - matched = true; - break; + if (subRules != EMPTY_RULES) { + if (selectFirstMatch) { + /* only add first matching rule and when-matched rules iff a + * previous rule matched */ + for (Rule r : subRules) { + /* continue if matched xor selectWhenMatch */ + if (matched ^ r.selectWhenMatched) + continue; + + if (r.matchElement(type, tags, zoomLevel, result)) + matched = true; + } + } else { + /* add all rules and when-matched rules iff a previous rule + * matched */ + for (Rule r : subRules) { + if (r.selectWhenMatched && !matched) + continue; + + if (r.matchElement(type, tags, zoomLevel, result)) + matched = true; + } } } - if (!mMatchFirst || matched) { - // add instructions for this rule - for (RenderStyle ri : mRenderInstructions) - matchingList.add(ri); - } + if (styles == EMPTY_STYLE) + /* matched if styles where added */ + return matched; - // this rule did match + /* add instructions for this rule */ + for (RenderStyle ri : styles) + result.add(ri); + + /* this rule did not match */ return true; } - // this rule did not match + /* this rule did not match */ return false; } - public void onComplete() { - MATCHERS_CACHE_KEY.clear(); - MATCHERS_CACHE_VALUE.clear(); + public void dispose() { + for (RenderStyle ri : styles) + ri.dispose(); - mRenderInstructions = new RenderStyle[builder.renderInstructions.size()]; - builder.renderInstructions.toArray(mRenderInstructions); - - mSubRules = new Rule[builder.subRules.size()]; - builder.subRules.toArray(mSubRules); - - builder.clear(); - builder = null; - - for (Rule subRule : mSubRules) - subRule.onComplete(); - } - - public void onDestroy() { - for (RenderStyle ri : mRenderInstructions) - ri.destroy(); - - for (Rule subRule : mSubRules) - subRule.onDestroy(); + for (Rule subRule : subRules) + subRule.dispose(); } public void scaleTextSize(float scaleFactor) { - for (RenderStyle ri : mRenderInstructions) + for (RenderStyle ri : styles) ri.scaleTextSize(scaleFactor); - for (Rule subRule : mSubRules) + + for (Rule subRule : subRules) subRule.scaleTextSize(scaleFactor); } - public void updateInstructions() { - for (RenderStyle ri : mRenderInstructions) + public void updateStyles() { + for (RenderStyle ri : styles) ri.update(); - for (Rule subRule : mSubRules) - subRule.updateInstructions(); + + for (Rule subRule : subRules) + subRule.updateStyles(); } public static class RuleVisitor { - boolean apply(Rule r) { - - for (Rule subRule : r.mSubRules) + public void apply(Rule r) { + for (Rule subRule : r.subRules) this.apply(subRule); + } + } - return true; + public static class TextSizeVisitor extends RuleVisitor { + float scaleFactor = 1; + + public void setScaleFactor(float scaleFactor) { + this.scaleFactor = scaleFactor; + } + + @Override + public void apply(Rule r) { + for (RenderStyle ri : r.styles) + ri.scaleTextSize(scaleFactor); + super.apply(r); } } public static class UpdateVisitor extends RuleVisitor { @Override - boolean apply(Rule r) { - for (RenderStyle ri : r.mRenderInstructions) + public void apply(Rule r) { + for (RenderStyle ri : r.styles) ri.update(); - - return super.apply(r); + super.apply(r); } } - public boolean apply(RuleVisitor v) { - - return v.apply(this); + public void apply(RuleVisitor v) { + v.apply(this); } } diff --git a/vtm/src/org/oscim/theme/rule/RuleBuilder.java b/vtm/src/org/oscim/theme/rule/RuleBuilder.java new file mode 100644 index 00000000..00c3cca0 --- /dev/null +++ b/vtm/src/org/oscim/theme/rule/RuleBuilder.java @@ -0,0 +1,271 @@ +package org.oscim.theme.rule; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.oscim.theme.IRenderTheme.ThemeException; +import org.oscim.theme.XmlThemeBuilder; +import org.oscim.theme.styles.RenderStyle; +import org.xml.sax.Attributes; + +public class RuleBuilder { + boolean positiveRule; + + int zoom; + int element; + int selector; + + AttributeMatcher keyMatcher; + AttributeMatcher valueMatcher; + + ArrayList renderStyles = new ArrayList(4); + ArrayList subRules = new ArrayList(4); + + private static final Map, AttributeMatcher> MATCHERS_CACHE_KEY = + new HashMap, AttributeMatcher>(); + private static final Map, AttributeMatcher> MATCHERS_CACHE_VALUE = + new HashMap, AttributeMatcher>(); + + private static final String STRING_NEGATION = "~"; + private static final String STRING_EXCLUSIVE = "-"; + private static final String STRING_WILDCARD = "*"; + + private static final int SELECT_FIRST = 1 << 0; + private static final int SELECT_WHEN_MATCHED = 1 << 1; + + public RuleBuilder(boolean positive, int element, int zoom, int selector, + AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) { + this.positiveRule = positive; + this.element = element; + this.zoom = zoom; + this.selector = selector; + this.keyMatcher = keyMatcher; + this.valueMatcher = valueMatcher; + } + + public RuleBuilder(boolean positive, AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) { + this.positiveRule = positive; + this.keyMatcher = keyMatcher; + this.valueMatcher = valueMatcher; + } + + public static RuleBuilder create(Stack ruleStack, String keys, String values) { + + List keyList = null, valueList = null; + boolean negativeRule = false; + boolean exclusionRule = false; + + AttributeMatcher keyMatcher, valueMatcher = null; + + if (values == null) { + valueMatcher = AnyMatcher.getInstance(); + } else { + valueList = new ArrayList(Arrays.asList(values.split("\\|"))); + if (valueList.remove(STRING_NEGATION)) + negativeRule = true; + else if (valueList.remove(STRING_EXCLUSIVE)) + exclusionRule = true; + else { + valueMatcher = getValueMatcher(valueList); + valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack); + } + } + + if (keys == null) { + if (negativeRule || exclusionRule) { + throw new ThemeException("negative rule requires key"); + } + keyMatcher = AnyMatcher.getInstance(); + } else { + keyList = new ArrayList(Arrays.asList(keys.split("\\|"))); + keyMatcher = getKeyMatcher(keyList); + + if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) { + throw new ThemeException("negative rule requires key"); + } + + if (negativeRule) { + AttributeMatcher m = new NegativeMatcher(keyList, valueList, false); + return new RuleBuilder(false, m, null); + } else if (exclusionRule) { + AttributeMatcher m = new NegativeMatcher(keyList, valueList, true); + return new RuleBuilder(false, m, null); + } + + keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack); + } + + return new RuleBuilder(true, keyMatcher, valueMatcher); + } + + private static AttributeMatcher getKeyMatcher(List keyList) { + if (STRING_WILDCARD.equals(keyList.get(0))) { + return AnyMatcher.getInstance(); + } + + AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList); + if (attributeMatcher == null) { + if (keyList.size() == 1) { + attributeMatcher = new SingleKeyMatcher(keyList.get(0)); + } else { + attributeMatcher = new MultiKeyMatcher(keyList); + } + MATCHERS_CACHE_KEY.put(keyList, attributeMatcher); + } + return attributeMatcher; + } + + private static AttributeMatcher getValueMatcher(List valueList) { + if (STRING_WILDCARD.equals(valueList.get(0))) { + return AnyMatcher.getInstance(); + } + + AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList); + if (attributeMatcher == null) { + if (valueList.size() == 1) { + attributeMatcher = new SingleValueMatcher(valueList.get(0)); + } else { + attributeMatcher = new MultiValueMatcher(valueList); + } + MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher); + } + return attributeMatcher; + } + + private static void validate(byte zoomMin, byte zoomMax) { + XmlThemeBuilder.validateNonNegative("zoom-min", zoomMin); + XmlThemeBuilder.validateNonNegative("zoom-max", zoomMax); + if (zoomMin > zoomMax) + throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin); + } + + public static RuleBuilder create(String elementName, Attributes attributes, + Stack ruleStack) { + int element = Element.ANY; + int closed = Closed.ANY; + String keys = null; + String values = null; + byte zoomMin = 0; + byte zoomMax = Byte.MAX_VALUE; + int selector = 0; + + for (int i = 0; i < attributes.getLength(); ++i) { + String name = attributes.getLocalName(i); + String value = attributes.getValue(i); + + if ("e".equals(name)) { + String val = value.toUpperCase(); + if ("WAY".equals(val)) + element = Element.WAY; + else if ("NODE".equals(val)) + element = Element.NODE; + } else if ("k".equals(name)) { + keys = value; + } else if ("v".equals(name)) { + values = value; + } else if ("closed".equals(name)) { + String val = value.toUpperCase(); + if ("YES".equals(val)) + closed = Closed.YES; + else if ("NO".equals(val)) + closed = Closed.NO; + } else if ("zoom-min".equals(name)) { + zoomMin = Byte.parseByte(value); + } else if ("zoom-max".equals(name)) { + zoomMax = Byte.parseByte(value); + } else if ("select".equals(name)) { + if ("first".equals(value)) + selector |= SELECT_FIRST; + if ("when-matched".equals(value)) + selector |= SELECT_WHEN_MATCHED; + } else { + XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i); + } + } + + if (closed == Closed.YES) + element = Element.POLY; + else if (closed == Closed.NO) + element = Element.LINE; + + validate(zoomMin, zoomMax); + + RuleBuilder b = create(ruleStack, keys, values); + b.setZoom(zoomMin, zoomMax); + b.element = element; + b.selector = selector; + return b; + } + + public RuleBuilder setZoom(byte zoomMin, byte zoomMax) { + // zoom-level bitmask + zoom = 0; + for (int z = zoomMin; z <= zoomMax && z < 32; z++) + zoom |= (1 << z); + + return this; + } + + public Rule onComplete() { + MATCHERS_CACHE_KEY.clear(); + MATCHERS_CACHE_VALUE.clear(); + + RenderStyle[] styles = null; + Rule[] rules = null; + + if (renderStyles.size() > 0) { + styles = new RenderStyle[renderStyles.size()]; + renderStyles.toArray(styles); + } + + if (subRules.size() > 0) { + rules = new Rule[subRules.size()]; + for (int i = 0; i < rules.length; i++) + rules[i] = subRules.get(i).onComplete(); + } + + if (positiveRule) + return new PositiveRule(element, zoom, selector, keyMatcher, + valueMatcher, rules, styles); + else + return new NegativeRule(element, zoom, selector, keyMatcher, + rules, styles); + } + + public void addStyle(RenderStyle style) { + renderStyles.add(style); + } + + public void addSubRule(RuleBuilder rule) { + subRules.add(rule); + } + + RuleBuilder(boolean positive) { + this.positiveRule = positive; + this.element = Element.ANY; + this.zoom = ~0; + } + + public static RuleBuilder get() { + return new RuleBuilder(true); + } + + public RuleBuilder select(int selector) { + this.selector = selector; + return this; + } + + public RuleBuilder zoom(int zoom) { + this.zoom = zoom; + return this; + } + + public RuleBuilder element(int element) { + this.element = element; + return this; + } +} diff --git a/vtm/src/org/oscim/theme/rule/RuleOptimizer.java b/vtm/src/org/oscim/theme/rule/RuleOptimizer.java index e6bae924..5b74f873 100644 --- a/vtm/src/org/oscim/theme/rule/RuleOptimizer.java +++ b/vtm/src/org/oscim/theme/rule/RuleOptimizer.java @@ -22,12 +22,13 @@ import java.util.Stack; final class RuleOptimizer { private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher, - Stack ruleStack) { + Stack ruleStack) { for (int i = 0, n = ruleStack.size(); i < n; ++i) { - if (ruleStack.get(i) instanceof PositiveRule) { - PositiveRule positiveRule = (PositiveRule) ruleStack.get(i); - if (positiveRule.mKeyMatcher != null - && positiveRule.mKeyMatcher.isCoveredBy(attributeMatcher)) { + if (ruleStack.get(i).positiveRule) { + RuleBuilder positiveRule = ruleStack.get(i); + + if (positiveRule.keyMatcher != null + && positiveRule.keyMatcher.isCoveredBy(attributeMatcher)) { return null; } } @@ -37,13 +38,13 @@ final class RuleOptimizer { } private static AttributeMatcher optimizeValueMatcher( - AttributeMatcher attributeMatcher, Stack ruleStack) { + AttributeMatcher attributeMatcher, Stack ruleStack) { for (int i = 0, n = ruleStack.size(); i < n; ++i) { - if (ruleStack.get(i) instanceof PositiveRule) { - PositiveRule positiveRule = (PositiveRule) ruleStack.get(i); + if (ruleStack.get(i).positiveRule) { + RuleBuilder positiveRule = ruleStack.get(i); - if (positiveRule.mValueMatcher != null - && positiveRule.mValueMatcher.isCoveredBy(attributeMatcher)) { + if (positiveRule.valueMatcher != null + && positiveRule.valueMatcher.isCoveredBy(attributeMatcher)) { return null; } } @@ -53,7 +54,7 @@ final class RuleOptimizer { } static AttributeMatcher optimize(AttributeMatcher attributeMatcher, - Stack ruleStack) { + Stack ruleStack) { if (attributeMatcher instanceof AnyMatcher) return attributeMatcher;// return null; else if (attributeMatcher instanceof NegativeMatcher) { diff --git a/vtm/src/org/oscim/theme/rule/Selector.java b/vtm/src/org/oscim/theme/rule/Selector.java new file mode 100644 index 00000000..9ba12caf --- /dev/null +++ b/vtm/src/org/oscim/theme/rule/Selector.java @@ -0,0 +1,8 @@ +package org.oscim.theme.rule; + +public class Selector { + + public static final int ANY = 0; + public static final int FIRST = 1 << 0; + public static final int WHEN_MATCHED = 1 << 1; +} diff --git a/vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java b/vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java index 12eda8a5..90b26088 100644 --- a/vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java +++ b/vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java @@ -19,10 +19,10 @@ package org.oscim.theme.rule; import org.oscim.core.Tag; -class SingleKeyMatcher implements AttributeMatcher { +public class SingleKeyMatcher implements AttributeMatcher { private final String mKey; - SingleKeyMatcher(String key) { + public SingleKeyMatcher(String key) { mKey = key.intern(); } diff --git a/vtm/src/org/oscim/theme/rule/SingleValueMatcher.java b/vtm/src/org/oscim/theme/rule/SingleValueMatcher.java index 5327bf56..8dc3ef7b 100644 --- a/vtm/src/org/oscim/theme/rule/SingleValueMatcher.java +++ b/vtm/src/org/oscim/theme/rule/SingleValueMatcher.java @@ -19,10 +19,10 @@ package org.oscim.theme.rule; import org.oscim.core.Tag; -class SingleValueMatcher implements AttributeMatcher { +public class SingleValueMatcher implements AttributeMatcher { private final String mValue; - SingleValueMatcher(String value) { + public SingleValueMatcher(String value) { mValue = value.intern(); } diff --git a/vtm/src/org/oscim/theme/styles/Area.java b/vtm/src/org/oscim/theme/styles/Area.java deleted file mode 100644 index aaaa704c..00000000 --- a/vtm/src/org/oscim/theme/styles/Area.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek - * - * 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.styles; - -import org.oscim.backend.canvas.Color; -import org.oscim.renderer.elements.TextureItem; -import org.oscim.theme.IRenderTheme.Callback; - -/** - * Represents a closed polygon on the map. - */ -public final class Area extends RenderStyle { - - public Area(int fill) { - this(0, fill); - } - - public Area(int level, int fill) { - this.level = level; - this.style = ""; - this.fade = -1; - this.blendColor = 0; - this.blend = -1; - this.color = fill; - this.texture = null; - this.outline = null; - } - - public Area(String style, int fill, int stroke, float strokeWidth, - int fade, int level, int blend, int blendFill, TextureItem texture) { - - this.style = style; - this.color = fill; - this.blendColor = blendFill; - this.blend = blend; - this.fade = fade; - this.level = level; - this.texture = texture; - - if (stroke == Color.TRANSPARENT) { - this.outline = null; - return; - } - - this.outline = new Line(level + 1, stroke, strokeWidth); - } - - @Override - public void renderWay(Callback renderCallback) { - renderCallback.renderArea(this, level); - - if (outline != null) - renderCallback.renderWay(outline, level + 1); - } - - private final int level; - public String style; - public final Line outline; - public final int color; - public final int fade; - public final int blendColor; - public final int blend; - public final TextureItem texture; -} diff --git a/vtm/src/org/oscim/theme/styles/AreaLevel.java b/vtm/src/org/oscim/theme/styles/AreaLevel.java deleted file mode 100644 index 31ab5809..00000000 --- a/vtm/src/org/oscim/theme/styles/AreaLevel.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 Hannes Janetzek - * - * 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.styles; - -import org.oscim.theme.IRenderTheme.Callback; - -public class AreaLevel extends RenderStyle { - private final Area area; - private final int level; - - public AreaLevel(Area area, int level) { - this.area = area; - this.level = level; - } - - @Override - public void renderWay(Callback renderCallback) { - renderCallback.renderArea(this.area, level); - if (this.area.outline != null) - renderCallback.renderWay(this.area.outline, level + 1); - } -} diff --git a/vtm/src/org/oscim/theme/styles/AreaStyle.java b/vtm/src/org/oscim/theme/styles/AreaStyle.java new file mode 100644 index 00000000..84e22611 --- /dev/null +++ b/vtm/src/org/oscim/theme/styles/AreaStyle.java @@ -0,0 +1,227 @@ +/* + * Copyright 2013 Hannes Janetzek + * + * 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.styles; + +import static org.oscim.backend.canvas.Color.parseColor; + +import org.oscim.backend.canvas.Color; +import org.oscim.renderer.elements.TextureItem; +import org.oscim.theme.IRenderTheme.Callback; + +public class AreaStyle extends RenderStyle { + + /** Drawing order level */ + private final int level; + + /** Style name */ + public final String style; + + /** Fill color */ + public final int color; + + /** Fade-out zoom-level */ + public final int fadeScale; + + /** Fade to blendColor zoom-level */ + public final int blendColor; + + /** Blend fill color */ + public final int blendScale; + + /** Pattern texture */ + public final TextureItem texture; + + /** Outline */ + public final LineStyle outline; + + public AreaStyle(int color) { + this(0, color); + } + + public AreaStyle(int level, int color) { + this.level = level; + this.style = ""; + this.fadeScale = -1; + this.blendColor = 0; + this.blendScale = -1; + this.color = color; + this.texture = null; + this.outline = null; + } + + public AreaStyle(AreaBuilder b) { + this.level = b.level; + this.style = b.style; + this.fadeScale = b.fadeScale; + this.blendColor = b.blendColor; + this.blendScale = b.blendScale; + this.color = b.color; + this.texture = b.texture; + + if (b.outline != null && + b.outlineColor == b.outline.color && + b.outlineWidth == b.outline.width) { + this.outline = b.outline; + } else if (b.outlineColor != Color.TRANSPARENT) { + this.outline = new LineStyle(-1, b.outlineColor, b.outlineWidth); + } else { + this.outline = null; + } + } + + @Override + public void update() { + super.update(); + + if (outline != null) + outline.update(); + } + + public AreaStyle current() { + return (AreaStyle) (mCurrent == null ? this : mCurrent); + } + + @Override + public void renderWay(Callback renderCallback) { + renderCallback.renderArea(this, level); + + if (outline != null) + renderCallback.renderWay(outline, level + 1); + } + + public static class AreaBuilder { + public int level; + public String style; + public LineStyle outline; + public int color; + public int fadeScale; + public int blendColor; + public int blendScale; + + public int outlineColor; + public float outlineWidth; + + public TextureItem texture; + + public AreaBuilder set(AreaStyle area) { + if (area == null) + return reset(); + + this.level = area.level; + this.style = area.style; + this.fadeScale = area.fadeScale; + this.blendColor = area.blendColor; + this.blendScale = area.blendScale; + this.color = area.color; + this.texture = area.texture; + this.outline = area.outline; + if (area.outline != null) { + this.outlineColor = outline.color; + this.outlineWidth = outline.width; + } else { + outlineColor = Color.TRANSPARENT; + outlineWidth = 1; + } + + return this; + } + + public AreaBuilder style(String name) { + this.style = name; + return this; + } + + public AreaBuilder level(int level) { + this.level = level; + return this; + } + + public AreaBuilder outline(int color, float width) { + this.outlineColor = color; + this.outlineWidth = width; + return this; + } + + public AreaBuilder outlineColor(int color) { + this.outlineColor = color; + return this; + } + + public AreaBuilder outlineColor(String color) { + this.outlineColor = parseColor(color); + return this; + } + + public AreaBuilder outlineWidth(float width) { + this.outlineWidth = width; + return this; + } + + public AreaBuilder color(int color) { + this.color = color; + return this; + } + + public AreaBuilder color(String color) { + this.color = parseColor(color); + return this; + } + + public AreaBuilder blendScale(int zoom) { + this.blendScale = zoom; + return this; + } + + public AreaBuilder blendColor(int color) { + this.blendColor = color; + return this; + } + + public AreaBuilder blendColor(String color) { + this.blendColor = parseColor(color); + return this; + } + + public AreaBuilder texture(TextureItem texture) { + this.texture = texture; + return this; + } + + public AreaBuilder fadeScale(int zoom) { + this.fadeScale = zoom; + return this; + } + + public AreaBuilder reset() { + color = Color.BLACK; + + outlineColor = Color.TRANSPARENT; + outlineWidth = 1; + + fadeScale = -1; + blendScale = -1; + blendColor = Color.TRANSPARENT; + style = null; + texture = null; + return this; + } + + public AreaStyle build() { + return new AreaStyle(this); + } + } +} diff --git a/vtm/src/org/oscim/theme/styles/Circle.java b/vtm/src/org/oscim/theme/styles/CircleStyle.java similarity index 92% rename from vtm/src/org/oscim/theme/styles/Circle.java rename to vtm/src/org/oscim/theme/styles/CircleStyle.java index c8129219..c11eff9e 100644 --- a/vtm/src/org/oscim/theme/styles/Circle.java +++ b/vtm/src/org/oscim/theme/styles/CircleStyle.java @@ -22,7 +22,7 @@ import org.oscim.theme.IRenderTheme.Callback; /** * Represents a round area on the map. */ -public final class Circle extends RenderStyle { +public final class CircleStyle extends RenderStyle { public final int level; @@ -33,7 +33,7 @@ public final class Circle extends RenderStyle { public final boolean scaleRadius; public final float strokeWidth; - public Circle(Float radius, boolean scaleRadius, int fill, int stroke, + public CircleStyle(Float radius, boolean scaleRadius, int fill, int stroke, float strokeWidth, int level) { super(); diff --git a/vtm/src/org/oscim/theme/styles/Extrusion.java b/vtm/src/org/oscim/theme/styles/ExtrusionStyle.java similarity index 93% rename from vtm/src/org/oscim/theme/styles/Extrusion.java rename to vtm/src/org/oscim/theme/styles/ExtrusionStyle.java index a4827347..d96b2d7a 100644 --- a/vtm/src/org/oscim/theme/styles/Extrusion.java +++ b/vtm/src/org/oscim/theme/styles/ExtrusionStyle.java @@ -19,9 +19,9 @@ package org.oscim.theme.styles; import org.oscim.backend.canvas.Color; import org.oscim.theme.IRenderTheme.Callback; -public class Extrusion extends RenderStyle { +public class ExtrusionStyle extends RenderStyle { - public Extrusion(int level, int colorSides, int colorTop, int colorLine, int defaultHeight) { + public ExtrusionStyle(int level, int colorSides, int colorTop, int colorLine, int defaultHeight) { this.colors = new float[16]; fillColors(colorSides, colorTop, colorLine, colors); diff --git a/vtm/src/org/oscim/theme/styles/Line.java b/vtm/src/org/oscim/theme/styles/Line.java deleted file mode 100644 index 15160302..00000000 --- a/vtm/src/org/oscim/theme/styles/Line.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek - * - * 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.styles; - -import org.oscim.backend.canvas.Paint.Cap; -import org.oscim.theme.IRenderTheme.Callback; - -/** - * Represents a polyline on the map. - */ -public final class Line extends RenderStyle { - - private final int level; - - public final String style; - public final float width; - public final int color; - public final Cap cap; - public final boolean outline; - public final boolean fixed; - public final int fade; - public final float blur; - - public final int stipple; - public final int stippleColor; - public final float stippleWidth; - - public Line(int level, String style, int color, float width, - Cap cap, boolean fixed, - int stipple, int stippleColor, float stippleWidth, - int fade, float blur, boolean isOutline) { - - this.level = level; - this.style = style; - this.outline = isOutline; - - // paint = new Paint(Paint.ANTI_ALIAS_FLAG); - // - // if (src != null) { - // Shader shader = BitmapUtils.createBitmapShader(src); - // paint.setShader(shader); - // } - // - // paint.setStyle(Style.STROKE); - // paint.setColor(stroke); - // if (strokeDasharray != null) { - // paint.setPathEffect(new DashPathEffect(strokeDasharray, 0)); - // } - - //GlUtils.changeSaturation(color, 1.02f); - - this.cap = cap; - this.color = color; - this.width = width; - this.fixed = fixed; - - this.stipple = stipple; - this.stippleColor = stippleColor; - this.stippleWidth = stippleWidth; - - this.blur = blur; - this.fade = fade; - } - - public Line(int stroke, float width) { - this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false); - } - - public Line(int level, int stroke, float width) { - this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false); - } - - public Line(int stroke, float width, Cap cap) { - this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false); - } - - @Override - public void renderWay(Callback renderCallback) { - renderCallback.renderWay(this, level); - } -} diff --git a/vtm/src/org/oscim/theme/styles/LineStyle.java b/vtm/src/org/oscim/theme/styles/LineStyle.java new file mode 100644 index 00000000..e9924f5f --- /dev/null +++ b/vtm/src/org/oscim/theme/styles/LineStyle.java @@ -0,0 +1,202 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * Copyright 2013 Hannes Janetzek + * + * 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.styles; + +import static org.oscim.backend.canvas.Color.parseColor; + +import org.oscim.backend.canvas.Color; +import org.oscim.backend.canvas.Paint.Cap; +import org.oscim.theme.IRenderTheme.Callback; + +public final class LineStyle extends RenderStyle { + + final int level; + public final String style; + public final float width; + public final int color; + public final Cap cap; + public final boolean outline; + public final boolean fixed; + public final int fadeScale; + public final float blur; + + public final int stipple; + public final int stippleColor; + public final float stippleWidth; + + private LineStyle(LineBuilder builer) { + this.level = builer.level; + this.style = builer.style; + this.width = builer.width; + this.color = builer.color; + this.cap = builer.cap; + this.outline = builer.outline; + this.fixed = builer.fixed; + this.fadeScale = builer.fadeScale; + this.blur = builer.blur; + this.stipple = builer.stipple; + this.stippleColor = builer.stippleColor; + this.stippleWidth = builer.stippleWidth; + } + + 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) { + + this.level = level; + this.style = style; + this.outline = isOutline; + + this.cap = cap; + this.color = color; + this.width = width; + this.fixed = fixed; + + this.stipple = stipple; + this.stippleColor = stippleColor; + this.stippleWidth = stippleWidth; + + this.blur = blur; + this.fadeScale = fadeScale; + } + + public LineStyle(int stroke, float width) { + this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false); + } + + public LineStyle(int level, int stroke, float width) { + this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false); + } + + public LineStyle(int stroke, float width, Cap cap) { + this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false); + } + + @Override + public void renderWay(Callback renderCallback) { + renderCallback.renderWay(this, level); + } + + public final static class LineBuilder { + public int level; + + public String style; + public float width; + public int color; + public Cap cap; + public boolean outline; + public boolean fixed; + public int fadeScale; + public float blur; + + public int stipple; + public int stippleColor; + public float stippleWidth; + + public LineBuilder set(LineStyle line) { + if (line == null) + return reset(); + this.level = line.level; + this.style = line.style; + this.width = line.width; + this.color = line.color; + this.cap = line.cap; + this.outline = line.outline; + this.fixed = line.fixed; + this.fadeScale = line.fadeScale; + this.blur = line.blur; + this.stipple = line.stipple; + this.stippleColor = line.stippleColor; + this.stippleWidth = line.stippleWidth; + return this; + } + + public LineBuilder reset() { + level = -1; + style = null; + color = Color.BLACK; + cap = Cap.ROUND; + width = 1; + fixed = false; + + fadeScale = -1; + blur = 0; + + stipple = 0; + stippleWidth = 1; + stippleColor = Color.BLACK; + + return this; + } + + public LineBuilder style(String name) { + this.style = name; + return this; + } + + public LineBuilder level(int level) { + this.level = level; + return this; + } + + public LineBuilder color(int color) { + this.color = color; + return this; + } + + public LineBuilder width(float width) { + this.width = width; + return this; + } + + public LineBuilder blur(float blur) { + this.blur = blur; + return this; + } + + public LineBuilder fadeScale(int zoom) { + this.fadeScale = zoom; + return this; + } + + public LineBuilder stippleColor(int color) { + this.stippleColor = color; + return this; + } + + public LineBuilder color(String color) { + this.color = parseColor(color); + return this; + } + + public LineBuilder stippleColor(String color) { + this.stippleColor = parseColor(color); + return this; + } + + public LineBuilder isOutline(boolean outline) { + this.outline = outline; + return this; + } + + public LineStyle build() { + return new LineStyle(this); + } + } +} diff --git a/vtm/src/org/oscim/theme/styles/LineSymbol.java b/vtm/src/org/oscim/theme/styles/LineSymbol.java deleted file mode 100644 index 2c042740..00000000 --- a/vtm/src/org/oscim/theme/styles/LineSymbol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek - * - * 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.styles; - -import org.oscim.theme.IRenderTheme.Callback; - -/** - * Represents an icon along a polyline on the map. - */ -public final class LineSymbol extends RenderStyle { - - public final boolean alignCenter; - // public final Bitmap bitmap; - public final boolean repeat; - public final String bitmap; - - public LineSymbol(String src, boolean alignCenter, boolean repeat) { - super(); - - this.bitmap = src; - // this.bitmap = BitmapUtils.createBitmap(src); - this.alignCenter = alignCenter; - this.repeat = repeat; - } - - @Override - public void renderWay(Callback renderCallback) { - renderCallback.renderWaySymbol(this); - } -} diff --git a/vtm/src/org/oscim/theme/styles/RenderStyle.java b/vtm/src/org/oscim/theme/styles/RenderStyle.java index 2158d35f..21f4a2a3 100644 --- a/vtm/src/org/oscim/theme/styles/RenderStyle.java +++ b/vtm/src/org/oscim/theme/styles/RenderStyle.java @@ -41,7 +41,7 @@ public abstract class RenderStyle { /** * Destroys this RenderInstruction and cleans up all its internal resources. */ - public void destroy() { + public void dispose() { } /** diff --git a/vtm/src/org/oscim/theme/styles/Symbol.java b/vtm/src/org/oscim/theme/styles/SymbolStyle.java similarity index 91% rename from vtm/src/org/oscim/theme/styles/Symbol.java rename to vtm/src/org/oscim/theme/styles/SymbolStyle.java index f9e79215..28000b6f 100644 --- a/vtm/src/org/oscim/theme/styles/Symbol.java +++ b/vtm/src/org/oscim/theme/styles/SymbolStyle.java @@ -23,16 +23,16 @@ import org.oscim.theme.IRenderTheme.Callback; /** * Represents an icon on the map. */ -public final class Symbol extends RenderStyle { +public final class SymbolStyle extends RenderStyle { public final TextureRegion texture; - public Symbol(TextureRegion symbol) { + public SymbolStyle(TextureRegion symbol) { this.texture = symbol; } @Override - public void destroy() { + public void dispose() { } @Override diff --git a/vtm/src/org/oscim/theme/styles/Text.java b/vtm/src/org/oscim/theme/styles/Text.java deleted file mode 100644 index 063b5c4c..00000000 --- a/vtm/src/org/oscim/theme/styles/Text.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2010, 2011, 2012 mapsforge.org - * Copyright 2013 Hannes Janetzek - * - * 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.styles; - -import org.oscim.backend.CanvasAdapter; -import org.oscim.backend.canvas.Paint; -import org.oscim.backend.canvas.Paint.Align; -import org.oscim.backend.canvas.Paint.FontFamily; -import org.oscim.backend.canvas.Paint.FontStyle; -import org.oscim.renderer.atlas.TextureRegion; -import org.oscim.theme.IRenderTheme.Callback; - -/** - * Represents a text along a polyline on the map. - */ -public final class Text extends RenderStyle { - - public final String style; - - public final float fontSize; - public final Paint paint; - public final Paint stroke; - public final String textKey; - - public final boolean caption; - public final float dy; - public final int priority; - - public float fontHeight; - public float fontDescent; - - public final TextureRegion texture; - - public static Text createText(float fontSize, float strokeWidth, int fill, int outline, - boolean billboard) { - - return createText("", fontSize, strokeWidth, fill, outline, billboard); - } - - public static Text createText(String textKey, float fontSize, float strokeWidth, int fill, - int outline, - boolean billboard) { - - Text t = new Text("", - textKey, - FontFamily.DEFAULT, - FontStyle.NORMAL, - fontSize, - fill, - outline, - strokeWidth, - 0, - billboard, - null, - Integer.MAX_VALUE); - - t.fontHeight = t.paint.getFontHeight(); - t.fontDescent = t.paint.getFontDescent(); - - return t; - } - - public Text(String style, String textKey, FontFamily fontFamily, FontStyle fontStyle, - float fontSize, int fill, int outline, float strokeWidth, float dy, boolean caption, - TextureRegion symbol, int priority) { - - this.style = style; - this.textKey = textKey; - this.caption = caption; - this.dy = -dy; - this.priority = priority; - this.texture = symbol; - - paint = CanvasAdapter.g.getPaint(); - paint.setTextAlign(Align.CENTER); - paint.setTypeface(fontFamily, fontStyle); - - paint.setColor(fill); - paint.setTextSize(fontSize); - - if (strokeWidth > 0) { - stroke = CanvasAdapter.g.getPaint(); - stroke.setStyle(Paint.Style.STROKE); - stroke.setTextAlign(Align.CENTER); - stroke.setTypeface(fontFamily, fontStyle); - stroke.setColor(outline); - stroke.setStrokeWidth(strokeWidth); - stroke.setTextSize(fontSize); - } else - stroke = null; - - this.fontSize = fontSize; - - //fontHeight = paint.getFontHeight(); - //fontDescent = paint.getFontDescent(); - } - - @Override - public void renderNode(Callback renderCallback) { - if (caption) - renderCallback.renderPointText(this); - } - - @Override - public void renderWay(Callback renderCallback) { - if (caption) - renderCallback.renderAreaText(this); - else - renderCallback.renderWayText(this); - } - - @Override - public void scaleTextSize(float scaleFactor) { - paint.setTextSize(fontSize * scaleFactor); - if (stroke != null) - stroke.setTextSize(fontSize * scaleFactor); - - fontHeight = paint.getFontHeight(); - fontDescent = paint.getFontDescent(); - } -} diff --git a/vtm/src/org/oscim/theme/styles/TextStyle.java b/vtm/src/org/oscim/theme/styles/TextStyle.java new file mode 100644 index 00000000..6bb9a2bf --- /dev/null +++ b/vtm/src/org/oscim/theme/styles/TextStyle.java @@ -0,0 +1,207 @@ +/* + * Copyright 2013 Hannes Janetzek + * + * 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.styles; + +import org.oscim.backend.CanvasAdapter; +import org.oscim.backend.canvas.Color; +import org.oscim.backend.canvas.Paint; +import org.oscim.backend.canvas.Paint.Align; +import org.oscim.backend.canvas.Paint.FontFamily; +import org.oscim.backend.canvas.Paint.FontStyle; +import org.oscim.renderer.atlas.TextureRegion; +import org.oscim.theme.IRenderTheme.Callback; + +public final class TextStyle extends RenderStyle { + + public static class TextBuilder { + + public String style; + public float fontSize; + + public String textKey; + public boolean caption; + public float dy; + public int priority; + public TextureRegion texture; + public FontFamily fontFamily; + public FontStyle fontStyle; + + public int color; + public int stroke; + public float strokeWidth; + + public TextBuilder reset() { + fontFamily = FontFamily.DEFAULT; + fontStyle = FontStyle.NORMAL; + style = null; + textKey = null; + fontSize = 0; + caption = false; + priority = Integer.MAX_VALUE; + texture = null; + color = Color.BLACK; + stroke = Color.BLACK; + strokeWidth = 0; + dy = 0; + return this; + } + + public TextBuilder() { + reset(); + } + + public TextStyle build() { + TextStyle t = new TextStyle(this); + t.fontHeight = t.paint.getFontHeight(); + t.fontDescent = t.paint.getFontDescent(); + return t; + } + + public TextStyle buildInternal() { + return new TextStyle(this); + } + + public TextBuilder setStyle(String style) { + this.style = style; + return this; + } + + public TextBuilder setFontSize(float fontSize) { + this.fontSize = fontSize; + return this; + } + + public TextBuilder setTextKey(String textKey) { + this.textKey = textKey; + return this; + } + + public TextBuilder setCaption(boolean caption) { + this.caption = caption; + return this; + } + + public TextBuilder setOffsetY(float dy) { + this.dy = dy; + return this; + } + + public TextBuilder setPriority(int priority) { + this.priority = priority; + return this; + } + + public TextBuilder setTexture(TextureRegion texture) { + this.texture = texture; + return this; + } + + public TextBuilder setFontFamily(FontFamily fontFamily) { + this.fontFamily = fontFamily; + return this; + } + + public TextBuilder setFontStyle(FontStyle fontStyle) { + this.fontStyle = fontStyle; + return this; + } + + public TextBuilder setColor(int color) { + this.color = color; + return this; + } + + public TextBuilder setStroke(int stroke) { + this.stroke = stroke; + return this; + } + + public TextBuilder setStrokeWidth(float strokeWidth) { + this.strokeWidth = strokeWidth; + return this; + } + } + + TextStyle(TextBuilder tb) { + this.style = tb.style; + this.textKey = tb.textKey; + this.caption = tb.caption; + this.dy = tb.dy; + this.priority = tb.priority; + this.texture = tb.texture; + + paint = CanvasAdapter.g.getPaint(); + paint.setTextAlign(Align.CENTER); + paint.setTypeface(tb.fontFamily, tb.fontStyle); + + paint.setColor(tb.color); + paint.setTextSize(tb.fontSize); + + if (tb.strokeWidth > 0) { + stroke = CanvasAdapter.g.getPaint(); + stroke.setStyle(Paint.Style.STROKE); + stroke.setTextAlign(Align.CENTER); + stroke.setTypeface(tb.fontFamily, tb.fontStyle); + stroke.setColor(tb.stroke); + stroke.setStrokeWidth(tb.strokeWidth); + stroke.setTextSize(tb.fontSize); + } else + stroke = null; + + this.fontSize = tb.fontSize; + } + + public final String style; + + public final float fontSize; + public final Paint paint; + public final Paint stroke; + public final String textKey; + + public final boolean caption; + public final float dy; + public final int priority; + + public float fontHeight; + public float fontDescent; + + public final TextureRegion texture; + + @Override + public void renderNode(Callback renderCallback) { + if (caption) + renderCallback.renderPointText(this); + } + + @Override + public void renderWay(Callback renderCallback) { + if (caption) + renderCallback.renderAreaText(this); + else + renderCallback.renderWayText(this); + } + + @Override + public void scaleTextSize(float scaleFactor) { + paint.setTextSize(fontSize * scaleFactor); + if (stroke != null) + stroke.setTextSize(fontSize * scaleFactor); + + fontHeight = paint.getFontHeight(); + fontDescent = paint.getFontDescent(); + } +}