/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 |