Skip to content

Commit 4ae3f05

Browse files
committed
Add MaximumInscribedCircle fast exact calculation for simple shapes, port of locationtech/jts#1123
1 parent 06f7488 commit 4ae3f05

File tree

9 files changed

+553
-26
lines changed

9 files changed

+553
-26
lines changed

include/geos/algorithm/Angle.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,19 @@ class GEOS_DLL Angle {
147147
const geom::CoordinateXY& tail,
148148
const geom::CoordinateXY& tip2);
149149

150+
/// Computes the angle of the unoriented bisector
151+
/// of the smallest angle between two vectors.
152+
/// The computed angle will be in the range (-Pi, Pi].
153+
///
154+
/// @param tip1 the tip of v1
155+
/// @param tail the tail of each vector
156+
/// @param tip2 the tip of v2
157+
/// @return the angle of the bisector between v1 and v2
158+
///
159+
static double bisector(const geom::CoordinateXY& tip1,
160+
const geom::CoordinateXY& tail,
161+
const geom::CoordinateXY& tip2);
162+
150163
/// Computes the interior angle between two segments of a ring.
151164
///
152165
/// The ring is assumed to be oriented in a clockwise direction.
@@ -230,14 +243,23 @@ class GEOS_DLL Angle {
230243
/// @param rCos the result of cos(ang)
231244
///
232245
static inline void sinCosSnap(const double ang, double& rSin, double& rCos) {
233-
// calculate both; may be optimized with FSINCOS instruction
234246
rSin = std::sin(ang);
235247
rCos = std::cos(ang);
236248
// snap near-zero values
237249
if (std::fabs(rSin) < 5e-16) rSin = 0.0;
238250
if (std::fabs(rCos) < 5e-16) rCos = 0.0;
239251
}
240252

253+
/// Projects a point by a given angle and distance.
254+
///
255+
/// @param p the point to project
256+
/// @param angle the angle at which to project
257+
/// @param dist the distance to project
258+
/// @return the projected point
259+
///
260+
static geom::CoordinateXY project(const geom::CoordinateXY& p,
261+
double angle, double dist);
262+
241263
};
242264

243265

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**********************************************************************
2+
*
3+
* GEOS - Geometry Engine Open Source
4+
* http://geos.osgeo.org
5+
*
6+
* Copyright (c) 2020 Martin Davis
7+
* Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca>
8+
*
9+
* This is free software; you can redistribute and/or modify it under
10+
* the terms of the GNU Lesser General Public Licence as published
11+
* by the Free Software Foundation.
12+
* See the COPYING file for more information.
13+
*
14+
**********************************************************************
15+
*
16+
* Last port: algorithm/construct/ExactMaxInscribedCircle.java
17+
* https://github.com/locationtech/jts/commit/8d5ced1b784d232e1eecf5df4b71873e8822336a
18+
*
19+
**********************************************************************/
20+
21+
#pragma once
22+
23+
#include <geos/geom/Coordinate.h>
24+
#include <geos/geom/LineSegment.h>
25+
26+
#include <array>
27+
// #include <queue>
28+
29+
30+
31+
namespace geos {
32+
namespace geom {
33+
class CoordinateSequence;
34+
class Geometry;
35+
class Polygon;
36+
}
37+
}
38+
39+
namespace geos {
40+
namespace algorithm { // geos::algorithm
41+
namespace construct { // geos::algorithm::construct
42+
43+
/**
44+
* Computes the Maximum Inscribed Circle for some kinds of convex polygons.
45+
* It determines the circle center point by computing Voronoi node points
46+
* and testing them for distance to generating edges.
47+
* This is more precise than iterated approximation,
48+
* and faster for small polygons (such as triangles and convex quadrilaterals).
49+
*
50+
* @author Martin Davis
51+
*
52+
*/
53+
class GEOS_DLL ExactMaxInscribedCircle {
54+
55+
using CoordinateSequence = geos::geom::CoordinateSequence;
56+
using CoordinateXY = geos::geom::CoordinateXY;
57+
using LineSegment = geos::geom::LineSegment;
58+
using Polygon = geos::geom::Polygon;
59+
60+
public:
61+
62+
ExactMaxInscribedCircle();
63+
64+
/**
65+
* Tests whether a given geometry is supported by this class.
66+
* Currently only triangles and convex quadrilaterals are supported.
67+
*
68+
* @param geom an areal geometry
69+
* @return true if the geometry shape can be evaluated
70+
*/
71+
static bool isSupported(const geom::Geometry* geom);
72+
73+
static std::pair<CoordinateXY, CoordinateXY> computeRadius(const Polygon* polygon);
74+
75+
76+
private:
77+
78+
static bool isTriangle(const Polygon* polygon);
79+
80+
static bool isQuadrilateral(const Polygon* polygon);
81+
82+
static std::pair<CoordinateXY, CoordinateXY> computeTriangle(const CoordinateSequence* ring);
83+
84+
/**
85+
* The Voronoi nodes of a convex polygon occur at the intersection point
86+
* of two bisectors of each triplet of edges.
87+
* The Maximum Inscribed Circle center is the node
88+
* is the farthest distance from the generating edges.
89+
* For a quadrilateral there are 4 distinct edge triplets,
90+
* at each edge with its adjacent edges.
91+
*
92+
* @param ring the polygon ring
93+
* @return an array containing the incircle center and radius points
94+
*/
95+
static std::pair<CoordinateXY, CoordinateXY> computeConvexQuadrilateral(const CoordinateSequence* ring);
96+
97+
static std::array<LineSegment, 4> computeBisectors(const CoordinateSequence* ptsCW,
98+
double diameter);
99+
100+
static CoordinateXY nearestEdgePt(const CoordinateSequence* ring,
101+
const CoordinateXY& pt);
102+
103+
static LineSegment computeConvexBisector(const CoordinateSequence* pts,
104+
std::size_t index, double len);
105+
106+
static bool isConvex(const Polygon* polygon);
107+
108+
static bool isConvex(const CoordinateSequence* ring);
109+
110+
static bool isConvex(const CoordinateXY& p0,
111+
const CoordinateXY& p1,
112+
const CoordinateXY& p2);
113+
114+
static bool isPointInConvexRing(const CoordinateSequence* ringCW,
115+
const CoordinateXY& p);
116+
117+
};
118+
119+
120+
} // geos::algorithm::construct
121+
} // geos::algorithm
122+
} // geos

