Skip to content

Commit

Permalink
some more test cases loop segments
Browse files Browse the repository at this point in the history
  • Loading branch information
msbarry committed Nov 24, 2024
1 parent 4c445ae commit 41ed0b8
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
public class LoopLineMerger {
private final List<LineString> input = new ArrayList<>();
private final List<Node> output = new ArrayList<>();
private int nodes = 0;
private int edges = 0;
private int numNodes = 0;
private int numEdges = 0;
private PrecisionModel precisionModel = new PrecisionModel(GeoUtils.TILE_PRECISION);
private GeometryFactory factory = new GeometryFactory(precisionModel);
private double minLength = 0.0;
Expand Down Expand Up @@ -136,7 +136,10 @@ private Edge degreeTwoMerge(Node node) {
if (node.getEdges().size() == 2) {
Edge a = node.getEdges().getFirst();
Edge b = node.getEdges().get(1);
return mergeTwoEdges(node, a, b);
// if one side is a loop, degree is actually > 2
if (!a.isLoop() && !b.isLoop()) {
return mergeTwoEdges(node, a, b);
}
}
return null;
}
Expand Down Expand Up @@ -165,13 +168,17 @@ private Edge mergeTwoEdges(Node node, Edge edge1, Edge edge2) {
private void strokeMerge() {
for (var node : output) {
List<Edge> edges = List.copyOf(node.getEdges());
if (edges.size() >= 3) {
if (edges.size() >= 2) {
record AngledPair(Edge a, Edge b, double angle) {}
List<AngledPair> angledPairs = new ArrayList<>();
for (var i = 0; i < edges.size(); ++i) {
var edgei = edges.get(i);
for (var j = i + 1; j < edges.size(); ++j) {
double angle = edges.get(i).angleTo(edges.get(j));
angledPairs.add(new AngledPair(edges.get(i), edges.get(j), angle));
var edgej = edges.get(j);
if (edgei != edgej.reversed) {
double angle = edgei.angleTo(edgej);
angledPairs.add(new AngledPair(edgei, edgej, angle));
}
}
}
angledPairs.sort(Comparator.comparingDouble(angledPair -> angledPair.angle));
Expand Down Expand Up @@ -251,37 +258,39 @@ record Candidate(Node node, double length, double minTotalLength) {}
}

private void removeShortStubEdges() {
PriorityQueue<Edge> toRemove = new PriorityQueue<>(Comparator.comparingDouble(Edge::length));
PriorityQueue<Edge> toCheck = new PriorityQueue<>(Comparator.comparingDouble(Edge::length));
for (var node : output) {
for (var edge : node.getEdges()) {
if (isShortStubEdge(edge)) {
toRemove.offer(edge);
toCheck.offer(edge);
}
}
}
while (!toRemove.isEmpty()) {
var edge = toRemove.poll();
while (!toCheck.isEmpty()) {
var edge = toCheck.poll();
if (edge.removed) {
continue;
}
edge.remove();
if (degreeTwoMerge(edge.from) instanceof Edge merged && isShortStubEdge(merged)) {
toRemove.offer(merged);
if (isShortStubEdge(edge)) {
edge.remove();
}
if (degreeTwoMerge(edge.from) instanceof Edge merged) {
toCheck.offer(merged);
}
if (edge.from.getEdges().size() == 1) {
var other = edge.from.getEdges().getFirst();
if (isShortStubEdge(other)) {
toRemove.offer(other);
toCheck.offer(other);
}
}
if (edge.from != edge.to) {
if (degreeTwoMerge(edge.to) instanceof Edge merged && isShortStubEdge(merged)) {
toRemove.offer(merged);
if (degreeTwoMerge(edge.to) instanceof Edge merged) {
toCheck.offer(merged);
}
if (edge.to.getEdges().size() == 1) {
var other = edge.to.getEdges().getFirst();
if (isShortStubEdge(other)) {
toRemove.offer(other);
toCheck.offer(other);
}
}
}
Expand All @@ -290,7 +299,7 @@ private void removeShortStubEdges() {

private boolean isShortStubEdge(Edge edge) {
return edge != null && !edge.removed && edge.length < stubMinLength &&
(edge.from.getEdges().size() == 1 || edge.to.getEdges().size() == 1 || edge.from == edge.to);
(edge.from.getEdges().size() == 1 || edge.to.getEdges().size() == 1 || edge.isLoop());
}

private void removeShortEdges() {
Expand Down Expand Up @@ -422,7 +431,9 @@ private void buildNodes(List<List<Coordinate>> edges) {
Edge edge = new Edge(firstNode, lastNode, coordinateSequence, length);

firstNode.addEdge(edge);
lastNode.addEdge(edge.reversed);
if (firstNode != lastNode) {
lastNode.addEdge(edge.reversed);
}
}
}

Expand Down Expand Up @@ -466,7 +477,7 @@ private List<List<Coordinate>> nodeLines(List<LineString> input) {
}

private class Node {
final int id = nodes++;
final int id = numNodes++;
final List<Edge> edge = new ArrayList<>();
Coordinate coordinate;

Expand Down Expand Up @@ -515,9 +526,9 @@ private class Edge {


private Edge(Node from, Node to, List<Coordinate> coordinateSequence, double length) {
this(edges, from, to, length, coordinateSequence, true, null);
reversed = new Edge(edges, to, from, length, coordinateSequence.reversed(), false, this);
edges++;
this(numEdges, from, to, length, coordinateSequence, true, null);
reversed = new Edge(numEdges, to, from, length, coordinateSequence.reversed(), false, this);
numEdges++;
}

private Edge(int id, Node from, Node to, double length, List<Coordinate> coordinates, boolean main, Edge reversed) {
Expand Down Expand Up @@ -564,6 +575,10 @@ boolean isCollapsed() {
(coordinates.size() == 2 && coordinates.getFirst().equals(coordinates.getLast()));
}

boolean isLoop() {
return from == to;
}

@Override
public String toString() {
return "Edge{" + from.id + "->" + to.id + (main ? "" : "(R)") + ": [" + coordinates.getFirst() + ".." +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,13 +364,13 @@ void testRealWorldHarkingen() {

"mergelines_200433_lines.wkb.gz,0,false,9103",
"mergelines_200433_lines.wkb.gz,0.1,false,8834",
"mergelines_200433_lines.wkb.gz,1,false,878",
"mergelines_200433_lines.wkb.gz,1,true,527",
"mergelines_200433_lines.wkb.gz,1,false,861",
"mergelines_200433_lines.wkb.gz,1,true,508",

"mergelines_239823_lines.wkb.gz,0,false,6188",
"mergelines_239823_lines.wkb.gz,0.1,false,5941",
"mergelines_239823_lines.wkb.gz,1,false,832",
"mergelines_239823_lines.wkb.gz,1,true,688",
"mergelines_239823_lines.wkb.gz,1,false,826",
"mergelines_239823_lines.wkb.gz,1,true,681",

"i90.wkb.gz,0,false,17",
"i90.wkb.gz,1,false,18",
Expand Down Expand Up @@ -409,4 +409,110 @@ void testOnRealWorldData(String file, double minLengths, boolean simplify, int e
assertEquals(expected, merged.size());
}

@Test
void testMergeStrokesAt3WayIntersectionWithLoop() {
var merger = new LoopLineMerger()
.setMinLength(1)
.setLoopMinLength(1)
.setStubMinLength(1)
.setMergeStrokes(true);

merger.add(newLineString(-5, 0, 0, 0));
merger.add(newLineString(0, 0, 5, 0, 5, 5, 0, 5, 0, 0));

assertEquals(
List.of(
newLineString(-5, 0, 0, 0, 5, 0, 5, 5, 0, 5, 0, 0)
),
merger.getMergedLineStrings()
);
}

@Test
void testMergeStrokesAt3WayIntersectionWithLoop2() {
var merger = new LoopLineMerger()
.setMinLength(1)
.setLoopMinLength(1)
.setStubMinLength(1)
.setMergeStrokes(true);

merger.add(newLineString(-5, 0, 0, 0));
merger.add(newLineString(0, 0, 0, -1, 5, 0, 5, 5, 0, 5, 0, 0));

assertEquals(
List.of(
newLineString(
-5, 0, 0, 0, 0, -1, 5, 0, 5, 5, 0, 5, 0, 0
)
),
merger.getMergedLineStrings()
);
}

@Test
void testMergeStrokesAt3WayIntersection() {
var merger = new LoopLineMerger()
.setMinLength(1)
.setLoopMinLength(1)
.setStubMinLength(1)
.setMergeStrokes(true);

merger.add(newLineString(-5, 0, 0, 0));
merger.add(newLineString(0, 0, 5, 0));
merger.add(newLineString(0, 0, 0, 5));

assertEquals(
List.of(
newLineString(-5, 0, 0, 0, 5, 0),
newLineString(0, 0, 0, 5)
),
merger.getMergedLineStrings()
);
}

@Test
void testMergeStrokesAt4WayIntersection() {
var merger = new LoopLineMerger()
.setMinLength(1)
.setLoopMinLength(1)
.setStubMinLength(1)
.setMergeStrokes(true);

merger.add(newLineString(-5, 0, 0, 0));
merger.add(newLineString(0, 0, 5, 0));
merger.add(newLineString(0, 0, 0, 5));
merger.add(newLineString(0, 0, 0, -5));

assertEquals(
List.of(
newLineString(-5, 0, 0, 0, 5, 0),
newLineString(0, -5, 0, 0, 0, 5)
),
merger.getMergedLineStrings()
);
}

@Test
void testMergeStrokesAt5WayIntersection() {
var merger = new LoopLineMerger()
.setMinLength(1)
.setLoopMinLength(1)
.setStubMinLength(1)
.setMergeStrokes(true);

merger.add(newLineString(-5, 0, 0, 0));
merger.add(newLineString(0, 0, 5, 0));
merger.add(newLineString(0, 0, 0, 5));
merger.add(newLineString(0, 0, 0, -5));
merger.add(newLineString(0, 0, 5, 5));

assertEquals(
List.of(
newLineString(-5, 0, 0, 0, 5, 0),
newLineString(0, 0, 5, 5),
newLineString(0, -5, 0, 0, 0, 5)
),
merger.getMergedLineStrings()
);
}
}

0 comments on commit 41ed0b8

Please sign in to comment.