Use some new Java 21 features (#695)

pull/699/head
Michael Barry 2023-10-27 20:29:26 -04:00 zatwierdzone przez GitHub
rodzic 01114cb12c
commit 1be2fca45f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
37 zmienionych plików z 165 dodań i 204 usunięć

Wyświetl plik

@ -47,7 +47,7 @@ public class BenchmarkMbtilesRead {
List<TileCoord> randomCoordsToFetchPerRepetition = new LinkedList<>(); List<TileCoord> randomCoordsToFetchPerRepetition = new LinkedList<>();
do { do {
try (var db = Mbtiles.newReadOnlyDatabase(mbtilesPaths.get(0))) { try (var db = Mbtiles.newReadOnlyDatabase(mbtilesPaths.getFirst())) {
try (var statement = db.connection().prepareStatement(SELECT_RANDOM_COORDS)) { try (var statement = db.connection().prepareStatement(SELECT_RANDOM_COORDS)) {
statement.setInt(1, nrTileReads - randomCoordsToFetchPerRepetition.size()); statement.setInt(1, nrTileReads - randomCoordsToFetchPerRepetition.size());
var rs = statement.executeQuery(); var rs = statement.executeQuery();

Wyświetl plik

@ -22,16 +22,13 @@ import org.locationtech.jts.geom.Geometry;
* feature. * feature.
* <p> * <p>
* For example to add a polygon feature for a lake and a center label point with its name: * For example to add a polygon feature for a lake and a center label point with its name:
* * {@snippet :
* <pre>
* {@code
* featureCollector.polygon("water") * featureCollector.polygon("water")
* .setAttr("class", "lake"); * .setAttr("class", "lake");
* featureCollector.centroid("water_name") * featureCollector.centroid("water_name")
* .setAttr("class", "lake") * .setAttr("class", "lake")
* .setAttr("name", element.getString("name")); * .setAttr("name", element.getString("name"));
* } * }
* </pre>
*/ */
public class FeatureCollector implements Iterable<FeatureCollector.Feature> { public class FeatureCollector implements Iterable<FeatureCollector.Feature> {

Wyświetl plik

@ -124,7 +124,7 @@ public class FeatureMerge {
List<VectorTile.Feature> result = new ArrayList<>(features.size()); List<VectorTile.Feature> result = new ArrayList<>(features.size());
var groupedByAttrs = groupByAttrs(features, result, geometryType); var groupedByAttrs = groupByAttrs(features, result, geometryType);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) { for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
VectorTile.Feature feature1 = groupedFeatures.get(0); VectorTile.Feature feature1 = groupedFeatures.getFirst();
if (groupedFeatures.size() == 1) { if (groupedFeatures.size() == 1) {
result.add(feature1); result.add(feature1);
} else { } else {
@ -158,7 +158,7 @@ public class FeatureMerge {
List<VectorTile.Feature> result = new ArrayList<>(features.size()); List<VectorTile.Feature> result = new ArrayList<>(features.size());
var groupedByAttrs = groupByAttrs(features, result, GeometryType.LINE); var groupedByAttrs = groupByAttrs(features, result, GeometryType.LINE);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) { for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
VectorTile.Feature feature1 = groupedFeatures.get(0); VectorTile.Feature feature1 = groupedFeatures.getFirst();
double lengthLimit = lengthLimitCalculator.apply(feature1.attrs()); double lengthLimit = lengthLimitCalculator.apply(feature1.attrs());
// as a shortcut, can skip line merging only if: // as a shortcut, can skip line merging only if:
@ -300,7 +300,7 @@ public class FeatureMerge {
Collection<List<VectorTile.Feature>> groupedByAttrs = groupByAttrs(features, result, GeometryType.POLYGON); Collection<List<VectorTile.Feature>> groupedByAttrs = groupByAttrs(features, result, GeometryType.POLYGON);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) { for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
List<Polygon> outPolygons = new ArrayList<>(); List<Polygon> outPolygons = new ArrayList<>();
VectorTile.Feature feature1 = groupedFeatures.get(0); VectorTile.Feature feature1 = groupedFeatures.getFirst();
List<Geometry> geometries = new ArrayList<>(groupedFeatures.size()); List<Geometry> geometries = new ArrayList<>(groupedFeatures.size());
for (var feature : groupedFeatures) { for (var feature : groupedFeatures) {
try { try {
@ -331,7 +331,7 @@ public class FeatureMerge {
} }
merged = GeoUtils.snapAndFixPolygon(merged, stats, "merge").reverse(); merged = GeoUtils.snapAndFixPolygon(merged, stats, "merge").reverse();
} else { } else {
merged = polygonGroup.get(0); merged = polygonGroup.getFirst();
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) { if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
continue; continue;
} }
@ -572,5 +572,5 @@ public class FeatureMerge {
return result; return result;
} }
private record WithIndex<T> (T feature, int hilbert) {} private record WithIndex<T>(T feature, int hilbert) {}
} }

Wyświetl plik

@ -263,7 +263,7 @@ public class VectorTile {
lineStrings.add(gf.createLineString(coordSeq)); lineStrings.add(gf.createLineString(coordSeq));
} }
if (lineStrings.size() == 1) { if (lineStrings.size() == 1) {
geometry = lineStrings.get(0); geometry = lineStrings.getFirst();
} else if (lineStrings.size() > 1) { } else if (lineStrings.size() > 1) {
geometry = gf.createMultiLineString(lineStrings.toArray(new LineString[0])); geometry = gf.createMultiLineString(lineStrings.toArray(new LineString[0]));
} }
@ -305,12 +305,12 @@ public class VectorTile {
} }
List<Polygon> polygons = new ArrayList<>(); List<Polygon> polygons = new ArrayList<>();
for (List<LinearRing> rings : polygonRings) { for (List<LinearRing> rings : polygonRings) {
LinearRing shell = rings.get(0); LinearRing shell = rings.getFirst();
LinearRing[] holes = rings.subList(1, rings.size()).toArray(new LinearRing[rings.size() - 1]); LinearRing[] holes = rings.subList(1, rings.size()).toArray(new LinearRing[rings.size() - 1]);
polygons.add(gf.createPolygon(shell, holes)); polygons.add(gf.createPolygon(shell, holes));
} }
if (polygons.size() == 1) { if (polygons.size() == 1) {
geometry = polygons.get(0); geometry = polygons.getFirst();
} }
if (polygons.size() > 1) { if (polygons.size() > 1) {
geometry = gf.createMultiPolygon(GeometryFactory.toPolygonArray(polygons)); geometry = gf.createMultiPolygon(GeometryFactory.toPolygonArray(polygons));
@ -376,7 +376,7 @@ public class VectorTile {
for (VectorTileProto.Tile.Feature feature : layer.getFeaturesList()) { for (VectorTileProto.Tile.Feature feature : layer.getFeaturesList()) {
int tagsCount = feature.getTagsCount(); int tagsCount = feature.getTagsCount();
Map<String, Object> attrs = new HashMap<>(tagsCount / 2); Map<String, Object> attrs = HashMap.newHashMap(tagsCount / 2);
int tagIdx = 0; int tagIdx = 0;
while (tagIdx < feature.getTagsCount()) { while (tagIdx < feature.getTagsCount()) {
String key = keys.get(feature.getTags(tagIdx++)); String key = keys.get(feature.getTags(tagIdx++));
@ -509,20 +509,14 @@ public class VectorTile {
for (Object value : layer.values()) { for (Object value : layer.values()) {
VectorTileProto.Tile.Value.Builder tileValue = VectorTileProto.Tile.Value.newBuilder(); VectorTileProto.Tile.Value.Builder tileValue = VectorTileProto.Tile.Value.newBuilder();
if (value instanceof String stringValue) { switch (value) {
tileValue.setStringValue(stringValue); case String stringValue -> tileValue.setStringValue(stringValue);
} else if (value instanceof Integer intValue) { case Integer intValue -> tileValue.setSintValue(intValue);
tileValue.setSintValue(intValue); case Long longValue -> tileValue.setSintValue(longValue);
} else if (value instanceof Long longValue) { case Float floatValue -> tileValue.setFloatValue(floatValue);
tileValue.setSintValue(longValue); case Double doubleValue -> tileValue.setDoubleValue(doubleValue);
} else if (value instanceof Float floatValue) { case Boolean booleanValue -> tileValue.setBoolValue(booleanValue);
tileValue.setFloatValue(floatValue); case Object other -> tileValue.setStringValue(other.toString());
} else if (value instanceof Double doubleValue) {
tileValue.setDoubleValue(doubleValue);
} else if (value instanceof Boolean booleanValue) {
tileValue.setBoolValue(booleanValue);
} else {
tileValue.setStringValue(value.toString());
} }
tileLayer.addValues(tileValue.build()); tileLayer.addValues(tileValue.build());
} }
@ -1072,31 +1066,32 @@ public class VectorTile {
} }
void accept(Geometry geometry) { void accept(Geometry geometry) {
if (geometry instanceof MultiLineString multiLineString) { switch (geometry) {
for (int i = 0; i < multiLineString.getNumGeometries(); i++) { case MultiLineString multiLineString -> {
encode(((LineString) multiLineString.getGeometryN(i)).getCoordinateSequence(), false, GeometryType.LINE); for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
encode(((LineString) multiLineString.getGeometryN(i)).getCoordinateSequence(), false, GeometryType.LINE);
}
} }
} else if (geometry instanceof Polygon polygon) { case Polygon polygon -> {
LineString exteriorRing = polygon.getExteriorRing(); LineString exteriorRing = polygon.getExteriorRing();
encode(exteriorRing.getCoordinateSequence(), true, GeometryType.POLYGON); encode(exteriorRing.getCoordinateSequence(), true, GeometryType.POLYGON);
for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
for (int i = 0; i < polygon.getNumInteriorRing(); i++) { LineString interiorRing = polygon.getInteriorRingN(i);
LineString interiorRing = polygon.getInteriorRingN(i); encode(interiorRing.getCoordinateSequence(), true, GeometryType.LINE);
encode(interiorRing.getCoordinateSequence(), true, GeometryType.LINE); }
} }
} else if (geometry instanceof MultiPolygon multiPolygon) { case MultiPolygon multiPolygon -> {
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) { for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
accept(multiPolygon.getGeometryN(i)); accept(multiPolygon.getGeometryN(i));
}
} }
} else if (geometry instanceof LineString lineString) { case LineString lineString ->
encode(lineString.getCoordinateSequence(), shouldClosePath(geometry), GeometryType.LINE); encode(lineString.getCoordinateSequence(), shouldClosePath(geometry), GeometryType.LINE);
} else if (geometry instanceof Point point) { case Point point -> encode(point.getCoordinateSequence(), false, GeometryType.POINT);
encode(point.getCoordinateSequence(), false, GeometryType.POINT); case Puntal ignored -> encode(new CoordinateArraySequence(geometry.getCoordinates()), shouldClosePath(geometry),
} else if (geometry instanceof Puntal) {
encode(new CoordinateArraySequence(geometry.getCoordinates()), shouldClosePath(geometry),
geometry instanceof MultiPoint, GeometryType.POINT); geometry instanceof MultiPoint, GeometryType.POINT);
} else { case null -> LOGGER.warn("Null geometry type");
LOGGER.warn("Unrecognized geometry type: " + geometry.getGeometryType()); default -> LOGGER.warn("Unrecognized geometry type: " + geometry.getGeometryType());
} }
} }

Wyświetl plik

@ -95,7 +95,7 @@ class ArrayLongLongMapMmap implements LongLongMap.ParallelWrites {
int minChunks = 1; int minChunks = 1;
int maxChunks = (int) (MAX_BYTES_TO_USE / chunkSize); int maxChunks = (int) (MAX_BYTES_TO_USE / chunkSize);
int targetChunks = (int) (ProcessInfo.getMaxMemoryBytes() * 0.5d / chunkSize); int targetChunks = (int) (ProcessInfo.getMaxMemoryBytes() * 0.5d / chunkSize);
return Math.min(maxChunks, Math.max(minChunks, targetChunks)); return Math.clamp(targetChunks, minChunks, maxChunks);
} }
public void init() { public void init() {

Wyświetl plik

@ -185,7 +185,7 @@ class ExternalMergeSort implements FeatureSort {
.sinkToConsumer("worker", workers, group -> { .sinkToConsumer("worker", workers, group -> {
try { try {
readSemaphore.acquire(); readSemaphore.acquire();
var chunk = group.get(0); var chunk = group.getFirst();
var others = group.stream().skip(1).toList(); var others = group.stream().skip(1).toList();
var toSort = time(reading, () -> { var toSort = time(reading, () -> {
// merge all chunks into first one, and remove the others // merge all chunks into first one, and remove the others

Wyświetl plik

@ -217,24 +217,18 @@ public final class FeatureGroup implements Iterable<FeatureGroup.TileFeatures>,
var attrs = vectorTileFeature.attrs(); var attrs = vectorTileFeature.attrs();
packer.packMapHeader((int) attrs.values().stream().filter(Objects::nonNull).count()); packer.packMapHeader((int) attrs.values().stream().filter(Objects::nonNull).count());
for (Map.Entry<String, Object> entry : attrs.entrySet()) { for (Map.Entry<String, Object> entry : attrs.entrySet()) {
if (entry.getValue() != null) { Object value = entry.getValue();
if (value != null) {
packer.packInt(commonValueStrings.encode(entry.getKey())); packer.packInt(commonValueStrings.encode(entry.getKey()));
Object value = entry.getValue(); packer.packValue(switch (value) {
if (value instanceof String string) { case String string -> ValueFactory.newString(string);
packer.packValue(ValueFactory.newString(string)); case Integer integer -> ValueFactory.newInteger(integer.longValue());
} else if (value instanceof Integer integer) { case Long longValue -> ValueFactory.newInteger(longValue);
packer.packValue(ValueFactory.newInteger(integer.longValue())); case Float floatValue -> ValueFactory.newFloat(floatValue);
} else if (value instanceof Long longValue) { case Double doubleValue -> ValueFactory.newFloat(doubleValue);
packer.packValue(ValueFactory.newInteger(longValue)); case Boolean booleanValue -> ValueFactory.newBoolean(booleanValue);
} else if (value instanceof Float floatValue) { case Object other -> ValueFactory.newString(other.toString());
packer.packValue(ValueFactory.newFloat(floatValue)); });
} else if (value instanceof Double doubleValue) {
packer.packValue(ValueFactory.newFloat(doubleValue));
} else if (value instanceof Boolean booleanValue) {
packer.packValue(ValueFactory.newBoolean(booleanValue));
} else {
packer.packValue(ValueFactory.newString(value.toString()));
}
} }
} }
// Use the same binary format for encoding geometries in output vector tiles. Benchmarking showed // Use the same binary format for encoding geometries in output vector tiles. Benchmarking showed
@ -423,7 +417,7 @@ public final class FeatureGroup implements Iterable<FeatureGroup.TileFeatures>,
GeometryType geomType = decodeGeomType(geomTypeAndScale); GeometryType geomType = decodeGeomType(geomTypeAndScale);
int scale = decodeScale(geomTypeAndScale); int scale = decodeScale(geomTypeAndScale);
int mapSize = unpacker.unpackMapHeader(); int mapSize = unpacker.unpackMapHeader();
Map<String, Object> attrs = new HashMap<>(mapSize); Map<String, Object> attrs = HashMap.newHashMap(mapSize);
for (int i = 0; i < mapSize; i++) { for (int i = 0; i < mapSize; i++) {
String key = commonValueStrings.decode(unpacker.unpackInt()); String key = commonValueStrings.decode(unpacker.unpackInt());
Value v = unpacker.unpackValue(); Value v = unpacker.unpackValue();

Wyświetl plik

@ -34,19 +34,14 @@ public enum DataType implements BiFunction<WithTags, String, Object> {
/** Returns the data type associated with {@code value}, or {@link #GET_TAG} as a fallback. */ /** Returns the data type associated with {@code value}, or {@link #GET_TAG} as a fallback. */
public static DataType typeOf(Object value) { public static DataType typeOf(Object value) {
if (value instanceof String) { return switch (value) {
return GET_STRING; case String ignored -> GET_STRING;
} else if (value instanceof Integer) { case Integer ignored -> GET_INT;
return GET_INT; case Long ignored -> GET_LONG;
} else if (value instanceof Long) { case Double ignored -> GET_DOUBLE;
return GET_LONG; case Boolean ignored -> GET_BOOLEAN;
} else if (value instanceof Double) { default -> GET_TAG;
return GET_DOUBLE; };
} else if (value instanceof Boolean) {
return GET_BOOLEAN;
} else {
return GET_TAG;
}
} }
/** Returns the data type associated with {@code id}, or {@link #GET_TAG} as a fallback. */ /** Returns the data type associated with {@code id}, or {@link #GET_TAG} as a fallback. */

Wyświetl plik

@ -23,12 +23,9 @@ import org.slf4j.LoggerFactory;
* <p> * <p>
* Calling {@code toString()} on any expression will generate code that can be used to recreate an identical copy of the * Calling {@code toString()} on any expression will generate code that can be used to recreate an identical copy of the
* original expression, assuming that the generated code includes: * original expression, assuming that the generated code includes:
* * {@snippet :
* <pre>
* {@code
* import static com.onthegomap.planetiler.expression.Expression.*; * import static com.onthegomap.planetiler.expression.Expression.*;
* } * }
* </pre>
*/ */
// TODO rename to BooleanExpression // TODO rename to BooleanExpression
public interface Expression extends Simplifiable<Expression> { public interface Expression extends Simplifiable<Expression> {
@ -141,14 +138,13 @@ public interface Expression extends Simplifiable<Expression> {
default Expression replace(Predicate<Expression> replace, Expression b) { default Expression replace(Predicate<Expression> replace, Expression b) {
if (replace.test(this)) { if (replace.test(this)) {
return b; return b;
} else if (this instanceof Not not) {
return new Not(not.child.replace(replace, b));
} else if (this instanceof Or or) {
return new Or(or.children.stream().map(child -> child.replace(replace, b)).toList());
} else if (this instanceof And and) {
return new And(and.children.stream().map(child -> child.replace(replace, b)).toList());
} else { } else {
return this; return switch (this) {
case Not(var child) -> new Not(child.replace(replace, b));
case Or(var children) -> new Or(children.stream().map(child -> child.replace(replace, b)).toList());
case And(var children) -> new And(children.stream().map(child -> child.replace(replace, b)).toList());
default -> this;
};
} }
} }
@ -156,14 +152,13 @@ public interface Expression extends Simplifiable<Expression> {
default boolean contains(Predicate<Expression> filter) { default boolean contains(Predicate<Expression> filter) {
if (filter.test(this)) { if (filter.test(this)) {
return true; return true;
} else if (this instanceof Not not) {
return not.child.contains(filter);
} else if (this instanceof Or or) {
return or.children.stream().anyMatch(child -> child.contains(filter));
} else if (this instanceof And and) {
return and.children.stream().anyMatch(child -> child.contains(filter));
} else { } else {
return false; return switch (this) {
case Not(var child) -> child.contains(filter);
case Or(var children) -> children.stream().anyMatch(child -> child.contains(filter));
case And(var children) -> children.stream().anyMatch(child -> child.contains(filter));
default -> false;
};
} }
} }
@ -234,7 +229,7 @@ public interface Expression extends Simplifiable<Expression> {
return TRUE; return TRUE;
} }
if (children.size() == 1) { if (children.size() == 1) {
return children.get(0).simplifyOnce(); return children.getFirst().simplifyOnce();
} }
if (children.contains(FALSE)) { if (children.contains(FALSE)) {
return FALSE; return FALSE;
@ -288,7 +283,7 @@ public interface Expression extends Simplifiable<Expression> {
return FALSE; return FALSE;
} }
if (children.size() == 1) { if (children.size() == 1) {
return children.get(0).simplifyOnce(); return children.getFirst().simplifyOnce();
} }
if (children.contains(TRUE)) { if (children.contains(TRUE)) {
return TRUE; return TRUE;

Wyświetl plik

@ -50,19 +50,15 @@ public record MultiExpression<T> (List<Entry<T>> expressions) implements Simplif
* when a particular key is present on the input. * when a particular key is present on the input.
*/ */
private static boolean mustAlwaysEvaluate(Expression expression) { private static boolean mustAlwaysEvaluate(Expression expression) {
if (expression instanceof Expression.Or or) { return switch (expression) {
return or.children().stream().anyMatch(MultiExpression::mustAlwaysEvaluate); case Expression.Or(var children) -> children.stream().anyMatch(MultiExpression::mustAlwaysEvaluate);
} else if (expression instanceof Expression.And and) { case Expression.And(var children) -> children.stream().allMatch(MultiExpression::mustAlwaysEvaluate);
return and.children().stream().allMatch(MultiExpression::mustAlwaysEvaluate); case Expression.Not(var child) -> !mustAlwaysEvaluate(child);
} else if (expression instanceof Expression.Not not) { case Expression.MatchAny any when any.matchWhenMissing() -> true;
return !mustAlwaysEvaluate(not.child()); case null, default -> !(expression instanceof Expression.MatchAny) &&
} else if (expression instanceof Expression.MatchAny any && any.matchWhenMissing()) { !(expression instanceof Expression.MatchField) &&
return true; !FALSE.equals(expression);
} else { };
return !(expression instanceof Expression.MatchAny) &&
!(expression instanceof Expression.MatchField) &&
!FALSE.equals(expression);
}
} }
/** Calls {@code acceptKey} for every tag that could possibly cause {@code exp} to match an input element. */ /** Calls {@code acceptKey} for every tag that could possibly cause {@code exp} to match an input element. */
@ -176,7 +172,7 @@ public record MultiExpression<T> (List<Entry<T>> expressions) implements Simplif
*/ */
default O getOrElse(WithTags input, O defaultValue) { default O getOrElse(WithTags input, O defaultValue) {
List<O> matches = getMatches(input); List<O> matches = getMatches(input);
return matches.isEmpty() ? defaultValue : matches.get(0); return matches.isEmpty() ? defaultValue : matches.getFirst();
} }
/** /**
@ -184,7 +180,7 @@ public record MultiExpression<T> (List<Entry<T>> expressions) implements Simplif
*/ */
default O getOrElse(Map<String, Object> tags, O defaultValue) { default O getOrElse(Map<String, Object> tags, O defaultValue) {
List<O> matches = getMatches(WithTags.from(tags)); List<O> matches = getMatches(WithTags.from(tags));
return matches.isEmpty() ? defaultValue : matches.get(0); return matches.isEmpty() ? defaultValue : matches.getFirst();
} }
/** Returns true if any expression matches that tags from an input element. */ /** Returns true if any expression matches that tags from an input element. */

Wyświetl plik

@ -281,15 +281,15 @@ public class GeoUtils {
} }
public static Geometry combineLineStrings(List<LineString> lineStrings) { public static Geometry combineLineStrings(List<LineString> lineStrings) {
return lineStrings.size() == 1 ? lineStrings.get(0) : createMultiLineString(lineStrings); return lineStrings.size() == 1 ? lineStrings.getFirst() : createMultiLineString(lineStrings);
} }
public static Geometry combinePolygons(List<Polygon> polys) { public static Geometry combinePolygons(List<Polygon> polys) {
return polys.size() == 1 ? polys.get(0) : createMultiPolygon(polys); return polys.size() == 1 ? polys.getFirst() : createMultiPolygon(polys);
} }
public static Geometry combinePoints(List<Point> points) { public static Geometry combinePoints(List<Point> points) {
return points.size() == 1 ? points.get(0) : createMultiPoint(points); return points.size() == 1 ? points.getFirst() : createMultiPoint(points);
} }
/** /**
@ -383,29 +383,29 @@ public class GeoUtils {
if (lineStrings.isEmpty()) { if (lineStrings.isEmpty()) {
throw new GeometryException("polygon_to_linestring_empty", "No line strings"); throw new GeometryException("polygon_to_linestring_empty", "No line strings");
} else if (lineStrings.size() == 1) { } else if (lineStrings.size() == 1) {
return lineStrings.get(0); return lineStrings.getFirst();
} else { } else {
return createMultiLineString(lineStrings); return createMultiLineString(lineStrings);
} }
} }
private static void getLineStrings(Geometry input, List<LineString> output) throws GeometryException { private static void getLineStrings(Geometry input, List<LineString> output) throws GeometryException {
if (input instanceof LinearRing linearRing) { switch (input) {
output.add(JTS_FACTORY.createLineString(linearRing.getCoordinateSequence())); case LinearRing linearRing -> output.add(JTS_FACTORY.createLineString(linearRing.getCoordinateSequence()));
} else if (input instanceof LineString lineString) { case LineString lineString -> output.add(lineString);
output.add(lineString); case Polygon polygon -> {
} else if (input instanceof Polygon polygon) { getLineStrings(polygon.getExteriorRing(), output);
getLineStrings(polygon.getExteriorRing(), output); for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
for (int i = 0; i < polygon.getNumInteriorRing(); i++) { getLineStrings(polygon.getInteriorRingN(i), output);
getLineStrings(polygon.getInteriorRingN(i), output); }
} }
} else if (input instanceof GeometryCollection gc) { case GeometryCollection gc -> {
for (int i = 0; i < gc.getNumGeometries(); i++) { for (int i = 0; i < gc.getNumGeometries(); i++) {
getLineStrings(gc.getGeometryN(i), output); getLineStrings(gc.getGeometryN(i), output);
}
} }
} else { case null, default -> throw new GeometryException("get_line_strings_bad_type",
throw new GeometryException("get_line_strings_bad_type", "unrecognized geometry type: " + (input == null ? "null" : input.getGeometryType()));
"unrecognized geometry type: " + input.getGeometryType());
} }
} }
@ -416,7 +416,7 @@ public class GeoUtils {
/** Returns a point approximately {@code ratio} of the way from start to end and {@code offset} units to the right. */ /** Returns a point approximately {@code ratio} of the way from start to end and {@code offset} units to the right. */
public static Point pointAlongOffset(LineString lineString, double ratio, double offset) { public static Point pointAlongOffset(LineString lineString, double ratio, double offset) {
int numPoints = lineString.getNumPoints(); int numPoints = lineString.getNumPoints();
int middle = Math.max(0, Math.min(numPoints - 2, (int) (numPoints * ratio))); int middle = Math.clamp((int) (numPoints * ratio), 0, numPoints - 2);
Coordinate a = lineString.getCoordinateN(middle); Coordinate a = lineString.getCoordinateN(middle);
Coordinate b = lineString.getCoordinateN(middle + 1); Coordinate b = lineString.getCoordinateN(middle + 1);
LineSegment segment = new LineSegment(a, b); LineSegment segment = new LineSegment(a, b);
@ -530,7 +530,7 @@ public class GeoUtils {
innerGeometries.add(geom); innerGeometries.add(geom);
} }
} }
return innerGeometries.size() == 1 ? innerGeometries.get(0) : return innerGeometries.size() == 1 ? innerGeometries.getFirst() :
JTS_FACTORY.createGeometryCollection(innerGeometries.toArray(Geometry[]::new)); JTS_FACTORY.createGeometryCollection(innerGeometries.toArray(Geometry[]::new));
} }

Wyświetl plik

@ -19,7 +19,7 @@ import org.locationtech.jts.index.strtree.STRtree;
@ThreadSafe @ThreadSafe
public class PolygonIndex<T> { public class PolygonIndex<T> {
private record GeomWithData<T> (Polygon poly, T data) {} private record GeomWithData<T>(Polygon poly, T data) {}
private final STRtree index = new STRtree(); private final STRtree index = new STRtree();
@ -45,7 +45,7 @@ public class PolygonIndex<T> {
/** Returns the data associated with the first polygon containing {@code point}. */ /** Returns the data associated with the first polygon containing {@code point}. */
public T getOnlyContaining(Point point) { public T getOnlyContaining(Point point) {
List<T> result = getContaining(point); List<T> result = getContaining(point);
return result.isEmpty() ? null : result.get(0); return result.isEmpty() ? null : result.getFirst();
} }
/** Returns the data associated with all polygons containing {@code point}. */ /** Returns the data associated with all polygons containing {@code point}. */
@ -77,7 +77,7 @@ public class PolygonIndex<T> {
List<?> items = index.query(point.getEnvelopeInternal()); List<?> items = index.query(point.getEnvelopeInternal());
// optimization: if there's only one then skip checking contains/distance // optimization: if there's only one then skip checking contains/distance
if (items.size() == 1) { if (items.size() == 1) {
if (items.get(0)instanceof GeomWithData<?> value) { if (items.getFirst() instanceof GeomWithData<?> value) {
@SuppressWarnings("unchecked") T t = (T) value.data; @SuppressWarnings("unchecked") T t = (T) value.data;
return List.of(t); return List.of(t);
} }
@ -108,7 +108,7 @@ public class PolygonIndex<T> {
/** Returns the data associated with a polygon that contains {@code point} or nearest polygon if none are found. */ /** Returns the data associated with a polygon that contains {@code point} or nearest polygon if none are found. */
public T get(Point point) { public T get(Point point) {
List<T> nearests = getContainingOrNearest(point); List<T> nearests = getContainingOrNearest(point);
return nearests.isEmpty() ? null : nearests.get(0); return nearests.isEmpty() ? null : nearests.getFirst();
} }
/** Indexes {@code item} for all polygons contained in {@code geom}. */ /** Indexes {@code item} for all polygons contained in {@code geom}. */

Wyświetl plik

@ -21,11 +21,11 @@ public class TileExtents implements Predicate<TileCoord> {
} }
private static int quantizeDown(double value, int levels) { private static int quantizeDown(double value, int levels) {
return Math.max(0, Math.min(levels, (int) Math.floor(value * levels))); return Math.clamp((int) Math.floor(value * levels), 0, levels);
} }
private static int quantizeUp(double value, int levels) { private static int quantizeUp(double value, int levels) {
return Math.max(0, Math.min(levels, (int) Math.ceil(value * levels))); return Math.clamp((int) Math.ceil(value * levels), 0, levels);
} }
/** Returns a filter to tiles that intersect {@code worldBounds} (specified in world web mercator coordinates). */ /** Returns a filter to tiles that intersect {@code worldBounds} (specified in world web mercator coordinates). */

Wyświetl plik

@ -153,7 +153,7 @@ public class GeoPackageReader extends SimpleReader<SimpleFeature> {
Geometry latLonGeom = (transform.isIdentity()) ? featureGeom : JTS.transform(featureGeom, transform); Geometry latLonGeom = (transform.isIdentity()) ? featureGeom : JTS.transform(featureGeom, transform);
FeatureColumns columns = feature.getColumns(); FeatureColumns columns = feature.getColumns();
SimpleFeature geom = SimpleFeature.create(latLonGeom, new HashMap<>(columns.columnCount()), SimpleFeature geom = SimpleFeature.create(latLonGeom, HashMap.newHashMap(columns.columnCount()),
sourceName, featureName, ++id); sourceName, featureName, ++id);
for (int i = 0; i < columns.columnCount(); ++i) { for (int i = 0; i < columns.columnCount(); ++i) {

Wyświetl plik

@ -177,7 +177,7 @@ public class NaturalEarthReader extends SimpleReader<SimpleFeature> {
// create the feature and pass to next stage // create the feature and pass to next stage
Geometry latLonGeometry = GeoUtils.WKB_READER.read(geometry); Geometry latLonGeometry = GeoUtils.WKB_READER.read(geometry);
SimpleFeature readerGeometry = SimpleFeature.create(latLonGeometry, new HashMap<>(column.length - 1), SimpleFeature readerGeometry = SimpleFeature.create(latLonGeometry, HashMap.newHashMap(column.length - 1),
sourceName, table, ++id); sourceName, table, ++id);
for (int c = 0; c < column.length; c++) { for (int c = 0; c < column.length; c++) {
if (c != geometryColumn) { if (c != geometryColumn) {

Wyświetl plik

@ -137,7 +137,7 @@ public class ShapefileReader extends SimpleReader<SimpleFeature> {
latLonGeometry = JTS.transform(source, transformToLatLon); latLonGeometry = JTS.transform(source, transformToLatLon);
} }
if (latLonGeometry != null) { if (latLonGeometry != null) {
SimpleFeature geom = SimpleFeature.create(latLonGeometry, new HashMap<>(attributeNames.length), SimpleFeature geom = SimpleFeature.create(latLonGeometry, HashMap.newHashMap(attributeNames.length),
sourceName, layer, ++id); sourceName, layer, ++id);
for (int i = 1; i < attributeNames.length; i++) { for (int i = 1; i < attributeNames.length; i++) {
geom.setTag(attributeNames[i], feature.getAttribute(i)); geom.setTag(attributeNames[i], feature.getAttribute(i));

Wyświetl plik

@ -128,7 +128,7 @@ public abstract class SourceFeature implements WithTags, WithGeometryType {
private Geometry computeCentroidIfConvex() throws GeometryException { private Geometry computeCentroidIfConvex() throws GeometryException {
if (!canBePolygon()) { if (!canBePolygon()) {
return centroid(); return centroid();
} else if (polygon()instanceof Polygon poly && } else if (polygon() instanceof Polygon poly &&
poly.getNumInteriorRing() == 0 && poly.getNumInteriorRing() == 0 &&
GeoUtils.isConvex(poly.getExteriorRing())) { GeoUtils.isConvex(poly.getExteriorRing())) {
return centroid(); return centroid();

Wyświetl plik

@ -232,7 +232,7 @@ public class OsmMultipolygon {
if (numPolygons == 0) { if (numPolygons == 0) {
return shells; return shells;
} }
shells.add(polygons.get(0)); shells.add(polygons.getFirst());
if (numPolygons == 1) { if (numPolygons == 1) {
return shells; return shells;
} }

Wyświetl plik

@ -133,7 +133,7 @@ public class PbfDecoder implements Iterable<OsmElement> {
private Map<String, Object> buildTags(int num, IntUnaryOperator key, IntUnaryOperator value) { private Map<String, Object> buildTags(int num, IntUnaryOperator key, IntUnaryOperator value) {
if (num > 0) { if (num > 0) {
Map<String, Object> tags = new HashMap<>(num); Map<String, Object> tags = HashMap.newHashMap(num);
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
String k = fieldDecoder.decodeString(key.applyAsInt(i)); String k = fieldDecoder.decodeString(key.applyAsInt(i));
String v = fieldDecoder.decodeString(value.applyAsInt(i)); String v = fieldDecoder.decodeString(value.applyAsInt(i));
@ -366,7 +366,7 @@ public class PbfDecoder implements Iterable<OsmElement> {
if (tags == null) { if (tags == null) {
// divide by 2 as key&value, multiply by 2 because of the better approximation // divide by 2 as key&value, multiply by 2 because of the better approximation
tags = new HashMap<>(Math.max(3, 2 * (nodes.getKeysValsCount() / 2) / nodes.getKeysValsCount())); tags = HashMap.newHashMap(Math.max(3, 2 * (nodes.getKeysValsCount() / 2) / nodes.getKeysValsCount()));
} }
tags.put(fieldDecoder.decodeString(keyIndex), fieldDecoder.decodeString(valueIndex)); tags.put(fieldDecoder.decodeString(keyIndex), fieldDecoder.decodeString(valueIndex));

Wyświetl plik

@ -122,7 +122,7 @@ class GeometryCoordinateSequences {
static Geometry reassemblePolygons(List<List<CoordinateSequence>> groups) throws GeometryException { static Geometry reassemblePolygons(List<List<CoordinateSequence>> groups) throws GeometryException {
int numGeoms = groups.size(); int numGeoms = groups.size();
if (numGeoms == 1) { if (numGeoms == 1) {
return reassemblePolygon(groups.get(0)); return reassemblePolygon(groups.getFirst());
} else { } else {
Polygon[] polygons = new Polygon[numGeoms]; Polygon[] polygons = new Polygon[numGeoms];
for (int i = 0; i < numGeoms; i++) { for (int i = 0; i < numGeoms; i++) {
@ -135,7 +135,7 @@ class GeometryCoordinateSequences {
/** Returns a {@link Polygon} built from all outer/inner rings in {@code group}, reversing all inner rings. */ /** Returns a {@link Polygon} built from all outer/inner rings in {@code group}, reversing all inner rings. */
private static Polygon reassemblePolygon(List<CoordinateSequence> group) throws GeometryException { private static Polygon reassemblePolygon(List<CoordinateSequence> group) throws GeometryException {
try { try {
LinearRing first = GeoUtils.JTS_FACTORY.createLinearRing(group.get(0)); LinearRing first = GeoUtils.JTS_FACTORY.createLinearRing(group.getFirst());
LinearRing[] rest = new LinearRing[group.size() - 1]; LinearRing[] rest = new LinearRing[group.size() - 1];
for (int j = 1; j < group.size(); j++) { for (int j = 1; j < group.size(); j++) {
CoordinateSequence seq = group.get(j); CoordinateSequence seq = group.get(j);

Wyświetl plik

@ -258,7 +258,7 @@ public class TiledGeometry {
TileCoord tile = TileCoord.ofXYZ(wrappedX, y, z); TileCoord tile = TileCoord.ofXYZ(wrappedX, y, z);
double tileY = worldY - y; double tileY = worldY - y;
tileContents.computeIfAbsent(tile, t -> List.of(new ArrayList<>())) tileContents.computeIfAbsent(tile, t -> List.of(new ArrayList<>()))
.get(0) .getFirst()
.add(GeoUtils.coordinateSequence(tileX * 256, tileY * 256)); .add(GeoUtils.coordinateSequence(tileX * 256, tileY * 256));
} }
} }
@ -384,7 +384,7 @@ public class TiledGeometry {
for (var entry : inProgressShapes.entrySet()) { for (var entry : inProgressShapes.entrySet()) {
TileCoord tileID = entry.getKey(); TileCoord tileID = entry.getKey();
List<CoordinateSequence> inSeqs = entry.getValue(); List<CoordinateSequence> inSeqs = entry.getValue();
if (area && inSeqs.get(0).size() < 4) { if (area && inSeqs.getFirst().size() < 4) {
// not enough points in outer polygon, ignore // not enough points in outer polygon, ignore
continue; continue;
} }
@ -573,20 +573,20 @@ public class TiledGeometry {
} }
/* /*
A tile is inside a filled region when there is an odd number of vertical edges to the left and right A tile is inside a filled region when there is an odd number of vertical edges to the left and right
for example a simple shape: for example a simple shape:
--------- ---------
out | in | out out | in | out
(0/2) | (1/1) | (2/0) (0/2) | (1/1) | (2/0)
--------- ---------
or a more complex shape or a more complex shape
--------- --------- --------- ---------
out | in | out | in | out | in | out | in |
(0/4) | (1/3) | (2/2) | (3/1) | (0/4) | (1/3) | (2/2) | (3/1) |
| --------- | | --------- |
------------------------- -------------------------
So we keep track of this number by xor'ing the left and right fills repeatedly, So we keep track of this number by xor'ing the left and right fills repeatedly,
then and'ing them together at the end. then and'ing them together at the end.
*/ */

Wyświetl plik

@ -38,7 +38,7 @@ public class ProcessInfo {
for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) { for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) {
if (garbageCollectorMXBean instanceof NotificationEmitter emitter) { if (garbageCollectorMXBean instanceof NotificationEmitter emitter) {
emitter.addNotificationListener((notification, handback) -> { emitter.addNotificationListener((notification, handback) -> {
if (notification.getUserData()instanceof CompositeData compositeData) { if (notification.getUserData() instanceof CompositeData compositeData) {
var info = GarbageCollectionNotificationInfo.from(compositeData); var info = GarbageCollectionNotificationInfo.from(compositeData);
GcInfo gcInfo = info.getGcInfo(); GcInfo gcInfo = info.getGcInfo();
postGcMemoryUsage.set(gcInfo.getMemoryUsageAfterGc().entrySet().stream() postGcMemoryUsage.set(gcInfo.getMemoryUsageAfterGc().entrySet().stream()
@ -142,7 +142,7 @@ public class ProcessInfo {
* Returns the total amount of memory available on the system if available. * Returns the total amount of memory available on the system if available.
*/ */
public static OptionalLong getSystemMemoryBytes() { public static OptionalLong getSystemMemoryBytes() {
if (ManagementFactory.getOperatingSystemMXBean()instanceof com.sun.management.OperatingSystemMXBean osBean) { if (ManagementFactory.getOperatingSystemMXBean() instanceof com.sun.management.OperatingSystemMXBean osBean) {
return OptionalLong.of(osBean.getTotalMemorySize()); return OptionalLong.of(osBean.getTotalMemorySize());
} else { } else {
return OptionalLong.empty(); return OptionalLong.empty();

Wyświetl plik

@ -10,15 +10,12 @@ import javax.annotation.concurrent.Immutable;
* A utility for measuring the wall and CPU time that this JVM consumes between snapshots. * A utility for measuring the wall and CPU time that this JVM consumes between snapshots.
* <p> * <p>
* For example: * For example:
* * {@snippet :
* <pre>
* {@code
* var start = ProcessTime.now(); * var start = ProcessTime.now();
* // do expensive work... * // do expensive work...
* var end - ProcessTime.now(); * var end = ProcessTime.now();
* LOGGER.log("Expensive work took " + end.minus(start)); * LOGGER.log("Expensive work took " + end.minus(start));
* } * }
* </pre>
*/ */
@Immutable @Immutable
public record ProcessTime(Duration wall, Optional<Duration> cpu, Duration gc) { public record ProcessTime(Duration wall, Optional<Duration> cpu, Duration gc) {

Wyświetl plik

@ -275,7 +275,7 @@ public class ProgressLoggers {
/** Adds the CPU utilization of every thread starting with {@code prefix} since the last log to output. */ /** Adds the CPU utilization of every thread starting with {@code prefix} since the last log to output. */
public ProgressLoggers addThreadPoolStats(String name, String prefix) { public ProgressLoggers addThreadPoolStats(String name, String prefix) {
boolean first = loggers.isEmpty() || !(loggers.get(loggers.size() - 1) instanceof WorkerPipelineLogger); boolean first = loggers.isEmpty() || !(loggers.getLast() instanceof WorkerPipelineLogger);
try { try {
Map<Long, ProcessInfo.ThreadState> lastThreads = ProcessInfo.getThreadStats(); Map<Long, ProcessInfo.ThreadState> lastThreads = ProcessInfo.getThreadStats();
AtomicLong lastTime = new AtomicLong(System.nanoTime()); AtomicLong lastTime = new AtomicLong(System.nanoTime());

Wyświetl plik

@ -95,7 +95,7 @@ public class AwsOsm {
} else if (results.size() > 1) { } else if (results.size() > 1) {
throw new IllegalArgumentException("Found multiple AWS osm download URLs for " + searchQuery + ": " + results); throw new IllegalArgumentException("Found multiple AWS osm download URLs for " + searchQuery + ": " + results);
} }
return results.get(0); return results.getFirst();
} }
} }

Wyświetl plik

@ -43,15 +43,12 @@ import org.slf4j.LoggerFactory;
* changes. * changes.
* <p> * <p>
* For example: * For example:
* * {@snippet :
* <pre>
* {@code
* Downloader.create(PlanetilerConfig.defaults()) * Downloader.create(PlanetilerConfig.defaults())
* .add("natural_earth", "http://url/of/natural_earth.zip", Path.of("natural_earth.zip")) * .add("natural_earth", "http://url/of/natural_earth.zip", Path.of("natural_earth.zip"))
* .add("osm", "http://url/of/file.osm.pbf", Path.of("file.osm.pbf")) * .add("osm", "http://url/of/file.osm.pbf", Path.of("file.osm.pbf"))
* .run(); * .run();
* } * }
* </pre>
* <p> * <p>
* As a shortcut to find the URL of a file to download from the <a href="https://download.geofabrik.de/">Geofabrik * As a shortcut to find the URL of a file to download from the <a href="https://download.geofabrik.de/">Geofabrik
* download site</a>, you can use "geofabrik:extract name" (i.e. "geofabrik:monaco" or "geofabrik:australia") to look up * download site</a>, you can use "geofabrik:extract name" (i.e. "geofabrik:monaco" or "geofabrik:australia") to look up
@ -247,7 +244,7 @@ public class Downloader {
CompletableFuture<ResourceMetadata> httpHead(String url) { CompletableFuture<ResourceMetadata> httpHead(String url) {
return client return client
.sendAsync(newHttpRequest(url).method("HEAD", HttpRequest.BodyPublishers.noBody()).build(), .sendAsync(newHttpRequest(url).HEAD().build(),
responseInfo -> { responseInfo -> {
int status = responseInfo.statusCode(); int status = responseInfo.statusCode();
Optional<String> location = Optional.empty(); Optional<String> location = Optional.empty();

Wyświetl plik

@ -106,7 +106,7 @@ public class Geofabrik {
"Multiple " + name + " for '" + searchQuery + "': " + values.stream().map(d -> d.id).collect( "Multiple " + name + " for '" + searchQuery + "': " + values.stream().map(d -> d.id).collect(
Collectors.joining(", "))); Collectors.joining(", ")));
} else if (values.size() == 1) { } else if (values.size() == 1) {
return values.get(0).urls.get("pbf"); return values.getFirst().urls.get("pbf");
} else { } else {
return null; return null;
} }

Wyświetl plik

@ -13,19 +13,15 @@ import com.onthegomap.planetiler.collection.FeatureGroup;
* To sort by a field descending, specify its range from high to low. * To sort by a field descending, specify its range from high to low.
* <p> * <p>
* For example this SQL ordering: * For example this SQL ordering:
* *
* <pre> * {@snippet lang = "sql" :
* {@code
* ORDER BY rank ASC, * ORDER BY rank ASC,
* population DESC, * population DESC,
* length(name) ASC * length(name) ASC
* } * }
* </pre>
* <p> * <p>
* would become: * would become:
* * {@snippet :
* <pre>
* {@code
* feature.setSortKey( * feature.setSortKey(
* SortKey * SortKey
* .orderByInt(rank, MIN_RANK, MAX_RANK) * .orderByInt(rank, MIN_RANK, MAX_RANK)
@ -125,7 +121,7 @@ public class SortKey {
} }
int levels = end + 1 - start; int levels = end + 1 - start;
if (value < start || value > end) { if (value < start || value > end) {
value = Math.max(start, Math.min(end, value)); value = Math.clamp(value, start, end);
} }
return accumulate(value, start, levels); return accumulate(value, start, levels);
} }
@ -141,7 +137,7 @@ public class SortKey {
return thenByDouble(start - value, end, start, levels); return thenByDouble(start - value, end, start, levels);
} }
if (value < start || value > end) { if (value < start || value > end) {
value = Math.max(start, Math.min(end, value)); value = Math.clamp(value, start, end);
} }
int intVal = doubleRangeToInt(value, start, end, levels); int intVal = doubleRangeToInt(value, start, end, levels);
@ -160,7 +156,7 @@ public class SortKey {
} }
assert start > 0 : "log thresholds must be > 0 got [" + start + ", " + end + "]"; assert start > 0 : "log thresholds must be > 0 got [" + start + ", " + end + "]";
if (value < start || value > end) { if (value < start || value > end) {
value = Math.max(start, Math.min(end, value)); value = Math.clamp(value, start, end);
} }
int intVal = doubleRangeToInt(Math.log(value), Math.log(start), Math.log(end), levels); int intVal = doubleRangeToInt(Math.log(value), Math.log(start), Math.log(end), levels);

Wyświetl plik

@ -128,7 +128,7 @@ public class Translations {
Map<String, String> result = new HashMap<>(); Map<String, String> result = new HashMap<>();
for (var entry : tags.entrySet()) { for (var entry : tags.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if (key.startsWith("name:") && entry.getValue()instanceof String stringVal) { if (key.startsWith("name:") && entry.getValue() instanceof String stringVal) {
result.put(key, stringVal); result.put(key, stringVal);
} }
} }

Wyświetl plik

@ -17,24 +17,21 @@ import java.util.function.Consumer;
* A mini-framework for chaining sequential steps that run in dedicated threads with a queue between each. * A mini-framework for chaining sequential steps that run in dedicated threads with a queue between each.
* <p> * <p>
* For example: * For example:
* * {@snippet :
* <pre>
* {@code
* WorkerPipeline.start("name", stats) * WorkerPipeline.start("name", stats)
* .readFrom("reader", List.of(1, 2, 3)) * .readFrom("reader", List.of(1, 2, 3))
* .addBuffer("reader_queue", 10) * .addBuffer("reader_queue", 10)
* .addWorker("process", 2, (i, next) -> next.accept(doExpensiveWork(i)) * .addWorker("process", 2, (i, next) -> next.accept(doExpensiveWork(i)))
* .addBuffer("writer_queue", 10) * .addBuffer("writer_queue", 10)
* .sinkToConsumer("writer", 1, result -> writeToDisk(result)) * .sinkToConsumer("writer", 1, result -> writeToDisk(result))
* .await(); * .await();
* } * }
* </pre>
* <p> * <p>
* NOTE: to do any forking/joining, you must construct and wire-up queues and each sequence of steps manually. * NOTE: to do any forking/joining, you must construct and wire-up queues and each sequence of steps manually.
* *
* @param <T> input type of this pipeline * @param <T> input type of this pipeline
*/ */
public record WorkerPipeline<T> ( public record WorkerPipeline<T>(
String name, String name,
WorkerPipeline<?> previous, WorkerPipeline<?> previous,
WorkQueue<T> inputQueue, WorkQueue<T> inputQueue,
@ -219,7 +216,7 @@ public record WorkerPipeline<T> (
* *
* @param <O> type of elements that the next step must process * @param <O> type of elements that the next step must process
*/ */
public record Builder<O> ( public record Builder<O>(
String prefix, String prefix,
String name, String name,
// keep track of previous elements so that build can wire-up the computation graph // keep track of previous elements so that build can wire-up the computation graph

Wyświetl plik

@ -827,7 +827,7 @@ class PlanetilerTests {
var tileContents = results.tiles.get(TileCoord.ofXYZ(0, 0, 0)); var tileContents = results.tiles.get(TileCoord.ofXYZ(0, 0, 0));
assertEquals(1, tileContents.size()); assertEquals(1, tileContents.size());
Geometry geom = tileContents.get(0).geometry().geom(); Geometry geom = tileContents.getFirst().geometry().geom();
assertTrue(geom instanceof MultiPolygon, geom.toString()); assertTrue(geom instanceof MultiPolygon, geom.toString());
MultiPolygon multiPolygon = (MultiPolygon) geom; MultiPolygon multiPolygon = (MultiPolygon) geom;
assertSameNormalizedFeature(newPolygon( assertSameNormalizedFeature(newPolygon(
@ -1884,7 +1884,7 @@ class PlanetilerTests {
var point = newPoint(tileX, tileY); var point = newPoint(tileX, tileY);
assertEquals(1, problematicTile.size()); assertEquals(1, problematicTile.size());
var geomCompare = problematicTile.get(0).geometry(); var geomCompare = problematicTile.getFirst().geometry();
geomCompare.validate(); geomCompare.validate();
var geom = geomCompare.geom(); var geom = geomCompare.geom();

Wyświetl plik

@ -160,7 +160,7 @@ class VectorTileTest {
List<VectorTile.Feature> decoded = VectorTile.decode(encoded); List<VectorTile.Feature> decoded = VectorTile.decode(encoded);
assertEquals(1, decoded.size()); assertEquals(1, decoded.size());
Map<String, Object> decodedAttributes = decoded.get(0).attrs(); Map<String, Object> decodedAttributes = decoded.getFirst().attrs();
assertEquals("value1", decodedAttributes.get("key1")); assertEquals("value1", decodedAttributes.get("key1"));
assertEquals(123L, decodedAttributes.get("key2")); assertEquals(123L, decodedAttributes.get("key2"));
assertEquals(234.1f, decodedAttributes.get("key3")); assertEquals(234.1f, decodedAttributes.get("key3"));
@ -220,7 +220,7 @@ class VectorTileTest {
var features = VectorTile.decode(encoded); var features = VectorTile.decode(encoded);
assertEquals(1, features.size()); assertEquals(1, features.size());
MultiPolygon mp2 = (MultiPolygon) decodeSilently(features.get(0).geometry()); MultiPolygon mp2 = (MultiPolygon) decodeSilently(features.getFirst().geometry());
assertEquals(mp.getNumGeometries(), mp2.getNumGeometries()); assertEquals(mp.getNumGeometries(), mp2.getNumGeometries());
} }

Wyświetl plik

@ -94,9 +94,9 @@ class ShapefileReaderTest {
assertEquals(1, reader.getFeatureCount()); assertEquals(1, reader.getFeatureCount());
List<SimpleFeature> features = new ArrayList<>(); List<SimpleFeature> features = new ArrayList<>();
reader.readFeatures(features::add); reader.readFeatures(features::add);
assertEquals(10.5113, features.get(0).latLonGeometry().getCentroid().getX(), 1e-4); assertEquals(10.5113, features.getFirst().latLonGeometry().getCentroid().getX(), 1e-4);
assertEquals(0, features.get(0).latLonGeometry().getCentroid().getY(), 1e-4); assertEquals(0, features.getFirst().latLonGeometry().getCentroid().getY(), 1e-4);
assertEquals(3, features.get(0).getTag("value")); assertEquals(3, features.getFirst().getTag("value"));
} }
} }

Wyświetl plik

@ -47,7 +47,7 @@ class FeatureRendererTest {
private FeatureCollector collector(Geometry worldGeom) { private FeatureCollector collector(Geometry worldGeom) {
var latLonGeom = GeoUtils.worldToLatLonCoords(worldGeom); var latLonGeom = GeoUtils.worldToLatLonCoords(worldGeom);
return new FeatureCollector.Factory(config, stats) return new FeatureCollector.Factory(config, stats)
.get(SimpleFeature.create(latLonGeom, new HashMap<>(0), null, null, .get(SimpleFeature.create(latLonGeom, HashMap.newHashMap(0), null, null,
1)); 1));
} }

Wyświetl plik

@ -410,7 +410,7 @@ public class Contexts {
} }
public String matchKey() { public String matchKey() {
return matchKeys().isEmpty() ? null : matchKeys().get(0); return matchKeys().isEmpty() ? null : matchKeys().getFirst();
} }
public Object matchValue() { public Object matchValue() {

Wyświetl plik

@ -164,7 +164,7 @@ public interface ConfigExpression<I extends ScriptContext, O>
public ConfigExpression<I, O> simplifyOnce() { public ConfigExpression<I, O> simplifyOnce() {
return switch (children.size()) { return switch (children.size()) {
case 0 -> constOf(null); case 0 -> constOf(null);
case 1 -> children.get(0); case 1 -> children.getFirst();
default -> { default -> {
var result = children.stream() var result = children.stream()
.flatMap( .flatMap(

Wyświetl plik

@ -76,10 +76,12 @@ public class OsmQaTiles implements Profile {
} }
feature feature
.setAttr("@id", sourceFeature.id()) .setAttr("@id", sourceFeature.id())
.setAttr("@type", element instanceof OsmElement.Node ? "node" : .setAttr("@type", switch (element) {
element instanceof OsmElement.Way ? "way" : case OsmElement.Node ignored -> "node";
element instanceof OsmElement.Relation ? "relation" : null case OsmElement.Way ignored -> "way";
); case OsmElement.Relation ignored -> "relation";
default -> null;
});
var info = element.info(); var info = element.info();
if (info != null) { if (info != null) {
feature feature