kopia lustrzana https://github.com/onthegomap/planetiler
Encode OSM node/way/relation in vector tile feature id (#826)
rodzic
07afc77fbb
commit
db0eb8afb8
|
|
@ -64,7 +64,11 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
|
|||
* @return a feature that can be configured further.
|
||||
*/
|
||||
public Feature geometry(String layer, Geometry geometry) {
|
||||
Feature feature = new Feature(layer, geometry, source.id());
|
||||
// TODO args could also provide a list of source IDs to put into slot 4, 5, 6, etc..
|
||||
// to differentiate between other sources besides just OSM and "other"
|
||||
long vectorTileId = config.featureSourceIdMultiplier() < 4 ? source.id() :
|
||||
source.vectorTileFeatureId(config.featureSourceIdMultiplier());
|
||||
Feature feature = new Feature(layer, geometry, vectorTileId);
|
||||
output.add(feature);
|
||||
return feature;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,7 +445,11 @@ public class Arguments {
|
|||
*/
|
||||
public int getInteger(String key, String description, int defaultValue) {
|
||||
String value = getArg(key, Integer.toString(defaultValue));
|
||||
int parsed = Integer.parseInt(value);
|
||||
int parsed = switch (value.toLowerCase(Locale.ROOT)) {
|
||||
case "false" -> 0;
|
||||
case "true" -> defaultValue;
|
||||
default -> Integer.parseInt(value);
|
||||
};
|
||||
logArgValue(key, description, parsed);
|
||||
return parsed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ public record PlanetilerConfig(
|
|||
Path tmpDir,
|
||||
Path tileWeights,
|
||||
double maxPointBuffer,
|
||||
boolean logJtsExceptions
|
||||
boolean logJtsExceptions,
|
||||
int featureSourceIdMultiplier
|
||||
) {
|
||||
|
||||
public static final int MIN_MINZOOM = 0;
|
||||
|
|
@ -213,7 +214,11 @@ public record PlanetilerConfig(
|
|||
"clients that handle label collisions across tiles (most web and native clients). NOTE: Do not reduce if you need to support " +
|
||||
"raster tile rendering",
|
||||
Double.POSITIVE_INFINITY),
|
||||
arguments.getBoolean("log_jts_exceptions", "Emit verbose details to debug JTS geometry errors", false)
|
||||
arguments.getBoolean("log_jts_exceptions", "Emit verbose details to debug JTS geometry errors", false),
|
||||
arguments.getInteger("feature_source_id_multiplier",
|
||||
"Set vector tile feature IDs to (featureId * thisValue) + sourceId " +
|
||||
"where sourceId is 1 for OSM nodes, 2 for ways, 3 for relations, and 0 for other sources. Set to false to disable.",
|
||||
10)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -320,6 +320,10 @@ public abstract class SourceFeature implements WithTags, WithGeometryType {
|
|||
return id;
|
||||
}
|
||||
|
||||
/** By default, the feature id is taken as-is from the input data source id. */
|
||||
public long vectorTileFeatureId(int multiplier) {
|
||||
return multiplier * id;
|
||||
}
|
||||
|
||||
/** Returns true if this element has any OSM relation info. */
|
||||
public boolean hasRelationInfo() {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public interface OsmElement extends WithTags {
|
|||
Type type();
|
||||
|
||||
enum Type {
|
||||
OTHER,
|
||||
NODE,
|
||||
WAY,
|
||||
RELATION
|
||||
|
|
@ -46,7 +47,7 @@ public interface OsmElement extends WithTags {
|
|||
|
||||
@Override
|
||||
public Type type() {
|
||||
return null;
|
||||
return Type.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -644,6 +644,16 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
|
|||
this.polygon = polygon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long vectorTileFeatureId(int multiplier) {
|
||||
return (id() * multiplier) + switch (originalElement.type()) {
|
||||
case OTHER -> 0;
|
||||
case NODE -> 1;
|
||||
case WAY -> 2;
|
||||
case RELATION -> 3;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Geometry latLonGeometry() throws GeometryException {
|
||||
return latLonGeom != null ? latLonGeom : (latLonGeom = GeoUtils.worldToLatLonCoords(worldGeometry()));
|
||||
|
|
|
|||
|
|
@ -942,7 +942,7 @@ class PlanetilerTests {
|
|||
feature(newPoint(128, 128), Map.of(
|
||||
"attr", "value",
|
||||
"name", "name value"
|
||||
))
|
||||
), 11)
|
||||
)
|
||||
), results.tiles);
|
||||
}
|
||||
|
|
@ -1031,7 +1031,7 @@ class PlanetilerTests {
|
|||
feature(newLineString(128, 128, 192, 192), Map.of(
|
||||
"attr", "value",
|
||||
"name", "name value"
|
||||
))
|
||||
), 32)
|
||||
)
|
||||
), results.tiles);
|
||||
}
|
||||
|
|
@ -1157,7 +1157,7 @@ class PlanetilerTests {
|
|||
"attr", "value",
|
||||
"name", "name value",
|
||||
"relname", "rel name"
|
||||
))
|
||||
), 173)
|
||||
)
|
||||
), results.tiles);
|
||||
}
|
||||
|
|
@ -1219,20 +1219,21 @@ class PlanetilerTests {
|
|||
|
||||
@Test
|
||||
void testPreprocessOsmNodesAndWays() throws Exception {
|
||||
Set<Long> nodes1 = new HashSet<>();
|
||||
HashMap<Long, Long> nodes1 = new HashMap<>();
|
||||
Set<Long> nodes2 = new HashSet<>();
|
||||
var profile = new Profile.NullProfile() {
|
||||
@Override
|
||||
public void preprocessOsmNode(OsmElement.Node node) {
|
||||
if (node.hasTag("a", "b")) {
|
||||
nodes1.add(node.id());
|
||||
nodes1.put(node.id(), node.id());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOsmWay(OsmElement.Way way) {
|
||||
if (nodes1.contains(way.nodes().get(0))) {
|
||||
nodes2.add(way.nodes().get(0));
|
||||
Long featureId = nodes1.get(way.nodes().get(0));
|
||||
if (featureId != null) {
|
||||
nodes2.add(featureId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,9 @@ public class TestUtils {
|
|||
case UNKNOWN -> throw new IllegalArgumentException("cannot decompress \"UNKNOWN\"");
|
||||
};
|
||||
var decoded = VectorTile.decode(bytes).stream()
|
||||
.map(feature -> feature(decodeSilently(feature.geometry()), feature.layer(), feature.tags())).toList();
|
||||
.map(
|
||||
feature -> feature(decodeSilently(feature.geometry()), feature.layer(), feature.tags(), feature.id()))
|
||||
.toList();
|
||||
tiles.put(tile.coord(), decoded);
|
||||
}
|
||||
return tiles;
|
||||
|
|
@ -490,12 +492,21 @@ public class TestUtils {
|
|||
public record ComparableFeature(
|
||||
GeometryComparision geometry,
|
||||
String layer,
|
||||
Map<String, Object> attrs
|
||||
Map<String, Object> attrs,
|
||||
Long id
|
||||
) {
|
||||
ComparableFeature(
|
||||
GeometryComparision geometry,
|
||||
String layer,
|
||||
Map<String, Object> attrs
|
||||
) {
|
||||
this(geometry, layer, attrs, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == this || (o instanceof ComparableFeature other &&
|
||||
(id == null || other.id == null || id.equals(other.id)) &&
|
||||
geometry.equals(other.geometry) &&
|
||||
attrs.equals(other.attrs) &&
|
||||
(layer == null || other.layer == null || Objects.equals(layer, other.layer)));
|
||||
|
|
@ -507,12 +518,25 @@ public class TestUtils {
|
|||
result = 31 * result + attrs.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
ComparableFeature withId(long id) {
|
||||
return new ComparableFeature(geometry, layer, attrs, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ComparableFeature feature(Geometry geom, String layer, Map<String, Object> attrs, long id) {
|
||||
return new ComparableFeature(new NormGeometry(geom), layer, attrs, id);
|
||||
}
|
||||
|
||||
public static ComparableFeature feature(Geometry geom, String layer, Map<String, Object> attrs) {
|
||||
return new ComparableFeature(new NormGeometry(geom), layer, attrs);
|
||||
}
|
||||
|
||||
public static ComparableFeature feature(Geometry geom, Map<String, Object> attrs, long id) {
|
||||
return new ComparableFeature(new NormGeometry(geom), null, attrs, id);
|
||||
}
|
||||
|
||||
public static ComparableFeature feature(Geometry geom, Map<String, Object> attrs) {
|
||||
return new ComparableFeature(new NormGeometry(geom), null, attrs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,4 +363,16 @@ class ArgumentsTest {
|
|||
assertEquals("val_1", args.getArg("key-1"));
|
||||
assertNull(args.getArg("key-3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFalseForInt() {
|
||||
var args = Arguments.of(Map.of(
|
||||
"true", "true",
|
||||
"false", "false",
|
||||
"3", "3"
|
||||
));
|
||||
assertEquals(1, args.getInteger("true", "", 1));
|
||||
assertEquals(0, args.getInteger("false", "", 1));
|
||||
assertEquals(3, args.getInteger("3", "", 1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue