[geos-commits] [SCM] GEOS branch 3.11 updated. c42e663523b9eb6aa8f149f23cc7659697f5fbbb

git at osgeo.org git at osgeo.org
Tue May 30 14:43:33 PDT 2023


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, 3.11 has been updated
       via  c42e663523b9eb6aa8f149f23cc7659697f5fbbb (commit)
       via  72936087b4af8bf5ed3a170cbae2ac9b055a7ec2 (commit)
       via  804a6a5583677ab586bcd94ddce42cc8ef5936e1 (commit)
      from  1009ff5c8c2337c5b1eac2d84d175d45346fbb34 (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 c42e663523b9eb6aa8f149f23cc7659697f5fbbb
Author: Mike Taves <mwtoews at gmail.com>
Date:   Wed May 31 09:37:11 2023 +1200

    GEOSClipByRect: Fix case with POINT EMPTY, add more tests (#913)

diff --git a/NEWS.md b/NEWS.md
index 2765f7f90..adc1ea982 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -9,6 +9,8 @@
   - OffsetCurve: fix EndCap parameter handling (GH-899, Martin Davis)
   - GeoJSONReader: Fix 2D empty geometry creation (GH-910, Mike Taves)
   - OffsetCurve: add minimum threshold for quadsegs (GH-897, Martin Davis, Paul Ramsey)
+  - GEOSClipByRect: Fix case with POINT EMPTY (GH-913, Mike Taves)
+
 
 ## Changes in 3.11.2
 2023-03-16
diff --git a/src/operation/intersection/RectangleIntersection.cpp b/src/operation/intersection/RectangleIntersection.cpp
index bad0391c5..d5945ff24 100644
--- a/src/operation/intersection/RectangleIntersection.cpp
+++ b/src/operation/intersection/RectangleIntersection.cpp
@@ -117,7 +117,7 @@ RectangleIntersection::clip_point(const geom::Point* g,
                                   RectangleIntersectionBuilder& parts,
                                   const Rectangle& rect)
 {
-    if(g == nullptr) {
+    if(g == nullptr || g->isEmpty()) {
         return;
     }
 
@@ -538,6 +538,10 @@ RectangleIntersection::clip_polygon(const geom::Polygon* g,
                                     const Rectangle& rect,
                                     bool keep_polygons)
 {
+    if(g == nullptr || g->isEmpty()) {
+        return;
+    }
+
     if(keep_polygons) {
         clip_polygon_to_polygons(g, parts, rect);
     }
diff --git a/tests/unit/capi/GEOSClipByRectTest.cpp b/tests/unit/capi/GEOSClipByRectTest.cpp
index b81dccad8..d5c7f4685 100644
--- a/tests/unit/capi/GEOSClipByRectTest.cpp
+++ b/tests/unit/capi/GEOSClipByRectTest.cpp
@@ -203,6 +203,31 @@ template<> template<> void object::test<15>
     isEqual(geom2_, "POLYGON ((2 2, 2 5, 5 5, 5 2, 2 2))");
 }
 
+/// Empty combinations - always return GEOMETRYCOLLECTION EMPTY
+template<> template<> void object::test<16>
+()
+{
+    std::vector<const char*> variants{
+        "POINT EMPTY",
+        "LINESTRING EMPTY",
+        "POLYGON EMPTY",
+        "MULTIPOINT EMPTY",
+        "MULTILINESTRING EMPTY",
+        "MULTIPOLYGON EMPTY",
+        "GEOMETRYCOLLECTION EMPTY",
+        "LINEARRING EMPTY",
+    };
+    for (const auto& wkt : variants) {
+        GEOSGeom geom1 = GEOSGeomFromWKT(wkt);
+        GEOSGeom geom2 = GEOSClipByRect(geom1, 0, 0, 1, 1);
+        char* obt_wkt = GEOSWKTWriter_write(wktw_, geom2);
+        std::string obt_wkt2(obt_wkt);
+        GEOSFree(obt_wkt);
+        GEOSGeom_destroy(geom1);
+        GEOSGeom_destroy(geom2);
+        ensure_equals(obt_wkt2, "GEOMETRYCOLLECTION EMPTY");
+    }
+}
 
 
 } // namespace tut
diff --git a/tests/unit/operation/intersection/RectangleIntersectionTest.cpp b/tests/unit/operation/intersection/RectangleIntersectionTest.cpp
index 37080edd6..8e126fcb9 100644
--- a/tests/unit/operation/intersection/RectangleIntersectionTest.cpp
+++ b/tests/unit/operation/intersection/RectangleIntersectionTest.cpp
@@ -1679,4 +1679,27 @@ template<> template<> void object::test<208>
 
     doClipTest(inp, exp, r, 1e-10);
 }
+
+/// Empty combinations - always return GEOMETRYCOLLECTION EMPTY
+template<> template<> void object::test<209>
+()
+{
+    std::vector<const char*> variants{
+        "POINT EMPTY",
+        "LINESTRING EMPTY",
+        "POLYGON EMPTY",
+        "MULTIPOINT EMPTY",
+        "MULTILINESTRING EMPTY",
+        "MULTIPOLYGON EMPTY",
+        "GEOMETRYCOLLECTION EMPTY",
+        "LINEARRING EMPTY",
+    };
+    for (const auto& inp : variants) {
+        doClipTest(
+            inp,
+            "GEOMETRYCOLLECTION EMPTY",
+            Rectangle(0, 0, 1, 1)
+        );
+    }
+}
 }

commit 72936087b4af8bf5ed3a170cbae2ac9b055a7ec2
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Mon May 29 07:16:56 2023 -0700

    News entry for GH-897

diff --git a/NEWS.md b/NEWS.md
index 81a8ec789..2765f7f90 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,6 +8,7 @@
   - Build issues with RH (GH-860)
   - OffsetCurve: fix EndCap parameter handling (GH-899, Martin Davis)
   - GeoJSONReader: Fix 2D empty geometry creation (GH-910, Mike Taves)
+  - OffsetCurve: add minimum threshold for quadsegs (GH-897, Martin Davis, Paul Ramsey)
 
 ## Changes in 3.11.2
 2023-03-16

commit 804a6a5583677ab586bcd94ddce42cc8ef5936e1
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Mon May 29 07:13:30 2023 -0700

    * Port https://github.com/locationtech/jts/pull/981
    * References https://github.com/qgis/QGIS/issues/53165
    * References https://github.com/libgeos/geos/issues/897

diff --git a/include/geos/operation/buffer/OffsetCurve.h b/include/geos/operation/buffer/OffsetCurve.h
index b41285cfd..0cfac127f 100644
--- a/include/geos/operation/buffer/OffsetCurve.h
+++ b/include/geos/operation/buffer/OffsetCurve.h
@@ -187,9 +187,15 @@ private:
 public:
 
     /**
-    * Creates a new instance for computing an offset curve for a geometryat a given distance.
-    * with default quadrant segments BufferParameters::DEFAULT_QUADRANT_SEGMENTS
-    * and join style BufferParameters::JOIN_STYLE.
+    * A QuadSegs minimum value that will prevent generating
+    * unwanted offset curve artifacts near end caps.
+    */
+    static constexpr int MIN_QUADRANT_SEGMENTS = 8;
+
+    /**
+    * Creates a new instance for computing an offset curve for a geometry at a given distance.
+    * with default quadrant segments (BufferParameters::DEFAULT_QUADRANT_SEGMENTS)
+    * and join style (BufferParameters::JOIN_STYLE).
     *
     * @param geom the geometry to offset
     * @param dist the offset distance (positive = left, negative = right)
@@ -226,7 +232,17 @@ public:
                 throw util::IllegalArgumentException("OffsetCurve distance must be a finite value");
             }
             //-- set buffer params, leaving cap style as the default CAP_ROUND
-            bufferParams.setQuadrantSegments( bp.getQuadrantSegments());
+
+            /**
+            * Prevent using a very small QuadSegs value, to avoid
+            * offset curve artifacts near the end caps.
+            */
+            int quadSegs = bp.getQuadrantSegments();
+            if (quadSegs < MIN_QUADRANT_SEGMENTS) {
+                quadSegs = MIN_QUADRANT_SEGMENTS;
+            }
+            bufferParams.setQuadrantSegments(quadSegs);
+
             bufferParams.setJoinStyle( bp.getJoinStyle());
             bufferParams.setMitreLimit( bp.getMitreLimit());
         };
