[geos-commits] [SCM] GEOS branch 3.9 updated. 4a91381dc0971d68e0524e5337d2080a0be85958

git at osgeo.org git at osgeo.org
Thu Nov 11 15:13:40 PST 2021


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.9 has been updated
       via  4a91381dc0971d68e0524e5337d2080a0be85958 (commit)
      from  34a21eca7dfc45e8dafd4e131d98be1a4dcb2522 (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 4a91381dc0971d68e0524e5337d2080a0be85958
Author: Sandro Santilli <strk at kbt.io>
Date:   Wed Aug 11 22:12:02 2021 +0200

    Use custom rings comparator in BuildArea
    
    Closes #1122 in 3.9 branch (3.9.3dev)

diff --git a/NEWS b/NEWS
index 9fe4485d1..47be78aac 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,7 @@ Changes in 3.9.3
 2022-xx-xx
 
 - Bug fixes / improvements:
-  -
+  - Improve BuildArea performance (#1122, Sandro Santilli)
 
 
 Changes in 3.9.2
diff --git a/include/geos/geom/CoordinateSequence.h b/include/geos/geom/CoordinateSequence.h
index e8eeca5a6..4fbf0a1c9 100644
--- a/include/geos/geom/CoordinateSequence.h
+++ b/include/geos/geom/CoordinateSequence.h
@@ -159,10 +159,9 @@ public:
     static CoordinateSequence* atLeastNCoordinatesOrNothing(std::size_t n,
             CoordinateSequence* c);
 
-    /// Return position of a Coordinate, or -1 if not found
-    ///
-    /// FIXME: return std::size_t, using numeric_limits<std::size_t>::max
-    /// as 'not found' value.
+    /// Return position of a Coordinate
+    //
+    /// or numeric_limits<std::size_t>::max() if not found
     ///
     static size_t indexOf(const Coordinate* coordinate,
                           const CoordinateSequence* cl);
diff --git a/src/operation/polygonize/BuildArea.cpp b/src/operation/polygonize/BuildArea.cpp
index 960a9d651..56d12e3bc 100644
--- a/src/operation/polygonize/BuildArea.cpp
+++ b/src/operation/polygonize/BuildArea.cpp
@@ -66,6 +66,74 @@ struct Face {
     }
 };
 
+static bool ringsEqualAnyDirection(const LinearRing* r1, const LinearRing* r2)
+{
+
+    const CoordinateSequence *cs1 = r1->getCoordinatesRO();
+    const CoordinateSequence *cs2 = r2->getCoordinatesRO();
+
+    /* Check same number of points */
+    size_t npoints = cs1->size();
+    if ( npoints != cs2->size() )
+    {
+        return false;
+    }
+
+    if ( npoints == 0 ) return true; /* if empty, they are equal */
+
+    /* Check same envelope (probably better avoid, as it'd need to
+     * compute the envelope doing an additional scan for each) */
+    if ( ! r1->getEnvelopeInternal()->equals(r2->getEnvelopeInternal()) )
+    {
+        return false;
+    }
+
+    /* Pretend the rings had one less point, as the last one will be
+     * equal to the first one anyway */
+    --npoints;
+
+    const Coordinate& firstPoint = cs1->getAt(0);
+    size_t offset = CoordinateSequence::indexOf(&firstPoint, cs2);
+    if ( offset == std::numeric_limits<std::size_t>::max() ) return false;
+
+    bool equal = true;
+
+    /* Check equals forward (skip first point, we checked it alread) */
+    for (size_t i=1; i<npoints; ++i)
+    {
+        size_t j = ( i + offset ) % npoints;
+        const Coordinate& c1 = cs1->getAt(i);
+        const Coordinate& c2 = cs2->getAt(j);
+        if ( ! c1.equals(c2) ) {
+            equal = false;
+            break;
+        }
+    }
+
+    if ( equal ) return true;
+
+    /* Check equals backward (skip first point, we checked it already) */
+    equal = true;
+    for (size_t i=1; i<npoints; ++i)
+    {
+        size_t j;
+        if ( i <= offset ) {
+            j = offset - i;
+        } else {
+            j = npoints - ( i - offset );
+        }
+
+        const Coordinate& c1 = cs1->getAt(i);
+        const Coordinate& c2 = cs2->getAt(j);
+        if ( ! c1.equals(c2) ) {
+            equal = false;
+            break;
+        }
+    }
+
+    return equal;
+}
+
 static std::unique_ptr<Face> newFace(const geom::Polygon* p) {
     auto f = std::unique_ptr<Face>(new Face());
     f->poly = p;
@@ -100,13 +168,8 @@ static void findFaceHoles(std::vector<std::unique_ptr<Face>>& faces) {
                 if( f2->parent ) {
                     continue; /* hole already assigned */
                 }
-                const auto f2er = f2->poly->getExteriorRing();
-                /* TODO: can be optimized as the ring would have the
-                *       same vertices, possibly in different order.
-                *       maybe comparing number of points could already be
-                *       useful.
-                */
-                if( f2er->equals(hole) ) {
+                const auto shell = f2->poly->getExteriorRing();
+                if( ringsEqualAnyDirection(shell, hole) ) {
                     f2->parent = f.get();
                     break;
                 }

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

Summary of changes:
 NEWS                                   |  2 +-
 include/geos/geom/CoordinateSequence.h |  7 ++--
 src/operation/polygonize/BuildArea.cpp | 77 ++++++++++++++++++++++++++++++----
 3 files changed, 74 insertions(+), 12 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list