[geos-commits] [SCM] GEOS branch master updated. 658b865930b15b733bf108ebd1009eea64d5e9fa

git at osgeo.org git at osgeo.org
Tue Apr 21 09:22:47 PDT 2020


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, master has been updated
       via  658b865930b15b733bf108ebd1009eea64d5e9fa (commit)
       via  061656eab5cf856565a18de0ed7977d3eac7fafe (commit)
      from  0c16f648c5f1ee8ed1628ad207fbf4fb790801fd (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 658b865930b15b733bf108ebd1009eea64d5e9fa
Merge: 061656e 0c16f64
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Tue Apr 21 09:22:40 2020 -0700

    Merge branch 'master' of https://git.osgeo.org/gitea/geos/geos


commit 061656eab5cf856565a18de0ed7977d3eac7fafe
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Tue Apr 21 09:22:30 2020 -0700

    Buffering a specific closed linestring erroneously produces polygon without hole. References #1022

diff --git a/NEWS b/NEWS
index 7c07c32..db44ee1 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Changes in 3.9.0
   - Replace ttmath with JTS DD double-double implementation (Paul Ramsey)
   - Fix bug in DistanceOp for geometries with empty components (#1026, Paul Ramsey)
   - Remove undefined behaviour in CAPI (#1021, Greg Troxel)
+  - Fix buffering issue (#1022, JTS-525, Paul Ramsey)
 
 
 Changes in 3.8.0
diff --git a/include/geos/geom/CoordinateSequence.h b/include/geos/geom/CoordinateSequence.h
index d255713..976b2cc 100644
--- a/include/geos/geom/CoordinateSequence.h
+++ b/include/geos/geom/CoordinateSequence.h
@@ -197,6 +197,17 @@ public:
      */
     static int increasingDirection(const CoordinateSequence& pts);
 
+
+    /** \brief
+    * Tests whether an array of {@link Coordinate}s forms a ring,
+    * by checking length and closure.
+    * Self-intersection is not checked.
+    *
+    * @param pts an array of Coordinates
+    * @return true if the coordinate form a ring.
+    */
+    static bool isRing(const CoordinateSequence *pts);
+
     /// Reverse Coordinate order in given CoordinateSequence
     static void reverse(CoordinateSequence* cl);
 
diff --git a/include/geos/operation/buffer/OffsetCurveBuilder.h b/include/geos/operation/buffer/OffsetCurveBuilder.h
index 8c90a6c..eda4b5b 100644
--- a/include/geos/operation/buffer/OffsetCurveBuilder.h
+++ b/include/geos/operation/buffer/OffsetCurveBuilder.h
@@ -88,6 +88,20 @@ public:
         return bufParams;
     }
 
+    /**
+     * Tests whether the offset curve for line or point geometries
+     * at the given offset distance is empty (does not exist).
+     * This is the case if:
+     * <ul>
+     * <li>the distance is zero,
+     * <li>the distance is negative, except for the case of singled-sided buffers
+     * </ul>
+     *
+     * @param distance the offset curve distance
+     * @return true if the offset curve is empty
+     */
+    bool isLineOffsetEmpty(double distance);
+
     /** \brief
      * This method handles single points as well as lines.
      *
@@ -140,7 +154,6 @@ public:
                       double distance,
                       std::vector<geom::CoordinateSequence*>& lineList);
 
-
 private:
 
     double distance;
diff --git a/include/geos/operation/buffer/OffsetCurveSetBuilder.h b/include/geos/operation/buffer/OffsetCurveSetBuilder.h
index 392e76f..4162e0c 100644
--- a/include/geos/operation/buffer/OffsetCurveSetBuilder.h
+++ b/include/geos/operation/buffer/OffsetCurveSetBuilder.h
@@ -115,6 +115,8 @@ private:
 
     void addPolygon(const geom::Polygon* p);
 
+    void addRingBothSides(const geom::CoordinateSequence* coord, double distance);
+
     /**
      * Add an offset curve for a polygon ring.
      * The side and left and right topological location arguments
@@ -133,9 +135,9 @@ private:
      * @param cwRightLoc the location on the R side of the ring
      *                   (if it is CW)
      */
-    void addPolygonRing(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 cwLeftLoc,
+                     geom::Location cwRightLoc);
 
     /**
      * The ringCoord is assumed to contain no repeated points.
diff --git a/src/geom/CoordinateSequence.cpp b/src/geom/CoordinateSequence.cpp
index 2f6ed6e..addafec 100644
--- a/src/geom/CoordinateSequence.cpp
+++ b/src/geom/CoordinateSequence.cpp
@@ -158,6 +158,19 @@ CoordinateSequence::increasingDirection(const CoordinateSequence& pts)
     return 1;
 }
 
+/* public static */
+bool
+CoordinateSequence::isRing(const CoordinateSequence *pts)
+{
+    if (pts->size() < 4) return false;
+
+    if (pts->getAt(0) != pts->getAt(pts->size()-1)) {
+        return false;
+    }
+
+    return true;
+}
+
 void
 CoordinateSequence::reverse(CoordinateSequence* cl)
 {
diff --git a/src/operation/buffer/OffsetCurveBuilder.cpp b/src/operation/buffer/OffsetCurveBuilder.cpp
index 83baadc..1629c26 100644
--- a/src/operation/buffer/OffsetCurveBuilder.cpp
+++ b/src/operation/buffer/OffsetCurveBuilder.cpp
@@ -60,11 +60,7 @@ OffsetCurveBuilder::getLineCurve(const CoordinateSequence* inputPts,
 {
     distance = nDistance;
 
-    // a zero or (non-singlesided) negative width buffer of a line/point is empty
-    if(distance == 0.0) {
-        return;
-    }
-    if(distance < 0.0 && ! bufParams.isSingleSided()) {
+    if (isLineOffsetEmpty(distance)) {
         return;
     }
 
@@ -169,6 +165,19 @@ OffsetCurveBuilder::getSingleSidedLineCurve(const CoordinateSequence* inputPts,
 }
 
 /*public*/
+bool
+OffsetCurveBuilder::isLineOffsetEmpty(double distance)
+{
+    // a zero width buffer of a line or point is empty
+    if (distance == 0.0) return true;
+    // a negative width buffer of a line or point is empty,
+    // except for single-sided buffers, where the sign indicates the side
+    if (distance < 0.0 && ! bufParams.isSingleSided()) return true;
+    return false;
+}
+
+
+/*public*/
 void
 OffsetCurveBuilder::getRingCurve(const CoordinateSequence* inputPts,
                                  int side, double nDistance,
diff --git a/src/operation/buffer/OffsetCurveSetBuilder.cpp b/src/operation/buffer/OffsetCurveSetBuilder.cpp
index e2c3804..0f548a9 100644
--- a/src/operation/buffer/OffsetCurveSetBuilder.cpp
+++ b/src/operation/buffer/OffsetCurveSetBuilder.cpp
@@ -184,6 +184,7 @@ OffsetCurveSetBuilder::addCollection(const GeometryCollection* gc)
 void
 OffsetCurveSetBuilder::addPoint(const Point* p)
 {
+    // a zero or negative width buffer of a point is empty
     if(distance <= 0.0) {
         return;
     }
@@ -198,22 +199,32 @@ OffsetCurveSetBuilder::addPoint(const Point* p)
 void
 OffsetCurveSetBuilder::addLineString(const LineString* line)
 {
-    if(distance <= 0.0 && ! curveBuilder.getBufferParameters().isSingleSided()) {
+    if (curveBuilder.isLineOffsetEmpty(distance)) {
         return;
     }
 
-#if GEOS_DEBUG
-    std::cerr << __FUNCTION__ << ": " << line->toString() << std::endl;
-#endif
     auto coord = operation::valid::RepeatedPointRemover::removeRepeatedPoints(line->getCoordinatesRO());
-#if GEOS_DEBUG
-    std::cerr << " After coordinate removal: " << coord->toString() << std::endl;
-#endif
-    std::vector<CoordinateSequence*> lineList;
-    curveBuilder.getLineCurve(coord.get(), distance, lineList);
-    addCurves(lineList, Location::EXTERIOR, Location::INTERIOR);
+
+    /**
+     * Rings (closed lines) are generated with a continuous curve,
+     * with no end arcs. This produces better quality linework,
+     * and avoids noding issues with arcs around almost-parallel end segments.
+     * See JTS #523 and #518.
+     *
+     * Singled-sided buffers currently treat rings as if they are lines.
+     */
+    if (CoordinateSequence::isRing(coord.get()) && ! curveBuilder.getBufferParameters().isSingleSided()) {
+        addRingBothSides(coord.get(), distance);
+    }
+    else {
+        std::vector<CoordinateSequence*> lineList;
+        curveBuilder.getLineCurve(coord.get(), distance, lineList);
+        addCurves(lineList, Location::EXTERIOR, Location::INTERIOR);
+    }
+
 }
 
+
 /*private*/
 void
 OffsetCurveSetBuilder::addPolygon(const Polygon* p)
@@ -246,7 +257,7 @@ OffsetCurveSetBuilder::addPolygon(const Polygon* p)
         return;
     }
 
-    addPolygonRing(
+    addRingSide(
         shellCoord.get(),
         offsetDistance,
         offsetSide,
@@ -268,7 +279,7 @@ OffsetCurveSetBuilder::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)
-        addPolygonRing(
+        addRingSide(
             holeCoord.get(),
             offsetDistance,
             Position::opposite(offsetSide),
@@ -279,7 +290,22 @@ OffsetCurveSetBuilder::addPolygon(const Polygon* p)
 
 /* private */
 void
-OffsetCurveSetBuilder::addPolygonRing(const CoordinateSequence* coord,
+OffsetCurveSetBuilder::addRingBothSides(const CoordinateSequence* coord, double distance)
+{
+    addRingSide(coord, distance,
+                Position::LEFT,
+                Location::EXTERIOR, Location::INTERIOR);
+    /* Add the opposite side of the ring
+    */
+    addRingSide(coord, distance,
+                Position::RIGHT,
+                Location::INTERIOR, Location::EXTERIOR);
+}
+
+
+/* private */
+void
+OffsetCurveSetBuilder::addRingSide(const CoordinateSequence* coord,
                                       double offsetDistance, int side, geom::Location cwLeftLoc, geom::Location cwRightLoc)
 {
 
diff --git a/tests/xmltester/tests/general/TestBuffer.xml b/tests/xmltester/tests/general/TestBuffer.xml
index bdba99d..865a7ac 100644
--- a/tests/xmltester/tests/general/TestBuffer.xml
+++ b/tests/xmltester/tests/general/TestBuffer.xml
@@ -14,8 +14,8 @@
   </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='10.0'>   
-	POLYGON ((110 100, 109.80785280403231 98.04909677983872, 109.23879532511287 96.1731656763491, 108.31469612302546 94.44429766980397, 107.07106781186548 92.92893218813452, 105.55570233019603 91.68530387697454, 103.8268343236509 90.76120467488713, 101.95090322016128 90.19214719596769, 100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488713, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100.00000000000001, 90.19214719596769 101.9509032201613, 90.76120467488714 103.82683432365091, 91.68530387697456 105.55570233019603, 92.92893218813454 107.07106781186549, 94.44429766980399 108.31469612302547, 96.17316567634911 109.23879532511287, 98.04909677983873 109.80785280403231, 100.00000000000003 110, 101.95090322016131 109.8078528040323, 103.82683432365093 109.23879532511286, 105.55570233019606 108.31469612302544, 107.0710678118655 10
 7.07106781186545, 108.31469612302547 105.555702330196, 109.23879532511287 103.82683432365086, 109.80785280403231 101.95090322016124, 110 100))  
+<test><op name='buffer' arg1='A' arg2='10.0'>
+	POLYGON ((110 100, 109.80785280403231 98.04909677983872, 109.23879532511287 96.1731656763491, 108.31469612302546 94.44429766980397, 107.07106781186548 92.92893218813452, 105.55570233019603 91.68530387697454, 103.8268343236509 90.76120467488713, 101.95090322016128 90.19214719596769, 100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488713, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100.00000000000001, 90.19214719596769 101.9509032201613, 90.76120467488714 103.82683432365091, 91.68530387697456 105.55570233019603, 92.92893218813454 107.07106781186549, 94.44429766980399 108.31469612302547, 96.17316567634911 109.23879532511287, 98.04909677983873 109.80785280403231, 100.00000000000003 110, 101.95090322016131 109.8078528040323, 103.82683432365093 109.23879532511286, 105.55570233019606 108.31469612302544, 107.0710678118655 10
 7.07106781186545, 108.31469612302547 105.555702330196, 109.23879532511287 103.82683432365086, 109.80785280403231 101.95090322016124, 110 100))
 	</op></test>
 </case>
 
@@ -28,7 +28,7 @@
   </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='10.0'>   
+<test><op name='buffer' arg1='A' arg2='10.0'>
 	POLYGON ((92.92893218813452 107.07106781186548, 94.44429766980397 108.31469612302546, 96.1731656763491 109.23879532511287, 98.04909677983872 109.80785280403231, 100 110, 101.95090322016128 109.80785280403231, 103.8268343236509 109.23879532511287, 105.55570233019603 108.31469612302546, 107.07106781186548 107.07106781186548, 108.31469612302546 105.55570233019603, 109.23879532511287 103.8268343236509, 109.80785280403231 101.95090322016128, 110 100, 109.80785280403231 98.04909677983872, 109.23879532511286 96.1731656763491, 108.31469612302544 94.44429766980397, 107.07106781186548 92.92893218813452, 17.071067811865476 2.9289321881345254, 15.555702330196024 1.6853038769745474, 13.826834323650898 0.7612046748871322, 11.950903220161283 0.1921471959676957, 10 0, 8.049096779838719 0.1921471959676957, 6.173165676349103 0.7612046748871322, 4.44429766980398 1.6853038769745474, 2.9289321881345254 2.9289321881345245, 1.6853038769745474 4.444297669803978, 0.7612046748871322 6.173165676349101, 0.192
 1471959676957 8.049096779838713, 0 9.999999999999998, 0.1921471959676957 11.950903220161283, 0.761204674887134 13.8268343236509, 1.685303876974551 15.555702330196027, 2.9289321881345254 17.071067811865476, 92.92893218813452 107.07106781186548))
   </op></test>
 </case>
@@ -43,13 +43,13 @@
 <test><op name='buffer' arg1='A' arg2='-100.0'>   POLYGON EMPTY  </op></test>
 <test><op name='buffer' arg1='A' arg2='-10.0'>   POLYGON ((110 110, 110 190, 190 190, 190 110, 110 110))  </op></test>
 <test><op name='buffer' arg1='A' arg2='0.0'>    POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))  </op></test>
-<test><op name='buffer' arg1='A' arg2='10.0'>   
+<test><op name='buffer' arg1='A' arg2='10.0'>
 	POLYGON ((100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488714, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100, 90 200, 90.19214719596769 201.95090322016128, 90.76120467488713 203.8268343236509, 91.68530387697454 205.55570233019603, 92.92893218813452 207.07106781186548, 94.44429766980397 208.31469612302544, 96.1731656763491 209.23879532511287, 98.04909677983872 209.8078528040323, 100 210, 200 210, 201.95090322016128 209.8078528040323, 203.8268343236509 209.23879532511287, 205.55570233019603 208.31469612302544, 207.07106781186548 207.07106781186548, 208.31469612302544 205.55570233019603, 209.23879532511287 203.8268343236509, 209.8078528040323 201.95090322016128, 210 200, 210 100, 209.8078528040323 98.04909677983872, 209.23879532511287 96.1731656763491, 208.31469612302544 94.44429766980397, 207.07106781186548 92.928
 93218813452, 205.55570233019603 91.68530387697454, 203.8268343236509 90.76120467488713, 201.95090322016128 90.19214719596769, 200 90, 100 90))
   </op></test>
-<test><op name='buffer' arg1='A' arg2='20.0'>   
+<test><op name='buffer' arg1='A' arg2='20.0'>
 	POLYGON ((100 80, 96.09819355967743 80.3842943919354, 92.3463313526982 81.52240934977428, 88.88859533960796 83.37060775394909, 85.85786437626905 85.85786437626905, 83.37060775394909 88.88859533960796, 81.52240934977426 92.3463313526982, 80.38429439193538 96.09819355967743, 80 100, 80 200, 80.38429439193538 203.90180644032256, 81.52240934977426 207.6536686473018, 83.37060775394909 211.11140466039205, 85.85786437626905 214.14213562373095, 88.88859533960796 216.6293922460509, 92.3463313526982 218.47759065022575, 96.09819355967744 219.61570560806462, 100 220, 200 220, 203.90180644032256 219.61570560806462, 207.6536686473018 218.47759065022575, 211.11140466039205 216.6293922460509, 214.14213562373095 214.14213562373095, 216.6293922460509 211.11140466039205, 218.47759065022575 207.6536686473018, 219.61570560806462 203.90180644032256, 220 200, 220 100, 219.61570560806462 96.09819355967744, 218.47759065022575 92.3463313526982, 216.6293922460509 88.88859533960796, 214.14213562373095 85.8578
 6437626905, 211.11140466039205 83.37060775394909, 207.6536686473018 81.52240934977426, 203.90180644032256 80.38429439193538, 200 80, 100 80))
   </op></test>
-<test><op name='buffer' arg1='A' arg2='100.0'>   
+<test><op name='buffer' arg1='A' arg2='100.0'>
 	POLYGON ((100 0, 80.49096779838713 1.921471959676964, 61.73165676349097 7.61204674887135, 44.442976698039786 16.85303876974548, 29.28932188134523 29.28932188134526, 16.853038769745453 44.44297669803981, 7.612046748871322 61.73165676349103, 1.9214719596769498 80.49096779838716, 0 100, 0 200, 1.9214719596769498 219.50903220161285, 7.612046748871322 238.268343236509, 16.853038769745467 255.55702330196021, 29.28932188134526 270.71067811865476, 44.44297669803981 283.14696123025453, 61.731656763491024 292.3879532511287, 80.49096779838717 298.078528040323, 100 300, 200 300, 219.50903220161283 298.078528040323, 238.268343236509 292.3879532511287, 255.55702330196021 283.14696123025453, 270.71067811865476 270.71067811865476, 283.14696123025453 255.55702330196021, 292.3879532511287 238.26834323650897, 298.078528040323 219.50903220161283, 300 200, 300 100, 298.078528040323 80.49096779838717, 292.3879532511287 61.731656763491024, 283.14696123025453 44.44297669803978, 270.71067811865476 29.28932
 1881345245, 255.55702330196021 16.85303876974548, 238.268343236509 7.612046748871322, 219.50903220161283 1.9214719596769498, 200 0, 100 0))
   </op></test>
 </case>
@@ -62,26 +62,26 @@
 	POLYGON ((80 300, 280 300, 280 80, 80 80, 80 300), (260 280, 180 200, 100 280, 100 100, 260 100, 260 280))
   </a>
 <test><op name='buffer' arg1='A' arg2='-100.0'>   POLYGON EMPTY  </op></test>
-<test><op name='buffer' arg1='A' arg2='-10.0'>   
-		MULTIPOLYGON (((90 100, 90.19214719596769 98.04909677983872, 90.76120467488713 96.1731656763491, 91.68530387697454 94.44429766980397, 92.92893218813452 92.92893218813452, 94.44429766980397 91.68530387697454, 96.1731656763491 90.76120467488713, 98.04909677983872 90.19214719596769, 100 90, 90 90, 90 100)), 
-  	((260 90, 261.9509032201613 90.19214719596769, 263.82683432365087 90.76120467488713, 265.555702330196 91.68530387697454, 267.0710678118655 92.92893218813452, 268.31469612302544 94.44429766980397, 269.23879532511285 96.1731656763491, 269.8078528040323 98.04909677983872, 270 100, 270 90, 260 90)), 
-  	((270 280, 269.8078528040323 281.9509032201613, 269.23879532511285 283.82683432365087, 268.31469612302544 285.555702330196, 267.0710678118655 287.0710678118655, 265.555702330196 288.31469612302544, 263.82683432365087 289.23879532511285, 261.9509032201613 289.8078528040323, 260 290, 270 290, 270 280)), 
-  	((260 290, 258.0490967798387 289.8078528040323, 256.17316567634913 289.23879532511285, 254.44429766980397 288.31469612302544, 252.92893218813452 287.0710678118655, 180 214.14213562373095, 107.07106781186548 287.0710678118655, 105.55570233019603 288.31469612302544, 103.8268343236509 289.23879532511285, 101.95090322016128 289.8078528040323, 100 290, 260 290)), 
+<test><op name='buffer' arg1='A' arg2='-10.0'>
+		MULTIPOLYGON (((90 100, 90.19214719596769 98.04909677983872, 90.76120467488713 96.1731656763491, 91.68530387697454 94.44429766980397, 92.92893218813452 92.92893218813452, 94.44429766980397 91.68530387697454, 96.1731656763491 90.76120467488713, 98.04909677983872 90.19214719596769, 100 90, 90 90, 90 100)),
+  	((260 90, 261.9509032201613 90.19214719596769, 263.82683432365087 90.76120467488713, 265.555702330196 91.68530387697454, 267.0710678118655 92.92893218813452, 268.31469612302544 94.44429766980397, 269.23879532511285 96.1731656763491, 269.8078528040323 98.04909677983872, 270 100, 270 90, 260 90)),
+  	((270 280, 269.8078528040323 281.9509032201613, 269.23879532511285 283.82683432365087, 268.31469612302544 285.555702330196, 267.0710678118655 287.0710678118655, 265.555702330196 288.31469612302544, 263.82683432365087 289.23879532511285, 261.9509032201613 289.8078528040323, 260 290, 270 290, 270 280)),
+  	((260 290, 258.0490967798387 289.8078528040323, 256.17316567634913 289.23879532511285, 254.44429766980397 288.31469612302544, 252.92893218813452 287.0710678118655, 180 214.14213562373095, 107.07106781186548 287.0710678118655, 105.55570233019603 288.31469612302544, 103.8268343236509 289.23879532511285, 101.95090322016128 289.8078528040323, 100 290, 260 290)),
   	((100 290, 98.04909677983872 289.8078528040323, 96.1731656763491 289.23879532511285, 94.44429766980397 288.31469612302544, 92.92893218813452 287.0710678118655, 91.68530387697454 285.555702330196, 90.76120467488713 283.82683432365087, 90.19214719596769 281.9509032201613, 90 280, 90 290, 100 290)))
     </op></test>
-<test><op name='buffer' arg1='A' arg2='0.0'>    
-	POLYGON ((80 300, 280 300, 280 80, 80 80, 80 300), 
+<test><op name='buffer' arg1='A' arg2='0.0'>
+	POLYGON ((80 300, 280 300, 280 80, 80 80, 80 300),
   	(260 280, 180 200, 100 280, 100 100, 260 100, 260 280))
   </op></test>
-<test><op name='buffer' arg1='A' arg2='10.0'>   
-	POLYGON ((70 300, 70.19214719596769 301.9509032201613, 70.76120467488713 303.82683432365087, 71.68530387697454 305.555702330196, 72.92893218813452 307.0710678118655, 74.44429766980397 308.31469612302544, 76.1731656763491 309.23879532511285, 78.04909677983872 309.8078528040323, 80 310, 280 310, 281.9509032201613 309.8078528040323, 283.82683432365087 309.23879532511285, 285.555702330196 308.31469612302544, 287.0710678118655 307.0710678118655, 288.31469612302544 305.555702330196, 289.23879532511285 303.82683432365087, 289.8078528040323 301.9509032201613, 290 300, 290 80, 289.8078528040323 78.04909677983872, 289.23879532511285 76.1731656763491, 288.31469612302544 74.44429766980397, 287.0710678118655 72.92893218813452, 285.555702330196 71.68530387697454, 283.82683432365087 70.76120467488713, 281.9509032201613 70.19214719596769, 280 70, 80 70, 78.04909677983872 70.19214719596769, 76.1731656763491 70.76120467488714, 74.44429766980397 71.68530387697454, 72.92893218813452 72.92893218813452,
  71.68530387697454 74.44429766980397, 70.76120467488713 76.1731656763491, 70.19214719596769 78.04909677983872, 70 80, 70 300), 
+<test><op name='buffer' arg1='A' arg2='10.0'>
+	POLYGON ((70 300, 70.19214719596769 301.9509032201613, 70.76120467488713 303.82683432365087, 71.68530387697454 305.555702330196, 72.92893218813452 307.0710678118655, 74.44429766980397 308.31469612302544, 76.1731656763491 309.23879532511285, 78.04909677983872 309.8078528040323, 80 310, 280 310, 281.9509032201613 309.8078528040323, 283.82683432365087 309.23879532511285, 285.555702330196 308.31469612302544, 287.0710678118655 307.0710678118655, 288.31469612302544 305.555702330196, 289.23879532511285 303.82683432365087, 289.8078528040323 301.9509032201613, 290 300, 290 80, 289.8078528040323 78.04909677983872, 289.23879532511285 76.1731656763491, 288.31469612302544 74.44429766980397, 287.0710678118655 72.92893218813452, 285.555702330196 71.68530387697454, 283.82683432365087 70.76120467488713, 281.9509032201613 70.19214719596769, 280 70, 80 70, 78.04909677983872 70.19214719596769, 76.1731656763491 70.76120467488714, 74.44429766980397 71.68530387697454, 72.92893218813452 72.92893218813452,
  71.68530387697454 74.44429766980397, 70.76120467488713 76.1731656763491, 70.19214719596769 78.04909677983872, 70 80, 70 300),
   	(250 255.85786437626905, 187.07106781186548 192.92893218813452, 185.55570233019603 191.68530387697456, 183.8268343236509 190.76120467488713, 181.95090322016128 190.1921471959677, 180 190, 178.04909677983872 190.1921471959677, 176.1731656763491 190.76120467488713, 174.44429766980397 191.68530387697456, 172.92893218813452 192.92893218813452, 110 255.85786437626905, 110 110, 250 110, 250 255.85786437626905))
  </op></test>
-<test><op name='buffer' arg1='A' arg2='20.0'>   
-	POLYGON ((60 300, 60.38429439193539 303.90180644032256, 61.522409349774264 307.6536686473018, 63.370607753949095 311.11140466039205, 65.85786437626905 314.14213562373095, 68.88859533960796 316.6293922460509, 72.3463313526982 318.47759065022575, 76.09819355967744 319.6157056080646, 80 320, 280 320, 283.90180644032256 319.6157056080646, 287.6536686473018 318.47759065022575, 291.11140466039205 316.6293922460509, 294.14213562373095 314.14213562373095, 296.6293922460509 311.11140466039205, 298.47759065022575 307.6536686473018, 299.6157056080646 303.90180644032256, 300 300, 300 80, 299.6157056080646 76.09819355967744, 298.47759065022575 72.3463313526982, 296.6293922460509 68.88859533960796, 294.14213562373095 65.85786437626905, 291.11140466039205 63.370607753949095, 287.6536686473018 61.522409349774264, 283.90180644032256 60.38429439193539, 280 60, 80 60, 76.09819355967743 60.3842943919354, 72.3463313526982 61.52240934977427, 68.88859533960796 63.370607753949095, 65.85786437626905 65.857
 86437626905, 63.37060775394909 68.88859533960796, 61.522409349774264 72.3463313526982, 60.38429439193539 76.09819355967743, 60 80, 60 300), 
+<test><op name='buffer' arg1='A' arg2='20.0'>
+	POLYGON ((60 300, 60.38429439193539 303.90180644032256, 61.522409349774264 307.6536686473018, 63.370607753949095 311.11140466039205, 65.85786437626905 314.14213562373095, 68.88859533960796 316.6293922460509, 72.3463313526982 318.47759065022575, 76.09819355967744 319.6157056080646, 80 320, 280 320, 283.90180644032256 319.6157056080646, 287.6536686473018 318.47759065022575, 291.11140466039205 316.6293922460509, 294.14213562373095 314.14213562373095, 296.6293922460509 311.11140466039205, 298.47759065022575 307.6536686473018, 299.6157056080646 303.90180644032256, 300 300, 300 80, 299.6157056080646 76.09819355967744, 298.47759065022575 72.3463313526982, 296.6293922460509 68.88859533960796, 294.14213562373095 65.85786437626905, 291.11140466039205 63.370607753949095, 287.6536686473018 61.522409349774264, 283.90180644032256 60.38429439193539, 280 60, 80 60, 76.09819355967743 60.3842943919354, 72.3463313526982 61.52240934977427, 68.88859533960796 63.370607753949095, 65.85786437626905 65.857
 86437626905, 63.37060775394909 68.88859533960796, 61.522409349774264 72.3463313526982, 60.38429439193539 76.09819355967743, 60 80, 60 300),
   	(240 231.7157287525381, 194.14213562373095 185.85786437626905, 191.11140466039205 183.3706077539491, 187.6536686473018 181.52240934977425, 183.90180644032256 180.38429439193538, 180 180, 176.09819355967744 180.38429439193538, 172.3463313526982 181.52240934977425, 168.88859533960795 183.3706077539491, 165.85786437626905 185.85786437626905, 120 231.7157287525381, 120 120, 240 120, 240 231.7157287525381))
   </op></test>
-<test><op name='buffer' arg1='A' arg2='100.0'>   
+<test><op name='buffer' arg1='A' arg2='100.0'>
 	POLYGON ((-20 300, -18.07852804032305 319.50903220161285, -12.387953251128678 338.268343236509, -3.146961230254533 355.5570233019602, 9.28932188134526 370.71067811865476, 24.442976698039807 383.14696123025453, 41.731656763491024 392.3879532511287, 60.49096779838718 398.078528040323, 80 400, 280 400, 299.50903220161285 398.078528040323, 318.268343236509 392.3879532511287, 335.5570233019602 383.14696123025453, 350.71067811865476 370.71067811865476, 363.14696123025453 355.5570233019602, 372.3879532511287 338.268343236509, 378.078528040323 319.50903220161285, 380 300, 380 80, 378.078528040323 60.490967798387175, 372.3879532511287 41.731656763491024, 363.14696123025453 24.44297669803978, 350.71067811865476 9.289321881345245, 335.5570233019602 -3.1469612302545187, 318.268343236509 -12.387953251128678, 299.50903220161285 -18.07852804032305, 280 -20, 80 -20, 60.49096779838713 -18.078528040323036, 41.73165676349097 -12.38795325112865, 24.442976698039786 -3.1469612302545187, 9.28932188134523
  9.28932188134526, -3.146961230254547 24.442976698039807, -12.387953251128678 41.73165676349103, -18.07852804032305 60.49096779838716, -20 80, -20 300))
   </op></test>
 </case>
@@ -91,14 +91,14 @@
   	MultiLineString which caused failure for distance > 10 in ver 1.10
   </desc>
   <a>
-    MULTILINESTRING ((1335558.59524 631743.01449, 1335572.28215 631775.89056, 1335573.2578018496 631782.1915185435), 
-  (1335573.2578018496 631782.1915185435, 1335576.62035 631803.90754), 
+    MULTILINESTRING ((1335558.59524 631743.01449, 1335572.28215 631775.89056, 1335573.2578018496 631782.1915185435),
+  (1335573.2578018496 631782.1915185435, 1335576.62035 631803.90754),
   (1335573.2578018496 631782.1915185435, 1335580.70187 631802.08139))
   </a>
-<test><op name='buffer' arg1='A' arg2='10.0'>   
+<test><op name='buffer' arg1='A' arg2='10.0'>
 POLYGON ((1335548.595256113 631743.032441783, 1335548.790905219 631744.982996921, 1335549.363329412 631746.857903442, 1335562.585102127 631778.616709872, 1335563.375568292 631783.721701512, 1335566.738116443 631805.437722968, 1335567.226524677 631807.336249059, 1335568.075932351 631809.103011783, 1335569.253697204 631810.67011544, 1335570.714558392 631811.977337115, 1335572.402375839 631812.974441013, 1335574.252287668 631813.62310899, 1335576.193202805 631813.898413099, 1335578.150532968 631813.789773558, 1335580.049059059 631813.301365323, 1335581.815821783 631812.451957649, 1335582.575762837 631811.880820023, 1335584.207062652 631811.446945214, 1335585.966840541 631810.583159534, 1335587.524288564 631809.392655618, 1335588.819554868 631807.921183865, 1335589.802863095 631806.225292108, 1335590.436425262 631804.370152517, 1335590.695893928 631802.427057067, 1335590.57129786 631800.470677824, 1335590.067425214 631798.576197348, 1335582.983023804 631779.64732263, 1335582.164383558 6
 31774.360377032, 1335581.514060589 631772.047146558, 1335567.827150589 631739.171076558, 1335566.899949249 631737.44387026, 1335565.653602591 631735.930739755, 1335564.136007016 631734.689833799, 1335562.405482873 631733.768839712, 1335560.528533233 631733.203150781, 1335558.577288218 631733.014506113, 1335556.626733079 631733.210155219, 1335554.751826558 631733.782579411, 1335553.02462026 631734.709780751, 1335551.511489755 631735.956127409, 1335550.270583799 631737.473722984, 1335549.349589712 631739.204247127, 1335548.783900781 631741.081196768, 1335548.595256113 631743.032441783))
   </op></test>
-<test><op name='buffer' arg1='A' arg2='15.0'>   
+<test><op name='buffer' arg1='A' arg2='15.0'>
 POLYGON ((1335543.59526417 631743.041417674, 1335543.888737828 631745.967250381, 1335544.747374117 631748.779610163, 1335557.736578191 631779.97978481, 1335558.434451514 631784.486792996, 1335561.796999664 631806.202814452, 1335562.529612016 631809.050603588, 1335563.803723527 631811.700747674, 1335565.570370805 631814.051403159, 1335567.761662587 631816.012235673, 1335570.293388759 631817.507891519, 1335573.068256502 631818.480893485, 1335575.979629207 631818.893849648, 1335578.915624452 631818.730890336, 1335581.763413588 631817.998277984, 1335584.413557674 631816.724166473, 1335584.790893177 631816.440578026, 1335585.959658978 631816.129722821, 1335588.599325811 631814.834044301, 1335590.935497846 631813.048288427, 1335592.878397303 631810.841080797, 1335594.353359643 631808.297243162, 1335595.303702892 631805.514533776, 1335595.692905893 631802.5998906, 1335595.50601179 631799.665321737, 1335594.750202821 631796.823601022, 1335587.845634781 631778.375224674, 1335587.105500336 63
 1773.595285547, 1335586.130015883 631770.125439837, 1335572.443105883 631737.249369837, 1335571.052303874 631734.65856039, 1335569.182783886 631732.388864632, 1335566.906390525 631730.527505698, 1335564.310604309 631729.146014568, 1335561.495179849 631728.297481171, 1335558.568312326 631728.01451417, 1335555.642479619 631728.307987828, 1335552.830119837 631729.166624117, 1335550.23931039 631730.557426126, 1335547.969614632 631732.426946114, 1335546.108255698 631734.703339476, 1335544.726764568 631737.299125691, 1335543.878231171 631740.114550151, 1335543.59526417 631743.041417674))
   </op></test>
 </case>
@@ -110,7 +110,7 @@ POLYGON ((1335543.59526417 631743.041417674, 1335543.888737828 631745.967250381,
   <a>
     POLYGON ((-69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90, -69 -90))
   </a>
-<test><op name='buffer' arg1='A' arg2='0.0'>   
+<test><op name='buffer' arg1='A' arg2='0.0'>
 POLYGON EMPTY
   </op></test>
 </case>
@@ -123,13 +123,36 @@ POLYGON EMPTY
   <a>
     POLYGON ((100 100, 200 100, 200 100, 100 100))
   </a>
-<test><op name='buffer' arg1='A' arg2='0.0'>   
+<test><op name='buffer' arg1='A' arg2='0.0'>
 POLYGON EMPTY
   </op></test>
-<test><op name='buffer' arg1='A' arg2='10.0'>   
+<test><op name='buffer' arg1='A' arg2='10.0'>
 POLYGON ((100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488714, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100, 90.19214719596769 101.95090322016128, 90.76120467488713 103.8268343236509, 91.68530387697454 105.55570233019603, 92.92893218813452 107.07106781186548, 94.44429766980397 108.31469612302546, 96.1731656763491 109.23879532511287, 98.04909677983872 109.80785280403231, 100 110, 200 110, 201.95090322016128 109.80785280403231, 203.8268343236509 109.23879532511287, 205.55570233019603 108.31469612302546, 207.07106781186548 107.07106781186548, 208.31469612302544 105.55570233019603, 209.23879532511287 103.8268343236509, 209.8078528040323 101.95090322016128, 210 100, 209.8078528040323 98.04909677983872, 209.23879532511287 96.1731656763491, 208.31469612302544 94.44429766980397, 207.07106781186548 92.92893218813452, 205
 .55570233019603 91.68530387697454, 203.8268343236509 90.76120467488713, 201.95090322016128 90.19214719596769, 200 90, 100 90))
   </op></test>
 </case>
 
 
+<case>
+  <desc>
+    LinearRing with end segments almost parallel.
+    In JTS 1.16 this causes the hole to be omitted.
+    Also test that a zero-width buffer is empty,
+    and a large buffer does not contain a hole.
+  </desc>
+  <a>
+    LINESTRING (278601.0234 4295292.7193, 278598.7192 4295290.4934, 278589.0628369178 4295303.481014691, 278605.493 4295297.0369, 278601.0234 4295292.7193)
+  </a>
+<test><op name='buffer' arg1='A' arg2='0.0'>
+POLYGON EMPTY
+  </op></test>
+<test><op name='buffer' arg1='A' arg2='1.0'>
+POLYGON ((278601.71817759715 4295292.000075355, 278599.413981099 4295289.774178738, 278599.26661589916 4295289.656539299, 278599.0997870315 4295289.568654894, 278598.9194261865 4295289.5136503, 278598.7319461913 4295289.493481236, 278598.54401299846 4295289.508864823, 278598.36230867397 4295289.55925409, 278598.19329381327 4295289.642857418, 278598.0429778308 4295289.756702248, 278597.9167052926 4295289.896740763, 278588.2603422104 4295302.884355455, 278588.1583281413 4295303.054559684, 278588.09193032637 4295303.241556155, 278588.0637632691 4295303.437981629, 278588.0749360855 4295303.636101588, 278588.12500883086 4295303.828114791, 278588.2120098231 4295304.006460459, 278588.33251328085 4295304.1641159905, 278588.48177421774 4295304.294873486, 278588.6539152828 4295304.393584194, 278588.84215818933 4295304.456361244, 278589.03909061867 4295304.480732708, 278589.2369580906 4295304.465738925, 278589.4279693065 4295304.411970297, 278605.8581323887 4295297.967855605, 278606.0357824957
  4295297.8767733015, 278606.1917997098 4295297.752217388, 278606.3199658795 4295297.599152109, 278606.41517287196 4295297.423677965, 278606.4736261605 4295297.232788573, 278606.4929960574 4295297.034091936, 278606.4725105647 4295296.835507215, 278606.4129861431 4295296.644949114, 278606.3167951708 4295296.47001243, 278606.18777139165 4295296.31766936, 278601.71817759715 4295292.000075355), (278600.32862860855 4295293.43853064, 278603.6784434623 4295296.674426606, 278591.9493371884 4295301.2747282395, 278598.84278545994 4295292.003178559, 278600.32862860855 4295293.43853064))
+  </op></test>
+<test><op name='buffer' arg1='A' arg2='4.0'>
+POLYGON ((278603.8025082337 4295289.842399337, 278601.4983243959 4295287.61651495, 278600.9088635962 4295287.145957194, 278600.2415481254 4295286.794419575, 278599.5201047454 4295286.574401201, 278598.7701847649 4295286.493724944, 278598.0184519935 4295286.555259293, 278597.2916346957 4295286.756816359, 278596.61557525286 4295287.091229674, 278596.01431132323 4295287.546608992, 278595.50922117033 4295288.106763054, 278585.85285808815 4295301.094377745, 278585.44480181177 4295301.775194663, 278585.17921055184 4295302.523180546, 278585.066542323 4295303.308882442, 278585.11123358866 4295304.101362279, 278585.31152457 4295304.86941509, 278585.6595285392 4295305.582797763, 278586.14154237026 4295306.213419889, 278586.7385861178 4295306.736449872, 278587.4271503783 4295307.131292701, 278588.1801220044 4295307.382400904, 278588.96785172186 4295307.479886759, 278589.7593216097 4295307.419911628, 278590.52336647245 4295307.204837112, 278606.95352955465 4295300.76072242, 278607.66412998334 4
 295300.396393205, 278608.2881988397 4295299.898169551, 278608.80086351826 4295299.2859084355, 278609.1816914881 4295298.584011859, 278609.4155046422 4295297.820454294, 278609.4929842295 4295297.025667744, 278609.41104225884 4295296.231328862, 278609.1729445721 4295295.469096458, 278608.7881806828 4295294.76934972, 278608.2720855661 4295294.15997744, 278603.8025082337 4295289.842399337))
+  </op></test>
+</case>
+
+
+
 </run>
diff --git a/tools/ci/berrie.sh b/tools/ci/berrie.sh
index ecd8fe8..3655b38 100644
--- a/tools/ci/berrie.sh
+++ b/tools/ci/berrie.sh
@@ -10,7 +10,7 @@
 # See the COPYING file for more information.
 #
 # auto tools
-if false; then
+if true; then
     sh autogen.sh
     ./configure
     make
@@ -19,7 +19,7 @@ fi
 
 
 # cmake
-if true; then
+if false; then
     rm -rf build
     mkdir -p build
     cd build

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                               |  1 +
 include/geos/geom/CoordinateSequence.h             | 11 ++++
 include/geos/operation/buffer/OffsetCurveBuilder.h | 15 ++++-
 .../geos/operation/buffer/OffsetCurveSetBuilder.h  |  8 ++-
 src/geom/CoordinateSequence.cpp                    | 13 ++++
 src/operation/buffer/OffsetCurveBuilder.cpp        | 19 ++++--
 src/operation/buffer/OffsetCurveSetBuilder.cpp     | 52 +++++++++++----
 tests/xmltester/tests/general/TestBuffer.xml       | 73 ++++++++++++++--------
 8 files changed, 145 insertions(+), 47 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list