Skip to content

Commit

Permalink
Fix InteriorPoint to handle partially empty collections (#698)
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Davis <mtnclimb@gmail.com>
  • Loading branch information
dr-jts authored Mar 5, 2021
1 parent 13def67 commit b3cab45
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import org.locationtech.jts.algorithm.construct.MaximumInscribedCircle;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryComponentFilter;
import org.locationtech.jts.geom.GeometryFilter;

/**
* Computes an interior point of a <code>{@link Geometry}</code>.
Expand Down Expand Up @@ -57,8 +60,12 @@ public static Coordinate getInteriorPoint(Geometry geom) {
return null;

Coordinate interiorPt = null;
//TODO: determine highest non-empty dimension
int dim = geom.getDimension();
//int dim = geom.getDimension();
int dim = effectiveDimension(geom);
// this should not happen, but just in case...
if (dim < 0) {
return null;
}
if (dim == 0) {
interiorPt = InteriorPointPoint.getInteriorPoint(geom);
}
Expand All @@ -71,4 +78,27 @@ else if (dim == 1) {
return interiorPt;
}

private static int effectiveDimension(Geometry geom) {
EffectiveDimensionFilter dimFilter = new EffectiveDimensionFilter();
geom.apply(dimFilter);
return dimFilter.getDimension();
}

private static class EffectiveDimensionFilter implements GeometryFilter
{
private int dim = -1;

public int getDimension() {
return dim;
}

public void filter(Geometry elem) {
if (elem instanceof GeometryCollection)
return;
if (! elem.isEmpty()) {
int elemDim = elem.getDimension();
if (elemDim > dim) dim = elemDim;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -780,10 +780,10 @@ public boolean intersects(Geometry g) {
* <li><code>[0********]</code> (for L/L situations)
* </ul>
* </ul>
* For any other combination of dimensions this predicate returns <code>false</code>.
* For the A/A and P/P situations this predicate returns <code>false</code>.
* <p>
* The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations.
* In order to make the relation symmetric,
* To make the relation symmetric
* JTS extends the definition to apply to L/P, A/P and A/L situations as well.
*
*@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
Expand Down Expand Up @@ -1857,6 +1857,9 @@ protected boolean equal(Coordinate a, Coordinate b, double tolerance) {

private Point createPointFromInternalCoord(Coordinate coord, Geometry exemplar)
{
// create empty point for null input
if (coord == null)
return exemplar.getFactory().createPoint();
exemplar.getPrecisionModel().makePrecise(coord);
return exemplar.getFactory().createPoint(coord);
}
Expand Down
41 changes: 34 additions & 7 deletions modules/tests/src/test/resources/testxml/general/TestCentroid.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@
<test><op name="getCentroid" arg1="A" > POINT (0 0) </op></test>
</case>

<case>
<desc>A - empty</desc>
<a> POLYGON EMPTY
</a>
<test><op name="getCentroid" arg1="A" > POINT EMPTY </op></test>
</case>

<case>
<desc>A - box</desc>
<a> POLYGON ((40 160, 160 160, 160 40, 40 40, 40 160)) </a>
Expand Down Expand Up @@ -218,6 +225,33 @@
<test><op name="getCentroid" arg1="A" > POINT (10 10) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, line, and point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING (20 20, 30 30, 40 40),
MULTIPOINT ((20 10), (10 20)) )
</a>
<test><op name="getCentroid" arg1="A" > POINT (30 30) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, empty line, and point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING EMPTY,
POINT (10 10) )
</a>
<test><op name="getCentroid" arg1="A" > POINT (10 10) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, empty line, and empty point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING EMPTY,
POINT EMPTY )
</a>
<test><op name="getCentroid" arg1="A" > POINT EMPTY </op></test>
</case>

<case>
<desc>GC - overlapping polygons </desc>
<a> GEOMETRYCOLLECTION (POLYGON ((20 100, 20 -20, 60 -20, 60 100, 20 100)),
Expand All @@ -238,13 +272,6 @@
<test><op name="getCentroid" arg1="A" > POINT (55 55) </op></test>
</case>

<case>
<desc>A - empty</desc>
<a> POLYGON EMPTY
</a>
<test><op name="getCentroid" arg1="A" > POINT EMPTY </op></test>
</case>

<case>
<desc>A - almost degenerate triangle</desc>
<a> POLYGON((
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@
<test><op name="getInteriorPoint" arg1="A" > POINT (140 240) </op></test>
</case>

<case>
<desc>L - empty</desc>
<a> LINESTRING EMPTY
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT EMPTY </op></test>
</case>

<case>
<desc>L - linestring with single segment</desc>
<a> LINESTRING (0 0, 7 14)
</a>
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT (7 14) </op></test>
</case>

Expand Down Expand Up @@ -119,10 +126,37 @@
<a> GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),
LINESTRING (20 20, 20 20),
MULTIPOINT ((20 10), (10 20)) )
</a>
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT (10 10) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, line, and point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING (20 20, 30 30, 40 40),
MULTIPOINT ((20 10), (10 20)) )
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT (30 30) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, empty line, and point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING EMPTY,
POINT (10 10) )
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT (10 10) </op></test>
</case>

<case>
<desc>GC - collection with empty polygon, empty line, and empty point</desc>
<a> GEOMETRYCOLLECTION (POLYGON EMPTY,
LINESTRING EMPTY,
POINT EMPTY )
</a>
<test><op name="getInteriorPoint" arg1="A" > POINT EMPTY </op></test>
</case>



</run>

0 comments on commit b3cab45

Please sign in to comment.