diff --git a/src/operation/relateng/TopologyComputer.cpp b/src/operation/relateng/TopologyComputer.cpp index 1e1c64683..1c164d635 100644 --- a/src/operation/relateng/TopologyComputer.cpp +++ b/src/operation/relateng/TopologyComputer.cpp @@ -302,10 +302,16 @@ TopologyComputer::addPointOnPointExterior(bool isGeomA, const CoordinateXY* pt) /* public */ void -TopologyComputer::addPointOnGeometry(bool isA, Location locTarget, int dimTarget, const CoordinateXY* pt) +TopologyComputer::addPointOnGeometry(bool isPointA, Location locTarget, int dimTarget, const CoordinateXY* pt) { (void)pt; - updateDim(isA, Location::INTERIOR, locTarget, Dimension::P); + //-- update entry for Point interior + updateDim(isPointA, Location::INTERIOR, locTarget, Dimension::P); + + //-- an empty geometry has no points to infer entries from + if (getGeometry(! isPointA).isEmpty()) + return; + switch (dimTarget) { case Dimension::P: return; @@ -323,8 +329,8 @@ TopologyComputer::addPointOnGeometry(bool isA, Location locTarget, int dimTarget * If a point intersects an area target, then the area interior and boundary * must extend beyond the point and thus interact with its exterior. */ - updateDim(isA, Location::EXTERIOR, Location::INTERIOR, Dimension::A); - updateDim(isA, Location::EXTERIOR, Location::BOUNDARY, Dimension::L); + updateDim(isPointA, Location::EXTERIOR, Location::INTERIOR, Dimension::A); + updateDim(isPointA, Location::EXTERIOR, Location::BOUNDARY, Dimension::L); return; } throw IllegalStateException("Unknown target dimension: " + std::to_string(dimTarget)); @@ -339,6 +345,10 @@ TopologyComputer::addLineEndOnGeometry(bool isLineA, Location locLineEnd, Locati //-- record topology at line end point updateDim(isLineA, locLineEnd, locTarget, Dimension::P); + //-- an empty geometry has no points to infer entries from + if (getGeometry(! isLineA).isEmpty()) + return; + //-- Line and Area targets may have additional topology switch (dimTarget) { case Dimension::P: diff --git a/tests/unit/operation/relateng/RelateNGTest.cpp b/tests/unit/operation/relateng/RelateNGTest.cpp index 7e54c71c9..2a4a53156 100644 --- a/tests/unit/operation/relateng/RelateNGTest.cpp +++ b/tests/unit/operation/relateng/RelateNGTest.cpp @@ -839,20 +839,21 @@ void object::test<60> () //================ Empty Geometries ============== +std::string empties[] = { + "POINT EMPTY", + "LINESTRING EMPTY", + "POLYGON EMPTY", + "MULTIPOINT EMPTY", + "MULTILINESTRING EMPTY", + "MULTIPOLYGON EMPTY", + "GEOMETRYCOLLECTION EMPTY" +}; + //-- test equals against all combinations of empty geometries template<> template<> void object::test<61> () { - std::string empties[] = { - "POINT EMPTY", - "LINESTRING EMPTY", - "POLYGON EMPTY", - "MULTIPOINT EMPTY", - "MULTILINESTRING EMPTY", - "MULTIPOLYGON EMPTY", - "GEOMETRYCOLLECTION EMPTY" - }; int nempty = 7; for (int i = 0; i < nempty; i++) { for (int j = 0; j < nempty; j++) { @@ -862,13 +863,51 @@ void object::test<61> () checkEquals(a, b, true); } } +} +// testEmptyNonEmpty +template<> +template<> +void object::test<62> () +{ + std::string nonEmptyPoint = "POINT (1 1)"; + std::string nonEmptyLine = "LINESTRING (1 1, 2 2)"; + std::string nonEmptyPolygon = "POLYGON ((1 1, 1 2, 2 1, 1 1))"; + + for (int i = 0; i < 7; i++) { + std::string empty = empties[i]; + + checkRelate(empty, nonEmptyPoint, "FFFFFF0F2"); + checkRelate(nonEmptyPoint, empty, "FF0FFFFF2"); + + checkRelate(empty, nonEmptyLine, "FFFFFF102"); + checkRelate(nonEmptyLine, empty, "FF1FF0FF2"); + + checkRelate(empty, nonEmptyPolygon, "FFFFFF212"); + checkRelate(nonEmptyPolygon, empty, "FF2FF1FF2"); + + checkEquals(empty, nonEmptyPoint, false); + checkEquals(empty, nonEmptyLine, false); + checkEquals(empty, nonEmptyPolygon, false); + + checkIntersectsDisjoint(empty, nonEmptyPoint, false); + checkIntersectsDisjoint(empty, nonEmptyLine, false); + checkIntersectsDisjoint(empty, nonEmptyPolygon, false); + + checkContainsWithin(empty, nonEmptyPoint, false); + checkContainsWithin(empty, nonEmptyLine, false); + checkContainsWithin(empty, nonEmptyPolygon, false); + + checkContainsWithin(nonEmptyPoint, empty, false); + checkContainsWithin(nonEmptyLine, empty, false); + checkContainsWithin(nonEmptyPolygon, empty, false); + } } // Prepared test template<> template<> -void object::test<62> () +void object::test<63> () { std::string a = "POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))"; std::string b = "POLYGON((0.5 0.5, 1.5 0.5, 1.5 1.5, 0.5 1.5, 0.5 0.5))"; diff --git a/tests/xmltester/tests/general/TestRelateEmpty.xml b/tests/xmltester/tests/general/TestRelateEmpty.xml new file mode 100644 index 000000000..6ed612820 --- /dev/null +++ b/tests/xmltester/tests/general/TestRelateEmpty.xml @@ -0,0 +1,1114 @@ + + + Test relate predicates against cases containing EMPTY geometries. + + + + + P/P - empty point VS empty point + + POINT EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/L - empty point VS empty line + + POINT EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/A - empty point VS empty polygon + + POINT EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/mP - empty Point VS empty MultiPoint + + POINT EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/mL - empty Point VS empty MultiLineString + + POINT EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/mA - empty Point VS empty MultiPolygon + + POINT EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + P/GC - empty Point VS empty GC + + POINT EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + L/P - empty line VS empty point + + LINESTRING EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/L - empty line VS empty line + + LINESTRING EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/A - empty line VS empty polygon + + LINESTRING EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/mP - empty line VS empty MultiPoint + + LINESTRING EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/mL - empty line VS empty MultiLineString + + LINESTRING EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/mA - empty line VS empty MultiPolygon + + LINESTRING EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + L/GC - empty line VS empty GC + + LINESTRING EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + + A/P - empty polygon VS empty line + + POLYGON EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/L - empty polygon VS empty line + + POLYGON EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/A - empty polygon VS empty polygon + + POLYGON EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/mP - empty polygon VS empty MultiPoint + + POLYGON EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/mP - empty polygon VS empty MultiLineString + + POLYGON EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/mP - empty polygon VS empty MultiPolygon + + POLYGON EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + A/mP - empty polygon VS empty GC + + POLYGON EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + mP/P - empty MultiPoint VS empty point + + MULTIPOINT EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/L - empty MultiPoint VS empty line + + MULTIPOINT EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/A - empty MultiPoint VS empty polygon + + MULTIPOINT EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/mP - empty MultiPoint VS empty MultiPoint + + MULTIPOINT EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/mL - empty MultiPoint VS empty MultiLineString + + MULTIPOINT EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/mA - empty MultiPoint VS empty MultiPolygon + + MULTIPOINT EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mP/GC - empty MultiPoint VS empty GC + + MULTIPOINT EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + mL/P - empty Multiline VS empty point + + MULTILINESTRING EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/L - empty Multiline VS empty line + + MULTILINESTRING EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/A - empty Multiline VS empty polygon + + MULTILINESTRING EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/mP - empty Multiline VS empty MultiPoint + + MULTILINESTRING EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/mL - empty Multiline VS empty MultiLineString + + MULTILINESTRING EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/mA - empty Multiline VS empty MultiPolygon + + MULTILINESTRING EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mL/GC - empty Multiline VS empty GC + + MULTILINESTRING EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + + mA/P - empty Multipolygon VS empty line + + MULTIPOLYGON EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/L - empty Multipolygon VS empty line + + MULTIPOLYGON EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/A - empty Multipolygon VS empty polygon + + MULTIPOLYGON EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/mP - empty Multipolygon VS empty MultiPoint + + MULTIPOLYGON EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/mL - empty Multipolygon VS empty MultiLineString + + MULTIPOLYGON EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/mA - empty Multipolygon VS empty MultiPolygon + + MULTIPOLYGON EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + mA/GC - empty Multipolygon VS empty GC + + MULTIPOLYGON EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + + GC/P - empty GC VS empty line + + GEOMETRYCOLLECTION EMPTY + + + POINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/L - empty GC VS empty line + + GEOMETRYCOLLECTION EMPTY + + + LINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/A - empty GC VS empty polygon + + GEOMETRYCOLLECTION EMPTY + + + POLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/mP - empty GC VS empty MultiPoint + + GEOMETRYCOLLECTION EMPTY + + + MULTIPOINT EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/mL - empty GC VS empty MultiLineString + + GEOMETRYCOLLECTION EMPTY + + + MULTILINESTRING EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/mA - empty GC VS empty MultiPolygon + + GEOMETRYCOLLECTION EMPTY + + + MULTIPOLYGON EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + GC/GC - empty GC VS empty GC + + GEOMETRYCOLLECTION EMPTY + + + GEOMETRYCOLLECTION EMPTY + + true + false + false + false + false + true + true + false + false + false + false + + + + + + P/P - empty Point VS Point + + POINT EMPTY + + + POINT (1 1) + + true + false + false + false + false + true + false + false + false + false + false + + + + + P/L - empty Point VS LineString + + POINT EMPTY + + + LINESTRING (1 1, 2 2) + + true + false + false + false + false + true + false + false + false + false + false + + + + P/L - empty Point VS Polygon + + POINT EMPTY + + + POLYGON ((1 1, 1 2, 2 1, 1 1)) + + true + false + false + false + false + true + false + false + false + false + false + + + + + +