include/geos/algorithm/construct/MaximumInscribedCircle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ class GEOS_DLL MaximumInscribedCircle {
139139
double distanceToBoundary(const geom::Point& pt);
140140
double distanceToBoundary(double x, double y);
141141
void compute();
142+
void computeApproximation();
143+
void createResult(const geom::CoordinateXY& c, const geom::CoordinateXY& r);
142144

143145
/* private class */
144146
class Cell {

include/geos/geom/Triangle.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ class GEOS_DLL Triangle {
4545
*/
4646
void inCentre(CoordinateXY& resultPoint);
4747

48+
static CoordinateXY inCentre(
49+
const CoordinateXY& p0,
50+
const CoordinateXY& p1,
51+
const CoordinateXY& p2);
52+
4853
/** \brief
4954
* Computes the circumcentre of a triangle.
5055
*

src/algorithm/Angle.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,19 @@ Angle::angleBetweenOriented(const geom::CoordinateXY& tip1,
118118
return angDel;
119119
}
120120

121+
122+
/* public static */
123+
double
124+
Angle::bisector(const geom::CoordinateXY& tip1,
125+
const geom::CoordinateXY& tail,
126+
const geom::CoordinateXY& tip2)
127+
{
128+
double angDel = angleBetweenOriented(tip1, tail, tip2);
129+
double angBi = angle(tail, tip1) + angDel / 2;
130+
return normalize(angBi);
131+
}
132+
133+
121134
/* public static */
122135
double
123136
Angle::interiorAngle(const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
@@ -187,20 +200,32 @@ Angle::diff(double ang1, double ang2)
187200
{
188201
double delAngle;
189202

190-
if(ang1 < ang2) {
203+
if (ang1 < ang2) {
191204
delAngle = ang2 - ang1;
192205
}
193206
else {
194207
delAngle = ang1 - ang2;
195208
}
196209

197-
if(delAngle > MATH_PI) {
210+
if (delAngle > MATH_PI) {
198211
delAngle = PI_TIMES_2 - delAngle;
199212
}
200213

201214
return delAngle;
202215
}
203216

217+
/* public static */
218+
geom::CoordinateXY
219+
Angle::project(const geom::CoordinateXY& p, double angle, double dist)
220+
{
221+
double cosSnap, sinSnap;
222+
sinCosSnap(angle, sinSnap, cosSnap);
223+
double x = p.x + dist * cosSnap;
224+
double y = p.y + dist * sinSnap;
225+
return geom::CoordinateXY(x, y);
226+
}
227+
228+
204229
} // namespace geos.algorithm
205230
} //namespace geos
206231

0 commit comments

Comments
 (0)