/src/geos/include/geos/index/kdtree/KdTree.h
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca> |
7 | | * |
8 | | * This is free software; you can redistribute and/or modify it under |
9 | | * the terms of the GNU Lesser General Public Licence as published |
10 | | * by the Free Software Foundation. |
11 | | * See the COPYING file for more information. |
12 | | * |
13 | | **********************************************************************/ |
14 | | |
15 | | #pragma once |
16 | | |
17 | | #include <geos/export.h> |
18 | | #include <geos/geom/Envelope.h> |
19 | | #include <geos/index/kdtree/KdNodeVisitor.h> |
20 | | #include <geos/index/kdtree/KdNode.h> |
21 | | |
22 | | #include <memory> |
23 | | #include <vector> |
24 | | #include <string> |
25 | | #include <deque> |
26 | | |
27 | | #ifdef _MSC_VER |
28 | | #pragma warning(push) |
29 | | #pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class |
30 | | #endif |
31 | | |
32 | | |
33 | | namespace geos { |
34 | | namespace index { // geos::index |
35 | | namespace kdtree { // geos::index::kdtree |
36 | | |
37 | | /** |
38 | | * An implementation of a 2-D KD-Tree. KD-trees provide fast range searching on |
39 | | * point data. |
40 | | * <p> |
41 | | * This implementation supports detecting and snapping points which are closer |
42 | | * than a given distance tolerance. |
43 | | * If the same point (up to tolerance) is inserted |
44 | | * more than once, it is snapped to the existing node. |
45 | | * In other words, if a point is inserted which lies within the tolerance of a node already in the index, |
46 | | * it is snapped to that node. |
47 | | * When a point is snapped to a node then a new node is not created but the count of the existing node |
48 | | * is incremented. |
49 | | * If more than one node in the tree is within tolerance of an inserted point, |
50 | | * the closest and then lowest node is snapped to. |
51 | | * |
52 | | * @author David Skea |
53 | | * @author Martin Davis |
54 | | */ |
55 | | class GEOS_DLL KdTree { |
56 | | |
57 | | private: |
58 | | |
59 | | std::deque<KdNode> nodeQue; |
60 | | KdNode *root; |
61 | | std::size_t numberOfNodes; |
62 | | double tolerance; |
63 | | |
64 | | KdNode* findBestMatchNode(const geom::Coordinate& p); |
65 | | KdNode* insertExact(const geom::Coordinate& p, void* data); |
66 | | |
67 | | void queryNode(KdNode* currentNode, const geom::Envelope& queryEnv, bool odd, KdNodeVisitor& visitor); |
68 | | KdNode* queryNodePoint(KdNode* currentNode, const geom::Coordinate& queryPt, bool odd); |
69 | | |
70 | | /** |
71 | | * Create a node on a locally managed deque to allow easy |
72 | | * disposal and hopefully faster allocation as well. |
73 | | */ |
74 | | KdNode* createNode(const geom::Coordinate& p, void* data); |
75 | | |
76 | | |
77 | | /** |
78 | | * BestMatchVisitor used to query the tree for a match |
79 | | * within tolerance. |
80 | | */ |
81 | | class BestMatchVisitor : public KdNodeVisitor { |
82 | | public: |
83 | | BestMatchVisitor(const geom::Coordinate& p_p, double p_tolerance); |
84 | | geom::Envelope queryEnvelope(); |
85 | | KdNode* getNode(); |
86 | | void visit(KdNode* node) override; |
87 | | |
88 | | private: |
89 | | // Members |
90 | | double tolerance; |
91 | | KdNode* matchNode; |
92 | | double matchDist; |
93 | | const geom::Coordinate& p; |
94 | | // Declare type as noncopyable |
95 | | BestMatchVisitor(const BestMatchVisitor& other); |
96 | | BestMatchVisitor& operator=(const BestMatchVisitor& rhs); |
97 | | }; |
98 | | |
99 | | /** |
100 | | * AccumulatingVisitor used to query the tree and get list |
101 | | * of matching nodes. |
102 | | */ |
103 | | class AccumulatingVisitor : public KdNodeVisitor { |
104 | | public: |
105 | | AccumulatingVisitor(std::vector<KdNode*>& p_nodeList) : |
106 | 0 | nodeList(p_nodeList) {}; |
107 | 0 | void visit(KdNode* node) override { nodeList.push_back(node); } |
108 | | |
109 | | private: |
110 | | // Members |
111 | | std::vector<KdNode*>& nodeList; |
112 | | // Declare type as noncopyable |
113 | | AccumulatingVisitor(const AccumulatingVisitor& other); |
114 | | AccumulatingVisitor& operator=(const AccumulatingVisitor& rhs); |
115 | | }; |
116 | | |
117 | | |
118 | | |
119 | | public: |
120 | | |
121 | | /** |
122 | | * Converts a collection of {@link KdNode}s to an vector of {@link geom::Coordinate}s. |
123 | | * |
124 | | * @param kdnodes a collection of nodes |
125 | | * @return an vector of the coordinates represented by the nodes |
126 | | */ |
127 | | static std::unique_ptr<std::vector<geom::Coordinate>> toCoordinates(std::vector<KdNode*>& kdnodes); |
128 | | |
129 | | /** |
130 | | * Converts a collection of {@link KdNode}s |
131 | | * to an vector of {@link geom::Coordinate}s, |
132 | | * specifying whether repeated nodes should be represented |
133 | | * by multiple coordinates. |
134 | | * |
135 | | * @param kdnodes a collection of nodes |
136 | | * @param includeRepeated true if repeated nodes should |
137 | | * be included multiple times |
138 | | * @return an vector of the coordinates represented by the nodes |
139 | | */ |
140 | | static std::unique_ptr<std::vector<geom::Coordinate>> toCoordinates(std::vector<KdNode*>& kdnodes, bool includeRepeated); |
141 | | |
142 | | KdTree() : |
143 | 6.88k | root(nullptr), |
144 | 6.88k | numberOfNodes(0), |
145 | 6.88k | tolerance(0.0) |
146 | 6.88k | {}; |
147 | | |
148 | | KdTree(double p_tolerance) : |
149 | 202k | root(nullptr), |
150 | 202k | numberOfNodes(0), |
151 | 202k | tolerance(p_tolerance) |
152 | 202k | {}; |
153 | | |
154 | 0 | bool isEmpty() { return root == nullptr; } |
155 | | |
156 | | /** |
157 | | * Inserts a new point in the kd-tree. |
158 | | */ |
159 | | KdNode* insert(const geom::Coordinate& p); |
160 | | KdNode* insert(const geom::Coordinate& p, void* data); |
161 | | |
162 | | /** |
163 | | * Performs a range search of the points in the index and visits all nodes found. |
164 | | */ |
165 | | void query(const geom::Envelope& queryEnv, KdNodeVisitor& visitor); |
166 | | |
167 | | /** |
168 | | * Performs a range search of the points in the index. |
169 | | */ |
170 | | std::unique_ptr<std::vector<KdNode*>> query(const geom::Envelope& queryEnv); |
171 | | |
172 | | /** |
173 | | * Performs a range search of the points in the index. |
174 | | */ |
175 | | void query(const geom::Envelope& queryEnv, std::vector<KdNode*>& result); |
176 | | |
177 | | /** |
178 | | * Searches for a given point in the index and returns its node if found. |
179 | | */ |
180 | | KdNode* query(const geom::Coordinate& queryPt); |
181 | | |
182 | | }; |
183 | | |
184 | | } // namespace geos::index::kdtree |
185 | | } // namespace geos::index |
186 | | } // namespace geos |
187 | | |
188 | | #ifdef _MSC_VER |
189 | | #pragma warning(pop) |
190 | | #endif |
191 | | |