Skip to content

Commit 18fe3f4

Browse files
authored
Use an error bound filter instead of long double in isInCircle predicate. (#1162)
1 parent 16b0ff4 commit 18fe3f4

File tree

1 file changed

+64
-13
lines changed

1 file changed

+64
-13
lines changed

src/triangulate/quadedge/TrianglePredicate.cpp

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,33 @@ namespace quadedge {
2929

3030
geom::Location
3131
TrianglePredicate::isInCircleNonRobust(
32-
const CoordinateXY& a, const CoordinateXY& b, const CoordinateXY& c,
33-
const CoordinateXY& p)
32+
const CoordinateXY& p, const CoordinateXY& q, const CoordinateXY& r,
33+
const CoordinateXY& t)
3434
{
35-
auto det =
36-
(a.x * a.x + a.y * a.y) * triArea(b, c, p)
37-
- (b.x * b.x + b.y * b.y) * triArea(a, c, p)
38-
+ (c.x * c.x + c.y * c.y) * triArea(a, b, p)
39-
- (p.x * p.x + p.y * p.y) * triArea(a, b, c);
40-
41-
return det > 0 ? geom::Location::EXTERIOR : (det < 0 ? geom::Location::INTERIOR : geom::Location::BOUNDARY);
35+
// The following expression is based on a simplification of the more
36+
// well-known det(ax-cx, ay-cy, (ax-cx)^2 + (ay-cy)^2, ...) found in
37+
// https://github.com/CGAL/cgal/blob/e871025f364360a15671f6e825127df6207afa16/Cartesian_kernel/include/CGAL/predicates/kernel_ftC2.h#L495
38+
auto qpx = q.x - p.x;
39+
auto qpy = q.y - p.y;
40+
auto rpx = r.x - p.x;
41+
auto rpy = r.y - p.y;
42+
auto tpx = t.x - p.x;
43+
auto tpy = t.y - p.y;
44+
auto tqx = t.x - q.x;
45+
auto tqy = t.y - q.y;
46+
auto rqx = r.x - q.x;
47+
auto rqy = r.y - q.y;
48+
auto qpxtpy = qpx * tpy;
49+
auto qpytpx = qpy * tpx;
50+
auto tpxtqx = tpx * tqx;
51+
auto tpytqy = tpy * tqy;
52+
auto qpxrpy = qpx * rpy;
53+
auto qpyrpx = qpy * rpx;
54+
auto rpxrqx = rpx * rqx;
55+
auto rpyrqy = rpy * rqy;
56+
auto det = (qpxtpy - qpytpx) * (rpxrqx + rpyrqy)
57+
- (qpxrpy - qpyrpx) * (tpxtqx + tpytqy);
58+
return static_cast<geom::Location>( (det > 0) - (det < 0) + 1 );
4259
}
4360

4461
geom::Location
@@ -91,11 +108,45 @@ TrianglePredicate::triArea(const CoordinateXY& a,
91108

92109
geom::Location
93110
TrianglePredicate::isInCircleRobust(
94-
const CoordinateXY& a, const CoordinateXY& b, const CoordinateXY& c,
95-
const CoordinateXY& p)
111+
const CoordinateXY& q, const CoordinateXY& p, const CoordinateXY& r,
112+
const CoordinateXY& t)
96113
{
97-
// This implementation is not robust, name is ported from JTS.
98-
return isInCircleNormalized(a, b, c, p);
114+
// This implementation is not robust and defaults to BOUNDARY in case of
115+
// uncertainty arising from floating-point round-off errors or overflow.
116+
// There merits of this approach are discussed in
117+
// https://github.com/libgeos/geos/pull/1162
118+
// The source for the below expression is given in isInCircleNonRobust(...)
119+
auto qpx = q.x - p.x;
120+
auto qpy = q.y - p.y;
121+
auto rpx = r.x - p.x;
122+
auto rpy = r.y - p.y;
123+
auto tpx = t.x - p.x;
124+
auto tpy = t.y - p.y;
125+
auto tqx = t.x - q.x;
126+
auto tqy = t.y - q.y;
127+
auto rqx = r.x - q.x;
128+
auto rqy = r.y - q.y;
129+
auto qpxtpy = qpx * tpy;
130+
auto qpytpx = qpy * tpx;
131+
auto tpxtqx = tpx * tqx;
132+
auto tpytqy = tpy * tqy;
133+
auto qpxrpy = qpx * rpy;
134+
auto qpyrpx = qpy * rpx;
135+
auto rpxrqx = rpx * rqx;
136+
auto rpyrqy = rpy * rqy;
137+
auto det = (qpxtpy - qpytpx) * (rpxrqx + rpyrqy)
138+
- (qpxrpy - qpyrpx) * (tpxtqx + tpytqy);
139+
// The following error bound computation is based on the publication
140+
// https://doi.org/10.1007/s10543-023-00975-x
141+
// It can be replicated by modifying the example given in the accompanying
142+
// repository's https://zenodo.org/records/7539355 incircle.ipynb to render
143+
// the error bound for the above incircle expression.
144+
auto deterror = ((std::abs(qpxtpy) + std::abs(qpytpx))
145+
* (std::abs(rpxrqx) + std::abs(rpyrqy))
146+
+ (std::abs(qpxrpy) + std::abs(qpyrpx))
147+
* (std::abs(tpxtqx) + std::abs(tpytqy)))
148+
* 9.99200719823023e-16;
149+
return static_cast<geom::Location>( (det > deterror) - (det < -deterror) + 1 );
99150
}
100151

101152
} // namespace geos.triangulate.quadedge

0 commit comments

Comments
 (0)