@@ -29,16 +29,33 @@ namespace quadedge {
2929
3030geom::Location
3131TrianglePredicate::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
4461geom::Location
@@ -91,11 +108,45 @@ TrianglePredicate::triArea(const CoordinateXY& a,
91108
92109geom::Location
93110TrianglePredicate::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