CoveragePolygonValidatorTest.java
/*
* Copyright (c) 2022 Martin Davis.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.coverage;
import java.util.List;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.util.PolygonExtracter;
import junit.textui.TestRunner;
import test.jts.GeometryTestCase;
public class CoveragePolygonValidatorTest extends GeometryTestCase {
public static void main(String args[]) {
TestRunner.run(CoveragePolygonValidatorTest.class);
}
public CoveragePolygonValidatorTest(String name) {
super(name);
}
//======== Invalid cases =============================
public void testCollinearUnmatchedEdge() {
checkInvalid("POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))",
"POLYGON ((100 300, 180 300, 180 200, 100 200, 100 300))",
"LINESTRING (100 200, 200 200)");
}
public void testDuplicate() {
checkInvalid("POLYGON ((1 3, 3 3, 3 1, 1 1, 1 3))",
"MULTIPOLYGON (((1 3, 3 3, 3 1, 1 1, 1 3)), ((5 3, 5 1, 3 1, 3 3, 5 3)))",
"LINEARRING (1 3, 1 1, 3 1, 3 3, 1 3)");
}
public void testDuplicateReversed() {
checkInvalid("POLYGON ((1 3, 3 3, 3 1, 1 1, 1 3))",
"MULTIPOLYGON (((1 3, 1 1, 3 1, 3 3, 1 3))), ((5 3, 5 1, 3 1, 3 3, 5 3)))",
"LINEARRING (1 3, 1 1, 3 1, 3 3, 1 3)");
}
public void testCrossingSegment() {
checkInvalid("POLYGON ((1 9, 9 9, 9 3, 1 3, 1 9))",
"POLYGON ((1 1, 5 6, 9 1, 1 1))",
"LINESTRING (1 3, 9 3)");
}
public void testCrossingAndInteriorSegments() {
checkInvalid("POLYGON ((1 1, 3 4, 7 4, 9 1, 1 1))",
"POLYGON ((1 9, 9 9, 9 3, 1 3, 1 9))",
"LINESTRING (1 1, 3 4, 7 4, 9 1)");
}
public void testTargetVertexTouchesSegment() {
checkInvalid("POLYGON ((1 9, 9 9, 9 5, 1 5, 1 9))",
"POLYGON ((1 1, 5 5, 9 1, 1 1))",
"LINESTRING (9 5, 1 5)");
}
public void testAdjVertexTouchesSegment() {
checkInvalid("POLYGON ((1 1, 5 5, 9 1, 1 1))",
"POLYGON ((1 9, 9 9, 9 5, 1 5, 1 9))",
"LINESTRING (1 1, 5 5, 9 1)");
}
public void testInteriorSegmentTouchingEdge() {
checkInvalid("POLYGON ((4 3, 4 7, 8 9, 8 1, 4 3))",
"POLYGON ((1 7, 6 7, 6 3, 1 3, 1 7))",
"LINESTRING (8 1, 4 3, 4 7, 8 9)");
}
public void testInteriorSegmentTouchingNodes() {
checkInvalid("POLYGON ((4 2, 4 8, 8 9, 8 1, 4 2))",
"POLYGON ((1 5, 4 8, 7 5, 4 2, 1 5))",
"LINESTRING (4 2, 4 8)");
}
public void testInteriorSegmentsTouching() {
checkInvalid("POLYGON ((1 9, 5 9, 8 7, 5 7, 3 5, 8 2, 1 2, 1 9))",
"POLYGON ((5 9, 9 9, 9 1, 5 1, 5 9))",
"LINESTRING (5 9, 8 7, 5 7, 3 5, 8 2, 1 2)");
}
public void testTargetMultiPolygon() {
checkInvalid("MULTIPOLYGON (((4 8, 9 9, 9 7, 4 8)), ((3 5, 9 6, 9 4, 3 5)), ((2 2, 9 3, 9 1, 2 2)))",
"POLYGON ((1 1, 1 9, 5 9, 6 7, 5 5, 6 3, 5 1, 1 1))",
"MULTILINESTRING ((9 7, 4 8, 9 9), (9 4, 3 5, 9 6), (9 1, 2 2, 9 3))");
}
public void testBothMultiPolygon() {
checkInvalid("MULTIPOLYGON (((4 8, 9 9, 9 7, 4 8)), ((3 5, 9 6, 9 4, 3 5)), ((2 2, 9 3, 9 1, 2 2)))",
"MULTIPOLYGON (((1 6, 1 9, 5 9, 6 7, 5 5, 1 6)), ((1 4, 5 5, 6 3, 5 1, 1 1, 1 4)))",
"MULTILINESTRING ((9 7, 4 8, 9 9), (9 4, 3 5, 9 6), (9 1, 2 2, 9 3))");
}
/**
* Shows need to evaluate both start and end point of intersecting segments
* in InvalidSegmentDetector,
* since matched segments are not tested
*/
public void testInteriorSegmentsWithMatch() {
checkInvalid("POLYGON ((7 6, 1 1, 3 6, 7 6))",
"MULTIPOLYGON (((1 9, 9 9, 9 1, 1 1, 3 6, 1 9)), ((0 1, 0 9, 1 9, 3 6, 1 1, 0 1)))",
"LINESTRING (7 6, 1 1, 3 6, 7 6)");
}
public void testAdjacentHoleOverlap() {
checkInvalid("POLYGON ((3 3, 3 7, 6 8, 7 3, 3 3))",
"POLYGON ((1 9, 9 9, 9 1, 1 1, 1 9), (3 7, 7 7, 7 3, 3 3, 3 7))",
"LINESTRING (3 7, 6 8, 7 3)");
}
public void testTargetHoleOverlap() {
checkInvalid("POLYGON ((1 1, 1 9, 9 9, 9 1, 1 1), (2 2, 8 2, 8 8, 5 4, 3 5, 2 5, 2 2))",
"POLYGON ((2 2, 2 5, 3 5, 8 6.7, 8 2, 2 2))",
"LINESTRING (8 2, 8 8, 5 4, 3 5)");
}
public void testFullyContained() {
checkInvalid("POLYGON ((3 7, 7 7, 7 3, 3 3, 3 7))",
"POLYGON ((1 9, 9 9, 9 1, 1 1, 1 9))",
"LINESTRING (3 7, 7 7, 7 3, 3 3, 3 7)");
}
public void testFullyCoveredAndMatched() {
checkInvalid("POLYGON ((1 3, 2 3, 2 2, 1 2, 1 3))",
"MULTIPOLYGON (((1 1, 1 2, 2 2, 2 1, 1 1)), ((3 1, 2 1, 2 2, 3 2, 3 1)), ((3 3, 3 2, 2 2, 2 3, 3 3)), ((2 3, 3 3, 3 2, 3 1, 2 1, 1 1, 1 2, 1 3, 2 3)))",
"LINESTRING (1 2, 1 3, 2 3)");
}
public void testTargetCoveredAndMatching() {
checkInvalid("POLYGON ((1 7, 5 7, 9 7, 9 3, 5 3, 1 3, 1 7))",
"MULTIPOLYGON (((5 9, 9 7, 5 7, 1 7, 5 9)), ((1 7, 5 7, 5 3, 1 3, 1 7)), ((9 3, 5 3, 5 7, 9 7, 9 3)), ((1 3, 5 3, 9 3, 5 1, 1 3)))",
"LINESTRING (1 7, 5 7, 9 7, 9 3, 5 3, 1 3, 1 7))");
}
public void testCoveredBy2AndMatching() {
checkInvalid("POLYGON ((1 9, 9 9, 9 5, 1 5, 1 9))",
"MULTIPOLYGON (((1 5, 9 5, 9 1, 1 1, 1 5)), ((1 9, 5 9, 5 1, 1 1, 1 9)), ((9 9, 9 1, 5 1, 5 9, 9 9)))",
"LINESTRING (1 5, 1 9, 9 9, 9 5)");
}
//======== Gap cases =============================
public void testGap() {
checkInvalidGap("POLYGON ((1 5, 9 5, 9 1, 1 1, 1 5))",
"POLYGON ((1 9, 5 9, 5 5.1, 1 5, 1 9))",
0.5,
"LINESTRING (1 5, 9 5)");
}
//======== Valid cases =============================
public void testMatchedEdges() {
checkValid("POLYGON ((3 7, 7 7, 7 3, 3 3, 3 7))",
"MULTIPOLYGON (((1 7, 3 7, 3 3, 1 3, 1 7)), ((3 9, 7 9, 7 7, 3 7, 3 9)), ((9 7, 9 3, 7 3, 7 7, 9 7)), ((3 1, 3 3, 7 3, 7 1, 3 1)))");
}
public void testRingsCCW() {
checkValid("POLYGON ((1 1, 6 5, 4 9, 1 9, 1 1))",
"POLYGON ((1 1, 9 1, 9 4, 6 5, 1 1))");
}
//-- confirms zero-length segments are skipped in processing
public void testRepeatedCommonVertexInTarget() {
checkValid("POLYGON ((1 1, 1 3, 5 3, 5 3, 9 1, 1 1))",
"POLYGON ((1 9, 9 9, 9 5, 5 3, 1 3, 1 9))");
}
//-- confirms zero-length segments are skipped in processing
public void testRepeatedCommonVertexInAdjacent() {
checkValid("POLYGON ((1 1, 1 3, 5 3, 9 1, 1 1))",
"POLYGON ((1 9, 9 9, 9 5, 5 3, 5 3, 1 3, 1 9))");
}
//----------------------------------------------------------------------
private void checkInvalid(String wktTarget, String wktAdj, String wktExpected) {
Geometry target = read(wktTarget);
Geometry adj = read(wktAdj);
Geometry[] adjPolygons = extractPolygons(adj);
Geometry actual = CoveragePolygonValidator.validate(target, adjPolygons);
//System.out.println(actual);
Geometry expected = read(wktExpected);
checkEqual(expected, actual);
}
private void checkInvalidGap(String wktTarget, String wktAdj,
double gapWidth, String wktExpected) {
Geometry target = read(wktTarget);
Geometry adj = read(wktAdj);
Geometry[] adjPolygons = extractPolygons(adj);
Geometry actual = CoveragePolygonValidator.validate(target, adjPolygons, gapWidth);
//System.out.println(actual);
Geometry expected = read(wktExpected);
checkEqual(expected, actual);
}
private void checkValid(String wktTarget, String wktAdj) {
Geometry target = read(wktTarget);
Geometry adj = read(wktAdj);
Geometry[] adjPolygons = extractPolygons(adj);
Geometry actual = CoveragePolygonValidator.validate(target, adjPolygons);
Geometry expected = read("LINESTRING EMPTY"); //TODO: check equals LINESTRING EMPTY
checkEqual(expected, actual);
}
private Geometry[] extractPolygons(Geometry geom) {
List<Polygon> polygons = PolygonExtracter.getPolygons(geom);
return GeometryFactory.toPolygonArray(polygons);
}
}