Skip to content
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 @@ -29,6 +29,15 @@
public class BasicSegmentString
implements SegmentString
{
public static BasicSegmentString substring(SegmentString segString, int start, int end) {
Coordinate[] pts = new Coordinate[end - start + 1];
int ipts = 0;
for (int i = start; i < end + 1; i++) {
pts[ipts++] = segString.getCoordinate(i).copy();
}
return new BasicSegmentString(pts, segString.getData());
}

private Coordinate[] pts;
private Object data;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineSegment;
Expand Down Expand Up @@ -50,11 +51,17 @@ public BoundaryChainNoder() {

@Override
public void computeNodes(Collection segStrings) {
HashSet<Segment> segSet = new HashSet<Segment>();
HashSet<Segment> boundarySegSet = new HashSet<Segment>();
BoundaryChainMap[] boundaryChains = new BoundaryChainMap[segStrings.size()];
addSegments(segStrings, segSet, boundaryChains);
markBoundarySegments(segSet);
addSegments(segStrings, boundarySegSet, boundaryChains);
markBoundarySegments(boundarySegSet);
chainList = extractChains(boundaryChains);

//-- check for self-touching nodes and split chains at those nodes
Set<Coordinate> nodePts = findNodePts(chainList);
if (nodePts.size() > 0) {
chainList = nodeChains(chainList, nodePts);
}
}

private static void addSegments(Collection<SegmentString> segStrings, HashSet<Segment> segSet,
Expand Down Expand Up @@ -95,6 +102,56 @@ private static List<SegmentString> extractChains(BoundaryChainMap[] boundaryChai
return chainList;
}

private Set<Coordinate> findNodePts(List<SegmentString> segStrings) {
Set<Coordinate> interorVertices = new HashSet<Coordinate>();
Set<Coordinate> nodes = new HashSet<Coordinate>();
for (SegmentString ss : segStrings) {
//-- endpoints are nodes
nodes.add(ss.getCoordinate(0));
nodes.add(ss.getCoordinate(ss.size() - 1));

//-- check for duplicate interior points
for (int i = 1; i < ss.size() - 1; i++) {
Coordinate p = ss.getCoordinate(i);
if (interorVertices.contains(p)) {
nodes.add(p);
}
interorVertices.add(p);
}
}
return nodes;
}

private List<SegmentString> nodeChains(List<SegmentString> chains, Set<Coordinate> nodePts) {
List<SegmentString> nodedChains = new ArrayList<SegmentString>();
for (SegmentString chain : chains) {
nodeChain(chain, nodePts, nodedChains);
}
return nodedChains;
}

private void nodeChain(SegmentString chain, Set<Coordinate> nodePts, List<SegmentString> nodedChains) {
int start = 0;
while (start < chain.size() - 1) {
int end = findNodeIndex(chain, start, nodePts);
//-- if no interior nodes found, keep original chain
if (start == 0 && end == chain.size() - 1) {
nodedChains.add(chain);
return;
}
nodedChains.add(BasicSegmentString.substring(chain, start, end));
start = end;
}
}

private int findNodeIndex(SegmentString chain, int start, Set<Coordinate> nodePts) {
for (int i = start + 1; i < chain.size(); i++) {
if (nodePts.contains(chain.getCoordinate(i)))
return i;
}
return chain.size() - 1;
}

@Override
public Collection getNodedSubstrings() {
return chainList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ public void testEmpty() {
);
}

public void testHoleTouchingSide() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 5 3, 9 6, 9 1, 1 1)))",
"POLYGON ((9 6, 9 1, 1 1, 1 9, 9 9, 9 6), (9 6, 2 6, 5 3, 9 6))"
);
}

public void testHolesTouchingSide() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 5 7, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 4 3, 5 7, 7 3, 9 6, 9 1, 1 1)))",
"POLYGON ((9 9, 9 6, 9 1, 1 1, 1 9, 9 9), (5 7, 7 3, 9 6, 5 7), (2 6, 4 3, 5 7, 2 6))"
);
}

