Skip to content
Draft
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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
- Breaking Changes:
- BufferOp returns POLYGON EMPTY when fed Inf/Nan coords (GH-1332)
- Return Inf when calculating distance to an empty geometry (GH-1345, Even Rouault)
- Overlay operations now produce a LineString geometry in cases that would previously
produce a MultiLineString with contiguous sub-geometries. (GH-1459, Dan Baston)


- Fixes/Improvements:
Expand Down
4 changes: 2 additions & 2 deletions src/operation/overlayng/LineBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ std::vector<std::unique_ptr<Curve>>
LineBuilder::getLines()
{
markResultLines();
addResultLines();
addResultLinesMerged();

// Transfer ownership of all the lines to the
// caller
Expand Down Expand Up @@ -252,10 +252,10 @@ LineBuilder::buildLine(OverlayEdge* node) const
const bool constructZ = node->getCoordinatesRO()->hasZ();
const bool constructM = node->getCoordinatesRO()->hasM();
geom::util::CurveBuilder cb(*geometryFactory, constructZ, constructM);
cb.setOutputLinearRing(false);

// assert: edgeStart degree = 1
// assert: edgeStart direction = forward
cb.add(*node->getCoordinatesRO(), node->isCurved());

bool isNodeForward = node->isForward();

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/capi/GEOSDifferenceTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void object::test<3>()
result_ = GEOSDifference(geom1_, geom2_);
ensure(result_);

expected_ = fromWKT("MULTICURVE (CIRCULARSTRING (1.7071067812 0.7071067812, 1.9238795325 0.3826834324, 2 0), CIRCULARSTRING (0 0, 0.6173165676 0.9238795325, 1.7071067812 0.7071067812))");
expected_ = fromWKT("CIRCULARSTRING (0 0, 0.6173165676 0.9238795325, 1.7071067812 0.7071067812, 1.9238795325 0.3826834324, 2 0)");

ensure_geometry_equals(result_, expected_, 1e-8);
}
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/operation/geounion/UnaryUnionOpTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ struct test_unaryuniontest_data {
GeomPtr b2 = normalize(b);
bool eq = a2->equalsExact(b2.get());
if(! eq) {
cout << "EXPECTED: " << wktwriter.write(a2.get()) << endl;
cout << "OBTAINED: " << wktwriter.write(b2.get()) << endl;
}
return eq;
Expand Down Expand Up @@ -184,6 +185,8 @@ template<>
void object::test<6>
()
{
set_test_name("non-simple LineString");

static char const* const geoms[] = {
"LINESTRING (0 0, 10 0, 5 -5, 5 5)",
nullptr
Expand Down
19 changes: 11 additions & 8 deletions tests/unit/operation/overlayng/CoverageUnionNGTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void object::test<9> ()
{
checkUnion(
"MULTILINESTRING ((1 1, 5 1), (9 1, 5 1))",
"MULTILINESTRING ((1 1, 5 1), (5 1, 9 1))");
"LINESTRING (1 1, 5 1, 9 1)");
}

/**
Expand All @@ -169,7 +169,7 @@ void object::test<10> ()
{
checkUnion(
"MULTILINESTRING ((1 1, 2 1, 3 1), (4 1, 3 1, 2 1))",
"MULTILINESTRING ((1 1, 2 1), (2 1, 3 1), (3 1, 4 1))");
"LINESTRING (1 1, 2 1, 3 1, 4 1)");
}

/**
Expand All @@ -181,27 +181,29 @@ void object::test<11> ()
{
checkUnion(
"MULTILINESTRING ((1 9, 3.1 8, 5 7, 7 8, 9 9), (5 7, 5 3, 4 3, 2 3), (9 5, 7 4, 5 3, 8 1))",
"MULTILINESTRING ((1 9, 3.1 8), (2 3, 4 3), (3.1 8, 5 7), (4 3, 5 3), (5 3, 5 7), (5 3, 7 4), (5 3, 8 1), (5 7, 7 8), (7 4, 9 5), (7 8, 9 9))");
"MULTILINESTRING ((1 9, 3.1 8, 5 7), (2 3, 4 3, 5 3), (5 3, 5 7), (5 3, 7 4, 9 5), (5 3, 8 1), (5 7, 7 8, 9 9))");
}

// Z values preserved in linear inpuuts
// Z values preserved in linear inputs
template<>
template<>
void object::test<12> ()
{
// TODO: Should Z values be averaged?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

They are in overlay, so they should be in this operation too, I think is consistent. Probably better than unpredictable ordering based first-in / last-in selection.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agree that averaging is desirable (if the cost is not too great), but after giving the implementation some thought I think it's out-of-scope for this changeset. It's the job of the Noder to average Z values but the noders used in CoverageUnion deliberately avoid the intersection calculations that would produce averages. You can see the same winner-take-all behavior in the polygon CoverageUnion, which is unaffected by this PR:

geosop -a "GEOMETRYCOLLECTION (POLYGON Z ((0 0 0, 1 0 1, 0 1 2, 0 0 0)), POLYGON Z ((1 0 100, 1 1 200, 0 1 300, 1 0 100)))" coverageUnionNG
POLYGON Z ((1 0 1, 0 0 0, 0 1 2, 1 1 200, 1 0 100))

checkUnion(
"MULTILINESTRING Z ((1 1 8, 5 1 9), (9 1 6, 5 1 2))",
"MULTILINESTRING Z ((1 1 8, 5 1 9), (5 1 2, 9 1 6))");
"LINESTRING Z (1 1 8, 5 1 9, 9 1 6)");
}

// M values preserved in linear inpuuts
// M values preserved in linear inputs
template<>
template<>
void object::test<13> ()
{
// TODO: Should M values be averaged?
checkUnion(
"MULTILINESTRING M ((1 1 8, 5 1 9), (9 1 6, 5 1 2))",
"MULTILINESTRING M ((1 1 8, 5 1 9), (5 1 2, 9 1 6))");
"LINESTRING M (1 1 8, 5 1 9, 9 1 6)");
}

// Mixed Z/M values handled in linear inputs
Expand All @@ -210,8 +212,9 @@ template<>
template<>
void object::test<14>()
{
// TODO: Should M values be coalesced?
checkUnion("GEOMETRYCOLLECTION (LINESTRING Z(1 1 8, 5 1 9), LINESTRING M(9 1 6, 5 1 2))",
"MULTILINESTRING ZM ((1 1 8 NaN, 5 1 9 NaN), (5 1 9 2, 9 1 8.5 6))");
"LINESTRING ZM (1 1 8 NaN, 5 1 9 NaN, 9 1 8.5 6)");
}

// Z values preserved in polygonal inputs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,12 @@ template<>
template<>
void object::test<6> ()
{
set_test_name("testSimpleL_AA");

std::string a = "LINESTRING (0 0, 10 10)";
std::string b = "GEOMETRYCOLLECTION ( POLYGON ((1 1, 1 5, 5 5, 5 1, 1 1)), POLYGON ((9 9, 9 5, 5 5, 5 9, 9 9)) )";
testIntersection(a, b,
"MULTILINESTRING ((1 1, 5 5), (5 5, 9 9))");
"LINESTRING (1 1, 5 5, 9 9)");
testUnion(a, b,
"GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1), LINESTRING (9 9, 10 10), POLYGON ((1 1, 1 5, 5 5, 5 1, 1 1)), POLYGON ((5 5, 5 9, 9 9, 9 5, 5 5)))");
}
Expand Down
12 changes: 7 additions & 5 deletions tests/unit/operation/overlayng/OverlayNGTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,12 @@ template<>
template<>
void object::test<13> ()
{
set_test_name("testAreaLineIntersection");

std::string a = "POLYGON ((360 200, 220 200, 220 180, 300 180, 300 160, 300 140, 360 200))";
std::string b = "MULTIPOLYGON (((280 180, 280 160, 300 160, 300 180, 280 180)), ((220 230, 240 230, 240 180, 220 180, 220 230)))";
// std::string exp = "POLYGON ((220 200, 240 200, 240 180, 220 180, 220 200))";
std::string exp = "GEOMETRYCOLLECTION (LINESTRING (280 180, 300 180), LINESTRING (300 160, 300 180), POLYGON ((220 180, 220 200, 240 200, 240 180, 220 180)))";
std::string exp = "GEOMETRYCOLLECTION (LINESTRING (280 180, 300 180, 300 160), POLYGON ((220 180, 220 200, 240 200, 240 180, 220 180)))";
testOverlay(a, b, exp, OverlayNG::INTERSECTION, 1);
}

Expand Down Expand Up @@ -500,9 +502,11 @@ template<>
template<>
void object::test<37> ()
{
set_test_name("testCollapseTriBoxUnion");

std::string a = "POLYGON ((1 3.3, 1.3 1.4, 3.1 1.4, 3.1 0.9, 1.3 0.9, 1 -0.2, 0.8 1.3, 1 3.3))";
std::string b = "POLYGON ((1 2.9, 2.9 2.9, 2.9 1.3, 1.7 1, 1.3 0.9, 1 0.4, 1 2.9))";
std::string exp = "MULTILINESTRING ((1 1, 1 0), (1 3, 1 1), (1 1, 2 1), (2 1, 3 1))";
std::string exp = "MULTILINESTRING ((1 1, 1 0), (1 3, 1 1), (1 1, 2 1, 3 1))";
testOverlay(a, b, exp, OverlayNG::INTERSECTION, 1);
}

Expand Down Expand Up @@ -808,9 +812,7 @@ void object::test<62>()

std::string a = "CIRCULARSTRING (0 0, 1 1, 2 0, 3 -1, 4 0)";

// Noding causes the CircularString to split at (2, 0)
// OverlayNG does not merge output lines, so we get a MultiCurve.
std::string exp = "MULTICURVE (CIRCULARSTRING (0 0, 1 1, 2 0), CIRCULARSTRING (2 0, 3 -1, 4 0))";
std::string exp = "CIRCULARSTRING (0 0, 1 1, 2 0, 3 -1, 4 0)";

testOverlay(a, a, exp, OverlayNG::UNION, 0);
}
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/operation/overlayng/OverlayNGZTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,13 @@ template<>
template<>
void object::test<5> ()
{
set_test_name("testLineOverlapUnion");

checkUnion("LINESTRING (0 0 0, 10 10 10)", "LINESTRING (5 5 990, 15 15 999)",
"MULTILINESTRING Z((0 0 0, 5 5 990), (5 5 990, 10 10 10), (10 10 10, 15 15 999))");
"LINESTRING Z(0 0 0, 5 5 990, 10 10 10, 15 15 999)");

checkUnion("LINESTRING M (0 0 0, 10 10 10)", "LINESTRING M (5 5 990, 15 15 999)",
"MULTILINESTRING M((0 0 0, 5 5 990), (5 5 990, 10 10 10), (10 10 10, 15 15 999))");
"LINESTRING M(0 0 0, 5 5 990, 10 10 10, 15 15 999)");
}

// testLineLineXYDifferenceLineInterpolated
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/operation/overlayng/PrecisionReducerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,10 @@ template<>
template<>
void object::test<13> ()
{
set_test_name("testCollapsedNodedLine");

checkReduce("LINESTRING(1 1, 3 3, 9 9, 5.1 5, 2.1 2)",
1, "MULTILINESTRING ((1 1, 2 2), (2 2, 3 3), (3 3, 5 5), (5 5, 9 9))");
1, "LINESTRING (1 1, 2 2, 3 3, 5 5, 9 9)");
}

//
Expand Down
10 changes: 4 additions & 6 deletions tests/unit/operation/sharedpaths/SharedPathsOpTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,8 @@ void object::test<16>
forwDir.clear();
backDir.clear();
SharedPathsOp::sharedPathsOp(*g0, *g1, forwDir, backDir);
ensure_equals(forwDir.size(), 2u);
ensure_equals(wktwriter.write(forwDir[0]), "LINESTRING (0 0, 5 10)");
ensure_equals(wktwriter.write(forwDir[1]), "LINESTRING (5 10, 10 10)");
ensure_equals(forwDir.size(), 1u);
ensure_equals(wktwriter.write(forwDir[0]), "LINESTRING (0 0, 5 10, 10 10)");
SharedPathsOp::clearEdges(forwDir);

ensure(backDir.empty());
Expand All @@ -343,9 +342,8 @@ void object::test<17>
forwDir.clear();
backDir.clear();
SharedPathsOp::sharedPathsOp(*g0, *g1, forwDir, backDir);
ensure_equals(backDir.size(), 2u);
ensure_equals(wktwriter.write(backDir[0]), "LINESTRING (0 0, 5 10)");
ensure_equals(wktwriter.write(backDir[1]), "LINESTRING (5 10, 10 10)");
ensure_equals(backDir.size(), 1u);
ensure_equals(wktwriter.write(backDir[0]), "LINESTRING (0 0, 5 10, 10 10)");
SharedPathsOp::clearEdges(backDir);

ensure(forwDir.empty());
Expand Down
5 changes: 5 additions & 0 deletions tests/xmltester/XMLTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <geos/operation/buffer/BufferParameters.h>
#include <geos/operation/buffer/BufferOp.h>
#include <geos/operation/polygonize/BuildArea.h>
#include <geos/operation/split/GeometrySplitter.h>
#include <geos/operation/valid/MakeValid.h>
#include <geos/precision/MinimumClearance.h>
#include <geos/simplify/TopologyPreservingSimplifier.h>
Expand Down Expand Up @@ -1395,6 +1396,10 @@ void Test::executeOp(Geometry* gA, Geometry* gB)
double tolerance = std::atof(opArg2.c_str());
checkResult( *geos::simplify::TopologyPreservingSimplifier::simplify(gA, tolerance) );
}
else if (opName == "split")
{
checkResult(*geos::operation::split::GeometrySplitter::split(*gA, *gB));
}
else {
//TODO: error out here?
std::cerr << tester.testcaseRef() << " - " << opName;
Expand Down
5 changes: 2 additions & 3 deletions tests/xmltester/tests/general/TestNGOverlayA.xml
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ Uses a floating precision model.
</b>
<test>
<op name="intersectionNG" arg1="A" arg2="B">
MULTILINESTRING ((27 27, 27 13), (27 13, 13 13), (13 27, 27 27), (13 13, 13 27))
LINESTRING (13 13, 13 27, 27 27, 27 13, 13 13)
</op>
</test>
<test>
Expand Down Expand Up @@ -482,8 +482,7 @@ POLYGON ((13 27, 27 27, 27 13, 13 13, 13 27), (15 25, 20 25, 20 20, 15 20, 15 25
<op name="intersectionNG" arg1="A" arg2="B">
GEOMETRYCOLLECTION (POLYGON ((22 22, 27 22, 27 20, 20 20, 20 25, 20 27, 22 27, 22 22)),
POLYGON ((15 20, 20 20, 20 13, 15 13, 15 15, 13 15, 13 20, 15 20)),
LINESTRING (22 27, 27 27),
LINESTRING (27 27, 27 22))
LINESTRING (22 27, 27 27, 27 22))
</op>
</test>
<test>
Expand Down
11 changes: 5 additions & 6 deletions tests/xmltester/tests/general/TestNGOverlayAPrec.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,9 @@ POLYGON ((1 3.3, 1.3 1.4, 3.1 1.4, 3.1 0.9, 1.3 0.9, 1 -0.2, 0.8 1.3, 1 3.3))
POLYGON ((1 2.9, 2.9 2.9, 2.9 1.3, 1.7 1, 1.3 0.9, 1 0.4, 1 2.9))
</b>
<test> <op name="intersectionSR" arg1="A" arg2="B" arg3="1">
MULTILINESTRING ((1 1, 2 1),
MULTILINESTRING ((1 1, 2 1, 3 1),
(1 1, 1 0),
(1 3, 1 1),
(2 1, 3 1))
(1 3, 1 1))
</op></test>
<test> <op name="unionSR" arg1="A" arg2="B" arg3="1">
GEOMETRYCOLLECTION (POLYGON ((1 1, 1 3, 3 3, 3 1, 2 1, 1 1)),
Expand Down Expand Up @@ -307,10 +306,10 @@ POLYGON ((1 1, 1 4, 3 4, 3 1.3, 7 1, 1 1))
POLYGON ((8 4, 9 4, 9 1, 4 1, 8 1.3, 8 4))
</b>
<test> <op name="intersectionSR" arg1="A" arg2="B" arg3="1">
MULTILINESTRING ((6 1, 7 1), (4 1, 6 1))
LINESTRING (4 1, 6 1, 7 1)
</op></test>
<test> <op name="unionSR" arg1="A" arg2="B" arg3="1">
GEOMETRYCOLLECTION (POLYGON ((9 4, 9 1, 8 1, 8 4, 9 4)), POLYGON ((1 4, 3 4, 3 1, 1 1, 1 4)), LINESTRING (8 1, 7 1), LINESTRING (6 1, 7 1), LINESTRING (3 1, 4 1), LINESTRING (4 1, 6 1))
GEOMETRYCOLLECTION (POLYGON ((9 4, 9 1, 8 1, 8 4, 9 4)), POLYGON ((1 4, 3 4, 3 1, 1 1, 1 4)), LINESTRING (3 1, 4 1, 6 1, 7 1, 8 1))
</op></test>
<test> <op name="differenceSR" arg1="A" arg2="B" arg3="1">
GEOMETRYCOLLECTION (POLYGON ((1 4, 3 4, 3 1, 1 1, 1 4)), LINESTRING (3 1, 4 1))
Expand All @@ -323,4 +322,4 @@ GEOMETRYCOLLECTION (POLYGON ((9 4, 9 1, 8 1, 8 4, 9 4)), POLYGON ((1 4, 3 4, 3 1
</op></test>
</case>

</run>
</run>
2 changes: 1 addition & 1 deletion tests/xmltester/tests/general/TestNGOverlayGC.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Uses a floating precision model.
</b>
<test>
<op name="intersectionNG" arg1="A" arg2="B">
MULTILINESTRING ((1 1, 5 5), (5 5, 9 9))
LINESTRING (1 1, 5 5, 9 9)
</op>
</test>
<test>
Expand Down
18 changes: 9 additions & 9 deletions tests/xmltester/tests/general/TestNGOverlayL.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ POINT (15 15)
MULTILINESTRING ((10 10, 15 15), (15 15, 20 20), (10 20, 15 15), (15 15, 20 10))
</op></test>
<test> <op name="differenceNG" arg1="A" arg2="B">
MULTILINESTRING ((10 10, 15 15), (15 15, 20 20))
LINESTRING (10 10, 15 15, 20 20)
</op></test>
<test> <op name="differenceNG" arg1="B" arg2="A">
MULTILINESTRING ((10 20, 15 15), (15 15, 20 10))
LINESTRING (10 20, 15 15, 20 10)
</op></test>
<test> <op name="symdifferenceNG" arg1="A" arg2="B">
MULTILINESTRING ((10 10, 15 15), (15 15, 20 20), (10 20, 15 15), (15 15, 20 10))
Expand Down Expand Up @@ -75,7 +75,7 @@ LINESTRING (10 10, 20 20)
LINESTRING (20 20, 30 30)
</op></test>
<test> <op name="symdifferenceNG" arg1="A" arg2="B">
MULTILINESTRING ((20 20, 30 30), (10 10, 20 20))
LINESTRING (10 10, 20 20, 30 30)
</op></test>
</case>

Expand Down Expand Up @@ -150,7 +150,7 @@ MULTILINESTRING ((0 10, 10 10, 20 20), (30 30, 40 30))
MULTILINESTRING ((20 0, 20 20), (30 30, 30 40))
</op></test>
<test> <op name="symdifferenceNG" arg1="A" arg2="B">
MULTILINESTRING ((0 10, 10 10, 20 20), (20 0, 20 20), (30 30, 30 40), (30 30, 40 30))
MULTILINESTRING ((0 10, 10 10, 20 20, 20 0), (40 30, 30 30, 30 40))
</op></test>
</case>

Expand All @@ -169,13 +169,13 @@ GEOMETRYCOLLECTION (LINESTRING (0 0, 3 3), POINT (5 5))
MULTILINESTRING ((5 5, 1 9), (0 0, 3 3), (5 5, 10 10), (3 3, 8 2, 5 5), (3 3, 5 5))
</op></test>
<test> <op name="differenceNG" arg1="A" arg2="B">
MULTILINESTRING ((5 5, 10 10), (3 3, 5 5))
LINESTRING (3 3, 5 5, 10 10)
</op></test>
<test> <op name="differenceNG" arg1="B" arg2="A">
MULTILINESTRING ((5 5, 1 9), (3 3, 8 2, 5 5))
LINESTRING (3 3, 8 2, 5 5, 1 9)
</op></test>
<test> <op name="symdifferenceNG" arg1="A" arg2="B">
MULTILINESTRING ((5 5, 1 9), (5 5, 10 10), (3 3, 8 2, 5 5), (3 3, 5 5))
MULTILINESTRING ((5 5, 1 9), (5 5, 10 10), (5 5, 3 3, 8 2, 5 5))
</op></test>
</case>

Expand All @@ -194,10 +194,10 @@ POINT (150 150)
MULTILINESTRING ((150 150, 200 200, 300 300, 400 200), (100 100, 150 150), (190 110, 150 150), (150 150, 120 180))
</op></test>
<test> <op name="differenceNG" arg1="A" arg2="B">
MULTILINESTRING ((150 150, 200 200, 300 300, 400 200), (100 100, 150 150))
LINESTRING (100 100, 150 150, 200 200, 300 300, 400 200)
</op></test>
<test> <op name="differenceNG" arg1="B" arg2="A">
MULTILINESTRING ((190 110, 150 150), (150 150, 120 180))
LINESTRING (190 110, 150 150, 120 180)
</op></test>
<test> <op name="symdifferenceNG" arg1="A" arg2="B">
MULTILINESTRING ((150 150, 200 200, 300 300, 400 200), (100 100, 150 150), (190 110, 150 150), (150 150, 120 180))
Expand Down
Loading
Loading