Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix InteriorPoint to handle partially empty collections #698

Merged
merged 1 commit into from
Mar 5, 2021
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 @@ -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>