[geos-commits] [SCM] GEOS branch master updated. d6d4e12ff8142e008d88302ebcc84b6372807cdd

git at osgeo.org git at osgeo.org
Sun Nov 22 20:06:44 PST 2020


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".

The branch, master has been updated
       via  d6d4e12ff8142e008d88302ebcc84b6372807cdd (commit)
      from  cb2a1dae659825759037e7e81ad16d726e61a3dc (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 d6d4e12ff8142e008d88302ebcc84b6372807cdd
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Sun Nov 22 20:04:53 2020 -0800

    Add nearestNeighbor() to the SimpleSTRtree implementation as well as
    isWithinDistance(). Refactor classes a little to put all the
    distance related calculations and classes in SimpleSTRdistance instead of in the
    tree class, for a cleaner tree. Add some tests to the unit test,
    but only enough to check that it turns over and returns minimally
    sensible results.

diff --git a/include/geos/index/strtree/Makefile.am b/include/geos/index/strtree/Makefile.am
index 2f9191e..204059d 100644
--- a/include/geos/index/strtree/Makefile.am
+++ b/include/geos/index/strtree/Makefile.am
@@ -20,4 +20,5 @@ geos_HEADERS = \
     SIRtree.h \
     STRtree.h \
     SimpleSTRtree.h \
-    SimpleSTRnode.h
+    SimpleSTRnode.h \
+    SimpleSTRdistance.h
diff --git a/include/geos/index/strtree/SimpleSTRdistance.h b/include/geos/index/strtree/SimpleSTRdistance.h
new file mode 100644
index 0000000..3024f57
--- /dev/null
+++ b/include/geos/index/strtree/SimpleSTRdistance.h
@@ -0,0 +1,166 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2020 Paul Ramsey
+ *
+ * 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.
+ *
+ **********************************************************************/
+
+#pragma once
+
+#include <cassert>
+#include <cstddef>
+#include <geos/export.h>
+#include <geos/geom/Envelope.h>
+#include <geos/index/strtree/SimpleSTRtree.h>
+#include <geos/index/strtree/SimpleSTRnode.h>
+
+#include <vector>
+#include <queue>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
+#endif
+
+namespace geos {
+namespace index { // geos::index
+namespace strtree { // geos::index::strtree
+
+
+
+
+
+class GEOS_DLL SimpleSTRpair {
+
+private:
+
+    SimpleSTRnode* node1;
+    SimpleSTRnode* node2;
+    ItemDistance* itemDistance;
+    double m_distance;
+
+    /** \brief
+     * Computes the distance between the {@link SimpleSTRnode}s in this pair.
+     * The nodes are either composites or leaves.
+     *
+     * If either is composite, the distance is computed as the minimum distance
+     * between the bounds.
+     * If both are leaves, the distance is computed by
+     * ItemDistance::distance(const void* item1, const void* item2).
+     *
+     * @return the distance between the items
+     */
+    double distance();
+
+public:
+
+    SimpleSTRpair(SimpleSTRnode* p_node1, SimpleSTRnode* p_node2, ItemDistance* p_itemDistance)
+        : node1(p_node1)
+        , node2(p_node2)
+        , itemDistance(p_itemDistance)
+        {
+            m_distance = distance();
+        }
+
+    SimpleSTRnode* getNode(int i) const;
+
+    /** \brief
+     * Gets the minimum possible distance between the SimpleSTRnode in this pair.
+     *
+     * If the members are both items, this will be the
+     * exact distance between them.
+     * Otherwise, this distance will be a lower bound on
+     * the distances between the items in the members.
+     *
+     * @return the exact or lower bound distance for this pair
+     */
+    double getDistance() const;
+
+    /**
+     * Tests if both elements of the pair are leaf nodes
+     *
+     * @return true if both pair elements are leaf nodes
+     */
+    bool isLeaves() const;
+
+    /** \brief
+     * Computes the maximum distance between any
+     * two items in the pair of nodes.
+     *
+     * @return the maximum distance between items in the pair
+     */
+    double maximumDistance();
+
+    friend std::ostream& operator<<(std::ostream& os, SimpleSTRpair& pair);
+
+
+};
+
+
+
+class GEOS_DLL SimpleSTRdistance {
+
+
+public:
+
+    struct STRpairQueueCompare {
+        bool
+        operator()(const SimpleSTRpair* a, const SimpleSTRpair* b)
+        {
+            return a->getDistance() > b->getDistance();
+        }
+    };
+
+    typedef std::priority_queue<SimpleSTRpair*,
+        std::vector<SimpleSTRpair*>,
+        STRpairQueueCompare> STRpairQueue;
+
+
+    /* Initialize class */
+    SimpleSTRdistance(SimpleSTRnode* root1, SimpleSTRnode* root2, ItemDistance* p_itemDistance);
+
+    /* Turn over the calculation */
+    std::pair<const void*, const void*> nearestNeighbour();
+    bool isWithinDistance(double maxDistance);
+
+
+private:
+
+    std::deque<SimpleSTRpair> pairStore;
+    SimpleSTRpair* initPair;
+    ItemDistance* itemDistance;
+
+    /* Utility method to store allocated pairs */
+    SimpleSTRpair* createPair(SimpleSTRnode* p_node1, SimpleSTRnode* p_node2, ItemDistance* p_itemDistance);
+
+    std::pair<const void*, const void*> nearestNeighbour(SimpleSTRpair* p_initPair);
+    std::pair<const void*, const void*> nearestNeighbour(SimpleSTRpair* p_initPair, double maxDistance);
+
+    bool isWithinDistance(SimpleSTRpair* p_initPair, double maxDistance);
+
+    void expandToQueue(SimpleSTRpair* pair, STRpairQueue&, double minDistance);
+    void expand(SimpleSTRnode* nodeComposite, SimpleSTRnode* nodeOther,
+        bool isFlipped, STRpairQueue& priQ, double minDistance);
+
+
+};
+
+
+
+
+
+} // namespace geos::index::strtree
+} // namespace geos::index
+} // namespace geos
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
diff --git a/include/geos/index/strtree/SimpleSTRnode.h b/include/geos/index/strtree/SimpleSTRnode.h
index 1826382..b5ea81e 100644
--- a/include/geos/index/strtree/SimpleSTRnode.h
+++ b/include/geos/index/strtree/SimpleSTRnode.h
@@ -15,9 +15,9 @@
 #pragma once
 
 #include <cassert>
-#include <cstddef>
 #include <geos/export.h>
 #include <geos/geom/Envelope.h>
+#include <geos/index/strtree/ItemBoundable.h>
 
 #include <vector>
 
@@ -34,12 +34,12 @@ namespace strtree { // geos::index::strtree
  * A node of the STR tree.
  *
  */
-class GEOS_DLL SimpleSTRnode {
+class GEOS_DLL SimpleSTRnode : public ItemBoundable {
 
 private:
 
-    void *item;
     std::vector<SimpleSTRnode*> childNodes;
+    void *item;
     geom::Envelope bounds;
     std::size_t level;
 
@@ -50,13 +50,15 @@ public:
     /*
      * Constructs an AbstractNode at the given level in the tree
      */
-    SimpleSTRnode(std::size_t newLevel, const geom::Envelope *itemEnv, void* item, size_t capacity = 10)
-        : item(item)
+    SimpleSTRnode(std::size_t newLevel, const geom::Envelope *p_env, void* p_item, size_t capacity = 10)
+        : ItemBoundable(p_env, p_item)
+        , item(p_item)
+        , bounds()
         , level(newLevel)
     {
         childNodes.reserve(capacity);
-        if (itemEnv) {
-            bounds = *itemEnv;
+        if (p_env) {
+            bounds = *p_env;
         }
 
     }
@@ -65,7 +67,7 @@ public:
         : SimpleSTRnode(newLevel, nullptr, nullptr)
     {}
 
-    void toString(std::ostream& os, int level) const;
+    void toString(std::ostream& os, int indentLevel) const;
 
     const std::vector<SimpleSTRnode*>&
     getChildNodes() const
@@ -80,13 +82,17 @@ public:
     /**
      * Returns a representation of space that encloses this Node
      */
-    const geom::Envelope& getBounds() {
+    const geom::Envelope& getEnvelope() {
         if(bounds.isNull()) {
             computeBounds();
         }
         return bounds;
     }
 
+    const void* getBounds() const {
+        return &bounds;
+    }
+
     /**
     * Returns 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the
     * root node will have the highest level
@@ -114,6 +120,16 @@ public:
         return item != nullptr;
     }
 
+    bool isComposite() const
+    {
+        return ! isLeaf();
+    }
+
+    double area()
+    {
+        return getEnvelope().getArea();
+    }
+
 
 };
 
diff --git a/include/geos/index/strtree/SimpleSTRtree.h b/include/geos/index/strtree/SimpleSTRtree.h
index 3477ab0..baf79a4 100644
--- a/include/geos/index/strtree/SimpleSTRtree.h
+++ b/include/geos/index/strtree/SimpleSTRtree.h
@@ -20,6 +20,8 @@
 #include <geos/index/strtree/SimpleSTRnode.h>
 
 #include <vector>
+#include <utility>
+
 
 #ifdef _MSC_VER
 #pragma warning(push)
@@ -33,8 +35,12 @@ namespace geom {
 class Geometry;
 class Envelope;
 }
+namespace index {
+namespace strtree {
+class ItemDistance;
+}
+}
 }
-
 
 
 namespace geos {
@@ -62,14 +68,14 @@ class GEOS_DLL SimpleSTRtree: public SpatialIndex {
 private:
 
     /* Members */
-    std::deque<SimpleSTRnode> storedNodes;
+    std::deque<SimpleSTRnode> nodesQue;
     std::vector<SimpleSTRnode*> nodes;
     std::size_t nodeCapacity;
     SimpleSTRnode* root;
     bool built;
 
     /*
-    * Allocate node in storedNodes std::deque for memory locality,
+    * Allocate node in nodesQue std::deque for memory locality,
     * return reference to node.
     */
     SimpleSTRnode* createNode(int newLevel, const geom::Envelope* itemEnv, void* item);
@@ -125,7 +131,8 @@ public:
         return built;
     }
 
-    SimpleSTRnode* getRoot() const {
+    SimpleSTRnode* getRoot() {
+        build();
         return root;
     }
 
@@ -142,6 +149,22 @@ public:
     friend std::ostream& operator<<(std::ostream& os, const SimpleSTRtree& tree);
 
 
+    /*********************************************************************************/
+    /* Nearest neighbor searches, public API */
+
+    /* Internal nearest node to node */
+    std::pair<const void*, const void*> nearestNeighbour(ItemDistance* itemDist);
+
+    /* Nearest to another geometry/item */
+    const void* nearestNeighbour(const geom::Envelope* env, const void* item, ItemDistance* itemDist);
+
+    /* Nearest to another tree */
+    std::pair<const void*, const void*> nearestNeighbour(SimpleSTRtree& tree, ItemDistance* itemDist);
+
+    /* Radius test */
+    bool isWithinDistance(SimpleSTRtree& tree, ItemDistance* itemDist, double maxDistance);
+
+
 };
 
 } // namespace geos::index::strtree
diff --git a/src/index/strtree/Makefile.am b/src/index/strtree/Makefile.am
index 4f3d773..335b673 100644
--- a/src/index/strtree/Makefile.am
+++ b/src/index/strtree/Makefile.am
@@ -14,6 +14,7 @@ libindexstrtree_la_SOURCES = \
     SIRtree.cpp \
     STRtree.cpp \
     SimpleSTRtree.cpp \
-    SimpleSTRnode.cpp
+    SimpleSTRnode.cpp \
+    SimpleSTRdistance.cpp
 
 libindexstrtree_la_LIBADD =
diff --git a/src/index/strtree/SimpleSTRdistance.cpp b/src/index/strtree/SimpleSTRdistance.cpp
new file mode 100644
index 0000000..d1e3316
--- /dev/null
+++ b/src/index/strtree/SimpleSTRdistance.cpp
@@ -0,0 +1,328 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2020 Paul Ramsey
+ *
+ * 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.
+ *
+ **********************************************************************/
+
+#include <geos/index/strtree/SimpleSTRdistance.h>
+#include <geos/index/strtree/SimpleSTRnode.h>
+#include <geos/index/strtree/ItemDistance.h>
+#include <geos/index/strtree/EnvelopeUtil.h>
+#include <geos/geom/Envelope.h>
+#include <geos/util/GEOSException.h>
+#include <geos/util/IllegalArgumentException.h>
+
+#include <iostream>
+
+using namespace geos::geom;
+
+namespace geos {
+namespace index { // geos.index
+namespace strtree { // geos.index.strtree
+
+
+
+SimpleSTRdistance::SimpleSTRdistance(SimpleSTRnode* root1,
+    SimpleSTRnode* root2, ItemDistance* p_itemDistance)
+    : initPair(createPair(root1, root2, p_itemDistance))
+    , itemDistance(p_itemDistance)
+    {}
+
+
+SimpleSTRpair*
+SimpleSTRdistance::createPair(SimpleSTRnode* p_node1, SimpleSTRnode* p_node2,
+    ItemDistance* p_itemDistance)
+{
+    pairStore.emplace_back(p_node1, p_node2, p_itemDistance);
+    SimpleSTRpair& pair = pairStore.back();
+    return &pair;
+}
+
+
+/*public*/
+std::pair<const void*, const void*>
+SimpleSTRdistance::nearestNeighbour()
+{
+    return nearestNeighbour(initPair);
+}
+
+
+/*private*/
+std::pair<const void*, const void*>
+SimpleSTRdistance::nearestNeighbour(SimpleSTRpair* p_initPair)
+{
+    return nearestNeighbour(p_initPair, std::numeric_limits<double>::infinity());
+}
+
+
+/*private*/
+std::pair<const void*, const void*>
+SimpleSTRdistance::nearestNeighbour(SimpleSTRpair* p_initPair, double maxDistance)
+{
+    double distanceLowerBound = maxDistance;
+    SimpleSTRpair* minPair = nullptr;
+
+    STRpairQueue priQ;
+    priQ.push(p_initPair);
+
+    while(!priQ.empty() && distanceLowerBound > 0.0) {
+        SimpleSTRpair* pair = priQ.top();
+        double currentDistance = pair->getDistance();
+
+        // std::cout << *pair << std::endl;
+
+        /*
+         * If the distance for the first node in the queue
+         * is >= the current minimum distance, all other nodes
+         * in the queue must also have a greater distance.
+         * So the current minDistance must be the true minimum,
+         * and we are done.
+         */
+        if(minPair && currentDistance >= distanceLowerBound) {
+            break;
+        }
+
+        priQ.pop();
+
+        /*
+         * If the pair members are leaves
+         * then their distance is the exact lower bound.
+         * Update the distanceLowerBound to reflect this
+         * (which must be smaller, due to the test
+         * immediately prior to this).
+         */
+        if(pair->isLeaves()) {
+            distanceLowerBound = currentDistance;
+            minPair = pair;
+        }
+        else {
+            /*
+             * Otherwise, expand one side of the pair,
+             * (the choice of which side to expand is heuristically determined)
+             * and insert the new expanded pairs into the queue
+             */
+            expandToQueue(pair, priQ, distanceLowerBound);
+        }
+    }
+
+    /* Free any remaining node pairs in the queue */
+    while(!priQ.empty()) {
+        priQ.pop();
+    }
+
+    if(!minPair) {
+        throw util::GEOSException("Error computing nearest neighbor");
+    }
+
+    const void* item0 = minPair->getNode(0)->getItem();
+    const void* item1 = minPair->getNode(1)->getItem();
+
+    return std::pair<const void*, const void*>(item0, item1);
+}
+
+
+void
+SimpleSTRdistance::expandToQueue(SimpleSTRpair* pair, STRpairQueue& priQ, double minDistance)
+{
+
+    SimpleSTRnode* node1 = pair->getNode(0);
+    SimpleSTRnode* node2 = pair->getNode(1);
+
+    bool isComp1 = node1->isComposite();
+    bool isComp2 = node2->isComposite();
+
+    /**
+     * HEURISTIC: If both boundable are composite,
+     * choose the one with largest area to expand.
+     * Otherwise, simply expand whichever is composite.
+     */
+    if (isComp1 && isComp2) {
+      if (node1->area() > node2->area()) {
+        expand(node1, node2, false, priQ, minDistance);
+        return;
+      }
+      else {
+        expand(node2, node1, true, priQ, minDistance);
+        return;
+      }
+    }
+    else if (isComp1) {
+      expand(node1, node2, false, priQ, minDistance);
+      return;
+    }
+    else if (isComp2) {
+      expand(node2, node1, true, priQ, minDistance);
+      return;
+    }
+
+    throw util::IllegalArgumentException("neither boundable is composite");
+}
+
+
+void
+SimpleSTRdistance::expand(SimpleSTRnode* nodeComposite, SimpleSTRnode* nodeOther,
+    bool isFlipped, STRpairQueue& priQ, double minDistance)
+{
+    auto children = nodeComposite->getChildNodes();
+    for (auto* child: children) {
+        SimpleSTRpair* sp = nullptr;
+        if (isFlipped) {
+            sp = createPair(nodeOther, child, itemDistance);
+        }
+        else {
+            sp = createPair(child, nodeOther, itemDistance);
+        }
+        // only add to queue if this pair might contain the closest points
+        // MD - it's actually faster to construct the object rather than called distance(child, nodeOther)!
+        if (sp->getDistance() < minDistance) {
+            priQ.push(sp);
+        }
+    }
+}
+
+/* public */
+bool
+SimpleSTRdistance::isWithinDistance(double maxDistance)
+{
+    return isWithinDistance(initPair, maxDistance);
+}
+
+/* private */
+bool
+SimpleSTRdistance::isWithinDistance(SimpleSTRpair* p_initPair, double maxDistance)
+{
+    double distanceUpperBound = std::numeric_limits<double>::infinity();
+
+    // initialize search queue
+    STRpairQueue priQ;
+    priQ.push(p_initPair);
+
+    while (! priQ.empty()) {
+        // pop head of queue and expand one side of pair
+        SimpleSTRpair* pair = priQ.top();
+        double pairDistance = pair->getDistance();
+
+        /**
+        * If the distance for the first pair in the queue
+        * is > maxDistance, all other pairs
+        * in the queue must have a greater distance as well.
+        * So can conclude no items are within the distance
+        * and terminate with result = false
+        */
+        if (pairDistance > maxDistance)
+            return false;
+
+        priQ.pop();
+        /**
+        * If the maximum distance between the nodes
+        * is less than the maxDistance,
+        * than all items in the nodes must be
+        * closer than the max distance.
+        * Then can terminate with result = true.
+        *
+        * NOTE: using Envelope MinMaxDistance
+        * would provide a tighter bound,
+        * but not much performance improvement has been observed
+        */
+        if (pair->maximumDistance() <= maxDistance)
+            return true;
+        /**
+        * If the pair items are leaves
+        * then their actual distance is an upper bound.
+        * Update the distanceUpperBound to reflect this
+        */
+        if (pair->isLeaves()) {
+            // assert: currentDistance < minimumDistanceFound
+            distanceUpperBound = pairDistance;
+            /**
+            * If the items are closer than maxDistance
+            * can terminate with result = true.
+            */
+            if (distanceUpperBound <= maxDistance)
+                return true;
+        }
+        else {
+            /**
+            * Otherwise, expand one side of the pair,
+            * and insert the expanded pairs into the queue.
+            * The choice of which side to expand is determined heuristically.
+            */
+            expandToQueue(pair, priQ, distanceUpperBound);
+        }
+    }
+    return false;
+}
+
+
+/*********************************************************************************/
+
+SimpleSTRnode*
+SimpleSTRpair::getNode(int i) const
+{
+    if (i == 0) {
+        return node1;
+    }
+    return node2;
+}
+
+
+/* private */
+double
+SimpleSTRpair::distance()
+{
+    // if items, compute exact distance
+    if (isLeaves()) {
+        return itemDistance->distance(node1, node2);
+    }
+
+    // otherwise compute distance between bounds of nodes
+    const geom::Envelope& e1 = node1->getEnvelope();
+    const geom::Envelope& e2 = node2->getEnvelope();
+    return e1.distance(e2);
+}
+
+
+double
+SimpleSTRpair::getDistance() const
+{
+    return m_distance;
+}
+
+bool
+SimpleSTRpair::isLeaves() const
+{
+    return node1->isLeaf() && node2->isLeaf();
+}
+
+double
+SimpleSTRpair::maximumDistance()
+{
+    return EnvelopeUtil::maximumDistance(&(node1->getEnvelope()), &(node2->getEnvelope()));
+}
+
+/*public static*/
+std::ostream&
+operator<<(std::ostream& os, SimpleSTRpair& pair)
+{
+    const geom::Envelope& e1 = pair.getNode(0)->getEnvelope();
+    const geom::Envelope& e2 = pair.getNode(1)->getEnvelope();
+    double distance = pair.getDistance();
+
+    os << e1 << " " << e2 << " " << distance;
+    return os;
+}
+
+
+} // namespace geos.index.strtree
+} // namespace geos.index
+} // namespace geos
+
+
diff --git a/src/index/strtree/SimpleSTRnode.cpp b/src/index/strtree/SimpleSTRnode.cpp
index 6f3671c..047dafc 100644
--- a/src/index/strtree/SimpleSTRnode.cpp
+++ b/src/index/strtree/SimpleSTRnode.cpp
@@ -3,18 +3,13 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.osgeo.org
  *
- * Copyright (C) 2006 Refractions Research Inc.
- * Copyright (C) 2001-2002 Vivid Solutions Inc.
+ * Copyright (C) 2020 Paul Ramsey
  *
  * 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.
  *
- **********************************************************************
- *
- * Last port: index/strtree/STRtree.java rev. 1.11
- *
  **********************************************************************/
 
 #include <geos/index/strtree/SimpleSTRnode.h>
@@ -32,21 +27,20 @@ void
 SimpleSTRnode::computeBounds()
 {
     for (auto* node: childNodes) {
-        bounds.expandToInclude(node->getBounds());
+        bounds.expandToInclude(node->getEnvelope());
     }
 }
 
-
 /*public*/
 void
-SimpleSTRnode::toString(std::ostream& os, int level) const
+SimpleSTRnode::toString(std::ostream& os, int indentLevel) const
 {
-    for (int i = 0; i < level; i++) {
+    for (int i = 0; i < indentLevel; i++) {
         os << "  ";
     }
     os << bounds << std::endl;
     for (auto* node: childNodes) {
-        node->toString(os, level+1);
+        node->toString(os, indentLevel+1);
     }
 }
 
diff --git a/src/index/strtree/SimpleSTRtree.cpp b/src/index/strtree/SimpleSTRtree.cpp
index 8f800a8..8103a15 100644
--- a/src/index/strtree/SimpleSTRtree.cpp
+++ b/src/index/strtree/SimpleSTRtree.cpp
@@ -3,21 +3,17 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.osgeo.org
  *
- * Copyright (C) 2006 Refractions Research Inc.
- * Copyright (C) 2001-2002 Vivid Solutions Inc.
+ * Copyright (C) 2020 Paul Ramsey
  *
  * 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.
  *
- **********************************************************************
- *
- * Last port: index/strtree/STRtree.java rev. 1.11
- *
  **********************************************************************/
 
 #include <geos/index/strtree/SimpleSTRtree.h>
+#include <geos/index/strtree/SimpleSTRdistance.h>
 #include <geos/index/ItemVisitor.h>
 #include <geos/geom/Envelope.h>
 #include <geos/geom/Geometry.h>
@@ -40,9 +36,9 @@ namespace strtree { // geos.index.strtree
 SimpleSTRnode*
 SimpleSTRtree::createNode(int newLevel, const geom::Envelope* itemEnv, void* item)
 {
-    storedNodes.emplace_back(newLevel, itemEnv, item, nodeCapacity);
-    SimpleSTRnode* node = &(storedNodes.back());
-    return node;
+    nodesQue.emplace_back(newLevel, itemEnv, item, nodeCapacity);
+    SimpleSTRnode& node = nodesQue.back();
+    return &node;
 }
 
 /* private */
@@ -74,8 +70,8 @@ SimpleSTRtree::sortNodesY(std::vector<SimpleSTRnode*>& nodeList)
     struct {
         bool operator()(SimpleSTRnode* a, SimpleSTRnode* b) const
         {
-            const geom::Envelope& ea = a->getBounds();
-            const geom::Envelope& eb = b->getBounds();
+            const geom::Envelope& ea = a->getEnvelope();
+            const geom::Envelope& eb = b->getEnvelope();
             double ya = (ea.getMinY() + ea.getMaxY()) / 2.0;
             double yb = (eb.getMinY() + eb.getMaxY()) / 2.0;
             return ya < yb;
@@ -92,8 +88,8 @@ SimpleSTRtree::sortNodesX(std::vector<SimpleSTRnode*>& nodeList)
     struct {
         bool operator()(SimpleSTRnode* a, SimpleSTRnode* b) const
         {
-            const geom::Envelope& ea = a->getBounds();
-            const geom::Envelope& eb = b->getBounds();
+            const geom::Envelope& ea = a->getEnvelope();
+            const geom::Envelope& eb = b->getEnvelope();
             double xa = (ea.getMinX() + ea.getMaxX()) / 2.0;
             double xb = (eb.getMinX() + eb.getMaxX()) / 2.0;
             return xa < xb;
@@ -202,7 +198,7 @@ SimpleSTRtree::query(const geom::Envelope* searchEnv, ItemVisitor& visitor)
         return;
     }
 
-    if(root->getBounds().intersects(searchEnv)) {
+    if(root->getEnvelope().intersects(searchEnv)) {
         query(searchEnv, root, visitor);
     }
 }
@@ -214,7 +210,7 @@ SimpleSTRtree::query(const geom::Envelope* searchEnv,
 {
     for(auto* childNode: node->getChildNodes()) {
 
-        if(!childNode->getBounds().intersects(searchEnv)) {
+        if(!childNode->getEnvelope().intersects(searchEnv)) {
             continue;
         }
 
@@ -239,7 +235,7 @@ SimpleSTRtree::query(const geom::Envelope* searchEnv, std::vector<void*>& matche
         return;
     }
 
-    if(root->getBounds().intersects(searchEnv)) {
+    if(root->getEnvelope().intersects(searchEnv)) {
         query(searchEnv, root, matches);
     }
 }
@@ -253,7 +249,7 @@ SimpleSTRtree::query(const geom::Envelope* searchEnv,
 
     for(auto* childNode: node->getChildNodes()) {
 
-        if(!childNode->getBounds().intersects(searchEnv)) {
+        if(!childNode->getEnvelope().intersects(searchEnv)) {
             continue;
         }
 
@@ -276,7 +272,7 @@ SimpleSTRtree::remove(const geom::Envelope* itemEnv, void* item)
 
 /*public static*/
 std::ostream&
-operator<<(std::ostream& os, const SimpleSTRtree& tree)
+operator<<(std::ostream& os, SimpleSTRtree& tree)
 {
 
     os << "nodeCapacity: " << tree.getNodeCapacity() << std::endl;
@@ -289,6 +285,45 @@ operator<<(std::ostream& os, const SimpleSTRtree& tree)
     return os;
 }
 
+/*********************************************************************************/
+
+/*public*/
+std::pair<const void*, const void*>
+SimpleSTRtree::nearestNeighbour(ItemDistance* itemDist)
+{
+    SimpleSTRdistance strDist(this->getRoot(), this->getRoot(), itemDist);
+    return strDist.nearestNeighbour();
+}
+
+
+/*public*/
+const void*
+SimpleSTRtree::nearestNeighbour(const geom::Envelope* p_env, const void* p_item, ItemDistance* itemDist)
+{
+    std::unique_ptr<SimpleSTRnode> ssn(new SimpleSTRnode(0, p_env, (void*)p_item));
+    SimpleSTRdistance strDist(getRoot(), ssn.get(), itemDist);
+    std::pair<const void*, const void*> result = strDist.nearestNeighbour();
+    return result.first;
+}
+
+
+/*public*/
+std::pair<const void*, const void*>
+SimpleSTRtree::nearestNeighbour(SimpleSTRtree& tree, ItemDistance* itemDist)
+{
+    SimpleSTRdistance strDist(this->getRoot(), tree.getRoot(), itemDist);
+    return strDist.nearestNeighbour();
+}
+
+/*public*/
+bool
+SimpleSTRtree::isWithinDistance(SimpleSTRtree& tree, ItemDistance* itemDist, double maxDistance)
+{
+    SimpleSTRdistance strDist(this->getRoot(), tree.getRoot(), itemDist);
+    return strDist.isWithinDistance(maxDistance);
+}
+
+
 
 
 } // namespace geos.index.strtree
diff --git a/tests/unit/index/strtree/SimpleSTRtreeTest.cpp b/tests/unit/index/strtree/SimpleSTRtreeTest.cpp
index 698f5ab..7fa2869 100644
--- a/tests/unit/index/strtree/SimpleSTRtreeTest.cpp
+++ b/tests/unit/index/strtree/SimpleSTRtreeTest.cpp
@@ -1,9 +1,12 @@
 #include <tut/tut.hpp>
 // geos
-#include <geos/index/strtree/SimpleSTRtree.h>
 #include <geos/geom/GeometryFactory.h>
 #include <geos/geom/Geometry.h>
 #include <geos/geom/Point.h>
+#include <geos/index/strtree/SimpleSTRtree.h>
+#include <geos/index/strtree/GeometryItemDistance.h>
+#include <geos/index/ItemVisitor.h>
+
 
 using namespace geos;
 
@@ -32,19 +35,81 @@ void object::test<1>
     for (int i = 0; i < gridSize; ++i) {
         for (int j = 0; j < gridSize; ++j) {
             geom::Coordinate c((double)i, (double)j);
-            geom::Point *pt = gf->createPoint(c);
+            geom::Point* pt = gf->createPoint(c);
             geoms.emplace_back(pt);
             t.insert(pt);
         }
     }
 
+    // std::cout << t << std::endl;
+
     geom::Envelope qe(-0.5, 1.5, -0.5, 1.5);
     std::vector<void*> matches;
     t.query(&qe, matches);
-    std::cout << matches.size() << std::endl;
+    // std::cout << matches.size() << std::endl;
     ensure(matches.size() == 4);
 
-    // std::cout << t << std::endl;
+    class SimpleTestVisitor: public index::ItemVisitor {
+        public:
+            std::size_t count;
+
+            SimpleTestVisitor()
+                : count(0)
+                {}
+
+            void
+            visitItem(void* item) override
+            {
+                count++;
+                // geom::Point* pt = static_cast<geom::Point*>(item);
+                // std::cout << pt << std::endl;
+            }
+    };
+
+    SimpleTestVisitor vis;
+    t.query(&qe, vis);
+    ensure(vis.count == 4);
+}
+
+
+template<>
+template<>
+void object::test<2>
+()
+{
+    const int gridSize = 10;
+    index::strtree::SimpleSTRtree t1(10);
+    index::strtree::SimpleSTRtree t2(10);
+    std::vector<std::unique_ptr<geom::Geometry>> geoms;
+
+    auto gf = geom::GeometryFactory::create();
+    for (int i = 0; i < gridSize; ++i) {
+        for (int j = 0; j < gridSize; ++j) {
+            geom::Coordinate c1((double)i, (double)j);
+            geom::Coordinate c2((double)(i+gridSize+1), (double)(j+gridSize+1));
+            geom::Point *pt1 = gf->createPoint(c1);
+            geom::Point *pt2 = gf->createPoint(c2);
+            geoms.emplace_back(pt1);
+            geoms.emplace_back(pt2);
+            t1.insert(pt1);
+            t2.insert(pt2);
+        }
+    }
+
+    std::pair<const void*, const void*> rslt;
+    index::strtree::GeometryItemDistance gi;
+    rslt = t1.nearestNeighbour(t2, &gi);
+
+    const geom::Point* g1 = static_cast<const geom::Point*>(rslt.first);
+    const geom::Point* g2 = static_cast<const geom::Point*>(rslt.second);
+
+    // std::cout << *g1 << std::endl;
+    // std::cout << *g2 << std::endl;
+
+    ensure_equals(g1->getX(), 9.0);
+    ensure_equals(g1->getY(), 9.0);
+    ensure_equals(g2->getX(), 11.0);
+    ensure_equals(g2->getY(), 11.0);
 }
 
 

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

Summary of changes:
 include/geos/index/strtree/Makefile.am         |   3 +-
 include/geos/index/strtree/SimpleSTRdistance.h | 166 +++++++++++++
 include/geos/index/strtree/SimpleSTRnode.h     |  34 ++-
 include/geos/index/strtree/SimpleSTRtree.h     |  31 ++-
 src/index/strtree/Makefile.am                  |   3 +-
 src/index/strtree/SimpleSTRdistance.cpp        | 328 +++++++++++++++++++++++++
 src/index/strtree/SimpleSTRnode.cpp            |  16 +-
 src/index/strtree/SimpleSTRtree.cpp            |  71 ++++--
 tests/unit/index/strtree/SimpleSTRtreeTest.cpp |  73 +++++-
 9 files changed, 677 insertions(+), 48 deletions(-)
 create mode 100644 include/geos/index/strtree/SimpleSTRdistance.h
 create mode 100644 src/index/strtree/SimpleSTRdistance.cpp


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list