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();
}