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

Improve how zero-length linestring are handled by relate #346

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;

/**
Expand Down Expand Up @@ -92,22 +90,22 @@ private void add(Geometry geom)
{
if (geom.isEmpty())
return;
if (geom instanceof Point) {
if (geom instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) geom;
for (int i = 0; i < gc.getNumGeometries(); i++) {
add(gc.getGeometryN(i));
}
}
else if (geom.getDimension() == 0) {
addPoint(geom.getCoordinate());
}
else if (geom instanceof LineString) {
else if (geom.getDimension() == 1) {
addLineSegments(geom.getCoordinates());
}
else if (geom instanceof Polygon) {
else if (geom.getDimension() == 2) {
Polygon poly = (Polygon) geom;
add(poly);
}
else if (geom instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) geom;
for (int i = 0; i < gc.getNumGeometries(); i++) {
add(gc.getGeometryN(i));
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public Coordinate getInteriorPoint()
*/
private void addInterior(Geometry geom)
{
if (geom instanceof LineString) {
if (geom.getDimension() == 1) {
addInterior(geom.getCoordinates());
}
else if (geom instanceof GeometryCollection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.Point;

/**
* Computes a point in the interior of an point geometry.
Expand Down Expand Up @@ -44,15 +43,15 @@ public InteriorPointPoint(Geometry g)
*/
private void add(Geometry geom)
{
if (geom instanceof Point) {
add(geom.getCoordinate());
}
else if (geom instanceof GeometryCollection) {
if (geom instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) geom;
for (int i = 0; i < gc.getNumGeometries(); i++) {
add(gc.getGeometryN(i));
}
}
else if (geom.getDimension() == 0) {
add(geom.getCoordinate());
}
}
private void add(Coordinate point)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,16 @@ public Coordinate getCoordinate()
}

public int getDimension() {
return 1;
// Test if geometry is non empty and has several distinct coordinates
if (new CoordinateList(points.toCoordinateArray(),false).size()==1)
return 0;
else
// valid or empty LineString return 1
return 1;
}

public int getBoundaryDimension() {
if (isClosed()) {
if (isClosed() || getDimension() == 0) {
return Dimension.FALSE;
}
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,16 @@ public MultiLineString(LineString[] lineStrings, GeometryFactory factory) {
super(lineStrings, factory);
}


public int getDimension() {
return 1;
if (isEmpty())
return 1;
else
// super will get the heighest dimension of components
return super.getDimension();
}


public int getBoundaryDimension() {
if (isClosed()) {
return Dimension.FALSE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ public MultiPolygon(Polygon[] polygons, GeometryFactory factory) {
}

public int getDimension() {
return 2;
if (isEmpty())
return 2;
else
// super will get the heighest dimension of components
return super.getDimension();
}

public int getBoundaryDimension() {
Expand Down
13 changes: 11 additions & 2 deletions modules/core/src/main/java/org/locationtech/jts/geom/Polygon.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,20 @@ public int getNumPoints() {
}

public int getDimension() {
return 2;
if (getExteriorRing().getDimension() == 0)
return 0;
else
// Does not handle the case of 1-dimension collapsed polygon
// if exteriorRing is empty, returns 2 (not sure why)
return 2;
}

public int getBoundaryDimension() {
return 1;
if (isEmpty())
// Return the same dimension as an empty LinearRing
return 1;
else
return getExteriorRing().getDimension();
}

public boolean isEmpty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ private void addLineString(LineString line)
if (coord.length < 2) {
hasTooFewPoints = true;
invalidPoint = coord[0];
// If line is made of a single point, geometry is invalid (hasTooFewPoint),
// but the point must still be added to the graph in order to be able to be
// compute correct predicate (e.g. intersects) with another GeometryGraphe
addPoint(coord[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a BIG comment here indicating that this is an enhancement to standard OGC semantics, and is potentially a source of (as yet unknown) logic bugs.

return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,34 @@ private void checkInteriorPoint(Geometry g)
assertTrue(g.contains(ip));
}

/**
public void testPointInteriorPoint() throws ParseException {
Geometry point = rdr.read("Point(10 10)");
assertTrue(point.getInteriorPoint().equals(rdr.read("POINT(10 10)")));
}

public void testMultiPointInteriorPoint() throws ParseException {
Geometry point = rdr.read("MULTIPOINT ((60 300), (200 200), (240 240), (200 300), (40 140), (80 240), (140 240), (100 160), (140 200), (60 200))");
assertTrue(point.getInteriorPoint().equals(rdr.read("POINT (140 240)")));
}

public void testRelate() throws ParseException {
Geometry point = rdr.read("POINT (10 10)");
Geometry line = rdr.read("LINESTRING (10 10, 10 10)");
assertTrue(point.equalsTopo(line));
}

public void testGeometryCollection() throws ParseException {
Geometry gc = rdr.read("GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)), \n" +
" LINESTRING (20 20, 30 30))");
assertTrue(gc.getInteriorPoint().equals(rdr.read("POINT(20 20)")));
}


public void testZeroLengthLineStringInteriorPoint() throws ParseException {
Geometry line = rdr.read("LineString(10 10, 10 10)");
assertTrue(line.getInteriorPoint().equals(rdr.read("POINT(10 10)")));
}
**/

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package org.locationtech.jts.geom;

import junit.framework.TestCase;
import junit.textui.TestRunner;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;


public class CollapsedGeometryDimensionTest extends TestCase {

public static void main(String args[]) {
TestRunner.run(CollapsedGeometryDimensionTest.class);
}

private GeometryFactory factory = new GeometryFactory();
private WKTReader reader = new WKTReader(factory);

public CollapsedGeometryDimensionTest(String name) { super(name); }

public void testMock()
{
assertTrue(true);
}

public void testPoint() throws ParseException
{
// empty
assertTrue(reader.read("Point Empty").getDimension() == 0);
// normal
assertTrue(reader.read("Point(0 0)").getDimension() == 0);
// collapsed
assertTrue(reader.read("Point Empty").getDimension() == 0);
}

public void testLineString() throws ParseException
{
// empty
assertTrue(reader.read("LineString Empty").getDimension() == 1);
// normal (open/closed)
assertTrue(reader.read("LineString(0 0, 1 0)").getDimension() == 1);
assertTrue(reader.read("LineString(0 0, 1 0, 0.5 0.5, 0 0)").getDimension() == 1);
// collapsed
assertTrue(reader.read("LineString(0 0, 0 0)").getDimension() == 0);
}

public void testPolygon() throws ParseException
{
// empty
assertTrue(reader.read("Polygon Empty").getDimension() == 2);
// normal
assertTrue(reader.read("Polygon((0 0, 1 0, 0.5 0.5, 0 0))").getDimension() == 2);
// collapsed in dimension 1 (not yet detected -> dimension 2)
assertTrue(reader.read("Polygon((0 0, 1 0, 2 0, 0 0))").getDimension() == 2);
// collapsed
assertTrue(reader.read("Polygon((0 0, 0 0, 0 0, 0 0))").getDimension() == 0);
// cannot be initialized (linear ring not closed)
//assertTrue(reader.read("Polygon((0 0, 1 0, 1 0, 1 0))").getDimension() == 1);
}

public void testLinearRing() throws ParseException
{
// empty
assertTrue(reader.read("LinearRing Empty").getDimension() == 1);
// normal
assertTrue(reader.read("LinearRing(0 0, 1 0, 0.5 0.5, 0 0)").getDimension() == 1);
assertTrue(reader.read("LinearRing(0 0, 1 0, 2 0, 0 0)").getDimension() == 1);
// collapsed
assertTrue(reader.read("LinearRing(0 0, 0 0, 0 0, 0 0)").getDimension() == 0);
}

public void testMultiPoint() throws ParseException
{
// empty
assertTrue(reader.read("MultiPoint Empty").getDimension() == 0);
// normal
assertTrue(reader.read("MultiPoint((0 0), (1 1))").getDimension() == 0);
// normal
assertTrue(reader.read("MultiPoint((0 0), (0 0))").getDimension() == 0);
}

public void testMultiLineString() throws ParseException
{
// empty
assertTrue(reader.read("MultiLineString Empty").getDimension() == 1);
// normal (open/closed)
assertTrue(reader.read("MultiLineString((0 0, 1 0), (2 0, 3 0))").getDimension() == 1);
assertTrue(reader.read("MultiLineString((0 0, 1 0, 0.5 0.5, 0 0))").getDimension() == 1);
// partially collapsed
assertTrue(reader.read("MultiLineString((0 0, 0 0), (1 0, 2 0))").getDimension() == 1);
// collapsed
assertTrue(reader.read("MultiLineString((0 0, 0 0), (1 0, 1 0))").getDimension() == 0);
}

public void testMultiPolygon() throws ParseException
{
// empty
assertTrue(reader.read("MultiPolygon Empty").getDimension() == 2);
// normal
assertTrue(reader.read("MultiPolygon(((0 0, 1 0, 0.5 0.5, 0 0)),((10 0, 11 0, 10.5 0.5, 10 0)))").getDimension() == 2);
// partially collapsed
assertTrue(reader.read("MultiPolygon(((0 0, 1 0, 0.5 0.5, 0 0)),((0 0, 0 0, 0 0, 0 0)))").getDimension() == 2);
// collapsed
assertTrue(reader.read("MultiPolygon(((0 0, 0 0, 0 0, 0 0)),((1 1, 1 1, 1 1, 1 1)))").getDimension() == 0);
}

public void tesGeometryCollection() throws ParseException
{
// empty
assertTrue(reader.read("GeometryCollection Empty").getDimension() == 0);
// normal
assertTrue(reader.read("GeometryCollection (Point(0 0),LineString(0 0, 1 0)").getDimension() == 1);
assertTrue(reader.read("GeometryCollection (Point(0 0),LineString(0 0, 1 0), Polygon((0 0, 1 0, 0.5 0.5, 0 0))").getDimension() == 2);
// collapsed
assertTrue(reader.read("GeometryCollection (Point(0 0),LineString(0 0, 0 0)").getDimension() == 0);
assertTrue(reader.read("GeometryCollection (Point(0 0),Polygon((0 0, 0 0, 0 0, 0 0))").getDimension() == 0);
}

}