Skip to content

Commit 3903a21

Browse files
authored
Fix GeometryFactory.create to deep-copy polygonal geometry (#1158)
1 parent 0fbfdc9 commit 3903a21

File tree

3 files changed

+104
-15
lines changed

3 files changed

+104
-15
lines changed

modules/core/src/main/java/org/locationtech/jts/geom/util/GeometryEditor.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,18 +165,21 @@ private Geometry editInternal(Geometry geometry, GeometryEditorOperation operati
165165

166166
private Polygon editPolygon(Polygon polygon,
167167
GeometryEditorOperation operation) {
168+
168169
Polygon newPolygon = (Polygon) operation.edit(polygon, factory);
169-
// create one if needed
170+
// create empty polygon if needed (will be removed subsequently if a multi component)
170171
if (newPolygon == null)
171172
newPolygon = factory.createPolygon();
172173
if (newPolygon.isEmpty()) {
173-
//RemoveSelectedPlugIn relies on this behaviour. [Jon Aquino]
174+
//-- ensure empty polygons are copied
175+
if (newPolygon == polygon) {
176+
newPolygon = factory.createPolygon();
177+
}
174178
return newPolygon;
175179
}
176180

177181
LinearRing shell = (LinearRing) edit(newPolygon.getExteriorRing(), operation);
178182
if (shell == null || shell.isEmpty()) {
179-
//RemoveSelectedPlugIn relies on this behaviour. [Jon Aquino]
180183
return factory.createPolygon();
181184
}
182185

modules/core/src/test/java/org/locationtech/jts/geom/GeometryFactoryTest.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
import org.locationtech.jts.io.ParseException;
1818
import org.locationtech.jts.io.WKTReader;
1919

20-
import junit.framework.TestCase;
2120
import junit.textui.TestRunner;
21+
import test.jts.GeometryTestCase;
2222

2323

2424
/**
2525
* Tests for {@link GeometryFactory}.
2626
*
2727
* @version 1.13
2828
*/
29-
public class GeometryFactoryTest extends TestCase {
29+
public class GeometryFactoryTest extends GeometryTestCase {
3030

3131
PrecisionModel precisionModel = new PrecisionModel();
3232
GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 0);
@@ -38,18 +38,27 @@ public static void main(String args[]) {
3838

3939
public GeometryFactoryTest(String name) { super(name); }
4040

41-
public void testCreateGeometry() throws ParseException
41+
public void testCreateGeometry()
4242
{
43-
checkCreateGeometryExact("POINT EMPTY");
4443
checkCreateGeometryExact("POINT ( 10 20 )");
45-
checkCreateGeometryExact("LINESTRING EMPTY");
44+
checkCreateGeometryExact("MULTIPOINT ( (10 20), (30 40) )");
4645
checkCreateGeometryExact("LINESTRING(0 0, 10 10)");
4746
checkCreateGeometryExact("MULTILINESTRING ((50 100, 100 200), (100 100, 150 200))");
4847
checkCreateGeometryExact("POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))");
4948
checkCreateGeometryExact("MULTIPOLYGON (((100 200, 200 200, 200 100, 100 100, 100 200)), ((300 200, 400 200, 400 100, 300 100, 300 200)))");
5049
checkCreateGeometryExact("GEOMETRYCOLLECTION (POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200)), LINESTRING (250 100, 350 200), POINT (350 150))");
5150
}
5251

52+
public void testCreateGeometryEmpty() {
53+
checkCreateGeometryExact("POINT EMPTY");
54+
checkCreateGeometryExact("LINESTRING EMPTY");
55+
checkCreateGeometryExact("POLYGON EMPTY");
56+
checkCreateGeometryExact("MULTIPOINT EMPTY");
57+
checkCreateGeometryExact("MULTILINESTRING EMPTY");
58+
checkCreateGeometryExact("MULTIPOLYGON EMPTY");
59+
checkCreateGeometryExact("GEOMETRYCOLLECTION EMPTY");
60+
}
61+
5362
public void testCreateEmpty() {
5463
checkEmpty( geometryFactory.createEmpty(0), Point.class);
5564
checkEmpty( geometryFactory.createEmpty(1), LineString.class);
@@ -70,7 +79,7 @@ private void checkEmpty(Geometry geom, Class clz) {
7079
assertTrue( geom.getClass() == clz );
7180
}
7281

73-
public void testDeepCopy() throws ParseException
82+
public void testDeepCopy()
7483
{
7584
Point g = (Point) read("POINT ( 10 10) ");
7685
Geometry g2 = geometryFactory.createGeometry(g);
@@ -100,7 +109,7 @@ public void testMultiPointCS()
100109
*
101110
* @throws ParseException
102111
*/
103-
public void testCopyGeometryWithNonDefaultDimension() throws ParseException
112+
public void testCopyGeometryWithNonDefaultDimension()
104113
{
105114
GeometryFactory gf = new GeometryFactory(CoordinateArraySequenceFactory.instance());
106115
CoordinateSequence mpSeq = gf.getCoordinateSequenceFactory().create(1, 2);
@@ -116,15 +125,13 @@ public void testCopyGeometryWithNonDefaultDimension() throws ParseException
116125

117126
}
118127

119-
private void checkCreateGeometryExact(String wkt) throws ParseException
128+
private void checkCreateGeometryExact(String wkt)
120129
{
121130
Geometry g = read(wkt);
122131
Geometry g2 = geometryFactory.createGeometry(g);
123132
assertTrue(g.equalsExact(g2));
133+
// check a copy has been made
134+
assertTrue(g != g2);
124135
}
125136

126-
private Geometry read(String wkt) throws ParseException
127-
{
128-
return reader.read(wkt);
129-
}
130137
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2021 Martin Davis.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
7+
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
8+
* and the Eclipse Distribution License is available at
9+
*
10+
* http://www.eclipse.org/org/documents/edl-v10.php.
11+
*/
12+
package org.locationtech.jts.geom.util;
13+
14+
import org.locationtech.jts.geom.CoordinateSequence;
15+
import org.locationtech.jts.geom.CoordinateSequenceFactory;
16+
import org.locationtech.jts.geom.Geometry;
17+
18+
import junit.textui.TestRunner;
19+
import test.jts.GeometryTestCase;
20+
21+
public class GeometryEditorTest extends GeometryTestCase {
22+
23+
public static void main(String args[]) {
24+
TestRunner.run(GeometryFixerTest.class);
25+
}
26+
27+
public GeometryEditorTest(String name) {
28+
super(name);
29+
}
30+
31+
public void testCopy() {
32+
checkCopy("POINT ( 10 20 )");
33+
checkCopy("MULTIPOINT ( (10 20), (30 40) )");
34+
checkCopy("LINESTRING(0 0, 10 10)");
35+
checkCopy("MULTILINESTRING ((50 100, 100 200), (100 100, 150 200))");
36+
checkCopy("POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))");
37+
checkCopy(
38+
"MULTIPOLYGON (((100 200, 200 200, 200 100, 100 100, 100 200)), ((300 200, 400 200, 400 100, 300 100, 300 200)))");
39+
checkCopy(
40+
"GEOMETRYCOLLECTION (POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200)), LINESTRING (250 100, 350 200), POINT (350 150))");
41+
}
42+
43+
public void testCopyEmpty() {
44+
checkCopy("POINT EMPTY");
45+
checkCopy("LINESTRING EMPTY");
46+
checkCopy("POLYGON EMPTY");
47+
checkCopy("MULTIPOINT EMPTY");
48+
checkCopy("MULTILINESTRING EMPTY");
49+
checkCopy("MULTIPOLYGON EMPTY");
50+
checkCopy("GEOMETRYCOLLECTION EMPTY");
51+
}
52+
53+
//========================================================
54+
55+
private void checkCopy(String wkt) {
56+
Geometry g = read(wkt);
57+
Geometry g2 = copy(g);
58+
assertTrue(g.equalsExact(g2));
59+
// check a copy has been made
60+
assertTrue(g != g2);
61+
}
62+
63+
private static Geometry copy(Geometry g) {
64+
GeometryEditor editor = new GeometryEditor(g.getFactory());
65+
return editor.edit(g, new CoordSeqCloneOp(g.getFactory().getCoordinateSequenceFactory()));
66+
}
67+
68+
private static class CoordSeqCloneOp extends GeometryEditor.CoordinateSequenceOperation {
69+
CoordinateSequenceFactory coordinateSequenceFactory;
70+
71+
public CoordSeqCloneOp(CoordinateSequenceFactory coordinateSequenceFactory) {
72+
this.coordinateSequenceFactory = coordinateSequenceFactory;
73+
}
74+
75+
public CoordinateSequence edit(CoordinateSequence coordSeq, Geometry geometry) {
76+
return coordinateSequenceFactory.create(coordSeq);
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)