diff --git a/tests/unit/capi/GEOSOffsetCurveTest.cpp b/tests/unit/capi/GEOSOffsetCurveTest.cpp
index c2ab6805c..052a5f9df 100644
--- a/tests/unit/capi/GEOSOffsetCurveTest.cpp
+++ b/tests/unit/capi/GEOSOffsetCurveTest.cpp
@@ -104,7 +104,7 @@ void object::test<3>()
 {
      checkOffset(
         "LINESTRING(0 0, 10 0, 10 10)",
-        "LINESTRING (12 10, 12 0, 10 -2, 0 -2)",
+        "LINESTRING (0 -2, 10 -2, 10.3901806 -1.9615705, 10.76536686 -1.8477590, 11.11114046 -1.66293922, 11.41421356 -1.41421356, 11.66293922 -1.11114046, 11.84775906 -0.76536686, 11.96157056 -0.3901806, 12 0, 12 10)",
         -2, 1, GEOSBUF_JOIN_ROUND, 2,
         0.000001
         );
@@ -132,7 +132,7 @@ void object::test<5>()
         "LINESTRING(33282908 6005055,33282900 6005050,33282892 6005042,33282876 6005007,33282863 6004982,33282866 6004971,33282876 6004975,33282967 6005018,33282999 6005031)",
         // Old algorithm
         // "LINESTRING EMPTY",
-        "LINESTRING (33282939.63869393 6005053.735950421, 33282948.754269257 6005058.043310191, 33282949.873293087 6005058.534544423, 33282982.439409934 6005071.764529393)",
+        "LINESTRING (33282951.601378817 6005059.236579252, 33282982.439409934 6005071.764529393)",
         44, 1, GEOSBUF_JOIN_MITRE, 1,
         0.000001
         );
