File indexing completed on 2025-12-16 10:04:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_POLYGON_DETAIL_VORONOI_PREDICATES
0011 #define BOOST_POLYGON_DETAIL_VORONOI_PREDICATES
0012
0013 #include <utility>
0014
0015 #include "voronoi_robust_fpt.hpp"
0016
0017 namespace boost {
0018 namespace polygon {
0019 namespace detail {
0020
0021
0022
0023 template <typename CTYPE_TRAITS>
0024 class voronoi_predicates {
0025 public:
0026 typedef typename CTYPE_TRAITS::int_type int_type;
0027 typedef typename CTYPE_TRAITS::int_x2_type int_x2_type;
0028 typedef typename CTYPE_TRAITS::uint_x2_type uint_x2_type;
0029 typedef typename CTYPE_TRAITS::big_int_type big_int_type;
0030 typedef typename CTYPE_TRAITS::fpt_type fpt_type;
0031 typedef typename CTYPE_TRAITS::efpt_type efpt_type;
0032 typedef typename CTYPE_TRAITS::ulp_cmp_type ulp_cmp_type;
0033 typedef typename CTYPE_TRAITS::to_fpt_converter_type to_fpt_converter;
0034 typedef typename CTYPE_TRAITS::to_efpt_converter_type to_efpt_converter;
0035
0036 enum {
0037 ULPS = 64,
0038 ULPSx2 = 128
0039 };
0040
0041 template <typename Point>
0042 static bool is_vertical(const Point& point1, const Point& point2) {
0043 return point1.x() == point2.x();
0044 }
0045
0046 template <typename Site>
0047 static bool is_vertical(const Site& site) {
0048 return is_vertical(site.point0(), site.point1());
0049 }
0050
0051
0052
0053
0054 static fpt_type robust_cross_product(int_x2_type a1_,
0055 int_x2_type b1_,
0056 int_x2_type a2_,
0057 int_x2_type b2_) {
0058 static to_fpt_converter to_fpt;
0059 uint_x2_type a1 = static_cast<uint_x2_type>(is_neg(a1_) ? -a1_ : a1_);
0060 uint_x2_type b1 = static_cast<uint_x2_type>(is_neg(b1_) ? -b1_ : b1_);
0061 uint_x2_type a2 = static_cast<uint_x2_type>(is_neg(a2_) ? -a2_ : a2_);
0062 uint_x2_type b2 = static_cast<uint_x2_type>(is_neg(b2_) ? -b2_ : b2_);
0063
0064 uint_x2_type l = a1 * b2;
0065 uint_x2_type r = b1 * a2;
0066
0067 if (is_neg(a1_) ^ is_neg(b2_)) {
0068 if (is_neg(a2_) ^ is_neg(b1_))
0069 return (l > r) ? -to_fpt(l - r) : to_fpt(r - l);
0070 else
0071 return -to_fpt(l + r);
0072 } else {
0073 if (is_neg(a2_) ^ is_neg(b1_))
0074 return to_fpt(l + r);
0075 else
0076 return (l < r) ? -to_fpt(r - l) : to_fpt(l - r);
0077 }
0078 }
0079
0080 struct orientation_test {
0081 public:
0082
0083 enum Orientation {
0084 RIGHT = -1,
0085 COLLINEAR = 0,
0086 LEFT = 1
0087 };
0088
0089
0090
0091 template <typename T>
0092 static Orientation eval(T value) {
0093 if (is_zero(value)) return COLLINEAR;
0094 return (is_neg(value)) ? RIGHT : LEFT;
0095 }
0096
0097 static Orientation eval(int_x2_type dif_x1_,
0098 int_x2_type dif_y1_,
0099 int_x2_type dif_x2_,
0100 int_x2_type dif_y2_) {
0101 return eval(robust_cross_product(dif_x1_, dif_y1_, dif_x2_, dif_y2_));
0102 }
0103
0104 template <typename Point>
0105 static Orientation eval(const Point& point1,
0106 const Point& point2,
0107 const Point& point3) {
0108 int_x2_type dx1 = static_cast<int_x2_type>(point1.x()) -
0109 static_cast<int_x2_type>(point2.x());
0110 int_x2_type dx2 = static_cast<int_x2_type>(point2.x()) -
0111 static_cast<int_x2_type>(point3.x());
0112 int_x2_type dy1 = static_cast<int_x2_type>(point1.y()) -
0113 static_cast<int_x2_type>(point2.y());
0114 int_x2_type dy2 = static_cast<int_x2_type>(point2.y()) -
0115 static_cast<int_x2_type>(point3.y());
0116 return eval(robust_cross_product(dx1, dy1, dx2, dy2));
0117 }
0118 };
0119 typedef orientation_test ot;
0120
0121 template <typename Point>
0122 class point_comparison_predicate {
0123 public:
0124 typedef Point point_type;
0125
0126 bool operator()(const point_type& lhs, const point_type& rhs) const {
0127 if (lhs.x() == rhs.x())
0128 return lhs.y() < rhs.y();
0129 return lhs.x() < rhs.x();
0130 }
0131 };
0132
0133 template <typename Site, typename Circle>
0134 class event_comparison_predicate {
0135 public:
0136 typedef Site site_type;
0137 typedef Circle circle_type;
0138
0139 bool operator()(const site_type& lhs, const site_type& rhs) const {
0140 if (lhs.x0() != rhs.x0())
0141 return lhs.x0() < rhs.x0();
0142 if (!lhs.is_segment()) {
0143 if (!rhs.is_segment())
0144 return lhs.y0() < rhs.y0();
0145 if (is_vertical(rhs))
0146 return lhs.y0() <= rhs.y0();
0147 return true;
0148 } else {
0149 if (is_vertical(rhs)) {
0150 if (is_vertical(lhs))
0151 return lhs.y0() < rhs.y0();
0152 return false;
0153 }
0154 if (is_vertical(lhs))
0155 return true;
0156 if (lhs.y0() != rhs.y0())
0157 return lhs.y0() < rhs.y0();
0158 return ot::eval(lhs.point1(), lhs.point0(), rhs.point1()) == ot::LEFT;
0159 }
0160 }
0161
0162 bool operator()(const site_type& lhs, const circle_type& rhs) const {
0163 typename ulp_cmp_type::Result xCmp =
0164 ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPS);
0165 return xCmp == ulp_cmp_type::LESS;
0166 }
0167
0168 bool operator()(const circle_type& lhs, const site_type& rhs) const {
0169 typename ulp_cmp_type::Result xCmp =
0170 ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPS);
0171 return xCmp == ulp_cmp_type::LESS;
0172 }
0173
0174 bool operator()(const circle_type& lhs, const circle_type& rhs) const {
0175 if (lhs.lower_x() != rhs.lower_x()) {
0176 return lhs.lower_x() < rhs.lower_x();
0177 }
0178 return lhs.y() < rhs.y();
0179 }
0180
0181 private:
0182 ulp_cmp_type ulp_cmp;
0183 to_fpt_converter to_fpt;
0184 };
0185
0186 template <typename Site>
0187 class distance_predicate {
0188 public:
0189 typedef Site site_type;
0190 typedef typename site_type::point_type point_type;
0191
0192
0193
0194
0195 bool operator()(const site_type& left_site,
0196 const site_type& right_site,
0197 const point_type& new_point) const {
0198 if (!left_site.is_segment()) {
0199 if (!right_site.is_segment()) {
0200 return pp(left_site, right_site, new_point);
0201 } else {
0202 return ps(left_site, right_site, new_point, false);
0203 }
0204 } else {
0205 if (!right_site.is_segment()) {
0206 return ps(right_site, left_site, new_point, true);
0207 } else {
0208 return ss(left_site, right_site, new_point);
0209 }
0210 }
0211 }
0212
0213 private:
0214
0215
0216 enum kPredicateResult {
0217 LESS = -1,
0218 UNDEFINED = 0,
0219 MORE = 1
0220 };
0221
0222
0223
0224
0225
0226 bool pp(const site_type& left_site,
0227 const site_type& right_site,
0228 const point_type& new_point) const {
0229 const point_type& left_point = left_site.point0();
0230 const point_type& right_point = right_site.point0();
0231 if (left_point.x() > right_point.x()) {
0232 if (new_point.y() <= left_point.y())
0233 return false;
0234 } else if (left_point.x() < right_point.x()) {
0235 if (new_point.y() >= right_point.y())
0236 return true;
0237 } else {
0238 return static_cast<int_x2_type>(left_point.y()) +
0239 static_cast<int_x2_type>(right_point.y()) <
0240 static_cast<int_x2_type>(new_point.y()) * 2;
0241 }
0242
0243 fpt_type dist1 = find_distance_to_point_arc(left_site, new_point);
0244 fpt_type dist2 = find_distance_to_point_arc(right_site, new_point);
0245
0246
0247 return dist1 < dist2;
0248 }
0249
0250 bool ps(const site_type& left_site, const site_type& right_site,
0251 const point_type& new_point, bool reverse_order) const {
0252 kPredicateResult fast_res = fast_ps(
0253 left_site, right_site, new_point, reverse_order);
0254 if (fast_res != UNDEFINED) {
0255 return fast_res == LESS;
0256 }
0257
0258 fpt_type dist1 = find_distance_to_point_arc(left_site, new_point);
0259 fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point);
0260
0261
0262 return reverse_order ^ (dist1 < dist2);
0263 }
0264
0265 bool ss(const site_type& left_site,
0266 const site_type& right_site,
0267 const point_type& new_point) const {
0268
0269 if (left_site.sorted_index() == right_site.sorted_index()) {
0270 return ot::eval(
0271 left_site.point0(), left_site.point1(), new_point) == ot::LEFT;
0272 }
0273
0274 fpt_type dist1 = find_distance_to_segment_arc(left_site, new_point);
0275 fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point);
0276
0277
0278 return dist1 < dist2;
0279 }
0280
0281 fpt_type find_distance_to_point_arc(
0282 const site_type& site, const point_type& point) const {
0283 fpt_type dx = to_fpt(site.x()) - to_fpt(point.x());
0284 fpt_type dy = to_fpt(site.y()) - to_fpt(point.y());
0285
0286 return (dx * dx + dy * dy) / (to_fpt(2.0) * dx);
0287 }
0288
0289 fpt_type find_distance_to_segment_arc(
0290 const site_type& site, const point_type& point) const {
0291 if (is_vertical(site)) {
0292 return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5);
0293 } else {
0294 const point_type& segment0 = site.point0();
0295 const point_type& segment1 = site.point1();
0296 fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x());
0297 fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y());
0298 fpt_type k = get_sqrt(a1 * a1 + b1 * b1);
0299
0300 if (!is_neg(b1)) {
0301 k = to_fpt(1.0) / (b1 + k);
0302 } else {
0303 k = (k - b1) / (a1 * a1);
0304 }
0305
0306 return k * robust_cross_product(
0307 static_cast<int_x2_type>(segment1.x()) -
0308 static_cast<int_x2_type>(segment0.x()),
0309 static_cast<int_x2_type>(segment1.y()) -
0310 static_cast<int_x2_type>(segment0.y()),
0311 static_cast<int_x2_type>(point.x()) -
0312 static_cast<int_x2_type>(segment0.x()),
0313 static_cast<int_x2_type>(point.y()) -
0314 static_cast<int_x2_type>(segment0.y()));
0315 }
0316 }
0317
0318 kPredicateResult fast_ps(
0319 const site_type& left_site, const site_type& right_site,
0320 const point_type& new_point, bool reverse_order) const {
0321 const point_type& site_point = left_site.point0();
0322 const point_type& segment_start = right_site.point0();
0323 const point_type& segment_end = right_site.point1();
0324
0325 if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT)
0326 return (!right_site.is_inverse()) ? LESS : MORE;
0327
0328 fpt_type dif_x = to_fpt(new_point.x()) - to_fpt(site_point.x());
0329 fpt_type dif_y = to_fpt(new_point.y()) - to_fpt(site_point.y());
0330 fpt_type a = to_fpt(segment_end.x()) - to_fpt(segment_start.x());
0331 fpt_type b = to_fpt(segment_end.y()) - to_fpt(segment_start.y());
0332
0333 if (is_vertical(right_site)) {
0334 if (new_point.y() < site_point.y() && !reverse_order)
0335 return MORE;
0336 else if (new_point.y() > site_point.y() && reverse_order)
0337 return LESS;
0338 return UNDEFINED;
0339 } else {
0340 typename ot::Orientation orientation = ot::eval(
0341 static_cast<int_x2_type>(segment_end.x()) -
0342 static_cast<int_x2_type>(segment_start.x()),
0343 static_cast<int_x2_type>(segment_end.y()) -
0344 static_cast<int_x2_type>(segment_start.y()),
0345 static_cast<int_x2_type>(new_point.x()) -
0346 static_cast<int_x2_type>(site_point.x()),
0347 static_cast<int_x2_type>(new_point.y()) -
0348 static_cast<int_x2_type>(site_point.y()));
0349 if (orientation == ot::LEFT) {
0350 if (!right_site.is_inverse())
0351 return reverse_order ? LESS : UNDEFINED;
0352 return reverse_order ? UNDEFINED : MORE;
0353 }
0354 }
0355
0356 fpt_type fast_left_expr = a * (dif_y + dif_x) * (dif_y - dif_x);
0357 fpt_type fast_right_expr = (to_fpt(2.0) * b) * dif_x * dif_y;
0358 typename ulp_cmp_type::Result expr_cmp =
0359 ulp_cmp(fast_left_expr, fast_right_expr, 4);
0360 if (expr_cmp != ulp_cmp_type::EQUAL) {
0361 if ((expr_cmp == ulp_cmp_type::MORE) ^ reverse_order)
0362 return reverse_order ? LESS : MORE;
0363 return UNDEFINED;
0364 }
0365 return UNDEFINED;
0366 }
0367
0368 private:
0369 ulp_cmp_type ulp_cmp;
0370 to_fpt_converter to_fpt;
0371 };
0372
0373 template <typename Node>
0374 class node_comparison_predicate {
0375 public:
0376 typedef Node node_type;
0377 typedef typename Node::site_type site_type;
0378 typedef typename site_type::point_type point_type;
0379 typedef typename point_type::coordinate_type coordinate_type;
0380 typedef point_comparison_predicate<point_type> point_comparison_type;
0381 typedef distance_predicate<site_type> distance_predicate_type;
0382
0383
0384
0385
0386
0387
0388
0389 bool operator() (const node_type& node1,
0390 const node_type& node2) const {
0391
0392 const site_type& site1 = get_comparison_site(node1);
0393 const site_type& site2 = get_comparison_site(node2);
0394 const point_type& point1 = get_comparison_point(site1);
0395 const point_type& point2 = get_comparison_point(site2);
0396
0397 if (point1.x() < point2.x()) {
0398
0399 return distance_predicate_(
0400 node1.left_site(), node1.right_site(), point2);
0401 } else if (point1.x() > point2.x()) {
0402
0403 return !distance_predicate_(
0404 node2.left_site(), node2.right_site(), point1);
0405 } else {
0406
0407 if (site1.sorted_index() == site2.sorted_index()) {
0408
0409 return get_comparison_y(node1) < get_comparison_y(node2);
0410 } else if (site1.sorted_index() < site2.sorted_index()) {
0411 std::pair<coordinate_type, int> y1 = get_comparison_y(node1, false);
0412 std::pair<coordinate_type, int> y2 = get_comparison_y(node2, true);
0413 if (y1.first != y2.first) return y1.first < y2.first;
0414 return (!site1.is_segment()) ? (y1.second < 0) : false;
0415 } else {
0416 std::pair<coordinate_type, int> y1 = get_comparison_y(node1, true);
0417 std::pair<coordinate_type, int> y2 = get_comparison_y(node2, false);
0418 if (y1.first != y2.first) return y1.first < y2.first;
0419 return (!site2.is_segment()) ? (y2.second > 0) : true;
0420 }
0421 }
0422 }
0423
0424 private:
0425
0426 const site_type& get_comparison_site(const node_type& node) const {
0427 if (node.left_site().sorted_index() > node.right_site().sorted_index()) {
0428 return node.left_site();
0429 }
0430 return node.right_site();
0431 }
0432
0433 const point_type& get_comparison_point(const site_type& site) const {
0434 return point_comparison_(site.point0(), site.point1()) ?
0435 site.point0() : site.point1();
0436 }
0437
0438
0439 std::pair<coordinate_type, int> get_comparison_y(
0440 const node_type& node, bool is_new_node = true) const {
0441 if (node.left_site().sorted_index() ==
0442 node.right_site().sorted_index()) {
0443 return std::make_pair(node.left_site().y0(), 0);
0444 }
0445 if (node.left_site().sorted_index() > node.right_site().sorted_index()) {
0446 if (!is_new_node &&
0447 node.left_site().is_segment() &&
0448 is_vertical(node.left_site())) {
0449 return std::make_pair(node.left_site().y0(), 1);
0450 }
0451 return std::make_pair(node.left_site().y1(), 1);
0452 }
0453 return std::make_pair(node.right_site().y0(), -1);
0454 }
0455
0456 point_comparison_type point_comparison_;
0457 distance_predicate_type distance_predicate_;
0458 };
0459
0460 template <typename Site>
0461 class circle_existence_predicate {
0462 public:
0463 typedef typename Site::point_type point_type;
0464 typedef Site site_type;
0465
0466 bool ppp(const site_type& site1,
0467 const site_type& site2,
0468 const site_type& site3) const {
0469 return ot::eval(site1.point0(),
0470 site2.point0(),
0471 site3.point0()) == ot::RIGHT;
0472 }
0473
0474 bool pps(const site_type& site1,
0475 const site_type& site2,
0476 const site_type& site3,
0477 int segment_index) const {
0478 if (segment_index != 2) {
0479 typename ot::Orientation orient1 = ot::eval(
0480 site1.point0(), site2.point0(), site3.point0());
0481 typename ot::Orientation orient2 = ot::eval(
0482 site1.point0(), site2.point0(), site3.point1());
0483 if (segment_index == 1 && site1.x0() >= site2.x0()) {
0484 if (orient1 != ot::RIGHT)
0485 return false;
0486 } else if (segment_index == 3 && site2.x0() >= site1.x0()) {
0487 if (orient2 != ot::RIGHT)
0488 return false;
0489 } else if (orient1 != ot::RIGHT && orient2 != ot::RIGHT) {
0490 return false;
0491 }
0492 } else {
0493 return (site3.point0() != site1.point0()) ||
0494 (site3.point1() != site2.point0());
0495 }
0496 return true;
0497 }
0498
0499 bool pss(const site_type& site1,
0500 const site_type& site2,
0501 const site_type& site3,
0502 int point_index) const {
0503 if (site2.sorted_index() == site3.sorted_index()) {
0504 return false;
0505 }
0506 if (point_index == 2) {
0507 if (!site2.is_inverse() && site3.is_inverse())
0508 return false;
0509 if (site2.is_inverse() == site3.is_inverse() &&
0510 ot::eval(site2.point0(),
0511 site1.point0(),
0512 site3.point1()) != ot::RIGHT)
0513 return false;
0514 }
0515 return true;
0516 }
0517
0518 bool sss(const site_type& site1,
0519 const site_type& site2,
0520 const site_type& site3) const {
0521 return (site1.sorted_index() != site2.sorted_index()) &&
0522 (site2.sorted_index() != site3.sorted_index());
0523 }
0524 };
0525
0526 template <typename Site, typename Circle>
0527 class mp_circle_formation_functor {
0528 public:
0529 typedef typename Site::point_type point_type;
0530 typedef Site site_type;
0531 typedef Circle circle_type;
0532 typedef robust_sqrt_expr<big_int_type, efpt_type, to_efpt_converter>
0533 robust_sqrt_expr_type;
0534
0535 void ppp(const site_type& site1,
0536 const site_type& site2,
0537 const site_type& site3,
0538 circle_type& circle,
0539 bool recompute_c_x = true,
0540 bool recompute_c_y = true,
0541 bool recompute_lower_x = true) {
0542 big_int_type dif_x[3], dif_y[3], sum_x[2], sum_y[2];
0543 dif_x[0] = static_cast<int_x2_type>(site1.x()) -
0544 static_cast<int_x2_type>(site2.x());
0545 dif_x[1] = static_cast<int_x2_type>(site2.x()) -
0546 static_cast<int_x2_type>(site3.x());
0547 dif_x[2] = static_cast<int_x2_type>(site1.x()) -
0548 static_cast<int_x2_type>(site3.x());
0549 dif_y[0] = static_cast<int_x2_type>(site1.y()) -
0550 static_cast<int_x2_type>(site2.y());
0551 dif_y[1] = static_cast<int_x2_type>(site2.y()) -
0552 static_cast<int_x2_type>(site3.y());
0553 dif_y[2] = static_cast<int_x2_type>(site1.y()) -
0554 static_cast<int_x2_type>(site3.y());
0555 sum_x[0] = static_cast<int_x2_type>(site1.x()) +
0556 static_cast<int_x2_type>(site2.x());
0557 sum_x[1] = static_cast<int_x2_type>(site2.x()) +
0558 static_cast<int_x2_type>(site3.x());
0559 sum_y[0] = static_cast<int_x2_type>(site1.y()) +
0560 static_cast<int_x2_type>(site2.y());
0561 sum_y[1] = static_cast<int_x2_type>(site2.y()) +
0562 static_cast<int_x2_type>(site3.y());
0563 fpt_type inv_denom = to_fpt(0.5) / to_fpt(static_cast<big_int_type>(
0564 dif_x[0] * dif_y[1] - dif_x[1] * dif_y[0]));
0565 big_int_type numer1 = dif_x[0] * sum_x[0] + dif_y[0] * sum_y[0];
0566 big_int_type numer2 = dif_x[1] * sum_x[1] + dif_y[1] * sum_y[1];
0567
0568 if (recompute_c_x || recompute_lower_x) {
0569 big_int_type c_x = numer1 * dif_y[1] - numer2 * dif_y[0];
0570 circle.x(to_fpt(c_x) * inv_denom);
0571
0572 if (recompute_lower_x) {
0573
0574 big_int_type sqr_r = (dif_x[0] * dif_x[0] + dif_y[0] * dif_y[0]) *
0575 (dif_x[1] * dif_x[1] + dif_y[1] * dif_y[1]) *
0576 (dif_x[2] * dif_x[2] + dif_y[2] * dif_y[2]);
0577 fpt_type r = get_sqrt(to_fpt(sqr_r));
0578
0579
0580
0581
0582 if (!is_neg(circle.x())) {
0583 if (!is_neg(inv_denom)) {
0584 circle.lower_x(circle.x() + r * inv_denom);
0585 } else {
0586 circle.lower_x(circle.x() - r * inv_denom);
0587 }
0588 } else {
0589 big_int_type numer = c_x * c_x - sqr_r;
0590 fpt_type lower_x = to_fpt(numer) * inv_denom / (to_fpt(c_x) + r);
0591 circle.lower_x(lower_x);
0592 }
0593 }
0594 }
0595
0596 if (recompute_c_y) {
0597 big_int_type c_y = numer2 * dif_x[0] - numer1 * dif_x[1];
0598 circle.y(to_fpt(c_y) * inv_denom);
0599 }
0600 }
0601
0602
0603 void pps(const site_type& site1,
0604 const site_type& site2,
0605 const site_type& site3,
0606 int segment_index,
0607 circle_type& c_event,
0608 bool recompute_c_x = true,
0609 bool recompute_c_y = true,
0610 bool recompute_lower_x = true) {
0611 big_int_type cA[4], cB[4];
0612 big_int_type line_a = static_cast<int_x2_type>(site3.y1()) -
0613 static_cast<int_x2_type>(site3.y0());
0614 big_int_type line_b = static_cast<int_x2_type>(site3.x0()) -
0615 static_cast<int_x2_type>(site3.x1());
0616 big_int_type segm_len = line_a * line_a + line_b * line_b;
0617 big_int_type vec_x = static_cast<int_x2_type>(site2.y()) -
0618 static_cast<int_x2_type>(site1.y());
0619 big_int_type vec_y = static_cast<int_x2_type>(site1.x()) -
0620 static_cast<int_x2_type>(site2.x());
0621 big_int_type sum_x = static_cast<int_x2_type>(site1.x()) +
0622 static_cast<int_x2_type>(site2.x());
0623 big_int_type sum_y = static_cast<int_x2_type>(site1.y()) +
0624 static_cast<int_x2_type>(site2.y());
0625 big_int_type teta = line_a * vec_x + line_b * vec_y;
0626 big_int_type denom = vec_x * line_b - vec_y * line_a;
0627
0628 big_int_type dif0 = static_cast<int_x2_type>(site3.y1()) -
0629 static_cast<int_x2_type>(site1.y());
0630 big_int_type dif1 = static_cast<int_x2_type>(site1.x()) -
0631 static_cast<int_x2_type>(site3.x1());
0632 big_int_type A = line_a * dif1 - line_b * dif0;
0633 dif0 = static_cast<int_x2_type>(site3.y1()) -
0634 static_cast<int_x2_type>(site2.y());
0635 dif1 = static_cast<int_x2_type>(site2.x()) -
0636 static_cast<int_x2_type>(site3.x1());
0637 big_int_type B = line_a * dif1 - line_b * dif0;
0638 big_int_type sum_AB = A + B;
0639
0640 if (is_zero(denom)) {
0641 big_int_type numer = teta * teta - sum_AB * sum_AB;
0642 denom = teta * sum_AB;
0643 cA[0] = denom * sum_x * 2 + numer * vec_x;
0644 cB[0] = segm_len;
0645 cA[1] = denom * sum_AB * 2 + numer * teta;
0646 cB[1] = 1;
0647 cA[2] = denom * sum_y * 2 + numer * vec_y;
0648 fpt_type inv_denom = to_fpt(1.0) / to_fpt(denom);
0649 if (recompute_c_x)
0650 c_event.x(to_fpt(0.25) * to_fpt(cA[0]) * inv_denom);
0651 if (recompute_c_y)
0652 c_event.y(to_fpt(0.25) * to_fpt(cA[2]) * inv_denom);
0653 if (recompute_lower_x) {
0654 c_event.lower_x(to_fpt(0.25) * to_fpt(sqrt_expr_.eval2(cA, cB)) *
0655 inv_denom / get_sqrt(to_fpt(segm_len)));
0656 }
0657 return;
0658 }
0659
0660 big_int_type det = (teta * teta + denom * denom) * A * B * 4;
0661 fpt_type inv_denom_sqr = to_fpt(1.0) / to_fpt(denom);
0662 inv_denom_sqr *= inv_denom_sqr;
0663
0664 if (recompute_c_x || recompute_lower_x) {
0665 cA[0] = sum_x * denom * denom + teta * sum_AB * vec_x;
0666 cB[0] = 1;
0667 cA[1] = (segment_index == 2) ? -vec_x : vec_x;
0668 cB[1] = det;
0669 if (recompute_c_x) {
0670 c_event.x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(cA, cB)) *
0671 inv_denom_sqr);
0672 }
0673 }
0674
0675 if (recompute_c_y || recompute_lower_x) {
0676 cA[2] = sum_y * denom * denom + teta * sum_AB * vec_y;
0677 cB[2] = 1;
0678 cA[3] = (segment_index == 2) ? -vec_y : vec_y;
0679 cB[3] = det;
0680 if (recompute_c_y) {
0681 c_event.y(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(&cA[2], &cB[2])) *
0682 inv_denom_sqr);
0683 }
0684 }
0685
0686 if (recompute_lower_x) {
0687 cB[0] = cB[0] * segm_len;
0688 cB[1] = cB[1] * segm_len;
0689 cA[2] = sum_AB * (denom * denom + teta * teta);
0690 cB[2] = 1;
0691 cA[3] = (segment_index == 2) ? -teta : teta;
0692 cB[3] = det;
0693 c_event.lower_x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval4(cA, cB)) *
0694 inv_denom_sqr / get_sqrt(to_fpt(segm_len)));
0695 }
0696 }
0697
0698
0699 void pss(const site_type& site1,
0700 const site_type& site2,
0701 const site_type& site3,
0702 int point_index,
0703 circle_type& c_event,
0704 bool recompute_c_x = true,
0705 bool recompute_c_y = true,
0706 bool recompute_lower_x = true) {
0707 big_int_type a[2], b[2], c[2], cA[4], cB[4];
0708 const point_type& segm_start1 = site2.point1();
0709 const point_type& segm_end1 = site2.point0();
0710 const point_type& segm_start2 = site3.point0();
0711 const point_type& segm_end2 = site3.point1();
0712 a[0] = static_cast<int_x2_type>(segm_end1.x()) -
0713 static_cast<int_x2_type>(segm_start1.x());
0714 b[0] = static_cast<int_x2_type>(segm_end1.y()) -
0715 static_cast<int_x2_type>(segm_start1.y());
0716 a[1] = static_cast<int_x2_type>(segm_end2.x()) -
0717 static_cast<int_x2_type>(segm_start2.x());
0718 b[1] = static_cast<int_x2_type>(segm_end2.y()) -
0719 static_cast<int_x2_type>(segm_start2.y());
0720 big_int_type orientation = a[1] * b[0] - a[0] * b[1];
0721 if (is_zero(orientation)) {
0722 fpt_type denom = to_fpt(2.0) * to_fpt(
0723 static_cast<big_int_type>(a[0] * a[0] + b[0] * b[0]));
0724 c[0] = b[0] * (static_cast<int_x2_type>(segm_start2.x()) -
0725 static_cast<int_x2_type>(segm_start1.x())) -
0726 a[0] * (static_cast<int_x2_type>(segm_start2.y()) -
0727 static_cast<int_x2_type>(segm_start1.y()));
0728 big_int_type dx = a[0] * (static_cast<int_x2_type>(site1.y()) -
0729 static_cast<int_x2_type>(segm_start1.y())) -
0730 b[0] * (static_cast<int_x2_type>(site1.x()) -
0731 static_cast<int_x2_type>(segm_start1.x()));
0732 big_int_type dy = b[0] * (static_cast<int_x2_type>(site1.x()) -
0733 static_cast<int_x2_type>(segm_start2.x())) -
0734 a[0] * (static_cast<int_x2_type>(site1.y()) -
0735 static_cast<int_x2_type>(segm_start2.y()));
0736 cB[0] = dx * dy;
0737 cB[1] = 1;
0738
0739 if (recompute_c_y) {
0740 cA[0] = b[0] * ((point_index == 2) ? 2 : -2);
0741 cA[1] = a[0] * a[0] * (static_cast<int_x2_type>(segm_start1.y()) +
0742 static_cast<int_x2_type>(segm_start2.y())) -
0743 a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) +
0744 static_cast<int_x2_type>(segm_start2.x()) -
0745 static_cast<int_x2_type>(site1.x()) * 2) +
0746 b[0] * b[0] * (static_cast<int_x2_type>(site1.y()) * 2);
0747 fpt_type c_y = to_fpt(sqrt_expr_.eval2(cA, cB));
0748 c_event.y(c_y / denom);
0749 }
0750
0751 if (recompute_c_x || recompute_lower_x) {
0752 cA[0] = a[0] * ((point_index == 2) ? 2 : -2);
0753 cA[1] = b[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) +
0754 static_cast<int_x2_type>(segm_start2.x())) -
0755 a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.y()) +
0756 static_cast<int_x2_type>(segm_start2.y()) -
0757 static_cast<int_x2_type>(site1.y()) * 2) +
0758 a[0] * a[0] * (static_cast<int_x2_type>(site1.x()) * 2);
0759
0760 if (recompute_c_x) {
0761 fpt_type c_x = to_fpt(sqrt_expr_.eval2(cA, cB));
0762 c_event.x(c_x / denom);
0763 }
0764
0765 if (recompute_lower_x) {
0766 cA[2] = is_neg(c[0]) ? -c[0] : c[0];
0767 cB[2] = a[0] * a[0] + b[0] * b[0];
0768 fpt_type lower_x = to_fpt(sqrt_expr_.eval3(cA, cB));
0769 c_event.lower_x(lower_x / denom);
0770 }
0771 }
0772 return;
0773 }
0774 c[0] = b[0] * segm_end1.x() - a[0] * segm_end1.y();
0775 c[1] = a[1] * segm_end2.y() - b[1] * segm_end2.x();
0776 big_int_type ix = a[0] * c[1] + a[1] * c[0];
0777 big_int_type iy = b[0] * c[1] + b[1] * c[0];
0778 big_int_type dx = ix - orientation * site1.x();
0779 big_int_type dy = iy - orientation * site1.y();
0780 if (is_zero(dx) && is_zero(dy)) {
0781 fpt_type denom = to_fpt(orientation);
0782 fpt_type c_x = to_fpt(ix) / denom;
0783 fpt_type c_y = to_fpt(iy) / denom;
0784 c_event = circle_type(c_x, c_y, c_x);
0785 return;
0786 }
0787
0788 big_int_type sign = ((point_index == 2) ? 1 : -1) *
0789 (is_neg(orientation) ? 1 : -1);
0790 cA[0] = a[1] * -dx + b[1] * -dy;
0791 cA[1] = a[0] * -dx + b[0] * -dy;
0792 cA[2] = sign;
0793 cA[3] = 0;
0794 cB[0] = a[0] * a[0] + b[0] * b[0];
0795 cB[1] = a[1] * a[1] + b[1] * b[1];
0796 cB[2] = a[0] * a[1] + b[0] * b[1];
0797 cB[3] = (a[0] * dy - b[0] * dx) * (a[1] * dy - b[1] * dx) * -2;
0798 fpt_type temp = to_fpt(
0799 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
0800 fpt_type denom = temp * to_fpt(orientation);
0801
0802 if (recompute_c_y) {
0803 cA[0] = b[1] * (dx * dx + dy * dy) - iy * (dx * a[1] + dy * b[1]);
0804 cA[1] = b[0] * (dx * dx + dy * dy) - iy * (dx * a[0] + dy * b[0]);
0805 cA[2] = iy * sign;
0806 fpt_type cy = to_fpt(
0807 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
0808 c_event.y(cy / denom);
0809 }
0810
0811 if (recompute_c_x || recompute_lower_x) {
0812 cA[0] = a[1] * (dx * dx + dy * dy) - ix * (dx * a[1] + dy * b[1]);
0813 cA[1] = a[0] * (dx * dx + dy * dy) - ix * (dx * a[0] + dy * b[0]);
0814 cA[2] = ix * sign;
0815
0816 if (recompute_c_x) {
0817 fpt_type cx = to_fpt(
0818 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
0819 c_event.x(cx / denom);
0820 }
0821
0822 if (recompute_lower_x) {
0823 cA[3] = orientation * (dx * dx + dy * dy) * (is_neg(temp) ? -1 : 1);
0824 fpt_type lower_x = to_fpt(
0825 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
0826 c_event.lower_x(lower_x / denom);
0827 }
0828 }
0829 }
0830
0831
0832 void sss(const site_type& site1,
0833 const site_type& site2,
0834 const site_type& site3,
0835 circle_type& c_event,
0836 bool recompute_c_x = true,
0837 bool recompute_c_y = true,
0838 bool recompute_lower_x = true) {
0839 big_int_type a[3], b[3], c[3], cA[4], cB[4];
0840
0841
0842 a[0] = static_cast<int_x2_type>(site1.x1()) -
0843 static_cast<int_x2_type>(site1.x0());
0844 a[1] = static_cast<int_x2_type>(site2.x1()) -
0845 static_cast<int_x2_type>(site2.x0());
0846 a[2] = static_cast<int_x2_type>(site3.x1()) -
0847 static_cast<int_x2_type>(site3.x0());
0848
0849 b[0] = static_cast<int_x2_type>(site1.y1()) -
0850 static_cast<int_x2_type>(site1.y0());
0851 b[1] = static_cast<int_x2_type>(site2.y1()) -
0852 static_cast<int_x2_type>(site2.y0());
0853 b[2] = static_cast<int_x2_type>(site3.y1()) -
0854 static_cast<int_x2_type>(site3.y0());
0855
0856 c[0] = static_cast<int_x2_type>(site1.x0()) *
0857 static_cast<int_x2_type>(site1.y1()) -
0858 static_cast<int_x2_type>(site1.y0()) *
0859 static_cast<int_x2_type>(site1.x1());
0860 c[1] = static_cast<int_x2_type>(site2.x0()) *
0861 static_cast<int_x2_type>(site2.y1()) -
0862 static_cast<int_x2_type>(site2.y0()) *
0863 static_cast<int_x2_type>(site2.x1());
0864 c[2] = static_cast<int_x2_type>(site3.x0()) *
0865 static_cast<int_x2_type>(site3.y1()) -
0866 static_cast<int_x2_type>(site3.y0()) *
0867 static_cast<int_x2_type>(site3.x1());
0868
0869 for (int i = 0; i < 3; ++i)
0870 cB[i] = a[i] * a[i] + b[i] * b[i];
0871
0872 for (int i = 0; i < 3; ++i) {
0873 int j = (i+1) % 3;
0874 int k = (i+2) % 3;
0875 cA[i] = a[j] * b[k] - a[k] * b[j];
0876 }
0877 fpt_type denom = to_fpt(sqrt_expr_.eval3(cA, cB));
0878
0879 if (recompute_c_y) {
0880 for (int i = 0; i < 3; ++i) {
0881 int j = (i+1) % 3;
0882 int k = (i+2) % 3;
0883 cA[i] = b[j] * c[k] - b[k] * c[j];
0884 }
0885 fpt_type c_y = to_fpt(sqrt_expr_.eval3(cA, cB));
0886 c_event.y(c_y / denom);
0887 }
0888
0889 if (recompute_c_x || recompute_lower_x) {
0890 cA[3] = 0;
0891 for (int i = 0; i < 3; ++i) {
0892 int j = (i+1) % 3;
0893 int k = (i+2) % 3;
0894 cA[i] = a[j] * c[k] - a[k] * c[j];
0895 if (recompute_lower_x) {
0896 cA[3] = cA[3] + cA[i] * b[i];
0897 }
0898 }
0899
0900 if (recompute_c_x) {
0901 fpt_type c_x = to_fpt(sqrt_expr_.eval3(cA, cB));
0902 c_event.x(c_x / denom);
0903 }
0904
0905 if (recompute_lower_x) {
0906 cB[3] = 1;
0907 fpt_type lower_x = to_fpt(sqrt_expr_.eval4(cA, cB));
0908 c_event.lower_x(lower_x / denom);
0909 }
0910 }
0911 }
0912
0913 private:
0914
0915
0916 template <typename _int, typename _fpt>
0917 _fpt sqrt_expr_evaluator_pss4(_int *A, _int *B) {
0918 _int cA[4], cB[4];
0919 if (is_zero(A[3])) {
0920 _fpt lh = sqrt_expr_.eval2(A, B);
0921 cA[0] = 1;
0922 cB[0] = B[0] * B[1];
0923 cA[1] = B[2];
0924 cB[1] = 1;
0925 _fpt rh = sqrt_expr_.eval1(A+2, B+3) *
0926 get_sqrt(sqrt_expr_.eval2(cA, cB));
0927 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
0928 return lh + rh;
0929 cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
0930 A[2] * A[2] * B[3] * B[2];
0931 cB[0] = 1;
0932 cA[1] = A[0] * A[1] * 2 - A[2] * A[2] * B[3];
0933 cB[1] = B[0] * B[1];
0934 _fpt numer = sqrt_expr_.eval2(cA, cB);
0935 return numer / (lh - rh);
0936 }
0937 cA[0] = 1;
0938 cB[0] = B[0] * B[1];
0939 cA[1] = B[2];
0940 cB[1] = 1;
0941 _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB));
0942 cA[0] = A[0];
0943 cB[0] = B[0];
0944 cA[1] = A[1];
0945 cB[1] = B[1];
0946 cA[2] = A[3];
0947 cB[2] = 1;
0948 _fpt lh = sqrt_expr_.eval3(cA, cB);
0949 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
0950 return lh + rh;
0951 cA[0] = A[3] * A[0] * 2;
0952 cA[1] = A[3] * A[1] * 2;
0953 cA[2] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] +
0954 A[3] * A[3] - A[2] * A[2] * B[2] * B[3];
0955 cA[3] = A[0] * A[1] * 2 - A[2] * A[2] * B[3];
0956 cB[3] = B[0] * B[1];
0957 _fpt numer = sqrt_expr_evaluator_pss3<_int, _fpt>(cA, cB);
0958 return numer / (lh - rh);
0959 }
0960
0961 template <typename _int, typename _fpt>
0962
0963
0964
0965 _fpt sqrt_expr_evaluator_pss3(_int *A, _int *B) {
0966 _int cA[2], cB[2];
0967 _fpt lh = sqrt_expr_.eval2(A, B);
0968 _fpt rh = sqrt_expr_.eval2(A+2, B+2);
0969 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
0970 return lh + rh;
0971 cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
0972 A[2] * A[2] - A[3] * A[3] * B[0] * B[1];
0973 cB[0] = 1;
0974 cA[1] = (A[0] * A[1] - A[2] * A[3]) * 2;
0975 cB[1] = B[3];
0976 _fpt numer = sqrt_expr_.eval2(cA, cB);
0977 return numer / (lh - rh);
0978 }
0979
0980 robust_sqrt_expr_type sqrt_expr_;
0981 to_fpt_converter to_fpt;
0982 };
0983
0984 template <typename Site, typename Circle>
0985 class lazy_circle_formation_functor {
0986 public:
0987 typedef robust_fpt<fpt_type> robust_fpt_type;
0988 typedef robust_dif<robust_fpt_type> robust_dif_type;
0989 typedef typename Site::point_type point_type;
0990 typedef Site site_type;
0991 typedef Circle circle_type;
0992 typedef mp_circle_formation_functor<site_type, circle_type>
0993 exact_circle_formation_functor_type;
0994
0995 void ppp(const site_type& site1,
0996 const site_type& site2,
0997 const site_type& site3,
0998 circle_type& c_event) {
0999 fpt_type dif_x1 = to_fpt(site1.x()) - to_fpt(site2.x());
1000 fpt_type dif_x2 = to_fpt(site2.x()) - to_fpt(site3.x());
1001 fpt_type dif_y1 = to_fpt(site1.y()) - to_fpt(site2.y());
1002 fpt_type dif_y2 = to_fpt(site2.y()) - to_fpt(site3.y());
1003 fpt_type orientation = robust_cross_product(
1004 static_cast<int_x2_type>(site1.x()) -
1005 static_cast<int_x2_type>(site2.x()),
1006 static_cast<int_x2_type>(site2.x()) -
1007 static_cast<int_x2_type>(site3.x()),
1008 static_cast<int_x2_type>(site1.y()) -
1009 static_cast<int_x2_type>(site2.y()),
1010 static_cast<int_x2_type>(site2.y()) -
1011 static_cast<int_x2_type>(site3.y()));
1012 robust_fpt_type inv_orientation(to_fpt(0.5) / orientation, to_fpt(2.0));
1013 fpt_type sum_x1 = to_fpt(site1.x()) + to_fpt(site2.x());
1014 fpt_type sum_x2 = to_fpt(site2.x()) + to_fpt(site3.x());
1015 fpt_type sum_y1 = to_fpt(site1.y()) + to_fpt(site2.y());
1016 fpt_type sum_y2 = to_fpt(site2.y()) + to_fpt(site3.y());
1017 fpt_type dif_x3 = to_fpt(site1.x()) - to_fpt(site3.x());
1018 fpt_type dif_y3 = to_fpt(site1.y()) - to_fpt(site3.y());
1019 robust_dif_type c_x, c_y;
1020 c_x += robust_fpt_type(dif_x1 * sum_x1 * dif_y2, to_fpt(2.0));
1021 c_x += robust_fpt_type(dif_y1 * sum_y1 * dif_y2, to_fpt(2.0));
1022 c_x -= robust_fpt_type(dif_x2 * sum_x2 * dif_y1, to_fpt(2.0));
1023 c_x -= robust_fpt_type(dif_y2 * sum_y2 * dif_y1, to_fpt(2.0));
1024 c_y += robust_fpt_type(dif_x2 * sum_x2 * dif_x1, to_fpt(2.0));
1025 c_y += robust_fpt_type(dif_y2 * sum_y2 * dif_x1, to_fpt(2.0));
1026 c_y -= robust_fpt_type(dif_x1 * sum_x1 * dif_x2, to_fpt(2.0));
1027 c_y -= robust_fpt_type(dif_y1 * sum_y1 * dif_x2, to_fpt(2.0));
1028 robust_dif_type lower_x(c_x);
1029 lower_x -= robust_fpt_type(get_sqrt(
1030 (dif_x1 * dif_x1 + dif_y1 * dif_y1) *
1031 (dif_x2 * dif_x2 + dif_y2 * dif_y2) *
1032 (dif_x3 * dif_x3 + dif_y3 * dif_y3)), to_fpt(5.0));
1033 c_event = circle_type(
1034 c_x.dif().fpv() * inv_orientation.fpv(),
1035 c_y.dif().fpv() * inv_orientation.fpv(),
1036 lower_x.dif().fpv() * inv_orientation.fpv());
1037 bool recompute_c_x = c_x.dif().ulp() > ULPS;
1038 bool recompute_c_y = c_y.dif().ulp() > ULPS;
1039 bool recompute_lower_x = lower_x.dif().ulp() > ULPS;
1040 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
1041 exact_circle_formation_functor_.ppp(
1042 site1, site2, site3, c_event,
1043 recompute_c_x, recompute_c_y, recompute_lower_x);
1044 }
1045 }
1046
1047 void pps(const site_type& site1,
1048 const site_type& site2,
1049 const site_type& site3,
1050 int segment_index,
1051 circle_type& c_event) {
1052 fpt_type line_a = to_fpt(site3.y1()) - to_fpt(site3.y0());
1053 fpt_type line_b = to_fpt(site3.x0()) - to_fpt(site3.x1());
1054 fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y());
1055 fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x());
1056 robust_fpt_type teta(robust_cross_product(
1057 static_cast<int_x2_type>(site3.y1()) -
1058 static_cast<int_x2_type>(site3.y0()),
1059 static_cast<int_x2_type>(site3.x0()) -
1060 static_cast<int_x2_type>(site3.x1()),
1061 static_cast<int_x2_type>(site2.x()) -
1062 static_cast<int_x2_type>(site1.x()),
1063 static_cast<int_x2_type>(site2.y()) -
1064 static_cast<int_x2_type>(site1.y())), to_fpt(1.0));
1065 robust_fpt_type A(robust_cross_product(
1066 static_cast<int_x2_type>(site3.y0()) -
1067 static_cast<int_x2_type>(site3.y1()),
1068 static_cast<int_x2_type>(site3.x0()) -
1069 static_cast<int_x2_type>(site3.x1()),
1070 static_cast<int_x2_type>(site3.y1()) -
1071 static_cast<int_x2_type>(site1.y()),
1072 static_cast<int_x2_type>(site3.x1()) -
1073 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
1074 robust_fpt_type B(robust_cross_product(
1075 static_cast<int_x2_type>(site3.y0()) -
1076 static_cast<int_x2_type>(site3.y1()),
1077 static_cast<int_x2_type>(site3.x0()) -
1078 static_cast<int_x2_type>(site3.x1()),
1079 static_cast<int_x2_type>(site3.y1()) -
1080 static_cast<int_x2_type>(site2.y()),
1081 static_cast<int_x2_type>(site3.x1()) -
1082 static_cast<int_x2_type>(site2.x())), to_fpt(1.0));
1083 robust_fpt_type denom(robust_cross_product(
1084 static_cast<int_x2_type>(site1.y()) -
1085 static_cast<int_x2_type>(site2.y()),
1086 static_cast<int_x2_type>(site1.x()) -
1087 static_cast<int_x2_type>(site2.x()),
1088 static_cast<int_x2_type>(site3.y1()) -
1089 static_cast<int_x2_type>(site3.y0()),
1090 static_cast<int_x2_type>(site3.x1()) -
1091 static_cast<int_x2_type>(site3.x0())), to_fpt(1.0));
1092 robust_fpt_type inv_segm_len(to_fpt(1.0) /
1093 get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0));
1094 robust_dif_type t;
1095 if (ot::eval(denom) == ot::COLLINEAR) {
1096 t += teta / (robust_fpt_type(to_fpt(8.0)) * A);
1097 t -= A / (robust_fpt_type(to_fpt(2.0)) * teta);
1098 } else {
1099 robust_fpt_type det = ((teta * teta + denom * denom) * A * B).sqrt();
1100 if (segment_index == 2) {
1101 t -= det / (denom * denom);
1102 } else {
1103 t += det / (denom * denom);
1104 }
1105 t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom);
1106 }
1107 robust_dif_type c_x, c_y;
1108 c_x += robust_fpt_type(to_fpt(0.5) *
1109 (to_fpt(site1.x()) + to_fpt(site2.x())));
1110 c_x += robust_fpt_type(vec_x) * t;
1111 c_y += robust_fpt_type(to_fpt(0.5) *
1112 (to_fpt(site1.y()) + to_fpt(site2.y())));
1113 c_y += robust_fpt_type(vec_y) * t;
1114 robust_dif_type r, lower_x(c_x);
1115 r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0());
1116 r -= robust_fpt_type(line_b) * robust_fpt_type(site3.y0());
1117 r += robust_fpt_type(line_a) * c_x;
1118 r += robust_fpt_type(line_b) * c_y;
1119 if (r.pos().fpv() < r.neg().fpv())
1120 r = -r;
1121 lower_x += r * inv_segm_len;
1122 c_event = circle_type(
1123 c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
1124 bool recompute_c_x = c_x.dif().ulp() > ULPS;
1125 bool recompute_c_y = c_y.dif().ulp() > ULPS;
1126 bool recompute_lower_x = lower_x.dif().ulp() > ULPS;
1127 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
1128 exact_circle_formation_functor_.pps(
1129 site1, site2, site3, segment_index, c_event,
1130 recompute_c_x, recompute_c_y, recompute_lower_x);
1131 }
1132 }
1133
1134 void pss(const site_type& site1,
1135 const site_type& site2,
1136 const site_type& site3,
1137 int point_index,
1138 circle_type& c_event) {
1139 const point_type& segm_start1 = site2.point1();
1140 const point_type& segm_end1 = site2.point0();
1141 const point_type& segm_start2 = site3.point0();
1142 const point_type& segm_end2 = site3.point1();
1143 fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x());
1144 fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y());
1145 fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x());
1146 fpt_type b2 = to_fpt(segm_end2.y()) - to_fpt(segm_start2.y());
1147 bool recompute_c_x, recompute_c_y, recompute_lower_x;
1148 robust_fpt_type orientation(robust_cross_product(
1149 static_cast<int_x2_type>(segm_end1.y()) -
1150 static_cast<int_x2_type>(segm_start1.y()),
1151 static_cast<int_x2_type>(segm_end1.x()) -
1152 static_cast<int_x2_type>(segm_start1.x()),
1153 static_cast<int_x2_type>(segm_end2.y()) -
1154 static_cast<int_x2_type>(segm_start2.y()),
1155 static_cast<int_x2_type>(segm_end2.x()) -
1156 static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0));
1157 if (ot::eval(orientation) == ot::COLLINEAR) {
1158 robust_fpt_type a(a1 * a1 + b1 * b1, to_fpt(2.0));
1159 robust_fpt_type c(robust_cross_product(
1160 static_cast<int_x2_type>(segm_end1.y()) -
1161 static_cast<int_x2_type>(segm_start1.y()),
1162 static_cast<int_x2_type>(segm_end1.x()) -
1163 static_cast<int_x2_type>(segm_start1.x()),
1164 static_cast<int_x2_type>(segm_start2.y()) -
1165 static_cast<int_x2_type>(segm_start1.y()),
1166 static_cast<int_x2_type>(segm_start2.x()) -
1167 static_cast<int_x2_type>(segm_start1.x())), to_fpt(1.0));
1168 robust_fpt_type det(
1169 robust_cross_product(
1170 static_cast<int_x2_type>(segm_end1.x()) -
1171 static_cast<int_x2_type>(segm_start1.x()),
1172 static_cast<int_x2_type>(segm_end1.y()) -
1173 static_cast<int_x2_type>(segm_start1.y()),
1174 static_cast<int_x2_type>(site1.x()) -
1175 static_cast<int_x2_type>(segm_start1.x()),
1176 static_cast<int_x2_type>(site1.y()) -
1177 static_cast<int_x2_type>(segm_start1.y())) *
1178 robust_cross_product(
1179 static_cast<int_x2_type>(segm_end1.y()) -
1180 static_cast<int_x2_type>(segm_start1.y()),
1181 static_cast<int_x2_type>(segm_end1.x()) -
1182 static_cast<int_x2_type>(segm_start1.x()),
1183 static_cast<int_x2_type>(site1.y()) -
1184 static_cast<int_x2_type>(segm_start2.y()),
1185 static_cast<int_x2_type>(site1.x()) -
1186 static_cast<int_x2_type>(segm_start2.x())),
1187 to_fpt(3.0));
1188 robust_dif_type t;
1189 t -= robust_fpt_type(a1) * robust_fpt_type((
1190 to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())) * to_fpt(0.5) -
1191 to_fpt(site1.x()));
1192 t -= robust_fpt_type(b1) * robust_fpt_type((
1193 to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())) * to_fpt(0.5) -
1194 to_fpt(site1.y()));
1195 if (point_index == 2) {
1196 t += det.sqrt();
1197 } else {
1198 t -= det.sqrt();
1199 }
1200 t /= a;
1201 robust_dif_type c_x, c_y;
1202 c_x += robust_fpt_type(to_fpt(0.5) * (
1203 to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())));
1204 c_x += robust_fpt_type(a1) * t;
1205 c_y += robust_fpt_type(to_fpt(0.5) * (
1206 to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())));
1207 c_y += robust_fpt_type(b1) * t;
1208 robust_dif_type lower_x(c_x);
1209 if (is_neg(c)) {
1210 lower_x -= robust_fpt_type(to_fpt(0.5)) * c / a.sqrt();
1211 } else {
1212 lower_x += robust_fpt_type(to_fpt(0.5)) * c / a.sqrt();
1213 }
1214 recompute_c_x = c_x.dif().ulp() > ULPS;
1215 recompute_c_y = c_y.dif().ulp() > ULPS;
1216 recompute_lower_x = lower_x.dif().ulp() > ULPS;
1217 c_event =
1218 circle_type(c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
1219 } else {
1220 robust_fpt_type sqr_sum1(get_sqrt(a1 * a1 + b1 * b1), to_fpt(2.0));
1221 robust_fpt_type sqr_sum2(get_sqrt(a2 * a2 + b2 * b2), to_fpt(2.0));
1222 robust_fpt_type a(robust_cross_product(
1223 static_cast<int_x2_type>(segm_end1.x()) -
1224 static_cast<int_x2_type>(segm_start1.x()),
1225 static_cast<int_x2_type>(segm_end1.y()) -
1226 static_cast<int_x2_type>(segm_start1.y()),
1227 static_cast<int_x2_type>(segm_start2.y()) -
1228 static_cast<int_x2_type>(segm_end2.y()),
1229 static_cast<int_x2_type>(segm_end2.x()) -
1230 static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0));
1231 if (!is_neg(a)) {
1232 a += sqr_sum1 * sqr_sum2;
1233 } else {
1234 a = (orientation * orientation) / (sqr_sum1 * sqr_sum2 - a);
1235 }
1236 robust_fpt_type or1(robust_cross_product(
1237 static_cast<int_x2_type>(segm_end1.y()) -
1238 static_cast<int_x2_type>(segm_start1.y()),
1239 static_cast<int_x2_type>(segm_end1.x()) -
1240 static_cast<int_x2_type>(segm_start1.x()),
1241 static_cast<int_x2_type>(segm_end1.y()) -
1242 static_cast<int_x2_type>(site1.y()),
1243 static_cast<int_x2_type>(segm_end1.x()) -
1244 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
1245 robust_fpt_type or2(robust_cross_product(
1246 static_cast<int_x2_type>(segm_end2.x()) -
1247 static_cast<int_x2_type>(segm_start2.x()),
1248 static_cast<int_x2_type>(segm_end2.y()) -
1249 static_cast<int_x2_type>(segm_start2.y()),
1250 static_cast<int_x2_type>(segm_end2.x()) -
1251 static_cast<int_x2_type>(site1.x()),
1252 static_cast<int_x2_type>(segm_end2.y()) -
1253 static_cast<int_x2_type>(site1.y())), to_fpt(1.0));
1254 robust_fpt_type det = robust_fpt_type(to_fpt(2.0)) * a * or1 * or2;
1255 robust_fpt_type c1(robust_cross_product(
1256 static_cast<int_x2_type>(segm_end1.y()) -
1257 static_cast<int_x2_type>(segm_start1.y()),
1258 static_cast<int_x2_type>(segm_end1.x()) -
1259 static_cast<int_x2_type>(segm_start1.x()),
1260 static_cast<int_x2_type>(segm_end1.y()),
1261 static_cast<int_x2_type>(segm_end1.x())), to_fpt(1.0));
1262 robust_fpt_type c2(robust_cross_product(
1263 static_cast<int_x2_type>(segm_end2.x()) -
1264 static_cast<int_x2_type>(segm_start2.x()),
1265 static_cast<int_x2_type>(segm_end2.y()) -
1266 static_cast<int_x2_type>(segm_start2.y()),
1267 static_cast<int_x2_type>(segm_end2.x()),
1268 static_cast<int_x2_type>(segm_end2.y())), to_fpt(1.0));
1269 robust_fpt_type inv_orientation =
1270 robust_fpt_type(to_fpt(1.0)) / orientation;
1271 robust_dif_type t, b, ix, iy;
1272 ix += robust_fpt_type(a2) * c1 * inv_orientation;
1273 ix += robust_fpt_type(a1) * c2 * inv_orientation;
1274 iy += robust_fpt_type(b1) * c2 * inv_orientation;
1275 iy += robust_fpt_type(b2) * c1 * inv_orientation;
1276
1277 b += ix * (robust_fpt_type(a1) * sqr_sum2);
1278 b += ix * (robust_fpt_type(a2) * sqr_sum1);
1279 b += iy * (robust_fpt_type(b1) * sqr_sum2);
1280 b += iy * (robust_fpt_type(b2) * sqr_sum1);
1281 b -= sqr_sum1 * robust_fpt_type(robust_cross_product(
1282 static_cast<int_x2_type>(segm_end2.x()) -
1283 static_cast<int_x2_type>(segm_start2.x()),
1284 static_cast<int_x2_type>(segm_end2.y()) -
1285 static_cast<int_x2_type>(segm_start2.y()),
1286 static_cast<int_x2_type>(-site1.y()),
1287 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
1288 b -= sqr_sum2 * robust_fpt_type(robust_cross_product(
1289 static_cast<int_x2_type>(segm_end1.x()) -
1290 static_cast<int_x2_type>(segm_start1.x()),
1291 static_cast<int_x2_type>(segm_end1.y()) -
1292 static_cast<int_x2_type>(segm_start1.y()),
1293 static_cast<int_x2_type>(-site1.y()),
1294 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
1295 t -= b;
1296 if (point_index == 2) {
1297 t += det.sqrt();
1298 } else {
1299 t -= det.sqrt();
1300 }
1301 t /= (a * a);
1302 robust_dif_type c_x(ix), c_y(iy);
1303 c_x += t * (robust_fpt_type(a1) * sqr_sum2);
1304 c_x += t * (robust_fpt_type(a2) * sqr_sum1);
1305 c_y += t * (robust_fpt_type(b1) * sqr_sum2);
1306 c_y += t * (robust_fpt_type(b2) * sqr_sum1);
1307 if (t.pos().fpv() < t.neg().fpv()) {
1308 t = -t;
1309 }
1310 robust_dif_type lower_x(c_x);
1311 if (is_neg(orientation)) {
1312 lower_x -= t * orientation;
1313 } else {
1314 lower_x += t * orientation;
1315 }
1316 recompute_c_x = c_x.dif().ulp() > ULPS;
1317 recompute_c_y = c_y.dif().ulp() > ULPS;
1318 recompute_lower_x = lower_x.dif().ulp() > ULPS;
1319 c_event = circle_type(
1320 c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
1321 }
1322 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
1323 exact_circle_formation_functor_.pss(
1324 site1, site2, site3, point_index, c_event,
1325 recompute_c_x, recompute_c_y, recompute_lower_x);
1326 }
1327 }
1328
1329 void sss(const site_type& site1,
1330 const site_type& site2,
1331 const site_type& site3,
1332 circle_type& c_event) {
1333 robust_fpt_type a1(to_fpt(site1.x1()) - to_fpt(site1.x0()));
1334 robust_fpt_type b1(to_fpt(site1.y1()) - to_fpt(site1.y0()));
1335 robust_fpt_type c1(robust_cross_product(
1336 site1.x0(), site1.y0(),
1337 site1.x1(), site1.y1()), to_fpt(1.0));
1338
1339 robust_fpt_type a2(to_fpt(site2.x1()) - to_fpt(site2.x0()));
1340 robust_fpt_type b2(to_fpt(site2.y1()) - to_fpt(site2.y0()));
1341 robust_fpt_type c2(robust_cross_product(
1342 site2.x0(), site2.y0(),
1343 site2.x1(), site2.y1()), to_fpt(1.0));
1344
1345 robust_fpt_type a3(to_fpt(site3.x1()) - to_fpt(site3.x0()));
1346 robust_fpt_type b3(to_fpt(site3.y1()) - to_fpt(site3.y0()));
1347 robust_fpt_type c3(robust_cross_product(
1348 site3.x0(), site3.y0(),
1349 site3.x1(), site3.y1()), to_fpt(1.0));
1350
1351 robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt();
1352 robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt();
1353 robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt();
1354 robust_fpt_type cross_12(robust_cross_product(
1355 static_cast<int_x2_type>(site1.x1()) -
1356 static_cast<int_x2_type>(site1.x0()),
1357 static_cast<int_x2_type>(site1.y1()) -
1358 static_cast<int_x2_type>(site1.y0()),
1359 static_cast<int_x2_type>(site2.x1()) -
1360 static_cast<int_x2_type>(site2.x0()),
1361 static_cast<int_x2_type>(site2.y1()) -
1362 static_cast<int_x2_type>(site2.y0())), to_fpt(1.0));
1363 robust_fpt_type cross_23(robust_cross_product(
1364 static_cast<int_x2_type>(site2.x1()) -
1365 static_cast<int_x2_type>(site2.x0()),
1366 static_cast<int_x2_type>(site2.y1()) -
1367 static_cast<int_x2_type>(site2.y0()),
1368 static_cast<int_x2_type>(site3.x1()) -
1369 static_cast<int_x2_type>(site3.x0()),
1370 static_cast<int_x2_type>(site3.y1()) -
1371 static_cast<int_x2_type>(site3.y0())), to_fpt(1.0));
1372 robust_fpt_type cross_31(robust_cross_product(
1373 static_cast<int_x2_type>(site3.x1()) -
1374 static_cast<int_x2_type>(site3.x0()),
1375 static_cast<int_x2_type>(site3.y1()) -
1376 static_cast<int_x2_type>(site3.y0()),
1377 static_cast<int_x2_type>(site1.x1()) -
1378 static_cast<int_x2_type>(site1.x0()),
1379 static_cast<int_x2_type>(site1.y1()) -
1380 static_cast<int_x2_type>(site1.y0())), to_fpt(1.0));
1381
1382
1383 robust_dif_type denom;
1384 denom += cross_12 * len3;
1385 denom += cross_23 * len1;
1386 denom += cross_31 * len2;
1387
1388
1389 robust_dif_type r;
1390 r -= cross_12 * c3;
1391 r -= cross_23 * c1;
1392 r -= cross_31 * c2;
1393
1394 robust_dif_type c_x;
1395 c_x += a1 * c2 * len3;
1396 c_x -= a2 * c1 * len3;
1397 c_x += a2 * c3 * len1;
1398 c_x -= a3 * c2 * len1;
1399 c_x += a3 * c1 * len2;
1400 c_x -= a1 * c3 * len2;
1401
1402 robust_dif_type c_y;
1403 c_y += b1 * c2 * len3;
1404 c_y -= b2 * c1 * len3;
1405 c_y += b2 * c3 * len1;
1406 c_y -= b3 * c2 * len1;
1407 c_y += b3 * c1 * len2;
1408 c_y -= b1 * c3 * len2;
1409
1410 robust_dif_type lower_x = c_x + r;
1411
1412 robust_fpt_type denom_dif = denom.dif();
1413 robust_fpt_type c_x_dif = c_x.dif() / denom_dif;
1414 robust_fpt_type c_y_dif = c_y.dif() / denom_dif;
1415 robust_fpt_type lower_x_dif = lower_x.dif() / denom_dif;
1416
1417 bool recompute_c_x = c_x_dif.ulp() > ULPS;
1418 bool recompute_c_y = c_y_dif.ulp() > ULPS;
1419 bool recompute_lower_x = lower_x_dif.ulp() > ULPS;
1420 c_event = circle_type(c_x_dif.fpv(), c_y_dif.fpv(), lower_x_dif.fpv());
1421 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
1422 exact_circle_formation_functor_.sss(
1423 site1, site2, site3, c_event,
1424 recompute_c_x, recompute_c_y, recompute_lower_x);
1425 }
1426 }
1427
1428 private:
1429 exact_circle_formation_functor_type exact_circle_formation_functor_;
1430 to_fpt_converter to_fpt;
1431 };
1432
1433 template <typename Site,
1434 typename Circle,
1435 typename CEP = circle_existence_predicate<Site>,
1436 typename CFF = lazy_circle_formation_functor<Site, Circle> >
1437 class circle_formation_predicate {
1438 public:
1439 typedef Site site_type;
1440 typedef Circle circle_type;
1441 typedef CEP circle_existence_predicate_type;
1442 typedef CFF circle_formation_functor_type;
1443
1444
1445
1446
1447 bool operator()(const site_type& site1, const site_type& site2,
1448 const site_type& site3, circle_type& circle) {
1449 if (!site1.is_segment()) {
1450 if (!site2.is_segment()) {
1451 if (!site3.is_segment()) {
1452
1453 if (!circle_existence_predicate_.ppp(site1, site2, site3))
1454 return false;
1455 circle_formation_functor_.ppp(site1, site2, site3, circle);
1456 } else {
1457
1458 if (!circle_existence_predicate_.pps(site1, site2, site3, 3))
1459 return false;
1460 circle_formation_functor_.pps(site1, site2, site3, 3, circle);
1461 }
1462 } else {
1463 if (!site3.is_segment()) {
1464
1465 if (!circle_existence_predicate_.pps(site1, site3, site2, 2))
1466 return false;
1467 circle_formation_functor_.pps(site1, site3, site2, 2, circle);
1468 } else {
1469
1470 if (!circle_existence_predicate_.pss(site1, site2, site3, 1))
1471 return false;
1472 circle_formation_functor_.pss(site1, site2, site3, 1, circle);
1473 }
1474 }
1475 } else {
1476 if (!site2.is_segment()) {
1477 if (!site3.is_segment()) {
1478
1479 if (!circle_existence_predicate_.pps(site2, site3, site1, 1))
1480 return false;
1481 circle_formation_functor_.pps(site2, site3, site1, 1, circle);
1482 } else {
1483
1484 if (!circle_existence_predicate_.pss(site2, site1, site3, 2))
1485 return false;
1486 circle_formation_functor_.pss(site2, site1, site3, 2, circle);
1487 }
1488 } else {
1489 if (!site3.is_segment()) {
1490
1491 if (!circle_existence_predicate_.pss(site3, site1, site2, 3))
1492 return false;
1493 circle_formation_functor_.pss(site3, site1, site2, 3, circle);
1494 } else {
1495
1496 if (!circle_existence_predicate_.sss(site1, site2, site3))
1497 return false;
1498 circle_formation_functor_.sss(site1, site2, site3, circle);
1499 }
1500 }
1501 }
1502 if (lies_outside_vertical_segment(circle, site1) ||
1503 lies_outside_vertical_segment(circle, site2) ||
1504 lies_outside_vertical_segment(circle, site3)) {
1505 return false;
1506 }
1507 return true;
1508 }
1509
1510 private:
1511 bool lies_outside_vertical_segment(
1512 const circle_type& c, const site_type& s) {
1513 if (!s.is_segment() || !is_vertical(s)) {
1514 return false;
1515 }
1516 fpt_type y0 = to_fpt(s.is_inverse() ? s.y1() : s.y0());
1517 fpt_type y1 = to_fpt(s.is_inverse() ? s.y0() : s.y1());
1518 return ulp_cmp(c.y(), y0, ULPS) == ulp_cmp_type::LESS ||
1519 ulp_cmp(c.y(), y1, ULPS) == ulp_cmp_type::MORE;
1520 }
1521
1522 private:
1523 to_fpt_converter to_fpt;
1524 ulp_cmp_type ulp_cmp;
1525 circle_existence_predicate_type circle_existence_predicate_;
1526 circle_formation_functor_type circle_formation_functor_;
1527 };
1528 };
1529 }
1530 }
1531 }
1532
1533 #endif