parent
a322768f8a
commit
ca841f5181
resources
vtm-themes/resources/assets/styles
vtm/src/org/oscim
core
layers/tile/vector/labeling
theme
tiling/source/mapfile
utils/geom
@ -145,7 +145,8 @@
|
|||||||
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional" />
|
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional" />
|
||||||
<!-- priority for label placement, 0 = highest priority -->
|
<!-- priority for label placement, 0 = highest priority -->
|
||||||
<xs:attribute name="priority" default="0" type="xs:integer" use="optional" />
|
<xs:attribute name="priority" default="0" type="xs:integer" use="optional" />
|
||||||
|
<!-- polygon area expressed as a ratio to tile area, e.g. 0.1 for 10% of tile area -->
|
||||||
|
<xs:attribute name="area-size" default="0" type="tns:nonNegativeFloat" use="optional" />
|
||||||
<!-- symbol src name in atlas -->
|
<!-- symbol src name in atlas -->
|
||||||
<xs:attribute name="symbol" type="tns:src" use="optional" />
|
<xs:attribute name="symbol" type="tns:src" use="optional" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
@ -260,6 +260,7 @@
|
|||||||
-->
|
-->
|
||||||
<m v="parking" zoom-min="15">
|
<m v="parking" zoom-min="15">
|
||||||
<area fill="#f4f4f4" stroke="#d4d4d4" stroke-width="0.2" />
|
<area fill="#f4f4f4" stroke="#d4d4d4" stroke-width="0.2" />
|
||||||
|
<symbol src="assets:symbols/transport/parking.svg" />
|
||||||
</m>
|
</m>
|
||||||
<m closed="yes" v="fountain">
|
<m closed="yes" v="fountain">
|
||||||
<area fill="#b4cbdc" stroke="#000080" stroke-width="0.15" />
|
<area fill="#b4cbdc" stroke="#000080" stroke-width="0.15" />
|
||||||
@ -401,6 +402,7 @@
|
|||||||
<m e="way">
|
<m e="way">
|
||||||
<m closed="yes" k="natural" v="water">
|
<m closed="yes" k="natural" v="water">
|
||||||
<area use="water" />
|
<area use="water" />
|
||||||
|
<caption k="name" fill="#777744" size="16" stroke="#aaffffff" stroke-width="2.0" area-size="0.4" />
|
||||||
<!--<line use="water:outline" />-->
|
<!--<line use="water:outline" />-->
|
||||||
</m>
|
</m>
|
||||||
|
|
||||||
@ -521,7 +523,18 @@
|
|||||||
<!-- runways areas -->
|
<!-- runways areas -->
|
||||||
<m k="aeroway">
|
<m k="aeroway">
|
||||||
<m closed="yes" v="aerodrome">
|
<m closed="yes" v="aerodrome">
|
||||||
<area fill="#e8ecde" />
|
<m zoom-min="12">
|
||||||
|
<area fill="#e8ecde" />
|
||||||
|
</m>
|
||||||
|
<m zoom-min="12">
|
||||||
|
<caption dy="18" fill="#000000" k="name" priority="5" size="19" stroke="#ffffff"
|
||||||
|
stroke-width="2.0" area-size="0.1"/>
|
||||||
|
</m>
|
||||||
|
<m zoom-max="11">
|
||||||
|
<caption dy="18" fill="#000000" k="ref" priority="5" size="19" stroke="#ffffff"
|
||||||
|
stroke-width="2.0" />
|
||||||
|
</m>
|
||||||
|
<symbol src="assets:symbols/transport/airport.svg" />
|
||||||
</m>
|
</m>
|
||||||
<!-- A place where planes are parked -->
|
<!-- A place where planes are parked -->
|
||||||
<m v="apron">
|
<m v="apron">
|
||||||
@ -554,7 +567,7 @@
|
|||||||
<m zoom-min="17">
|
<m zoom-min="17">
|
||||||
<caption style="bold" fill="#4040ff" k="name" priority="9" size="14"
|
<caption style="bold" fill="#4040ff" k="name" priority="9" size="14"
|
||||||
stroke="#ffffff" stroke-width="2.0" />
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
<caption style="bold" fill="#606060" k="addr:housenumber" priority="10" size="10"
|
<caption style="bold" fill="#606060" k="addr:housenumber" priority="10" size="16"
|
||||||
stroke="#ffffff" stroke-width="2.0" />
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
</m>
|
</m>
|
||||||
</m>
|
</m>
|
||||||
@ -929,7 +942,7 @@
|
|||||||
</m>
|
</m>
|
||||||
|
|
||||||
<m k="highway" v="track">
|
<m k="highway" v="track">
|
||||||
<m k="areay" v="yes">
|
<m k="area" v="yes">
|
||||||
<area fill="#aaff0000" />
|
<area fill="#aaff0000" />
|
||||||
</m>
|
</m>
|
||||||
</m>
|
</m>
|
||||||
@ -984,6 +997,7 @@
|
|||||||
|
|
||||||
<!-- place -->
|
<!-- place -->
|
||||||
<m k="place">
|
<m k="place">
|
||||||
|
<circle radius="5.0" fill="#ff0000"/>
|
||||||
<m v="suburb" zoom-max="14">
|
<m v="suburb" zoom-max="14">
|
||||||
<caption style="italic" fill="#606060" k="name" priority="4" size="17"
|
<caption style="italic" fill="#606060" k="name" priority="4" size="17"
|
||||||
stroke="#ffffff" stroke-width="2.0" />
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
@ -998,7 +1012,7 @@
|
|||||||
</m>
|
</m>
|
||||||
<m v="town">
|
<m v="town">
|
||||||
<caption dy="14" fill="#000000" k="name" priority="2" size="19" stroke="#ffffff"
|
<caption dy="14" fill="#000000" k="name" priority="2" size="19" stroke="#ffffff"
|
||||||
stroke-width="2.0" symbol="assets:symbols/dot_white.svg" />
|
stroke-width="2.0" />
|
||||||
</m>
|
</m>
|
||||||
<m v="city">
|
<m v="city">
|
||||||
<m zoom-min="7">
|
<m zoom-min="7">
|
||||||
@ -1039,7 +1053,7 @@
|
|||||||
<m k="aeroway" v="helipad" zoom-min="16">
|
<m k="aeroway" v="helipad" zoom-min="16">
|
||||||
<symbol src="assets:symbols/transport/helicopter_pad.svg" />
|
<symbol src="assets:symbols/transport/helicopter_pad.svg" />
|
||||||
</m>
|
</m>
|
||||||
<m k="aeroway" v="aerodrome|airport">
|
<m k="aeroway" v="aerodrome|airport" zoom-min="9">
|
||||||
<symbol src="assets:symbols/transport/airport.svg" />
|
<symbol src="assets:symbols/transport/airport.svg" />
|
||||||
</m>
|
</m>
|
||||||
</m>
|
</m>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -411,6 +412,27 @@ public class GeometryBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates geometry area, only polygon outer ring is taken into account.
|
||||||
|
*
|
||||||
|
* @return polygon area, 0 for other geometries
|
||||||
|
*/
|
||||||
|
public float area() {
|
||||||
|
if (isPoint() || isLine() || getNumPoints() < 3)
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
float area = 0f;
|
||||||
|
// use only outer ring
|
||||||
|
int n = index[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < n - 2; i += 2) {
|
||||||
|
area = area + (points[i] * points[i+3]) - (points[i+1] * points[i+2]);
|
||||||
|
}
|
||||||
|
area = area + (points[n-2] * points[1]) - (points[n-1] * points[0]);
|
||||||
|
|
||||||
|
return 0.5f * area;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
int o = 0;
|
int o = 0;
|
||||||
|
@ -33,6 +33,8 @@ public class MapElement extends GeometryBuffer {
|
|||||||
|
|
||||||
public final TagSet tags = new TagSet();
|
public final TagSet tags = new TagSet();
|
||||||
|
|
||||||
|
public PointF labelPosition;
|
||||||
|
|
||||||
public MapElement() {
|
public MapElement() {
|
||||||
super(1024, 16);
|
super(1024, 16);
|
||||||
}
|
}
|
||||||
@ -45,6 +47,10 @@ public class MapElement extends GeometryBuffer {
|
|||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLabelPosition(float x, float y) {
|
||||||
|
labelPosition = new PointF(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MapElement clear() {
|
public MapElement clear() {
|
||||||
layer = 5;
|
layer = 5;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 devemux86
|
* Copyright 2016 devemux86
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -18,6 +19,7 @@ package org.oscim.layers.tile.vector.labeling;
|
|||||||
|
|
||||||
import org.oscim.core.MapElement;
|
import org.oscim.core.MapElement;
|
||||||
import org.oscim.core.PointF;
|
import org.oscim.core.PointF;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
import org.oscim.layers.tile.MapTile;
|
import org.oscim.layers.tile.MapTile;
|
||||||
import org.oscim.layers.tile.vector.VectorTileLayer.TileLoaderThemeHook;
|
import org.oscim.layers.tile.vector.VectorTileLayer.TileLoaderThemeHook;
|
||||||
import org.oscim.renderer.bucket.RenderBuckets;
|
import org.oscim.renderer.bucket.RenderBuckets;
|
||||||
@ -26,6 +28,7 @@ import org.oscim.renderer.bucket.TextItem;
|
|||||||
import org.oscim.theme.styles.RenderStyle;
|
import org.oscim.theme.styles.RenderStyle;
|
||||||
import org.oscim.theme.styles.SymbolStyle;
|
import org.oscim.theme.styles.SymbolStyle;
|
||||||
import org.oscim.theme.styles.TextStyle;
|
import org.oscim.theme.styles.TextStyle;
|
||||||
|
import org.oscim.utils.geom.PolyLabel;
|
||||||
|
|
||||||
import static org.oscim.core.GeometryBuffer.GeometryType.LINE;
|
import static org.oscim.core.GeometryBuffer.GeometryType.LINE;
|
||||||
import static org.oscim.core.GeometryBuffer.GeometryType.POINT;
|
import static org.oscim.core.GeometryBuffer.GeometryType.POINT;
|
||||||
@ -70,23 +73,25 @@ public class LabelTileLoaderHook implements TileLoaderThemeHook {
|
|||||||
offset += length;
|
offset += length;
|
||||||
}
|
}
|
||||||
} else if (element.type == POLY) {
|
} else if (element.type == POLY) {
|
||||||
// TODO place somewhere on polygon
|
|
||||||
String value = element.tags.getValue(text.textKey);
|
String value = element.tags.getValue(text.textKey);
|
||||||
if (value == null || value.length() == 0)
|
if (value == null || value.length() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float x = 0;
|
if (text.areaSize > 0f) {
|
||||||
float y = 0;
|
float area = element.area();
|
||||||
int n = element.index[0];
|
float ratio = area / (Tile.SIZE * Tile.SIZE); // we can't use static as it's recalculated based on dpi
|
||||||
|
if (ratio < text.areaSize)
|
||||||
for (int i = 0; i < n; ) {
|
return false;
|
||||||
x += element.points[i++];
|
|
||||||
y += element.points[i++];
|
|
||||||
}
|
}
|
||||||
x /= (n / 2);
|
|
||||||
y /= (n / 2);
|
|
||||||
|
|
||||||
ld.labels.push(TextItem.pool.get().set(x, y, value, text));
|
PointF label = element.labelPosition;
|
||||||
|
if (label == null)
|
||||||
|
label = PolyLabel.get(element, 5f);
|
||||||
|
|
||||||
|
if (label.x < 0 || label.x > Tile.SIZE || label.y < 0 || label.y > Tile.SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ld.labels.push(TextItem.pool.get().set(label.x, label.y, value, text));
|
||||||
} else if (element.type == POINT) {
|
} else if (element.type == POINT) {
|
||||||
String value = element.tags.getValue(text.textKey);
|
String value = element.tags.getValue(text.textKey);
|
||||||
if (value == null || value.length() == 0)
|
if (value == null || value.length() == 0)
|
||||||
@ -97,7 +102,7 @@ public class LabelTileLoaderHook implements TileLoaderThemeHook {
|
|||||||
ld.labels.push(TextItem.pool.get().set(p.x, p.y, value, text));
|
ld.labels.push(TextItem.pool.get().set(p.x, p.y, value, text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((element.type == POINT) && (style instanceof SymbolStyle)) {
|
} else if (style instanceof SymbolStyle) {
|
||||||
SymbolStyle symbol = (SymbolStyle) style;
|
SymbolStyle symbol = (SymbolStyle) style;
|
||||||
|
|
||||||
if (symbol.bitmap == null && symbol.texture == null)
|
if (symbol.bitmap == null && symbol.texture == null)
|
||||||
@ -105,14 +110,32 @@ public class LabelTileLoaderHook implements TileLoaderThemeHook {
|
|||||||
|
|
||||||
LabelTileData ld = get(tile);
|
LabelTileData ld = get(tile);
|
||||||
|
|
||||||
for (int i = 0, n = element.getNumPoints(); i < n; i++) {
|
if (element.type == POINT) {
|
||||||
PointF p = element.getPoint(i);
|
for (int i = 0, n = element.getNumPoints(); i < n; i++) {
|
||||||
|
PointF p = element.getPoint(i);
|
||||||
|
|
||||||
|
SymbolItem it = SymbolItem.pool.get();
|
||||||
|
if (symbol.bitmap != null)
|
||||||
|
it.set(p.x, p.y, symbol.bitmap, true);
|
||||||
|
else
|
||||||
|
it.set(p.x, p.y, symbol.texture, true);
|
||||||
|
ld.symbols.push(it);
|
||||||
|
}
|
||||||
|
} else if (element.type == LINE) {
|
||||||
|
//TODO: implement
|
||||||
|
} else if (element.type == POLY) {
|
||||||
|
PointF centroid = element.labelPosition;
|
||||||
|
if (centroid == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (centroid.x < 0 || centroid.x > Tile.SIZE || centroid.y < 0 || centroid.y > Tile.SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
SymbolItem it = SymbolItem.pool.get();
|
SymbolItem it = SymbolItem.pool.get();
|
||||||
if (symbol.bitmap != null)
|
if (symbol.bitmap != null)
|
||||||
it.set(p.x, p.y, symbol.bitmap, true);
|
it.set(centroid.x, centroid.y, symbol.bitmap, true);
|
||||||
else
|
else
|
||||||
it.set(p.x, p.y, symbol.texture, true);
|
it.set(centroid.x, centroid.y, symbol.texture, true);
|
||||||
ld.symbols.push(it);
|
ld.symbols.push(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
* Copyright 2016 devemux86
|
* Copyright 2016 devemux86
|
||||||
* Copyright 2016 Longri
|
* Copyright 2016 Longri
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -863,6 +864,9 @@ public class XmlThemeBuilder extends DefaultHandler {
|
|||||||
else if ("priority".equals(name))
|
else if ("priority".equals(name))
|
||||||
b.priority = Integer.parseInt(value);
|
b.priority = Integer.parseInt(value);
|
||||||
|
|
||||||
|
else if ("area-size".equals(name))
|
||||||
|
b.areaSize = Float.parseFloat(value);
|
||||||
|
|
||||||
else if ("dy".equals(name))
|
else if ("dy".equals(name))
|
||||||
// NB: minus..
|
// NB: minus..
|
||||||
b.dy = -Float.parseFloat(value) * CanvasAdapter.dpi / 160;
|
b.dy = -Float.parseFloat(value) * CanvasAdapter.dpi / 160;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
* Copyright 2016 devemux86
|
* Copyright 2016 devemux86
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -36,6 +37,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
public boolean caption;
|
public boolean caption;
|
||||||
public float dy;
|
public float dy;
|
||||||
public int priority;
|
public int priority;
|
||||||
|
public float areaSize;
|
||||||
public Bitmap bitmap;
|
public Bitmap bitmap;
|
||||||
public TextureRegion texture;
|
public TextureRegion texture;
|
||||||
public FontFamily fontFamily;
|
public FontFamily fontFamily;
|
||||||
@ -49,6 +51,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
fontSize = 0;
|
fontSize = 0;
|
||||||
caption = false;
|
caption = false;
|
||||||
priority = Integer.MAX_VALUE;
|
priority = Integer.MAX_VALUE;
|
||||||
|
areaSize = 0f;
|
||||||
bitmap = null;
|
bitmap = null;
|
||||||
texture = null;
|
texture = null;
|
||||||
fillColor = Color.BLACK;
|
fillColor = Color.BLACK;
|
||||||
@ -98,6 +101,11 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T areaSize(float areaSize) {
|
||||||
|
this.areaSize = areaSize;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
public T bitmap(Bitmap bitmap) {
|
public T bitmap(Bitmap bitmap) {
|
||||||
this.bitmap = bitmap;
|
this.bitmap = bitmap;
|
||||||
return self();
|
return self();
|
||||||
@ -126,6 +134,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
fontSize = other.fontSize;
|
fontSize = other.fontSize;
|
||||||
caption = other.caption;
|
caption = other.caption;
|
||||||
priority = other.priority;
|
priority = other.priority;
|
||||||
|
areaSize = other.areaSize;
|
||||||
bitmap = other.bitmap;
|
bitmap = other.bitmap;
|
||||||
texture = other.texture;
|
texture = other.texture;
|
||||||
fillColor = other.fillColor;
|
fillColor = other.fillColor;
|
||||||
@ -141,6 +150,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
this.caption = style.caption;
|
this.caption = style.caption;
|
||||||
this.dy = style.dy;
|
this.dy = style.dy;
|
||||||
this.priority = style.priority;
|
this.priority = style.priority;
|
||||||
|
this.areaSize = style.areaSize;
|
||||||
this.bitmap = style.bitmap;
|
this.bitmap = style.bitmap;
|
||||||
this.texture = style.texture;
|
this.texture = style.texture;
|
||||||
this.fillColor = style.paint.getColor();
|
this.fillColor = style.paint.getColor();
|
||||||
@ -159,6 +169,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
this.caption = tb.caption;
|
this.caption = tb.caption;
|
||||||
this.dy = tb.dy;
|
this.dy = tb.dy;
|
||||||
this.priority = tb.priority;
|
this.priority = tb.priority;
|
||||||
|
this.areaSize = tb.areaSize;
|
||||||
this.bitmap = tb.bitmap;
|
this.bitmap = tb.bitmap;
|
||||||
this.texture = tb.texture;
|
this.texture = tb.texture;
|
||||||
|
|
||||||
@ -193,6 +204,7 @@ public final class TextStyle extends RenderStyle<TextStyle> {
|
|||||||
public final boolean caption;
|
public final boolean caption;
|
||||||
public final float dy;
|
public final float dy;
|
||||||
public final int priority;
|
public final int priority;
|
||||||
|
public final float areaSize;
|
||||||
|
|
||||||
public float fontHeight;
|
public float fontHeight;
|
||||||
public float fontDescent;
|
public float fontDescent;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
* Copyright 2013, 2014 Hannes Janetzek
|
* Copyright 2013, 2014 Hannes Janetzek
|
||||||
* Copyright 2016 devemux86
|
* Copyright 2016 devemux86
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -840,9 +841,11 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
e.tags.add(new Tag(Tag.KEY_REF, str, false));
|
e.tags.add(new Tag(Tag.KEY_REF, str, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0)
|
|
||||||
// labelPosition =
|
int[] labelPosition = null;
|
||||||
readOptionalLabelPosition();
|
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) {
|
||||||
|
labelPosition = readOptionalLabelPosition();
|
||||||
|
}
|
||||||
|
|
||||||
if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) {
|
if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) {
|
||||||
wayDataBlocks = mReadBuffer.readUnsignedInt();
|
wayDataBlocks = mReadBuffer.readUnsignedInt();
|
||||||
@ -870,6 +873,8 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (labelPosition != null && wayDataBlock == 0)
|
||||||
|
e.setLabelPosition(e.points[0] + labelPosition[0], e.points[1] + labelPosition[1]);
|
||||||
mTileProjection.project(e);
|
mTileProjection.project(e);
|
||||||
|
|
||||||
if (!e.tags.containsKey("building"))
|
if (!e.tags.containsKey("building"))
|
||||||
@ -879,6 +884,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
e.simplify(1, true);
|
e.simplify(1, true);
|
||||||
|
|
||||||
e.setLayer(layer);
|
e.setLayer(layer);
|
||||||
|
|
||||||
mapDataSink.process(e);
|
mapDataSink.process(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,14 +892,14 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float[] readOptionalLabelPosition() {
|
private int[] readOptionalLabelPosition() {
|
||||||
float[] labelPosition = new float[2];
|
int[] labelPosition = new int[2];
|
||||||
|
|
||||||
/* get the label position latitude offset (VBE-S) */
|
/* get the label position latitude offset (VBE-S) */
|
||||||
labelPosition[1] = mTileLatitude + mReadBuffer.readSignedInt();
|
labelPosition[1] = mReadBuffer.readSignedInt();
|
||||||
|
|
||||||
/* get the label position longitude offset (VBE-S) */
|
/* get the label position longitude offset (VBE-S) */
|
||||||
labelPosition[0] = mTileLongitude + mReadBuffer.readSignedInt();
|
labelPosition[0] = mReadBuffer.readSignedInt();
|
||||||
|
|
||||||
return labelPosition;
|
return labelPosition;
|
||||||
}
|
}
|
||||||
@ -1021,6 +1027,10 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
indices[idx] = (short) cnt;
|
indices[idx] = (short) cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (e.labelPosition != null) {
|
||||||
|
e.labelPosition.x = projectLon(e.labelPosition.x);
|
||||||
|
e.labelPosition.y = projectLat(e.labelPosition.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
198
vtm/src/org/oscim/utils/geom/PolyLabel.java
Normal file
198
vtm/src/org/oscim/utils/geom/PolyLabel.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 Andrey Novikov
|
||||||
|
* Java implementation of
|
||||||
|
* https://github.com/mapbox/polylabel
|
||||||
|
*
|
||||||
|
* ISC License
|
||||||
|
* Copyright (c) 2016 Mapbox
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||||
|
* with or without fee is hereby granted, provided that the above copyright notice
|
||||||
|
* and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||||
|
* THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||||
|
* IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
package org.oscim.utils.geom;
|
||||||
|
|
||||||
|
import org.oscim.core.GeometryBuffer;
|
||||||
|
import org.oscim.core.PointF;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
public class PolyLabel {
|
||||||
|
private static float SQRT2 = (float) Math.sqrt(2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns pole of inaccessibility, the most distant internal point from the polygon outline.
|
||||||
|
* @param polygon polygon geometry
|
||||||
|
* @param precision calculation precision
|
||||||
|
* @return optimal label placement point
|
||||||
|
*/
|
||||||
|
public static PointF get(GeometryBuffer polygon, float precision) {
|
||||||
|
// find the bounding box of the outer ring
|
||||||
|
float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, maxX = Float.MIN_VALUE, maxY = Float.MIN_VALUE;
|
||||||
|
|
||||||
|
int n = polygon.index[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ) {
|
||||||
|
float x = polygon.points[i++];
|
||||||
|
float y = polygon.points[i++];
|
||||||
|
if (x < minX) minX = x;
|
||||||
|
if (y < minY) minY = y;
|
||||||
|
if (x > maxX) maxX = x;
|
||||||
|
if (y > maxY) maxY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float width = maxX - minX;
|
||||||
|
float height = maxY - minY;
|
||||||
|
float cellSize = Math.min(width, height);
|
||||||
|
float h = cellSize / 2;
|
||||||
|
|
||||||
|
// a priority queue of cells in order of their "potential" (max distance to polygon)
|
||||||
|
PriorityQueue<Cell> cellQueue = new PriorityQueue<>(1, new MaxComparator());
|
||||||
|
|
||||||
|
// cover polygon with initial cells
|
||||||
|
for (float x = minX; x < maxX; x += cellSize) {
|
||||||
|
for (float y = minY; y < maxY; y += cellSize) {
|
||||||
|
cellQueue.add(new Cell(x + h, y + h, h, polygon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// take centroid as the first best guess
|
||||||
|
Cell bestCell = getCentroidCell(polygon);
|
||||||
|
|
||||||
|
// special case for rectangular polygons
|
||||||
|
Cell bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
|
||||||
|
if (bboxCell.d > bestCell.d) bestCell = bboxCell;
|
||||||
|
|
||||||
|
while (!cellQueue.isEmpty()) {
|
||||||
|
// pick the most promising cell from the queue
|
||||||
|
Cell cell = cellQueue.remove();
|
||||||
|
|
||||||
|
// update the best cell if we found a better one
|
||||||
|
if (cell.d > bestCell.d)
|
||||||
|
bestCell = cell;
|
||||||
|
|
||||||
|
// do not drill down further if there's no chance of a better solution
|
||||||
|
if (cell.max - bestCell.d <= precision) continue;
|
||||||
|
|
||||||
|
// split the cell into four cells
|
||||||
|
h = cell.h / 2;
|
||||||
|
cellQueue.add(new Cell(cell.x - h, cell.y - h, h, polygon));
|
||||||
|
cellQueue.add(new Cell(cell.x + h, cell.y - h, h, polygon));
|
||||||
|
cellQueue.add(new Cell(cell.x - h, cell.y + h, h, polygon));
|
||||||
|
cellQueue.add(new Cell(cell.x + h, cell.y + h, h, polygon));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PointF(bestCell.x, bestCell.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MaxComparator implements Comparator<Cell>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(Cell a, Cell b) {
|
||||||
|
return Float.compare(b.max, a.max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Cell {
|
||||||
|
final float x;
|
||||||
|
final float y;
|
||||||
|
final float h;
|
||||||
|
final float d;
|
||||||
|
final float max;
|
||||||
|
|
||||||
|
Cell(float x, float y, float h, GeometryBuffer polygon) {
|
||||||
|
this.x = x; // cell center x
|
||||||
|
this.y = y; // cell center y
|
||||||
|
this.h = h; // half the cell size
|
||||||
|
this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
|
||||||
|
this.max = this.d + this.h * SQRT2; // max distance to polygon within a cell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// signed distance from point to polygon outline (negative if point is outside)
|
||||||
|
private static float pointToPolygonDist(float x, float y, GeometryBuffer polygon) {
|
||||||
|
boolean inside = false;
|
||||||
|
float minDistSq = Float.POSITIVE_INFINITY;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < polygon.index.length; k++) {
|
||||||
|
if (polygon.index[k] < 0)
|
||||||
|
break;
|
||||||
|
if (polygon.index[k] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = 0, n = polygon.index[k], j = n - 2; i < n; j = i, i += 2) {
|
||||||
|
float ax = polygon.points[pos+i];
|
||||||
|
float ay = polygon.points[pos+i+1];
|
||||||
|
float bx = polygon.points[pos+j];
|
||||||
|
float by = polygon.points[pos+j+1];
|
||||||
|
|
||||||
|
if (((ay > y) ^ (by > y)) &&
|
||||||
|
(x < (bx - ax) * (y - ay) / (by - ay) + ax)) inside = !inside;
|
||||||
|
|
||||||
|
minDistSq = Math.min(minDistSq, getSegDistSq(x, y, ax, ay, bx, by));
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += polygon.index[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) ((inside ? 1 : -1) * Math.sqrt(minDistSq));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get polygon centroid
|
||||||
|
private static Cell getCentroidCell(GeometryBuffer polygon) {
|
||||||
|
float area = 0f;
|
||||||
|
float x = 0f;
|
||||||
|
float y = 0f;
|
||||||
|
|
||||||
|
for (int i = 0, n = polygon.index[0], j = n - 2; i < n; j = i, i += 2) {
|
||||||
|
float ax = polygon.points[i];
|
||||||
|
float ay = polygon.points[i+1];
|
||||||
|
float bx = polygon.points[j];
|
||||||
|
float by = polygon.points[j+1];
|
||||||
|
float f = ax * by - bx * ay;
|
||||||
|
x += (ax + bx) * f;
|
||||||
|
y += (ay + by) * f;
|
||||||
|
area += f * 3;
|
||||||
|
}
|
||||||
|
return new Cell(x / area, y / area, 0f, polygon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get squared distance from a point to a segment
|
||||||
|
private static float getSegDistSq(float px, float py, float ax, float ay, float bx, float by) {
|
||||||
|
|
||||||
|
float x = ax;
|
||||||
|
float y = ay;
|
||||||
|
float dx = bx - x;
|
||||||
|
float dy = by - y;
|
||||||
|
|
||||||
|
if (dx != 0f || dy != 0f) {
|
||||||
|
|
||||||
|
float t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (t > 1) {
|
||||||
|
x = bx;
|
||||||
|
y = by;
|
||||||
|
|
||||||
|
} else if (t > 0) {
|
||||||
|
x += dx * t;
|
||||||
|
y += dy * t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = px - x;
|
||||||
|
dy = py - y;
|
||||||
|
|
||||||
|
return dx * dx + dy * dy;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user