diff --git a/tests/unit/operation/buffer/OffsetCurveTest.cpp b/tests/unit/operation/buffer/OffsetCurveTest.cpp
index e1fdbb533..9b47f1b1f 100644
--- a/tests/unit/operation/buffer/OffsetCurveTest.cpp
+++ b/tests/unit/operation/buffer/OffsetCurveTest.cpp
@@ -292,7 +292,7 @@ void object::test<20> ()
     checkOffsetCurve(
         "LINESTRING (20 20, 50 50, 80 20)",
         10, 2, -1, -1,
-        "LINESTRING (12.93 27.07, 42.93 57.07, 50 60, 57.07 57.07, 87.07 27.07)"
+        "LINESTRING (12.928932188134524 27.071067811865476, 42.928932188134524 57.071067811865476, 44.44429766980398 58.314696123025456, 46.1731656763491 59.23879532511287, 48.04909677983872 59.80785280403231, 50 60, 51.95090322016128 59.80785280403231, 53.8268343236509 59.23879532511287, 55.55570233019602 58.314696123025456, 57.071067811865476 57.071067811865476, 87.07106781186548 27.071067811865476)"
         );
 }
 
@@ -321,5 +321,32 @@ void object::test<22> ()
 }
 
 
+// testMinQuadrantSegments
+// See https://github.com/qgis/QGIS/issues/53165
+template<>
+template<>
+void object::test<41> ()
+{
+    checkOffsetCurve(
+        "LINESTRING (553772.0645892698 177770.05079236583, 553780.9235869241 177768.99614978794, 553781.8325485934 177768.41771963477)",
+        -11, 0, BufferParameters::JOIN_MITRE, -1,
+        "LINESTRING (553770.76 177759.13, 553777.54 177758.32)"
+    );
+}
+
+// testMinQuadrantSegments_QGIS
+// See https://github.com/qgis/QGIS/issues/53165#issuecomment-1563214857
+template<>
+template<>
+void object::test<42> ()
+{
+    checkOffsetCurve(
+        "LINESTRING (421 622, 446 625, 449 627)",
+        133, 0, BufferParameters::JOIN_MITRE, -1,
+        "LINESTRING (405.15 754.05, 416.3 755.39)"
+    );
+}
+
+
 
 } // namespace tut
