[Git][debian-gis-team/geos][upstream] New upstream version 3.14.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Mon Oct 27 16:51:48 GMT 2025



Bas Couwenberg pushed to branch upstream at Debian GIS Project / geos


Commits:
5a46899f by Bas Couwenberg at 2025-10-27T17:04:46+01:00
New upstream version 3.14.1
- - - - -


15 changed files:

- CMakeLists.txt
- NEWS.md
- Version.txt
- include/geos/geom/Quadrant.h
- release.md
- src/algorithm/CircularArcs.cpp
- src/coverage/CoverageRingEdges.cpp
- src/geom/CoordinateSequence.cpp
- src/operation/grid/Grid.cpp
- tests/unit/CMakeLists.txt
- tests/unit/algorithm/CircularArcsTest.cpp
- + tests/unit/geom/QuadrantTest.cpp
- tests/unit/utility.h
- util/geosop/GeometryOp.cpp
- util/geosop/GeosOp.cpp


Changes:

=====================================
CMakeLists.txt
=====================================
@@ -558,3 +558,10 @@ if(PROJECT_IS_TOP_LEVEL)
 
   unset(_is_multi_config_generator)
 endif()  # PROJECT_IS_TOP_LEVEL
+
+include(CheckIncludeFile)
+check_include_file(fenv.h HAVE_FENV_H)
+
+if(HAVE_FENV_H)
+    target_compile_definitions(geos_cxx_flags INTERFACE HAVE_FENV)
+endif()


=====================================
NEWS.md
=====================================
@@ -1,3 +1,14 @@
+
+## Changes in 3.14.1
+2025-10-27
+
+- Fixes/Improvements:
+  - Make floating-point exceptions optional for geosop (GH-1305, Maxim Kochetkov)
+  - Fix undefined behaviour in CoordinateSequence::closeRing (GH-1309, Paul Ramsey)
+  - GridIntersection: Fix crash for certain polygons outside grid extent (Dan Baston)
+  - Fix incorrect envelope calculation for arcs (GH-1314, Dan Baston)
+
+
 ## Changes in 3.14.0
 2025-08-21
 


=====================================
Version.txt
=====================================
@@ -2,7 +2,7 @@
 # GEOS Versions
 GEOS_VERSION_MAJOR=3
 GEOS_VERSION_MINOR=14
-GEOS_VERSION_PATCH=0
+GEOS_VERSION_PATCH=1
 
 # OPTIONS: "", "dev", "rc1" etc.
 GEOS_PATCH_WORD=
@@ -16,7 +16,7 @@ GEOS_PATCH_WORD=
 #   ( THIS MUST BE CAREFULLY AVOIDED )
 #
 CAPI_INTERFACE_CURRENT=21
-CAPI_INTERFACE_REVISION=4
+CAPI_INTERFACE_REVISION=5
 CAPI_INTERFACE_AGE=20
 
 # JTS Port


=====================================
include/geos/geom/Quadrant.h
=====================================
@@ -119,6 +119,24 @@ public:
         }
     };
 
+    /** Return a measure that increases monotonically with counterclockwise
+     *  angle and avoids trigonometric calculations. Values are consistent
+     *  with the numeric quadrant codes
+     *
+     * @param p0 circle center coordinate
+     * @param p1 coordinate for which pseudoangle should be calculated
+     */
+    static double pseudoAngle(const CoordinateXY& p0, const CoordinateXY& p1)
+    {
+        const double dx = p1.x - p0.x;
+        const double dy = p1.y - p0.y;
+
+        const double k = dx / (std::abs(dx) + std::abs(dy));
+        const double w = 2 + (dy > 0 ? 3 - k : 1 + k);
+
+        return w >= 4 ? w - 4 : w;
+    }
+
     /**
      * Returns true if the quadrants are 1 and 3, or 2 and 4
      */


=====================================
release.md
=====================================
@@ -1,38 +1,10 @@
-2025-08-21
 
