Skip to content

Commit

Permalink
Review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
wipfli committed Nov 16, 2024
1 parent 66648e3 commit c151d0d
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntStack;
import com.onthegomap.planetiler.collection.Hppc;
import com.onthegomap.planetiler.geo.DouglasPeuckerSimplifier;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.geo.GeometryType;
Expand Down Expand Up @@ -173,6 +172,8 @@ public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature>
result.add(feature1);
} else {
LoopLineMerger merger = new LoopLineMerger()
.setTolerance(tolerance)
.setMergeStrokes(true)
.setMinLength(lengthLimit)
.setLoopMinLength(lengthLimit);
for (VectorTile.Feature feature : groupedFeatures) {
Expand All @@ -188,33 +189,18 @@ public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature>
// TODO remove debug features comment
// Map<String, Object> attrs = new HashMap<>();
// attrs.put("idx", i++);
// result.add(feature1.copyWithNewGeometry(((LineString) merged).getStartPoint()).copyWithExtraAttrs(attrs));
// result.add(feature1.copyWithNewGeometry((LineString) merged).copyWithExtraAttrs(attrs));
// result.add(feature1.copyWithNewGeometry(line.getStartPoint()).copyWithExtraAttrs(attrs));
// result.add(feature1.copyWithNewGeometry(line).copyWithExtraAttrs(attrs));
// attrs.put("end", "yes");
// result.add(feature1.copyWithNewGeometry(((LineString) merged).getEndPoint()).copyWithExtraAttrs(attrs));

// re-simplify since some endpoints of merged segments may be unnecessary
if (line.getNumPoints() > 2 && tolerance >= 0) {
Geometry simplified = DouglasPeuckerSimplifier.simplify(line, tolerance);
if (simplified instanceof LineString simpleLineString) {
line = simpleLineString;
} else {
LOGGER.warn("line string merge simplify emitted {}", simplified.getGeometryType());
}
}
// result.add(feature1.copyWithNewGeometry(line.getEndPoint()).copyWithExtraAttrs(attrs));

if (buffer >= 0) {
removeDetailOutsideTile(line, buffer, outputSegments);
} else {
outputSegments.add(line);
}
}

merger = new LoopLineMerger();
for (var outputSegment : outputSegments) {
merger.add(outputSegment);
}
outputSegments = merger.getMergedByAngle();

if (!outputSegments.isEmpty()) {
outputSegments = sortByHilbertIndex(outputSegments);
Geometry newGeometry = GeoUtils.combineLineStrings(outputSegments);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.onthegomap.planetiler.util;

import com.onthegomap.planetiler.geo.DouglasPeuckerSimplifier;
import com.onthegomap.planetiler.geo.GeoUtils;
import java.util.ArrayList;
import java.util.Comparator;
Expand All @@ -26,6 +27,8 @@ public class LoopLineMerger {
private GeometryFactory factory = new GeometryFactory(precisionModel);
private double minLength = 0.0;
private double loopMinLength = 0.0;
private double tolerance = 0.0;
private boolean mergeStrokes = false;

public LoopLineMerger setPrecisionModel(PrecisionModel precisionModel) {
this.precisionModel = precisionModel;
Expand All @@ -43,6 +46,16 @@ public LoopLineMerger setLoopMinLength(double loopMinLength) {
return this;
}

public LoopLineMerger setTolerance(double tolerance) {
this.tolerance = tolerance;
return this;
}

public LoopLineMerger setMergeStrokes(boolean mergeStrokes) {
this.mergeStrokes = mergeStrokes;
return this;
}

public void add(Geometry geometry) {
geometry.apply((GeometryComponentFilter) component -> {
if (component instanceof LineString lineString) {
Expand All @@ -51,20 +64,19 @@ public void add(Geometry geometry) {
});
}

private void merge() {
private void degreeTwoMerge() {
for (var node : output) {
if (node.getEdges().size() == 2) {
Edge a = node.getEdges().getFirst();
Edge b = node.getEdges().get(1);
mergeTwoEdges(a, b);
mergeTwoEdges(node, a, b);
}
}
}

private void mergeTwoEdges(Edge a, Edge b) {
assert a.to == b.from;
a.to.getEdges().remove(a);
b.from.getEdges().remove(b);
private void mergeTwoEdges(Node node, Edge a, Edge b) {
node.getEdges().remove(a);
node.getEdges().remove(b);
List<Coordinate> coordinates = new ArrayList<>();
coordinates.addAll(a.coordinates.reversed());
coordinates.addAll(b.coordinates.subList(1, b.coordinates.size()));
Expand All @@ -77,7 +89,7 @@ private void mergeTwoEdges(Edge a, Edge b) {
}
}

private void mergeByAngle() {
private void strokeMerge() {
for (var node : output) {
List<Edge> edges = List.copyOf(node.getEdges());
if (edges.size() >= 3) {
Expand All @@ -95,7 +107,7 @@ record AngledPair(Edge a, Edge b, double angle) {}
if (merged.contains(angledPair.a) || merged.contains(angledPair.b)) {
continue;
}
mergeTwoEdges(angledPair.a, angledPair.b);
mergeTwoEdges(angledPair.a.from, angledPair.a, angledPair.b);
merged.add(angledPair.a);
merged.add(angledPair.b);
}
Expand Down Expand Up @@ -186,49 +198,93 @@ private void removeShortEdges() {
}
}

private void simplify() {
Map<Edge, LineString> mainEdgeToLineString = new HashMap<>();
for (var node : output) {
for (var edge : node.getEdges()) {
if (edge.main) {
mainEdgeToLineString.put(edge, factory.createLineString(edge.coordinates.toArray(Coordinate[]::new)));
}
}
}
for (var mainEdge : mainEdgeToLineString.keySet()) {
var line = mainEdgeToLineString.get(mainEdge);
if (line.getNumPoints() <= 2) {
continue;
}
Geometry simplified = DouglasPeuckerSimplifier.simplify(line, tolerance);
if (simplified instanceof LineString simpleLineString) {
mainEdgeToLineString.put(mainEdge, simpleLineString);
} else {
// TODO handle error
// LOGGER.warn("line string merge simplify emitted {}", simplified.getGeometryType());
}
}
for (var node : output) {
for (var edge : node.getEdges()) {
if (edge.main) {
edge.setCoordinates(List.of(mainEdgeToLineString.get(edge).getCoordinates()));
}
else {
edge.setCoordinates(List.of(mainEdgeToLineString.get(edge.reversed).getCoordinates()).reversed());
}
}
}
}

private void removeDuplicatedEdges() {
for (var node : output) {
List<Edge> toRemove = new ArrayList<>();
for (var i = 0; i < node.getEdges().size(); ++i) {
Edge a = node.getEdges().get(i);
for (var j = i + 1; j < node.getEdges().size(); ++j) {
Edge b = node.getEdges().get(j);
if (a.coordinates.equals(b.coordinates)) {
toRemove.add(b);
}
}
}
for (var edge : toRemove) {
edge.remove();
}
}
}

public List<LineString> getMergedLineStrings() {
output.clear();
List<List<Coordinate>> edges = nodeLines(input);
buildNodes(edges);

merge();
degreeTwoMerge();

if (loopMinLength > 0.0) {
breakLoops();
merge();
degreeTwoMerge();
}

if (minLength > 0.0) {
double step = 1.0 / precisionModel.getScale();
for (double stubMinLength = 0.0; stubMinLength < minLength; stubMinLength += step) {
removeShortStubEdges(stubMinLength);
merge();
degreeTwoMerge();
}
removeShortStubEdges(minLength);
merge();
// minLength = 10 * 0.0625;
// removeShortEdges();
// merge();
degreeTwoMerge();
}

List<LineString> result = new ArrayList<>();

for (var node : output) {
for (var edge : node.getEdges()) {
if (edge.main) {
result.add(factory.createLineString(edge.coordinates.toArray(Coordinate[]::new)));
}
}
if (tolerance >= 0.0) {
simplify();
removeDuplicatedEdges();
degreeTwoMerge();
}

return result;
}

public List<LineString> getMergedByAngle() {
List<List<Coordinate>> edges = nodeLines(input);
buildNodes(edges);
if (mergeStrokes) {
strokeMerge();
}

mergeByAngle();
if (minLength > 0) {
removeShortEdges();
}

List<LineString> result = new ArrayList<>();

Expand Down Expand Up @@ -399,6 +455,10 @@ public void remove() {
to.removeEdge(reversed);
}

public void setCoordinates(List<Coordinate> coordinates) {
this.coordinates = new ArrayList<>(coordinates);
}

double angleTo(Edge other) {
assert from.equals(other.from);
assert coordinates.size() >= 2;
Expand Down

0 comments on commit c151d0d

Please sign in to comment.