diff --git a/web/content/specifications/geojson.md b/web/content/specifications/geojson.md
new file mode 100644
index 000000000..fb3cee7de
--- /dev/null
+++ b/web/content/specifications/geojson.md
@@ -0,0 +1,99 @@
+---
+title: "GeoJSON"
+date: 2021-10-04T14:18:42-07:00
+draft: false
+---
+
+"GeoJSON" is a standard for structuring JSON when encoding geometry and features. By using GeoJSON, rather than some other arbitrary scheme for structuring JSON, you maximize the interoperability of your JSON output. There are dozens of tools and [websites](http://geojson.io) that happily consume and emit GeoJSON.
+
+The GeoJSON standard is formally maintained by the IETF as "[RFC 7946](https://datatracker.ietf.org/doc/html/rfc7946)".
+
+Unlike [WKB]({{< ref "wkb" >}}) and [WKT]({{< ref "wkt" >}}), GeoJSON does not restrict itself to just geometry representation. It also standardizes the transport of attribution. The three key levels of GeoJSON are:
+
+* [Geometry](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1), representation of Points, LineStrings, Polygons, etc.
+* [Feature](https://datatracker.ietf.org/doc/html/rfc7946#section-3.2), representation of an object that has a "geometry" and an arbitrary set of other non-geometric "properties".
+* [FeatureCollection](https://datatracker.ietf.org/doc/html/rfc7946#section-3.3), representation of a list of Features.
+
+Since GEOS is almost 100% concerned with geometry operations, there is no GEOS abstraction to translate the non-geometric properties of GeoJSON Feature into, so handling of Feature properties is only available via the C++ [GeoJSON.h](https://github.com/libgeos/geos/blob/main/include/geos/io/GeoJSON.h) utilities.
+
+
+### Writing GeoJSON
+
+The GeoJSON writer, in both the C and C++ APIs, only supports writing out the Geometry portion of GeoJSON. So for writing features, the writer will end up embedded in some larger JSON emitter.
+
+```c
+/* Read a linestring */
+const char* linestring = "LINESTRING(0 0 1, 1 1 1, 2 1 2)";
+GEOSWKTReader* reader = GEOSWKTReader_create();
+GEOSGeom* geom = GEOSWKTReader_read(reader, linestring);
+
+/* Write it out as GeoJSON */
+GEOSGeoJSONWriter* writer = GEOSGeoJSONWriter_create();
+
+/* Generate the JSON, with an indentation of 2 */
+int indentation = 2;
+unsigned char* json = GEOSGeoJSONWriter_writeGeometry(writer, geom, indentation);
+
+/* do something ... */
+
+/* Free the WKB */
+GEOSFree(json);
+GEOSGeom_destroy(geom);
+GEOSGeoJSONWriter_destroy(writer);
+GEOSWKTReader_destroy(reader);
+```
+
+### Reading GeoJSON
+
+The C++ GeoJSON reader does include the option to read full `Feature` and `FeatureCollection` objects, with a narrow API for reading the resulting objects.
+
+```c++
+#include <geos/io/GeoJSON.h> // GeoJSONFeatureCollection, etc
+#include <geos/io/GeoJSONReader.h>
+#include <geos/io/WKTWriter.h>
+#include <geos/geom/Geometry.h>
+
+using namespace geos::io;
+using namespace geos::geom;
+
+void main(void)
+{
+    // Read file into string
+    std::ifstream ifs("geojson.json");
+    std::string content((std::istreambuf_iterator<char>(ifs) ),
+                        (std::istreambuf_iterator<char>()    ));
+
+    // Parse GeoJSON string into GeoJSON objects
+
+    GeoJSONReader reader;
+    GeoJSONFeatureCollection fc = reader.readFeatures(content);
+
+    // Prepare WKT writer
+    WKTWriter writer;
+    writer.setTrim(true);
+    writer.setRoundingPrecision(2);
+
+    // Print out the features
+    for (auto& feature: fc) {
+
+        // Read the geometry
+        const Geometry* geom = feature.getGeometry();
+
+        // Read the properties
+        std::map<std::string, GeoJSONValue>& props = feature.getProperties();
+
+        // Write all properties
+        std::cout << "----------" << std::endl;
+        for (const auto& prop : props) {
+            std::cout << prop.first << ": " << prop.second << std::endl;
+        }
+
+        // Write WKT feometry
+        std::cout << "geometry: " << writer.write(geom) << std::endl;
+    }
+}
+```
+
+
+
+

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

Summary of changes:
 NEWS.md                                            |  3 +
 include/geos/operation/buffer/OffsetCurve.h        | 24 +++++-
 .../intersection/RectangleIntersection.cpp         |  6 +-
 tests/unit/capi/GEOSClipByRectTest.cpp             | 25 ++++++
 tests/unit/capi/GEOSOffsetCurveTest.cpp            |  4 +-
 tests/unit/operation/buffer/OffsetCurveTest.cpp    | 29 ++++++-
 .../intersection/RectangleIntersectionTest.cpp     | 23 +++++
 web/content/specifications/geojson.md              | 99 ++++++++++++++++++++++
 8 files changed, 205 insertions(+), 8 deletions(-)
 create mode 100644 web/content/specifications/geojson.md


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list