diff --git a/docs/Changelog.md b/docs/Changelog.md index bd9626a1..c009485d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -5,7 +5,8 @@ - S3DB layer [#475](https://github.com/mapsforge/vtm/pull/475) - vtm-mvt module with MVT tile decoder [#481](https://github.com/mapsforge/vtm/pull/481) - OpenMapTiles MVT vector tiles [#482](https://github.com/mapsforge/vtm/issues/482) -- Theme styles improvements [#479](https://github.com/mapsforge/vtm/pull/479) +- Render themes: symbols on lines [#495](https://github.com/mapsforge/vtm/issues/495) +- Render themes: styles improvements [#479](https://github.com/mapsforge/vtm/pull/479) - Internal render themes improvements [#488](https://github.com/mapsforge/vtm/pull/488) - Map view roll [#474](https://github.com/mapsforge/vtm/pull/474) - Fling animation improvements [#489](https://github.com/mapsforge/vtm/pull/489) diff --git a/resources/rendertheme.xsd b/resources/rendertheme.xsd index 87c3b91d..ef5453d0 100644 --- a/resources/rendertheme.xsd +++ b/resources/rendertheme.xsd @@ -234,6 +234,9 @@ + + + diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java index bbab31db..8d1ef20c 100644 --- a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java +++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java @@ -123,7 +123,16 @@ public class LabelTileLoaderHook implements TileLoaderThemeHook { LabelTileData ld = get(tile); if (element.type == LINE) { - // TODO + int offset = 0; + for (int i = 0, n = element.index.length; i < n; i++) { + int length = element.index[i]; + if (length < 4) + break; + + WayDecorator.renderSymbol(null, element.points, symbol, + offset, length, ld); + offset += length; + } } else if (element.type == POLY) { PointF centroid = element.labelPosition; if (!Parameters.POLY_SYMBOL) { diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java b/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java index 226eebb6..4a3e4862 100644 --- a/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java +++ b/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java @@ -1,6 +1,7 @@ /* - * Copyright 2010, 2011, 2012 mapsforge.org + * Copyright 2010, 2011, 2012, 2013 mapsforge.org * Copyright 2013 Hannes Janetzek + * Copyright 2018 devemux86 * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -18,13 +19,94 @@ package org.oscim.layers.tile.vector.labeling; import org.oscim.core.Tile; +import org.oscim.renderer.bucket.SymbolItem; import org.oscim.renderer.bucket.TextItem; +import org.oscim.theme.styles.SymbolStyle; import org.oscim.theme.styles.TextStyle; import org.oscim.utils.geom.GeometryUtils; import org.oscim.utils.geom.LineClipper; public final class WayDecorator { + /** + * Mapsforge implementation. + */ + public static void renderSymbol(LineClipper clipper, float[] coordinates, SymbolStyle symbol, + int pos, int len, LabelTileData ld) { + int skipPixels = (int) symbol.repeatStart; + + // get the first way point coordinates + float previousX = coordinates[pos + 0]; + float previousY = coordinates[pos + 1]; + + // draw the symbol on each way segment + float segmentLengthRemaining; + float segmentSkipPercentage; + float theta = 0; + + for (int i = pos; i < pos + len - 2; i += 2) { + // get the current way point coordinates + float currentX = coordinates[i + 2]; + float currentY = coordinates[i + 3]; + + // calculate the length of the current segment (Euclidean distance) + float diffX = currentX - previousX; + float diffY = currentY - previousY; + double segmentLengthInPixel = Math.sqrt(diffX * diffX + diffY * diffY); + segmentLengthRemaining = (float) segmentLengthInPixel; + + while (segmentLengthRemaining - skipPixels > symbol.repeatStart) { + // calculate the percentage of the current segment to skip + segmentSkipPercentage = skipPixels / segmentLengthRemaining; + + // move the previous point forward towards the current point + previousX += diffX * segmentSkipPercentage; + previousY += diffY * segmentSkipPercentage; + + // TODO + /*if (rotate) { + // if we do not rotate theta will be 0, which is correct + theta = (float) Math.atan2(currentY - previousY, currentX - previousX); + }*/ + + float x = previousX; + float y = previousY; + if (x >= 0 && x <= Tile.SIZE && y >= 0 && y <= Tile.SIZE) { + SymbolItem s = SymbolItem.pool.get(); + if (symbol.bitmap != null) + s.set(x, y, symbol.bitmap, 0, true); + else + s.set(x, y, symbol.texture, 0, true); + ld.symbols.push(s); + } + + // check if the symbol should only be rendered once + if (!symbol.repeat) { + return; + } + + // recalculate the distances + diffX = currentX - previousX; + diffY = currentY - previousY; + + // recalculate the remaining length of the current segment + segmentLengthRemaining -= skipPixels; + + // set the amount of pixels to skip before repeating the symbol + skipPixels = (int) symbol.repeatGap; + } + + skipPixels -= segmentLengthRemaining; + if (skipPixels < symbol.repeatStart) { + skipPixels = (int) symbol.repeatStart; + } + + // set the previous way point coordinates for the next loop + previousX = currentX; + previousY = currentY; + } + } + public static void renderText(LineClipper clipper, float[] coordinates, String label, TextStyle text, int pos, int len, LabelTileData ld) { //TextItem items = textItems; @@ -82,7 +164,7 @@ public final class WayDecorator { int last = i; - // calculate the length of the current segment (Euclidian distance) + // calculate the length of the current segment (Euclidean distance) float vx = prevX - curX; float vy = prevY - curY; if (vx == 0 && vy == 0) diff --git a/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java b/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java index 1fcf1dec..3e9ca7b9 100644 --- a/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java +++ b/vtm/src/org/oscim/theme/XmlMapsforgeThemeBuilder.java @@ -1123,6 +1123,15 @@ public class XmlMapsforgeThemeBuilder extends DefaultHandler { else if ("symbol-scaling".equals(name)) ; // no-op + else if ("repeat".equals(name)) + b.repeat(Boolean.parseBoolean(value)); + + else if ("repeat-start".equals(name)) + b.repeatStart = Float.parseFloat(value) * mScale; + + else if ("repeat-gap".equals(name)) + b.repeatGap = Float.parseFloat(value) * mScale; + else logUnknownAttribute(elementName, name, value, i); } diff --git a/vtm/src/org/oscim/theme/XmlThemeBuilder.java b/vtm/src/org/oscim/theme/XmlThemeBuilder.java index b78cda2d..d6217d9f 100644 --- a/vtm/src/org/oscim/theme/XmlThemeBuilder.java +++ b/vtm/src/org/oscim/theme/XmlThemeBuilder.java @@ -1,7 +1,7 @@ /* * Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2013 Hannes Janetzek - * Copyright 2016-2017 devemux86 + * Copyright 2016-2018 devemux86 * Copyright 2016-2017 Longri * Copyright 2016 Andrey Novikov * @@ -1100,6 +1100,15 @@ public class XmlThemeBuilder extends DefaultHandler { else if ("symbol-scaling".equals(name)) ; // no-op + else if ("repeat".equals(name)) + b.repeat(Boolean.parseBoolean(value)); + + else if ("repeat-start".equals(name)) + b.repeatStart = Float.parseFloat(value) * mScale; + + else if ("repeat-gap".equals(name)) + b.repeatGap = Float.parseFloat(value) * mScale; + else logUnknownAttribute(elementName, name, value, i); } diff --git a/vtm/src/org/oscim/theme/styles/SymbolStyle.java b/vtm/src/org/oscim/theme/styles/SymbolStyle.java index e7315ea2..75240945 100644 --- a/vtm/src/org/oscim/theme/styles/SymbolStyle.java +++ b/vtm/src/org/oscim/theme/styles/SymbolStyle.java @@ -1,7 +1,7 @@ /* * Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2013 Hannes Janetzek - * Copyright 2016-2017 devemux86 + * Copyright 2016-2018 devemux86 * Copyright 2017 Longri * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). @@ -27,6 +27,9 @@ import org.oscim.renderer.atlas.TextureRegion; */ public final class SymbolStyle extends RenderStyle { + public static final float REPEAT_START_DEFAULT = 30f; + public static final float REPEAT_GAP_DEFAULT = 200f; + public final Bitmap bitmap; public final TextureRegion texture; public final int hash; @@ -35,6 +38,10 @@ public final class SymbolStyle extends RenderStyle { public final int symbolHeight; public final int symbolPercent; + public final boolean repeat; + public final float repeatStart; + public final float repeatGap; + public SymbolStyle(Bitmap bitmap) { this(bitmap, null, 0); } @@ -55,6 +62,10 @@ public final class SymbolStyle extends RenderStyle { this.symbolWidth = 0; this.symbolHeight = 0; this.symbolPercent = 100; + + this.repeat = false; + this.repeatStart = REPEAT_START_DEFAULT; + this.repeatGap = REPEAT_GAP_DEFAULT; } public SymbolStyle(SymbolBuilder b) { @@ -67,6 +78,10 @@ public final class SymbolStyle extends RenderStyle { this.symbolWidth = b.symbolWidth; this.symbolHeight = b.symbolHeight; this.symbolPercent = b.symbolPercent; + + this.repeat = b.repeat; + this.repeatStart = b.repeatStart; + this.repeatGap = b.repeatGap; } @Override @@ -100,6 +115,10 @@ public final class SymbolStyle extends RenderStyle { public int symbolHeight; public int symbolPercent; + public boolean repeat; + public float repeatStart; + public float repeatGap; + public SymbolBuilder() { } @@ -117,6 +136,10 @@ public final class SymbolStyle extends RenderStyle { this.symbolHeight = symbol.symbolHeight; this.symbolPercent = symbol.symbolPercent; + this.repeat = symbol.repeat; + this.repeatStart = symbol.repeatStart; + this.repeatGap = symbol.repeatGap; + return self(); } @@ -150,6 +173,21 @@ public final class SymbolStyle extends RenderStyle { return self(); } + public T repeat(boolean repeat) { + this.repeat = repeat; + return self(); + } + + public T repeatStart(float repeatStart) { + this.repeatStart = repeatStart; + return self(); + } + + public T repeatGap(float repeatGap) { + this.repeatGap = repeatGap; + return self(); + } + public T reset() { cat = null; @@ -161,6 +199,10 @@ public final class SymbolStyle extends RenderStyle { symbolHeight = 0; symbolPercent = 100; + repeat = false; + repeatStart = REPEAT_START_DEFAULT; + repeatGap = REPEAT_GAP_DEFAULT; + return self(); }