public void testHolesTouching() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 7 7, 5 7, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 4 3, 5 7, 7 3, 7 7, 9 6, 9 1, 1 1)))",
"POLYGON ((9 9, 9 6, 9 1, 1 1, 1 9, 9 9), (5 7, 7 3, 7 7, 5 7), (2 6, 4 3, 5 7, 2 6))"
);
}

private void checkUnion(String wktCoverage, String wktExpected) {
Geometry covGeom = read(wktCoverage);
Geometry[] coverage = toArray(covGeom);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,25 @@ public void testPolygonsConcentricHalfDonuts( ) {
"MULTIPOLYGON (((1 9, 6 9, 9 9, 9 1, 6 1, 1 1, 1 9), (2 8, 2 2, 6 2, 8 2, 8 8, 6 8, 2 8)), ((5 3, 3 3, 3 7, 5 7, 7 7, 7 3, 5 3), (5 4, 6 4, 6 6, 5 6, 4 6, 4 4, 5 4)))");
}

public void testPolygonsNested( ) {
checkUnion("GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 1, 1 1, 1 9), (3 7, 3 3, 7 3, 7 7, 3 7)), POLYGON ((3 7, 7 7, 7 3, 3 3, 3 7)))",
"POLYGON ((1 1, 1 9, 9 9, 9 1, 1 1))");
public void testHoleTouchingSide() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 5 3, 9 6, 9 1, 1 1)))",
"POLYGON ((9 6, 9 1, 1 1, 1 9, 9 9, 9 6), (9 6, 2 6, 5 3, 9 6))"
);
}

public void testHolesTouchingSide() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 5 7, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 4 3, 5 7, 7 3, 9 6, 9 1, 1 1)))",
"POLYGON ((9 9, 9 6, 9 1, 1 1, 1 9, 9 9), (5 7, 7 3, 9 6, 5 7), (2 6, 4 3, 5 7, 2 6))"
);
}

public void testHolesTouching() {
checkUnion(
"GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 6, 7 7, 5 7, 2 6, 1 9)), POLYGON ((1 1, 1 9, 2 6, 4 3, 5 7, 7 3, 7 7, 9 6, 9 1, 1 1)))",
"POLYGON ((9 9, 9 6, 9 1, 1 1, 1 9, 9 9), (5 7, 7 3, 7 7, 5 7), (2 6, 4 3, 5 7, 2 6))"
);
}

public void testPolygonsFormingHole( ) {
Expand All @@ -45,6 +61,13 @@ public void testPolygonsSquareGrid( ) {
"POLYGON ((0 25, 0 50, 0 75, 0 100, 25 100, 50 100, 75 100, 100 100, 100 75, 100 50, 100 25, 100 0, 75 0, 50 0, 25 0, 0 0, 0 25))");
}

public void testPolygonsNested( ) {
checkUnion("GEOMETRYCOLLECTION (POLYGON ((1 9, 9 9, 9 1, 1 1, 1 9), (3 7, 3 3, 7 3, 7 7, 3 7)), POLYGON ((3 7, 7 7, 7 3, 3 3, 3 7)))",
"POLYGON ((1 1, 1 9, 9 9, 9 1, 1 1))");
}

//------------------------------------------------------------

/**
* Sequential lines are still noded
*/
Expand All @@ -69,6 +92,8 @@ public void testLinesNetwork( ) {
"MULTILINESTRING ((1 9, 3.1 8), (2 3, 4 3), (3.1 8, 5 7), (4 3, 5 3), (5 3, 5 7), (5 3, 7 4), (5 3, 8 1), (5 7, 7 8), (7 4, 9 5), (7 8, 9 9))");
}

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

private void checkUnion(String wkt, String wktExpected) {
Geometry coverage = read(wkt);
Geometry expected = read(wktExpected);
Expand Down