From git at osgeo.org Mon Dec 1 09:25:18 2025 From: git at osgeo.org (git at osgeo.org) Date: Mon, 1 Dec 2025 09:25:18 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. c2a1d40c2d86f0b6f8028d4965ffa2aef79473d7 Message-ID: <20251201172518.6B1E116FF29@trac.osgeo.org> 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 c2a1d40c2d86f0b6f8028d4965ffa2aef79473d7 (commit) from c0b00fc4a4b3a33dd16c4266f247dbf931241564 (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 c2a1d40c2d86f0b6f8028d4965ffa2aef79473d7 Author: Sven Jensen Date: Mon Dec 1 09:24:48 2025 -0800 SIMD vectorization of Length.cpp, up to 2.8x faster Enables the SIMD vectorization of the line-length loop when HAVE_OPEN_SIMD is defined. diff --git a/src/algorithm/Length.cpp b/src/algorithm/Length.cpp index 68897dac4..64087b6bc 100644 --- a/src/algorithm/Length.cpp +++ b/src/algorithm/Length.cpp @@ -35,22 +35,15 @@ Length::ofLine(const geom::CoordinateSequence* pts) } double len = 0.0; - - const geom::CoordinateXY& p = pts->getAt(0); - double x0 = p.x; - double y0 = p.y; - + for(std::size_t i = 1; i < n; i++) { const geom::CoordinateXY& pi = pts->getAt(i); - double x1 = pi.x; - double y1 = pi.y; - double dx = x1 - x0; - double dy = y1 - y0; + const geom::CoordinateXY& pi_1 = pts->getAt(i-1); + + double dx = pi.x - pi_1.x; + double dy = pi.y - pi_1.y; len += std::sqrt(dx * dx + dy * dy); - - x0 = x1; - y0 = y1; } return len; } @@ -63,20 +56,15 @@ Length::ofLine(const std::vector& pts) } double len = 0; - double x0 = pts[0].x; - double y0 = pts[0].y; - + for(std::size_t i = 1; i < pts.size(); i++) { const geom::CoordinateXY& pi = pts[i]; - double x1 = pi.x; - double y1 = pi.y; - double dx = x1 - x0; - double dy = y1 - y0; + const geom::CoordinateXY& pi_1 = pts[i-1]; + + double dx = pi.x - pi_1.x; + double dy = pi.y - pi_1.y; len += std::sqrt(dx * dx + dy * dy); - - x0 = x1; - y0 = y1; } return len; ----------------------------------------------------------------------- Summary of changes: src/algorithm/Length.cpp | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Mon Dec 1 18:44:58 2025 From: git at osgeo.org (git at osgeo.org) Date: Mon, 1 Dec 2025 18:44:58 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. d48d7fc02968b6a12f93afb9cd1ae74b3cd24fdf Message-ID: <20251202024458.CF6D4188BF1@trac.osgeo.org> 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 d48d7fc02968b6a12f93afb9cd1ae74b3cd24fdf (commit) from c2a1d40c2d86f0b6f8028d4965ffa2aef79473d7 (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 d48d7fc02968b6a12f93afb9cd1ae74b3cd24fdf Author: Mike Taves Date: Tue Dec 2 15:39:54 2025 +1300 Cleanup old scripts used for Travis CI (RIP) diff --git a/tools/ci/common.sh b/tools/ci/common.sh deleted file mode 100755 index 08c065162..000000000 --- a/tools/ci/common.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# Common utilities for Travis CI setup for GEOS -# -# Copyright (c) 2013 Mateusz Loskot -# -# This is free software; you can redistribute and/or modify it under -# the terms of the GNU Lesser General Public Licence as published -# by the Free Software Foundation. -# See the COPYING file for more information. -# -if [ "$TRAVIS" != "true" ] ; then - echo "Running this script makes no sense outside of travis-ci.org" - exit 1 -fi -# -# Environment -# -TCI_NUMTHREADS=2 -if [ -f /sys/devices/system/cpu/online ]; then - # Calculates 1.5 times physical threads - TCI_NUMTHREADS=$(( ( $(cut -f 2 -d '-' /sys/devices/system/cpu/online) + 1 ) * 15 / 10 )) -fi -# -# Functions -# -tmstamp() -{ - echo -n "[$(date '+%H:%M:%S')]" ; -} - -run_make() -{ - [ $TCI_NUMTHREADS -gt 0 ] && make -j $TCI_NUMTHREADS || make -} diff --git a/tools/ci/script.sh b/tools/ci/script.sh deleted file mode 100755 index 5b9e75d35..000000000 --- a/tools/ci/script.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# -# Travis CI script runner for GEOS -# -# Copyright (c) 2013 Mateusz Loskot -# -# This is free software; you can redistribute and/or modify it under -# the terms of the GNU Lesser General Public Licence as published -# by the Free Software Foundation. -# See the COPYING file for more information. -# - -if [ -z "${TRAVIS_BUILD_DIR+x}" ]; then - echo TRAVIS_BUILD_DIR not defined - exit 1 -fi - -# source common functions -. ${TRAVIS_BUILD_DIR}/tools/ci/common.sh - -# prepare build directory -builddir=${TRAVIS_BUILD_DIR}/_build -mkdir -p ${builddir} -cd ${builddir} - -# build and run tests -${TRAVIS_BUILD_DIR}/tools/ci/script_cmake.sh diff --git a/tools/ci/script_cmake.sh b/tools/ci/script_cmake.sh deleted file mode 100755 index b5a173ee9..000000000 --- a/tools/ci/script_cmake.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Travis CI script for GEOS build with CMake -# -# Copyright (C) 2013 Mateusz Loskot -# -# This is free software; you can redistribute and/or modify it under -# the terms of the GNU Lesser General Public Licence as published -# by the Free Software Foundation. -# See the COPYING file for more information. -# - -if [ -z "${TRAVIS_BUILD_DIR+x}" ]; then - echo TRAVIS_BUILD_DIR not defined - exit 1 -fi - -# source common functions -. ${TRAVIS_BUILD_DIR}/tools/ci/common.sh - -# return on first failure -set -e - -cmake --version - -cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_DOCUMENTATION=YES ${TRAVIS_BUILD_DIR} -run_make -cmake --build . --target docs -ctest --output-on-failure . - -if [ "${BUILD_TYPE}" = "Coverage" ]; then - curl -o codecov.sh https://codecov.io/bash - bash codecov.sh -fi ----------------------------------------------------------------------- Summary of changes: tools/ci/common.sh | 35 ----------------------------------- tools/ci/script.sh | 27 --------------------------- tools/ci/script_cmake.sh | 34 ---------------------------------- 3 files changed, 96 deletions(-) delete mode 100755 tools/ci/common.sh delete mode 100755 tools/ci/script.sh delete mode 100755 tools/ci/script_cmake.sh hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 10:30:17 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 10:30:17 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. bf3be9ebb55f2912a19acc54adeaae68c7fd01dd Message-ID: <20251205183017.CF5141B6693@trac.osgeo.org> 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 bf3be9ebb55f2912a19acc54adeaae68c7fd01dd (commit) from d48d7fc02968b6a12f93afb9cd1ae74b3cd24fdf (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 bf3be9ebb55f2912a19acc54adeaae68c7fd01dd Author: Lo?c Bartoletti Date: Fri Dec 5 19:29:47 2025 +0100 Fix geosop crash when using negative numeric arguments (#1336) diff --git a/util/geosop/GeosOp.cpp b/util/geosop/GeosOp.cpp index 05307cf30..97db2c3f8 100644 --- a/util/geosop/GeosOp.cpp +++ b/util/geosop/GeosOp.cpp @@ -106,8 +106,11 @@ int main(int argc, char** argv) { cxxopts::ParseResult result; try { result = options.parse(argc, argv); - } catch ( cxxopts::option_not_exists_exception& ex ) { + } catch ( cxxopts::OptionParseException& ex ) { std::cerr << ex.what() << std::endl; + std::cerr << "Hint: To use negative numeric arguments, either:" << std::endl; + std::cerr << " - put '--' before the operation name: geosop -a GEOM -- opName -0.4" << std::endl; + std::cerr << " - use 'N' prefix for negative numbers: geosop -a GEOM opName N-0.4" << std::endl; exit(1); } ----------------------------------------------------------------------- Summary of changes: util/geosop/GeosOp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 10:47:08 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 10:47:08 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. cad26ad980e9c7e15e7286122abcf091c37aa398 Message-ID: <20251205184708.EAD691B6717@trac.osgeo.org> 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 cad26ad980e9c7e15e7286122abcf091c37aa398 (commit) from bf3be9ebb55f2912a19acc54adeaae68c7fd01dd (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 cad26ad980e9c7e15e7286122abcf091c37aa398 Author: Paul Ramsey Date: Fri Dec 5 10:46:04 2025 -0800 Return EMPTY components when repeated point removal renders the underlying parts (rings, lines, etc) invalid (0 dimensional), closes #1326 and #1293 diff --git a/include/geos/io/WKTReader.h b/include/geos/io/WKTReader.h index 7294d64f5..9fc86c978 100644 --- a/include/geos/io/WKTReader.h +++ b/include/geos/io/WKTReader.h @@ -115,6 +115,7 @@ public: } std::unique_ptr read(const std::string& wellKnownText) const; + std::unique_ptr readCoordinates(const std::string& wellKnownText) const; protected: std::unique_ptr getCoordinates(io::StringTokenizer* tokenizer, OrdinateSet& ordinates) const; diff --git a/include/geos/operation/valid/RepeatedPointRemover.h b/include/geos/operation/valid/RepeatedPointRemover.h index e6e91c24c..d70e71802 100644 --- a/include/geos/operation/valid/RepeatedPointRemover.h +++ b/include/geos/operation/valid/RepeatedPointRemover.h @@ -48,6 +48,13 @@ namespace valid { const geom::CoordinateSequence* seq, double tolerance = 0.0); + static std::unique_ptr + removeRepeatedOrInvalidPoints( + const geom::CoordinateSequence* seq, + double tolerance = 0.0) { + return removeRepeatedAndInvalidPoints(seq, tolerance); + }; + static std::unique_ptr removeRepeatedPoints( const geom::Geometry* geom, diff --git a/src/coverage/CoverageRingEdges.cpp b/src/coverage/CoverageRingEdges.cpp index 4d1495a47..a5a697cc1 100644 --- a/src/coverage/CoverageRingEdges.cpp +++ b/src/coverage/CoverageRingEdges.cpp @@ -140,7 +140,8 @@ CoverageRingEdges::extractRingEdges( std::unique_ptr pts = RepeatedPointRemover::removeRepeatedPoints( ring->getCoordinatesRO() ); std::vector ringEdges; - //-- if compacted ring is too short, don't process it + // if compacted ring is too short, don't process it, + // just return empty vector if (pts->getSize() < 3) return ringEdges; diff --git a/src/io/WKTReader.cpp b/src/io/WKTReader.cpp index 2b4400a6b..3c1d6fa69 100644 --- a/src/io/WKTReader.cpp +++ b/src/io/WKTReader.cpp @@ -65,6 +65,23 @@ WKTReader::read(const std::string& wellKnownText) const return ret; } + +std::unique_ptr +WKTReader::readCoordinates(const std::string& wellKnownText) const +{ + CLocalizer clocale; + StringTokenizer tokenizer(wellKnownText); + OrdinateSet ordinateFlags = OrdinateSet::createXY(); + auto ret = getCoordinates(&tokenizer, ordinateFlags); + + if (tokenizer.peekNextToken() != StringTokenizer::TT_EOF) { + tokenizer.nextToken(); + throw ParseException("Unexpected text after end of geometry"); + } + + return ret; +} + std::unique_ptr WKTReader::getCoordinates(StringTokenizer* tokenizer, OrdinateSet& ordinateFlags) const { diff --git a/src/operation/valid/RepeatedPointRemover.cpp b/src/operation/valid/RepeatedPointRemover.cpp index 22b4a9aa2..aea5e320b 100644 --- a/src/operation/valid/RepeatedPointRemover.cpp +++ b/src/operation/valid/RepeatedPointRemover.cpp @@ -200,19 +200,21 @@ public: auto filtCoords = filter.getCoords(); if (filtCoords->size() == 0) return nullptr; + if (filtCoords->size() == 1) return nullptr; // End points for comparison and sequence repair const Coordinate& origEndCoord = coordinates->back(); + bool origEndCoordIsValid = origEndCoord.isValid(); // Fluff up overly small filtered outputs - if(filtCoords->size() < minLength) { + if(filtCoords->size() < minLength && origEndCoordIsValid) { filtCoords->add(origEndCoord); } const Coordinate& filtEndCoord = filtCoords->back(); // We stripped the last point, let's put it back on - if (!origEndCoord.equals2D(filtEndCoord)) { + if (origEndCoordIsValid && !origEndCoord.equals2D(filtEndCoord)) { // If the end of the filtered coordinates is within // tolerance of the original end, we drop the last filtered // coordinate so the output still follows the tolerance rule @@ -223,8 +225,14 @@ public: filtCoords->add(origEndCoord); } - return filtCoords; + if (filtCoords->size() <= 1) return nullptr; + else return filtCoords; }; + + + + + }; // RepeatedPointCoordinateOperation diff --git a/tests/unit/capi/GEOSRemoveRepeatedPointsTest.cpp b/tests/unit/capi/GEOSRemoveRepeatedPointsTest.cpp index 0b78590b2..c1a53bb32 100644 --- a/tests/unit/capi/GEOSRemoveRepeatedPointsTest.cpp +++ b/tests/unit/capi/GEOSRemoveRepeatedPointsTest.cpp @@ -32,9 +32,9 @@ void object::test<1> () { geom1_ = GEOSGeomFromWKT("POLYGON((0 0, 0 1, 0 10, 10 10, 10 0, 9 0, 1 0, 0 0))"); - geom2_ = GEOSRemoveRepeatedPoints(geom1_, 3.0); + result_ = GEOSRemoveRepeatedPoints(geom1_, 3.0); expected_ = GEOSGeomFromWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"); - ensure_geometry_equals(geom2_, expected_); + ensure_geometry_equals(result_, expected_); } // https://github.com/libgeos/geos/issues/759 @@ -44,9 +44,9 @@ void object::test<2> () { geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"); + expected_ = GEOSGeomFromWKT("POLYGON EMPTY"); result_ = GEOSRemoveRepeatedPoints(geom1_, 2.0); - - ensure(result_ == nullptr); + ensure_geometry_equals(result_, expected_); } template<> @@ -57,7 +57,6 @@ void object::test<3>() ensure(input_); result_ = GEOSRemoveRepeatedPoints(input_, 0); - ensure("curved geometry not supported", result_ == nullptr); } diff --git a/tests/unit/operation/valid/RepeatedPointRemoverTest.cpp b/tests/unit/operation/valid/RepeatedPointRemoverTest.cpp index 205eefcc9..5d12c1b35 100644 --- a/tests/unit/operation/valid/RepeatedPointRemoverTest.cpp +++ b/tests/unit/operation/valid/RepeatedPointRemoverTest.cpp @@ -44,6 +44,19 @@ struct test_repeated_point_remover_test_data return writer.write(&geom); } + void + checkSimpleSequence(const std::string& input, const std::string& expected, double tolerance = 0.0) + { + std::unique_ptr inCoords = reader.readCoordinates(input); + std::unique_ptr exCoords = reader.readCoordinates(expected); + auto outCoords = RepeatedPointRemover::removeRepeatedPoints(inCoords.get(), tolerance); + // std::cout << "output" << std::endl; + // std::cout << outCoords->toString() << std::endl; + // std::cout << "expected" << std::endl; + // std::cout << exCoords->toString() << std::endl; + ensure_equals(*outCoords, *exCoords); + } + void checkSequence(const std::string& input, const std::string& expected, double tolerance = 0.0) { @@ -58,6 +71,10 @@ struct test_repeated_point_remover_test_data ensure_equals("hasZ", exCoords->hasZ(), outCoords->hasZ()); ensure_equals("hasM", exCoords->hasM(), outCoords->hasM()); + // std::cout << "output" << std::endl; + // std::cout << outCoords->toString() << std::endl; + // std::cout << "expected" << std::endl; + // std::cout << exCoords->toString() << std::endl; ensure_equals(*outCoords, *exCoords); } @@ -75,7 +92,6 @@ struct test_repeated_point_remover_test_data ensure_equals_geometry(outGeom.get(), exGeom.get()); } - }; typedef test_group group; @@ -87,9 +103,9 @@ template<> template<> void object::test<1>() { - checkSequence( - "LINESTRING (3 7, 8 8, 8 8, 8 8, 10 9)", - "LINESTRING (3 7, 8 8, 10 9)", + checkSimpleSequence( + "(3 7, 8 8, 8 8, 8 8, 10 9)", + "(3 7, 8 8, 10 9)", 0.0 ); } @@ -98,24 +114,28 @@ template<> template<> void object::test<2>() { - checkSequence( - "LINESTRING (3 7, 8 8, 8 8, 8 8)", - "LINESTRING (3 7, 8 8)", + checkSimpleSequence( + "(3 7, 8 8, 8 8, 8 8)", + "(3 7, 8 8)", 0.0 ); } +// CoordinateSequences just retain each coordinate within +// the filter tolerance template<> template<> void object::test<3>() { - checkSequence( - "LINESTRING (0 0, 1 0, 4 0, 5 0)", - "LINESTRING (0 0, 4 0)", + checkSimpleSequence( + "(0 0, 1 0, 4 0, 5 0)", + "(0 0, 4 0)", 3.0 ); } +// Linestrings note the last point and somehow +// retain it in preference over the internal point template<> template<> void object::test<4>() @@ -123,7 +143,7 @@ void object::test<4>() checkGeometry( "LINESTRING (0 0, 1 0, 4 0, 5 0)", "LINESTRING (0 0, 5 0)", - 3.0 + 3 ); } @@ -140,7 +160,7 @@ void object::test<5>() } -// Dimension is preserved +// Dimension is preserved during reduction template<> template<> void object::test<6>() @@ -151,6 +171,141 @@ void object::test<6>() } +// Removing from a sequence with enough tolerance +// results in single-entry sequence +template<> +template<> +void object::test<7>() +{ + checkSimpleSequence( + "(3 7, 3 7, 3 7, 3 7)", + "(3 7)", + 0.0 + ); +} + +// Removing from a sequence with enough tolerance +// results in single-entry sequence +template<> +template<> +void object::test<8>() +{ + checkSimpleSequence( + "(3 7, 3.1 7.1, 3.2 7.2, 3.3 7.3)", + "(3 7)", + 1.0 + ); +} + + +template<> +template<> +void object::test<9>() +{ + checkGeometry( + "LINESTRING (0 0, 0 1, 0 2, 0 3)", + "LINESTRING EMPTY", + 14.0 + ); +} + + +// small hole should collapse away +template<> +template<> +void object::test<10>() +{ + checkGeometry( + "POLYGON ((0 0, 9 0, 10 0, 10 10, 0 10, 0 1, 0 0), (5 5, 5 6, 6 6, 6 5, 5 5))", + "POLYGON ((0 0, 9 0, 10 10, 0 10, 0 0))", + 3.0 + ); +} + +// small exterior ring should disappear whole polygon +template<> +template<> +void object::test<11>() +{ + checkGeometry( + "POLYGON ((0 0, 9 0, 10 0, 10 10, 0 10, 0 1, 0 0))", + "POLYGON ((0 0, 10 10, 0 0))", + 12.0 + ); +} + +template<> +template<> +void object::test<12>() +{ + checkGeometry( + "POLYGON ((0 0, 9 0, 10 0, 10 10, 0 10, 0 1, 0 0))", + "POLYGON EMPTY", + 22.0 + ); +} + +// Careful not to replace invalid coordinates +template<> +template<> +void object::test<13>() +{ + checkGeometry( + "LINESTRING (0 0, 0 Inf, 1 1, Inf 0)", + "LINESTRING (0 0, 1 1)", + 1.0 + ); +} + +// If it filters down to just one point, it should be empty +template<> +template<> +void object::test<14>() +{ + checkGeometry( + "LINESTRING (0 0, 0 Inf, 1 1)", + "LINESTRING EMPTY", + 2.0 + ); +} + +// Filter out invalid coordinate, even at start/ends +template<> +template<> +void object::test<15>() +{ + checkGeometry( + "POLYGON ((Inf Inf, 0 0, 10 0, 10 10, 0 10, 0 0, Inf Inf))", + "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", + 2.0 + ); +} + +// If it filters down to just one point, it should be empty +template<> +template<> +void object::test<16>() +{ + checkGeometry( + "POLYGON ((Inf Inf, 0 0, 10 0, 10 10, 0 10, 0 0, Inf Inf))", + "POLYGON EMPTY", + 22.0 + ); +} + +// https://github.com/libgeos/geos/issues/1293 +// Hole collapses, should not error out. +template<> +template<> +void object::test<17>() +{ + checkGeometry( + "POLYGON ((139770.26822331376024522 188334.00010800323798321, 139769.5 188338.01162790699163452, 139769.5 188338.3723930635896977, 139769.5 188338.5, 139769.81343283582828008 188338.5, 139770.375 188339.375, 139772.39924806414637715 188340.26989983080420643, 139770.26822331376024522 188334.00010800323798321),(139769.75256541155977175 188338.40516005983226933, 139769.75256541153066792 188338.40516005983226933, 139769.75256541153066792 188338.4051600598031655, 139769.75256541155977175 188338.40516005983226933))", + "POLYGON ((139769.5 188338.011627907, 139769.5 188338.3723930636, 139769.5 188338.5, 139769.81343283583 188338.5, 139770.375 188339.375, 139772.39924806415 188340.2698998308, 139770.26822331376 188334.00010800324, 139769.5 188338.011627907))", + 1e-8 + ); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: include/geos/io/WKTReader.h | 1 + .../geos/operation/valid/RepeatedPointRemover.h | 7 + src/coverage/CoverageRingEdges.cpp | 3 +- src/io/WKTReader.cpp | 17 ++ src/operation/valid/RepeatedPointRemover.cpp | 14 +- tests/unit/capi/GEOSRemoveRepeatedPointsTest.cpp | 9 +- .../operation/valid/RepeatedPointRemoverTest.cpp | 179 +++++++++++++++++++-- 7 files changed, 209 insertions(+), 21 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 12:53:30 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 12:53:30 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 36686663d0d3758f1068807733bd3a8d337d78af Message-ID: <20251205205330.AABFC1B6AD3@trac.osgeo.org> 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 36686663d0d3758f1068807733bd3a8d337d78af (commit) from cad26ad980e9c7e15e7286122abcf091c37aa398 (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 36686663d0d3758f1068807733bd3a8d337d78af Author: Paul Ramsey Date: Fri Dec 5 12:53:07 2025 -0800 Quiet MSVC compiler warning diff --git a/src/util/string.cpp b/src/util/string.cpp index b61b147c1..f3712f58b 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -56,7 +56,14 @@ bool startsWith(const std::string & s, char prefix) { void toUpper(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); + std::transform( + s.begin(), + s.end(), + s.begin(), + [](unsigned char c) { + return (char)std::tolower(c); + } + ); } ----------------------------------------------------------------------- Summary of changes: src/util/string.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 13:01:58 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 13:01:58 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. de9084960cfdbc621f4e544ff1c429253c86f39c Message-ID: <20251205210158.92A7A1B6750@trac.osgeo.org> 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 de9084960cfdbc621f4e544ff1c429253c86f39c (commit) from 36686663d0d3758f1068807733bd3a8d337d78af (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 de9084960cfdbc621f4e544ff1c429253c86f39c Author: Paul Ramsey Date: Fri Dec 5 13:01:35 2025 -0800 Fix lower -> upper diff --git a/src/util/string.cpp b/src/util/string.cpp index f3712f58b..6657a09ee 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -61,7 +61,7 @@ void toUpper(std::string& s) s.end(), s.begin(), [](unsigned char c) { - return (char)std::tolower(c); + return (char)std::toupper(c); } ); } ----------------------------------------------------------------------- Summary of changes: src/util/string.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 13:17:05 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 13:17:05 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. a7626dbb6dd7f19b5edb6846bddb1550a0d7c142 Message-ID: <20251205211705.44A081B6E2D@trac.osgeo.org> 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 a7626dbb6dd7f19b5edb6846bddb1550a0d7c142 (commit) from de9084960cfdbc621f4e544ff1c429253c86f39c (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 a7626dbb6dd7f19b5edb6846bddb1550a0d7c142 Author: Paul Ramsey Date: Fri Dec 5 13:16:41 2025 -0800 Quiet MSVC warning about type conversion diff --git a/src/operation/GeometryGraphOperation.cpp b/src/operation/GeometryGraphOperation.cpp index 41249ca0a..d44c7cce9 100644 --- a/src/operation/GeometryGraphOperation.cpp +++ b/src/operation/GeometryGraphOperation.cpp @@ -80,8 +80,8 @@ GeometryGraphOperation::GeometryGraphOperation(const Geometry* g0, setComputationPrecision(pm1); } - arg[0] = std::make_unique(0, g0, boundaryNodeRule); - arg[1] = std::make_unique(1, g1, boundaryNodeRule); + arg[0] = std::make_unique(static_cast(0), g0, boundaryNodeRule); + arg[1] = std::make_unique(static_cast(1), g1, boundaryNodeRule); } @@ -93,7 +93,7 @@ GeometryGraphOperation::GeometryGraphOperation(const Geometry* g0): setComputationPrecision(pm0); - arg[0] = std::make_unique(0, g0); + arg[0] = std::make_unique(static_cast(0), g0); } const Geometry* ----------------------------------------------------------------------- Summary of changes: src/operation/GeometryGraphOperation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 13:19:40 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 13:19:40 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 7403b6fdee35ba00570b440f697b0976c6582252 Message-ID: <20251205211940.9DC051B63E2@trac.osgeo.org> 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 7403b6fdee35ba00570b440f697b0976c6582252 (commit) from a7626dbb6dd7f19b5edb6846bddb1550a0d7c142 (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 7403b6fdee35ba00570b440f697b0976c6582252 Author: Paul Ramsey Date: Fri Dec 5 13:19:04 2025 -0800 Add CMAKE detection for openmd simd support in compiler, closes #1334 diff --git a/CMakeLists.txt b/CMakeLists.txt index a1e2f0c6e..79d397efb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,24 @@ target_compile_options(geos_cxx_flags INTERFACE # works with multi-configuration generators. target_compile_definitions(geos_cxx_flags INTERFACE $<$>:NDEBUG>) +# OpenMP SIMD +include(CheckCXXCompilerFlag) + +if(MSVC) + set(SIMD_FLAGS "/openmp:experimental") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") + set(SIMD_FLAGS "-qopenmp-simd") +else() + set(SIMD_FLAGS "-fopenmp-simd") +endif() + +check_cxx_compiler_flag(${SIMD_FLAGS} COMPILER_HAS_SIMD) +if(COMPILER_HAS_SIMD) + target_compile_options(geos_cxx_flags INTERFACE ${SIMD_FLAGS}) + target_compile_definitions(geos_cxx_flags INTERFACE HAVE_OPEN_SIMD) +endif() + + #----------------------------------------------------------------------------- # Target geos_developer_cxx_flags: developer mode compilation flags #----------------------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 13:40:48 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 13:40:48 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 953e1c3d307d9e9a3e2c95fd7b981c39d3365317 Message-ID: <20251205214048.395DA1B6A51@trac.osgeo.org> 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 953e1c3d307d9e9a3e2c95fd7b981c39d3365317 (commit) from 7403b6fdee35ba00570b440f697b0976c6582252 (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 953e1c3d307d9e9a3e2c95fd7b981c39d3365317 Author: Paul Ramsey Date: Fri Dec 5 13:40:24 2025 -0800 Quiet MSVC compiler warning diff --git a/src/operation/overlayng/CoverageUnion.cpp b/src/operation/overlayng/CoverageUnion.cpp index 05cd4d0b3..5d67428e8 100644 --- a/src/operation/overlayng/CoverageUnion.cpp +++ b/src/operation/overlayng/CoverageUnion.cpp @@ -48,7 +48,7 @@ CoverageUnion::geomunion(const Geometry* coverage) try { result = OverlayNG::geomunion(coverage, nullptr, &bcn); } - catch (const geos::util::TopologyException& te) { + catch (const geos::util::TopologyException&) { throw geos::util::TopologyException("CoverageUnion cannot process incorrectly noded inputs"); } } ----------------------------------------------------------------------- Summary of changes: src/operation/overlayng/CoverageUnion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Fri Dec 5 15:12:33 2025 From: git at osgeo.org (git at osgeo.org) Date: Fri, 5 Dec 2025 15:12:33 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 347b3fad55b05750e471aafa8ca3c7338ba25ee5 Message-ID: <20251205231233.E0EF71B6E97@trac.osgeo.org> 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 347b3fad55b05750e471aafa8ca3c7338ba25ee5 (commit) via 14376eeb7a53f970fc31a574c941fd1d3a4aed5b (commit) from 953e1c3d307d9e9a3e2c95fd7b981c39d3365317 (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 347b3fad55b05750e471aafa8ca3c7338ba25ee5 Author: Paul Ramsey Date: Fri Dec 5 15:05:31 2025 -0800 news diff --git a/NEWS.md b/NEWS.md index 716795d7a..43926615a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,9 @@ - New things: - +- Breaking Changes: + - BufferOp returns POLYGON EMPTY when fed Inf/Nan coords (GH-1332) + ## Changes in 3.14.0 2025-08-21 commit 14376eeb7a53f970fc31a574c941fd1d3a4aed5b Author: Paul Ramsey Date: Fri Dec 5 14:54:19 2025 -0800 Return EMPTY when confronted with request to buffer input with NaN/Inf coordinates, references #1332 diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index 7fc39e77c..69e5976e3 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -201,6 +201,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->size() == 0) { + return; + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, @@ -272,21 +276,22 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p) return; } - auto shellCoord = + auto shellCoords = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(shell->getCoordinatesRO()); - if (shellCoord->isEmpty()) { - throw util::GEOSException("Shell empty after removing invalid points"); + if (shellCoords->isEmpty()) { + return; + //throw util::GEOSException("Shell empty after removing invalid points"); } // don't attempt to buffer a polygon // with too few distinct vertices - if(distance <= 0.0 && shellCoord->size() < 3) { + if(distance <= 0.0 && shellCoords->size() < 3) { return; } addPolygonRingSide( - shellCoord.get(), + shellCoords.get(), offsetDistance, offsetSide, Location::EXTERIOR, @@ -302,13 +307,17 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p) continue; } - auto holeCoord = valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(hole->getCoordinatesRO()); + auto holeCoords = valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(hole->getCoordinatesRO()); + + //-- skip if no valid coordinates + if (holeCoords->isEmpty()) + continue; // 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) addPolygonRingSide( - holeCoord.get(), + holeCoords.get(), offsetDistance, Position::opposite(offsetSide), Location::INTERIOR, diff --git a/tests/unit/capi/GEOSBufferTest.cpp b/tests/unit/capi/GEOSBufferTest.cpp index 538dfbf75..702cc8dff 100644 --- a/tests/unit/capi/GEOSBufferTest.cpp +++ b/tests/unit/capi/GEOSBufferTest.cpp @@ -436,10 +436,15 @@ void object::test<24>() std::string wkb("0106000020E61000000100000001030000000100000005000000000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F"); geom1_ = GEOSGeomFromHEX_buf(reinterpret_cast(wkb.c_str()), wkb.size()); ensure(geom1_ != nullptr); + + expected_ = fromWKT("POLYGON EMPTY"); + ensure(expected_ != nullptr); + geom2_ = GEOSBuffer(geom1_, 20, 8); - ensure(geom2_ == nullptr); + ensure_geometry_equals(expected_, geom2_, 0.001); + geom3_ = GEOSBuffer(geom1_, -20, 8); - ensure(geom3_ == nullptr); + ensure_geometry_equals(expected_, geom3_, 0.001); } diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index 7ac585ccc..3e5bc5d92 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -63,13 +63,19 @@ struct test_bufferop_data { ensure_equals("Area", actualArea, expectedArea, tolerance); } - void checkBufferEmpty(const std::string& wkt, double dist, bool isEmpty) + void checkBufferPolygonEmpty(const std::string& wkt, double dist, bool isEmpty) { std::unique_ptr geom = wktreader.read(wkt); std::unique_ptr actual = geom->buffer(dist); ensure_equals(actual->isEmpty(), isEmpty); } + void checkBufferPolygonEmpty(const Geometry& geom, double dist, bool isEmpty) + { + std::unique_ptr actual = geom.buffer(dist); + ensure_equals(actual->isEmpty(), isEmpty); + } + void checkBuffer(const std::string& wkt, double dist, double tolerance, const std::string& wktExpected) { std::unique_ptr geom = wktreader.read(wkt); @@ -421,10 +427,10 @@ void object::test<16> () { std::string wkt0("POLYGON ((666360.09 429614.71, 666344.4 429597.12, 666358.47 429584.52, 666374.5 429602.33, 666360.09 429614.71))"); - checkBufferEmpty(wkt0, -9, false); - checkBufferEmpty(wkt0, -10, true); - checkBufferEmpty(wkt0, -15, true); - checkBufferEmpty(wkt0, -18, true); + checkBufferPolygonEmpty(wkt0, -9, false); + checkBufferPolygonEmpty(wkt0, -10, true); + checkBufferPolygonEmpty(wkt0, -15, true); + checkBufferPolygonEmpty(wkt0, -18, true); } // Test for https://trac.osgeo.org/geos/ticket/1101 - Non-empty negative buffer of 5-pt convex polygon @@ -434,10 +440,10 @@ void object::test<17> () { std::string wkt0("POLYGON ((6 20, 16 20, 21 9, 9 0, 0 10, 6 20))"); - checkBufferEmpty(wkt0, -8, false); - checkBufferEmpty(wkt0, -8.6, true); - checkBufferEmpty(wkt0, -9.6, true); - checkBufferEmpty(wkt0, -11, true); + checkBufferPolygonEmpty(wkt0, -8, false); + checkBufferPolygonEmpty(wkt0, -8.6, true); + checkBufferPolygonEmpty(wkt0, -9.6, true); + checkBufferPolygonEmpty(wkt0, -11, true); } // Test for https://trac.osgeo.org/geos/ticket/1101 - Buffer of Polygon with hole with hole eroded @@ -662,4 +668,39 @@ void object::test<30> ensure(bufGeom->getArea() > 12000); } + +// testInvalidCoordPoint +template<> +template<> +void object::test<31> () +{ + // works for Inf ordinates as well + auto geom = wktreader.read("POINT (NaN NaN)"); + checkBufferPolygonEmpty(*geom, 1, true); +} + +// testInvalidCoordsLine +template<> +template<> +void object::test<32> () +{ + // works for Inf ordinates as well + auto geom = wktreader.read("LINESTRING (NaN NaN, NaN NaN)"); + checkBufferPolygonEmpty(*geom, 1, true); +} + +// testInvalidCoordShell +template<> +template<> +void object::test<33> () +{ + // using Inf ordinates creates a valid ring with equal endpoints + // this would be simpler if JTS WKT supported Inf + auto geom = wktreader.read("POLYGON ((Inf Inf, Inf Inf, Inf Inf, Inf Inf, Inf Inf))"); + checkBufferPolygonEmpty(*geom, 1, true); +} + + + + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS.md | 3 ++ src/operation/buffer/BufferCurveSetBuilder.cpp | 23 +++++++--- tests/unit/capi/GEOSBufferTest.cpp | 9 +++- tests/unit/operation/buffer/BufferOpTest.cpp | 59 ++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 18 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Sun Dec 7 13:05:53 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 7 Dec 2025 13:05:53 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. cdc6dbd6def66a73ad89d2dcf4f01893afe1f94c Message-ID: <20251207210553.AF59C131F76@trac.osgeo.org> 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 cdc6dbd6def66a73ad89d2dcf4f01893afe1f94c (commit) from 347b3fad55b05750e471aafa8ca3c7338ba25ee5 (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 cdc6dbd6def66a73ad89d2dcf4f01893afe1f94c Author: Mike Taves Date: Mon Dec 8 10:05:18 2025 +1300 Codecov threshold configuration and README.md badge (#1337) diff --git a/.codecov.yml b/.codecov.yml index c22939992..8241bcfb1 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,8 +1,13 @@ coverage: precision: 2 + status: + project: + default: + target: auto + threshold: 1% ignore: - "tests/unit/tut" - "tests/xmltester/tinyxml2" -comment: off +comment: false diff --git a/README.md b/README.md index 4f198e8bc..f50da2760 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ The official Git repository is at [GitHub](https://github.com/libgeos/geos). | :---: | :----- | :---: | :----- | :---: | :----- | | GitHub | [![github](https://github.com/libgeos/geos/workflows/CI/badge.svg?branch/main)](https://github.com/libgeos/geos/actions?query=workflow:CI+branch:main) | Bessie | [![bessie](https://debbie.postgis.net/buildStatus/icon?job=GEOS_Worker_Run/label=bessie&build=last:${params.reference=refs/heads/main})](https://debbie.postgis.net/view/GEOS/job/GEOS_Worker_Run/label=bessie) | Debbie | [![debbie](https://debbie.postgis.net/buildStatus/icon?job=GEOS_Master)](https://debbie.postgis.net/view/GEOS/job/GEOS_Master/) | | Winnie | [![winnie](https://winnie.postgis.net/view/GEOS/job/GEOS_Master/badge/icon)](https://winnie.postgis.net/view/GEOS/job/GEOS_Master/) | Berrie | [![berrie](https://debbie.postgis.net/buildStatus/icon?job=GEOS_Worker_Run/label=berrie&build=last:${params.reference=refs/heads/main})](https://debbie.postgis.net/view/GEOS/job/GEOS_Worker_Run/label=berrie) | Berrie64 | [![berrie64](https://debbie.postgis.net/buildStatus/icon?job=GEOS_Worker_Run/label=berrie64&build=last:${params.reference=refs/heads/main})](https://debbie.postgis.net/view/GEOS/job/GEOS_Worker_Run/label=berrie64) | +| Codecov | [![codecov](https://codecov.io/gh/libgeos/geos/branch/main/graph/badge.svg?token=rOsQs83Jbu)](https://codecov.io/gh/libgeos/geos) | | | | | ## Community Resources ----------------------------------------------------------------------- Summary of changes: .codecov.yml | 7 ++++++- README.md | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Sun Dec 7 13:54:47 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 7 Dec 2025 13:54:47 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. ad73047bf08756f0786c920358059fe3b9c5fa02 Message-ID: <20251207215447.5D029132341@trac.osgeo.org> 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 ad73047bf08756f0786c920358059fe3b9c5fa02 (commit) from cdc6dbd6def66a73ad89d2dcf4f01893afe1f94c (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 ad73047bf08756f0786c920358059fe3b9c5fa02 Author: Mike Taves Date: Mon Dec 8 10:53:37 2025 +1300 Refactor FE_ macro checks for Emscripten; add CI job (#1333) * Refactor FE_ macro checks for Emscripten; add CI job * Re-introduce HAVE_FENV via opt-in MISSING_FENV define * Check for cfenv C++ header instead of fenv.h C header diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69b0b8601..6a68e6351 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -485,6 +485,49 @@ jobs: working-directory: ./build run: ctest -V --output-on-failure -C ${{ matrix.build_type }} + emscripten: + name: Emscripten WASM build + runs-on: ubuntu-latest + steps: + - name: Install + run: | + set -e + sudo -E apt-get update + sudo -E apt-get autopurge -y needrestart + sudo -E apt-get -yq --no-install-suggests --no-install-recommends install make cmake emscripten ccache + + - uses: actions/checkout at v5 + + - name: Retrieve build cache + uses: actions/cache/restore at v4 + id: restore-cache + with: + path: .ccache + key: emscripten-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: emscripten + + - name: Build + run: | + set -e + mkdir build + cd build + cmake --version + emcmake cmake \ + -D BUILD_SHARED_LIBS=OFF \ + -D USE_CCACHE=ON \ + .. + cmake --build . -j $(nproc) + ccache --show-stats + + - name: Save build cache + uses: actions/cache/save at v4 + with: + path: .ccache + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + +# - name: Test +# working-directory: ./build +# run: ctest --output-on-failure code-quality: name: Code quality checks diff --git a/CMakeLists.txt b/CMakeLists.txt index 79d397efb..852c724ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -335,6 +335,12 @@ set(CMAKE_CXX_FLAGS_COVERAGE "-fprofile-arcs -ftest-coverage") include(CheckLibraryExists) check_library_exists(m pow "" HAVE_LIBM) +#----------------------------------------------------------------------------- +# Extra include +#----------------------------------------------------------------------------- +include(CheckIncludeFileCXX) +check_include_file_cxx(cfenv HAVE_FENV_H) + #----------------------------------------------------------------------------- # Target geos: C++ API library #----------------------------------------------------------------------------- @@ -576,10 +582,3 @@ 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() diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 063c408ff..ecaa63d2f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -63,6 +63,11 @@ foreach(_testfile ${_testfiles}) set_tests_properties(unit-${_cmake_testname} PROPERTIES TIMEOUT 30) endforeach() +if(NOT HAVE_FENV_H) + # Used to set HAVE_FENV in test files + add_compile_definitions(MISSING_FENV) +endif() + # Run all the unit tests in one go, for faster memory checking # under valgrind. Restrict to one configuration so it is only # run with 'ctest -C Valgrind' diff --git a/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp b/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp index f50b58680..8e85bf0a4 100644 --- a/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp +++ b/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp @@ -16,7 +16,10 @@ #include #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif namespace geos { namespace geom { @@ -191,13 +194,17 @@ template<> void object::test<6> () { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif runTest( "LINESTRING (0 0, 100 0, 10 100, 10 100)", "LINESTRING (0 100, 0 10, 80 10)", 0.001, 47.89); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif } // Crash on collection with empty components diff --git a/tests/unit/capi/GEOSDistanceTest.cpp b/tests/unit/capi/GEOSDistanceTest.cpp index f5f5e1471..152aade8b 100644 --- a/tests/unit/capi/GEOSDistanceTest.cpp +++ b/tests/unit/capi/GEOSDistanceTest.cpp @@ -9,7 +9,10 @@ #include #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include #include "capi_test_utils.h" @@ -119,8 +122,10 @@ void object::test<4> geom1_ = fromWKT("POINT (0 0)"); geom2_ = fromWKT("POINT (1 1)"); +#ifdef HAVE_FENV // clear all floating point exceptions feclearexcept (FE_ALL_EXCEPT); +#endif double d; int status = GEOSDistance(geom1_, geom2_, &d); @@ -128,9 +133,11 @@ void object::test<4> ensure_equals(status, 1); ensure_equals(d, std::sqrt(2)); +#ifdef FE_OVERFLOW // check for floating point overflow exceptions int raised = fetestexcept(FE_OVERFLOW); ensure_equals(raised & FE_OVERFLOW, 0); +#endif } // same distance between boundables should not raise floating point exception @@ -142,8 +149,10 @@ void object::test<5> geom1_ = fromWKT("LINESTRING (0 0, 1 1)"); geom2_ = fromWKT("LINESTRING (2 1, 1 2)"); +#ifdef HAVE_FENV // clear all floating point exceptions feclearexcept (FE_ALL_EXCEPT); +#endif double d; int status = GEOSDistance(geom1_, geom2_, &d); @@ -151,9 +160,11 @@ void object::test<5> ensure_equals(status, 1); // ensure_equals(d, std::sqrt(2)); +#ifdef FE_OVERFLOW // check for floating point overflow exceptions int raised = fetestexcept(FE_OVERFLOW); ensure_equals(raised & FE_OVERFLOW, 0); +#endif } template<> diff --git a/tests/unit/capi/GEOSIntersectionTest.cpp b/tests/unit/capi/GEOSIntersectionTest.cpp index c94b056a7..4a03845df 100644 --- a/tests/unit/capi/GEOSIntersectionTest.cpp +++ b/tests/unit/capi/GEOSIntersectionTest.cpp @@ -140,7 +140,9 @@ void object::test<7> result_ = GEOSIntersection(geom1_, geom2_); +#ifdef FE_INVALID ensure(!std::fetestexcept(FE_INVALID)); +#endif } template<> diff --git a/tests/unit/capi/GEOSProjectTest.cpp b/tests/unit/capi/GEOSProjectTest.cpp index af8640f8b..d2556a897 100644 --- a/tests/unit/capi/GEOSProjectTest.cpp +++ b/tests/unit/capi/GEOSProjectTest.cpp @@ -100,14 +100,22 @@ void object::test<5> geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 1 1, 1 1, 2 2)"); geom2_ = GEOSGeomFromWKT("POINT (0 1)"); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif double dist = GEOSProject(geom1_, geom2_); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif ensure_equals("GEOSProject", dist, 0.7071, 0.0001); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif double dist_norm = GEOSProjectNormalized(geom1_, geom2_); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif ensure_equals("GEOSProjectNormalized", dist_norm, 0.25); } diff --git a/tests/unit/capi/GEOSVoronoiDiagramTest.cpp b/tests/unit/capi/GEOSVoronoiDiagramTest.cpp index 7c5b05bcd..d79181351 100644 --- a/tests/unit/capi/GEOSVoronoiDiagramTest.cpp +++ b/tests/unit/capi/GEOSVoronoiDiagramTest.cpp @@ -5,7 +5,10 @@ // geos #include // std +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include "capi_test_utils.h" @@ -57,7 +60,9 @@ template<> void object::test<1> () { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif geom1_ = GEOSGeomFromWKT("POINT(10 20)"); @@ -69,7 +74,9 @@ void object::test<1> geom2_ = GEOSVoronoiDiagram(geom1_, nullptr, 0, 1); ensure_geometry_equals(geom2_, "MULTILINESTRING EMPTY"); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif } //More points: diff --git a/tests/unit/capi/capi_test_utils.h b/tests/unit/capi/capi_test_utils.h index 67818d6a1..0b8d03284 100644 --- a/tests/unit/capi/capi_test_utils.h +++ b/tests/unit/capi/capi_test_utils.h @@ -7,7 +7,10 @@ #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif namespace capitest { @@ -29,7 +32,9 @@ namespace capitest { wktw_ = GEOSWKTWriter_create(); GEOSWKTWriter_setRoundingPrecision(wktw_, 10); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif } ~utility() diff --git a/tests/unit/geom/EnvelopeTest.cpp b/tests/unit/geom/EnvelopeTest.cpp index a816f84f3..1e9385e81 100644 --- a/tests/unit/geom/EnvelopeTest.cpp +++ b/tests/unit/geom/EnvelopeTest.cpp @@ -8,7 +8,10 @@ #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include namespace tut { @@ -23,7 +26,9 @@ using geos::geom::Envelope; struct test_envelope_data { test_envelope_data() { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif } static std::size_t @@ -91,11 +96,21 @@ struct test_envelope_data { static void ensure_no_fp_except() { +#ifdef FE_DIVBYZERO ensure("FE_DIVBYZERO raised", !std::fetestexcept(FE_DIVBYZERO)); +#endif +//#ifdef FE_INEXACT //ensure("FE_INEXACT raised", !std::fetestexcept(FE_INEXACT)); +//#endif +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif +#ifdef FE_OVERFLOW ensure("FE_OVERFLOW raised", !std::fetestexcept(FE_OVERFLOW)); +#endif +#ifdef FE_UNDERFLOW ensure("FE_UNDERFLOW raised", !std::fetestexcept(FE_UNDERFLOW)); +#endif } }; diff --git a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp index 27279708e..66865b349 100644 --- a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp +++ b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp @@ -9,7 +9,10 @@ #include // std +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include using namespace geos::geom; @@ -33,9 +36,13 @@ struct test_coverageunionng_data { { std::unique_ptr geom = r.read(wkt); std::unique_ptr expected = r.read(wktExpected); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif std::unique_ptr result = CoverageUnion::geomunion(geom.get()); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif try { ensure_equals_geometry_xyzm(result.get(), expected.get()); diff --git a/util/geosop/CMakeLists.txt b/util/geosop/CMakeLists.txt index 165727460..2351fc6ff 100644 --- a/util/geosop/CMakeLists.txt +++ b/util/geosop/CMakeLists.txt @@ -16,6 +16,10 @@ add_executable(geosop target_link_libraries(geosop PRIVATE geos geos_c) +if(NOT HAVE_FENV_H) + target_compile_definitions(geosop PRIVATE MISSING_FENV) +endif() + install(TARGETS geosop DESTINATION ${CMAKE_INSTALL_BINDIR} ) diff --git a/util/geosop/GeosOp.cpp b/util/geosop/GeosOp.cpp index 97db2c3f8..b6c0d0a9f 100644 --- a/util/geosop/GeosOp.cpp +++ b/util/geosop/GeosOp.cpp @@ -26,7 +26,8 @@ #include #include -#if defined(HAVE_FENV) +#if !defined(MISSING_FENV) +#define HAVE_FENV #include #endif #include @@ -399,30 +400,44 @@ void GeosOp::run(OpArguments& opArgs) { //------------------------ try { -#if defined(HAVE_FENV) +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); // clear floating-point status flags -#endif execute(op, opArgs); -#if defined(HAVE_FENV) +#ifdef FE_INEXACT // Catch everything except for FE_INEXACT, which is usually harmless const int fpexp = std::fetestexcept(FE_ALL_EXCEPT ^ FE_INEXACT); +#else + const int fpexp = std::fetestexcept(FE_ALL_EXCEPT); +#endif if (args.isVerbose && (fpexp != 0)) { std::cerr << "Operation raised floating-point environment flag(s):"; +#ifdef FE_DIVBYZERO if (fpexp & FE_DIVBYZERO) std::cerr << " FE_DIVBYZERO"; +#endif +#ifdef FE_INEXACT if (fpexp & FE_INEXACT) std::cerr << " FE_INEXACT"; +#endif +#ifdef FE_INVALID if (fpexp & FE_INVALID) std::cerr << " FE_INVALID"; +#endif +#ifdef FE_OVERFLOW if (fpexp & FE_OVERFLOW) std::cerr << " FE_OVERFLOW"; +#endif +#ifdef FE_UNDERFLOW if (fpexp & FE_UNDERFLOW) std::cerr << " FE_UNDERFLOW"; +#endif std::cerr << std::endl; } -#endif +#else // MISSING_FENV + execute(op, opArgs); +#endif // HAVE_FENV } catch (std::exception &e) { std::cerr << "Run-time exception: " << e.what() << std::endl; ----------------------------------------------------------------------- Summary of changes: .github/workflows/ci.yml | 43 ++++++++++++++++++++++ CMakeLists.txt | 13 +++---- tests/unit/CMakeLists.txt | 5 +++ .../distance/DiscreteHausdorffDistanceTest.cpp | 7 ++++ tests/unit/capi/GEOSDistanceTest.cpp | 11 ++++++ tests/unit/capi/GEOSIntersectionTest.cpp | 2 + tests/unit/capi/GEOSProjectTest.cpp | 8 ++++ tests/unit/capi/GEOSVoronoiDiagramTest.cpp | 7 ++++ tests/unit/capi/capi_test_utils.h | 5 +++ tests/unit/geom/EnvelopeTest.cpp | 15 ++++++++ .../operation/overlayng/CoverageUnionNGTest.cpp | 7 ++++ util/geosop/CMakeLists.txt | 4 ++ util/geosop/GeosOp.cpp | 25 ++++++++++--- 13 files changed, 140 insertions(+), 12 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Sun Dec 7 14:08:32 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 7 Dec 2025 14:08:32 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.14 updated. d18db3a1108a504938e7da4f7818c7195cc021c4 Message-ID: <20251207220832.A310F1324A6@trac.osgeo.org> 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.14 has been updated via d18db3a1108a504938e7da4f7818c7195cc021c4 (commit) from beb52e94b100efc12a8f764d896586adc10420c8 (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 d18db3a1108a504938e7da4f7818c7195cc021c4 Author: Mike Taves Date: Mon Dec 8 10:53:37 2025 +1300 Refactor FE_ macro checks for Emscripten; add CI job (#1333) * Refactor FE_ macro checks for Emscripten; add CI job * Re-introduce HAVE_FENV via opt-in MISSING_FENV define * Check for cfenv C++ header instead of fenv.h C header * Add NEWS entry diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 113f55e61..c1741a25f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -481,6 +481,49 @@ jobs: working-directory: ./build run: ctest -V --output-on-failure -C ${{ matrix.build_type }} + emscripten: + name: Emscripten WASM build + runs-on: ubuntu-latest + steps: + - name: Install + run: | + set -e + sudo -E apt-get update + sudo -E apt-get autopurge -y needrestart + sudo -E apt-get -yq --no-install-suggests --no-install-recommends install make cmake emscripten ccache + + - uses: actions/checkout at v5 + + - name: Retrieve build cache + uses: actions/cache/restore at v4 + id: restore-cache + with: + path: .ccache + key: emscripten-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: emscripten + + - name: Build + run: | + set -e + mkdir build + cd build + cmake --version + emcmake cmake \ + -D BUILD_SHARED_LIBS=OFF \ + -D USE_CCACHE=ON \ + .. + cmake --build . -j $(nproc) + ccache --show-stats + + - name: Save build cache + uses: actions/cache/save at v4 + with: + path: .ccache + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + +# - name: Test +# working-directory: ./build +# run: ctest --output-on-failure code-quality: name: Code quality checks diff --git a/CMakeLists.txt b/CMakeLists.txt index a1e2f0c6e..8f63318f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,6 +317,12 @@ set(CMAKE_CXX_FLAGS_COVERAGE "-fprofile-arcs -ftest-coverage") include(CheckLibraryExists) check_library_exists(m pow "" HAVE_LIBM) +#----------------------------------------------------------------------------- +# Extra include +#----------------------------------------------------------------------------- +include(CheckIncludeFileCXX) +check_include_file_cxx(cfenv HAVE_FENV_H) + #----------------------------------------------------------------------------- # Target geos: C++ API library #----------------------------------------------------------------------------- @@ -558,10 +564,3 @@ 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() diff --git a/NEWS.md b/NEWS.md index d31f941e0..cf736c28d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,10 @@ +## Changes in 3.14.2 +2025-xx-xx + +- Fixes/Improvements: + - Relax other floating-point exception handling with other compilers (GH-1333, Mike Taves) + ## Changes in 3.14.1 2025-10-27 @@ -8,7 +14,6 @@ - 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 diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 063c408ff..ecaa63d2f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -63,6 +63,11 @@ foreach(_testfile ${_testfiles}) set_tests_properties(unit-${_cmake_testname} PROPERTIES TIMEOUT 30) endforeach() +if(NOT HAVE_FENV_H) + # Used to set HAVE_FENV in test files + add_compile_definitions(MISSING_FENV) +endif() + # Run all the unit tests in one go, for faster memory checking # under valgrind. Restrict to one configuration so it is only # run with 'ctest -C Valgrind' diff --git a/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp b/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp index f50b58680..8e85bf0a4 100644 --- a/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp +++ b/tests/unit/algorithm/distance/DiscreteHausdorffDistanceTest.cpp @@ -16,7 +16,10 @@ #include #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif namespace geos { namespace geom { @@ -191,13 +194,17 @@ template<> void object::test<6> () { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif runTest( "LINESTRING (0 0, 100 0, 10 100, 10 100)", "LINESTRING (0 100, 0 10, 80 10)", 0.001, 47.89); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif } // Crash on collection with empty components diff --git a/tests/unit/capi/GEOSDistanceTest.cpp b/tests/unit/capi/GEOSDistanceTest.cpp index f5f5e1471..152aade8b 100644 --- a/tests/unit/capi/GEOSDistanceTest.cpp +++ b/tests/unit/capi/GEOSDistanceTest.cpp @@ -9,7 +9,10 @@ #include #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include #include "capi_test_utils.h" @@ -119,8 +122,10 @@ void object::test<4> geom1_ = fromWKT("POINT (0 0)"); geom2_ = fromWKT("POINT (1 1)"); +#ifdef HAVE_FENV // clear all floating point exceptions feclearexcept (FE_ALL_EXCEPT); +#endif double d; int status = GEOSDistance(geom1_, geom2_, &d); @@ -128,9 +133,11 @@ void object::test<4> ensure_equals(status, 1); ensure_equals(d, std::sqrt(2)); +#ifdef FE_OVERFLOW // check for floating point overflow exceptions int raised = fetestexcept(FE_OVERFLOW); ensure_equals(raised & FE_OVERFLOW, 0); +#endif } // same distance between boundables should not raise floating point exception @@ -142,8 +149,10 @@ void object::test<5> geom1_ = fromWKT("LINESTRING (0 0, 1 1)"); geom2_ = fromWKT("LINESTRING (2 1, 1 2)"); +#ifdef HAVE_FENV // clear all floating point exceptions feclearexcept (FE_ALL_EXCEPT); +#endif double d; int status = GEOSDistance(geom1_, geom2_, &d); @@ -151,9 +160,11 @@ void object::test<5> ensure_equals(status, 1); // ensure_equals(d, std::sqrt(2)); +#ifdef FE_OVERFLOW // check for floating point overflow exceptions int raised = fetestexcept(FE_OVERFLOW); ensure_equals(raised & FE_OVERFLOW, 0); +#endif } template<> diff --git a/tests/unit/capi/GEOSIntersectionTest.cpp b/tests/unit/capi/GEOSIntersectionTest.cpp index c94b056a7..4a03845df 100644 --- a/tests/unit/capi/GEOSIntersectionTest.cpp +++ b/tests/unit/capi/GEOSIntersectionTest.cpp @@ -140,7 +140,9 @@ void object::test<7> result_ = GEOSIntersection(geom1_, geom2_); +#ifdef FE_INVALID ensure(!std::fetestexcept(FE_INVALID)); +#endif } template<> diff --git a/tests/unit/capi/GEOSProjectTest.cpp b/tests/unit/capi/GEOSProjectTest.cpp index af8640f8b..d2556a897 100644 --- a/tests/unit/capi/GEOSProjectTest.cpp +++ b/tests/unit/capi/GEOSProjectTest.cpp @@ -100,14 +100,22 @@ void object::test<5> geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 1 1, 1 1, 2 2)"); geom2_ = GEOSGeomFromWKT("POINT (0 1)"); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif double dist = GEOSProject(geom1_, geom2_); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif ensure_equals("GEOSProject", dist, 0.7071, 0.0001); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif double dist_norm = GEOSProjectNormalized(geom1_, geom2_); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif ensure_equals("GEOSProjectNormalized", dist_norm, 0.25); } diff --git a/tests/unit/capi/GEOSVoronoiDiagramTest.cpp b/tests/unit/capi/GEOSVoronoiDiagramTest.cpp index 7c5b05bcd..d79181351 100644 --- a/tests/unit/capi/GEOSVoronoiDiagramTest.cpp +++ b/tests/unit/capi/GEOSVoronoiDiagramTest.cpp @@ -5,7 +5,10 @@ // geos #include // std +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include "capi_test_utils.h" @@ -57,7 +60,9 @@ template<> void object::test<1> () { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif geom1_ = GEOSGeomFromWKT("POINT(10 20)"); @@ -69,7 +74,9 @@ void object::test<1> geom2_ = GEOSVoronoiDiagram(geom1_, nullptr, 0, 1); ensure_geometry_equals(geom2_, "MULTILINESTRING EMPTY"); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif } //More points: diff --git a/tests/unit/capi/capi_test_utils.h b/tests/unit/capi/capi_test_utils.h index 67818d6a1..0b8d03284 100644 --- a/tests/unit/capi/capi_test_utils.h +++ b/tests/unit/capi/capi_test_utils.h @@ -7,7 +7,10 @@ #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif namespace capitest { @@ -29,7 +32,9 @@ namespace capitest { wktw_ = GEOSWKTWriter_create(); GEOSWKTWriter_setRoundingPrecision(wktw_, 10); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif } ~utility() diff --git a/tests/unit/geom/EnvelopeTest.cpp b/tests/unit/geom/EnvelopeTest.cpp index b1250a63e..5974f84e0 100644 --- a/tests/unit/geom/EnvelopeTest.cpp +++ b/tests/unit/geom/EnvelopeTest.cpp @@ -8,7 +8,10 @@ #include #include +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include namespace tut { @@ -23,7 +26,9 @@ using geos::geom::Envelope; struct test_envelope_data { test_envelope_data() { +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif } static std::size_t @@ -91,11 +96,21 @@ struct test_envelope_data { static void ensure_no_fp_except() { +#ifdef FE_DIVBYZERO ensure("FE_DIVBYZERO raised", !std::fetestexcept(FE_DIVBYZERO)); +#endif +//#ifdef FE_INEXACT //ensure("FE_INEXACT raised", !std::fetestexcept(FE_INEXACT)); +//#endif +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif +#ifdef FE_OVERFLOW ensure("FE_OVERFLOW raised", !std::fetestexcept(FE_OVERFLOW)); +#endif +#ifdef FE_UNDERFLOW ensure("FE_UNDERFLOW raised", !std::fetestexcept(FE_UNDERFLOW)); +#endif } }; diff --git a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp index 27279708e..66865b349 100644 --- a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp +++ b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp @@ -9,7 +9,10 @@ #include // std +#if !defined(MISSING_FENV) +#define HAVE_FENV #include +#endif #include using namespace geos::geom; @@ -33,9 +36,13 @@ struct test_coverageunionng_data { { std::unique_ptr geom = r.read(wkt); std::unique_ptr expected = r.read(wktExpected); +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); +#endif std::unique_ptr result = CoverageUnion::geomunion(geom.get()); +#ifdef FE_INVALID ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID)); +#endif try { ensure_equals_geometry_xyzm(result.get(), expected.get()); diff --git a/util/geosop/CMakeLists.txt b/util/geosop/CMakeLists.txt index 165727460..2351fc6ff 100644 --- a/util/geosop/CMakeLists.txt +++ b/util/geosop/CMakeLists.txt @@ -16,6 +16,10 @@ add_executable(geosop target_link_libraries(geosop PRIVATE geos geos_c) +if(NOT HAVE_FENV_H) + target_compile_definitions(geosop PRIVATE MISSING_FENV) +endif() + install(TARGETS geosop DESTINATION ${CMAKE_INSTALL_BINDIR} ) diff --git a/util/geosop/GeosOp.cpp b/util/geosop/GeosOp.cpp index 05307cf30..bee8b75a9 100644 --- a/util/geosop/GeosOp.cpp +++ b/util/geosop/GeosOp.cpp @@ -26,7 +26,8 @@ #include #include -#if defined(HAVE_FENV) +#if !defined(MISSING_FENV) +#define HAVE_FENV #include #endif #include @@ -396,30 +397,44 @@ void GeosOp::run(OpArguments& opArgs) { //------------------------ try { -#if defined(HAVE_FENV) +#ifdef HAVE_FENV std::feclearexcept(FE_ALL_EXCEPT); // clear floating-point status flags -#endif execute(op, opArgs); -#if defined(HAVE_FENV) +#ifdef FE_INEXACT // Catch everything except for FE_INEXACT, which is usually harmless const int fpexp = std::fetestexcept(FE_ALL_EXCEPT ^ FE_INEXACT); +#else + const int fpexp = std::fetestexcept(FE_ALL_EXCEPT); +#endif if (args.isVerbose && (fpexp != 0)) { std::cerr << "Operation raised floating-point environment flag(s):"; +#ifdef FE_DIVBYZERO if (fpexp & FE_DIVBYZERO) std::cerr << " FE_DIVBYZERO"; +#endif +#ifdef FE_INEXACT if (fpexp & FE_INEXACT) std::cerr << " FE_INEXACT"; +#endif +#ifdef FE_INVALID if (fpexp & FE_INVALID) std::cerr << " FE_INVALID"; +#endif +#ifdef FE_OVERFLOW if (fpexp & FE_OVERFLOW) std::cerr << " FE_OVERFLOW"; +#endif +#ifdef FE_UNDERFLOW if (fpexp & FE_UNDERFLOW) std::cerr << " FE_UNDERFLOW"; +#endif std::cerr << std::endl; } -#endif +#else // MISSING_FENV + execute(op, opArgs); +#endif // HAVE_FENV } catch (std::exception &e) { std::cerr << "Run-time exception: " << e.what() << std::endl; ----------------------------------------------------------------------- Summary of changes: .github/workflows/ci.yml | 43 ++++++++++++++++++++++ CMakeLists.txt | 13 +++---- NEWS.md | 7 +++- tests/unit/CMakeLists.txt | 5 +++ .../distance/DiscreteHausdorffDistanceTest.cpp | 7 ++++ tests/unit/capi/GEOSDistanceTest.cpp | 11 ++++++ tests/unit/capi/GEOSIntersectionTest.cpp | 2 + tests/unit/capi/GEOSProjectTest.cpp | 8 ++++ tests/unit/capi/GEOSVoronoiDiagramTest.cpp | 7 ++++ tests/unit/capi/capi_test_utils.h | 5 +++ tests/unit/geom/EnvelopeTest.cpp | 15 ++++++++ .../operation/overlayng/CoverageUnionNGTest.cpp | 7 ++++ util/geosop/CMakeLists.txt | 4 ++ util/geosop/GeosOp.cpp | 25 ++++++++++--- 14 files changed, 146 insertions(+), 13 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Wed Dec 10 11:15:03 2025 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Dec 2025 11:15:03 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. f175f9af82fd0c4ab2d913205ff8480b7a12a055 Message-ID: <20251210191504.17C4C18A839@trac.osgeo.org> 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 f175f9af82fd0c4ab2d913205ff8480b7a12a055 (commit) via bfa9cd118979a46de25a2355fd0b9973c476691a (commit) from ad73047bf08756f0786c920358059fe3b9c5fa02 (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 f175f9af82fd0c4ab2d913205ff8480b7a12a055 Author: Paul Ramsey Date: Wed Dec 10 11:13:59 2025 -0800 Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection showing in downstream libraries, closes #1235 diff --git a/include/geos/math/DD.h b/include/geos/math/DD.h index 7be00a6f7..83b26f6a3 100644 --- a/include/geos/math/DD.h +++ b/include/geos/math/DD.h @@ -114,6 +114,7 @@ class GEOS_DLL DD { int signum() const; DD rint() const; + void setNaN(); public: DD(double p_hi, double p_lo) : hi(p_hi), lo(p_lo) {}; @@ -166,6 +167,7 @@ class GEOS_DLL DD { static DD pow(const DD &d, int exp); static DD trunc(const DD &d); + bool isInf() const; bool isNaN() const; bool isNegative() const; bool isPositive() const; diff --git a/src/algorithm/CGAlgorithmsDD.cpp b/src/algorithm/CGAlgorithmsDD.cpp index 0d61b335e..df6fd0112 100644 --- a/src/algorithm/CGAlgorithmsDD.cpp +++ b/src/algorithm/CGAlgorithmsDD.cpp @@ -139,19 +139,12 @@ CGAlgorithmsDD::intersection(const CoordinateXY& p1, const CoordinateXY& p2, DD y = (qx * pw) - (px * qw); DD w = (px * qy) - (qx * py); + if (w.isZero()) + return CoordinateXY::getNull(); + double xInt = (x / w).ToDouble(); double yInt = (y / w).ToDouble(); - - Coordinate rv; - - if (!std::isfinite(xInt) || !std::isfinite(yInt)) { - rv.setNull(); - return rv; - } - - rv.x = xInt; - rv.y = yInt; - return rv; + return {xInt, yInt}; } /* public static */ diff --git a/src/math/DD.cpp b/src/math/DD.cpp index 662f1f1d3..e158dc685 100644 --- a/src/math/DD.cpp +++ b/src/math/DD.cpp @@ -20,8 +20,16 @@ namespace geos { namespace math { // geos.util - - +/* private */ +void DD::setNaN() +{ + hi = std::numeric_limits::quiet_NaN(); +} +/* public */ +bool DD::isInf() const +{ + return std::isinf(hi); +} /* public */ bool DD::isNaN() const { @@ -351,6 +359,7 @@ DD DD::determinant(double x1, double y1, double x2, double y2) return determinant(DD(x1), DD(y1), DD(x2), DD(y2) ); } + /** * Computes the value of this number raised to an integral power. * Follows semantics of Java Math.pow as closely as possible. diff --git a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp index a36723bb8..55cf17826 100644 --- a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp +++ b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp @@ -147,35 +147,37 @@ template<> template<> void object::test<10>() { - // bool error = false; - // try { - checkMinRectangle( - "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", - "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); + checkMinRectangle( + "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", + "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); } + // testBadRectl template<> template<> void object::test<11>() { - // bool error = false; - // try { checkMinRectangle( "POLYGON ((-5.21175 49.944633, -5.77435 50.021367, -5.7997 50.0306, -5.81815 50.0513, -5.82625 50.073567, -5.83085 50.1173, -6.2741 56.758767, -5.93245 57.909, -5.1158 58.644533, -5.07915 58.661733, -3.42575 58.686633, -3.1392 58.6685, -3.12495 58.666233, -1.88745 57.6444, 1.68845 52.715133, 1.7057 52.6829, 1.70915 52.6522, 1.7034 52.585433, 1.3867 51.214033, 1.36595 51.190267, 1.30485 51.121967, 0.96365 50.928567, 0.93025 50.912433, 0.1925 50.7436, -5.21175 49.944633))", "POLYGON ((1.8583607388069103 50.41649058582797, -5.816631979932251 49.904263313964535, -6.395241388167441 58.57389735949991, 1.2797513305717105 59.08612463136336, 1.8583607388069103 50.41649058582797))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); } +// https://github.com/libgeos/geos/issues/1235 +// throwing FE_DIVBYZERO +template<> +template<> +void object::test<12>() +{ + checkMinRectangle( + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))", + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))"); +} + + + + + } // namespace tut diff --git a/tests/unit/geos_unit.cpp b/tests/unit/geos_unit.cpp index 9526b009e..cbd1a86cc 100644 --- a/tests/unit/geos_unit.cpp +++ b/tests/unit/geos_unit.cpp @@ -50,7 +50,7 @@ usage() << " " << module << " geos::geom::Envelope\n" << " " << module << " geos::geom::Envelope 2\n" << endl - << "GEOS homepage: http://geos.osgeo.org" << endl; + << "GEOS homepage: https://libgeos.org" << endl; } int commit bfa9cd118979a46de25a2355fd0b9973c476691a Author: Paul Ramsey Date: Wed Dec 10 10:49:16 2025 -0800 Use nameless catch for exceptions that do not use exception var diff --git a/src/linearref/LinearGeometryBuilder.cpp b/src/linearref/LinearGeometryBuilder.cpp index 445f2d70d..947747ba8 100644 --- a/src/linearref/LinearGeometryBuilder.cpp +++ b/src/linearref/LinearGeometryBuilder.cpp @@ -117,10 +117,9 @@ LinearGeometryBuilder::endLine() try { line = geomFact->createLineString(std::move(coordList)); } - catch(util::IllegalArgumentException & ex) { + catch(util::IllegalArgumentException &) { // exception is due to too few points in line. // only propagate if not ignoring short lines - ::geos::ignore_unused_variable_warning(ex); if(! ignoreInvalidLines) { throw; } diff --git a/src/operation/union/CascadedPolygonUnion.cpp b/src/operation/union/CascadedPolygonUnion.cpp index 82cd91bcc..35a93b0e9 100644 --- a/src/operation/union/CascadedPolygonUnion.cpp +++ b/src/operation/union/CascadedPolygonUnion.cpp @@ -204,8 +204,7 @@ ClassicUnionStrategy::Union(const geom::Geometry* g0, const geom::Geometry* g1) try { return operation::overlayng::OverlayNGRobust::Overlay(g0, g1, operation::overlayng::OverlayNG::UNION); } - catch (const util::TopologyException &ex) { - ::geos::ignore_unused_variable_warning(ex); + catch (const util::TopologyException &) { // union-by-buffer only works for polygons if (g0->getDimension() != 2 || g1->getDimension() != 2) throw; diff --git a/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp b/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp index e7e917509..f17568ef7 100644 --- a/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp +++ b/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp @@ -202,16 +202,15 @@ void object::test<8> () try { MaximumInscribedCircle mic(g1.get(), 1); mic.getCenter(); - } catch (const util::GEOSException & e) { - ::geos::ignore_unused_variable_warning(e); + } catch (const util::GEOSException &) { } auto g2 = reader_.read("POLYGON ((0 0, 1 0, 2 NaN, 0 0))"); try { MaximumInscribedCircle mic(g1.get(), 1); mic.getCenter(); - } catch (const util::GEOSException & e) { - ::geos::ignore_unused_variable_warning(e); + } + catch (const util::GEOSException &) { } } diff --git a/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp b/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp index 86472ac06..b98c8f8d5 100644 --- a/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp +++ b/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp @@ -76,27 +76,24 @@ void object::test<1> () try { checkDensifiedFrechet("LINESTRING (0 0, 2 1)", "LINESTRING EMPTY", 0.0, 0); } - catch(const geos::util::IllegalArgumentException& e) { + catch(const geos::util::IllegalArgumentException &) { // We do expect an exception - ::geos::ignore_unused_variable_warning(e); } // too big densify factor try { checkDensifiedFrechet("LINESTRING (0 0, 2 1)", "LINESTRING EMPTY", 1 + 1e-10, 0); } - catch(const geos::util::IllegalArgumentException& e) { + catch(const geos::util::IllegalArgumentException &) { // We do expect an exception - ::geos::ignore_unused_variable_warning(e); } // too small positive densify factor try { checkDensifiedFrechet("LINESTRING (0 0, 2 1)", "LINESTRING EMPTY", 1e-30, 0); } - catch(const geos::util::IllegalArgumentException& e) { + catch(const geos::util::IllegalArgumentException &) { // We do expect an exception - ::geos::ignore_unused_variable_warning(e); } } diff --git a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp index 66865b349..01095d0f5 100644 --- a/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp +++ b/tests/unit/operation/overlayng/CoverageUnionNGTest.cpp @@ -46,8 +46,7 @@ struct test_coverageunionng_data { try { ensure_equals_geometry_xyzm(result.get(), expected.get()); - } catch (const std::exception& e) { - ::geos::ignore_unused_variable_warning(e); + } catch (const std::exception &) { std::string wkt_result = w.write(result.get()); std::cerr << std::endl << wkt_result << std::endl; throw; diff --git a/tests/unit/triangulate/VoronoiTest.cpp b/tests/unit/triangulate/VoronoiTest.cpp index dd9066a95..e1ffaf6ee 100644 --- a/tests/unit/triangulate/VoronoiTest.cpp +++ b/tests/unit/triangulate/VoronoiTest.cpp @@ -323,8 +323,7 @@ void object::test<14> try { runVoronoi(wkt, "", 0, false, true); fail(); - } catch (const geos::util::GEOSException & e) { - ::geos::ignore_unused_variable_warning(e); + } catch (const geos::util::GEOSException &) { } } ----------------------------------------------------------------------- Summary of changes: include/geos/math/DD.h | 2 ++ src/algorithm/CGAlgorithmsDD.cpp | 15 +++------ src/linearref/LinearGeometryBuilder.cpp | 3 +- src/math/DD.cpp | 13 ++++++-- src/operation/union/CascadedPolygonUnion.cpp | 3 +- tests/unit/algorithm/MinimumAreaRectangleTest.cpp | 36 ++++++++++++---------- .../construct/MaximumInscribedCircleTest.cpp | 7 ++--- .../distance/DiscreteFrechetDistanceTest.cpp | 9 ++---- tests/unit/geos_unit.cpp | 2 +- .../operation/overlayng/CoverageUnionNGTest.cpp | 3 +- tests/unit/triangulate/VoronoiTest.cpp | 3 +- 11 files changed, 47 insertions(+), 49 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Wed Dec 10 11:16:35 2025 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Dec 2025 11:16:35 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.14 updated. a3d7aa413d0975c54491e31e91b9f92a35425fb1 Message-ID: <20251210191635.8105B18AD72@trac.osgeo.org> 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.14 has been updated via a3d7aa413d0975c54491e31e91b9f92a35425fb1 (commit) via 314ca48155b30640c1cd150597bcdfb4ede43389 (commit) from d18db3a1108a504938e7da4f7818c7195cc021c4 (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 a3d7aa413d0975c54491e31e91b9f92a35425fb1 Author: Paul Ramsey Date: Wed Dec 10 11:15:55 2025 -0800 NEWS.md diff --git a/NEWS.md b/NEWS.md index cf736c28d..712f49a09 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,7 @@ - Fixes/Improvements: - Relax other floating-point exception handling with other compilers (GH-1333, Mike Taves) + - Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection (GH-1235, Paul Ramsey) ## Changes in 3.14.1 2025-10-27 commit 314ca48155b30640c1cd150597bcdfb4ede43389 Author: Paul Ramsey Date: Wed Dec 10 11:13:59 2025 -0800 Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection showing in downstream libraries, closes #1235 diff --git a/include/geos/math/DD.h b/include/geos/math/DD.h index 61e3a08a7..764801251 100644 --- a/include/geos/math/DD.h +++ b/include/geos/math/DD.h @@ -114,6 +114,7 @@ class GEOS_DLL DD { int signum() const; DD rint() const; + void setNaN(); public: DD(double p_hi, double p_lo) : hi(p_hi), lo(p_lo) {}; @@ -165,6 +166,7 @@ class GEOS_DLL DD { static DD pow(const DD &d, int exp); static DD trunc(const DD &d); + bool isInf() const; bool isNaN() const; bool isNegative() const; bool isPositive() const; diff --git a/src/algorithm/CGAlgorithmsDD.cpp b/src/algorithm/CGAlgorithmsDD.cpp index 0d61b335e..df6fd0112 100644 --- a/src/algorithm/CGAlgorithmsDD.cpp +++ b/src/algorithm/CGAlgorithmsDD.cpp @@ -139,19 +139,12 @@ CGAlgorithmsDD::intersection(const CoordinateXY& p1, const CoordinateXY& p2, DD y = (qx * pw) - (px * qw); DD w = (px * qy) - (qx * py); + if (w.isZero()) + return CoordinateXY::getNull(); + double xInt = (x / w).ToDouble(); double yInt = (y / w).ToDouble(); - - Coordinate rv; - - if (!std::isfinite(xInt) || !std::isfinite(yInt)) { - rv.setNull(); - return rv; - } - - rv.x = xInt; - rv.y = yInt; - return rv; + return {xInt, yInt}; } /* public static */ diff --git a/src/math/DD.cpp b/src/math/DD.cpp index c620c1b62..86d284a11 100644 --- a/src/math/DD.cpp +++ b/src/math/DD.cpp @@ -20,8 +20,16 @@ namespace geos { namespace math { // geos.util - - +/* private */ +void DD::setNaN() +{ + hi = std::numeric_limits::quiet_NaN(); +} +/* public */ +bool DD::isInf() const +{ + return std::isinf(hi); +} /* public */ bool DD::isNaN() const { @@ -346,6 +354,7 @@ DD DD::determinant(double x1, double y1, double x2, double y2) return determinant(DD(x1), DD(y1), DD(x2), DD(y2) ); } + /** * Computes the value of this number raised to an integral power. * Follows semantics of Java Math.pow as closely as possible. diff --git a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp index a36723bb8..55cf17826 100644 --- a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp +++ b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp @@ -147,35 +147,37 @@ template<> template<> void object::test<10>() { - // bool error = false; - // try { - checkMinRectangle( - "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", - "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); + checkMinRectangle( + "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", + "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); } + // testBadRectl template<> template<> void object::test<11>() { - // bool error = false; - // try { checkMinRectangle( "POLYGON ((-5.21175 49.944633, -5.77435 50.021367, -5.7997 50.0306, -5.81815 50.0513, -5.82625 50.073567, -5.83085 50.1173, -6.2741 56.758767, -5.93245 57.909, -5.1158 58.644533, -5.07915 58.661733, -3.42575 58.686633, -3.1392 58.6685, -3.12495 58.666233, -1.88745 57.6444, 1.68845 52.715133, 1.7057 52.6829, 1.70915 52.6522, 1.7034 52.585433, 1.3867 51.214033, 1.36595 51.190267, 1.30485 51.121967, 0.96365 50.928567, 0.93025 50.912433, 0.1925 50.7436, -5.21175 49.944633))", "POLYGON ((1.8583607388069103 50.41649058582797, -5.816631979932251 49.904263313964535, -6.395241388167441 58.57389735949991, 1.2797513305717105 59.08612463136336, 1.8583607388069103 50.41649058582797))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); } +// https://github.com/libgeos/geos/issues/1235 +// throwing FE_DIVBYZERO +template<> +template<> +void object::test<12>() +{ + checkMinRectangle( + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))", + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))"); +} + + + + + } // namespace tut diff --git a/tests/unit/geos_unit.cpp b/tests/unit/geos_unit.cpp index 9526b009e..cbd1a86cc 100644 --- a/tests/unit/geos_unit.cpp +++ b/tests/unit/geos_unit.cpp @@ -50,7 +50,7 @@ usage() << " " << module << " geos::geom::Envelope\n" << " " << module << " geos::geom::Envelope 2\n" << endl - << "GEOS homepage: http://geos.osgeo.org" << endl; + << "GEOS homepage: https://libgeos.org" << endl; } int ----------------------------------------------------------------------- Summary of changes: NEWS.md | 1 + include/geos/math/DD.h | 2 ++ src/algorithm/CGAlgorithmsDD.cpp | 15 +++------- src/math/DD.cpp | 13 ++++++-- tests/unit/algorithm/MinimumAreaRectangleTest.cpp | 36 ++++++++++++----------- tests/unit/geos_unit.cpp | 2 +- 6 files changed, 38 insertions(+), 31 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Wed Dec 10 11:18:55 2025 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Dec 2025 11:18:55 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.13 updated. cd28a08b0554dd9156856458b2f3123bbb8ba41c Message-ID: <20251210191855.892C918AC5E@trac.osgeo.org> 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.13 has been updated via cd28a08b0554dd9156856458b2f3123bbb8ba41c (commit) via 89546095ea121ac948b46b2f2795e2d0fbf8bf82 (commit) from 28f2e42a6c40910fda9f08fddec28f43c148583b (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 cd28a08b0554dd9156856458b2f3123bbb8ba41c Author: Paul Ramsey Date: Wed Dec 10 11:18:02 2025 -0800 Update NEWS diff --git a/NEWS.md b/NEWS.md index 5bcee20e8..d413c6c81 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,7 @@ - Fix DepthSegment comparison logic (really this time) (GH-1266, Martin Davis) - Change CoverageGapFinder to return polygons (Martin Davis) - Fix incorrect envelope calculation for arcs (GH-1314, Dan Baston) + - Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection (GH-1235, Paul Ramsey) ## Changes in 3.13.1 2025-03-03 commit 89546095ea121ac948b46b2f2795e2d0fbf8bf82 Author: Paul Ramsey Date: Wed Dec 10 11:13:59 2025 -0800 Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection showing in downstream libraries, closes #1235 diff --git a/include/geos/math/DD.h b/include/geos/math/DD.h index 61e3a08a7..764801251 100644 --- a/include/geos/math/DD.h +++ b/include/geos/math/DD.h @@ -114,6 +114,7 @@ class GEOS_DLL DD { int signum() const; DD rint() const; + void setNaN(); public: DD(double p_hi, double p_lo) : hi(p_hi), lo(p_lo) {}; @@ -165,6 +166,7 @@ class GEOS_DLL DD { static DD pow(const DD &d, int exp); static DD trunc(const DD &d); + bool isInf() const; bool isNaN() const; bool isNegative() const; bool isPositive() const; diff --git a/src/algorithm/CGAlgorithmsDD.cpp b/src/algorithm/CGAlgorithmsDD.cpp index ccfef602e..1526d3754 100644 --- a/src/algorithm/CGAlgorithmsDD.cpp +++ b/src/algorithm/CGAlgorithmsDD.cpp @@ -139,19 +139,12 @@ CGAlgorithmsDD::intersection(const CoordinateXY& p1, const CoordinateXY& p2, DD y = (qx * pw) - (px * qw); DD w = (px * qy) - (qx * py); + if (w.isZero()) + return CoordinateXY::getNull(); + double xInt = (x / w).ToDouble(); double yInt = (y / w).ToDouble(); - - Coordinate rv; - - if (!std::isfinite(xInt) || !std::isfinite(yInt)) { - rv.setNull(); - return rv; - } - - rv.x = xInt; - rv.y = yInt; - return rv; + return {xInt, yInt}; } /* public static */ diff --git a/src/math/DD.cpp b/src/math/DD.cpp index c620c1b62..86d284a11 100644 --- a/src/math/DD.cpp +++ b/src/math/DD.cpp @@ -20,8 +20,16 @@ namespace geos { namespace math { // geos.util - - +/* private */ +void DD::setNaN() +{ + hi = std::numeric_limits::quiet_NaN(); +} +/* public */ +bool DD::isInf() const +{ + return std::isinf(hi); +} /* public */ bool DD::isNaN() const { @@ -346,6 +354,7 @@ DD DD::determinant(double x1, double y1, double x2, double y2) return determinant(DD(x1), DD(y1), DD(x2), DD(y2) ); } + /** * Computes the value of this number raised to an integral power. * Follows semantics of Java Math.pow as closely as possible. diff --git a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp index dad960837..506ecea7f 100644 --- a/tests/unit/algorithm/MinimumAreaRectangleTest.cpp +++ b/tests/unit/algorithm/MinimumAreaRectangleTest.cpp @@ -148,35 +148,37 @@ template<> template<> void object::test<10>() { - // bool error = false; - // try { - checkMinRectangle( - "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", - "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); + checkMinRectangle( + "LINESTRING(-99.48710639268086 34.79029839231914,-99.48370699999998 34.78689899963806,-99.48152167568102 34.784713675318976)", + "POLYGON ((-99.48710639268066 34.790298392318675, -99.48710639268066 34.790298392318675, -99.48152167568082 34.78471367531866, -99.48152167568082 34.78471367531866, -99.48710639268066 34.790298392318675))"); } + // testBadRectl template<> template<> void object::test<11>() { - // bool error = false; - // try { checkMinRectangle( "POLYGON ((-5.21175 49.944633, -5.77435 50.021367, -5.7997 50.0306, -5.81815 50.0513, -5.82625 50.073567, -5.83085 50.1173, -6.2741 56.758767, -5.93245 57.909, -5.1158 58.644533, -5.07915 58.661733, -3.42575 58.686633, -3.1392 58.6685, -3.12495 58.666233, -1.88745 57.6444, 1.68845 52.715133, 1.7057 52.6829, 1.70915 52.6522, 1.7034 52.585433, 1.3867 51.214033, 1.36595 51.190267, 1.30485 51.121967, 0.96365 50.928567, 0.93025 50.912433, 0.1925 50.7436, -5.21175 49.944633))", "POLYGON ((1.8583607388069103 50.41649058582797, -5.816631979932251 49.904263313964535, -6.395241388167441 58.57389735949991, 1.2797513305717105 59.08612463136336, 1.8583607388069103 50.41649058582797))"); - // } catch (std::exception& e) { - // error = true; - // // errorMessage = e.what(); - // } - // ensure("caught exception", error == true); } +// https://github.com/libgeos/geos/issues/1235 +// throwing FE_DIVBYZERO +template<> +template<> +void object::test<12>() +{ + checkMinRectangle( + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))", + "POLYGON ((-100 -100, -100 100, 100 100, 100 -100, -100 -100))"); +} + + + + + } // namespace tut diff --git a/tests/unit/geos_unit.cpp b/tests/unit/geos_unit.cpp index 8e008c8b2..a3a78236f 100644 --- a/tests/unit/geos_unit.cpp +++ b/tests/unit/geos_unit.cpp @@ -49,7 +49,7 @@ usage() << " " << module << " geos::geom::Envelope\n" << " " << module << " geos::geom::Envelope 2\n" << endl - << "GEOS homepage: http://geos.osgeo.org" << endl; + << "GEOS homepage: https://libgeos.org" << endl; } int ----------------------------------------------------------------------- Summary of changes: NEWS.md | 1 + include/geos/math/DD.h | 2 ++ src/algorithm/CGAlgorithmsDD.cpp | 15 +++------- src/math/DD.cpp | 13 ++++++-- tests/unit/algorithm/MinimumAreaRectangleTest.cpp | 36 ++++++++++++----------- tests/unit/geos_unit.cpp | 2 +- 6 files changed, 38 insertions(+), 31 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Wed Dec 10 15:05:06 2025 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Dec 2025 15:05:06 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. be7330861f6d0d7a029e80a135634c81afd705ef Message-ID: <20251210230507.1A98C18A874@trac.osgeo.org> 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 be7330861f6d0d7a029e80a135634c81afd705ef (commit) from f175f9af82fd0c4ab2d913205ff8480b7a12a055 (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 be7330861f6d0d7a029e80a135634c81afd705ef Author: Paul Ramsey Date: Wed Dec 10 15:04:43 2025 -0800 Add CI support for Clang 19 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a68e6351..729951169 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,15 +99,6 @@ jobs: # clang 10 and lower are not supported # in ubuntu 22.04 and higher - - cxx_compiler: clang++-11 - c_compiler: clang-11 - build_type: Debug - cxxstd: 14 - arch: 64 - packages: 'clang-11' - cmake: 3.15.* - os: ubuntu-22.04 - - cxx_compiler: clang++-12 c_compiler: clang-12 build_type: ASAN @@ -174,6 +165,15 @@ jobs: cmake: 3.30.* os: ubuntu-24.04 + - cxx_compiler: clang++-19 + c_compiler: clang-19 + build_type: Debug + cxxstd: 20 + arch: 64 + packages: 'clang-19' + cmake: 3.30.* + os: ubuntu-24.04 + runs-on: ${{ matrix.ci.os }} steps: ----------------------------------------------------------------------- Summary of changes: .github/workflows/ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Wed Dec 10 15:29:03 2025 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Dec 2025 15:29:03 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. de22f50d319ce72004d0228fef00a3964eeb6a6a Message-ID: <20251210232903.3BE1718B386@trac.osgeo.org> 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 de22f50d319ce72004d0228fef00a3964eeb6a6a (commit) from be7330861f6d0d7a029e80a135634c81afd705ef (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 de22f50d319ce72004d0228fef00a3964eeb6a6a Author: Paul Ramsey Date: Wed Dec 10 15:28:23 2025 -0800 Add UBSAN build option to CMakeLists diff --git a/CMakeLists.txt b/CMakeLists.txt index 852c724ab..d114245cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,9 +179,22 @@ set(CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -fsanitize=address -f set(CMAKE_EXE_LINKER_FLAGS_ASAN "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address") set(CMAKE_SHARED_LINKER_FLAGS_ASAN "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address") +#----------------------------------------------------------------------------- +# Add UBSAN build option +#----------------------------------------------------------------------------- + +set(CMAKE_C_FLAGS_UBSAN "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined") +set(CMAKE_CXX_FLAGS_UBSAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined") +set(CMAKE_EXE_LINKER_FLAGS_UBSAN "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=undefined") +set(CMAKE_SHARED_LINKER_FLAGS_UBSAN "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=undefined") + +#----------------------------------------------------------------------------- +# Add ASAN and UBSAN as explicit items in menu +#----------------------------------------------------------------------------- + get_property(_cmake_build_type_is_cache CACHE CMAKE_BUILD_TYPE PROPERTY TYPE) if (_cmake_build_type_is_cache) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" "ASAN") + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" "ASAN" "UBSAN") endif() unset(_cmake_build_type_is_cache) ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Thu Dec 11 12:04:58 2025 From: git at osgeo.org (git at osgeo.org) Date: Thu, 11 Dec 2025 12:04:58 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. f112e8421cf3a1e9b6a62e032b03e4fa8e2733b8 Message-ID: <20251211200459.08C6E18F626@trac.osgeo.org> 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 f112e8421cf3a1e9b6a62e032b03e4fa8e2733b8 (commit) via 0ef7d3123bf0752b6f560886b3b25543e084f4a0 (commit) via 5b0e56a456ca38b7448ddc653e6a712b37e6146d (commit) via fbb3d5ce2544f3b76f9dd904ebbf06e0c99e5599 (commit) from de22f50d319ce72004d0228fef00a3964eeb6a6a (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 f112e8421cf3a1e9b6a62e032b03e4fa8e2733b8 Author: Daniel Baston Date: Thu Dec 11 09:36:04 2025 -0500 OffsetCurveTest: Fix invalid join style diff --git a/tests/unit/operation/buffer/OffsetCurveTest.cpp b/tests/unit/operation/buffer/OffsetCurveTest.cpp index 0e817439f..e6ad8b183 100644 --- a/tests/unit/operation/buffer/OffsetCurveTest.cpp +++ b/tests/unit/operation/buffer/OffsetCurveTest.cpp @@ -523,7 +523,7 @@ void object::test<38> () { checkOffsetCurve( "LINESTRING (20 20, 50 50, 80 20)", - 10, 2, -1, -1, + 10, 2, BufferParameters::JOIN_ROUND, -1, "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)" ); } commit 0ef7d3123bf0752b6f560886b3b25543e084f4a0 Author: Daniel Baston Date: Thu Dec 11 09:29:25 2025 -0500 LineDissolver: Avoid null-pointer dereference diff --git a/src/dissolve/LineDissolver.cpp b/src/dissolve/LineDissolver.cpp index 2c036cc0d..674c132d5 100644 --- a/src/dissolve/LineDissolver.cpp +++ b/src/dissolve/LineDissolver.cpp @@ -50,6 +50,10 @@ LineDissolver::dissolve(const Geometry* g) void LineDissolver::add(const Geometry* geom) { + if (factory == nullptr) { + factory = geom->getFactory(); + } + struct LineStringFilter : public GeometryComponentFilter { LineDissolver *m_ld; @@ -83,9 +87,6 @@ LineDissolver::add(std::vector geometries) void LineDissolver::add(const LineString* lineString) { - if (factory == nullptr) { - factory = lineString->getFactory(); - } const CoordinateSequence* seq = lineString->getCoordinatesRO(); bool doneStart = false; for (std::size_t i = 1; i < seq->size(); i++) { @@ -129,6 +130,7 @@ LineDissolver::computeResult() if (MarkHalfEdge::isMarked(e)) continue; process(e); } + result = factory->buildGeometry(std::move(lines)); } commit 5b0e56a456ca38b7448ddc653e6a712b37e6146d Author: Daniel Baston Date: Thu Dec 11 09:15:05 2025 -0500 OffsetCurve: Add guard for curved inputs diff --git a/src/operation/buffer/OffsetCurve.cpp b/src/operation/buffer/OffsetCurve.cpp index 09fc7d074..02ee1f94f 100644 --- a/src/operation/buffer/OffsetCurve.cpp +++ b/src/operation/buffer/OffsetCurve.cpp @@ -62,6 +62,8 @@ OffsetCurve::setJoined(bool pIsJoined) std::unique_ptr OffsetCurve::getCurve() { + util::ensureNoCurvedComponents(inputGeom); + GeometryMapper::mapOp GetCurveMapOp = [this](const Geometry& geom)->std::unique_ptr { if (geom.getGeometryTypeId() == GEOS_POINT) return nullptr; commit fbb3d5ce2544f3b76f9dd904ebbf06e0c99e5599 Author: Daniel Baston Date: Thu Dec 11 09:13:45 2025 -0500 WKTWriter: Fix casts to incorrect type diff --git a/src/io/WKTWriter.cpp b/src/io/WKTWriter.cpp index 7c8f04bdc..8293b31b5 100644 --- a/src/io/WKTWriter.cpp +++ b/src/io/WKTWriter.cpp @@ -241,12 +241,12 @@ WKTWriter::appendGeometryTaggedText(const Geometry& geometry, case GEOS_CIRCULARSTRING: appendSimpleCurveTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_COMPOUNDCURVE: appendCompoundCurveTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_CURVEPOLYGON: - case GEOS_POLYGON: appendSurfaceTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; + case GEOS_POLYGON: appendSurfaceTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_MULTIPOINT: appendMultiPointTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_MULTICURVE: - case GEOS_MULTILINESTRING: appendMultiCurveTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; + case GEOS_MULTILINESTRING: appendMultiCurveTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_MULTISURFACE: - case GEOS_MULTIPOLYGON: appendMultiSurfaceTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; + case GEOS_MULTIPOLYGON: appendMultiSurfaceTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; case GEOS_GEOMETRYCOLLECTION: appendGeometryCollectionTaggedText(static_cast(geometry), outputOrdinates, level, writer); break; } } ----------------------------------------------------------------------- Summary of changes: src/dissolve/LineDissolver.cpp | 8 +++++--- src/io/WKTWriter.cpp | 6 +++--- src/operation/buffer/OffsetCurve.cpp | 2 ++ tests/unit/operation/buffer/OffsetCurveTest.cpp | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Sat Dec 13 01:15:44 2025 From: git at osgeo.org (git at osgeo.org) Date: Sat, 13 Dec 2025 01:15:44 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. e8c6acca2cd023ea699eaa9237695f860e2ee72a Message-ID: <20251213091544.B202757AA@trac.osgeo.org> 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 e8c6acca2cd023ea699eaa9237695f860e2ee72a (commit) from f112e8421cf3a1e9b6a62e032b03e4fa8e2733b8 (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 e8c6acca2cd023ea699eaa9237695f860e2ee72a Author: Bas Couwenberg Date: Sat Dec 13 10:15:19 2025 +0100 Fix test_docs failure with doxygen 1.15.0. (#1341) diff --git a/include/geos/linearref/LengthIndexedLine.h b/include/geos/linearref/LengthIndexedLine.h index d5c823768..42af91e58 100644 --- a/include/geos/linearref/LengthIndexedLine.h +++ b/include/geos/linearref/LengthIndexedLine.h @@ -138,7 +138,7 @@ public: * slightly off the line and is equidistant from two different * points on the line. * - * The supplied point does not `*necessarily* have to lie precisely + * The supplied point does not *necessarily* have to lie precisely * on the line, but if it is far from the line the accuracy and * performance of this function is not guaranteed. * Use {@link #project} to compute a guaranteed result for points ----------------------------------------------------------------------- Summary of changes: include/geos/linearref/LengthIndexedLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Sat Dec 13 01:16:48 2025 From: git at osgeo.org (git at osgeo.org) Date: Sat, 13 Dec 2025 01:16:48 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.14 updated. d7d33e311a0f1383011ed127b54baa1c3befbb68 Message-ID: <20251213091649.2549257AC@trac.osgeo.org> 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.14 has been updated via d7d33e311a0f1383011ed127b54baa1c3befbb68 (commit) from a3d7aa413d0975c54491e31e91b9f92a35425fb1 (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 d7d33e311a0f1383011ed127b54baa1c3befbb68 Author: Bas Couwenberg Date: Sat Dec 13 10:15:19 2025 +0100 Fix test_docs failure with doxygen 1.15.0. (#1341) diff --git a/include/geos/linearref/LengthIndexedLine.h b/include/geos/linearref/LengthIndexedLine.h index d5c823768..42af91e58 100644 --- a/include/geos/linearref/LengthIndexedLine.h +++ b/include/geos/linearref/LengthIndexedLine.h @@ -138,7 +138,7 @@ public: * slightly off the line and is equidistant from two different * points on the line. * - * The supplied point does not `*necessarily* have to lie precisely + * The supplied point does not *necessarily* have to lie precisely * on the line, but if it is far from the line the accuracy and * performance of this function is not guaranteed. * Use {@link #project} to compute a guaranteed result for points ----------------------------------------------------------------------- Summary of changes: include/geos/linearref/LengthIndexedLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Sat Dec 13 01:17:55 2025 From: git at osgeo.org (git at osgeo.org) Date: Sat, 13 Dec 2025 01:17:55 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.13 updated. b41f45a16b5a0d6faee72a5eed3e739cbc727eba Message-ID: <20251213091755.607E94155@trac.osgeo.org> 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.13 has been updated via b41f45a16b5a0d6faee72a5eed3e739cbc727eba (commit) from cd28a08b0554dd9156856458b2f3123bbb8ba41c (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 b41f45a16b5a0d6faee72a5eed3e739cbc727eba Author: Bas Couwenberg Date: Sat Dec 13 10:15:19 2025 +0100 Fix test_docs failure with doxygen 1.15.0. (#1341) diff --git a/include/geos/linearref/LengthIndexedLine.h b/include/geos/linearref/LengthIndexedLine.h index d5c823768..42af91e58 100644 --- a/include/geos/linearref/LengthIndexedLine.h +++ b/include/geos/linearref/LengthIndexedLine.h @@ -138,7 +138,7 @@ public: * slightly off the line and is equidistant from two different * points on the line. * - * The supplied point does not `*necessarily* have to lie precisely + * The supplied point does not *necessarily* have to lie precisely * on the line, but if it is far from the line the accuracy and * performance of this function is not guaranteed. * Use {@link #project} to compute a guaranteed result for points ----------------------------------------------------------------------- Summary of changes: include/geos/linearref/LengthIndexedLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Sat Dec 13 01:18:40 2025 From: git at osgeo.org (git at osgeo.org) Date: Sat, 13 Dec 2025 01:18:40 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.12 updated. 168d863da9ad23ca084372651d090afb242f8934 Message-ID: <20251213091841.23FCC5416@trac.osgeo.org> 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.12 has been updated via 168d863da9ad23ca084372651d090afb242f8934 (commit) from 3d1d86b43f25c60400e491de64d7579b534747a3 (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 168d863da9ad23ca084372651d090afb242f8934 Author: Bas Couwenberg Date: Sat Dec 13 10:15:19 2025 +0100 Fix test_docs failure with doxygen 1.15.0. (#1341) diff --git a/include/geos/linearref/LengthIndexedLine.h b/include/geos/linearref/LengthIndexedLine.h index 462957153..0d0f88e3f 100644 --- a/include/geos/linearref/LengthIndexedLine.h +++ b/include/geos/linearref/LengthIndexedLine.h @@ -138,7 +138,7 @@ public: * slightly off the line and is equidistant from two different * points on the line. * - * The supplied point does not `*necessarily* have to lie precisely + * The supplied point does not *necessarily* have to lie precisely * on the line, but if it is far from the line the accuracy and * performance of this function is not guaranteed. * Use {@link #project} to compute a guaranteed result for points ----------------------------------------------------------------------- Summary of changes: include/geos/linearref/LengthIndexedLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Sat Dec 13 01:19:36 2025 From: git at osgeo.org (git at osgeo.org) Date: Sat, 13 Dec 2025 01:19:36 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.11 updated. 6efb5efe2f0f30b0834329aeb3283a81943436c2 Message-ID: <20251213091936.9C6614156@trac.osgeo.org> 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 6efb5efe2f0f30b0834329aeb3283a81943436c2 (commit) from 55b8bec12195e72b477e81a494e0f6e2314b31e1 (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 6efb5efe2f0f30b0834329aeb3283a81943436c2 Author: Bas Couwenberg Date: Sat Dec 13 10:15:19 2025 +0100 Fix test_docs failure with doxygen 1.15.0. (#1341) diff --git a/include/geos/linearref/LengthIndexedLine.h b/include/geos/linearref/LengthIndexedLine.h index 462957153..0d0f88e3f 100644 --- a/include/geos/linearref/LengthIndexedLine.h +++ b/include/geos/linearref/LengthIndexedLine.h @@ -138,7 +138,7 @@ public: * slightly off the line and is equidistant from two different * points on the line. * - * The supplied point does not `*necessarily* have to lie precisely + * The supplied point does not *necessarily* have to lie precisely * on the line, but if it is far from the line the accuracy and * performance of this function is not guaranteed. * Use {@link #project} to compute a guaranteed result for points ----------------------------------------------------------------------- Summary of changes: include/geos/linearref/LengthIndexedLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 06:47:06 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 06:47:06 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 88a987895022ff77fedad776d7835e5743208abb Message-ID: <20251216144707.BA4011A5C2A@trac.osgeo.org> 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 88a987895022ff77fedad776d7835e5743208abb (commit) from e8c6acca2cd023ea699eaa9237695f860e2ee72a (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 88a987895022ff77fedad776d7835e5743208abb Author: Daniel Baston Date: Tue Dec 16 09:46:35 2025 -0500 SimpleCurve / SegmentString: Store coordinates as std::shared_ptr (#1329) diff --git a/include/geos/coverage/CoverageCleaner.h b/include/geos/coverage/CoverageCleaner.h index 79b0ed855..233302045 100644 --- a/include/geos/coverage/CoverageCleaner.h +++ b/include/geos/coverage/CoverageCleaner.h @@ -323,7 +323,7 @@ public: */ std::vector getMergedGaps(); - std::unique_ptr toGeometry( + static std::unique_ptr toGeometry( std::vector>& segStrings, const GeometryFactory* geomFact); diff --git a/include/geos/coverage/CoverageEdge.h b/include/geos/coverage/CoverageEdge.h index 60afd1c7c..69d8f1fc4 100644 --- a/include/geos/coverage/CoverageEdge.h +++ b/include/geos/coverage/CoverageEdge.h @@ -56,7 +56,7 @@ class GEOS_DLL CoverageEdge { private: // Members - std::unique_ptr m_pts; + std::shared_ptr m_pts; std::size_t m_ringCount ; bool m_isFreeRing = true; @@ -119,7 +119,7 @@ public: const GeometryFactory* geomFactory); std::unique_ptr toLineString( - const GeometryFactory* geomFactory); + const GeometryFactory* geomFactory) const; /* public */ void incRingCount() @@ -144,14 +144,14 @@ public: return m_isFreeRing; } - void setCoordinates(const CoordinateSequence* pts) + void setCoordinates(const std::shared_ptr& pts) { - m_pts = pts->clone(); + m_pts = pts; } - const CoordinateSequence* getCoordinates() const + const std::shared_ptr& getCoordinates() const { - return m_pts.get(); + return m_pts; } const Coordinate& getEndCoordinate() const diff --git a/include/geos/coverage/CoveragePolygonValidator.h b/include/geos/coverage/CoveragePolygonValidator.h index 8c49bcc01..8751be7ed 100644 --- a/include/geos/coverage/CoveragePolygonValidator.h +++ b/include/geos/coverage/CoveragePolygonValidator.h @@ -204,7 +204,6 @@ private: double gapWidth = 0.0; std::vector> m_adjCovPolygons; std::deque coverageRingStore; - std::vector> localCoordinateSequences; std::deque coverageRingSegmentStore; typedef std::unordered_map CoverageRingSegmentMap; diff --git a/include/geos/coverage/CoverageRing.h b/include/geos/coverage/CoverageRing.h index f9a78f730..d74a256b6 100644 --- a/include/geos/coverage/CoverageRing.h +++ b/include/geos/coverage/CoverageRing.h @@ -78,7 +78,7 @@ private: public: - CoverageRing(CoordinateSequence* pts, bool interiorOnRight); + CoverageRing(const std::shared_ptr& pts, bool interiorOnRight); CoverageRing(const LinearRing* ring, bool isShell); diff --git a/include/geos/geom/CircularString.h b/include/geos/geom/CircularString.h index 85dc3014e..6a6d5f8c3 100644 --- a/include/geos/geom/CircularString.h +++ b/include/geos/geom/CircularString.h @@ -58,6 +58,9 @@ protected: CircularString(std::unique_ptr&& pts, const GeometryFactory& newFactory); + CircularString(const std::shared_ptr& pts, + const GeometryFactory& newFactory); + CircularString* cloneImpl() const override { return new CircularString(*this); diff --git a/include/geos/geom/GeometryFactory.h b/include/geos/geom/GeometryFactory.h index 125217770..4dfe6b593 100644 --- a/include/geos/geom/GeometryFactory.h +++ b/include/geos/geom/GeometryFactory.h @@ -236,6 +236,9 @@ public: std::unique_ptr createLinearRing( std::unique_ptr && newCoords) const; + std::unique_ptr createLinearRing( + const std::shared_ptr& newCoords) const; + /// Construct a LinearRing with a deep-copy of given arguments std::unique_ptr createLinearRing( const CoordinateSequence& coordinates) const; @@ -312,6 +315,10 @@ public: std::unique_ptr createLineString( const CoordinateSequence& coordinates) const; + /// Construct a LineString with a reference to shared coordinates + std::unique_ptr createLineString( + const std::shared_ptr&) const; + /// Construct an EMPTY CircularString std::unique_ptr createCircularString(bool hasZ, bool hasM) const; @@ -322,6 +329,10 @@ public: std::unique_ptr createCircularString( std::unique_ptr && coordinates) const; + /// Construct a CircularStrign with a reference to shared coordinates + std::unique_ptr createCircularString( + const std::shared_ptr& coordinates) const; + /// Construct a CircularString with a deep-copy of given argument std::unique_ptr createCircularString( const CoordinateSequence& coordinates) const; diff --git a/include/geos/geom/LineString.h b/include/geos/geom/LineString.h index 478970874..8d59cda5a 100644 --- a/include/geos/geom/LineString.h +++ b/include/geos/geom/LineString.h @@ -114,6 +114,9 @@ protected: LineString(CoordinateSequence::Ptr && pts, const GeometryFactory& newFactory); + LineString(const std::shared_ptr & pts, + const GeometryFactory& newFactory); + LineString* cloneImpl() const override { return new LineString(*this); } LineString* reverseImpl() const override; diff --git a/include/geos/geom/LinearRing.h b/include/geos/geom/LinearRing.h index b04b3bd35..545bcb655 100644 --- a/include/geos/geom/LinearRing.h +++ b/include/geos/geom/LinearRing.h @@ -78,6 +78,9 @@ public: LinearRing(CoordinateSequence::Ptr && points, const GeometryFactory& newFactory); + LinearRing(const std::shared_ptr& points, + const GeometryFactory& newFactory); + std::unique_ptr clone() const { return std::unique_ptr(cloneImpl()); diff --git a/include/geos/geom/SimpleCurve.h b/include/geos/geom/SimpleCurve.h index 1bf674f69..acfc8fc7e 100644 --- a/include/geos/geom/SimpleCurve.h +++ b/include/geos/geom/SimpleCurve.h @@ -61,6 +61,9 @@ public: /// Returns a read-only pointer to internal CoordinateSequence const CoordinateSequence* getCoordinatesRO() const; + /// Returns a read-only pointer to internal CoordinateSequence + const std::shared_ptr& getSharedCoordinates() const; + const SimpleCurve* getCurveN(std::size_t) const override; /// \brief @@ -107,19 +110,14 @@ public: */ void normalize() override; - /** - * \brief - * Take ownership of the CoordinateSequence managed by this geometry. - * After releasing the coordinates, the geometry should be considered - * in a moved-from state and should not be accessed. - * @return this Geometry's CoordinateSequence. - */ - std::unique_ptr releaseCoordinates(); - protected: SimpleCurve(const SimpleCurve& other); + SimpleCurve(const std::shared_ptr& newCoords, + bool isLinear, + const GeometryFactory& factory); + SimpleCurve(std::unique_ptr&& newCoords, bool isLinear, const GeometryFactory& factory); @@ -128,8 +126,7 @@ protected: Envelope computeEnvelopeInternal(bool isLinear) const; - // TODO: hold value or shared_ptr instead of unique_ptr? - std::unique_ptr points; + std::shared_ptr points; mutable Envelope envelope; diff --git a/include/geos/geomgraph/EdgeNodingValidator.h b/include/geos/geomgraph/EdgeNodingValidator.h index 84a506b01..e80b95e9d 100644 --- a/include/geos/geomgraph/EdgeNodingValidator.h +++ b/include/geos/geomgraph/EdgeNodingValidator.h @@ -62,12 +62,6 @@ private: // in turn expects this member to be initialized std::vector> segStr; - // Make sure this member is initialized *before* - // the NodingValidator, as initialization of - // NodingValidator will use toSegmentString(), that - // in turn expects this member to be initialized - std::vector newCoordSeq; - noding::FastNodingValidator nv; public: @@ -91,7 +85,6 @@ public: EdgeNodingValidator(std::vector& edges) : segStr(), - newCoordSeq(), nv(toSegmentStrings(edges)) {} diff --git a/include/geos/noding/BasicSegmentString.h b/include/geos/noding/BasicSegmentString.h index 1d253d637..079b02af2 100644 --- a/include/geos/noding/BasicSegmentString.h +++ b/include/geos/noding/BasicSegmentString.h @@ -50,7 +50,7 @@ public: /// @param newPts CoordinateSequence representing the string, externally owned /// @param newContext the context associated to this SegmentString /// - BasicSegmentString(geom::CoordinateSequence* newPts, + BasicSegmentString(const std::shared_ptr& newPts, const void* newContext) : SegmentString(newContext, newPts) diff --git a/include/geos/noding/NodableSegmentString.h b/include/geos/noding/NodableSegmentString.h index 8b4e0e1ff..7b3440d95 100644 --- a/include/geos/noding/NodableSegmentString.h +++ b/include/geos/noding/NodableSegmentString.h @@ -37,7 +37,7 @@ class GEOS_DLL NodableSegmentString : public SegmentString { private: protected: public: - NodableSegmentString(const void* newContext, geom::CoordinateSequence* newSeq) + NodableSegmentString(const void* newContext, std::shared_ptr newSeq) : SegmentString(newContext, newSeq) { } diff --git a/include/geos/noding/NodedSegmentString.h b/include/geos/noding/NodedSegmentString.h index 632ac9493..c63abf708 100644 --- a/include/geos/noding/NodedSegmentString.h +++ b/include/geos/noding/NodedSegmentString.h @@ -102,26 +102,23 @@ public: * @param newContext the user-defined data of this segment string * (may be null) */ - NodedSegmentString(geom::CoordinateSequence* newPts, bool constructZ, bool constructM, const void* newContext) + NodedSegmentString(const std::shared_ptr& newPts, bool constructZ, bool constructM, const void* newContext) : NodableSegmentString(newContext, newPts) , nodeList(*this, constructZ, constructM) {} NodedSegmentString(SegmentString* ss, bool constructZ, bool constructM) - : NodableSegmentString(ss->getData(), ss->getCoordinates()->clone().release()) + : NodableSegmentString(ss->getData(), ss->getCoordinates()) , nodeList(*this, constructZ, constructM) {} ~NodedSegmentString() override { - delete seq; } SegmentNodeList& getNodeList(); const SegmentNodeList& getNodeList() const; - std::unique_ptr releaseCoordinates(); - std::ostream& print(std::ostream& os) const override; /** \brief diff --git a/include/geos/noding/SegmentNodeList.h b/include/geos/noding/SegmentNodeList.h index 6791e9704..3abaf4a51 100644 --- a/include/geos/noding/SegmentNodeList.h +++ b/include/geos/noding/SegmentNodeList.h @@ -97,7 +97,7 @@ private: * @param ei1 the end node of the split edge * @return the points for the split edge */ - std::unique_ptr createSplitEdgePts(const SegmentNode* ei0, const SegmentNode* ei1) const; + std::shared_ptr createSplitEdgePts(const SegmentNode *ei0, const SegmentNode *ei1) const; /** * Adds nodes for any collapsed edge pairs. diff --git a/include/geos/noding/SegmentString.h b/include/geos/noding/SegmentString.h index 8e08b853b..5b76d8c89 100644 --- a/include/geos/noding/SegmentString.h +++ b/include/geos/noding/SegmentString.h @@ -57,7 +57,7 @@ public: /// @param newContext the context associated to this SegmentString /// @param newSeq coordinates of this SegmentString /// - SegmentString(const void* newContext, geom::CoordinateSequence* newSeq) + SegmentString(const void* newContext, const std::shared_ptr& newSeq) : seq(newSeq), context(newContext) @@ -100,15 +100,12 @@ public: /// \brief /// Return a pointer to the CoordinateSequence associated /// with this SegmentString. - /// - /// @note The CoordinateSequence is owned by this SegmentString! - /// - const geom::CoordinateSequence* getCoordinates() const { + const std::shared_ptr& getCoordinates() const { return seq; } - geom::CoordinateSequence* getCoordinates() { - return seq; + void setCoordinates(const std::shared_ptr& newSeq) { + seq = newSeq; } /** \brief @@ -176,7 +173,7 @@ public: virtual std::ostream& print(std::ostream& os) const; protected: - geom::CoordinateSequence* seq; + std::shared_ptr seq; private: const void* context; diff --git a/include/geos/noding/SegmentStringUtil.h b/include/geos/noding/SegmentStringUtil.h index b780a8f57..f489f6599 100644 --- a/include/geos/noding/SegmentStringUtil.h +++ b/include/geos/noding/SegmentStringUtil.h @@ -55,8 +55,8 @@ public: geom::util::LinearComponentExtracter::getLines(*g, lines); for(const geom::LineString* line : lines) { - auto pts = line->getCoordinatesRO(); - segStr.push_back(new BasicSegmentString(const_cast(pts), g)); + const auto& pts = line->getSharedCoordinates(); + segStr.push_back(new BasicSegmentString(pts, g)); } } diff --git a/include/geos/noding/snap/SnappingNoder.h b/include/geos/noding/snap/SnappingNoder.h index a143419c5..c872fbcc4 100644 --- a/include/geos/noding/snap/SnappingNoder.h +++ b/include/geos/noding/snap/SnappingNoder.h @@ -82,7 +82,7 @@ private: std::unique_ptr snapVertices(const SegmentString* ss); - std::unique_ptr snap(const geom::CoordinateSequence* cs); + std::shared_ptr snap(const geom::CoordinateSequence *cs); /** * Computes all interior intersections in the collection of {@link SegmentString}s, diff --git a/include/geos/operation/buffer/BufferCurveSetBuilder.h b/include/geos/operation/buffer/BufferCurveSetBuilder.h index 789b8c935..20be31912 100644 --- a/include/geos/operation/buffer/BufferCurveSetBuilder.h +++ b/include/geos/operation/buffer/BufferCurveSetBuilder.h @@ -104,7 +104,7 @@ private: * * @param coord is raw offset curve, ownership transferred here */ - void addCurve(geom::CoordinateSequence* coord, geom::Location leftLoc, + void addCurve(std::unique_ptr coord, geom::Location leftLoc, geom::Location rightLoc); void add(const geom::Geometry& g); @@ -279,7 +279,7 @@ public: /// @param leftLoc left location /// @param rightLoc right location /// - void addCurves(const std::vector& lineList, + void addCurves(std::vector>& lineList, geom::Location leftLoc, geom::Location rightLoc); /** diff --git a/include/geos/operation/buffer/OffsetCurveBuilder.h b/include/geos/operation/buffer/OffsetCurveBuilder.h index 1f6cddf74..0990305f0 100644 --- a/include/geos/operation/buffer/OffsetCurveBuilder.h +++ b/include/geos/operation/buffer/OffsetCurveBuilder.h @@ -117,11 +117,10 @@ public: * @param distance offset distance * @param lineList the std::vector to which the newly created * CoordinateSequences will be pushed_back. - * Caller is responsible to delete these new elements. */ void getLineCurve(const CoordinateSequence* inputPts, double distance, - std::vector& lineList); + std::vector>& lineList); /** * This method handles single points as well as LineStrings. @@ -156,7 +155,7 @@ public: * @note This is a GEOS extension. */ void getSingleSidedLineCurve(const CoordinateSequence* inputPts, - double distance, std::vector& lineList, + double distance, std::vector>& lineList, bool leftSide, bool rightSide) ; /** \brief @@ -171,7 +170,7 @@ public: */ void getRingCurve(const CoordinateSequence* inputPts, int side, double distance, - std::vector& lineList); + std::vector>& lineList); /** * This method handles the degenerate cases of single points and lines, @@ -189,7 +188,7 @@ public: void getOffsetCurve(const CoordinateSequence* inputPts, double p_distance, - std::vector& lineList); + std::vector>& lineList); std::unique_ptr getOffsetCurve( const CoordinateSequence* inputPts, diff --git a/include/geos/operation/buffer/OffsetSegmentGenerator.h b/include/geos/operation/buffer/OffsetSegmentGenerator.h index 2f3a369c6..5408f8787 100644 --- a/include/geos/operation/buffer/OffsetSegmentGenerator.h +++ b/include/geos/operation/buffer/OffsetSegmentGenerator.h @@ -101,9 +101,9 @@ public: /// FIXME: refactor memory management of this /// void - getCoordinates(std::vector& to) + getCoordinates(std::vector>& to) { - to.push_back(segList.getCoordinates()); + to.emplace_back(segList.getCoordinates()); } std::unique_ptr diff --git a/include/geos/operation/overlayng/Edge.h b/include/geos/operation/overlayng/Edge.h index b0f670b7b..4ed90968c 100644 --- a/include/geos/operation/overlayng/Edge.h +++ b/include/geos/operation/overlayng/Edge.h @@ -64,7 +64,7 @@ private: int bDim = OverlayLabel::DIM_UNKNOWN; int bDepthDelta = 0; bool bIsHole = false; - std::unique_ptr pts; + std::shared_ptr pts; // Methods @@ -198,8 +198,7 @@ public: static bool isCollapsed(const geom::CoordinateSequence* pts); - // takes ownership of pts from caller - Edge(std::unique_ptr&& p_pts, const EdgeSourceInfo* info); + Edge(const std::shared_ptr& p_pts, const EdgeSourceInfo* info); // return a clone of the underlying points std::unique_ptr getCoordinates() @@ -214,10 +213,10 @@ public: }; // release the underlying points to the caller - geom::CoordinateSequence* releaseCoordinates() + std::shared_ptr releaseCoordinates() { - geom::CoordinateSequence* cs = pts.release(); - pts.reset(nullptr); + auto cs = pts; + pts.reset(); return cs; }; diff --git a/include/geos/operation/overlayng/OverlayEdge.h b/include/geos/operation/overlayng/OverlayEdge.h index 42d3632cd..031e743a2 100644 --- a/include/geos/operation/overlayng/OverlayEdge.h +++ b/include/geos/operation/overlayng/OverlayEdge.h @@ -53,7 +53,7 @@ class GEOS_DLL OverlayEdge : public edgegraph::HalfEdge { private: // Members - const CoordinateSequence* pts; + std::shared_ptr pts; /** * 'true' indicates direction is forward along segString * 'false' is reverse direction @@ -80,7 +80,7 @@ public: OverlayEdge(const CoordinateXYZM& p_orig, const CoordinateXYZM& p_dirPt, bool p_direction, OverlayLabel* p_label, - const CoordinateSequence* p_pts) + const std::shared_ptr& p_pts) : HalfEdge(p_orig) , pts(p_pts) , direction(p_direction) @@ -124,16 +124,10 @@ public: const CoordinateSequence* getCoordinatesRO() const { - return pts; + return pts.get(); }; - std::unique_ptr getCoordinates() - { - // return a copy of pts - return pts->clone(); - }; - - std::unique_ptr getCoordinatesOriented(); + std::shared_ptr getCoordinatesOriented() const; /** * Adds the coordinates of this edge to the given list, diff --git a/include/geos/operation/overlayng/OverlayGraph.h b/include/geos/operation/overlayng/OverlayGraph.h index e44c46b2e..39dcbd15b 100644 --- a/include/geos/operation/overlayng/OverlayGraph.h +++ b/include/geos/operation/overlayng/OverlayGraph.h @@ -63,21 +63,19 @@ private: std::deque ovEdgeQue; std::deque ovLabelQue; - std::vector> csQue; - // Methods /** * Create and add HalfEdge pairs to map and vector containers, * using local std::deque storage for objects. */ - OverlayEdge* createEdgePair(const CoordinateSequence* pts, OverlayLabel* lbl); + OverlayEdge* createEdgePair(const std::shared_ptr &pts, OverlayLabel *lbl); /** * Create a single OverlayEdge in local std::deque storage, and return the * pointer. */ - OverlayEdge* createOverlayEdge(const CoordinateSequence* pts, OverlayLabel* lbl, bool direction); + OverlayEdge* createOverlayEdge(const std::shared_ptr &pts, OverlayLabel *lbl, bool direction); void insert(OverlayEdge* e); diff --git a/include/geos/operation/relateng/RelateGeometry.h b/include/geos/operation/relateng/RelateGeometry.h index d1282d52f..89d396909 100644 --- a/include/geos/operation/relateng/RelateGeometry.h +++ b/include/geos/operation/relateng/RelateGeometry.h @@ -87,7 +87,6 @@ private: */ std::vector> segStringTempStore; std::vector> segStringPermStore; - std::vector> csStore; // Methods @@ -133,11 +132,11 @@ private: std::vector& segStrings, std::vector>& segStore); - const CoordinateSequence* orientAndRemoveRepeated( - const CoordinateSequence* cs, bool orientCW); + static std::shared_ptr orientAndRemoveRepeated( + const std::shared_ptr& cs, bool orientCW); - const CoordinateSequence* removeRepeated( - const CoordinateSequence* cs); + static std::shared_ptr removeRepeated( + const std::shared_ptr& cs); public: diff --git a/include/geos/operation/relateng/RelateSegmentString.h b/include/geos/operation/relateng/RelateSegmentString.h index dcd486a76..c059092ec 100644 --- a/include/geos/operation/relateng/RelateSegmentString.h +++ b/include/geos/operation/relateng/RelateSegmentString.h @@ -62,14 +62,14 @@ private: // Constructor RelateSegmentString( - const CoordinateSequence* pts, + std::shared_ptr pts, bool isA, int dimension, int id, int ringId, const Geometry* poly, const RelateGeometry* inputGeom) - : BasicSegmentString(const_cast(pts), nullptr) + : BasicSegmentString(pts, nullptr) , m_isA(isA) , m_dimension(dimension) , m_id(id) @@ -82,7 +82,7 @@ private: // Methods static const RelateSegmentString* createSegmentString( - const CoordinateSequence* pts, + const std::shared_ptr& pts, bool isA, int dim, int elementId, int ringId, const Geometry* poly, const RelateGeometry* parent); @@ -111,14 +111,14 @@ private: public: static const RelateSegmentString* createLine( - const CoordinateSequence* pts, + const std::shared_ptr &pts, bool isA, int elementId, - const RelateGeometry* parent); + const RelateGeometry *parent); static const RelateSegmentString* createRing( - const CoordinateSequence* pts, + const std::shared_ptr &pts, bool isA, int elementId, int ringId, - const Geometry* poly, const RelateGeometry* parent); + const Geometry *poly, const RelateGeometry *parent); inline bool isA() const { return m_isA; @@ -132,7 +132,7 @@ public: return m_parentPolygonal; } - NodeSection* createNodeSection(std::size_t segIndex, const CoordinateXY intPt) const; + NodeSection* createNodeSection(std::size_t segIndex, const CoordinateXY &intPt) const; /** * Tests if a segment intersection point has that segment as its diff --git a/include/geos/operation/valid/IsSimpleOp.h b/include/geos/operation/valid/IsSimpleOp.h index 1f2abfa68..23a178591 100644 --- a/include/geos/operation/valid/IsSimpleOp.h +++ b/include/geos/operation/valid/IsSimpleOp.h @@ -129,11 +129,11 @@ private: bool isSimpleLinearGeometry(const geom::Geometry& geom); - static std::vector> + static std::vector> removeRepeatedPts(const geom::Geometry& geom); static std::vector> - createSegmentStrings(std::vector>& seqs); + createSegmentStrings(std::vector>& seqs); class NonSimpleIntersectionFinder : public noding::SegmentIntersector { diff --git a/include/geos/operation/valid/PolygonTopologyAnalyzer.h b/include/geos/operation/valid/PolygonTopologyAnalyzer.h index 8d7238112..91beba6bb 100644 --- a/include/geos/operation/valid/PolygonTopologyAnalyzer.h +++ b/include/geos/operation/valid/PolygonTopologyAnalyzer.h @@ -55,11 +55,6 @@ private: // can pass around pointers with abandon std::deque polyRingStore; std::deque segStringStore; - // when building SegmentStrings we sometimes want - // to use deduped CoordinateSequences so we will - // keep the deduped ones here so they get cleaned - // up when processing is complete - std::vector> coordSeqStore; PolygonRing* createPolygonRing(const LinearRing* p_ring); PolygonRing* createPolygonRing(const LinearRing* p_ring, int p_index, PolygonRing* p_shell); diff --git a/include/geos/triangulate/polygon/PolygonHoleJoiner.h b/include/geos/triangulate/polygon/PolygonHoleJoiner.h index 870282f7d..2ed2ec50c 100644 --- a/include/geos/triangulate/polygon/PolygonHoleJoiner.h +++ b/include/geos/triangulate/polygon/PolygonHoleJoiner.h @@ -74,8 +74,8 @@ private: const Polygon* inputPolygon; //-- normalized, sorted and noded polygon rings - std::unique_ptr shellRing; - std::vector> holeRings; + std::shared_ptr shellRing; + std::vector> holeRings; //-- indicates whether a hole should be testing for touching std::vector isHoleTouchingHint; @@ -97,7 +97,7 @@ private: void extractOrientedRings(const Polygon* polygon); - static std::unique_ptr extractOrientedRing(const LinearRing* ring, bool isCW); + static std::shared_ptr extractOrientedRing(const LinearRing* ring, bool isCW); void nodeRings(); void joinHoles(); diff --git a/include/geos/triangulate/polygon/PolygonNoder.h b/include/geos/triangulate/polygon/PolygonNoder.h index fde921356..465e63b98 100644 --- a/include/geos/triangulate/polygon/PolygonNoder.h +++ b/include/geos/triangulate/polygon/PolygonNoder.h @@ -66,8 +66,8 @@ class GEOS_DLL PolygonNoder { public: PolygonNoder( - std::unique_ptr& shellRing, - std::vector>& holeRings); + const std::shared_ptr& shellRing, + const std::vector>& holeRings); void node(); bool isShellNoded(); @@ -91,11 +91,11 @@ private: // Methods NodedSegmentString* - createNodedSegString(std::unique_ptr& ringPts, std::size_t i); + createNodedSegString(const std::shared_ptr &ringPts, std::size_t i); void createNodedSegmentStrings( - std::unique_ptr& shellRing, - std::vector>& holeRings); + const std::shared_ptr &shellRing, + const std::vector> &holeRings); /* Turn off copy constructors for MSVC */ PolygonNoder(const PolygonNoder&) = delete; diff --git a/src/algorithm/MinimumDiameter.cpp b/src/algorithm/MinimumDiameter.cpp index 813b161f9..a55f78e6f 100644 --- a/src/algorithm/MinimumDiameter.cpp +++ b/src/algorithm/MinimumDiameter.cpp @@ -135,7 +135,7 @@ MinimumDiameter::getDiameter() computeMinimumDiameter(); // return empty linestring if no minimum width calculated if(minWidthPt.isNull()) { - return std::unique_ptr(inputGeom->getFactory()->createLineString(nullptr)); + return std::unique_ptr(inputGeom->getFactory()->createLineString()); } Coordinate basePt; diff --git a/src/coverage/CoverageCleaner.cpp b/src/coverage/CoverageCleaner.cpp index 940dcd444..51c822e05 100644 --- a/src/coverage/CoverageCleaner.cpp +++ b/src/coverage/CoverageCleaner.cpp @@ -389,8 +389,8 @@ CoverageCleaner::toGeometry( { std::vector> lines; for (auto& ss : segStrings) { - auto cs = ss->getCoordinates()->clone(); - std::unique_ptr line = geomFact->createLineString(std::move(cs)); + const auto& cs = ss->getCoordinates(); + std::unique_ptr line = geomFact->createLineString(cs); lines.emplace_back(line.release()); } if (lines.size() == 1) return lines[0]->clone(); diff --git a/src/coverage/CoverageEdge.cpp b/src/coverage/CoverageEdge.cpp index 65971fc3a..a3504a2f6 100644 --- a/src/coverage/CoverageEdge.cpp +++ b/src/coverage/CoverageEdge.cpp @@ -59,8 +59,8 @@ CoverageEdge::createLines( { std::vector> lines; for (const CoverageEdge* edge : edges) { - auto cs = edge->getCoordinates()->clone(); - auto ls = geomFactory->createLineString(std::move(cs)); + const auto& cs = edge->getCoordinates(); + auto ls = geomFactory->createLineString(cs); lines.push_back(std::move(ls)); } return geomFactory->createMultiLineString(std::move(lines)); @@ -68,10 +68,10 @@ CoverageEdge::createLines( /* public */ std::unique_ptr -CoverageEdge::toLineString(const GeometryFactory* geomFactory) +CoverageEdge::toLineString(const GeometryFactory* geomFactory) const { - const CoordinateSequence* cs = getCoordinates(); - return geomFactory->createLineString(cs->clone()); + const auto& cs = getCoordinates(); + return geomFactory->createLineString(cs); } /* private static */ diff --git a/src/coverage/CoveragePolygonValidator.cpp b/src/coverage/CoveragePolygonValidator.cpp index 16b252e00..d77f95aab 100644 --- a/src/coverage/CoveragePolygonValidator.cpp +++ b/src/coverage/CoveragePolygonValidator.cpp @@ -386,13 +386,12 @@ CoveragePolygonValidator::addRing( CoverageRing* CoveragePolygonValidator::createRing(const LinearRing* ring, bool isShell) { - CoordinateSequence* pts = const_cast(ring->getCoordinatesRO()); + std::shared_ptr pts = ring->getSharedCoordinates(); if (pts->hasRepeatedOrInvalidPoints()) { - CoordinateSequence* cleanPts = RepeatedPointRemover::removeRepeatedAndInvalidPoints(pts).release(); - localCoordinateSequences.emplace_back(cleanPts); - pts = cleanPts; + auto cleanPts = RepeatedPointRemover::removeRepeatedAndInvalidPoints(pts.get()); + pts = std::move(cleanPts); } - bool isCCW = Orientation::isCCW(pts); + bool isCCW = Orientation::isCCW(pts.get()); bool isInteriorOnRight = isShell ? ! isCCW : isCCW; coverageRingStore.emplace_back(pts, isInteriorOnRight); CoverageRing& cRing = coverageRingStore.back(); diff --git a/src/coverage/CoverageRing.cpp b/src/coverage/CoverageRing.cpp index 9a331291f..d68c46cc6 100644 --- a/src/coverage/CoverageRing.cpp +++ b/src/coverage/CoverageRing.cpp @@ -51,7 +51,7 @@ CoverageRing::isKnown(std::vector& rings) /* public */ -CoverageRing::CoverageRing(CoordinateSequence* inPts, bool interiorOnRight) +CoverageRing::CoverageRing(const std::shared_ptr& inPts, bool interiorOnRight) : noding::BasicSegmentString(inPts, nullptr) , m_isInteriorOnRight(interiorOnRight) { @@ -63,13 +63,7 @@ CoverageRing::CoverageRing(CoordinateSequence* inPts, bool interiorOnRight) /* public */ CoverageRing::CoverageRing(const LinearRing* ring, bool isShell) : CoverageRing( - // This is bad. The ownership rules of SegmentStrings need - // to be carefully considered. Most noders don't even touch - // them so a const CoordinateSequence makes sense. Some add - // things, like the NodedSegmentString, but do so out-of-line. - // Some noders (just ScalingNoder?) completely transform the - // inputs. Could maybe do bulk copying for that case? - const_cast(ring->getCoordinatesRO()), + ring->getSharedCoordinates(), algorithm::Orientation::isCCW(ring->getCoordinatesRO()) != isShell) {} diff --git a/src/coverage/CoverageRingEdges.cpp b/src/coverage/CoverageRingEdges.cpp index a5a697cc1..99c53b04e 100644 --- a/src/coverage/CoverageRingEdges.cpp +++ b/src/coverage/CoverageRingEdges.cpp @@ -374,7 +374,7 @@ CoverageRingEdges::buildRing(const LinearRing* ring) const for (std::size_t i = 0; i < ringEdges->size(); i++) { Coordinate& lastPt = pts->isEmpty() ? nullPt : pts->back(); bool dir = isEdgeDirForward(*ringEdges, i, lastPt); - const CoordinateSequence* ringCs = ringEdges->at(i)->getCoordinates(); + const auto& ringCs = ringEdges->at(i)->getCoordinates(); pts->add(*ringCs, false, dir); } return ring->getFactory()->createLinearRing(std::move(pts)); diff --git a/src/coverage/CoverageSimplifier.cpp b/src/coverage/CoverageSimplifier.cpp index 98ba1ad87..0623cedce 100644 --- a/src/coverage/CoverageSimplifier.cpp +++ b/src/coverage/CoverageSimplifier.cpp @@ -136,7 +136,7 @@ CoverageSimplifier::setCoordinates(std::vector& edges, const Mult { for (std::size_t i = 0; i < edges.size(); i++) { CoverageEdge* edge = edges[i]; - edge->setCoordinates(lines->getGeometryN(i)->getCoordinatesRO()); + edge->setCoordinates(lines->getGeometryN(i)->getSharedCoordinates()); } } diff --git a/src/dissolve/LineDissolver.cpp b/src/dissolve/LineDissolver.cpp index 674c132d5..3c1d808fb 100644 --- a/src/dissolve/LineDissolver.cpp +++ b/src/dissolve/LineDissolver.cpp @@ -88,6 +88,7 @@ void LineDissolver::add(const LineString* lineString) { const CoordinateSequence* seq = lineString->getCoordinatesRO(); + bool doneStart = false; for (std::size_t i = 1; i < seq->size(); i++) { CoordinateXYZM orig, dest; diff --git a/src/geom/CircularString.cpp b/src/geom/CircularString.cpp index b666c8eb1..26f74d96f 100644 --- a/src/geom/CircularString.cpp +++ b/src/geom/CircularString.cpp @@ -30,6 +30,14 @@ CircularString::CircularString(std::unique_ptr&& newCoords, validateConstruction(); } +CircularString::CircularString(const std::shared_ptr& newCoords, + const GeometryFactory& factory) + : + SimpleCurve(newCoords, false, factory) +{ + validateConstruction(); +} + CircularString::~CircularString() = default; std::unique_ptr diff --git a/src/geom/GeometryFactory.cpp b/src/geom/GeometryFactory.cpp index 4e97f85cd..458fbe8e1 100644 --- a/src/geom/GeometryFactory.cpp +++ b/src/geom/GeometryFactory.cpp @@ -458,6 +458,13 @@ GeometryFactory::createLinearRing(CoordinateSequence::Ptr && newCoords) const return std::unique_ptr(new LinearRing(std::move(newCoords), *this)); } +std::unique_ptr +GeometryFactory::createLinearRing(const std::shared_ptr& newCoords) const +{ + // Can't use make_unique with protected constructor + return std::unique_ptr(new LinearRing(newCoords, *this)); +} + /*public*/ std::unique_ptr GeometryFactory::createLinearRing(const CoordinateSequence& fromCoords) const @@ -641,6 +648,16 @@ GeometryFactory::createCircularString(const CircularString& ls) const return std::unique_ptr(new CircularString(ls)); } +/*public*/ +std::unique_ptr +GeometryFactory::createLineString(const std::shared_ptr& newCoords) const +{ + if (!newCoords) + return createLineString(); + // Can't use make_unique with protected constructor + return std::unique_ptr(new LineString(newCoords, *this)); +} + /*public*/ std::unique_ptr GeometryFactory::createLineString(CoordinateSequence::Ptr && newCoords) @@ -663,6 +680,16 @@ const return std::unique_ptr(new CircularString(std::move(newCoords), *this)); } +std::unique_ptr +GeometryFactory::createCircularString(const std::shared_ptr& newCoords) +const +{ + if (!newCoords) + return createCircularString(false, false); + // Can't use make_unique with protected constructor + return std::unique_ptr(new CircularString(newCoords, *this)); +} + /*public*/ std::unique_ptr GeometryFactory::createCompoundCurve() diff --git a/src/geom/LineString.cpp b/src/geom/LineString.cpp index 90e37479f..fb52a2c5e 100644 --- a/src/geom/LineString.cpp +++ b/src/geom/LineString.cpp @@ -54,6 +54,15 @@ LineString::LineString(const LineString& ls) { } +/*public*/ +LineString::LineString(const std::shared_ptr & newCoords, + const GeometryFactory& factory) + : + SimpleCurve(newCoords, true, factory) +{ + validateConstruction(); +} + /*public*/ LineString::LineString(CoordinateSequence::Ptr && newCoords, const GeometryFactory& factory) diff --git a/src/geom/LinearRing.cpp b/src/geom/LinearRing.cpp index 6afc506c0..da3d848a5 100644 --- a/src/geom/LinearRing.cpp +++ b/src/geom/LinearRing.cpp @@ -44,6 +44,13 @@ LinearRing::LinearRing(CoordinateSequence::Ptr && newCoords, validateConstruction(); } +LinearRing::LinearRing(const std::shared_ptr& newCoords, + const GeometryFactory& newFactory) + : LineString(newCoords, newFactory) +{ + validateConstruction(); +} + void LinearRing::validateConstruction() { @@ -108,7 +115,13 @@ LinearRing::orient(bool isCW) } if (algorithm::Orientation::isCCW(points.get()) == isCW) { - points->reverse(); + if (points.use_count() == 1) { + const_cast(points.get())->reverse(); + } else { + auto newPoints = points->clone(); + newPoints->reverse(); + points = std::move(newPoints); + } } } diff --git a/src/geom/Polygon.cpp b/src/geom/Polygon.cpp index 3163e8543..850331c04 100644 --- a/src/geom/Polygon.cpp +++ b/src/geom/Polygon.cpp @@ -147,7 +147,7 @@ Polygon::getArea() const double area = 0.0; area += algorithm::Area::ofRing(shell->getCoordinatesRO()); for(const auto& lr : holes) { - const CoordinateSequence* h = lr->getCoordinatesRO(); + const auto& h = lr->getCoordinatesRO(); area -= algorithm::Area::ofRing(h); } return area; diff --git a/src/geom/SimpleCurve.cpp b/src/geom/SimpleCurve.cpp index 952d207d0..e062c4c8b 100644 --- a/src/geom/SimpleCurve.cpp +++ b/src/geom/SimpleCurve.cpp @@ -38,11 +38,20 @@ SimpleCurve::SimpleCurve(const SimpleCurve& other) { } +SimpleCurve::SimpleCurve(const std::shared_ptr& newCoords, + bool isLinear, + const GeometryFactory& factory) + : Curve(factory), + points(newCoords), + envelope(computeEnvelopeInternal(isLinear)) +{ +} + SimpleCurve::SimpleCurve(std::unique_ptr&& newCoords, bool isLinear, const GeometryFactory& factory) : Curve(factory), - points(newCoords ? std::move(newCoords) : std::make_unique()), + points(newCoords ? std::move(newCoords) : std::make_shared()), envelope(computeEnvelopeInternal(isLinear)) { } @@ -73,18 +82,24 @@ void SimpleCurve::apply_rw(const CoordinateFilter* filter) { assert(points.get()); - points->apply_rw(filter); + if (points.use_count() > 1) { + points = points->clone(); + } + const_cast(points.get())->apply_rw(filter); } void SimpleCurve::apply_rw(CoordinateSequenceFilter& filter) { + if (points.use_count() > 1) { + points = points->clone(); + } std::size_t npts = points->size(); if (!npts) { return; } for (std::size_t i = 0; i < npts; ++i) { - filter.filter_rw(*points, i); + filter.filter_rw(const_cast(*points), i); if (filter.isDone()) { break; } @@ -218,6 +233,13 @@ SimpleCurve::getCoordinatesRO() const return points.get(); } +const std::shared_ptr& +SimpleCurve::getSharedCoordinates() const +{ + assert(nullptr != points.get()); + return points; +} + const SimpleCurve* SimpleCurve::getCurveN(std::size_t) const { @@ -326,7 +348,10 @@ SimpleCurve::normalize() std::size_t j = npts - 1 - i; if (!(points->getAt(i) == points->getAt(j))) { if (points->getAt(i).compareTo(points->getAt(j)) > 0) { - points->reverse(); + if (points.use_count() > 1) { + points = points->clone(); + } + const_cast(points.get())->reverse(); } return; } @@ -360,15 +385,5 @@ SimpleCurve::normalizeClosed() points = std::move(coords); } -std::unique_ptr -SimpleCurve::releaseCoordinates() -{ - auto newPts = std::make_unique(0u, points->hasZ(), points->hasM()); - auto ret = std::move(points); - points = std::move(newPts); - geometryChanged(); - return ret; -} - } // namespace geos::geom } // namespace geos diff --git a/src/geom/util/CoordinateOperation.cpp b/src/geom/util/CoordinateOperation.cpp index 621b74142..07bc85695 100644 --- a/src/geom/util/CoordinateOperation.cpp +++ b/src/geom/util/CoordinateOperation.cpp @@ -35,13 +35,13 @@ CoordinateOperation::edit(const Geometry* geometry, } if(const LinearRing* ring = dynamic_cast(geometry)) { - const CoordinateSequence* coords = ring->getCoordinatesRO(); + const auto& coords = ring->getCoordinatesRO(); auto newCoords = edit(coords, geometry); // LinearRing instance takes over ownership of newCoords instance return factory->createLinearRing(std::move(newCoords)); } if(const LineString* line = dynamic_cast(geometry)) { - const CoordinateSequence* coords = line->getCoordinatesRO(); + const auto& coords = line->getCoordinatesRO(); auto newCoords = edit(coords, geometry); return factory->createLineString(std::move(newCoords)); } diff --git a/src/geomgraph/EdgeNodingValidator.cpp b/src/geomgraph/EdgeNodingValidator.cpp index eab396e81..6e30a7abd 100644 --- a/src/geomgraph/EdgeNodingValidator.cpp +++ b/src/geomgraph/EdgeNodingValidator.cpp @@ -37,17 +37,13 @@ EdgeNodingValidator::toSegmentStrings(std::vector& edges) for(std::size_t i = 0, n = edges.size(); i < n; ++i) { Edge* e = edges[i]; auto cs = e->getCoordinates()->clone(); - segStr.push_back(std::make_unique(cs.get(), e)); - newCoordSeq.push_back(cs.release()); + segStr.push_back(std::make_unique(std::move(cs), e)); } return segStr; } EdgeNodingValidator::~EdgeNodingValidator() { - for(std::size_t i = 0, n = newCoordSeq.size(); i < n; ++i) { - delete newCoordSeq[i]; - } } } // namespace geos.geomgraph diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index 35b3a6bfe..ad9d88d38 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -107,13 +107,9 @@ BoundaryChainNoder::nodeChain( std::unique_ptr BoundaryChainNoder::substring(const SegmentString* segString, std::size_t start, std::size_t end) { - // A BasicSegmentString does not own its CoordinateSequence, so why does this not leak? - // At least in the CoverageUnion case, we end up here from EdgeNodingBuilder::node, where the - // created BasicSegmentStrings are (incorrectly) down-casted to NodedSegmentStrings, and - // the coordinate ownership is transferred to an overlayng::Edge. - auto pts = std::make_unique(); + auto pts = std::make_shared(); pts->add(*segString->getCoordinates(), start, end); - return std::make_unique(pts.release(), segString->getData()); + return std::make_unique(pts, segString->getData()); } @@ -250,11 +246,11 @@ BoundaryChainNoder::BoundaryChainMap::createChain( bool constructM) { auto npts = endIndex - startIndex + 1; - auto pts = detail::make_unique(0, constructZ, constructM); + auto pts = std::make_shared(0, constructZ, constructM); pts->reserve(npts); pts->add(*segString->getCoordinates(), startIndex, endIndex); - return std::make_unique(pts.release(), constructZ, constructM, segString->getData()); + return std::make_unique(pts, constructZ, constructM, segString->getData()); } /* private */ diff --git a/src/noding/GeometryNoder.cpp b/src/noding/GeometryNoder.cpp index 5ec79d1f7..46a5f0e04 100644 --- a/src/noding/GeometryNoder.cpp +++ b/src/noding/GeometryNoder.cpp @@ -61,9 +61,8 @@ public: { const geom::LineString* ls = dynamic_cast(g); if(ls) { - auto coord = ls->getCoordinates(); - // coord ownership transferred to SegmentString - SegmentString* ss = new NodedSegmentString(coord.release(), _constructZ, _constructM, nullptr); + auto coord = ls->getSharedCoordinates(); + SegmentString* ss = new NodedSegmentString(coord, _constructZ, _constructM, nullptr); _to.push_back(ss); } } @@ -107,12 +106,12 @@ GeometryNoder::toGeometry(std::vector>& nodedEdge std::vector> lines; lines.reserve(nodedEdges.size()); for(auto& ss : nodedEdges) { - const geom::CoordinateSequence* coords = ss->getCoordinates(); + const auto& coords = ss->getCoordinates(); // Check if an equivalent edge is known OrientedCoordinateArray oca1(*coords); if(ocas.insert(oca1).second) { - lines.push_back(geomFact->createLineString(coords->clone())); + lines.push_back(geomFact->createLineString(coords)); } } diff --git a/src/noding/MCIndexNoder.cpp b/src/noding/MCIndexNoder.cpp index 556738ff4..9619e9adf 100644 --- a/src/noding/MCIndexNoder.cpp +++ b/src/noding/MCIndexNoder.cpp @@ -83,7 +83,7 @@ MCIndexNoder::add(SegmentString* segStr) // std::vector> segChains; // segChains will contain newly allocated MonotoneChain objects - MonotoneChainBuilder::getChains(segStr->getCoordinates(), + MonotoneChainBuilder::getChains(segStr->getCoordinates().get(), segStr, monoChains); } diff --git a/src/noding/MCIndexSegmentSetMutualIntersector.cpp b/src/noding/MCIndexSegmentSetMutualIntersector.cpp index b5b5e4d49..f51301acb 100644 --- a/src/noding/MCIndexSegmentSetMutualIntersector.cpp +++ b/src/noding/MCIndexSegmentSetMutualIntersector.cpp @@ -36,7 +36,7 @@ namespace noding { // geos::noding void MCIndexSegmentSetMutualIntersector::addToIndex(SegmentString* segStr) { - MonotoneChainBuilder::getChains(segStr->getCoordinates(), + MonotoneChainBuilder::getChains(segStr->getCoordinates().get(), segStr, indexChains); } @@ -49,7 +49,7 @@ MCIndexSegmentSetMutualIntersector::addToMonoChains(SegmentString* segStr) if (segStr->size() == 0) return; MonoChains segChains; - MonotoneChainBuilder::getChains(segStr->getCoordinates(), + MonotoneChainBuilder::getChains(segStr->getCoordinates().get(), segStr, segChains); for (auto& mc : segChains) { if (envelope == nullptr || envelope->intersects(mc.getEnvelope())) { diff --git a/src/noding/NodedSegmentString.cpp b/src/noding/NodedSegmentString.cpp index 4074d7342..7bcc5aa7d 100644 --- a/src/noding/NodedSegmentString.cpp +++ b/src/noding/NodedSegmentString.cpp @@ -70,14 +70,6 @@ NodedSegmentString::getNodedSubstrings( return resultEdgelist; } -std::unique_ptr -NodedSegmentString::releaseCoordinates() -{ - auto ret = std::unique_ptr(seq); - seq = nullptr; - return ret; -} - /* public virtual */ std::ostream& NodedSegmentString::print(std::ostream& os) const diff --git a/src/noding/ScaledNoder.cpp b/src/noding/ScaledNoder.cpp index 02192cac2..c6dec8502 100644 --- a/src/noding/ScaledNoder.cpp +++ b/src/noding/ScaledNoder.cpp @@ -139,7 +139,9 @@ ScaledNoder::rescale(std::vector>& segStrings) co { ReScaler rescaler(*this); for(auto& ss : segStrings) { - ss->getCoordinates()->apply_rw(&rescaler); + auto copy = ss->getCoordinates()->clone(); + copy->apply_rw(&rescaler); + ss->setCoordinates(std::move(copy)); } } @@ -152,7 +154,7 @@ ScaledNoder::scale(const SegmentString::NonConstVect& segStrings) const for(std::size_t i = 0; i < segStrings.size(); i++) { SegmentString* ss = segStrings[i]; - CoordinateSequence* cs = ss->getCoordinates(); + auto cs = ss->getCoordinates()->clone(); #ifndef NDEBUG std::size_t npts = cs->size(); @@ -162,10 +164,12 @@ ScaledNoder::scale(const SegmentString::NonConstVect& segStrings) const operation::valid::RepeatedPointTester rpt; // FIXME remove hardcoded hasZ, hasM and derive from input - if (rpt.hasRepeatedPoint(cs)) { - auto cs2 = operation::valid::RepeatedPointRemover::removeRepeatedPoints(cs); - const_cast&>(segStrings)[i] = new NodedSegmentString(cs2.release(), true, false, ss->getData()); + if (rpt.hasRepeatedPoint(cs.get())) { + auto cs2 = operation::valid::RepeatedPointRemover::removeRepeatedPoints(cs.get()); + const_cast&>(segStrings)[i] = new NodedSegmentString(std::move(cs2), true, false, ss->getData()); delete ss; + } else { + ss->setCoordinates(std::move(cs)); } } } diff --git a/src/noding/SegmentExtractingNoder.cpp b/src/noding/SegmentExtractingNoder.cpp index 0bfb095bf..67d79df50 100644 --- a/src/noding/SegmentExtractingNoder.cpp +++ b/src/noding/SegmentExtractingNoder.cpp @@ -54,17 +54,17 @@ SegmentExtractingNoder::extractSegments( const SegmentString* ss, std::vector>& outputSegs) { - const CoordinateSequence* ss_seq = ss->getCoordinates(); + const auto& ss_seq = ss->getCoordinates(); const NodedSegmentString* nss = dynamic_cast(ss); bool constructZ = nss ? nss->getNodeList().getConstructZ() : ss_seq->hasZ(); bool constructM = nss ? nss->getNodeList().getConstructM() : ss_seq->hasM(); for (std::size_t i = 0; i < ss_seq->getSize() - 1; i++) { - auto cs = detail::make_unique(0, constructZ, constructM); + auto cs = std::make_shared(0, constructZ, constructM); cs->reserve(2); cs->add(*ss_seq, i, i + 1); - std::unique_ptr seg(new NodedSegmentString(cs.release(), constructZ, constructM, ss->getData())); + std::unique_ptr seg(new NodedSegmentString(cs, constructZ, constructM, ss->getData())); outputSegs.push_back(std::move(seg)); } } diff --git a/src/noding/SegmentNodeList.cpp b/src/noding/SegmentNodeList.cpp index 5fa6dd7dc..4404ddfb0 100644 --- a/src/noding/SegmentNodeList.cpp +++ b/src/noding/SegmentNodeList.cpp @@ -67,7 +67,7 @@ SegmentNodeList::addEndpoints() { std::size_t maxSegIndex = edge.size() - 1; - const auto* edgePts = edge.getCoordinates(); + const auto& edgePts = edge.getCoordinates(); CoordinateXYZM p0, p1; edgePts->getAt(0, p0); @@ -212,7 +212,7 @@ SegmentNodeList::checkSplitEdgesCorrectness(const std::vector& s if (splitEdges.empty()) return; - const CoordinateSequence* edgePts = edge.getCoordinates(); + const auto& edgePts = edge.getCoordinates(); assert(edgePts); // check that first and last points of split edges @@ -228,7 +228,7 @@ SegmentNodeList::checkSplitEdgesCorrectness(const std::vector& s SegmentString* splitn = splitEdges[splitEdges.size() - 1]; assert(splitn); - const CoordinateSequence* splitnPts = splitn->getCoordinates(); + const auto& splitnPts = splitn->getCoordinates(); assert(splitnPts); const Coordinate& ptn = splitnPts->getAt(splitnPts->getSize() - 1); @@ -242,19 +242,19 @@ std::unique_ptr SegmentNodeList::createSplitEdge(const SegmentNode* ei0, const SegmentNode* ei1) const { auto pts = createSplitEdgePts(ei0, ei1); - return detail::make_unique(pts.release(), constructZ, constructM, edge.getData()); + return detail::make_unique(std::move(pts), constructZ, constructM, edge.getData()); } /*private*/ -std::unique_ptr -SegmentNodeList::createSplitEdgePts(const SegmentNode* ei0, const SegmentNode* ei1) const +std::shared_ptr +SegmentNodeList::createSplitEdgePts(const SegmentNode *ei0, const SegmentNode *ei1) const { bool twoPoints = (ei1->segmentIndex == ei0->segmentIndex); // if only two points in split edge they must be the node points if (twoPoints) { - auto pts = detail::make_unique(2u, constructZ, constructM); + auto pts = std::make_shared(2u, constructZ, constructM); pts->setAt(ei0->coord, 0); pts->setAt(ei1->coord, 1); return pts; @@ -272,11 +272,11 @@ SegmentNodeList::createSplitEdgePts(const SegmentNode* ei0, const SegmentNode* e std::size_t npts = 1 + (ei1->segmentIndex - ei0->segmentIndex) + useIntPt1; - auto pts = detail::make_unique(0u, constructZ, constructM); + auto pts = std::make_shared(0u, constructZ, constructM); pts->reserve(npts); pts->add(ei0->coord); - const CoordinateSequence* edgeCoords = edge.getCoordinates(); + const auto& edgeCoords = edge.getCoordinates(); pts->add(*edgeCoords, ei0->segmentIndex + 1, ei1->segmentIndex); if (useIntPt1) { pts->add(ei1->coord); diff --git a/src/noding/SimpleNoder.cpp b/src/noding/SimpleNoder.cpp index 8f5ea1d9e..6719a093e 100644 --- a/src/noding/SimpleNoder.cpp +++ b/src/noding/SimpleNoder.cpp @@ -33,8 +33,8 @@ SimpleNoder::computeIntersects(SegmentString* e0, SegmentString* e1) { assert(segInt); // must provide a segment intersector! - const CoordinateSequence* pts0 = e0->getCoordinates(); - const CoordinateSequence* pts1 = e1->getCoordinates(); + const CoordinateSequence* pts0 = e0->getCoordinates().get(); + const CoordinateSequence* pts1 = e1->getCoordinates().get(); for(std::size_t i0 = 0, n0 = pts0->getSize() - 1; i0 < n0; i0++) { for(std::size_t i1 = 0, n1 = pts1->getSize() - 1; i1 < n1; i1++) { segInt->processIntersections(e0, i0, e1, i1); diff --git a/src/noding/snap/SnappingNoder.cpp b/src/noding/snap/SnappingNoder.cpp index 614aeac7e..f4848d1fc 100644 --- a/src/noding/snap/SnappingNoder.cpp +++ b/src/noding/snap/SnappingNoder.cpp @@ -77,13 +77,13 @@ SnappingNoder::seedSnapIndex(const std::vector& segStrings) double PHI_INV = (std::sqrt(5.0) - 1.0) / 2.0; for (SegmentString* ss: segStrings) { - CoordinateSequence* cs = ss->getCoordinates(); + const auto& cs = ss->getCoordinates(); int numPts = (int) cs->size(); int numPtsToLoad = numPts / 100; double rand = 0.0; for (int i = 0; i < numPtsToLoad; i++) { - // quasi-random sequennce generated by additive recurrence with irrational constant + // quasi-random sequence generated by additive recurrence with irrational constant rand = rand + PHI_INV; if (rand > 1) rand = rand - floor(rand); @@ -97,17 +97,17 @@ SnappingNoder::seedSnapIndex(const std::vector& segStrings) std::unique_ptr SnappingNoder::snapVertices(const SegmentString* ss) { - auto snapCoords = snap(ss->getCoordinates()); + auto snapCoords = snap(ss->getCoordinates().get()); // FIXME remove hardcoded hasZ, hasM and derive from input - return std::make_unique(snapCoords.release(), false, false, ss->getData()); + return std::make_unique(std::move(snapCoords), false, false, ss->getData()); } /*private*/ -std::unique_ptr -SnappingNoder::snap(const CoordinateSequence* cs) +std::shared_ptr +SnappingNoder::snap(const CoordinateSequence *cs) { - auto snapCoords = detail::make_unique(); + auto snapCoords = std::make_shared(); snapCoords->reserve(cs->size()); cs->forEach([&snapCoords, this](const Coordinate& origPt) { diff --git a/src/noding/snapround/MCIndexSnapRounder.cpp b/src/noding/snapround/MCIndexSnapRounder.cpp index d76152ffb..fd65b1f63 100644 --- a/src/noding/snapround/MCIndexSnapRounder.cpp +++ b/src/noding/snapround/MCIndexSnapRounder.cpp @@ -60,7 +60,7 @@ MCIndexSnapRounder::computeIntersectionSnaps(std::vector& snapPts) void MCIndexSnapRounder::computeVertexSnaps(NodedSegmentString* e) { - CoordinateSequence& pts0 = *(e->getCoordinates()); + const CoordinateSequence& pts0 = *(e->getCoordinates()); for(std::size_t i = 0, n = pts0.size() - 1; i < n; ++i) { HotPixel hotPixel(pts0.getAt(i), scaleFactor); bool isNodeAdded = pointSnapper->snap(hotPixel, e, i); diff --git a/src/noding/snapround/SnapRoundingNoder.cpp b/src/noding/snapround/SnapRoundingNoder.cpp index 30d7b7be5..8eca8dd1d 100644 --- a/src/noding/snapround/SnapRoundingNoder.cpp +++ b/src/noding/snapround/SnapRoundingNoder.cpp @@ -89,8 +89,8 @@ void SnapRoundingNoder::addVertexPixels(const std::vector& segStrings) { for (SegmentString* nss : segStrings) { - const CoordinateSequence* pts = nss->getCoordinates(); - pixelIndex.add(pts); + const auto& pts = nss->getCoordinates(); + pixelIndex.add(pts.get()); } } @@ -153,7 +153,7 @@ SnapRoundingNoder::computeSegmentSnaps(NodedSegmentString* ss) return nullptr; // Create new nodedSS to allow adding any hot pixel nodes - NodedSegmentString* snapSS = new NodedSegmentString(ptsRound.release(), ss->getNodeList().getConstructZ(), ss->getNodeList().getConstructM(), ss->getData()); + NodedSegmentString* snapSS = new NodedSegmentString(std::move(ptsRound), ss->getNodeList().getConstructZ(), ss->getNodeList().getConstructM(), ss->getData()); std::size_t snapSSindex = 0; for (std::size_t i = 0, sz = pts->size()-1; i < sz; i++ ) { @@ -240,7 +240,7 @@ SnapRoundingNoder::snapSegment(const CoordinateXY& p0, const CoordinateXY& p1, N void SnapRoundingNoder::addVertexNodeSnaps(NodedSegmentString* ss) { - const CoordinateSequence* pts = ss->getCoordinates(); + const auto& pts = ss->getCoordinates(); std::size_t i = 0; pts->forEach([this, ss, &i](const auto& p0) -> void { if (i > 0 && i < ss->size() - 1) { diff --git a/src/operation/buffer/BufferBuilder.cpp b/src/operation/buffer/BufferBuilder.cpp index 1bdf09493..3c7c89da8 100644 --- a/src/operation/buffer/BufferBuilder.cpp +++ b/src/operation/buffer/BufferBuilder.cpp @@ -177,7 +177,7 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, // Then, get the raw (i.e. unnoded) single sided offset curve. OffsetCurveBuilder curveBuilder(precisionModel, modParams); - std::vector< CoordinateSequence* > lineList; + std::vector> lineList; { std::unique_ptr< CoordinateSequence > coords(g->getCoordinates()); @@ -188,11 +188,11 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, // Create a SegmentString from these coordinates. SegmentString::NonConstVect curveList; - for(unsigned int i = 0; i < lineList.size(); ++i) { - CoordinateSequence* seq = lineList[i]; - + for(auto& seq : lineList) { + const bool hasZ = seq->hasZ(); + const bool hasM = seq->hasM(); // SegmentString takes ownership of CoordinateSequence - SegmentString* ss = new NodedSegmentString(seq, seq->hasZ(), seq->hasM(), nullptr); + SegmentString* ss = new NodedSegmentString(std::move(seq), hasZ, hasM, nullptr); curveList.push_back(ss); } lineList.clear(); @@ -666,7 +666,7 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, for(auto& segStr : nodedSegStrings) { const Label* oldLabel = static_cast(segStr->getData()); - auto cs = operation::valid::RepeatedPointRemover::removeRepeatedPoints(segStr->getCoordinates()); + auto cs = operation::valid::RepeatedPointRemover::removeRepeatedPoints(segStr->getCoordinates().get()); segStr.reset(); if(cs->size() < 2) { // don't insert collapsed edges diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index 69e5976e3..1e4b38820 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -85,18 +85,17 @@ BufferCurveSetBuilder::getCurves() /*public*/ void -BufferCurveSetBuilder::addCurves(const std::vector& lineList, +BufferCurveSetBuilder::addCurves(std::vector>& lineList, geom::Location leftLoc, geom::Location rightLoc) { for(std::size_t i = 0, n = lineList.size(); i < n; ++i) { - CoordinateSequence* coords = lineList[i]; - addCurve(coords, leftLoc, rightLoc); + addCurve(std::move(lineList[i]), leftLoc, rightLoc); } } /*private*/ void -BufferCurveSetBuilder::addCurve(CoordinateSequence* coord, +BufferCurveSetBuilder::addCurve(std::unique_ptr coord, geom::Location leftLoc, geom::Location rightLoc) { #if GEOS_DEBUG @@ -107,15 +106,16 @@ BufferCurveSetBuilder::addCurve(CoordinateSequence* coord, #if GEOS_DEBUG std::cerr << " skipped (size<2)" << std::endl; #endif - delete coord; return; } // add the edge for a coordinate list which is a raw offset curve Label* newlabel = new Label(0, Location::BOUNDARY, leftLoc, rightLoc); + const bool hasZ = coord->hasZ(); + const bool hasM = coord->hasM(); // coord ownership transferred to SegmentString - SegmentString* e = new NodedSegmentString(coord, coord->hasZ(), coord->hasM(), newlabel); + SegmentString* e = new NodedSegmentString(std::move(coord), hasZ, hasM, newlabel); // SegmentString doesn't own the sequence, so we need to delete in // the destructor @@ -185,7 +185,7 @@ BufferCurveSetBuilder::addPoint(const Point* p) if (coord->size() >= 1 && ! coord->getAt(0).isValid()) { return; } - std::vector lineList; + std::vector> lineList; curveBuilder.getLineCurve(coord, distance, lineList); addCurves(lineList, Location::EXTERIOR, Location::INTERIOR); @@ -217,7 +217,7 @@ BufferCurveSetBuilder::addLineString(const LineString* line) addLinearRingSides(coord.get(), distance); } else { - std::vector lineList; + std::vector> lineList; curveBuilder.getLineCurve(coord.get(), distance, lineList); addCurves(lineList, Location::EXTERIOR, Location::INTERIOR); } @@ -365,20 +365,20 @@ BufferCurveSetBuilder::addPolygonRingSide(const CoordinateSequence* coord, /* private */ void BufferCurveSetBuilder::addRingSide(const CoordinateSequence* coord, - double offsetDistance, int side, geom::Location leftLoc, geom::Location rightLoc) + double offsetDistance, int side, geom::Location leftLoc, geom::Location rightLoc) { - std::vector lineList; + std::vector> lineList; curveBuilder.getRingCurve(coord, side, offsetDistance, lineList); // ASSERT: lineList contains exactly 1 curve (this is the JTS semantics) if (lineList.size() > 0) { - const CoordinateSequence* curve = lineList[0]; + const CoordinateSequence* curve = lineList[0].get(); /** * If the offset curve has inverted completely it will produce * an unwanted artifact in the result, so skip it. */ if (isRingCurveInverted(coord, offsetDistance, curve)) { - for( auto line: lineList ) { - delete line; + for(auto& line: lineList ) { + line.reset(); } return; } diff --git a/src/operation/buffer/OffsetCurveBuilder.cpp b/src/operation/buffer/OffsetCurveBuilder.cpp index 1628ef9bb..ed2ae6c22 100644 --- a/src/operation/buffer/OffsetCurveBuilder.cpp +++ b/src/operation/buffer/OffsetCurveBuilder.cpp @@ -53,7 +53,7 @@ const double OffsetCurveBuilder::SIMPLIFY_FACTOR = 100.0; /*public*/ void OffsetCurveBuilder::getLineCurve(const CoordinateSequence* inputPts, - double nDistance, std::vector& lineList) + double nDistance, std::vector>& lineList) { distance = nDistance; @@ -112,7 +112,7 @@ void OffsetCurveBuilder::getOffsetCurve( const CoordinateSequence* inputPts, double p_distance, - std::vector& lineList) + std::vector>& lineList) { distance = p_distance; @@ -133,7 +133,7 @@ OffsetCurveBuilder::getOffsetCurve( // for right side line is traversed in reverse direction, so have to reverse generated line if (isRightSide) { - for (auto* cs: lineList) { + for (auto& cs: lineList) { cs->reverse(); } } @@ -234,7 +234,7 @@ OffsetCurveBuilder::computePointCurve(const Coordinate& pt, /*public*/ void OffsetCurveBuilder::getSingleSidedLineCurve(const CoordinateSequence* inputPts, - double p_distance, std::vector& lineList, bool leftSide, + double p_distance, std::vector>& lineList, bool leftSide, bool rightSide) { // A zero or negative width buffer of a line/point is empty. @@ -311,13 +311,13 @@ OffsetCurveBuilder::isLineOffsetEmpty(double p_distance) void OffsetCurveBuilder::getRingCurve(const CoordinateSequence* inputPts, int side, double nDistance, - std::vector& lineList) + std::vector>& lineList) { distance = nDistance; // optimize creating ring for zero distance if(distance == 0.0) { - lineList.push_back(inputPts->clone().release()); + lineList.push_back(inputPts->clone()); return; } diff --git a/src/operation/overlayng/Edge.cpp b/src/operation/overlayng/Edge.cpp index fce8b1e58..7f231d722 100644 --- a/src/operation/overlayng/Edge.cpp +++ b/src/operation/overlayng/Edge.cpp @@ -27,14 +27,14 @@ using namespace geos::geom; using geos::util::GEOSException; /*public*/ -Edge::Edge(std::unique_ptr&& p_pts, const EdgeSourceInfo* info) +Edge::Edge(const std::shared_ptr& p_pts, const EdgeSourceInfo* info) : aDim(OverlayLabel::DIM_UNKNOWN) , aDepthDelta(0) , aIsHole(false) , bDim(OverlayLabel::DIM_UNKNOWN) , bDepthDelta(0) , bIsHole(false) - , pts(std::move(p_pts)) + , pts(p_pts) { copyInfo(info); } diff --git a/src/operation/overlayng/EdgeNodingBuilder.cpp b/src/operation/overlayng/EdgeNodingBuilder.cpp index 0800e8fcf..d63f4acb3 100644 --- a/src/operation/overlayng/EdgeNodingBuilder.cpp +++ b/src/operation/overlayng/EdgeNodingBuilder.cpp @@ -140,18 +140,17 @@ EdgeNodingBuilder::createEdges(std::vector>& segS std::vector createdEdges; for (auto& ss : segStrings) { - const CoordinateSequence* pts = ss->getCoordinates(); + const auto& pts = ss->getCoordinates(); // don't create edges from collapsed lines - if (Edge::isCollapsed(pts)) continue; + if (Edge::isCollapsed(pts.get())) continue; // This EdgeSourceInfo is already managed locally in a std::deque const EdgeSourceInfo* info = static_cast(ss->getData()); // Record that a non-collapsed edge exists for the parent geometry hasEdges[info->getIndex()] = true; // Allocate the new Edge locally in a std::deque - NodedSegmentString* nss = detail::down_cast(ss.get()); - edgeQue.emplace_back(nss->releaseCoordinates(), info); + edgeQue.emplace_back(ss->getCoordinates(), info); Edge* newEdge = &(edgeQue.back()); createdEdges.push_back(newEdge); } @@ -287,7 +286,7 @@ EdgeNodingBuilder::addEdge(std::unique_ptr& cas, const EdgeS // TODO: manage these internally to EdgeNodingBuilder in a std::deque, // since they do not have a life span longer than the EdgeNodingBuilder // in OverlayNG::buildGraph() - NodedSegmentString* ss = new NodedSegmentString(cas.release(), inputHasZ, inputHasM, reinterpret_cast(info)); + NodedSegmentString* ss = new NodedSegmentString(std::move(cas), inputHasZ, inputHasM, reinterpret_cast(info)); inputEdges->push_back(ss); } diff --git a/src/operation/overlayng/OverlayEdge.cpp b/src/operation/overlayng/OverlayEdge.cpp index a7e95c10f..8716e1503 100644 --- a/src/operation/overlayng/OverlayEdge.cpp +++ b/src/operation/overlayng/OverlayEdge.cpp @@ -31,11 +31,11 @@ namespace operation { // geos.operation namespace overlayng { // geos.operation.overlayng /*public*/ -std::unique_ptr -OverlayEdge::getCoordinatesOriented() +std::shared_ptr +OverlayEdge::getCoordinatesOriented() const { if (direction) { - return pts->clone(); + return pts; } std::unique_ptr ptsCopy = pts->clone(); ptsCopy->reverse(); diff --git a/src/operation/overlayng/OverlayGraph.cpp b/src/operation/overlayng/OverlayGraph.cpp index 01ce395b0..a58983e21 100644 --- a/src/operation/overlayng/OverlayGraph.cpp +++ b/src/operation/overlayng/OverlayGraph.cpp @@ -83,7 +83,7 @@ OverlayEdge* OverlayGraph::addEdge(Edge* edge) { // CoordinateSequence* pts = = edge->getCoordinates().release(); - CoordinateSequence* pts = edge->releaseCoordinates(); + std::shared_ptr pts = edge->releaseCoordinates(); OverlayEdge* e = createEdgePair(pts, createOverlayLabel(edge)); #if GEOS_DEBUG std::cerr << "added edge: " << *e << std::endl; @@ -95,9 +95,8 @@ OverlayGraph::addEdge(Edge* edge) /*private*/ OverlayEdge* -OverlayGraph::createEdgePair(const CoordinateSequence *pts, OverlayLabel *lbl) +OverlayGraph::createEdgePair(const std::shared_ptr& pts, OverlayLabel *lbl) { - csQue.emplace_back(const_cast(pts)); OverlayEdge* e0 = createOverlayEdge(pts, lbl, true); OverlayEdge* e1 = createOverlayEdge(pts, lbl, false); e0->link(e1); @@ -106,7 +105,7 @@ OverlayGraph::createEdgePair(const CoordinateSequence *pts, OverlayLabel *lbl) /*private*/ OverlayEdge* -OverlayGraph::createOverlayEdge(const CoordinateSequence* pts, OverlayLabel* lbl, bool direction) +OverlayGraph::createOverlayEdge(const std::shared_ptr& pts, OverlayLabel* lbl, bool direction) { CoordinateXYZM origin; CoordinateXYZM dirPt; diff --git a/src/operation/overlayng/OverlayUtil.cpp b/src/operation/overlayng/OverlayUtil.cpp index 0f77d1da8..23b07f22e 100644 --- a/src/operation/overlayng/OverlayUtil.cpp +++ b/src/operation/overlayng/OverlayUtil.cpp @@ -311,8 +311,8 @@ OverlayUtil::toLines(OverlayGraph* graph, bool isOutputEdges, const GeometryFact bool includeEdge = isOutputEdges || edge->isInResultArea(); if (! includeEdge) continue; - std::unique_ptr pts = edge->getCoordinatesOriented(); - std::unique_ptr line = geomFact->createLineString(std::move(pts)); + std::shared_ptr pts = edge->getCoordinatesOriented(); + std::unique_ptr line = geomFact->createLineString(pts); // line->setUserData(labelForResult(edge)); lines.push_back(std::move(line)); } diff --git a/src/operation/relateng/EdgeSetIntersector.cpp b/src/operation/relateng/EdgeSetIntersector.cpp index 5a33ef387..c512884c5 100644 --- a/src/operation/relateng/EdgeSetIntersector.cpp +++ b/src/operation/relateng/EdgeSetIntersector.cpp @@ -51,7 +51,7 @@ void EdgeSetIntersector::addToIndex(const SegmentString* segStr) { std::vector segChains; - MonotoneChainBuilder::getChains(segStr->getCoordinates(), const_cast(segStr), segChains); + MonotoneChainBuilder::getChains(segStr->getCoordinates().get(), const_cast(segStr), segChains); for (MonotoneChain& mc : segChains) { if (envelope == nullptr || envelope->intersects(mc.getEnvelope())) { diff --git a/src/operation/relateng/RelateGeometry.cpp b/src/operation/relateng/RelateGeometry.cpp index df00ad594..a54271f4b 100644 --- a/src/operation/relateng/RelateGeometry.cpp +++ b/src/operation/relateng/RelateGeometry.cpp @@ -404,9 +404,8 @@ RelateGeometry::extractSegmentStringsFromAtomic(bool isA, const LineString* line = static_cast(p_geom); /* * Condition the input Coordinate sequence so that it has no repeated points. - * This requires taking a copy which removeRepeated does behind the scenes and stores in csStore. */ - const CoordinateSequence* cs = removeRepeated(line->getCoordinatesRO()); + std::shared_ptr cs = removeRepeated(line->getSharedCoordinates()); auto ss = RelateSegmentString::createLine(cs, isA, elementId, this); segStore.emplace_back(ss); segStrings.push_back(ss); @@ -441,11 +440,11 @@ RelateGeometry::extractRingToSegmentString(bool isA, /* * Condition the input Coordinate sequence so that it has no repeated points - * and is oriented in a deterministic way. This requires taking a copy which - * orientAndRemoveRepeated does behind the scenes and stores in csStore. + * and is oriented in a deterministic way. This may require taking a copy which + * orientAndRemoveRepeated does behind the scenes. */ bool requireCW = (ringId == 0); - const CoordinateSequence* cs = orientAndRemoveRepeated(ring->getCoordinatesRO(), requireCW); + std::shared_ptr cs = orientAndRemoveRepeated(ring->getSharedCoordinates(), requireCW); auto ss = RelateSegmentString::createRing(cs, isA, elementId, ringId, parentPoly, this); segStore.emplace_back(ss); segStrings.push_back(ss); @@ -471,10 +470,10 @@ operator<<(std::ostream& os, const RelateGeometry& rg) /* private */ -const CoordinateSequence * -RelateGeometry::orientAndRemoveRepeated(const CoordinateSequence *seq, bool orientCW) +std::shared_ptr +RelateGeometry::orientAndRemoveRepeated(const std::shared_ptr& seq, bool orientCW) { - bool isFlipped = (orientCW == Orientation::isCCW(seq)); + bool isFlipped = (orientCW == Orientation::isCCW(seq.get())); bool hasRepeated = seq->hasRepeatedPoints(); /* Already conditioned */ if (!isFlipped && !hasRepeated) { @@ -482,36 +481,29 @@ RelateGeometry::orientAndRemoveRepeated(const CoordinateSequence *seq, bool orie } if (hasRepeated) { - auto deduped = RepeatedPointRemover::removeRepeatedPoints(seq); + auto deduped = RepeatedPointRemover::removeRepeatedPoints(seq.get()); if (isFlipped) deduped->reverse(); - CoordinateSequence* cs = deduped.release(); - csStore.emplace_back(cs); - return cs; + return deduped; } if (isFlipped) { auto reversed = seq->clone(); reversed->reverse(); - CoordinateSequence* cs = reversed.release(); - csStore.emplace_back(cs); - return cs; + return reversed; } return seq; } /* private */ -const CoordinateSequence * -RelateGeometry::removeRepeated(const CoordinateSequence *seq) +std::shared_ptr +RelateGeometry::removeRepeated(const std::shared_ptr& seq) { bool hasRepeated = seq->hasRepeatedPoints(); if (!hasRepeated) return seq; - auto deduped = RepeatedPointRemover::removeRepeatedPoints(seq); - CoordinateSequence* cs = deduped.release(); - csStore.emplace_back(cs); - return cs; + return RepeatedPointRemover::removeRepeatedPoints(seq.get()); } diff --git a/src/operation/relateng/RelateSegmentString.cpp b/src/operation/relateng/RelateSegmentString.cpp index 41c0c4bbf..5325da2ee 100644 --- a/src/operation/relateng/RelateSegmentString.cpp +++ b/src/operation/relateng/RelateSegmentString.cpp @@ -39,7 +39,7 @@ namespace relateng { // geos.operation.relateng /* public static */ const RelateSegmentString* RelateSegmentString::createLine( - const CoordinateSequence* pts, + const std::shared_ptr& pts, bool isA, int elementId, const RelateGeometry* parent) { @@ -50,7 +50,7 @@ RelateSegmentString::createLine( /* public static */ const RelateSegmentString* RelateSegmentString::createRing( - const CoordinateSequence* pts, + const std::shared_ptr& pts, bool isA, int elementId, int ringId, const Geometry* poly, const RelateGeometry* parent) { @@ -61,7 +61,7 @@ RelateSegmentString::createRing( /* private static */ const RelateSegmentString* RelateSegmentString::createSegmentString( - const CoordinateSequence* pts, + const std::shared_ptr& pts, bool isA, int dim, int elementId, int ringId, const Geometry* poly, const RelateGeometry* parent) { @@ -71,7 +71,7 @@ RelateSegmentString::createSegmentString( /* public */ NodeSection* -RelateSegmentString::createNodeSection(std::size_t segIndex, const CoordinateXY intPt) const +RelateSegmentString::createNodeSection(std::size_t segIndex, const CoordinateXY& intPt) const { const CoordinateXY& c0 = getCoordinate(segIndex); const CoordinateXY& c1 = getCoordinate(segIndex + 1); diff --git a/src/operation/valid/IsSimpleOp.cpp b/src/operation/valid/IsSimpleOp.cpp index 2a5d136f8..e7bea5442 100644 --- a/src/operation/valid/IsSimpleOp.cpp +++ b/src/operation/valid/IsSimpleOp.cpp @@ -224,15 +224,19 @@ IsSimpleOp::isSimpleLinearGeometry(const Geometry& geom) } /* private static */ -std::vector> +std::vector> IsSimpleOp::removeRepeatedPts(const Geometry& geom) { - std::vector> coordseqs; + std::vector> coordseqs; for (std::size_t i = 0, sz = geom.getNumGeometries(); i < sz; i++) { const LineString* line = dynamic_cast(geom.getGeometryN(i)); if (line) { - auto ptsNoRepeat = RepeatedPointRemover::removeRepeatedPoints(line->getCoordinatesRO()); - coordseqs.emplace_back(ptsNoRepeat.release()); + auto pts = line->getSharedCoordinates(); + if (pts->hasRepeatedPoints()) { + pts = RepeatedPointRemover::removeRepeatedPoints(line->getCoordinatesRO()); + } + + coordseqs.push_back(pts); } } return coordseqs; @@ -240,12 +244,12 @@ IsSimpleOp::removeRepeatedPts(const Geometry& geom) /* private static */ std::vector> -IsSimpleOp::createSegmentStrings(std::vector>& seqs) +IsSimpleOp::createSegmentStrings(std::vector>& seqs) { std::vector> segStrings; for (auto& seq : seqs) { BasicSegmentString* bss = new BasicSegmentString( - seq.get(), + seq, nullptr); segStrings.emplace_back(static_cast(bss)); } diff --git a/src/operation/valid/PolygonTopologyAnalyzer.cpp b/src/operation/valid/PolygonTopologyAnalyzer.cpp index 121d4f5ce..2a65cbc16 100644 --- a/src/operation/valid/PolygonTopologyAnalyzer.cpp +++ b/src/operation/valid/PolygonTopologyAnalyzer.cpp @@ -320,15 +320,14 @@ PolygonTopologyAnalyzer::createSegString(const LinearRing* ring, const PolygonRi // Let the input LinearRing retain ownership of the // CoordinateSequence, and pass it directly into the BasicSegmentString // constructor. - CoordinateSequence* pts = const_cast(ring->getCoordinatesRO()); + std::shared_ptr pts = ring->getSharedCoordinates(); // Repeated points must be removed for accurate intersection detection - // So, in this case we create a de-duped copy of the CoordinateSequence - // and manage the lifecycle locally. This we pass on to the SegmentString + // So, in this case we create a de-duped copy of the CoordinateSequence. + // This we pass on to the SegmentString. if (pts->hasRepeatedPoints()) { - std::unique_ptr newPts = RepeatedPointRemover::removeRepeatedPoints(pts); - pts = newPts.get(); - coordSeqStore.emplace_back(newPts.release()); + std::unique_ptr newPts = RepeatedPointRemover::removeRepeatedPoints(pts.get()); + pts = std::move(newPts); } // Allocate the BasicSegmentString in the store and return a diff --git a/src/triangulate/polygon/PolygonHoleJoiner.cpp b/src/triangulate/polygon/PolygonHoleJoiner.cpp index 239491672..fc453def7 100644 --- a/src/triangulate/polygon/PolygonHoleJoiner.cpp +++ b/src/triangulate/polygon/PolygonHoleJoiner.cpp @@ -142,18 +142,20 @@ PolygonHoleJoiner::extractOrientedRings(const Polygon* polygon) std::vector holes = sortHoles(polygon); for (const LinearRing* hole : holes) { auto oHole = extractOrientedRing(hole, false); - holeRings.emplace_back(oHole.release()); + holeRings.emplace_back(oHole); } } /* private static */ -std::unique_ptr +std::shared_ptr PolygonHoleJoiner::extractOrientedRing(const LinearRing* ring, bool isCW) { - std::unique_ptr pts = ring->getCoordinates(); + auto pts = ring->getSharedCoordinates(); bool isRingCW = ! Orientation::isCCW(pts.get()); if (isCW != isRingCW) { - pts->reverse(); + auto reversed = pts->clone(); + reversed->reverse(); + pts = std::move(reversed); } return pts; } @@ -408,8 +410,9 @@ PolygonHoleJoiner::findLowestLeftVertexIndex(const CoordinateSequence& holeCoord bool PolygonHoleJoiner::intersectsBoundary(const Coordinate& p0, const Coordinate& p1) { - CoordinateSequence cs { p0, p1 }; - BasicSegmentString bss(&cs, nullptr); + auto cs = std::make_shared(std::initializer_list{p0, p1}); + + BasicSegmentString bss(cs, nullptr); std::vector segStrings { &bss }; InteriorIntersectionDetector segInt; @@ -425,11 +428,11 @@ PolygonHoleJoiner::createBoundaryIntersector() { std::vector polySegStrings; polySegStringStore.clear(); - BasicSegmentString* bss = new BasicSegmentString(shellRing.get(), nullptr); + BasicSegmentString* bss = new BasicSegmentString(shellRing, nullptr); polySegStringStore.emplace_back(bss); polySegStrings.push_back(bss); for (auto& hole : holeRings) { - bss = new BasicSegmentString(hole.get(), nullptr); + bss = new BasicSegmentString(hole, nullptr); polySegStringStore.emplace_back(bss); polySegStrings.push_back(bss); } diff --git a/src/triangulate/polygon/PolygonNoder.cpp b/src/triangulate/polygon/PolygonNoder.cpp index 08462469e..51abcd845 100644 --- a/src/triangulate/polygon/PolygonNoder.cpp +++ b/src/triangulate/polygon/PolygonNoder.cpp @@ -37,8 +37,8 @@ namespace polygon { PolygonNoder::PolygonNoder( - std::unique_ptr& shellRing, - std::vector>& holeRings) + const std::shared_ptr& shellRing, + const std::vector>& holeRings) { isHoleTouching.resize(holeRings.size(), false); createNodedSegmentStrings(shellRing, holeRings); @@ -172,8 +172,8 @@ PolygonNoder::getHolesTouching() /* private */ void PolygonNoder::createNodedSegmentStrings( - std::unique_ptr& shellRing, - std::vector>& holeRings) + const std::shared_ptr& shellRing, + const std::vector>& holeRings) { nodedRings.emplace_back(createNodedSegString(shellRing, 0)); for (std::size_t i = 1; i <= holeRings.size(); i++) { @@ -184,12 +184,12 @@ PolygonNoder::createNodedSegmentStrings( /* private */ NodedSegmentString* -PolygonNoder::createNodedSegString(std::unique_ptr& ringPts, std::size_t i) +PolygonNoder::createNodedSegString(const std::shared_ptr& ringPts, std::size_t i) { // note: in PolygonHoleJoiner::nodeRings we will replace the contents // of the shellRing and holeRings with the results of the calculation // here, so it's OK to take ownership of the points from them here - NodedSegmentString* nss = new NodedSegmentString(ringPts.release(), false, false, nullptr); + NodedSegmentString* nss = new NodedSegmentString(ringPts, false, false, nullptr); nss->setData(nss); // need to map the identity of this nss to the index number of the // ring it represents. use an external map to avoid abusing the void* diff --git a/tests/unit/geom/LineStringTest.cpp b/tests/unit/geom/LineStringTest.cpp index 930f8885a..33d74af9d 100644 --- a/tests/unit/geom/LineStringTest.cpp +++ b/tests/unit/geom/LineStringTest.cpp @@ -7,6 +7,7 @@ // geos #include #include +#include #include #include #include @@ -22,6 +23,8 @@ #include #include +using geos::geom::CoordinateXY; + namespace tut { // // Test Group @@ -533,7 +536,7 @@ void object::test<29> ensure(c != nullptr); } -// releaseCoordinates +// getSharedCoordinates template<> template<> void object::test<30>() @@ -542,8 +545,21 @@ void object::test<30>() auto env = ls->getEnvelopeInternal(); ensure_equals(*env, geos::geom::Envelope(0,10, 0, 10)); - auto cs = ls->releaseCoordinates(); + auto cs = ls->getSharedCoordinates(); ensure_equals(cs->getSize(), 2u); + + struct AddFive : public geos::geom::CoordinateFilter { + void filter_rw(CoordinateXY* pt) const override { + pt->x += 5; + pt->y += 5; + } + }; + + AddFive filter; + ls->apply_rw(&filter); + + ensure_equals(cs->getAt(0), CoordinateXY(0, 0)); + ensure_equals(cs->getAt(1), CoordinateXY(10, 10)); } // Test of LinearRing constructor with a NaN coordinate diff --git a/tests/unit/geom/LinearRingTest.cpp b/tests/unit/geom/LinearRingTest.cpp index 80314767f..81f503e04 100644 --- a/tests/unit/geom/LinearRingTest.cpp +++ b/tests/unit/geom/LinearRingTest.cpp @@ -497,6 +497,34 @@ void object::test<35> } } +template<> +template<> +void object::test<36>() +{ + set_test_name("LinearRing::orient modifies coordinates in-place if there are no external references"); + auto lr = reader_.read("LINEARRING(0 0, 1 0, 1 1, 0 1, 0 0)"); + auto seq0 = lr->getCoordinatesRO(); + + lr->orient(false); + ensure_equals(lr->getCoordinatesRO(), seq0); + lr->orient(true); + ensure_equals(lr->getCoordinatesRO(), seq0); +} + +template<> +template<> +void object::test<37>() +{ + set_test_name("LinearRing::orient does not modify coordinates in-place if there are external references"); + + auto lr = reader_.read("LINEARRING(0 0, 1 0, 1 1, 0 1, 0 0)"); + auto seq0 = lr->getSharedCoordinates(); + + lr->orient(false); + ensure_equals(lr->getCoordinatesRO(), seq0.get()); + lr->orient(true); + ensure(lr->getCoordinatesRO() != seq0.get()); +} } // namespace tut diff --git a/tests/unit/noding/BasicSegmentStringTest.cpp b/tests/unit/noding/BasicSegmentStringTest.cpp index 808383c64..4abc8f4ea 100644 --- a/tests/unit/noding/BasicSegmentStringTest.cpp +++ b/tests/unit/noding/BasicSegmentStringTest.cpp @@ -26,7 +26,7 @@ struct test_basicsegmentstring_data { SegmentStringAutoPtr; SegmentStringAutoPtr - makeSegmentString(geos::geom::CoordinateSequence* cs, void* d = nullptr) + makeSegmentString(std::shared_ptr cs, void* d = nullptr) { return SegmentStringAutoPtr( new geos::noding::BasicSegmentString(cs, d) @@ -58,7 +58,7 @@ template<> void object::test<1> () { - auto cs = geos::detail::make_unique(0u, 2u); + auto cs = std::make_shared(0u, 2u); ensure(nullptr != cs.get()); @@ -70,14 +70,14 @@ void object::test<1> ensure_equals(cs->size(), 2u); - SegmentStringAutoPtr ss(makeSegmentString(cs.get())); + SegmentStringAutoPtr ss(makeSegmentString(cs)); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 2u); ensure_equals(ss->getData(), (void*)nullptr); - ensure_equals(ss->getCoordinates(), cs.get()); + ensure_equals(ss->getCoordinates().get(), cs.get()); ensure_equals(ss->getCoordinate(0), c0); @@ -103,7 +103,7 @@ template<> void object::test<2> () { - auto cs = geos::detail::make_unique(0u, 2u); + auto cs = std::make_shared(0u, 2u); ensure(nullptr != cs.get()); @@ -115,14 +115,14 @@ void object::test<2> ensure_equals(cs->size(), 2u); - SegmentStringAutoPtr ss(makeSegmentString(cs.get())); + SegmentStringAutoPtr ss(makeSegmentString(cs)); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 2u); ensure_equals(ss->getData(), (void*)nullptr); - ensure_equals(ss->getCoordinates(), cs.get()); + ensure_equals(ss->getCoordinates().get(), cs.get()); ensure_equals(ss->getCoordinate(0), c0); @@ -140,7 +140,7 @@ template<> void object::test<3> () { - auto cs = geos::detail::make_unique(0u, 2u); + auto cs = std::make_shared(0u, 2u); ensure(nullptr != cs.get()); @@ -155,14 +155,14 @@ void object::test<3> ensure_equals(cs->size(), 4u); - SegmentStringAutoPtr ss(makeSegmentString(cs.get())); + SegmentStringAutoPtr ss(makeSegmentString(cs)); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 4u); ensure_equals(ss->getData(), (void*)nullptr); - ensure_equals(ss->getCoordinates(), cs.get()); + ensure_equals(ss->getCoordinates().get(), cs.get()); ensure_equals(ss->getCoordinate(0), c0); diff --git a/tests/unit/noding/NodedSegmentStringTest.cpp b/tests/unit/noding/NodedSegmentStringTest.cpp index 26f8cc904..f4dd858ba 100644 --- a/tests/unit/noding/NodedSegmentStringTest.cpp +++ b/tests/unit/noding/NodedSegmentStringTest.cpp @@ -38,10 +38,10 @@ struct test_nodedsegmentstring_data { WKTReader r; SegmentStringAutoPtr - makeSegmentString(geos::geom::CoordinateSequence* cs, void* d = nullptr) + makeSegmentString(std::unique_ptr cs, void* d = nullptr) { return SegmentStringAutoPtr( - new geos::noding::NodedSegmentString(cs, true, false, d) + new geos::noding::NodedSegmentString(std::move(cs), true, false, d) ); } @@ -65,7 +65,7 @@ struct test_nodedsegmentstring_data { std::unique_ptr line = r.read(wktLine); std::unique_ptr pts = r.read(wktNodes); - NodedSegmentString nss(line->getCoordinates().release(), true, false, 0); + NodedSegmentString nss(line->getCoordinates(), true, false, 0); std::unique_ptr node = pts->getCoordinates(); for (std::size_t i = 0, n=node->size(); i < n; ++i) { @@ -116,7 +116,7 @@ void object::test<1> ensure_equals(cs->size(), 2u); - SegmentStringAutoPtr ss(makeSegmentString(cs.release())); + SegmentStringAutoPtr ss(makeSegmentString(std::move(cs))); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 2u); @@ -152,7 +152,7 @@ void object::test<2> ensure_equals(cs->size(), 2u); - SegmentStringAutoPtr ss(makeSegmentString(cs.release())); + SegmentStringAutoPtr ss(makeSegmentString(std::move(cs))); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 2u); @@ -191,7 +191,7 @@ void object::test<3> ensure_equals(cs->size(), 4u); - SegmentStringAutoPtr ss(makeSegmentString(cs.release())); + SegmentStringAutoPtr ss(makeSegmentString(std::move(cs))); ensure(nullptr != ss.get()); ensure_equals(ss->size(), 4u); @@ -253,7 +253,7 @@ void object::test<5> cs->add(p0); cs->add(p1); - SegmentStringAutoPtr ss(makeSegmentString(cs.release())); + SegmentStringAutoPtr ss(makeSegmentString(std::move(cs))); ensure_equals(ss->getNodeList().size(), 0u); diff --git a/tests/unit/noding/SegmentNodeTest.cpp b/tests/unit/noding/SegmentNodeTest.cpp index 8b71af518..4cb9e7098 100644 --- a/tests/unit/noding/SegmentNodeTest.cpp +++ b/tests/unit/noding/SegmentNodeTest.cpp @@ -50,7 +50,7 @@ void object::test<1> // Create coordinates sequence const std::size_t coords_size = 2; - auto cs = geos::detail::make_unique(0u, coords_size); + auto cs = std::make_unique(0u, coords_size); ensure(nullptr != cs.get()); @@ -63,7 +63,7 @@ void object::test<1> // Create SegmentString instance - NodedSegmentString segment(cs.release(), false, false, nullptr); + NodedSegmentString segment(std::move(cs), false, false, nullptr); ensure_equals(segment.size(), coords_size); @@ -99,7 +99,7 @@ void object::test<2> // Create coordinates sequence const std::size_t coords_size = 2; - auto cs = geos::detail::make_unique(0u, coords_size); + auto cs = std::make_unique(0u, coords_size); ensure(nullptr != cs.get()); @@ -112,7 +112,7 @@ void object::test<2> // Create SegmentString instance - NodedSegmentString segment(cs.release(), false, false, nullptr); + NodedSegmentString segment(std::move(cs), false, false, nullptr); ensure_equals(segment.size(), coords_size); @@ -142,7 +142,7 @@ void object::test<3> // Create coordinates sequence const std::size_t coords_size = 2; - auto cs = geos::detail::make_unique(0u, coords_size); + auto cs = std::make_unique(0u, coords_size); ensure(nullptr != cs.get()); @@ -155,7 +155,7 @@ void object::test<3> // Create SegmentString instance - NodedSegmentString segment(cs.release(), false, false, nullptr); + NodedSegmentString segment(std::move(cs), false, false, nullptr); ensure_equals(segment.size(), coords_size); @@ -185,7 +185,7 @@ void object::test<4> // Create coordinates sequence const std::size_t coords_size = 2; - auto cs = geos::detail::make_unique(0u, coords_size); + auto cs = std::make_unique(0u, coords_size); ensure(nullptr != cs.get()); @@ -198,7 +198,7 @@ void object::test<4> // Create SegmentString instance - NodedSegmentString segment(cs.release(), false, false, nullptr); + NodedSegmentString segment(std::move(cs), false, false, nullptr); ensure_equals(segment.size(), coords_size); diff --git a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp index d9d569a69..177f44e93 100644 --- a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp +++ b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp @@ -69,7 +69,7 @@ struct test_mcidxsnprndr_data { getSegmentStrings(const Geometry& g, SegStrVct& vct) { CoordSeqPtr s(g.getCoordinates()); - vct.push_back(new NodedSegmentString(s.release(), g.hasZ(), g.hasM(), nullptr)); + vct.push_back(new NodedSegmentString(std::move(s), g.hasZ(), g.hasM(), nullptr)); } GeomPtr diff --git a/tests/unit/util/NodingTestUtil.cpp b/tests/unit/util/NodingTestUtil.cpp index edb0b8072..dd6819f01 100644 --- a/tests/unit/util/NodingTestUtil.cpp +++ b/tests/unit/util/NodingTestUtil.cpp @@ -31,11 +31,8 @@ NodingTestUtil::toLines(const std::vector& nodedList, const Geom std::vector> lines; for (auto nss : nodedList) { - CoordinateSequence* pts = nss->getCoordinates(); - // pts is owned by nss, so we make a copy to build the line - // on top of. Lines are 100% self-contained and own all their parts. - // Input nodedList can be freed. - lines.emplace_back(geomFact->createLineString(pts->clone())); + const auto& pts = nss->getCoordinates(); + lines.emplace_back(geomFact->createLineString(pts)); } if (lines.size() == 1) return std::move(lines[0]); @@ -62,7 +59,7 @@ NodingTestUtil::toSegmentStrings(std::vector& lines) // into a unique_ptr<> which we have to release() to the // NodedSegmentString constructor, so // nss now owns nss->pts - NodedSegmentString* nss = new NodedSegmentString(line->getCoordinates().release(), constructZ, constructM, line); + NodedSegmentString* nss = new NodedSegmentString(line->getCoordinates(), constructZ, constructM, line); nssList.push_back(nss); } return nssList; ----------------------------------------------------------------------- Summary of changes: include/geos/coverage/CoverageCleaner.h | 2 +- include/geos/coverage/CoverageEdge.h | 12 +++--- include/geos/coverage/CoveragePolygonValidator.h | 1 - include/geos/coverage/CoverageRing.h | 2 +- include/geos/geom/CircularString.h | 3 ++ include/geos/geom/GeometryFactory.h | 11 ++++++ include/geos/geom/LineString.h | 3 ++ include/geos/geom/LinearRing.h | 3 ++ include/geos/geom/SimpleCurve.h | 19 ++++------ include/geos/geomgraph/EdgeNodingValidator.h | 7 ---- include/geos/noding/BasicSegmentString.h | 2 +- include/geos/noding/NodableSegmentString.h | 2 +- include/geos/noding/NodedSegmentString.h | 7 +--- include/geos/noding/SegmentNodeList.h | 2 +- include/geos/noding/SegmentString.h | 13 +++---- include/geos/noding/SegmentStringUtil.h | 4 +- include/geos/noding/snap/SnappingNoder.h | 2 +- .../geos/operation/buffer/BufferCurveSetBuilder.h | 4 +- include/geos/operation/buffer/OffsetCurveBuilder.h | 9 ++--- .../geos/operation/buffer/OffsetSegmentGenerator.h | 4 +- include/geos/operation/overlayng/Edge.h | 11 +++--- include/geos/operation/overlayng/OverlayEdge.h | 14 ++----- include/geos/operation/overlayng/OverlayGraph.h | 6 +-- include/geos/operation/relateng/RelateGeometry.h | 9 ++--- .../geos/operation/relateng/RelateSegmentString.h | 16 ++++---- include/geos/operation/valid/IsSimpleOp.h | 4 +- .../geos/operation/valid/PolygonTopologyAnalyzer.h | 5 --- .../geos/triangulate/polygon/PolygonHoleJoiner.h | 6 +-- include/geos/triangulate/polygon/PolygonNoder.h | 10 ++--- src/algorithm/MinimumDiameter.cpp | 2 +- src/coverage/CoverageCleaner.cpp | 4 +- src/coverage/CoverageEdge.cpp | 10 ++--- src/coverage/CoveragePolygonValidator.cpp | 9 ++--- src/coverage/CoverageRing.cpp | 10 +---- src/coverage/CoverageRingEdges.cpp | 2 +- src/coverage/CoverageSimplifier.cpp | 2 +- src/dissolve/LineDissolver.cpp | 1 + src/geom/CircularString.cpp | 8 ++++ src/geom/GeometryFactory.cpp | 27 ++++++++++++++ src/geom/LineString.cpp | 9 +++++ src/geom/LinearRing.cpp | 15 +++++++- src/geom/Polygon.cpp | 2 +- src/geom/SimpleCurve.cpp | 43 +++++++++++++++------- src/geom/util/CoordinateOperation.cpp | 4 +- src/geomgraph/EdgeNodingValidator.cpp | 6 +-- src/noding/BoundaryChainNoder.cpp | 12 ++---- src/noding/GeometryNoder.cpp | 9 ++--- src/noding/MCIndexNoder.cpp | 2 +- src/noding/MCIndexSegmentSetMutualIntersector.cpp | 4 +- src/noding/NodedSegmentString.cpp | 8 ---- src/noding/ScaledNoder.cpp | 14 ++++--- src/noding/SegmentExtractingNoder.cpp | 6 +-- src/noding/SegmentNodeList.cpp | 18 ++++----- src/noding/SimpleNoder.cpp | 4 +- src/noding/snap/SnappingNoder.cpp | 14 +++---- src/noding/snapround/MCIndexSnapRounder.cpp | 2 +- src/noding/snapround/SnapRoundingNoder.cpp | 8 ++-- src/operation/buffer/BufferBuilder.cpp | 12 +++--- src/operation/buffer/BufferCurveSetBuilder.cpp | 26 ++++++------- src/operation/buffer/OffsetCurveBuilder.cpp | 12 +++--- src/operation/overlayng/Edge.cpp | 4 +- src/operation/overlayng/EdgeNodingBuilder.cpp | 9 ++--- src/operation/overlayng/OverlayEdge.cpp | 6 +-- src/operation/overlayng/OverlayGraph.cpp | 7 ++-- src/operation/overlayng/OverlayUtil.cpp | 4 +- src/operation/relateng/EdgeSetIntersector.cpp | 2 +- src/operation/relateng/RelateGeometry.cpp | 34 +++++++---------- src/operation/relateng/RelateSegmentString.cpp | 8 ++-- src/operation/valid/IsSimpleOp.cpp | 16 +++++--- src/operation/valid/PolygonTopologyAnalyzer.cpp | 11 +++--- src/triangulate/polygon/PolygonHoleJoiner.cpp | 19 ++++++---- src/triangulate/polygon/PolygonNoder.cpp | 12 +++--- tests/unit/geom/LineStringTest.cpp | 20 +++++++++- tests/unit/geom/LinearRingTest.cpp | 28 ++++++++++++++ tests/unit/noding/BasicSegmentStringTest.cpp | 20 +++++----- tests/unit/noding/NodedSegmentStringTest.cpp | 14 +++---- tests/unit/noding/SegmentNodeTest.cpp | 16 ++++---- .../noding/snapround/MCIndexSnapRounderTest.cpp | 2 +- tests/unit/util/NodingTestUtil.cpp | 9 ++--- 79 files changed, 408 insertions(+), 331 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 06:48:47 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 06:48:47 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.14 updated. 25e08d264b9a1eb2267e76207da7995cf8c8254c Message-ID: <20251216144847.3A4D41A5E09@trac.osgeo.org> 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.14 has been updated via 25e08d264b9a1eb2267e76207da7995cf8c8254c (commit) from d7d33e311a0f1383011ed127b54baa1c3befbb68 (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 25e08d264b9a1eb2267e76207da7995cf8c8254c Author: Daniel Baston Date: Tue Dec 2 08:42:23 2025 -0500 BufferOp: Avoid crash on geometry with only invalid coordinates diff --git a/NEWS.md b/NEWS.md index 712f49a09..c77fa6a50 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ - Fixes/Improvements: - Relax other floating-point exception handling with other compilers (GH-1333, Mike Taves) - Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection (GH-1235, Paul Ramsey) + - Avoid crash on buffer of geometry with only invalid coordinates (GH-1335, Dan Baston) ## Changes in 3.14.1 2025-10-27 diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index 7fc39e77c..bde2aacf4 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -201,6 +201,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->isEmpty()) { + throw util::GEOSException("LineString has no valid points."); + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index b51914ca8..7c78fa41e 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -3,6 +3,8 @@ // tut #include +#include + #include // geos #include @@ -20,6 +22,7 @@ #include #include + using namespace geos::operation::buffer; namespace tut { @@ -623,4 +626,19 @@ void object::test<28> "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))"); } +template<> +template<> +void object::test<31> +() +{ + set_test_name("buffer of line with only Inf coordinates"); + // See https://github.com/libgeos/geos/issues/1332 + + std::string wkt = "LINESTRING (Inf Inf, Inf Inf)"; + + auto geom = wktreader.read(wkt); + + ensure_THROW(geom->buffer(0.1), geos::util::GEOSException); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS.md | 1 + src/operation/buffer/BufferCurveSetBuilder.cpp | 4 ++++ tests/unit/operation/buffer/BufferOpTest.cpp | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 06:50:56 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 06:50:56 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.13 updated. 2bf492cf2c9915663f08f3fc7e7e7b3aef45f6d6 Message-ID: <20251216145056.BF47D1A5AB5@trac.osgeo.org> 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.13 has been updated via 2bf492cf2c9915663f08f3fc7e7e7b3aef45f6d6 (commit) from b41f45a16b5a0d6faee72a5eed3e739cbc727eba (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 2bf492cf2c9915663f08f3fc7e7e7b3aef45f6d6 Author: Daniel Baston Date: Tue Dec 16 09:50:30 2025 -0500 BufferOp: Avoid crash on geometry with only invalid coordinates diff --git a/NEWS.md b/NEWS.md index d413c6c81..cfb667dee 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,3 @@ - ## Changes in 3.13.2 2025-xx-xx @@ -9,6 +8,7 @@ - Change CoverageGapFinder to return polygons (Martin Davis) - Fix incorrect envelope calculation for arcs (GH-1314, Dan Baston) - Quiet FP_DIVBYZERO exception from CGAlgorithmsDD::intersection (GH-1235, Paul Ramsey) + - Avoid crash on buffer of geometry with only invalid coordinates (GH-1335, Dan Baston) ## Changes in 3.13.1 2025-03-03 diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index 7fc39e77c..bde2aacf4 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -201,6 +201,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->isEmpty()) { + throw util::GEOSException("LineString has no valid points."); + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index 39f8592bb..298eaf7c6 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -3,6 +3,8 @@ // tut #include +#include + #include // geos #include @@ -21,6 +23,7 @@ #include #include + using namespace geos::operation::buffer; namespace tut { @@ -624,4 +627,19 @@ void object::test<28> "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))"); } +template<> +template<> +void object::test<31> +() +{ + set_test_name("buffer of line with only Inf coordinates"); + // See https://github.com/libgeos/geos/issues/1332 + + std::string wkt = "LINESTRING (Inf Inf, Inf Inf)"; + + auto geom = wktreader.read(wkt); + + ensure_THROW(geom->buffer(0.1), geos::util::GEOSException); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS.md | 2 +- src/operation/buffer/BufferCurveSetBuilder.cpp | 4 ++++ tests/unit/operation/buffer/BufferOpTest.cpp | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 06:56:12 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 06:56:12 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.11 updated. 63930d5392860983292b421b258cbbba530191ac Message-ID: <20251216145612.51BE51A5075@trac.osgeo.org> 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 63930d5392860983292b421b258cbbba530191ac (commit) from 6efb5efe2f0f30b0834329aeb3283a81943436c2 (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 63930d5392860983292b421b258cbbba530191ac Author: Daniel Baston Date: Tue Dec 16 09:55:34 2025 -0500 BufferOp: Avoid crash on geometry with only invalid coordinates diff --git a/NEWS.md b/NEWS.md index e545f4296..b0a84ad35 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ - Fixes/Improvements: - Fix DepthSegment comparison logic (really this time) (GH-1266, Martin Davis) + - Avoid crash on buffer of geometry with only invalid coordinates (GH-1335, Dan Baston) ## Changes in 3.11.5 2025-03-03 diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index 787f1b5c6..5f3f3dbc6 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -199,6 +199,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->isEmpty()) { + throw util::GEOSException("LineString has no valid points."); + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index 1103a0b46..ed606ce5b 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -3,6 +3,8 @@ // tut #include +#include + #include // geos #include @@ -21,6 +23,7 @@ #include #include + using namespace geos::operation::buffer; using namespace geos::geom; @@ -673,4 +676,19 @@ void object::test<28> "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))"); } +template<> +template<> +void object::test<31> +() +{ + set_test_name("buffer of line with only Inf coordinates"); + // See https://github.com/libgeos/geos/issues/1332 + + std::string wkt = "LINESTRING (Inf Inf, Inf Inf)"; + + auto geom = wktreader.read(wkt); + + ensure_THROW(geom->buffer(0.1), geos::util::GEOSException); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS.md | 1 + src/operation/buffer/BufferCurveSetBuilder.cpp | 4 ++++ tests/unit/operation/buffer/BufferOpTest.cpp | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 06:56:14 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 06:56:14 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.12 updated. 3802326b4d063a41550d9fe411d891cdd52e68bc Message-ID: <20251216145614.409A61A5D9E@trac.osgeo.org> 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.12 has been updated via 3802326b4d063a41550d9fe411d891cdd52e68bc (commit) from 168d863da9ad23ca084372651d090afb242f8934 (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 3802326b4d063a41550d9fe411d891cdd52e68bc Author: Daniel Baston Date: Tue Dec 16 09:52:36 2025 -0500 BufferOp: Avoid crash on geometry with only invalid coordinates diff --git a/NEWS.md b/NEWS.md index de09ec652..0934edb9d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ - Fix OverlayNG coordinate dimemsion 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) + - Avoid crash on buffer of geometry with only invalid coordinates (GH-1335, Dan Baston) ## Changes in 3.12.3 2025-03-03 diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp index d57532c6f..a9d99cf09 100644 --- a/src/operation/buffer/BufferCurveSetBuilder.cpp +++ b/src/operation/buffer/BufferCurveSetBuilder.cpp @@ -201,6 +201,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->isEmpty()) { + throw util::GEOSException("LineString has no valid points."); + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index 39f8592bb..298eaf7c6 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -3,6 +3,8 @@ // tut #include +#include + #include // geos #include @@ -21,6 +23,7 @@ #include #include + using namespace geos::operation::buffer; namespace tut { @@ -624,4 +627,19 @@ void object::test<28> "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))"); } +template<> +template<> +void object::test<31> +() +{ + set_test_name("buffer of line with only Inf coordinates"); + // See https://github.com/libgeos/geos/issues/1332 + + std::string wkt = "LINESTRING (Inf Inf, Inf Inf)"; + + auto geom = wktreader.read(wkt); + + ensure_THROW(geom->buffer(0.1), geos::util::GEOSException); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS.md | 1 + src/operation/buffer/BufferCurveSetBuilder.cpp | 4 ++++ tests/unit/operation/buffer/BufferOpTest.cpp | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 16 07:00:42 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Dec 2025 07:00:42 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch 3.10 updated. be92f62f870cef058c1d2c6446347456f5f774ec Message-ID: <20251216150042.781E41A5F93@trac.osgeo.org> 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.10 has been updated via be92f62f870cef058c1d2c6446347456f5f774ec (commit) from 1621a9dbb2d473d6ba0ff9132e937a9e753f41db (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 be92f62f870cef058c1d2c6446347456f5f774ec Author: Daniel Baston Date: Tue Dec 16 10:00:18 2025 -0500 BufferOp: Avoid crash on geometry with only invalid coordinates diff --git a/NEWS b/NEWS index 706ccec38..adcbd87a1 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,7 @@ 2025-xx-xx - Fixes/Improvements: - - + - Avoid crash on buffer of geometry with only invalid coordinates (GH-1335, Dan Baston) ## Changes in 3.10.7 2025-03-03 diff --git a/src/operation/buffer/OffsetCurveSetBuilder.cpp b/src/operation/buffer/OffsetCurveSetBuilder.cpp index e4db66496..e6166438b 100644 --- a/src/operation/buffer/OffsetCurveSetBuilder.cpp +++ b/src/operation/buffer/OffsetCurveSetBuilder.cpp @@ -209,6 +209,10 @@ OffsetCurveSetBuilder::addLineString(const LineString* line) auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO()); + if (coord->isEmpty()) { + throw util::GEOSException("LineString has no valid points."); + } + /** * Rings (closed lines) are generated with a continuous curve, * with no end arcs. This produces better quality linework, diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index b010da9e9..49f1c1ebd 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -3,6 +3,8 @@ // tut #include +#include + #include // geos #include @@ -19,7 +21,8 @@ // std #include #include -#include + +using namespace geos::operation::buffer; namespace tut { // @@ -549,4 +552,19 @@ void object::test<20> ensure( 0 == dynamic_cast(result1.get())->getNumInteriorRing() ); } +template<> +template<> +void object::test<31> +() +{ + set_test_name("buffer of line with only Inf coordinates"); + // See https://github.com/libgeos/geos/issues/1332 + + std::string wkt = "LINESTRING (Inf Inf, Inf Inf)"; + + auto geom = wktreader.read(wkt); + + ensure_THROW(geom->buffer(0.1), geos::util::GEOSException); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: NEWS | 2 +- src/operation/buffer/OffsetCurveSetBuilder.cpp | 4 ++++ tests/unit/operation/buffer/BufferOpTest.cpp | 20 +++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Mon Dec 22 11:36:02 2025 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Dec 2025 11:36:02 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 72c132a64e678dd1decb73fd5eafac3bd62307ce Message-ID: <20251222193605.A6DD8189CB4@trac.osgeo.org> 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 72c132a64e678dd1decb73fd5eafac3bd62307ce (commit) via f98d330e8fe14d1e1a77763423ec6dff12d369ae (commit) via 3e4581fad3974501880e59d47a6e852f624b5a67 (commit) via 0d2deb25cdc40c4040ea222e958b884a47a28b39 (commit) via 0211bbebe3b7741ba8f869e5ab19d4fdd2de1530 (commit) via fc9c1a0eda99660f1fe81a2f9a6f1151a3fbd1a1 (commit) via 5aaa5c8c3a0a8549c874356aad94d578ba45a7da (commit) via a3de1c7bed176836125e9f065b5018dbf2ada307 (commit) via cf9111810586691a46beea382c8e33abb3927878 (commit) from 88a987895022ff77fedad776d7835e5743208abb (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 72c132a64e678dd1decb73fd5eafac3bd62307ce Author: Daniel Baston Date: Thu Oct 23 16:42:03 2025 -0400 SegmentPointComparator: Use CoordinateXY diff --git a/include/geos/noding/SegmentPointComparator.h b/include/geos/noding/SegmentPointComparator.h index bd4739274..d56f78288 100644 --- a/include/geos/noding/SegmentPointComparator.h +++ b/include/geos/noding/SegmentPointComparator.h @@ -49,8 +49,8 @@ public: * @return 1 node1 occurs first */ static int - compare(int octant, const geom::Coordinate& p0, - const geom::Coordinate& p1) + compare(int octant, const geom::CoordinateXY& p0, + const geom::CoordinateXY& p1) { // nodes can only be equal if their coordinates are equal if(p0.equals2D(p1)) { commit f98d330e8fe14d1e1a77763423ec6dff12d369ae Author: Daniel Baston Date: Thu Oct 23 16:41:51 2025 -0400 Octant.h: clarify comment diff --git a/include/geos/noding/Octant.h b/include/geos/noding/Octant.h index 7b96c0af1..dce4616c7 100644 --- a/include/geos/noding/Octant.h +++ b/include/geos/noding/Octant.h @@ -33,11 +33,11 @@ namespace noding { // geos.noding * * Octants are numbered as follows: * - * 2|1 - * 3 | 0 + * \2|1/ + * 3 \|/ 0 * ---+-- - * 4 | 7 - * 5|6 + * 4 /|\ 7 + * /5|6\ * * If line segments lie along a coordinate axis, the octant is the lower of the two * possible values. commit 3e4581fad3974501880e59d47a6e852f624b5a67 Author: Daniel Baston Date: Thu Oct 23 15:16:03 2025 -0400 SimpleNoder: Remove unnecessary virtual specifier diff --git a/include/geos/noding/SimpleNoder.h b/include/geos/noding/SimpleNoder.h index 95468637a..70bc4765f 100644 --- a/include/geos/noding/SimpleNoder.h +++ b/include/geos/noding/SimpleNoder.h @@ -48,7 +48,7 @@ namespace noding { // geos.noding class GEOS_DLL SimpleNoder: public SinglePassNoder { private: std::vector nodedSegStrings; - virtual void computeIntersects(SegmentString* e0, SegmentString* e1); + void computeIntersects(SegmentString* e0, SegmentString* e1); public: SimpleNoder(SegmentIntersector* nSegInt = nullptr) commit 0d2deb25cdc40c4040ea222e958b884a47a28b39 Author: Daniel Baston Date: Thu Oct 23 15:10:08 2025 -0400 SinglePassNoder: Remove unnecessary overrides diff --git a/include/geos/noding/SinglePassNoder.h b/include/geos/noding/SinglePassNoder.h index b36d94a60..4c3891b24 100644 --- a/include/geos/noding/SinglePassNoder.h +++ b/include/geos/noding/SinglePassNoder.h @@ -15,9 +15,6 @@ #pragma once #include - -#include - #include // Forward declarations @@ -42,8 +39,6 @@ namespace noding { // geos.noding * * Last port: noding/SinglePassNoder.java rev. 1.3 (JTS-1.7) * - * TODO: Noder inheritance (that's just an interface!) - * */ class GEOS_DLL SinglePassNoder : public Noder { // implements Noder @@ -74,22 +69,6 @@ public: segInt = newSegInt; } - /** \brief - * Computes the noding for a collection of {@link SegmentString}s. - * - * @param segStrings a collection of {@link SegmentString}s to node - */ - void computeNodes(const std::vector& segStrings) override = 0; - - /** \brief - * Returns a Collection of fully noded {@link SegmentString}s. - * - * The SegmentStrings have the same context as their parent. - * - * @return a Collection of SegmentStrings - */ - std::vector> getNodedSubstrings() override = 0; - }; } // namespace geos.noding commit 0211bbebe3b7741ba8f869e5ab19d4fdd2de1530 Author: Daniel Baston Date: Thu Dec 4 12:04:57 2025 -0500 RobustLineIntersectorZTest: Add test for contained collinear segment diff --git a/tests/unit/algorithm/RobustLineIntersectorZTest.cpp b/tests/unit/algorithm/RobustLineIntersectorZTest.cpp index 1616e0650..7d7936bc8 100644 --- a/tests/unit/algorithm/RobustLineIntersectorZTest.cpp +++ b/tests/unit/algorithm/RobustLineIntersectorZTest.cpp @@ -266,7 +266,7 @@ void object::test<10> { // Intersection at interior of 3D line, endpoint of 2D line // result Z is interpolated - set_test_name("testInteriorEndpoint2D3D"); + set_test_name("testInteriorEndpoint3D2D"); checkIntersection( line({1, 1, 1}, {3, 3, 3}), @@ -424,5 +424,22 @@ void object::test<19> xyzm(2, 2, 11, -11)); } +template<> +template<> +void object::test<20> +() +{ + // Collinear intersection of XYZ lines + // Z values in the second line do not match interpolated values in the first + // Result Z uses endpoint values of the second line + set_test_name("testCollinearContainedDifferentZ"); + + checkIntersection( + line({1, 1, 1}, {5, 5, 5}), + line({3, 3, 7}, {4, 4, 13}), + xyz(3, 3, 7), + xyz(4, 4, 13)); +} + } // namespace tut commit fc9c1a0eda99660f1fe81a2f9a6f1151a3fbd1a1 Author: Daniel Baston Date: Thu Nov 27 10:01:40 2025 -0500 RobustLineIntersectorZTest: Set test names, add comments diff --git a/tests/unit/algorithm/RobustLineIntersectorZTest.cpp b/tests/unit/algorithm/RobustLineIntersectorZTest.cpp index d57c65b52..1616e0650 100644 --- a/tests/unit/algorithm/RobustLineIntersectorZTest.cpp +++ b/tests/unit/algorithm/RobustLineIntersectorZTest.cpp @@ -120,6 +120,10 @@ template<> void object::test<1> () { + // XYZ intersects XYZ at interior point. + // Z value at the intersection point is the average of the interpolated values from each line. + set_test_name("testInterior"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 3, 10}, {3, 1, 30}), @@ -133,6 +137,8 @@ template<> void object::test<2> () { + set_test_name("testInterior2D"); + checkIntersection( line({1, 1}, {3, 3}), line({1, 3}, {3, 1}), @@ -145,6 +151,10 @@ template<> void object::test<3> () { + // XYZ intersects XY at interior point. + // Z value at the intersection point is the interpolated value from the XYZ line. + set_test_name("testInterior3D2D"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 3}, {3, 1}), @@ -157,6 +167,10 @@ template<> void object::test<4> () { + // XY intersects XYZ at interior point. + // Z value at the intersection point is the interpolated value from the XZZ line. + set_test_name("testInterior2D3D"); + checkIntersection( line({1, 1}, {3, 3}), line({1, 3, 10}, {3, 1, 30}), @@ -164,12 +178,16 @@ void object::test<4> } // testInterior2D3DPart -// result is average of line1 interpolated and line2 p0 Z template<> template<> void object::test<5> () { + // XYZ intersects XYZ at interior point. + // Second line has a Z value of NaN at one point. + // result is average of line1 interpolated and line2 p0 Z + set_test_name("testInterior2D3DPart"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 3, 10}, {3, 1, geos::DoubleNotANumber}), @@ -182,6 +200,10 @@ template<> void object::test<6> () { + // XYZ intersects XYZ at endpoint. + // Result Z value at intersection point is taken from the first line. + set_test_name("testEndpoint"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({3, 3, 3}, {3, 1, 30}), @@ -194,6 +216,10 @@ template<> void object::test<7> () { + // XY intersects XY at endpoint. + // Result Z value at intersection point is NaN. + set_test_name("testEndpoint2D"); + checkIntersection( line({1, 1}, {3, 3}), line({3, 3}, {3, 1}), @@ -206,7 +232,10 @@ template<> void object::test<8> () { + // XYZ intersects XY at endpoint. // result Z is from 3D point + set_test_name("testEndpoint2D3D"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({3, 3}, {3, 1}), @@ -219,7 +248,10 @@ template<> void object::test<9> () { - // result Z is from 3D point + // Intersection at interior of 3D line, endpoint of 3D line + // result Z is from 3D endpoint + set_test_name("testInteriorEndpoint"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({2, 2, 10}, {3, 1, 30}), @@ -232,7 +264,10 @@ template<> void object::test<10> () { + // Intersection at interior of 3D line, endpoint of 2D line // result Z is interpolated + set_test_name("testInteriorEndpoint2D3D"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({2, 2}, {3, 1}), @@ -240,12 +275,15 @@ void object::test<10> } // testInteriorEndpoint2D3D -// result Z is from 3D point template<> template<> void object::test<11> () { + // Intersection at interior of 2D line, endpoint of 3D line + // result Z is from 3D point + set_test_name("testInteriorEndpoint2D3D"); + checkIntersection( line({1, 1}, {3, 3}), line({2, 2, 10}, {3, 1, 20}), @@ -258,6 +296,10 @@ template<> void object::test<12> () { + // Collinear intersection of two XYZ lines + // Z values are equivalent in both inputs + set_test_name("testCollinearEqual"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 1, 1}, {3, 3, 3}), @@ -270,6 +312,10 @@ template<> void object::test<13> () { + // Collinear intersection of XY and XYZ + // Z values taken from XYZ line + set_test_name("testCollinearEqual3D2D"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 1}, {3, 3}), @@ -282,6 +328,10 @@ template<> void object::test<14> () { + // Endpoint intersection of two collinear XYZ lines + // Z values of inputs are the same and are copied to output + set_test_name("testCollinearEndpoint"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({3, 3, 3}, {5, 5, 5}), @@ -295,6 +345,10 @@ template<> void object::test<15> () { + // Endpoint intersection of collinear XY and XYZ lines + // Z values of result is taken from the XYZ input + set_test_name("testCollinearEndpoint3D2D"); + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({3, 3}, {5, 5}), @@ -307,6 +361,11 @@ template<> void object::test<16> () { + // Collinear intersection of XYZ lines + // Z values in the second line match interpolated values in the first + set_test_name("testCollinearContained"); + + checkIntersection( line({1, 1, 1}, {5, 5, 5}), line({3, 3, 3}, {4, 4, 4}), @@ -320,7 +379,11 @@ template<> void object::test<17> () { + // Collinear intersection of XYZ line with XY line // result Z is interpolated + set_test_name("testCollinearContained3D2D"); + + checkIntersection( line({1, 1, 1}, {5, 5, 5}), line({3, 3}, {4, 4}), @@ -334,6 +397,11 @@ template<> void object::test<18> () { + // Interior intersection of two XYM lines. + // Result M is the average of the interpolated coordinate values. + set_test_name("testInteriorXYM-XYM"); + + checkIntersection( line({1, 1, 1}, {3, 3, 3}), line({1, 3, 10}, {3, 1, 30}), @@ -346,6 +414,10 @@ template<> void object::test<19> () { + // Interior intersection of two XYZM lines. + // Result Z and M are the average of the interpolated coordinate values. + set_test_name("testInteriorXYZM-XYZM"); + checkIntersection( line({1, 1, 1, -1}, {3, 3, 3, -3}), line({1, 3, 10, -10}, {3, 1, 30, -30}), commit 5aaa5c8c3a0a8549c874356aad94d578ba45a7da Author: Daniel Baston Date: Tue Dec 16 10:42:30 2025 -0500 CircularString: validate number of points on construction diff --git a/src/geom/CircularString.cpp b/src/geom/CircularString.cpp index 26f74d96f..6e95aa035 100644 --- a/src/geom/CircularString.cpp +++ b/src/geom/CircularString.cpp @@ -97,8 +97,8 @@ CircularString::validateConstruction() return; } - if (points->size() == 2) { - throw util::IllegalArgumentException("point array must contain 0 or >2 elements\n"); + if (points->size() > 0 && (points->size() < 3 || points->size() % 2 == 0)) { + throw util::IllegalArgumentException("point array size must zero or be an odd number >= 3"); } } diff --git a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp index 626465851..c52bce50a 100644 --- a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp +++ b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp @@ -193,10 +193,10 @@ void object::test<9> { GEOSGeometry* geoms[2]; geoms[0] = fromWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))"); - geoms[1] = fromWKT("CURVEPOLYGON (CIRCULARSTRING (10 10, 20 10, 15 15, 10 10))"); + geoms[1] = fromWKT("CURVEPOLYGON (COMPOUNDCURVE (CIRCULARSTRING (10 10, 20 10, 15 15), (15 15, 10 10)))"); result_ = GEOSGeom_createCollection(GEOS_MULTISURFACE, geoms, 2); - expected_ = fromWKT("MULTISURFACE (((0 0, 1 0, 1 1, 0 0)), CURVEPOLYGON (CIRCULARSTRING (10 10, 20 10, 15 15, 10 10)))"); + expected_ = fromWKT("MULTISURFACE (((0 0, 1 0, 1 1, 0 0)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING (10 10, 20 10, 15 15), (15 15, 10 10))))"); ensure_geometry_equals_identical(result_, expected_); } diff --git a/tests/unit/geom/CircularStringTest.cpp b/tests/unit/geom/CircularStringTest.cpp index 64bbe6524..a4a9a9d14 100644 --- a/tests/unit/geom/CircularStringTest.cpp +++ b/tests/unit/geom/CircularStringTest.cpp @@ -8,6 +8,8 @@ #include #include +#include "utility.h" + using geos::geom::CoordinateSequence; using geos::geom::CircularString; using XY = geos::geom::CoordinateXY; @@ -175,4 +177,26 @@ void object::test<4>() ensure("isCoordinate", cs_->isCoordinate(pt)); } +template<> +template<> +void object::test<5>() +{ + set_test_name("invalid number of points"); + + auto pts = std::make_shared(); + ensure_NO_THROW(factory_->createCircularString(pts)); + + pts->add(0.0, 0.0); + ensure_THROW(factory_->createCircularString(pts), geos::util::GEOSException); + + pts->add(1.0, 1.0); + ensure_THROW(factory_->createCircularString(pts), geos::util::GEOSException); + + pts->add(2.0, 0.0); + ensure_NO_THROW(factory_->createCircularString(pts)); + + pts->add(3.0, -1.0); + ensure_THROW(factory_->createCircularString(pts), geos::util::GEOSException); +} + } commit a3de1c7bed176836125e9f065b5018dbf2ada307 Author: Daniel Baston Date: Tue Dec 16 10:31:35 2025 -0500 SimpleCurve: Fix envelope calculation diff --git a/src/geom/SimpleCurve.cpp b/src/geom/SimpleCurve.cpp index e062c4c8b..21fd40c88 100644 --- a/src/geom/SimpleCurve.cpp +++ b/src/geom/SimpleCurve.cpp @@ -144,7 +144,7 @@ SimpleCurve::computeEnvelopeInternal(bool isLinear) const } else { Envelope e; - for (std::size_t i = 2; i < points->size(); i++) { + for (std::size_t i = 2; i < points->size(); i += 2) { algorithm::CircularArcs::expandEnvelope(e, points->getAt(i-2), points->getAt(i-1), commit cf9111810586691a46beea382c8e33abb3927878 Author: Daniel Baston Date: Tue Dec 16 10:31:18 2025 -0500 CircularArcs: Fix UB in expandEnvelope diff --git a/src/algorithm/CircularArcs.cpp b/src/algorithm/CircularArcs.cpp index 99ddb04ff..55d7a433a 100644 --- a/src/algorithm/CircularArcs.cpp +++ b/src/algorithm/CircularArcs.cpp @@ -131,7 +131,7 @@ CircularArcs::expandEnvelope(geom::Envelope& e, const geom::CoordinateXY& p0, co } // collinear - if (std::isnan(center.x)) { + if (!std::isfinite(center.x) || !std::isfinite(center.y)) { return; } ----------------------------------------------------------------------- Summary of changes: include/geos/noding/Octant.h | 8 +- include/geos/noding/SegmentPointComparator.h | 4 +- include/geos/noding/SimpleNoder.h | 2 +- include/geos/noding/SinglePassNoder.h | 21 ----- src/algorithm/CircularArcs.cpp | 2 +- src/geom/CircularString.cpp | 4 +- src/geom/SimpleCurve.cpp | 2 +- .../unit/algorithm/RobustLineIntersectorZTest.cpp | 95 +++++++++++++++++++++- tests/unit/capi/GEOSGeom_createCollectionTest.cpp | 4 +- tests/unit/geom/CircularStringTest.cpp | 24 ++++++ 10 files changed, 129 insertions(+), 37 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Tue Dec 23 05:55:52 2025 From: git at osgeo.org (git at osgeo.org) Date: Tue, 23 Dec 2025 05:55:52 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 158c588566e08fd2f31f8c9e7ae069518e8264c5 Message-ID: <20251223135552.6E1D018EFB1@trac.osgeo.org> 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 158c588566e08fd2f31f8c9e7ae069518e8264c5 (commit) from 72c132a64e678dd1decb73fd5eafac3bd62307ce (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 158c588566e08fd2f31f8c9e7ae069518e8264c5 Author: arriopolis Date: Tue Dec 23 14:55:23 2025 +0100 Updated the geojson example in the documentation (#1349) Co-authored-by: arriopolis diff --git a/web/content/specifications/geojson.md b/web/content/specifications/geojson.md index a1b58a4cb..37e26e335 100644 --- a/web/content/specifications/geojson.md +++ b/web/content/specifications/geojson.md @@ -52,11 +52,12 @@ The C++ GeoJSON reader does include the option to read full `Feature` and `Featu #include #include #include +#include using namespace geos::io; using namespace geos::geom; -void main(void) +int main() { // Read file into string std::ifstream ifs("geojson.json"); @@ -64,7 +65,6 @@ void main(void) (std::istreambuf_iterator() )); // Parse GeoJSON string into GeoJSON objects - GeoJSONReader reader; GeoJSONFeatureCollection fc = reader.readFeatures(content); @@ -74,18 +74,18 @@ void main(void) writer.setRoundingPrecision(2); // Print out the features - for (auto& feature: fc) { + for (auto& feature : fc.getFeatures()) { // Read the geometry const Geometry* geom = feature.getGeometry(); // Read the properties - std::map& props = feature.getProperties(); + const std::map& props = feature.getProperties(); // Write all properties std::cout << "----------" << std::endl; for (const auto& prop : props) { - std::cout << prop.first << ": " << prop.second << std::endl; + std::cout << prop.first << ": " << prop.second.getString() << std::endl; } // Write WKT feometry ----------------------------------------------------------------------- Summary of changes: web/content/specifications/geojson.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- GEOS