Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve line order in OverlayNG #665

Merged
merged 3 commits into from
Jan 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
package org.locationtech.jts.operation.overlayng;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.locationtech.jts.util.Assert;
import org.locationtech.jts.util.Debug;

/**
* Performs merging on the noded edges of the input geometries.
Expand All @@ -39,25 +37,22 @@
* no other coincident edge, or if all coincident edges have the same direction).
* This ensures that the overlay output line direction will be as consistent
* as possible with input lines.
* <p>
* The merger also preserves the order of the edges in the input.
* This means that for polygon-line overlay
* the result lines will be in the same order as in the input
* (possibly with multiple result lines for a single input line).
*
* @author mdavis
*
*/
class EdgeMerger {

public static List<Edge> merge(List<Edge> edges) {
EdgeMerger merger = new EdgeMerger(edges);
return merger.merge();
}
// use a list to collect the final edges, to preserve order
List<Edge> mergedEdges = new ArrayList<Edge>();
Map<EdgeKey, Edge> edgeMap = new HashMap<EdgeKey, Edge>();

private Collection<Edge> edges;
private Map<EdgeKey, Edge> edgeMap = new HashMap<EdgeKey, Edge>();

public EdgeMerger(List<Edge> edges) {
this.edges = edges;
}

public ArrayList<Edge> merge() {
for (Edge edge : edges) {
EdgeKey edgeKey = EdgeKey.create(edge);
Edge baseEdge = edgeMap.get(edgeKey);
Expand All @@ -66,6 +61,7 @@ public ArrayList<Edge> merge() {
edgeMap.put(edgeKey, edge);
//Debug.println("edge added: " + edge);
//Debug.println(edge.toLineString());
mergedEdges.add(edge);
}
else {
// found an existing edge
Expand All @@ -80,7 +76,7 @@ public ArrayList<Edge> merge() {
//Debug.println(edge.toLineString());
}
}
return new ArrayList<Edge>(edgeMap.values());
return mergedEdges;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ private void addResultLinesRings() {
* by the start edge direction. This implies
* that if all edges are reversed, the created line
* will be reversed to match.
* This ensures the orientation of linework is faithful to the input
* in the case of polygon-line overlay.
* However, this does not provide a consistent orientation
* in the case of line-line intersection(where A and B might have different orientations).
* (Other more complex strategies would be possible.
* E.g. using the direction of the majority of segments,
* or preferring the direction of the A edges.)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,14 @@ public void testPolygonFlatCollapseIntersection() {
checkEqual(expected, actual);
}

public void testPolygonLineIntersectionOrder() {
Geometry a = read("POLYGON ((1 1, 1 9, 9 9, 9 7, 3 7, 3 3, 9 3, 9 1, 1 1))");
Geometry b = read("MULTILINESTRING ((2 10, 2 0), (4 10, 4 0))");
Geometry expected = read("MULTILINESTRING ((2 9, 2 1), (4 9, 4 7), (4 3, 4 1))");
Geometry actual = intersection(a, b, 1);
checkEqualExact(expected, actual);
}

//============================================================


Expand Down
17 changes: 16 additions & 1 deletion modules/core/src/test/java/test/jts/GeometryTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ protected GeometryTestCase(String name, CoordinateSequenceFactory coordinateSequ

/**
* Checks that the normalized values of the expected and actual
* geometries are exactly equals.
* geometries are exactly equal.
*
* @param expected the expected value
* @param actual the actual value
Expand All @@ -72,6 +72,21 @@ protected void checkEqual(Geometry expected, Geometry actual) {
assertTrue(equal);
}

/**
* Checks that the values of the expected and actual
* geometries are exactly equal.
*
* @param expected the expected value
* @param actual the actual value
*/
protected void checkEqualExact(Geometry expected, Geometry actual) {
boolean equal = actual.equalsExact(expected);
if (! equal) {
System.out.format(CHECK_EQUAL_FAIL, expected, actual );
}
assertTrue(equal);
}

protected void checkEqual(Geometry expected, Geometry actual, double tolerance) {
Geometry actualNorm = actual.norm();
Geometry expectedNorm = expected.norm();
Expand Down