Coverage Report

Created: 2025-10-10 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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