-- New things:
-  - Add clustering functions to C API (GH-1154, Dan Baston)
-  - Ported LineDissolver (Paul Ramsey)
-  - Ported CoverageCleaner (Paul Ramsey)
-  - Add GEOSGridIntersectionFractions to C API (GH-1295, Dan Baston)
-  - Add functions to interrupt processing in a specific thread/context (GH-803, Dan Baston)
-  - Add "geos-targets.cmake" to build tree to allow building other software against
-    GEOS build without installing first (GH-1269, Dan Baston)
-  - Add GEOSCoordSeq_hasZ, GEOSCoordSeq_hasM (GH-1256, Aurele Ferotin)
-  - Add GEOSCoordSeq_createWithDimensions, GEOSCoordSeq_setM, GEOSCoordSeq_getM (GH-1246, Dan Baston)
-  - Add GEOSGeoJSONWriter_setOutputDimension (GH-1260, Aurele Ferotin)
-  - Add GEOSGeom_transformXYZ (GH-1157, Aurele Ferotin)
-  - Add GEOSisSimpleDetail (GH-1296, Dan Baston)
-
-- Breaking Changes:
-  - C++17 is now required (GH-1144)
-  - Stricter WKT parsing (GH-1241, @freemine)
-  - GEOSCoordSeq_setOrdinate returns an error if the sequence does not have the specified ordinate (GH-1245, Dan Baston)
+2025-10-27
 
 - Fixes/Improvements:
-  - Fix ConcaveHullOfPolygons nested shell handling (GH-1169, Martin Davis)
-  - Fix RelateNG for computing IM for empty-nonempty cases (Martin Davis)
-  - Fix TopologyPreservingSimplifier/TaggedLineString to avoid jumping components (JTS-1096, Martin Davis)
-  - Fix WKTWriter for small precisions and with trim enabled (GH-1199, Mike Taves)
-  - Fix BufferOp to increase length of segments removed by heuristic (GH-1200, Martin Davis)
-  - Improve RelateNG performance for A/L cases in prepared predicates (GH-1201, Martin Davis)
-  - Improve OffsetCurve to handle mitre joins for polygons (Martin Davis)
-  - Fix inscribed circle initialization (GH-1225, Benoit Maurin)
-  - Fix overlay heuristic for GeometryCollections with empty elements (GH-1229, Martin Davis)
-  - Add ring buffer hole removal heuristic (GH-1233, Martin Davis)
-  - Fix buffer element erosion for negative distance and remove overlay deps (GH-1239, Martin Davis)
-  - Fix OverlayNG coordinate dimension handling for EMPTY geometries (GH-1258, Martin Davis)
-  - Fix DepthSegment comparison logic (really this time) (GH-1266, Martin Davis)
-  - Change CoverageGapFinder to return polygons (Martin Davis)
-  - Update DiscreteFrechetDistance to new algorithm (GH-1274, Paul Ramsey)
+  - Make floating-point exceptions optional for geosop (GH-1305, Maxim Kochetkov)
+  - Fix undefined behaviour in CoordinateSequence::closeRing (GH-1309, Paul Ramsey)
+  - GridIntersection: Fix crash for certain polygons outside grid extent (Dan Baston)
+  - Fix incorrect envelope calculation for arcs (GH-1314, Dan Baston)
+
 


