Coverage Report

Created: 2025-11-16 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/algorithm/construct/LargestEmptyCircle.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
 * Last port: algorithm/construct/LargestEmptyCircle.java
16
 * https://github.com/locationtech/jts/commit/98274a7ea9b40651e9de6323dc10fb2cac17a245
17
 *
18
 **********************************************************************/
19
20
#pragma once
21
22
#include <geos/geom/Coordinate.h>
23
#include <geos/geom/Point.h>
24
#include <geos/geom/Envelope.h>
25
#include <geos/algorithm/construct/IndexedDistanceToPoint.h>
26
#include <geos/algorithm/locate/IndexedPointInAreaLocator.h>
27
#include <geos/operation/distance/IndexedFacetDistance.h>
28
29
#include <memory>
30
#include <queue>
31
32
namespace geos {
33
namespace geom {
34
class Coordinate;
35
class Envelope;
36
class Geometry;
37
class GeometryFactory;
38
class LineString;
39
class Point;
40
}
41
}
42
43
namespace geos {
44
namespace algorithm { // geos::algorithm
45
namespace construct { // geos::algorithm::construct
46
47
/**
48
* Constructs the Largest Empty Circle for a set of obstacle geometries,
49
* up to a specified tolerance. 
50
* The obstacles may be any combination of point, linear and polygonal geometries.
51
*
52
* The Largest Empty Circle (LEC) is the largest circle 
53
* whose interior does not intersect with any obstacle
54
* and whose center lies within a polygonal boundary.
55
* The circle center is the point in the interior of the boundary 
56
* which has the farthest distance from the obstacles 
57
* (up to the accuracy of the distance tolerance).
58
* The circle itself is determined by the center point
59
* and a point lying on an obstacle determining the circle radius.
60
* 
61
* The polygonal boundary may be supplied explicitly.
62
* If it is not specified the convex hull of the obstacles is used as the boundary.
63
* 
64
* To compute an LEC which lies wholly within
65
* a polygonal boundary, include the boundary of the polygon(s) as an obstacle.
66
*
67
* The implementation uses a successive-approximation technique
68
* over a grid of square cells covering the obstacles and boundary.
69
* The grid is refined using a branch-and-bound algorithm. Point
70
* containment and distance are computed in a performant way
71
* by using spatial indexes.
72
*
73
* \author Martin Davis
74
*/
75
class GEOS_DLL LargestEmptyCircle {
76
    using IndexedFacetDistance = geos::operation::distance::IndexedFacetDistance;
77
78
public:
79
80
    /**
81
    * Creates a new instance of a Largest Empty Circle construction.
82
    * The obstacles may be any collection of points, lines and polygons.
83
    * The constructed circle center lies within the convex hull of the obstacles.
84
    *
85
    * @param p_obstacles a geometry representing the obstacles
86
    * @param p_tolerance the distance tolerance for computing the circle center point
87
    */
88
    LargestEmptyCircle(const geom::Geometry* p_obstacles, double p_tolerance);
89
90
    /**
91
    * Creates a new instance of a Largest Empty Circle construction,
92
    * interior-disjoint to a set of obstacle geometries 
93
    * and having its center within a polygonal boundary.
94
    * The obstacles may be any collection of points, lines and polygons.
95
    * If the boundary is null or empty the convex hull
96
    * of the obstacles is used as the boundary.
97
    *
98
    * @param p_obstacles a geometry representing the obstacles
99
    * @param p_boundary a polygonal geometry to contain the LEC center
100
    * @param p_tolerance the distance tolerance for computing the circle center point
101
    */
102
    LargestEmptyCircle(const geom::Geometry* p_obstacles, const geom::Geometry* p_boundary, double p_tolerance);
103
104
0
    ~LargestEmptyCircle() = default;
105
106
    /**
107
    * Computes the center point of the Largest Empty Circle
108
    * within a set of obstacles, up to a given tolerance distance.
109
    * The obstacles may be any collection of points, lines and polygons.
110
    *
111
    * @param p_obstacles a geometry representing the obstacles
112
    * @param p_tolerance the distance tolerance for computing the center point
113
    * @return the center point of the Largest Empty Circle
114
    */
115
    static std::unique_ptr<geom::Point> getCenter(const geom::Geometry* p_obstacles, double p_tolerance);
116
117
    /**
118
    * Computes a radius line of the Largest Empty Circle
119
    * within a set of obstacles, up to a given distance tolerance.
120
    * The obstacles may be any collection of points, lines and polygons.
121
    *
122
    * @param p_obstacles a geometry representing the obstacles
123
    * @param p_tolerance the distance tolerance for computing the center point
124
    * @return a line from the center of the circle to a point on the edge
125
    */
126
    static std::unique_ptr<geom::LineString> getRadiusLine(const geom::Geometry* p_obstacles, double p_tolerance);
127
128
    std::unique_ptr<geom::Point> getCenter();
129
    std::unique_ptr<geom::Point> getRadiusPoint();
130
    std::unique_ptr<geom::LineString> getRadiusLine();
131
132
133
private:
134
135
    /* private members */
136
    double tolerance;
137
    const geom::Geometry* obstacles;
138
    std::unique_ptr<geom::Geometry> boundary;
139
    const geom::GeometryFactory* factory;
140
    geom::Envelope gridEnv;
141
    bool done;
142
    std::unique_ptr<algorithm::locate::IndexedPointInAreaLocator> boundaryPtLocater;
143
    IndexedDistanceToPoint obstacleDistance;
144
    std::unique_ptr<IndexedFacetDistance> boundaryDistance;
145
    geom::CoordinateXY centerPt;
146
    geom::CoordinateXY radiusPt;
147
148
    /**
149
    * Computes the signed distance from a point to the constraints
150
    * (obstacles and boundary).
151
    * Points outside the boundary polygon are assigned a negative distance.
152
    * Their containing cells will be last in the priority queue
153
    * (but will still end up being tested since they may be refined).
154
    *
155
    * @param c the point to compute the distance for
156
    * @return the signed distance to the constraints (negative indicates outside the boundary)
157
    */
158
    double distanceToConstraints(const geom::Coordinate& c);
159
    double distanceToConstraints(double x, double y);
160
    void initBoundary();
161
    void compute();
162
163
    /* private class */
164
    class Cell {
165
    private:
166
        static constexpr double SQRT2 = 1.4142135623730951;
167
        double x;
168
        double y;
169
        double hSize;
170
        double distance;
171
        double maxDist;
172
173
    public:
174
        Cell(double p_x, double p_y, double p_hSize, double p_distanceToConstraints)
175
0
            : x(p_x)
176
0
            , y(p_y)
177
0
            , hSize(p_hSize)
178
0
            , distance(p_distanceToConstraints)
179
0
            , maxDist(p_distanceToConstraints + (p_hSize*SQRT2))
180
0
        {};
181
182
        geom::Envelope getEnvelope() const
183
0
        {
184
0
            geom::Envelope env(x-hSize, x+hSize, y-hSize, y+hSize);
185
0
            return env;
186
0
        }
187
188
        bool isFullyOutside() const
189
0
        {
190
0
            return maxDist < 0.0;
191
0
        }
192
        bool isOutside() const
193
0
        {
194
0
            return distance < 0.0;
195
0
        }
196
        double getMaxDistance() const
197
0
        {
198
0
            return maxDist;
199
0
        }
200
        double getDistance() const
201
0
        {
202
0
            return distance;
203
0
        }
204
        double getHSize() const
205
0
        {
206
0
            return hSize;
207
0
        }
208
        double getX() const
209
0
        {
210
0
            return x;
211
0
        }
212
        double getY() const
213
0
        {
214
0
            return y;
215
0
        }
216
        bool operator< (const Cell& rhs) const
217
0
        {
218
0
            return maxDist < rhs.maxDist;
219
0
        }
220
        bool operator> (const Cell& rhs) const
221
0
        {
222
0
            return maxDist > rhs.maxDist;
223
0
        }
224
        bool operator==(const Cell& rhs) const
225
0
        {
226
0
            return maxDist == rhs.maxDist;
227
0
        }
228
    };
229
230
    bool mayContainCircleCenter(const Cell& cell, const Cell& farthestCell);
231
    void createInitialGrid(const geom::Envelope* env, std::priority_queue<Cell>& cellQueue);
232
    Cell createCentroidCell(const geom::Geometry* geom);
233
234
};
235
236
237
} // geos::algorithm::construct
238
} // geos::algorithm
239
} // geos