32template <
class... Numbers>
33using sign_coordinate_t = detail::promoted_number_t<std::common_type_t<Numbers...>>;
35template <
class AX,
class BX,
class CX>
36using orientation_coordinate_t = sign_coordinate_t<AX, BX, CX>;
37template <
class AX,
class BX>
38using dot_coordinate_t = sign_coordinate_t<AX, BX>;
46template <
class... Numbers>
47using incircle_coordinate_t = detail::promoted_number_t<sign_coordinate_t<Numbers...>>;
56template <
class Ordering>
57constexpr int signOf(
const Ordering& order) {
58 return order > 0 ? 1 : (order < 0 ? -1 : 0);
83struct ApproximatePoint {
94constexpr double approximateAbs(
double value) {
return value < 0.0 ? -value : value; }
105inline constexpr double approximateRoundoff = 0x1p-52;
113inline constexpr double approximateNarrowing = 0x1p-52;
128inline constexpr double approximateConversion = 0x1p-45;
133inline constexpr double approximateMargin = 1.0 + 0x1p-20;
138constexpr Approximate operator+(
const Approximate& a,
const Approximate& b) {
139 const double value = a.value + b.value;
140 return {value, a.error + b.error + approximateRoundoff * approximateAbs(value)};
146constexpr Approximate operator-(
const Approximate& a,
const Approximate& b) {
147 const double value = a.value - b.value;
148 return {value, a.error + b.error + approximateRoundoff * approximateAbs(value)};
157constexpr Approximate operator*(
const Approximate& a,
const Approximate& b) {
158 const double value = a.value * b.value;
160 approximateAbs(a.value) * b.error + approximateAbs(b.value) * a.error +
161 a.error * b.error + approximateRoundoff * approximateAbs(value)};
180 const double quotient =
static_cast<double>(value);
181 return {quotient, approximateConversion * approximateAbs(quotient)};
187template <
class Number>
188constexpr Approximate approximate(
const Number& value) {
189 if constexpr (std::is_floating_point_v<Number>) {
190 if constexpr (numeric_limits<Number>::digits <= numeric_limits<double>::digits &&
191 numeric_limits<Number>::max_exponent <= numeric_limits<double>::max_exponent) {
192 return {
static_cast<double>(value), 0.0};
194 const double narrowed =
static_cast<double>(value);
195 return {narrowed, approximateNarrowing * approximateAbs(narrowed)};
197 }
else if constexpr (numeric_limits<Number>::is_integer &&
198 numeric_limits<Number>::digits <= numeric_limits<double>::digits) {
199 return {
static_cast<double>(value), 0.0};
200 }
else if constexpr (extended_integral<Number>) {
201 const double narrowed =
static_cast<double>(value);
202 return {narrowed, approximateNarrowing * approximateAbs(narrowed)};
204 const double narrowed =
static_cast<double>(value);
205 return {narrowed, approximateConversion * approximateAbs(narrowed)};
210template <
class Po
intType>
211constexpr ApproximatePoint approximatePoint(
const PointType& point) {
212 return {approximate(point.x()), approximate(point.y())};
229constexpr std::partial_ordering approximateSign(
const Approximate& quantity) {
230 const double bound = quantity.error * approximateMargin + 0x1p-1000;
231 if (quantity.value > bound) {
232 return std::partial_ordering::greater;
234 if (quantity.value < -bound) {
235 return std::partial_ordering::less;
237 return std::partial_ordering::unordered;
261template <
class Coordinate>
262inline constexpr bool filtersSign = arbitraryPrecision<Coordinate>;
269constexpr std::partial_ordering crossFilter(
270 const Approximate& ax,
const Approximate& ay,
271 const Approximate& bx,
const Approximate& by) {
272 return approximateSign(ax * by - ay * bx);
281constexpr std::partial_ordering orientationFilter(
282 const ApproximatePoint& a,
const ApproximatePoint& b,
const ApproximatePoint& c) {
283 return crossFilter(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y);
287template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel>
288constexpr std::partial_ordering exactOrientationSign(
292 using Coordinate = orientation_coordinate_t<ANumber, BNumber, CNumber>;
294 const auto abx = asNumber<Coordinate>(b.x()) - asNumber<Coordinate>(a.x());
295 const auto aby = asNumber<Coordinate>(b.y()) - asNumber<Coordinate>(a.y());
296 const auto acx = asNumber<Coordinate>(c.x()) - asNumber<Coordinate>(a.x());
297 const auto acy = asNumber<Coordinate>(c.y()) - asNumber<Coordinate>(a.y());
299 return threeWay(abx * acy, aby * acx);
322template <
class Po
intType,
bool Filters>
323struct FilteredPoint {
324 const PointType* point;
325 ApproximatePoint approximation;
328template <
class Po
intType>
329struct FilteredPoint<PointType, false> {
330 const PointType* point;
341template <
class Coordinate,
class Po
intType>
342constexpr FilteredPoint<PointType, filtersSign<Coordinate>> filtered(
const PointType& point) {
343 if constexpr (filtersSign<Coordinate>) {
344 return {&point, approximatePoint(point)};
353template <
class Coordinate,
class Po
intType>
354constexpr FilteredPoint<PointType, filtersSign<Coordinate>> filtered(
const PointType&&) =
delete;
365template <
class Po
intType>
366constexpr ApproximatePoint approximationOf(
const FilteredPoint<PointType, true>& point) {
367 return point.approximation;
370template <
class Po
intType>
371constexpr ApproximatePoint approximationOf(
const FilteredPoint<PointType, false>& point) {
372 return approximatePoint(*point.point);
385template <
class APo
int,
class BPo
int,
class CPo
int,
bool Filters>
386class DeferredOrientationSign {
388 constexpr DeferredOrientationSign(
const APoint& a,
const BPoint& b,
const CPoint& c,
389 std::partial_ordering proved)
390 : a_(&a), b_(&b), c_(&c), proved_(proved) {}
393 [[nodiscard]]
constexpr bool decided()
const {
394 return proved_ != std::partial_ordering::unordered;
398 [[nodiscard]]
constexpr std::partial_ordering value()
const {
399 return decided() ? proved_ : exactOrientationSign(*a_, *b_, *c_);
406 std::partial_ordering proved_;
410template <
class APo
int,
class BPo
int,
class CPo
int>
411class DeferredOrientationSign<APoint, BPoint, CPoint, false> {
413 constexpr DeferredOrientationSign(
const APoint& a,
const BPoint& b,
const CPoint& c)
414 : a_(&a), b_(&b), c_(&c) {}
416 [[nodiscard]]
constexpr bool decided()
const {
return false; }
418 [[nodiscard]]
constexpr std::partial_ordering value()
const {
419 return exactOrientationSign(*a_, *b_, *c_);
433template <
class APo
int,
bool AFilters,
class BPo
int,
bool BFilters,
class CPo
int,
bool CFilters>
434constexpr auto orientationSignOf(
435 const FilteredPoint<APoint, AFilters>& a,
436 const FilteredPoint<BPoint, BFilters>& b,
437 const FilteredPoint<CPoint, CFilters>& c) {
445 using Coordinate = orientation_coordinate_t<
typename APoint::NumberType,
446 typename BPoint::NumberType,
447 typename CPoint::NumberType>;
448 if constexpr (filtersSign<Coordinate>) {
449 return DeferredOrientationSign<APoint, BPoint, CPoint, true>{
450 *a.point, *b.point, *c.point,
451 orientationFilter(approximationOf(a), approximationOf(b), approximationOf(c))};
453 return DeferredOrientationSign<APoint, BPoint, CPoint, false>{
454 *a.point, *b.point, *c.point};
459template <
class... Signs>
460constexpr bool allDecided(
const Signs&... signs) {
461 return (signs.decided() && ...);
485template <
class Coordinate,
class Po
intType>
486constexpr FilteredPoint<PointType, filtersSign<Coordinate>> filtered(
487 const PointType& point,
488 const std::vector<ApproximatePoint>& approximations,
490 if constexpr (filtersSign<Coordinate>) {
491 return {&point, approximations[index]};
502constexpr std::partial_ordering dotFilter(
503 const Approximate& ax,
const Approximate& ay,
504 const Approximate& bx,
const Approximate& by) {
505 return approximateSign(ax * bx + ay * by);
517template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel>
522 using Coordinate = detail::orientation_coordinate_t<ANumber, BNumber, CNumber>;
524 const auto abx = detail::asNumber<Coordinate>(b.
x()) - detail::asNumber<Coordinate>(a.
x());
525 const auto aby = detail::asNumber<Coordinate>(b.
y()) - detail::asNumber<Coordinate>(a.
y());
526 const auto acx = detail::asNumber<Coordinate>(c.
x()) - detail::asNumber<Coordinate>(a.
x());
527 const auto acy = detail::asNumber<Coordinate>(c.
y()) - detail::asNumber<Coordinate>(a.
y());
529 return abx * acy - aby * acx;
543template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel>
548 using Coordinate = detail::orientation_coordinate_t<ANumber, BNumber, CNumber>;
554 if constexpr (detail::filtersSign<Coordinate>) {
555 const detail::Approximate ax = detail::approximate(a.
x());
556 const detail::Approximate ay = detail::approximate(a.
y());
557 const std::partial_ordering filtered = detail::crossFilter(
558 detail::approximate(b.
x()) - ax, detail::approximate(b.
y()) - ay,
559 detail::approximate(c.
x()) - ax, detail::approximate(c.
y()) - ay);
560 if (filtered != std::partial_ordering::unordered) {
565 return detail::exactOrientationSign(a, b, c);
582template <
class UNumber,
class ULabel,
class VNumber,
class VLabel>
586 using Coordinate = detail::sign_coordinate_t<UNumber, VNumber>;
588 if constexpr (detail::filtersSign<Coordinate>) {
589 const std::partial_ordering filtered = detail::crossFilter(
590 detail::approximate(u.
x()), detail::approximate(u.
y()),
591 detail::approximate(v.
x()), detail::approximate(v.
y()));
592 if (filtered != std::partial_ordering::unordered) {
597 return detail::threeWay(detail::asNumber<Coordinate>(u.
x()) * detail::asNumber<Coordinate>(v.
y()),
598 detail::asNumber<Coordinate>(u.
y()) * detail::asNumber<Coordinate>(v.
x()));
614template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
615 class PNumber,
class PLabel,
class QNumber,
class QLabel>
621 using Coordinate = detail::sign_coordinate_t<ANumber, BNumber, PNumber, QNumber>;
623 if constexpr (detail::filtersSign<Coordinate>) {
624 const std::partial_ordering filtered = detail::crossFilter(
625 detail::approximate(b.
x()) - detail::approximate(a.
x()),
626 detail::approximate(b.
y()) - detail::approximate(a.
y()),
627 detail::approximate(q.
x()) - detail::approximate(p.
x()),
628 detail::approximate(q.
y()) - detail::approximate(p.
y()));
629 if (filtered != std::partial_ordering::unordered) {
634 const auto abx = detail::asNumber<Coordinate>(b.
x()) - detail::asNumber<Coordinate>(a.
x());
635 const auto aby = detail::asNumber<Coordinate>(b.
y()) - detail::asNumber<Coordinate>(a.
y());
636 const auto pqx = detail::asNumber<Coordinate>(q.
x()) - detail::asNumber<Coordinate>(p.
x());
637 const auto pqy = detail::asNumber<Coordinate>(q.
y()) - detail::asNumber<Coordinate>(p.
y());
639 return detail::threeWay(abx * pqy, aby * pqx);
650template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel>
672template <
class ANumber,
class ALabel,
class BNumber,
class BLabel>
687template <
class ANumber,
class ALabel,
class BNumber,
class BLabel>
691 using Coordinate = detail::sign_coordinate_t<ANumber, BNumber>;
693 if constexpr (detail::filtersSign<Coordinate>) {
694 const std::partial_ordering filtered = detail::dotFilter(
695 detail::approximate(a.
x()), detail::approximate(a.
y()),
696 detail::approximate(b.
x()), detail::approximate(b.
y()));
697 if (filtered != std::partial_ordering::unordered) {
702 const auto x = detail::asNumber<Coordinate>(a.
x()) * detail::asNumber<Coordinate>(b.
x());
703 const auto y = detail::asNumber<Coordinate>(a.
y()) * detail::asNumber<Coordinate>(b.
y());
705 return detail::threeWay(
x, -
y);
722template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
723 class PNumber,
class PLabel,
class QNumber,
class QLabel>
729 using Coordinate = detail::sign_coordinate_t<ANumber, BNumber, PNumber, QNumber>;
731 if constexpr (detail::filtersSign<Coordinate>) {
732 const std::partial_ordering filtered = detail::dotFilter(
733 detail::approximate(b.
x()) - detail::approximate(a.
x()),
734 detail::approximate(b.
y()) - detail::approximate(a.
y()),
735 detail::approximate(q.
x()) - detail::approximate(p.
x()),
736 detail::approximate(q.
y()) - detail::approximate(p.
y()));
737 if (filtered != std::partial_ordering::unordered) {
742 const auto abx = detail::asNumber<Coordinate>(b.
x()) - detail::asNumber<Coordinate>(a.
x());
743 const auto aby = detail::asNumber<Coordinate>(b.
y()) - detail::asNumber<Coordinate>(a.
y());
744 const auto pqx = detail::asNumber<Coordinate>(q.
x()) - detail::asNumber<Coordinate>(p.
x());
745 const auto pqy = detail::asNumber<Coordinate>(q.
y()) - detail::asNumber<Coordinate>(p.
y());
747 return detail::threeWay(abx * pqx, -(aby * pqy));
764constexpr std::partial_ordering inCircleFilter(
765 const ApproximatePoint& a,
766 const ApproximatePoint& b,
767 const ApproximatePoint& c,
768 const ApproximatePoint& d) {
769 const Approximate adx = a.x - d.x;
770 const Approximate ady = a.y - d.y;
771 const Approximate bdx = b.x - d.x;
772 const Approximate bdy = b.y - d.y;
773 const Approximate cdx = c.x - d.x;
774 const Approximate cdy = c.y - d.y;
775 const Approximate abdet = adx * bdy - bdx * ady;
776 const Approximate bcdet = bdx * cdy - cdx * bdy;
777 const Approximate cadet = cdx * ady - adx * cdy;
778 const Approximate alift = adx * adx + ady * ady;
779 const Approximate blift = bdx * bdx + bdy * bdy;
780 const Approximate clift = cdx * cdx + cdy * cdy;
781 return approximateSign(alift * bcdet + blift * cadet + clift * abdet);
785template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel,
class DNumber,
class DLabel>
786constexpr std::partial_ordering exactInCircleSign(
791 using Coordinate = incircle_coordinate_t<ANumber, BNumber, CNumber, DNumber>;
793 const auto adx = asNumber<Coordinate>(a.x()) - asNumber<Coordinate>(d.x());
794 const auto ady = asNumber<Coordinate>(a.y()) - asNumber<Coordinate>(d.y());
795 const auto bdx = asNumber<Coordinate>(b.x()) - asNumber<Coordinate>(d.x());
796 const auto bdy = asNumber<Coordinate>(b.y()) - asNumber<Coordinate>(d.y());
797 const auto cdx = asNumber<Coordinate>(c.x()) - asNumber<Coordinate>(d.x());
798 const auto cdy = asNumber<Coordinate>(c.y()) - asNumber<Coordinate>(d.y());
799 const auto abdet = adx * bdy - bdx * ady;
800 const auto bcdet = bdx * cdy - cdx * bdy;
801 const auto cadet = cdx * ady - adx * cdy;
802 const auto alift = adx * adx + ady * ady;
803 const auto blift = bdx * bdx + bdy * bdy;
804 const auto clift = cdx * cdx + cdy * cdy;
805 return threeWay(alift * bcdet + blift * cadet, -clift * abdet);
817template <
class APoint,
bool AFilters,
class BPoint,
bool BFilters,
818 class CPoint,
bool CFilters,
class DPoint,
bool DFilters>
819constexpr std::partial_ordering inCircleSignOf(
820 const FilteredPoint<APoint, AFilters>& a,
821 const FilteredPoint<BPoint, BFilters>& b,
822 const FilteredPoint<CPoint, CFilters>& c,
823 const FilteredPoint<DPoint, DFilters>& d) {
824 using Coordinate = incircle_coordinate_t<
typename APoint::NumberType,
825 typename BPoint::NumberType,
826 typename CPoint::NumberType,
827 typename DPoint::NumberType>;
828 if constexpr (filtersSign<Coordinate>) {
829 const std::partial_ordering filtered = inCircleFilter(
830 approximationOf(a), approximationOf(b), approximationOf(c), approximationOf(d));
831 if (filtered != std::partial_ordering::unordered) {
835 return exactInCircleSign(*a.point, *b.point, *c.point, *d.point);
856template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel,
class DNumber,
class DLabel>
862 using Coordinate = detail::incircle_coordinate_t<ANumber, BNumber, CNumber, DNumber>;
864 const auto adx = detail::asNumber<Coordinate>(a.
x()) - detail::asNumber<Coordinate>(d.
x());
865 const auto ady = detail::asNumber<Coordinate>(a.
y()) - detail::asNumber<Coordinate>(d.
y());
866 const auto bdx = detail::asNumber<Coordinate>(b.
x()) - detail::asNumber<Coordinate>(d.
x());
867 const auto bdy = detail::asNumber<Coordinate>(b.
y()) - detail::asNumber<Coordinate>(d.
y());
868 const auto cdx = detail::asNumber<Coordinate>(c.
x()) - detail::asNumber<Coordinate>(d.
x());
869 const auto cdy = detail::asNumber<Coordinate>(c.
y()) - detail::asNumber<Coordinate>(d.
y());
870 const auto abdet = adx * bdy - bdx * ady;
871 const auto bcdet = bdx * cdy - cdx * bdy;
872 const auto cadet = cdx * ady - adx * cdy;
873 const auto alift = adx * adx + ady * ady;
874 const auto blift = bdx * bdx + bdy * bdy;
875 const auto clift = cdx * cdx + cdy * cdy;
876 return alift * bcdet + blift * cadet + clift * abdet;
893template <
class ANumber,
class ALabel,
class BNumber,
class BLabel,
class CNumber,
class CLabel,
class DNumber,
class DLabel>
899 using Coordinate = detail::incircle_coordinate_t<ANumber, BNumber, CNumber, DNumber>;
907 if constexpr (detail::filtersSign<Coordinate>) {
908 const std::partial_ordering filtered = detail::inCircleFilter(
909 detail::approximatePoint(a), detail::approximatePoint(b),
910 detail::approximatePoint(c), detail::approximatePoint(d));
911 if (filtered != std::partial_ordering::unordered) {
916 return detail::exactInCircleSign(a, b, c, d);
Public declaration of pgl::EmptyShape.
Definition arrangement.hpp:67
constexpr std::partial_ordering inCircleSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c, const Point< DNumber, DLabel > &d)
Classifies a point with respect to the circumcircle of three others.
Definition orientation.hpp:894
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
constexpr auto inCircleDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c, const Point< DNumber, DLabel > &d)
Returns the signed in-circle determinant of a query point.
Definition orientation.hpp:857
constexpr bool sameDirection(const Point< ANumber, ALabel > &a1, const Point< ANumber, ALabel > &a2, const Point< BNumber, BLabel > &b1, const Point< BNumber, BLabel > &b2)
Tests whether the directions a1 -> a2 and b1 -> b2 are parallel.
Definition orientation.hpp:673
constexpr std::partial_ordering dotSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b)
Tells if the angle between two vectors is acute, right, or obtuse.
Definition orientation.hpp:688
constexpr std::partial_ordering orientationSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Classifies the orientation of three points.
Definition orientation.hpp:544
constexpr std::partial_ordering crossSign(const Point< UNumber, ULabel > &u, const Point< VNumber, VLabel > &v)
Classifies the turn from one vector to another.
Definition orientation.hpp:583
Rational(T) -> Rational< T >
constexpr bool collinear(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Tests whether three points are collinear.
Definition orientation.hpp:651
constexpr auto orientationDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Returns the signed orientation determinant of three points.
Definition orientation.hpp:518
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr const NumberType & x() const
Returns the x coordinate.
Definition point.hpp:193
constexpr const NumberType & y() const
Returns the y coordinate.
Definition point.hpp:205