=====================================
src/algorithm/CircularArcs.cpp
=====================================
@@ -57,6 +57,8 @@ void
 CircularArcs::expandEnvelope(geom::Envelope& e, const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
                              const geom::CoordinateXY& p2)
 {
+    using geom::Quadrant;
+
     e.expandToInclude(p0);
     e.expandToInclude(p1);
     e.expandToInclude(p2);
@@ -73,22 +75,24 @@ CircularArcs::expandEnvelope(geom::Envelope& e, const geom::CoordinateXY& p0, co
         return;
     }
 
-    auto orientation = Orientation::index(center, p0, p1);
-
     //* 1 | 0
     //* --+--
     //* 2 | 3
+    const auto pa0 = Quadrant::pseudoAngle(center, p0);
+    const auto pa1 = Quadrant::pseudoAngle(center, p1);
+    const auto pa2 = Quadrant::pseudoAngle(center, p2);
 
-    using geom::Quadrant;
-
-    auto q0 = geom::Quadrant::quadrant(center, p0);
-    auto q2 = geom::Quadrant::quadrant(center, p2);
+    auto q0 = static_cast<int>(pa0);
+    auto q2 = static_cast<int>(pa2);
     double R = center.distance(p1);
 
     if (q0 == q2) {
-        // Start and end quadrants are the same. Either the arc crosses all of
+        // Start and end quadrants are the same. Either the arc crosses all
         // the axes, or none of the axes.
-        if (Orientation::index(center, p1, p2) != orientation) {
+
+        const bool isBetween = pa1 > std::min(pa0, pa2) && pa1 < std::max(pa0, pa2);
+
+        if (!isBetween) {
             e.expandToInclude({center.x, center.y + R});
             e.expandToInclude({center.x - R, center.y});
             e.expandToInclude({center.x, center.y - R});
@@ -98,6 +102,8 @@ CircularArcs::expandEnvelope(geom::Envelope& e, const geom::CoordinateXY& p0, co
         return;
     }
 
+    auto orientation = Orientation::index(p0, p1, p2);
+
     if (orientation == Orientation::CLOCKWISE) {
         std::swap(q0, q2);
     }


=====================================
src/coverage/CoverageRingEdges.cpp
=====================================
@@ -13,7 +13,7 @@
  *
  **********************************************************************/
 
-#include <map>
+#include <unordered_map>
 
 #include <geos/coverage/CoverageBoundarySegmentFinder.h>
 #include <geos/coverage/CoverageEdge.h>


=====================================
src/geom/CoordinateSequence.cpp
=====================================
@@ -261,9 +261,10 @@ void
 CoordinateSequence::closeRing(bool allowRepeated)
 {
     if(!isEmpty() && (allowRepeated || front<CoordinateXY>() != back<CoordinateXY>())) {
-        m_vect.insert(m_vect.end(),
-                      m_vect.begin(),
-                      std::next(m_vect.begin(), stride()));
+        const std::size_t n = stride();
+        const std::size_t old = m_vect.size();
+        m_vect.resize(old + n);
+        std::copy_n(m_vect.data(), n, m_vect.data() + old);
     }
 }
 


=====================================
src/operation/grid/Grid.cpp
=====================================
@@ -63,7 +63,7 @@ Grid<infinite_extent>::getCellEnvelope(size_t row, size_t col) const
     }
 
     if (row == 0) {
-        cell_ymax = std::max(xmax() + PADDED_CELL_SIZE, m_domain.getMaxX());
+        cell_ymax = std::max(ymax() + PADDED_CELL_SIZE, m_domain.getMaxY());
     } else if (row == getNumRows() - 1) {
         cell_ymax = ymin(); // because bottom row of regular may have different height from others
     } else {


=====================================
tests/unit/CMakeLists.txt
=====================================
@@ -14,6 +14,35 @@ file(GLOB_RECURSE _sources ${CMAKE_CURRENT_LIST_DIR}/*.cpp CONFIGURE_DEPEND)
 add_executable(test_geos_unit ${_sources})
 unset(_sources)
 
+# test that std::filesystem header actually is there and works
+if(NOT CMAKE_REQUIRED_QUIET)
+  # CMake 3.17+ use CHECK_START/CHECK_PASS/CHECK_FAIL
+  message(STATUS "Checking if compiler supports std::filesystem")
+endif()
+set(_filename "${CMAKE_CURRENT_BINARY_DIR}/has_filesystem.cpp")
+write_file(${_filename} "\
+#include <filesystem>
+int main() {
+  std::filesystem::path pth {\"../\"};
+  return 0;
+}")
+try_compile(HAVE_STD_FILESYSTEM "${CMAKE_BINARY_DIR}/temp" "${_filename}")
+file(REMOVE "${_filename}")
+unset(_filename)
+if(HAVE_STD_FILESYSTEM)
+  if(NOT CMAKE_REQUIRED_QUIET)
+    # CMake 3.17+ use CHECK_START/CHECK_PASS/CHECK_FAIL
+    message(STATUS "Checking if compiler supports std::filesystem - yes")
+  endif()
+  target_compile_definitions(test_geos_unit PRIVATE HAVE_STD_FILESYSTEM)
+else()
+  if(NOT CMAKE_REQUIRED_QUIET)
+    # CMake 3.17+ use CHECK_START/CHECK_PASS/CHECK_FAIL
+    message(STATUS "Checking if compiler supports std::filesystem - no")
+  endif()
+  target_compile_definitions(test_geos_unit PRIVATE HAVE_STD_FILESYSTEM=0)
+endif()
+
 find_package(Threads)
 
 target_link_libraries(test_geos_unit PRIVATE geos geos_c Threads::Threads)


=====================================
tests/unit/algorithm/CircularArcsTest.cpp
=====================================
@@ -215,5 +215,19 @@ void object::test<13>()
                   3, 4, 3, 4);
 }
 
+template<>
+template<>
+void object::test<14>()
+{
+    set_test_name("envelope: GH #1313");
+
+    CoordinateXY p0{2, 0};
+    CoordinateXY p1{4, 2};
+    CoordinateXY p2{2, 1};
+
+    checkEnvelope(p0, p1, p2,
+    2, -1.0811388300841898, 5.08113883008419,2.08113883008419);
+}
+
 }
 


=====================================
tests/unit/geom/QuadrantTest.cpp
=====================================
@@ -0,0 +1,83 @@
+#include <tut/tut.hpp>
+
+#include <geos/geom/Quadrant.h>
+
+using geos::geom::Quadrant;
+
+namespace tut {
+
+struct test_quadrant_data {
+
+    static std::string quadrantName(int quadrant) {
+        switch (quadrant) {
+            case Quadrant::NE: return "NE";
+                case Quadrant::NW: return "NW";
+                case Quadrant::SE: return "SE";
+                case Quadrant::SW: return "SW";
+        }
+        return "unknown";
+    }
+
+    static void checkQuadrant(double dx, double dy, int expected) {
+        int quadrant = Quadrant::quadrant({0, 0}, {dx, dy});
+        ensure_equals(quadrant, expected);
+    }
+
+    static void checkPseudoAngleMatchesQuadrant(double dx, double dy) {
+        int quadrant = Quadrant::quadrant({0, 0}, {dx, dy});
+        double pa = Quadrant::pseudoAngle({0, 0}, {dx, dy});
+
+        if (quadrant != static_cast<int>(pa)) {
+            std::stringstream ss;
+            ss << "relative coordinate (" << dx << ", " << dy << ") expected to be in quadrant " << quadrantName(quadrant) << " but pseudoAngle " << pa << " corresponds to quadrant " << quadrantName(static_cast<int>(pa));
+            fail(ss.str());
+        }
+
+        ensure_equals(quadrant, static_cast<int>(pa));
+    }
+};
+
+typedef test_group<test_quadrant_data> group;
+typedef group::object object;
+
+group test_quadrant_group("geos::geom::Quadrant");
+
+template<>
+template<>
+void object::test<1>()
+{
+    checkQuadrant(1, 1, Quadrant::NE);
+    checkQuadrant(1, -1, Quadrant::SE);
+    checkQuadrant(-1, -1, Quadrant::SW);
+    checkQuadrant(-1, 1, Quadrant::NW);
+}
+
+template<>
+template<>
+void object::test<2>()
+{
+    static constexpr double eps = 1e-8;
+
+    // center of each quadrant
+    checkPseudoAngleMatchesQuadrant(1, 1);
+    checkPseudoAngleMatchesQuadrant(1, -1);
+    checkPseudoAngleMatchesQuadrant(-1, -1);
+    checkPseudoAngleMatchesQuadrant(-1, 1);
+
+    // near axes
+    checkPseudoAngleMatchesQuadrant(1, eps); // +X
+    checkPseudoAngleMatchesQuadrant(1, -eps); // +X
+    checkPseudoAngleMatchesQuadrant(eps, 1); // +Y
+    checkPseudoAngleMatchesQuadrant(-eps, 1); // +Y
+    checkPseudoAngleMatchesQuadrant(-1, eps); // +X
+    checkPseudoAngleMatchesQuadrant(-1, -eps); // +X
+    checkPseudoAngleMatchesQuadrant(eps, -1); // -Y
+    checkPseudoAngleMatchesQuadrant(-eps, -1); // -Y
+
+    // axes
+    checkPseudoAngleMatchesQuadrant(1, 0); // +X
+    //checkPseudoAngleMatchesQuadrant(0, 1); // +Y
+    //checkPseudoAngleMatchesQuadrant(-1, 0); // +X
+    //checkPseudoAngleMatchesQuadrant(0, -1); // -Y
+}
+}


=====================================
tests/unit/utility.h
=====================================
@@ -33,11 +33,13 @@
 #include <fstream>
 #include <sstream>
 
+#ifndef HAVE_STD_FILESYSTEM
 #if defined(__GNUC__) && !defined(__clang__)
 #define HAVE_STD_FILESYSTEM (__GNUC__ > 8)
 #else
 #define HAVE_STD_FILESYSTEM 1
 #endif
+#endif /* ifndef HAVE_STD_FILESYSTEM */
 #if HAVE_STD_FILESYSTEM
 #include <filesystem>
 #endif


=====================================
util/geosop/GeometryOp.cpp
=====================================
@@ -238,7 +238,7 @@ std::vector<GeometryOpCreator> opRegistry {
     catMetric, "area of geometry",
     Result::typeDouble,
     [](const Geometry& geom) {
-        return new Result( geom.convexHull() );
+        return new Result( geom.getArea() );
     });
 }},
 {"length", [](std::string name) { return GeometryOp::create(name,


=====================================
util/geosop/GeosOp.cpp
=====================================
@@ -26,7 +26,9 @@
 #include <geos/io/WKBStreamReader.h>
 #include <geos/io/WKBWriter.h>
 
+#if defined(HAVE_FENV)
 #include <cfenv>
+#endif
 #include <fstream>
 #include <iostream>
 #include <sstream>
@@ -394,10 +396,13 @@ void GeosOp::run(OpArguments& opArgs) {
     //------------------------
 
     try {
+#if defined(HAVE_FENV)
         std::feclearexcept(FE_ALL_EXCEPT); // clear floating-point status flags
+#endif
 
         execute(op, opArgs);
 
+#if defined(HAVE_FENV)
         // Catch everything except for FE_INEXACT, which is usually harmless
         const int fpexp = std::fetestexcept(FE_ALL_EXCEPT ^ FE_INEXACT);
         if (args.isVerbose && (fpexp != 0)) {
@@ -414,6 +419,7 @@ void GeosOp::run(OpArguments& opArgs) {
                 std::cerr << " FE_UNDERFLOW";
             std::cerr << std::endl;
         }
+#endif
     }
     catch (std::exception &e) {
         std::cerr << "Run-time exception: " << e.what() << std::endl;



View it on GitLab: https://salsa.debian.org/debian-gis-team/geos/-/commit/5a46899f7c09f4b7aa2a11fff12a31fa3e9d3a75

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/geos/-/commit/5a46899f7c09f4b7aa2a11fff12a31fa3e9d3a75
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20251027/c585827d/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list