[geos-commits] [SCM] GEOS branch main updated. 0eef2191a0563fca2996139ce130d3bd5d33997b
git at osgeo.org
git at osgeo.org
Tue Feb 11 15:20:25 PST 2025
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".
The branch, main has been updated
via 0eef2191a0563fca2996139ce130d3bd5d33997b (commit)
from f67563f307264544fb390528315511ab772386d0 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 0eef2191a0563fca2996139ce130d3bd5d33997b
Author: Martin Davis <mtnclimb at gmail.com>
Date: Tue Feb 11 15:19:28 2025 -0800
Fix CCW ring buffer generation
diff --git a/include/geos/operation/buffer/BufferCurveSetBuilder.h b/include/geos/operation/buffer/BufferCurveSetBuilder.h
index f1461871c..789b8c935 100644
--- a/include/geos/operation/buffer/BufferCurveSetBuilder.h
+++ b/include/geos/operation/buffer/BufferCurveSetBuilder.h
@@ -120,7 +120,7 @@ private:
void addPolygon(const geom::Polygon* p);
- void addRingBothSides(const geom::CoordinateSequence* coord, double p_distance);
+ void addLinearRingSides(const geom::CoordinateSequence* coord, double p_distance);
/**
* Add an offset curve for a polygon ring.
@@ -140,10 +140,14 @@ private:
* @param cwRightLoc the location on the R side of the ring
* (if it is CW)
*/
- void addRingSide(const geom::CoordinateSequence* coord,
+ void addPolygonRingSide(const geom::CoordinateSequence* coord,
double offsetDistance, int side, geom::Location cwLeftLoc,
geom::Location cwRightLoc);
+ void addRingSide(const geom::CoordinateSequence* coord,
+ double offsetDistance, int side, geom::Location leftLoc,
+ geom::Location rightLoc);
+
/**
* Tests whether the offset curve for a ring is fully inverted.
* An inverted ("inside-out") curve occurs in some specific situations
diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp
index cb2b1c510..7fc39e77c 100644
--- a/src/operation/buffer/BufferCurveSetBuilder.cpp
+++ b/src/operation/buffer/BufferCurveSetBuilder.cpp
@@ -210,16 +210,44 @@ BufferCurveSetBuilder::addLineString(const LineString* line)
* Singled-sided buffers currently treat rings as if they are lines.
*/
if (coord->isRing() && ! curveBuilder.getBufferParameters().isSingleSided()) {
- addRingBothSides(coord.get(), distance);
+ addLinearRingSides(coord.get(), distance);
}
else {
std::vector<CoordinateSequence*> lineList;
curveBuilder.getLineCurve(coord.get(), distance, lineList);
addCurves(lineList, Location::EXTERIOR, Location::INTERIOR);
}
-
}
+/* private */
+void
+BufferCurveSetBuilder::addLinearRingSides(const CoordinateSequence* coord, double p_distance)
+{
+ /*
+ * (f "hole" side will be eroded completely, avoid generating it.
+ * This prevents hole artifacts (e.g. https://github.com/libgeos/geos/issues/1223)
+ */
+ //-- distance is assumed positive, due to previous checks
+ Envelope env;
+ coord->expandEnvelope(env);
+ bool isHoleComputed = ! isRingFullyEroded(coord, &env, true, distance);
+
+ bool isCCW = isRingCCW(coord);
+
+ bool isShellLeft = ! isCCW;
+ if (isShellLeft || isHoleComputed) {
+ addRingSide(coord, p_distance,
+ Position::LEFT,
+ Location::EXTERIOR, Location::INTERIOR);
+ }
+
+ bool isShellRight = isCCW;
+ if (isShellRight || isHoleComputed) {
+ addRingSide(coord, p_distance,
+ Position::RIGHT,
+ Location::INTERIOR, Location::EXTERIOR);
+ }
+}
/*private*/
void
@@ -257,7 +285,7 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p)
return;
}
- addRingSide(
+ addPolygonRingSide(
shellCoord.get(),
offsetDistance,
offsetSide,
@@ -279,7 +307,7 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p)
// Holes are topologically labelled opposite to the shell,
// since the interior of the polygon lies on their opposite
// side (on the left, if the hole is oriented CCW)
- addRingSide(
+ addPolygonRingSide(
holeCoord.get(),
offsetDistance,
Position::opposite(offsetSide),
@@ -290,38 +318,7 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p)
/* private */
void
-BufferCurveSetBuilder::addRingBothSides(const CoordinateSequence* coord, double p_distance)
-{
- /*
- * (f "hole" side will be eroded completely, avoid generating it.
- * This prevents hole artifacts (e.g. https://github.com/libgeos/geos/issues/1223)
- */
- //-- distance is assumed positive, due to previous checks
- Envelope env;
- coord->expandEnvelope(env);
- bool isHoleComputed = ! isRingFullyEroded(coord, &env, true, distance);
-
- bool isCCW = isRingCCW(coord);
-
- bool isShellLeft = ! isCCW;
- if (isShellLeft || isHoleComputed) {
- addRingSide(coord, p_distance,
- Position::LEFT,
- Location::EXTERIOR, Location::INTERIOR);
- }
-
- bool isShellRight = isCCW;
- if (isShellRight || isHoleComputed) {
- addRingSide(coord, p_distance,
- Position::RIGHT,
- Location::INTERIOR, Location::EXTERIOR);
- }
-}
-
-
-/* private */
-void
-BufferCurveSetBuilder::addRingSide(const CoordinateSequence* coord,
+BufferCurveSetBuilder::addPolygonRingSide(const CoordinateSequence* coord,
double offsetDistance, int side, geom::Location cwLeftLoc, geom::Location cwRightLoc)
{
@@ -353,6 +350,14 @@ BufferCurveSetBuilder::addRingSide(const CoordinateSequence* coord,
#endif
side = Position::opposite(side);
}
+ addRingSide(coord, offsetDistance, side, leftLoc, rightLoc);
+}
+
+/* private */
+void
+BufferCurveSetBuilder::addRingSide(const CoordinateSequence* coord,
+ double offsetDistance, int side, geom::Location leftLoc, geom::Location rightLoc)
+{
std::vector<CoordinateSequence*> lineList;
curveBuilder.getRingCurve(coord, side, offsetDistance, lineList);
// ASSERT: lineList contains exactly 1 curve (this is the JTS semantics)
diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp
index f67d1a12b..63d8fb4bc 100644
--- a/tests/unit/operation/buffer/BufferOpTest.cpp
+++ b/tests/unit/operation/buffer/BufferOpTest.cpp
@@ -585,4 +585,17 @@ void object::test<25>
checkArea(*result2, 107);
}
+// testRingCCW
+// See https://github.com/libgeos/geos/issues/1236
+template<>
+template<>
+void object::test<26>
+()
+{
+ std::string wkt("LINEARRING (-0.25 0.25, -0.25 0.75, -0.75 0.75, -0.75 0.25, -0.25 0.25)");
+
+ checkBuffer(wkt, 1, 0.1,
+ "POLYGON ((0.73 0.05, 0.67 -0.13, 0.58 -0.31, 0.46 -0.46, 0.31 -0.58, 0.13 -0.67, -0.05 -0.73, -0.25 -0.75, -0.75 -0.75, -0.95 -0.73, -1.13 -0.67, -1.31 -0.58, -1.46 -0.46, -1.58 -0.31, -1.67 -0.13, -1.73 0.05, -1.75 0.25, -1.75 0.75, -1.73 0.95, -1.67 1.13, -1.58 1.31, -1.46 1.46, -1.31 1.58, -1.13 1.67, -0.95 1.73, -0.75 1.75, -0.25 1.75, -0.05 1.73, 0.13 1.67, 0.31 1.58, 0.46 1.46, 0.58 1.31, 0.67 1.13, 0.73 0.95, 0.75 0.75, 0.75 0.25, 0.73 0.05))");
+}
+
} // namespace tut
diff --git a/tests/xmltester/tests/general/TestBuffer.xml b/tests/xmltester/tests/general/TestBuffer.xml
index 865a7ac07..acc8efc2f 100644
--- a/tests/xmltester/tests/general/TestBuffer.xml
+++ b/tests/xmltester/tests/general/TestBuffer.xml
@@ -33,6 +33,57 @@
</op></test>
</case>
+<case>
+ <desc>
+ Closed Line
+ </desc>
+ <a>
+ LINESTRING (1 9, 9 9, 9 1, 1 1, 1 9)
+ </a>
+<test><op name='buffer' arg1='A' arg2='-1.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='0.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='1'>
+POLYGON ((1 10, 9 10, 9.195090322016128 9.98078528040323, 9.38268343236509 9.923879532511286, 9.555570233019603 9.831469612302545, 9.707106781186548 9.707106781186548, 9.831469612302545 9.555570233019601, 9.923879532511286 9.38268343236509, 9.98078528040323 9.195090322016128, 10 9, 10 1, 9.98078528040323 0.8049096779838718, 9.923879532511286 0.6173165676349102, 9.831469612302545 0.4444297669803978, 9.707106781186548 0.2928932188134525, 9.555570233019603 0.1685303876974548, 9.38268343236509 0.0761204674887133, 9.195090322016128 0.0192147195967696, 9 0, 1 0, 0.8049096779838718 0.0192147195967696, 0.6173165676349103 0.0761204674887133, 0.444429766980398 0.1685303876974547, 0.2928932188134525 0.2928932188134524, 0.1685303876974547 0.4444297669803978, 0.0761204674887133 0.6173165676349102, 0.0192147195967696 0.8049096779838714, 0 1, 0 9, 0.0192147195967696 9.195090322016128, 0.0761204674887133 9.38268343236509, 0.1685303876974547 9.555570233019601, 0.2928932188134525 9.707106781186548, 0
.444429766980398 9.831469612302545, 0.6173165676349103 9.923879532511286, 0.8049096779838718 9.98078528040323, 1 10), (2 8, 2 2, 8 2, 8 8, 2 8))
+ </op></test>
+<test><op name='buffer' arg1='A' arg2='10.0'>
+POLYGON ((1 19, 9 19, 10.950903220161283 18.807852804032304, 12.826834323650898 18.238795325112868, 14.555702330196024 17.314696123025453, 16.071067811865476 16.071067811865476, 17.314696123025453 14.555702330196022, 18.238795325112868 12.826834323650898, 18.807852804032304 10.950903220161283, 19 9, 19 1, 18.807852804032304 -0.9509032201612824, 18.238795325112868 -2.826834323650898, 17.314696123025453 -4.555702330196022, 16.071067811865476 -6.071067811865475, 14.555702330196024 -7.314696123025453, 12.826834323650898 -8.238795325112868, 10.950903220161283 -8.807852804032304, 9 -9, 1 -9, -0.9509032201612819 -8.807852804032304, -2.826834323650897 -8.238795325112868, -4.55570233019602 -7.314696123025453, -6.071067811865475 -6.0710678118654755, -7.314696123025453 -4.555702330196022, -8.238795325112868 -2.826834323650899, -8.807852804032304 -0.9509032201612861, -9 1, -9 9, -8.807852804032304 10.950903220161287, -8.238795325112868 12.8268343236509, -7.314696123025453 14.555702330196022, -6
.071067811865475 16.071067811865476, -4.55570233019602 17.314696123025453, -2.826834323650897 18.238795325112868, -0.9509032201612819 18.807852804032304, 1 19))
+ </op></test>
+</case>
+
+<case>
+ <desc>
+ Closed Line - CCW
+ </desc>
+ <a>
+ LINESTRING (1 9, 1 1, 9 1, 9 9, 1 9)
+ </a>
+<test><op name='buffer' arg1='A' arg2='-1.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='0.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='1'>
+POLYGON ((1 10, 9 10, 9.195090322016128 9.98078528040323, 9.38268343236509 9.923879532511286, 9.555570233019603 9.831469612302545, 9.707106781186548 9.707106781186548, 9.831469612302545 9.555570233019601, 9.923879532511286 9.38268343236509, 9.98078528040323 9.195090322016128, 10 9, 10 1, 9.98078528040323 0.8049096779838718, 9.923879532511286 0.6173165676349102, 9.831469612302545 0.4444297669803978, 9.707106781186548 0.2928932188134525, 9.555570233019603 0.1685303876974548, 9.38268343236509 0.0761204674887133, 9.195090322016128 0.0192147195967696, 9 0, 1 0, 0.8049096779838718 0.0192147195967696, 0.6173165676349103 0.0761204674887133, 0.444429766980398 0.1685303876974547, 0.2928932188134525 0.2928932188134524, 0.1685303876974547 0.4444297669803978, 0.0761204674887133 0.6173165676349102, 0.0192147195967696 0.8049096779838714, 0 1, 0 9, 0.0192147195967696 9.195090322016128, 0.0761204674887133 9.38268343236509, 0.1685303876974547 9.555570233019601, 0.2928932188134525 9.707106781186548, 0
.444429766980398 9.831469612302545, 0.6173165676349103 9.923879532511286, 0.8049096779838718 9.98078528040323, 1 10), (2 8, 2 2, 8 2, 8 8, 2 8))
+ </op></test>
+<test><op name='buffer' arg1='A' arg2='10.0'>
+POLYGON ((1 19, 9 19, 10.950903220161283 18.807852804032304, 12.826834323650898 18.238795325112868, 14.555702330196024 17.314696123025453, 16.071067811865476 16.071067811865476, 17.314696123025453 14.555702330196022, 18.238795325112868 12.826834323650898, 18.807852804032304 10.950903220161283, 19 9, 19 1, 18.807852804032304 -0.9509032201612824, 18.238795325112868 -2.826834323650898, 17.314696123025453 -4.555702330196022, 16.071067811865476 -6.071067811865475, 14.555702330196024 -7.314696123025453, 12.826834323650898 -8.238795325112868, 10.950903220161283 -8.807852804032304, 9 -9, 1 -9, -0.9509032201612819 -8.807852804032304, -2.826834323650897 -8.238795325112868, -4.55570233019602 -7.314696123025453, -6.071067811865475 -6.0710678118654755, -7.314696123025453 -4.555702330196022, -8.238795325112868 -2.826834323650899, -8.807852804032304 -0.9509032201612861, -9 1, -9 9, -8.807852804032304 10.950903220161287, -8.238795325112868 12.8268343236509, -7.314696123025453 14.555702330196022, -6
.071067811865475 16.071067811865476, -4.55570233019602 17.314696123025453, -2.826834323650897 18.238795325112868, -0.9509032201612819 18.807852804032304, 1 19))
+ </op></test>
+</case>
+
+<case>
+ <desc>
+ Linear Ring
+ </desc>
+ <a>
+ LINEARRING (1 9, 1 1, 9 1, 9 9, 1 9)
+ </a>
+<test><op name='buffer' arg1='A' arg2='-1.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='0.0'> POLYGON EMPTY </op></test>
+<test><op name='buffer' arg1='A' arg2='1'>
+POLYGON ((1 10, 9 10, 9.195090322016128 9.98078528040323, 9.38268343236509 9.923879532511286, 9.555570233019603 9.831469612302545, 9.707106781186548 9.707106781186548, 9.831469612302545 9.555570233019601, 9.923879532511286 9.38268343236509, 9.98078528040323 9.195090322016128, 10 9, 10 1, 9.98078528040323 0.8049096779838718, 9.923879532511286 0.6173165676349102, 9.831469612302545 0.4444297669803978, 9.707106781186548 0.2928932188134525, 9.555570233019603 0.1685303876974548, 9.38268343236509 0.0761204674887133, 9.195090322016128 0.0192147195967696, 9 0, 1 0, 0.8049096779838718 0.0192147195967696, 0.6173165676349103 0.0761204674887133, 0.444429766980398 0.1685303876974547, 0.2928932188134525 0.2928932188134524, 0.1685303876974547 0.4444297669803978, 0.0761204674887133 0.6173165676349102, 0.0192147195967696 0.8049096779838714, 0 1, 0 9, 0.0192147195967696 9.195090322016128, 0.0761204674887133 9.38268343236509, 0.1685303876974547 9.555570233019601, 0.2928932188134525 9.707106781186548, 0
.444429766980398 9.831469612302545, 0.6173165676349103 9.923879532511286, 0.8049096779838718 9.98078528040323, 1 10), (2 8, 2 2, 8 2, 8 8, 2 8))
+ </op></test>
+<test><op name='buffer' arg1='A' arg2='10.0'>
+POLYGON ((1 19, 9 19, 10.950903220161283 18.807852804032304, 12.826834323650898 18.238795325112868, 14.555702330196024 17.314696123025453, 16.071067811865476 16.071067811865476, 17.314696123025453 14.555702330196022, 18.238795325112868 12.826834323650898, 18.807852804032304 10.950903220161283, 19 9, 19 1, 18.807852804032304 -0.9509032201612824, 18.238795325112868 -2.826834323650898, 17.314696123025453 -4.555702330196022, 16.071067811865476 -6.071067811865475, 14.555702330196024 -7.314696123025453, 12.826834323650898 -8.238795325112868, 10.950903220161283 -8.807852804032304, 9 -9, 1 -9, -0.9509032201612819 -8.807852804032304, -2.826834323650897 -8.238795325112868, -4.55570233019602 -7.314696123025453, -6.071067811865475 -6.0710678118654755, -7.314696123025453 -4.555702330196022, -8.238795325112868 -2.826834323650899, -8.807852804032304 -0.9509032201612861, -9 1, -9 9, -8.807852804032304 10.950903220161287, -8.238795325112868 12.8268343236509, -7.314696123025453 14.555702330196022, -6
.071067811865475 16.071067811865476, -4.55570233019602 17.314696123025453, -2.826834323650897 18.238795325112868, -0.9509032201612819 18.807852804032304, 1 19))
+ </op></test>
+</case>
+
<case>
<desc>
Polygon
-----------------------------------------------------------------------
Summary of changes:
.../geos/operation/buffer/BufferCurveSetBuilder.h | 8 ++-
src/operation/buffer/BufferCurveSetBuilder.cpp | 77 ++++++++++++----------
tests/unit/operation/buffer/BufferOpTest.cpp | 13 ++++
tests/xmltester/tests/general/TestBuffer.xml | 51 ++++++++++++++
4 files changed, 111 insertions(+), 38 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list