The result rings touch at no more than the number of touching points in the input
- * (although they may touch at fewer points).
- * The key implication of this statement is that if the
- * input is topologically valid, so is the simplified output.
+ * (although they may touch at fewer points).
+ * The key implication of this statement is that if the
+ * input is topologically valid, so is the simplified output.
*
* For linear geometries, if the input does not contain
* any intersecting line segments, this property
@@ -47,19 +47,19 @@
* For polygonal geometries and LinearRings the ring endpoint will be simplified.
* For LineStrings the endpoints will be unchanged.
*
- * For all geometry types, the result will contain
+ * For all geometry types, the result will contain
* enough vertices to ensure validity. For polygons
* and closed linear geometries, the result will have at
* least 4 vertices; for open linestrings the result
* will have at least 2 vertices.
*
- * All geometry types are handled.
+ * All geometry types are handled.
* Empty and point geometries are returned unchanged.
* Empty geometry components are deleted.
*
* The simplification uses a maximum-distance difference algorithm
* similar to the Douglas-Peucker algorithm.
- *
+ *
* @author Martin Davis
* @see DouglasPeuckerSimplifier
*
@@ -73,8 +73,8 @@ public static Geometry simplify(Geometry geom, double distanceTolerance)
return tss.getResultGeometry();
}
- private Geometry inputGeom;
- private TaggedLinesSimplifier lineSimplifier = new TaggedLinesSimplifier();
+ private final Geometry inputGeom;
+ private final TaggedLinesSimplifier lineSimplifier = new TaggedLinesSimplifier();
private Map linestringMap;
public TopologyPreservingSimplifier(Geometry inputGeom)
@@ -97,11 +97,11 @@ public void setDistanceTolerance(double distanceTolerance) {
lineSimplifier.setDistanceTolerance(distanceTolerance);
}
- public Geometry getResultGeometry()
+ public Geometry getResultGeometry()
{
// empty input produces an empty result
if (inputGeom.isEmpty()) return inputGeom.copy();
-
+
linestringMap = new HashMap();
inputGeom.apply(new LineStringMapBuilderFilter(this));
lineSimplifier.simplify(linestringMap.values());
@@ -112,12 +112,12 @@ public Geometry getResultGeometry()
static class LineStringTransformer
extends GeometryTransformer
{
- private Map linestringMap;
-
+ private final Map linestringMap;
+
public LineStringTransformer(Map linestringMap) {
this.linestringMap = linestringMap;
}
-
+
protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent)
{
if (coords.size() == 0) return null;
@@ -132,13 +132,13 @@ protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geo
}
/**
- * A filter to add linear geometries to the linestring map
+ * A filter to add linear geometries to the linestring map
* with the appropriate minimum size constraint.
* Closed {@link LineString}s (including {@link LinearRing}s
- * have a minimum output size constraint of 4,
+ * have a minimum output size constraint of 4,
* to ensure the output is valid.
* For all other linestrings, the minimum size is 2 points.
- *
+ *
* @author Martin Davis
*
*/
@@ -146,15 +146,15 @@ static class LineStringMapBuilderFilter
implements GeometryComponentFilter
{
TopologyPreservingSimplifier tps;
-
+
LineStringMapBuilderFilter(TopologyPreservingSimplifier tps) {
this.tps = tps;
}
-
+
/**
* Filters linear geometries.
- *
- * geom a geometry of any type
+ *
+ * @param geom a geometry of any type
*/
public void filter(Geometry geom)
{
@@ -162,10 +162,10 @@ public void filter(Geometry geom)
LineString line = (LineString) geom;
// skip empty geometries
if (line.isEmpty()) return;
-
- int minSize = ((LineString) line).isClosed() ? 4 : 2;
- boolean isRing = (line instanceof LinearRing) ? true : false;
- TaggedLineString taggedLine = new TaggedLineString((LineString) line, minSize, isRing);
+
+ int minSize = line.isClosed() ? 4 : 2;
+ boolean isRing = line instanceof LinearRing || line.isRing();
+ TaggedLineString taggedLine = new TaggedLineString(line, minSize, isRing);
tps.linestringMap.put(line, taggedLine);
}
}
diff --git a/modules/core/src/test/java/org/locationtech/jts/simplify/TopologyPreservingSimplifierTest.java b/modules/core/src/test/java/org/locationtech/jts/simplify/TopologyPreservingSimplifierTest.java
index b8a2187791..784f446729 100644
--- a/modules/core/src/test/java/org/locationtech/jts/simplify/TopologyPreservingSimplifierTest.java
+++ b/modules/core/src/test/java/org/locationtech/jts/simplify/TopologyPreservingSimplifierTest.java
@@ -34,90 +34,90 @@ public static void main(String[] args) {
public void testPoint() {
checkTPSNoChange("POINT (10 10)", 1);
}
-
+
public void testPolygonEmpty() {
checkTPSNoChange("POLYGON(EMPTY)", 1);
}
-
+
public void testPolygonFlatVertices() throws Exception {
checkTPS("POLYGON ((20 220, 40 220, 60 220, 80 220, 100 220, 120 220, 140 220, 140 180, 100 180, 60 180, 20 180, 20 220))",
10,
"POLYGON ((20 220, 140 220, 140 180, 20 180, 20 220))");
}
-
+
public void testPolygonNoReduction() throws Exception {
checkTPSNoChange("POLYGON ((20 220, 140 220, 140 180, 20 180, 20 220))",
10);
}
-
+
public void testPolygonNoReductionWithConflicts() throws Exception {
checkTPSNoChange("POLYGON ((40 240, 160 241, 280 240, 280 160, 160 240, 40 140, 40 240))",
10);
}
-
+
public void testPolygonWithTouchingHole() throws Exception {
checkTPS("POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200), (120 120, 220 120, 180 199, 160 200, 140 199, 120 120))",
10,
"POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200), (120 120, 220 120, 180 199, 160 200, 140 199, 120 120))");
}
-
+
public void testFlattishPolygon() throws Exception {
checkTPS("POLYGON ((0 0, 50 0, 53 0, 55 0, 100 0, 70 1, 60 1, 50 1, 40 1, 0 0))",
10,
"POLYGON ((0 0, 50 0, 100 0, 70 1, 0 0))");
}
-
+
public void testPolygonWithFlattishHole() throws Exception {
checkTPS("POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0), (140 40, 90 95, 40 160, 95 100, 140 40))",
20,
"POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0), (140 40, 90 95, 40 160, 95 100, 140 40))");
}
-
+
public void testTinySquare() throws Exception {
checkTPS("POLYGON ((0 5, 5 5, 5 0, 0 0, 0 1, 0 5))",
10,
"POLYGON ((0 0, 5 5, 5 0, 0 0))");
}
-
+
public void testTinyLineString() throws Exception {
checkTPS("LINESTRING (0 5, 1 5, 2 5, 5 5)",
10,
"LINESTRING (0 5, 5 5)");
}
-
+
public void testTinyClosedLineString() throws Exception {
checkTPSNoChange("LINESTRING (0 0, 5 0, 5 5, 0 0)",
10);
}
-
+
public void testMultiPoint() throws Exception {
checkTPSNoChange("MULTIPOINT(80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120)",
10);
}
-
+
public void testMultiLineString() throws Exception {
checkTPS("MULTILINESTRING( (0 0, 50 0, 70 0, 80 0, 100 0), (0 0, 50 1, 60 1, 100 0) )",
10,
"MULTILINESTRING ((0 0, 100 0), (0 0, 50 1, 100 0))");
}
-
+
public void testMultiLineStringWithEmpty() throws Exception {
checkTPS("MULTILINESTRING(EMPTY, (0 0, 50 0, 70 0, 80 0, 100 0), (0 0, 50 1, 60 1, 100 0) )",
10,
"MULTILINESTRING ((0 0, 100 0), (0 0, 50 1, 100 0))");
}
-
+
public void testMultiPolygonWithEmpty() throws Exception {
checkTPS("MULTIPOLYGON (EMPTY, ((10 90, 10 10, 90 10, 50 60, 10 90)), ((70 90, 90 90, 90 70, 70 70, 70 90)))",
10,
"MULTIPOLYGON (((10 90, 10 10, 90 10, 50 60, 10 90)), ((70 90, 90 90, 90 70, 70 70, 70 90)))");
}
-
+
public void testGeometryCollection() {
checkTPSNoChange("GEOMETRYCOLLECTION (MULTIPOINT (80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120), POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200)), LINESTRING (80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120))",
10);
}
-
+
public void testNoCollapse_mL() throws Exception {
checkTPS(
"MULTILINESTRING ((0 0, 100 0), (0 0, 60 1, 100 0))",
@@ -141,7 +141,7 @@ public void testNoCollapseSmallSquare() throws Exception {
"POLYGON ((0 0, 5 5, 5 0, 0 0))"
);
}
-
+
public void testPolygonRemoveEndpoint() throws Exception {
checkTPS(
"POLYGON ((220 180, 261 175, 380 220, 300 40, 140 30, 30 220, 176 176, 220 180))",
@@ -149,20 +149,25 @@ public void testPolygonRemoveEndpoint() throws Exception {
"POLYGON ((30 220, 380 220, 300 40, 140 30, 30 220))"
);
}
-
+
public void testLinearRingRemoveEndpoint() throws Exception {
checkTPS(
"LINEARRING (220 180, 261 175, 380 220, 300 40, 140 30, 30 220, 176 176, 220 180)",
40,
"LINEARRING (30 220, 380 220, 300 40, 140 30, 30 220)"
);
+ checkTPS(
+ "LINESTRING (220 180, 261 175, 380 220, 300 40, 140 30, 30 220, 176 176, 220 180)",
+ 40,
+ "LINESTRING (30 220, 380 220, 300 40, 140 30, 30 220)"
+ );
}
-
+
public void testPolygonKeepFlatEndpointWithTouch() throws Exception {
checkTPSNoChange("POLYGON ((0 0, 5 2.05, 10 0, 10 10, 0 10, 0 0), (5 2.1, 6 2, 6 4, 4 4, 4 2, 5 2.1))",
0.1 );
}
-
+
public void testPolygonKeepEndpointWithCross() throws Exception {
checkTPS(
"POLYGON ((50 52, 60 50, 90 60, 90 10, 10 10, 10 90, 60 90, 50 55, 40 80, 20 60, 40 50, 50 52))",
@@ -170,7 +175,7 @@ public void testPolygonKeepEndpointWithCross() throws Exception {
"POLYGON ((20 60, 50 52, 90 60, 90 10, 10 10, 10 90, 60 90, 50 55, 40 80, 20 60))"
);
}
-
+
// see https://trac.osgeo.org/geos/ticket/1064
public void testPolygonRemoveFlatEndpoint() throws Exception {
checkTPS(
@@ -187,8 +192,8 @@ public void testPolygonManyFlatSegments() throws Exception {
"POLYGON ((9 5, 9 1, 1 1, 1 5, 9 5))"
);
}
-
- //-- vertex is not removed due to overly-restrictive heuristic result length calculation?
+
+ //-- vertex is not removed due to overly-restrictive heuristic result length calculation?
public void testPolygonSize5NotSimplfied() throws Exception {
checkTPS(
"POLYGON ((10 90, 10 10, 90 10, 47 57, 10 90))",
@@ -196,12 +201,12 @@ public void testPolygonSize5NotSimplfied() throws Exception {
"POLYGON ((10 90, 10 10, 90 10, 47 57, 10 90))"
);
}
-
+
/**
* Test is from http://postgis.refractions.net/pipermail/postgis-users/2008-April/019327.html
* Exhibits the issue where simplified polygon shells can "jump" across
* holes, causing invalid topology.
- *
+ *
* @throws Exception
*/
public void testMultiPolygonWithSmallComponents() throws Exception {
@@ -209,7 +214,7 @@ public void testMultiPolygonWithSmallComponents() throws Exception {
0.0057,
"MULTIPOLYGON (((13.73095 51.024734, 13.7123153 51.041449, 13.7412027 51.0463256, 13.7552745 51.0566237, 13.7484397 51.0324582, 13.73095 51.024734)), ((13.7390933 51.0471421, 13.7369099 51.0474154, 13.7390933 51.047209, 13.7390933 51.0471421)), ((13.7367293 51.0470057, 13.7346615 51.0466892, 13.7347106 51.0471899, 13.7367293 51.0470057)))");
}
-
+
/**
* Test is from http://lists.jump-project.org/pipermail/jts-devel/2008-February/002350.html
* @throws Exception
@@ -219,25 +224,25 @@ public void testPolygonWithSpike() throws Exception {
2,
"POLYGON ((3312459.605 6646878.353, 3312460.524 6646875.969, 3312459.427 6646878.421, 3312460.014 6646886.391, 3312465.889 6646887.398, 3312470.827 6646884.839, 3312477.289 6646871.694, 3312472.748 6646869.547, 3312459.605 6646878.353))");
}
-
+
public void testLineComponentCross() {
checkTPS("MULTILINESTRING ((0 0, 10 2, 20 0), (9 1, 11 1))",
4,
"MULTILINESTRING ((0 0, 10 2, 20 0), (9 1, 11 1))");
}
-
+
public void testPolygonComponentCrossAtEndpoint() {
checkTPS("MULTIPOLYGON (((50 40, 40 60, 80 40, 0 0, 30 70, 50 40)), ((40 56, 40 57, 41 56, 40 56)))",
30,
"MULTIPOLYGON (((50 40, 80 40, 0 0, 30 70, 50 40)), ((40 56, 40 57, 41 56, 40 56)))");
}
-
+
public void testPolygonIntersectingSegments() {
checkTPS("MULTIPOLYGON (((0.63 0.2, 0.35 0, 0.73 0.66, 0.63 0.2)), ((1.42 4.01, 3.45 0.7, 1.79 1.47, 0 0.57, 1.42 4.01)))",
10,
"MULTIPOLYGON (((0.63 0.2, 0.35 0, 0.73 0.66, 0.63 0.2)), ((1.42 4.01, 3.45 0.7, 1.79 1.47, 0 0.57, 1.42 4.01)))");
}
-
+
private void checkTPS(String wkt, double tolerance, String wktExpected) {
Geometry geom = read(wkt);
Geometry actual = TopologyPreservingSimplifier.simplify(geom, tolerance);
@@ -246,7 +251,7 @@ private void checkTPS(String wkt, double tolerance, String wktExpected) {
//checkValid(actual);
checkEqual(expected, actual);
}
-
+
private void checkTPSNoChange(String wkt, double tolerance) {
checkTPS(wkt, tolerance, wkt);
}