annotate DEPENDENCIES/generic/include/boost/polygon/detail/voronoi_predicates.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Boost.Polygon library detail/voronoi_predicates.hpp header file
Chris@16 2
Chris@16 3 // Copyright Andrii Sydorchuk 2010-2012.
Chris@16 4 // Distributed under the Boost Software License, Version 1.0.
Chris@16 5 // (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 6 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 7
Chris@16 8 // See http://www.boost.org for updates, documentation, and revision history.
Chris@16 9
Chris@16 10 #ifndef BOOST_POLYGON_DETAIL_VORONOI_PREDICATES
Chris@16 11 #define BOOST_POLYGON_DETAIL_VORONOI_PREDICATES
Chris@16 12
Chris@16 13 #include <utility>
Chris@16 14
Chris@16 15 #include "voronoi_robust_fpt.hpp"
Chris@16 16
Chris@16 17 namespace boost {
Chris@16 18 namespace polygon {
Chris@16 19 namespace detail {
Chris@16 20
Chris@16 21 // Predicate utilities. Operates with the coordinate types that could
Chris@16 22 // be converted to the 32-bit signed integer without precision loss.
Chris@16 23 template <typename CTYPE_TRAITS>
Chris@16 24 class voronoi_predicates {
Chris@16 25 public:
Chris@16 26 typedef typename CTYPE_TRAITS::int_type int_type;
Chris@16 27 typedef typename CTYPE_TRAITS::int_x2_type int_x2_type;
Chris@16 28 typedef typename CTYPE_TRAITS::uint_x2_type uint_x2_type;
Chris@16 29 typedef typename CTYPE_TRAITS::big_int_type big_int_type;
Chris@16 30 typedef typename CTYPE_TRAITS::fpt_type fpt_type;
Chris@16 31 typedef typename CTYPE_TRAITS::efpt_type efpt_type;
Chris@16 32 typedef typename CTYPE_TRAITS::ulp_cmp_type ulp_cmp_type;
Chris@16 33 typedef typename CTYPE_TRAITS::to_fpt_converter_type to_fpt_converter;
Chris@16 34 typedef typename CTYPE_TRAITS::to_efpt_converter_type to_efpt_converter;
Chris@16 35
Chris@16 36 enum {
Chris@16 37 ULPS = 64,
Chris@16 38 ULPSx2 = 128
Chris@16 39 };
Chris@16 40
Chris@16 41 template <typename Point>
Chris@16 42 static bool is_vertical(const Point& point1, const Point& point2) {
Chris@16 43 return point1.x() == point2.x();
Chris@16 44 }
Chris@16 45
Chris@16 46 template <typename Site>
Chris@16 47 static bool is_vertical(const Site& site) {
Chris@16 48 return is_vertical(site.point0(), site.point1());
Chris@16 49 }
Chris@16 50
Chris@16 51 // Compute robust cross_product: a1 * b2 - b1 * a2.
Chris@16 52 // It was mathematically proven that the result is correct
Chris@16 53 // with epsilon relative error equal to 1EPS.
Chris@16 54 static fpt_type robust_cross_product(int_x2_type a1_,
Chris@16 55 int_x2_type b1_,
Chris@16 56 int_x2_type a2_,
Chris@16 57 int_x2_type b2_) {
Chris@16 58 static to_fpt_converter to_fpt;
Chris@16 59 uint_x2_type a1 = static_cast<uint_x2_type>(is_neg(a1_) ? -a1_ : a1_);
Chris@16 60 uint_x2_type b1 = static_cast<uint_x2_type>(is_neg(b1_) ? -b1_ : b1_);
Chris@16 61 uint_x2_type a2 = static_cast<uint_x2_type>(is_neg(a2_) ? -a2_ : a2_);
Chris@16 62 uint_x2_type b2 = static_cast<uint_x2_type>(is_neg(b2_) ? -b2_ : b2_);
Chris@16 63
Chris@16 64 uint_x2_type l = a1 * b2;
Chris@16 65 uint_x2_type r = b1 * a2;
Chris@16 66
Chris@16 67 if (is_neg(a1_) ^ is_neg(b2_)) {
Chris@16 68 if (is_neg(a2_) ^ is_neg(b1_))
Chris@16 69 return (l > r) ? -to_fpt(l - r) : to_fpt(r - l);
Chris@16 70 else
Chris@16 71 return -to_fpt(l + r);
Chris@16 72 } else {
Chris@16 73 if (is_neg(a2_) ^ is_neg(b1_))
Chris@16 74 return to_fpt(l + r);
Chris@16 75 else
Chris@16 76 return (l < r) ? -to_fpt(r - l) : to_fpt(l - r);
Chris@16 77 }
Chris@16 78 }
Chris@16 79
Chris@16 80 typedef struct orientation_test {
Chris@16 81 public:
Chris@16 82 // Represents orientation test result.
Chris@16 83 enum Orientation {
Chris@16 84 RIGHT = -1,
Chris@16 85 COLLINEAR = 0,
Chris@16 86 LEFT = 1
Chris@16 87 };
Chris@16 88
Chris@16 89 // Value is a determinant of two vectors (e.g. x1 * y2 - x2 * y1).
Chris@16 90 // Return orientation based on the sign of the determinant.
Chris@16 91 template <typename T>
Chris@16 92 static Orientation eval(T value) {
Chris@16 93 if (is_zero(value)) return COLLINEAR;
Chris@16 94 return (is_neg(value)) ? RIGHT : LEFT;
Chris@16 95 }
Chris@16 96
Chris@16 97 static Orientation eval(int_x2_type dif_x1_,
Chris@16 98 int_x2_type dif_y1_,
Chris@16 99 int_x2_type dif_x2_,
Chris@16 100 int_x2_type dif_y2_) {
Chris@16 101 return eval(robust_cross_product(dif_x1_, dif_y1_, dif_x2_, dif_y2_));
Chris@16 102 }
Chris@16 103
Chris@16 104 template <typename Point>
Chris@16 105 static Orientation eval(const Point& point1,
Chris@16 106 const Point& point2,
Chris@16 107 const Point& point3) {
Chris@16 108 int_x2_type dx1 = static_cast<int_x2_type>(point1.x()) -
Chris@16 109 static_cast<int_x2_type>(point2.x());
Chris@16 110 int_x2_type dx2 = static_cast<int_x2_type>(point2.x()) -
Chris@16 111 static_cast<int_x2_type>(point3.x());
Chris@16 112 int_x2_type dy1 = static_cast<int_x2_type>(point1.y()) -
Chris@16 113 static_cast<int_x2_type>(point2.y());
Chris@16 114 int_x2_type dy2 = static_cast<int_x2_type>(point2.y()) -
Chris@16 115 static_cast<int_x2_type>(point3.y());
Chris@16 116 return eval(robust_cross_product(dx1, dy1, dx2, dy2));
Chris@16 117 }
Chris@16 118 } ot;
Chris@16 119
Chris@16 120 template <typename Point>
Chris@16 121 class point_comparison_predicate {
Chris@16 122 public:
Chris@16 123 typedef Point point_type;
Chris@16 124
Chris@16 125 bool operator()(const point_type& lhs, const point_type& rhs) const {
Chris@16 126 if (lhs.x() == rhs.x())
Chris@16 127 return lhs.y() < rhs.y();
Chris@16 128 return lhs.x() < rhs.x();
Chris@16 129 }
Chris@16 130 };
Chris@16 131
Chris@16 132 template <typename Site, typename Circle>
Chris@16 133 class event_comparison_predicate {
Chris@16 134 public:
Chris@16 135 typedef Site site_type;
Chris@16 136 typedef Circle circle_type;
Chris@16 137
Chris@16 138 bool operator()(const site_type& lhs, const site_type& rhs) const {
Chris@16 139 if (lhs.x0() != rhs.x0())
Chris@16 140 return lhs.x0() < rhs.x0();
Chris@16 141 if (!lhs.is_segment()) {
Chris@16 142 if (!rhs.is_segment())
Chris@16 143 return lhs.y0() < rhs.y0();
Chris@16 144 if (is_vertical(rhs))
Chris@16 145 return lhs.y0() <= rhs.y0();
Chris@16 146 return true;
Chris@16 147 } else {
Chris@16 148 if (is_vertical(rhs)) {
Chris@16 149 if (is_vertical(lhs))
Chris@16 150 return lhs.y0() < rhs.y0();
Chris@16 151 return false;
Chris@16 152 }
Chris@16 153 if (is_vertical(lhs))
Chris@16 154 return true;
Chris@16 155 if (lhs.y0() != rhs.y0())
Chris@16 156 return lhs.y0() < rhs.y0();
Chris@16 157 return ot::eval(lhs.point1(), lhs.point0(), rhs.point1()) == ot::LEFT;
Chris@16 158 }
Chris@16 159 }
Chris@16 160
Chris@16 161 bool operator()(const site_type& lhs, const circle_type& rhs) const {
Chris@16 162 typename ulp_cmp_type::Result xCmp =
Chris@16 163 ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPS);
Chris@16 164 return xCmp == ulp_cmp_type::LESS;
Chris@16 165 }
Chris@16 166
Chris@16 167 bool operator()(const circle_type& lhs, const site_type& rhs) const {
Chris@16 168 typename ulp_cmp_type::Result xCmp =
Chris@16 169 ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPS);
Chris@16 170 return xCmp == ulp_cmp_type::LESS;
Chris@16 171 }
Chris@16 172
Chris@16 173 bool operator()(const circle_type& lhs, const circle_type& rhs) const {
Chris@16 174 if (lhs.lower_x() != rhs.lower_x()) {
Chris@16 175 return lhs.lower_x() < rhs.lower_x();
Chris@16 176 }
Chris@16 177 return lhs.y() < rhs.y();
Chris@16 178 }
Chris@16 179
Chris@16 180 private:
Chris@16 181 ulp_cmp_type ulp_cmp;
Chris@16 182 to_fpt_converter to_fpt;
Chris@16 183 };
Chris@16 184
Chris@16 185 template <typename Site>
Chris@16 186 class distance_predicate {
Chris@16 187 public:
Chris@16 188 typedef Site site_type;
Chris@16 189 typedef typename site_type::point_type point_type;
Chris@16 190
Chris@16 191 // Returns true if a horizontal line going through a new site intersects
Chris@16 192 // right arc at first, else returns false. If horizontal line goes
Chris@16 193 // through intersection point of the given two arcs returns false also.
Chris@16 194 bool operator()(const site_type& left_site,
Chris@16 195 const site_type& right_site,
Chris@16 196 const point_type& new_point) const {
Chris@16 197 if (!left_site.is_segment()) {
Chris@16 198 if (!right_site.is_segment()) {
Chris@16 199 return pp(left_site, right_site, new_point);
Chris@16 200 } else {
Chris@16 201 return ps(left_site, right_site, new_point, false);
Chris@16 202 }
Chris@16 203 } else {
Chris@16 204 if (!right_site.is_segment()) {
Chris@16 205 return ps(right_site, left_site, new_point, true);
Chris@16 206 } else {
Chris@16 207 return ss(left_site, right_site, new_point);
Chris@16 208 }
Chris@16 209 }
Chris@16 210 }
Chris@16 211
Chris@16 212 private:
Chris@16 213 // Represents the result of the epsilon robust predicate. If the
Chris@16 214 // result is undefined some further processing is usually required.
Chris@16 215 enum kPredicateResult {
Chris@16 216 LESS = -1,
Chris@16 217 UNDEFINED = 0,
Chris@16 218 MORE = 1
Chris@16 219 };
Chris@16 220
Chris@16 221 // Robust predicate, avoids using high-precision libraries.
Chris@16 222 // Returns true if a horizontal line going through the new point site
Chris@16 223 // intersects right arc at first, else returns false. If horizontal line
Chris@16 224 // goes through intersection point of the given two arcs returns false.
Chris@16 225 bool pp(const site_type& left_site,
Chris@16 226 const site_type& right_site,
Chris@16 227 const point_type& new_point) const {
Chris@16 228 const point_type& left_point = left_site.point0();
Chris@16 229 const point_type& right_point = right_site.point0();
Chris@16 230 if (left_point.x() > right_point.x()) {
Chris@16 231 if (new_point.y() <= left_point.y())
Chris@16 232 return false;
Chris@16 233 } else if (left_point.x() < right_point.x()) {
Chris@16 234 if (new_point.y() >= right_point.y())
Chris@16 235 return true;
Chris@16 236 } else {
Chris@16 237 return static_cast<int_x2_type>(left_point.y()) +
Chris@16 238 static_cast<int_x2_type>(right_point.y()) <
Chris@16 239 static_cast<int_x2_type>(new_point.y()) * 2;
Chris@16 240 }
Chris@16 241
Chris@16 242 fpt_type dist1 = find_distance_to_point_arc(left_site, new_point);
Chris@16 243 fpt_type dist2 = find_distance_to_point_arc(right_site, new_point);
Chris@16 244
Chris@16 245 // The undefined ulp range is equal to 3EPS + 3EPS <= 6ULP.
Chris@16 246 return dist1 < dist2;
Chris@16 247 }
Chris@16 248
Chris@16 249 bool ps(const site_type& left_site, const site_type& right_site,
Chris@16 250 const point_type& new_point, bool reverse_order) const {
Chris@16 251 kPredicateResult fast_res = fast_ps(
Chris@16 252 left_site, right_site, new_point, reverse_order);
Chris@16 253 if (fast_res != UNDEFINED) {
Chris@16 254 return fast_res == LESS;
Chris@16 255 }
Chris@16 256
Chris@16 257 fpt_type dist1 = find_distance_to_point_arc(left_site, new_point);
Chris@16 258 fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point);
Chris@16 259
Chris@16 260 // The undefined ulp range is equal to 3EPS + 7EPS <= 10ULP.
Chris@16 261 return reverse_order ^ (dist1 < dist2);
Chris@16 262 }
Chris@16 263
Chris@16 264 bool ss(const site_type& left_site,
Chris@16 265 const site_type& right_site,
Chris@16 266 const point_type& new_point) const {
Chris@16 267 // Handle temporary segment sites.
Chris@16 268 if (left_site.sorted_index() == right_site.sorted_index()) {
Chris@16 269 return ot::eval(
Chris@16 270 left_site.point0(), left_site.point1(), new_point) == ot::LEFT;
Chris@16 271 }
Chris@16 272
Chris@16 273 fpt_type dist1 = find_distance_to_segment_arc(left_site, new_point);
Chris@16 274 fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point);
Chris@16 275
Chris@16 276 // The undefined ulp range is equal to 7EPS + 7EPS <= 14ULP.
Chris@16 277 return dist1 < dist2;
Chris@16 278 }
Chris@16 279
Chris@16 280 fpt_type find_distance_to_point_arc(
Chris@16 281 const site_type& site, const point_type& point) const {
Chris@16 282 fpt_type dx = to_fpt(site.x()) - to_fpt(point.x());
Chris@16 283 fpt_type dy = to_fpt(site.y()) - to_fpt(point.y());
Chris@16 284 // The relative error is at most 3EPS.
Chris@16 285 return (dx * dx + dy * dy) / (to_fpt(2.0) * dx);
Chris@16 286 }
Chris@16 287
Chris@16 288 fpt_type find_distance_to_segment_arc(
Chris@16 289 const site_type& site, const point_type& point) const {
Chris@16 290 if (is_vertical(site)) {
Chris@16 291 return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5);
Chris@16 292 } else {
Chris@16 293 const point_type& segment0 = site.point0();
Chris@16 294 const point_type& segment1 = site.point1();
Chris@16 295 fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x());
Chris@16 296 fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y());
Chris@16 297 fpt_type k = get_sqrt(a1 * a1 + b1 * b1);
Chris@16 298 // Avoid subtraction while computing k.
Chris@16 299 if (!is_neg(b1)) {
Chris@16 300 k = to_fpt(1.0) / (b1 + k);
Chris@16 301 } else {
Chris@16 302 k = (k - b1) / (a1 * a1);
Chris@16 303 }
Chris@16 304 // The relative error is at most 7EPS.
Chris@16 305 return k * robust_cross_product(
Chris@16 306 static_cast<int_x2_type>(segment1.x()) -
Chris@16 307 static_cast<int_x2_type>(segment0.x()),
Chris@16 308 static_cast<int_x2_type>(segment1.y()) -
Chris@16 309 static_cast<int_x2_type>(segment0.y()),
Chris@16 310 static_cast<int_x2_type>(point.x()) -
Chris@16 311 static_cast<int_x2_type>(segment0.x()),
Chris@16 312 static_cast<int_x2_type>(point.y()) -
Chris@16 313 static_cast<int_x2_type>(segment0.y()));
Chris@16 314 }
Chris@16 315 }
Chris@16 316
Chris@16 317 kPredicateResult fast_ps(
Chris@16 318 const site_type& left_site, const site_type& right_site,
Chris@16 319 const point_type& new_point, bool reverse_order) const {
Chris@16 320 const point_type& site_point = left_site.point0();
Chris@16 321 const point_type& segment_start = right_site.point0();
Chris@16 322 const point_type& segment_end = right_site.point1();
Chris@16 323
Chris@16 324 if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT)
Chris@16 325 return (!right_site.is_inverse()) ? LESS : MORE;
Chris@16 326
Chris@16 327 fpt_type dif_x = to_fpt(new_point.x()) - to_fpt(site_point.x());
Chris@16 328 fpt_type dif_y = to_fpt(new_point.y()) - to_fpt(site_point.y());
Chris@16 329 fpt_type a = to_fpt(segment_end.x()) - to_fpt(segment_start.x());
Chris@16 330 fpt_type b = to_fpt(segment_end.y()) - to_fpt(segment_start.y());
Chris@16 331
Chris@16 332 if (is_vertical(right_site)) {
Chris@16 333 if (new_point.y() < site_point.y() && !reverse_order)
Chris@16 334 return MORE;
Chris@16 335 else if (new_point.y() > site_point.y() && reverse_order)
Chris@16 336 return LESS;
Chris@16 337 return UNDEFINED;
Chris@16 338 } else {
Chris@16 339 typename ot::Orientation orientation = ot::eval(
Chris@16 340 static_cast<int_x2_type>(segment_end.x()) -
Chris@16 341 static_cast<int_x2_type>(segment_start.x()),
Chris@16 342 static_cast<int_x2_type>(segment_end.y()) -
Chris@16 343 static_cast<int_x2_type>(segment_start.y()),
Chris@16 344 static_cast<int_x2_type>(new_point.x()) -
Chris@16 345 static_cast<int_x2_type>(site_point.x()),
Chris@16 346 static_cast<int_x2_type>(new_point.y()) -
Chris@16 347 static_cast<int_x2_type>(site_point.y()));
Chris@16 348 if (orientation == ot::LEFT) {
Chris@16 349 if (!right_site.is_inverse())
Chris@16 350 return reverse_order ? LESS : UNDEFINED;
Chris@16 351 return reverse_order ? UNDEFINED : MORE;
Chris@16 352 }
Chris@16 353 }
Chris@16 354
Chris@16 355 fpt_type fast_left_expr = a * (dif_y + dif_x) * (dif_y - dif_x);
Chris@16 356 fpt_type fast_right_expr = (to_fpt(2.0) * b) * dif_x * dif_y;
Chris@16 357 typename ulp_cmp_type::Result expr_cmp =
Chris@16 358 ulp_cmp(fast_left_expr, fast_right_expr, 4);
Chris@16 359 if (expr_cmp != ulp_cmp_type::EQUAL) {
Chris@16 360 if ((expr_cmp == ulp_cmp_type::MORE) ^ reverse_order)
Chris@16 361 return reverse_order ? LESS : MORE;
Chris@16 362 return UNDEFINED;
Chris@16 363 }
Chris@16 364 return UNDEFINED;
Chris@16 365 }
Chris@16 366
Chris@16 367 private:
Chris@16 368 ulp_cmp_type ulp_cmp;
Chris@16 369 to_fpt_converter to_fpt;
Chris@16 370 };
Chris@16 371
Chris@16 372 template <typename Node>
Chris@16 373 class node_comparison_predicate {
Chris@16 374 public:
Chris@16 375 typedef Node node_type;
Chris@16 376 typedef typename Node::site_type site_type;
Chris@16 377 typedef typename site_type::point_type point_type;
Chris@16 378 typedef typename point_type::coordinate_type coordinate_type;
Chris@16 379 typedef point_comparison_predicate<point_type> point_comparison_type;
Chris@16 380 typedef distance_predicate<site_type> distance_predicate_type;
Chris@16 381
Chris@16 382 // Compares nodes in the balanced binary search tree. Nodes are
Chris@16 383 // compared based on the y coordinates of the arcs intersection points.
Chris@16 384 // Nodes with less y coordinate of the intersection point go first.
Chris@16 385 // Comparison is only called during the new site events processing.
Chris@16 386 // That's why one of the nodes will always lie on the sweepline and may
Chris@16 387 // be represented as a straight horizontal line.
Chris@16 388 bool operator() (const node_type& node1,
Chris@16 389 const node_type& node2) const {
Chris@16 390 // Get x coordinate of the rightmost site from both nodes.
Chris@16 391 const site_type& site1 = get_comparison_site(node1);
Chris@16 392 const site_type& site2 = get_comparison_site(node2);
Chris@16 393 const point_type& point1 = get_comparison_point(site1);
Chris@16 394 const point_type& point2 = get_comparison_point(site2);
Chris@16 395
Chris@16 396 if (point1.x() < point2.x()) {
Chris@16 397 // The second node contains a new site.
Chris@16 398 return distance_predicate_(
Chris@16 399 node1.left_site(), node1.right_site(), point2);
Chris@16 400 } else if (point1.x() > point2.x()) {
Chris@16 401 // The first node contains a new site.
Chris@16 402 return !distance_predicate_(
Chris@16 403 node2.left_site(), node2.right_site(), point1);
Chris@16 404 } else {
Chris@16 405 // This checks were evaluated experimentally.
Chris@16 406 if (site1.sorted_index() == site2.sorted_index()) {
Chris@16 407 // Both nodes are new (inserted during same site event processing).
Chris@16 408 return get_comparison_y(node1) < get_comparison_y(node2);
Chris@16 409 } else if (site1.sorted_index() < site2.sorted_index()) {
Chris@16 410 std::pair<coordinate_type, int> y1 = get_comparison_y(node1, false);
Chris@16 411 std::pair<coordinate_type, int> y2 = get_comparison_y(node2, true);
Chris@16 412 if (y1.first != y2.first) return y1.first < y2.first;
Chris@16 413 return (!site1.is_segment()) ? (y1.second < 0) : false;
Chris@16 414 } else {
Chris@16 415 std::pair<coordinate_type, int> y1 = get_comparison_y(node1, true);
Chris@16 416 std::pair<coordinate_type, int> y2 = get_comparison_y(node2, false);
Chris@16 417 if (y1.first != y2.first) return y1.first < y2.first;
Chris@16 418 return (!site2.is_segment()) ? (y2.second > 0) : true;
Chris@16 419 }
Chris@16 420 }
Chris@16 421 }
Chris@16 422
Chris@16 423 private:
Chris@16 424 // Get the newer site.
Chris@16 425 const site_type& get_comparison_site(const node_type& node) const {
Chris@16 426 if (node.left_site().sorted_index() > node.right_site().sorted_index()) {
Chris@16 427 return node.left_site();
Chris@16 428 }
Chris@16 429 return node.right_site();
Chris@16 430 }
Chris@16 431
Chris@16 432 const point_type& get_comparison_point(const site_type& site) const {
Chris@16 433 return point_comparison_(site.point0(), site.point1()) ?
Chris@16 434 site.point0() : site.point1();
Chris@16 435 }
Chris@16 436
Chris@16 437 // Get comparison pair: y coordinate and direction of the newer site.
Chris@16 438 std::pair<coordinate_type, int> get_comparison_y(
Chris@16 439 const node_type& node, bool is_new_node = true) const {
Chris@16 440 if (node.left_site().sorted_index() ==
Chris@16 441 node.right_site().sorted_index()) {
Chris@16 442 return std::make_pair(node.left_site().y0(), 0);
Chris@16 443 }
Chris@16 444 if (node.left_site().sorted_index() > node.right_site().sorted_index()) {
Chris@16 445 if (!is_new_node &&
Chris@16 446 node.left_site().is_segment() &&
Chris@16 447 is_vertical(node.left_site())) {
Chris@16 448 return std::make_pair(node.left_site().y0(), 1);
Chris@16 449 }
Chris@16 450 return std::make_pair(node.left_site().y1(), 1);
Chris@16 451 }
Chris@16 452 return std::make_pair(node.right_site().y0(), -1);
Chris@16 453 }
Chris@16 454
Chris@16 455 point_comparison_type point_comparison_;
Chris@16 456 distance_predicate_type distance_predicate_;
Chris@16 457 };
Chris@16 458
Chris@16 459 template <typename Site>
Chris@16 460 class circle_existence_predicate {
Chris@16 461 public:
Chris@16 462 typedef typename Site::point_type point_type;
Chris@16 463 typedef Site site_type;
Chris@16 464
Chris@16 465 bool ppp(const site_type& site1,
Chris@16 466 const site_type& site2,
Chris@16 467 const site_type& site3) const {
Chris@16 468 return ot::eval(site1.point0(),
Chris@16 469 site2.point0(),
Chris@16 470 site3.point0()) == ot::RIGHT;
Chris@16 471 }
Chris@16 472
Chris@16 473 bool pps(const site_type& site1,
Chris@16 474 const site_type& site2,
Chris@16 475 const site_type& site3,
Chris@16 476 int segment_index) const {
Chris@16 477 if (segment_index != 2) {
Chris@16 478 typename ot::Orientation orient1 = ot::eval(
Chris@16 479 site1.point0(), site2.point0(), site3.point0());
Chris@16 480 typename ot::Orientation orient2 = ot::eval(
Chris@16 481 site1.point0(), site2.point0(), site3.point1());
Chris@16 482 if (segment_index == 1 && site1.x0() >= site2.x0()) {
Chris@16 483 if (orient1 != ot::RIGHT)
Chris@16 484 return false;
Chris@16 485 } else if (segment_index == 3 && site2.x0() >= site1.x0()) {
Chris@16 486 if (orient2 != ot::RIGHT)
Chris@16 487 return false;
Chris@16 488 } else if (orient1 != ot::RIGHT && orient2 != ot::RIGHT) {
Chris@16 489 return false;
Chris@16 490 }
Chris@16 491 } else {
Chris@16 492 return (site3.point0() != site1.point0()) ||
Chris@16 493 (site3.point1() != site2.point0());
Chris@16 494 }
Chris@16 495 return true;
Chris@16 496 }
Chris@16 497
Chris@16 498 bool pss(const site_type& site1,
Chris@16 499 const site_type& site2,
Chris@16 500 const site_type& site3,
Chris@16 501 int point_index) const {
Chris@16 502 if (site2.sorted_index() == site3.sorted_index()) {
Chris@16 503 return false;
Chris@16 504 }
Chris@16 505 if (point_index == 2) {
Chris@16 506 if (!site2.is_inverse() && site3.is_inverse())
Chris@16 507 return false;
Chris@16 508 if (site2.is_inverse() == site3.is_inverse() &&
Chris@16 509 ot::eval(site2.point0(),
Chris@16 510 site1.point0(),
Chris@16 511 site3.point1()) != ot::RIGHT)
Chris@16 512 return false;
Chris@16 513 }
Chris@16 514 return true;
Chris@16 515 }
Chris@16 516
Chris@16 517 bool sss(const site_type& site1,
Chris@16 518 const site_type& site2,
Chris@16 519 const site_type& site3) const {
Chris@16 520 return (site1.sorted_index() != site2.sorted_index()) &&
Chris@16 521 (site2.sorted_index() != site3.sorted_index());
Chris@16 522 }
Chris@16 523 };
Chris@16 524
Chris@16 525 template <typename Site, typename Circle>
Chris@16 526 class mp_circle_formation_functor {
Chris@16 527 public:
Chris@16 528 typedef typename Site::point_type point_type;
Chris@16 529 typedef Site site_type;
Chris@16 530 typedef Circle circle_type;
Chris@16 531 typedef robust_sqrt_expr<big_int_type, efpt_type, to_efpt_converter>
Chris@16 532 robust_sqrt_expr_type;
Chris@16 533
Chris@16 534 void ppp(const site_type& site1,
Chris@16 535 const site_type& site2,
Chris@16 536 const site_type& site3,
Chris@16 537 circle_type& circle,
Chris@16 538 bool recompute_c_x = true,
Chris@16 539 bool recompute_c_y = true,
Chris@16 540 bool recompute_lower_x = true) {
Chris@16 541 big_int_type dif_x[3], dif_y[3], sum_x[2], sum_y[2];
Chris@16 542 dif_x[0] = static_cast<int_x2_type>(site1.x()) -
Chris@16 543 static_cast<int_x2_type>(site2.x());
Chris@16 544 dif_x[1] = static_cast<int_x2_type>(site2.x()) -
Chris@16 545 static_cast<int_x2_type>(site3.x());
Chris@16 546 dif_x[2] = static_cast<int_x2_type>(site1.x()) -
Chris@16 547 static_cast<int_x2_type>(site3.x());
Chris@16 548 dif_y[0] = static_cast<int_x2_type>(site1.y()) -
Chris@16 549 static_cast<int_x2_type>(site2.y());
Chris@16 550 dif_y[1] = static_cast<int_x2_type>(site2.y()) -
Chris@16 551 static_cast<int_x2_type>(site3.y());
Chris@16 552 dif_y[2] = static_cast<int_x2_type>(site1.y()) -
Chris@16 553 static_cast<int_x2_type>(site3.y());
Chris@16 554 sum_x[0] = static_cast<int_x2_type>(site1.x()) +
Chris@16 555 static_cast<int_x2_type>(site2.x());
Chris@16 556 sum_x[1] = static_cast<int_x2_type>(site2.x()) +
Chris@16 557 static_cast<int_x2_type>(site3.x());
Chris@16 558 sum_y[0] = static_cast<int_x2_type>(site1.y()) +
Chris@16 559 static_cast<int_x2_type>(site2.y());
Chris@16 560 sum_y[1] = static_cast<int_x2_type>(site2.y()) +
Chris@16 561 static_cast<int_x2_type>(site3.y());
Chris@16 562 fpt_type inv_denom = to_fpt(0.5) / to_fpt(static_cast<big_int_type>(
Chris@16 563 dif_x[0] * dif_y[1] - dif_x[1] * dif_y[0]));
Chris@16 564 big_int_type numer1 = dif_x[0] * sum_x[0] + dif_y[0] * sum_y[0];
Chris@16 565 big_int_type numer2 = dif_x[1] * sum_x[1] + dif_y[1] * sum_y[1];
Chris@16 566
Chris@16 567 if (recompute_c_x || recompute_lower_x) {
Chris@16 568 big_int_type c_x = numer1 * dif_y[1] - numer2 * dif_y[0];
Chris@16 569 circle.x(to_fpt(c_x) * inv_denom);
Chris@16 570
Chris@16 571 if (recompute_lower_x) {
Chris@16 572 // Evaluate radius of the circle.
Chris@16 573 big_int_type sqr_r = (dif_x[0] * dif_x[0] + dif_y[0] * dif_y[0]) *
Chris@16 574 (dif_x[1] * dif_x[1] + dif_y[1] * dif_y[1]) *
Chris@16 575 (dif_x[2] * dif_x[2] + dif_y[2] * dif_y[2]);
Chris@16 576 fpt_type r = get_sqrt(to_fpt(sqr_r));
Chris@16 577
Chris@16 578 // If c_x >= 0 then lower_x = c_x + r,
Chris@16 579 // else lower_x = (c_x * c_x - r * r) / (c_x - r).
Chris@16 580 // To guarantee epsilon relative error.
Chris@16 581 if (!is_neg(circle.x())) {
Chris@16 582 if (!is_neg(inv_denom)) {
Chris@16 583 circle.lower_x(circle.x() + r * inv_denom);
Chris@16 584 } else {
Chris@16 585 circle.lower_x(circle.x() - r * inv_denom);
Chris@16 586 }
Chris@16 587 } else {
Chris@16 588 big_int_type numer = c_x * c_x - sqr_r;
Chris@16 589 fpt_type lower_x = to_fpt(numer) * inv_denom / (to_fpt(c_x) + r);
Chris@16 590 circle.lower_x(lower_x);
Chris@16 591 }
Chris@16 592 }
Chris@16 593 }
Chris@16 594
Chris@16 595 if (recompute_c_y) {
Chris@16 596 big_int_type c_y = numer2 * dif_x[0] - numer1 * dif_x[1];
Chris@16 597 circle.y(to_fpt(c_y) * inv_denom);
Chris@16 598 }
Chris@16 599 }
Chris@16 600
Chris@16 601 // Recompute parameters of the circle event using high-precision library.
Chris@16 602 void pps(const site_type& site1,
Chris@16 603 const site_type& site2,
Chris@16 604 const site_type& site3,
Chris@16 605 int segment_index,
Chris@16 606 circle_type& c_event,
Chris@16 607 bool recompute_c_x = true,
Chris@16 608 bool recompute_c_y = true,
Chris@16 609 bool recompute_lower_x = true) {
Chris@16 610 big_int_type cA[4], cB[4];
Chris@16 611 big_int_type line_a = static_cast<int_x2_type>(site3.y1()) -
Chris@16 612 static_cast<int_x2_type>(site3.y0());
Chris@16 613 big_int_type line_b = static_cast<int_x2_type>(site3.x0()) -
Chris@16 614 static_cast<int_x2_type>(site3.x1());
Chris@16 615 big_int_type segm_len = line_a * line_a + line_b * line_b;
Chris@16 616 big_int_type vec_x = static_cast<int_x2_type>(site2.y()) -
Chris@16 617 static_cast<int_x2_type>(site1.y());
Chris@16 618 big_int_type vec_y = static_cast<int_x2_type>(site1.x()) -
Chris@16 619 static_cast<int_x2_type>(site2.x());
Chris@16 620 big_int_type sum_x = static_cast<int_x2_type>(site1.x()) +
Chris@16 621 static_cast<int_x2_type>(site2.x());
Chris@16 622 big_int_type sum_y = static_cast<int_x2_type>(site1.y()) +
Chris@16 623 static_cast<int_x2_type>(site2.y());
Chris@16 624 big_int_type teta = line_a * vec_x + line_b * vec_y;
Chris@16 625 big_int_type denom = vec_x * line_b - vec_y * line_a;
Chris@16 626
Chris@16 627 big_int_type dif0 = static_cast<int_x2_type>(site3.y1()) -
Chris@16 628 static_cast<int_x2_type>(site1.y());
Chris@16 629 big_int_type dif1 = static_cast<int_x2_type>(site1.x()) -
Chris@16 630 static_cast<int_x2_type>(site3.x1());
Chris@16 631 big_int_type A = line_a * dif1 - line_b * dif0;
Chris@16 632 dif0 = static_cast<int_x2_type>(site3.y1()) -
Chris@16 633 static_cast<int_x2_type>(site2.y());
Chris@16 634 dif1 = static_cast<int_x2_type>(site2.x()) -
Chris@16 635 static_cast<int_x2_type>(site3.x1());
Chris@16 636 big_int_type B = line_a * dif1 - line_b * dif0;
Chris@16 637 big_int_type sum_AB = A + B;
Chris@16 638
Chris@16 639 if (is_zero(denom)) {
Chris@16 640 big_int_type numer = teta * teta - sum_AB * sum_AB;
Chris@101 641 denom = teta * sum_AB;
Chris@16 642 cA[0] = denom * sum_x * 2 + numer * vec_x;
Chris@16 643 cB[0] = segm_len;
Chris@16 644 cA[1] = denom * sum_AB * 2 + numer * teta;
Chris@16 645 cB[1] = 1;
Chris@16 646 cA[2] = denom * sum_y * 2 + numer * vec_y;
Chris@16 647 fpt_type inv_denom = to_fpt(1.0) / to_fpt(denom);
Chris@16 648 if (recompute_c_x)
Chris@16 649 c_event.x(to_fpt(0.25) * to_fpt(cA[0]) * inv_denom);
Chris@16 650 if (recompute_c_y)
Chris@16 651 c_event.y(to_fpt(0.25) * to_fpt(cA[2]) * inv_denom);
Chris@16 652 if (recompute_lower_x) {
Chris@16 653 c_event.lower_x(to_fpt(0.25) * to_fpt(sqrt_expr_.eval2(cA, cB)) *
Chris@16 654 inv_denom / get_sqrt(to_fpt(segm_len)));
Chris@16 655 }
Chris@16 656 return;
Chris@16 657 }
Chris@16 658
Chris@16 659 big_int_type det = (teta * teta + denom * denom) * A * B * 4;
Chris@16 660 fpt_type inv_denom_sqr = to_fpt(1.0) / to_fpt(denom);
Chris@16 661 inv_denom_sqr *= inv_denom_sqr;
Chris@16 662
Chris@16 663 if (recompute_c_x || recompute_lower_x) {
Chris@16 664 cA[0] = sum_x * denom * denom + teta * sum_AB * vec_x;
Chris@16 665 cB[0] = 1;
Chris@16 666 cA[1] = (segment_index == 2) ? -vec_x : vec_x;
Chris@16 667 cB[1] = det;
Chris@16 668 if (recompute_c_x) {
Chris@16 669 c_event.x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(cA, cB)) *
Chris@16 670 inv_denom_sqr);
Chris@16 671 }
Chris@16 672 }
Chris@16 673
Chris@16 674 if (recompute_c_y || recompute_lower_x) {
Chris@16 675 cA[2] = sum_y * denom * denom + teta * sum_AB * vec_y;
Chris@16 676 cB[2] = 1;
Chris@16 677 cA[3] = (segment_index == 2) ? -vec_y : vec_y;
Chris@16 678 cB[3] = det;
Chris@16 679 if (recompute_c_y) {
Chris@16 680 c_event.y(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(&cA[2], &cB[2])) *
Chris@16 681 inv_denom_sqr);
Chris@16 682 }
Chris@16 683 }
Chris@16 684
Chris@16 685 if (recompute_lower_x) {
Chris@16 686 cB[0] = cB[0] * segm_len;
Chris@16 687 cB[1] = cB[1] * segm_len;
Chris@16 688 cA[2] = sum_AB * (denom * denom + teta * teta);
Chris@16 689 cB[2] = 1;
Chris@16 690 cA[3] = (segment_index == 2) ? -teta : teta;
Chris@16 691 cB[3] = det;
Chris@16 692 c_event.lower_x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval4(cA, cB)) *
Chris@16 693 inv_denom_sqr / get_sqrt(to_fpt(segm_len)));
Chris@16 694 }
Chris@16 695 }
Chris@16 696
Chris@16 697 // Recompute parameters of the circle event using high-precision library.
Chris@16 698 void pss(const site_type& site1,
Chris@16 699 const site_type& site2,
Chris@16 700 const site_type& site3,
Chris@16 701 int point_index,
Chris@16 702 circle_type& c_event,
Chris@16 703 bool recompute_c_x = true,
Chris@16 704 bool recompute_c_y = true,
Chris@16 705 bool recompute_lower_x = true) {
Chris@16 706 big_int_type a[2], b[2], c[2], cA[4], cB[4];
Chris@16 707 const point_type& segm_start1 = site2.point1();
Chris@16 708 const point_type& segm_end1 = site2.point0();
Chris@16 709 const point_type& segm_start2 = site3.point0();
Chris@16 710 const point_type& segm_end2 = site3.point1();
Chris@16 711 a[0] = static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 712 static_cast<int_x2_type>(segm_start1.x());
Chris@16 713 b[0] = static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 714 static_cast<int_x2_type>(segm_start1.y());
Chris@16 715 a[1] = static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 716 static_cast<int_x2_type>(segm_start2.x());
Chris@16 717 b[1] = static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 718 static_cast<int_x2_type>(segm_start2.y());
Chris@16 719 big_int_type orientation = a[1] * b[0] - a[0] * b[1];
Chris@16 720 if (is_zero(orientation)) {
Chris@16 721 fpt_type denom = to_fpt(2.0) * to_fpt(
Chris@16 722 static_cast<big_int_type>(a[0] * a[0] + b[0] * b[0]));
Chris@16 723 c[0] = b[0] * (static_cast<int_x2_type>(segm_start2.x()) -
Chris@16 724 static_cast<int_x2_type>(segm_start1.x())) -
Chris@16 725 a[0] * (static_cast<int_x2_type>(segm_start2.y()) -
Chris@16 726 static_cast<int_x2_type>(segm_start1.y()));
Chris@16 727 big_int_type dx = a[0] * (static_cast<int_x2_type>(site1.y()) -
Chris@16 728 static_cast<int_x2_type>(segm_start1.y())) -
Chris@16 729 b[0] * (static_cast<int_x2_type>(site1.x()) -
Chris@16 730 static_cast<int_x2_type>(segm_start1.x()));
Chris@16 731 big_int_type dy = b[0] * (static_cast<int_x2_type>(site1.x()) -
Chris@16 732 static_cast<int_x2_type>(segm_start2.x())) -
Chris@16 733 a[0] * (static_cast<int_x2_type>(site1.y()) -
Chris@16 734 static_cast<int_x2_type>(segm_start2.y()));
Chris@16 735 cB[0] = dx * dy;
Chris@16 736 cB[1] = 1;
Chris@16 737
Chris@16 738 if (recompute_c_y) {
Chris@16 739 cA[0] = b[0] * ((point_index == 2) ? 2 : -2);
Chris@16 740 cA[1] = a[0] * a[0] * (static_cast<int_x2_type>(segm_start1.y()) +
Chris@16 741 static_cast<int_x2_type>(segm_start2.y())) -
Chris@16 742 a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) +
Chris@16 743 static_cast<int_x2_type>(segm_start2.x()) -
Chris@16 744 static_cast<int_x2_type>(site1.x()) * 2) +
Chris@16 745 b[0] * b[0] * (static_cast<int_x2_type>(site1.y()) * 2);
Chris@16 746 fpt_type c_y = to_fpt(sqrt_expr_.eval2(cA, cB));
Chris@16 747 c_event.y(c_y / denom);
Chris@16 748 }
Chris@16 749
Chris@16 750 if (recompute_c_x || recompute_lower_x) {
Chris@16 751 cA[0] = a[0] * ((point_index == 2) ? 2 : -2);
Chris@16 752 cA[1] = b[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) +
Chris@16 753 static_cast<int_x2_type>(segm_start2.x())) -
Chris@16 754 a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.y()) +
Chris@16 755 static_cast<int_x2_type>(segm_start2.y()) -
Chris@16 756 static_cast<int_x2_type>(site1.y()) * 2) +
Chris@16 757 a[0] * a[0] * (static_cast<int_x2_type>(site1.x()) * 2);
Chris@16 758
Chris@16 759 if (recompute_c_x) {
Chris@16 760 fpt_type c_x = to_fpt(sqrt_expr_.eval2(cA, cB));
Chris@16 761 c_event.x(c_x / denom);
Chris@16 762 }
Chris@16 763
Chris@16 764 if (recompute_lower_x) {
Chris@16 765 cA[2] = is_neg(c[0]) ? -c[0] : c[0];
Chris@16 766 cB[2] = a[0] * a[0] + b[0] * b[0];
Chris@16 767 fpt_type lower_x = to_fpt(sqrt_expr_.eval3(cA, cB));
Chris@16 768 c_event.lower_x(lower_x / denom);
Chris@16 769 }
Chris@16 770 }
Chris@16 771 return;
Chris@16 772 }
Chris@16 773 c[0] = b[0] * segm_end1.x() - a[0] * segm_end1.y();
Chris@16 774 c[1] = a[1] * segm_end2.y() - b[1] * segm_end2.x();
Chris@16 775 big_int_type ix = a[0] * c[1] + a[1] * c[0];
Chris@16 776 big_int_type iy = b[0] * c[1] + b[1] * c[0];
Chris@16 777 big_int_type dx = ix - orientation * site1.x();
Chris@16 778 big_int_type dy = iy - orientation * site1.y();
Chris@16 779 if (is_zero(dx) && is_zero(dy)) {
Chris@16 780 fpt_type denom = to_fpt(orientation);
Chris@16 781 fpt_type c_x = to_fpt(ix) / denom;
Chris@16 782 fpt_type c_y = to_fpt(iy) / denom;
Chris@16 783 c_event = circle_type(c_x, c_y, c_x);
Chris@16 784 return;
Chris@16 785 }
Chris@16 786
Chris@16 787 big_int_type sign = ((point_index == 2) ? 1 : -1) *
Chris@16 788 (is_neg(orientation) ? 1 : -1);
Chris@16 789 cA[0] = a[1] * -dx + b[1] * -dy;
Chris@16 790 cA[1] = a[0] * -dx + b[0] * -dy;
Chris@16 791 cA[2] = sign;
Chris@16 792 cA[3] = 0;
Chris@16 793 cB[0] = a[0] * a[0] + b[0] * b[0];
Chris@16 794 cB[1] = a[1] * a[1] + b[1] * b[1];
Chris@16 795 cB[2] = a[0] * a[1] + b[0] * b[1];
Chris@16 796 cB[3] = (a[0] * dy - b[0] * dx) * (a[1] * dy - b[1] * dx) * -2;
Chris@16 797 fpt_type temp = to_fpt(
Chris@16 798 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
Chris@16 799 fpt_type denom = temp * to_fpt(orientation);
Chris@16 800
Chris@16 801 if (recompute_c_y) {
Chris@16 802 cA[0] = b[1] * (dx * dx + dy * dy) - iy * (dx * a[1] + dy * b[1]);
Chris@16 803 cA[1] = b[0] * (dx * dx + dy * dy) - iy * (dx * a[0] + dy * b[0]);
Chris@16 804 cA[2] = iy * sign;
Chris@16 805 fpt_type cy = to_fpt(
Chris@16 806 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
Chris@16 807 c_event.y(cy / denom);
Chris@16 808 }
Chris@16 809
Chris@16 810 if (recompute_c_x || recompute_lower_x) {
Chris@16 811 cA[0] = a[1] * (dx * dx + dy * dy) - ix * (dx * a[1] + dy * b[1]);
Chris@16 812 cA[1] = a[0] * (dx * dx + dy * dy) - ix * (dx * a[0] + dy * b[0]);
Chris@16 813 cA[2] = ix * sign;
Chris@16 814
Chris@16 815 if (recompute_c_x) {
Chris@16 816 fpt_type cx = to_fpt(
Chris@16 817 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
Chris@16 818 c_event.x(cx / denom);
Chris@16 819 }
Chris@16 820
Chris@16 821 if (recompute_lower_x) {
Chris@16 822 cA[3] = orientation * (dx * dx + dy * dy) * (is_neg(temp) ? -1 : 1);
Chris@16 823 fpt_type lower_x = to_fpt(
Chris@16 824 sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB));
Chris@16 825 c_event.lower_x(lower_x / denom);
Chris@16 826 }
Chris@16 827 }
Chris@16 828 }
Chris@16 829
Chris@16 830 // Recompute parameters of the circle event using high-precision library.
Chris@16 831 void sss(const site_type& site1,
Chris@16 832 const site_type& site2,
Chris@16 833 const site_type& site3,
Chris@16 834 circle_type& c_event,
Chris@16 835 bool recompute_c_x = true,
Chris@16 836 bool recompute_c_y = true,
Chris@16 837 bool recompute_lower_x = true) {
Chris@16 838 big_int_type a[3], b[3], c[3], cA[4], cB[4];
Chris@16 839 // cA - corresponds to the cross product.
Chris@16 840 // cB - corresponds to the squared length.
Chris@16 841 a[0] = static_cast<int_x2_type>(site1.x1()) -
Chris@16 842 static_cast<int_x2_type>(site1.x0());
Chris@16 843 a[1] = static_cast<int_x2_type>(site2.x1()) -
Chris@16 844 static_cast<int_x2_type>(site2.x0());
Chris@16 845 a[2] = static_cast<int_x2_type>(site3.x1()) -
Chris@16 846 static_cast<int_x2_type>(site3.x0());
Chris@16 847
Chris@16 848 b[0] = static_cast<int_x2_type>(site1.y1()) -
Chris@16 849 static_cast<int_x2_type>(site1.y0());
Chris@16 850 b[1] = static_cast<int_x2_type>(site2.y1()) -
Chris@16 851 static_cast<int_x2_type>(site2.y0());
Chris@16 852 b[2] = static_cast<int_x2_type>(site3.y1()) -
Chris@16 853 static_cast<int_x2_type>(site3.y0());
Chris@16 854
Chris@16 855 c[0] = static_cast<int_x2_type>(site1.x0()) *
Chris@16 856 static_cast<int_x2_type>(site1.y1()) -
Chris@16 857 static_cast<int_x2_type>(site1.y0()) *
Chris@16 858 static_cast<int_x2_type>(site1.x1());
Chris@16 859 c[1] = static_cast<int_x2_type>(site2.x0()) *
Chris@16 860 static_cast<int_x2_type>(site2.y1()) -
Chris@16 861 static_cast<int_x2_type>(site2.y0()) *
Chris@16 862 static_cast<int_x2_type>(site2.x1());
Chris@16 863 c[2] = static_cast<int_x2_type>(site3.x0()) *
Chris@16 864 static_cast<int_x2_type>(site3.y1()) -
Chris@16 865 static_cast<int_x2_type>(site3.y0()) *
Chris@16 866 static_cast<int_x2_type>(site3.x1());
Chris@16 867
Chris@16 868 for (int i = 0; i < 3; ++i)
Chris@16 869 cB[i] = a[i] * a[i] + b[i] * b[i];
Chris@16 870
Chris@16 871 for (int i = 0; i < 3; ++i) {
Chris@16 872 int j = (i+1) % 3;
Chris@16 873 int k = (i+2) % 3;
Chris@16 874 cA[i] = a[j] * b[k] - a[k] * b[j];
Chris@16 875 }
Chris@16 876 fpt_type denom = to_fpt(sqrt_expr_.eval3(cA, cB));
Chris@16 877
Chris@16 878 if (recompute_c_y) {
Chris@16 879 for (int i = 0; i < 3; ++i) {
Chris@16 880 int j = (i+1) % 3;
Chris@16 881 int k = (i+2) % 3;
Chris@16 882 cA[i] = b[j] * c[k] - b[k] * c[j];
Chris@16 883 }
Chris@16 884 fpt_type c_y = to_fpt(sqrt_expr_.eval3(cA, cB));
Chris@16 885 c_event.y(c_y / denom);
Chris@16 886 }
Chris@16 887
Chris@16 888 if (recompute_c_x || recompute_lower_x) {
Chris@16 889 cA[3] = 0;
Chris@16 890 for (int i = 0; i < 3; ++i) {
Chris@16 891 int j = (i+1) % 3;
Chris@16 892 int k = (i+2) % 3;
Chris@16 893 cA[i] = a[j] * c[k] - a[k] * c[j];
Chris@16 894 if (recompute_lower_x) {
Chris@16 895 cA[3] = cA[3] + cA[i] * b[i];
Chris@16 896 }
Chris@16 897 }
Chris@16 898
Chris@16 899 if (recompute_c_x) {
Chris@16 900 fpt_type c_x = to_fpt(sqrt_expr_.eval3(cA, cB));
Chris@16 901 c_event.x(c_x / denom);
Chris@16 902 }
Chris@16 903
Chris@16 904 if (recompute_lower_x) {
Chris@16 905 cB[3] = 1;
Chris@16 906 fpt_type lower_x = to_fpt(sqrt_expr_.eval4(cA, cB));
Chris@16 907 c_event.lower_x(lower_x / denom);
Chris@16 908 }
Chris@16 909 }
Chris@16 910 }
Chris@16 911
Chris@16 912 private:
Chris@16 913 // Evaluates A[3] + A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) +
Chris@16 914 // A[2] * sqrt(B[3] * (sqrt(B[0] * B[1]) + B[2])).
Chris@16 915 template <typename _int, typename _fpt>
Chris@16 916 _fpt sqrt_expr_evaluator_pss4(_int *A, _int *B) {
Chris@16 917 _int cA[4], cB[4];
Chris@16 918 if (is_zero(A[3])) {
Chris@16 919 _fpt lh = sqrt_expr_.eval2(A, B);
Chris@16 920 cA[0] = 1;
Chris@16 921 cB[0] = B[0] * B[1];
Chris@16 922 cA[1] = B[2];
Chris@16 923 cB[1] = 1;
Chris@16 924 _fpt rh = sqrt_expr_.eval1(A+2, B+3) *
Chris@16 925 get_sqrt(sqrt_expr_.eval2(cA, cB));
Chris@16 926 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
Chris@16 927 return lh + rh;
Chris@16 928 cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
Chris@16 929 A[2] * A[2] * B[3] * B[2];
Chris@16 930 cB[0] = 1;
Chris@16 931 cA[1] = A[0] * A[1] * 2 - A[2] * A[2] * B[3];
Chris@16 932 cB[1] = B[0] * B[1];
Chris@16 933 _fpt numer = sqrt_expr_.eval2(cA, cB);
Chris@16 934 return numer / (lh - rh);
Chris@16 935 }
Chris@16 936 cA[0] = 1;
Chris@16 937 cB[0] = B[0] * B[1];
Chris@16 938 cA[1] = B[2];
Chris@16 939 cB[1] = 1;
Chris@16 940 _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB));
Chris@16 941 cA[0] = A[0];
Chris@16 942 cB[0] = B[0];
Chris@16 943 cA[1] = A[1];
Chris@16 944 cB[1] = B[1];
Chris@16 945 cA[2] = A[3];
Chris@16 946 cB[2] = 1;
Chris@16 947 _fpt lh = sqrt_expr_.eval3(cA, cB);
Chris@16 948 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
Chris@16 949 return lh + rh;
Chris@16 950 cA[0] = A[3] * A[0] * 2;
Chris@16 951 cA[1] = A[3] * A[1] * 2;
Chris@16 952 cA[2] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] +
Chris@16 953 A[3] * A[3] - A[2] * A[2] * B[2] * B[3];
Chris@16 954 cA[3] = A[0] * A[1] * 2 - A[2] * A[2] * B[3];
Chris@16 955 cB[3] = B[0] * B[1];
Chris@16 956 _fpt numer = sqrt_expr_evaluator_pss3<_int, _fpt>(cA, cB);
Chris@16 957 return numer / (lh - rh);
Chris@16 958 }
Chris@16 959
Chris@16 960 template <typename _int, typename _fpt>
Chris@16 961 // Evaluates A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) +
Chris@16 962 // A[2] + A[3] * sqrt(B[0] * B[1]).
Chris@16 963 // B[3] = B[0] * B[1].
Chris@16 964 _fpt sqrt_expr_evaluator_pss3(_int *A, _int *B) {
Chris@16 965 _int cA[2], cB[2];
Chris@16 966 _fpt lh = sqrt_expr_.eval2(A, B);
Chris@16 967 _fpt rh = sqrt_expr_.eval2(A+2, B+2);
Chris@16 968 if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh)))
Chris@16 969 return lh + rh;
Chris@16 970 cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] -
Chris@16 971 A[2] * A[2] - A[3] * A[3] * B[0] * B[1];
Chris@16 972 cB[0] = 1;
Chris@16 973 cA[1] = (A[0] * A[1] - A[2] * A[3]) * 2;
Chris@16 974 cB[1] = B[3];
Chris@16 975 _fpt numer = sqrt_expr_.eval2(cA, cB);
Chris@16 976 return numer / (lh - rh);
Chris@16 977 }
Chris@16 978
Chris@16 979 robust_sqrt_expr_type sqrt_expr_;
Chris@16 980 to_fpt_converter to_fpt;
Chris@16 981 };
Chris@16 982
Chris@16 983 template <typename Site, typename Circle>
Chris@16 984 class lazy_circle_formation_functor {
Chris@16 985 public:
Chris@16 986 typedef robust_fpt<fpt_type> robust_fpt_type;
Chris@16 987 typedef robust_dif<robust_fpt_type> robust_dif_type;
Chris@16 988 typedef typename Site::point_type point_type;
Chris@16 989 typedef Site site_type;
Chris@16 990 typedef Circle circle_type;
Chris@16 991 typedef mp_circle_formation_functor<site_type, circle_type>
Chris@16 992 exact_circle_formation_functor_type;
Chris@16 993
Chris@16 994 void ppp(const site_type& site1,
Chris@16 995 const site_type& site2,
Chris@16 996 const site_type& site3,
Chris@16 997 circle_type& c_event) {
Chris@16 998 fpt_type dif_x1 = to_fpt(site1.x()) - to_fpt(site2.x());
Chris@16 999 fpt_type dif_x2 = to_fpt(site2.x()) - to_fpt(site3.x());
Chris@16 1000 fpt_type dif_y1 = to_fpt(site1.y()) - to_fpt(site2.y());
Chris@16 1001 fpt_type dif_y2 = to_fpt(site2.y()) - to_fpt(site3.y());
Chris@16 1002 fpt_type orientation = robust_cross_product(
Chris@16 1003 static_cast<int_x2_type>(site1.x()) -
Chris@16 1004 static_cast<int_x2_type>(site2.x()),
Chris@16 1005 static_cast<int_x2_type>(site2.x()) -
Chris@16 1006 static_cast<int_x2_type>(site3.x()),
Chris@16 1007 static_cast<int_x2_type>(site1.y()) -
Chris@16 1008 static_cast<int_x2_type>(site2.y()),
Chris@16 1009 static_cast<int_x2_type>(site2.y()) -
Chris@16 1010 static_cast<int_x2_type>(site3.y()));
Chris@16 1011 robust_fpt_type inv_orientation(to_fpt(0.5) / orientation, to_fpt(2.0));
Chris@16 1012 fpt_type sum_x1 = to_fpt(site1.x()) + to_fpt(site2.x());
Chris@16 1013 fpt_type sum_x2 = to_fpt(site2.x()) + to_fpt(site3.x());
Chris@16 1014 fpt_type sum_y1 = to_fpt(site1.y()) + to_fpt(site2.y());
Chris@16 1015 fpt_type sum_y2 = to_fpt(site2.y()) + to_fpt(site3.y());
Chris@16 1016 fpt_type dif_x3 = to_fpt(site1.x()) - to_fpt(site3.x());
Chris@16 1017 fpt_type dif_y3 = to_fpt(site1.y()) - to_fpt(site3.y());
Chris@16 1018 robust_dif_type c_x, c_y;
Chris@16 1019 c_x += robust_fpt_type(dif_x1 * sum_x1 * dif_y2, to_fpt(2.0));
Chris@16 1020 c_x += robust_fpt_type(dif_y1 * sum_y1 * dif_y2, to_fpt(2.0));
Chris@16 1021 c_x -= robust_fpt_type(dif_x2 * sum_x2 * dif_y1, to_fpt(2.0));
Chris@16 1022 c_x -= robust_fpt_type(dif_y2 * sum_y2 * dif_y1, to_fpt(2.0));
Chris@16 1023 c_y += robust_fpt_type(dif_x2 * sum_x2 * dif_x1, to_fpt(2.0));
Chris@16 1024 c_y += robust_fpt_type(dif_y2 * sum_y2 * dif_x1, to_fpt(2.0));
Chris@16 1025 c_y -= robust_fpt_type(dif_x1 * sum_x1 * dif_x2, to_fpt(2.0));
Chris@16 1026 c_y -= robust_fpt_type(dif_y1 * sum_y1 * dif_x2, to_fpt(2.0));
Chris@16 1027 robust_dif_type lower_x(c_x);
Chris@16 1028 lower_x -= robust_fpt_type(get_sqrt(
Chris@16 1029 (dif_x1 * dif_x1 + dif_y1 * dif_y1) *
Chris@16 1030 (dif_x2 * dif_x2 + dif_y2 * dif_y2) *
Chris@16 1031 (dif_x3 * dif_x3 + dif_y3 * dif_y3)), to_fpt(5.0));
Chris@16 1032 c_event = circle_type(
Chris@16 1033 c_x.dif().fpv() * inv_orientation.fpv(),
Chris@16 1034 c_y.dif().fpv() * inv_orientation.fpv(),
Chris@16 1035 lower_x.dif().fpv() * inv_orientation.fpv());
Chris@16 1036 bool recompute_c_x = c_x.dif().ulp() > ULPS;
Chris@16 1037 bool recompute_c_y = c_y.dif().ulp() > ULPS;
Chris@16 1038 bool recompute_lower_x = lower_x.dif().ulp() > ULPS;
Chris@16 1039 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
Chris@16 1040 exact_circle_formation_functor_.ppp(
Chris@16 1041 site1, site2, site3, c_event,
Chris@16 1042 recompute_c_x, recompute_c_y, recompute_lower_x);
Chris@16 1043 }
Chris@16 1044 }
Chris@16 1045
Chris@16 1046 void pps(const site_type& site1,
Chris@16 1047 const site_type& site2,
Chris@16 1048 const site_type& site3,
Chris@16 1049 int segment_index,
Chris@16 1050 circle_type& c_event) {
Chris@16 1051 fpt_type line_a = to_fpt(site3.y1()) - to_fpt(site3.y0());
Chris@16 1052 fpt_type line_b = to_fpt(site3.x0()) - to_fpt(site3.x1());
Chris@16 1053 fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y());
Chris@16 1054 fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x());
Chris@16 1055 robust_fpt_type teta(robust_cross_product(
Chris@16 1056 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1057 static_cast<int_x2_type>(site3.y0()),
Chris@16 1058 static_cast<int_x2_type>(site3.x0()) -
Chris@16 1059 static_cast<int_x2_type>(site3.x1()),
Chris@16 1060 static_cast<int_x2_type>(site2.x()) -
Chris@16 1061 static_cast<int_x2_type>(site1.x()),
Chris@16 1062 static_cast<int_x2_type>(site2.y()) -
Chris@16 1063 static_cast<int_x2_type>(site1.y())), to_fpt(1.0));
Chris@16 1064 robust_fpt_type A(robust_cross_product(
Chris@16 1065 static_cast<int_x2_type>(site3.y0()) -
Chris@16 1066 static_cast<int_x2_type>(site3.y1()),
Chris@16 1067 static_cast<int_x2_type>(site3.x0()) -
Chris@16 1068 static_cast<int_x2_type>(site3.x1()),
Chris@16 1069 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1070 static_cast<int_x2_type>(site1.y()),
Chris@16 1071 static_cast<int_x2_type>(site3.x1()) -
Chris@16 1072 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
Chris@16 1073 robust_fpt_type B(robust_cross_product(
Chris@16 1074 static_cast<int_x2_type>(site3.y0()) -
Chris@16 1075 static_cast<int_x2_type>(site3.y1()),
Chris@16 1076 static_cast<int_x2_type>(site3.x0()) -
Chris@16 1077 static_cast<int_x2_type>(site3.x1()),
Chris@16 1078 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1079 static_cast<int_x2_type>(site2.y()),
Chris@16 1080 static_cast<int_x2_type>(site3.x1()) -
Chris@16 1081 static_cast<int_x2_type>(site2.x())), to_fpt(1.0));
Chris@16 1082 robust_fpt_type denom(robust_cross_product(
Chris@16 1083 static_cast<int_x2_type>(site1.y()) -
Chris@16 1084 static_cast<int_x2_type>(site2.y()),
Chris@16 1085 static_cast<int_x2_type>(site1.x()) -
Chris@16 1086 static_cast<int_x2_type>(site2.x()),
Chris@16 1087 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1088 static_cast<int_x2_type>(site3.y0()),
Chris@16 1089 static_cast<int_x2_type>(site3.x1()) -
Chris@16 1090 static_cast<int_x2_type>(site3.x0())), to_fpt(1.0));
Chris@16 1091 robust_fpt_type inv_segm_len(to_fpt(1.0) /
Chris@16 1092 get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0));
Chris@16 1093 robust_dif_type t;
Chris@16 1094 if (ot::eval(denom) == ot::COLLINEAR) {
Chris@16 1095 t += teta / (robust_fpt_type(to_fpt(8.0)) * A);
Chris@16 1096 t -= A / (robust_fpt_type(to_fpt(2.0)) * teta);
Chris@16 1097 } else {
Chris@16 1098 robust_fpt_type det = ((teta * teta + denom * denom) * A * B).sqrt();
Chris@16 1099 if (segment_index == 2) {
Chris@16 1100 t -= det / (denom * denom);
Chris@16 1101 } else {
Chris@16 1102 t += det / (denom * denom);
Chris@16 1103 }
Chris@16 1104 t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom);
Chris@16 1105 }
Chris@16 1106 robust_dif_type c_x, c_y;
Chris@16 1107 c_x += robust_fpt_type(to_fpt(0.5) *
Chris@16 1108 (to_fpt(site1.x()) + to_fpt(site2.x())));
Chris@16 1109 c_x += robust_fpt_type(vec_x) * t;
Chris@16 1110 c_y += robust_fpt_type(to_fpt(0.5) *
Chris@16 1111 (to_fpt(site1.y()) + to_fpt(site2.y())));
Chris@16 1112 c_y += robust_fpt_type(vec_y) * t;
Chris@16 1113 robust_dif_type r, lower_x(c_x);
Chris@16 1114 r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0());
Chris@16 1115 r -= robust_fpt_type(line_b) * robust_fpt_type(site3.y0());
Chris@16 1116 r += robust_fpt_type(line_a) * c_x;
Chris@16 1117 r += robust_fpt_type(line_b) * c_y;
Chris@16 1118 if (r.pos().fpv() < r.neg().fpv())
Chris@16 1119 r = -r;
Chris@16 1120 lower_x += r * inv_segm_len;
Chris@16 1121 c_event = circle_type(
Chris@16 1122 c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
Chris@16 1123 bool recompute_c_x = c_x.dif().ulp() > ULPS;
Chris@16 1124 bool recompute_c_y = c_y.dif().ulp() > ULPS;
Chris@16 1125 bool recompute_lower_x = lower_x.dif().ulp() > ULPS;
Chris@16 1126 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
Chris@16 1127 exact_circle_formation_functor_.pps(
Chris@16 1128 site1, site2, site3, segment_index, c_event,
Chris@16 1129 recompute_c_x, recompute_c_y, recompute_lower_x);
Chris@16 1130 }
Chris@16 1131 }
Chris@16 1132
Chris@16 1133 void pss(const site_type& site1,
Chris@16 1134 const site_type& site2,
Chris@16 1135 const site_type& site3,
Chris@16 1136 int point_index,
Chris@16 1137 circle_type& c_event) {
Chris@16 1138 const point_type& segm_start1 = site2.point1();
Chris@16 1139 const point_type& segm_end1 = site2.point0();
Chris@16 1140 const point_type& segm_start2 = site3.point0();
Chris@16 1141 const point_type& segm_end2 = site3.point1();
Chris@16 1142 fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x());
Chris@16 1143 fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y());
Chris@16 1144 fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x());
Chris@16 1145 fpt_type b2 = to_fpt(segm_end2.y()) - to_fpt(segm_start2.y());
Chris@16 1146 bool recompute_c_x, recompute_c_y, recompute_lower_x;
Chris@16 1147 robust_fpt_type orientation(robust_cross_product(
Chris@16 1148 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1149 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1150 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1151 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1152 static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 1153 static_cast<int_x2_type>(segm_start2.y()),
Chris@16 1154 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1155 static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0));
Chris@16 1156 if (ot::eval(orientation) == ot::COLLINEAR) {
Chris@16 1157 robust_fpt_type a(a1 * a1 + b1 * b1, to_fpt(2.0));
Chris@16 1158 robust_fpt_type c(robust_cross_product(
Chris@16 1159 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1160 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1161 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1162 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1163 static_cast<int_x2_type>(segm_start2.y()) -
Chris@16 1164 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1165 static_cast<int_x2_type>(segm_start2.x()) -
Chris@16 1166 static_cast<int_x2_type>(segm_start1.x())), to_fpt(1.0));
Chris@16 1167 robust_fpt_type det(
Chris@16 1168 robust_cross_product(
Chris@16 1169 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1170 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1171 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1172 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1173 static_cast<int_x2_type>(site1.x()) -
Chris@16 1174 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1175 static_cast<int_x2_type>(site1.y()) -
Chris@16 1176 static_cast<int_x2_type>(segm_start1.y())) *
Chris@16 1177 robust_cross_product(
Chris@16 1178 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1179 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1180 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1181 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1182 static_cast<int_x2_type>(site1.y()) -
Chris@16 1183 static_cast<int_x2_type>(segm_start2.y()),
Chris@16 1184 static_cast<int_x2_type>(site1.x()) -
Chris@16 1185 static_cast<int_x2_type>(segm_start2.x())),
Chris@16 1186 to_fpt(3.0));
Chris@16 1187 robust_dif_type t;
Chris@16 1188 t -= robust_fpt_type(a1) * robust_fpt_type((
Chris@16 1189 to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())) * to_fpt(0.5) -
Chris@16 1190 to_fpt(site1.x()));
Chris@16 1191 t -= robust_fpt_type(b1) * robust_fpt_type((
Chris@16 1192 to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())) * to_fpt(0.5) -
Chris@16 1193 to_fpt(site1.y()));
Chris@16 1194 if (point_index == 2) {
Chris@16 1195 t += det.sqrt();
Chris@16 1196 } else {
Chris@16 1197 t -= det.sqrt();
Chris@16 1198 }
Chris@16 1199 t /= a;
Chris@16 1200 robust_dif_type c_x, c_y;
Chris@16 1201 c_x += robust_fpt_type(to_fpt(0.5) * (
Chris@16 1202 to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())));
Chris@16 1203 c_x += robust_fpt_type(a1) * t;
Chris@16 1204 c_y += robust_fpt_type(to_fpt(0.5) * (
Chris@16 1205 to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())));
Chris@16 1206 c_y += robust_fpt_type(b1) * t;
Chris@16 1207 robust_dif_type lower_x(c_x);
Chris@16 1208 if (is_neg(c)) {
Chris@16 1209 lower_x -= robust_fpt_type(to_fpt(0.5)) * c / a.sqrt();
Chris@16 1210 } else {
Chris@16 1211 lower_x += robust_fpt_type(to_fpt(0.5)) * c / a.sqrt();
Chris@16 1212 }
Chris@16 1213 recompute_c_x = c_x.dif().ulp() > ULPS;
Chris@16 1214 recompute_c_y = c_y.dif().ulp() > ULPS;
Chris@16 1215 recompute_lower_x = lower_x.dif().ulp() > ULPS;
Chris@16 1216 c_event =
Chris@16 1217 circle_type(c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
Chris@16 1218 } else {
Chris@16 1219 robust_fpt_type sqr_sum1(get_sqrt(a1 * a1 + b1 * b1), to_fpt(2.0));
Chris@16 1220 robust_fpt_type sqr_sum2(get_sqrt(a2 * a2 + b2 * b2), to_fpt(2.0));
Chris@16 1221 robust_fpt_type a(robust_cross_product(
Chris@16 1222 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1223 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1224 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1225 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1226 static_cast<int_x2_type>(segm_start2.y()) -
Chris@16 1227 static_cast<int_x2_type>(segm_end2.y()),
Chris@16 1228 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1229 static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0));
Chris@16 1230 if (!is_neg(a)) {
Chris@16 1231 a += sqr_sum1 * sqr_sum2;
Chris@16 1232 } else {
Chris@16 1233 a = (orientation * orientation) / (sqr_sum1 * sqr_sum2 - a);
Chris@16 1234 }
Chris@16 1235 robust_fpt_type or1(robust_cross_product(
Chris@16 1236 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1237 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1238 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1239 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1240 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1241 static_cast<int_x2_type>(site1.y()),
Chris@16 1242 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1243 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
Chris@16 1244 robust_fpt_type or2(robust_cross_product(
Chris@16 1245 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1246 static_cast<int_x2_type>(segm_start2.x()),
Chris@16 1247 static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 1248 static_cast<int_x2_type>(segm_start2.y()),
Chris@16 1249 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1250 static_cast<int_x2_type>(site1.x()),
Chris@16 1251 static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 1252 static_cast<int_x2_type>(site1.y())), to_fpt(1.0));
Chris@16 1253 robust_fpt_type det = robust_fpt_type(to_fpt(2.0)) * a * or1 * or2;
Chris@16 1254 robust_fpt_type c1(robust_cross_product(
Chris@16 1255 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1256 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1257 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1258 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1259 static_cast<int_x2_type>(segm_end1.y()),
Chris@16 1260 static_cast<int_x2_type>(segm_end1.x())), to_fpt(1.0));
Chris@16 1261 robust_fpt_type c2(robust_cross_product(
Chris@16 1262 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1263 static_cast<int_x2_type>(segm_start2.x()),
Chris@16 1264 static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 1265 static_cast<int_x2_type>(segm_start2.y()),
Chris@16 1266 static_cast<int_x2_type>(segm_end2.x()),
Chris@16 1267 static_cast<int_x2_type>(segm_end2.y())), to_fpt(1.0));
Chris@16 1268 robust_fpt_type inv_orientation =
Chris@16 1269 robust_fpt_type(to_fpt(1.0)) / orientation;
Chris@16 1270 robust_dif_type t, b, ix, iy;
Chris@16 1271 ix += robust_fpt_type(a2) * c1 * inv_orientation;
Chris@16 1272 ix += robust_fpt_type(a1) * c2 * inv_orientation;
Chris@16 1273 iy += robust_fpt_type(b1) * c2 * inv_orientation;
Chris@16 1274 iy += robust_fpt_type(b2) * c1 * inv_orientation;
Chris@16 1275
Chris@16 1276 b += ix * (robust_fpt_type(a1) * sqr_sum2);
Chris@16 1277 b += ix * (robust_fpt_type(a2) * sqr_sum1);
Chris@16 1278 b += iy * (robust_fpt_type(b1) * sqr_sum2);
Chris@16 1279 b += iy * (robust_fpt_type(b2) * sqr_sum1);
Chris@16 1280 b -= sqr_sum1 * robust_fpt_type(robust_cross_product(
Chris@16 1281 static_cast<int_x2_type>(segm_end2.x()) -
Chris@16 1282 static_cast<int_x2_type>(segm_start2.x()),
Chris@16 1283 static_cast<int_x2_type>(segm_end2.y()) -
Chris@16 1284 static_cast<int_x2_type>(segm_start2.y()),
Chris@16 1285 static_cast<int_x2_type>(-site1.y()),
Chris@16 1286 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
Chris@16 1287 b -= sqr_sum2 * robust_fpt_type(robust_cross_product(
Chris@16 1288 static_cast<int_x2_type>(segm_end1.x()) -
Chris@16 1289 static_cast<int_x2_type>(segm_start1.x()),
Chris@16 1290 static_cast<int_x2_type>(segm_end1.y()) -
Chris@16 1291 static_cast<int_x2_type>(segm_start1.y()),
Chris@16 1292 static_cast<int_x2_type>(-site1.y()),
Chris@16 1293 static_cast<int_x2_type>(site1.x())), to_fpt(1.0));
Chris@16 1294 t -= b;
Chris@16 1295 if (point_index == 2) {
Chris@16 1296 t += det.sqrt();
Chris@16 1297 } else {
Chris@16 1298 t -= det.sqrt();
Chris@16 1299 }
Chris@16 1300 t /= (a * a);
Chris@16 1301 robust_dif_type c_x(ix), c_y(iy);
Chris@16 1302 c_x += t * (robust_fpt_type(a1) * sqr_sum2);
Chris@16 1303 c_x += t * (robust_fpt_type(a2) * sqr_sum1);
Chris@16 1304 c_y += t * (robust_fpt_type(b1) * sqr_sum2);
Chris@16 1305 c_y += t * (robust_fpt_type(b2) * sqr_sum1);
Chris@16 1306 if (t.pos().fpv() < t.neg().fpv()) {
Chris@16 1307 t = -t;
Chris@16 1308 }
Chris@16 1309 robust_dif_type lower_x(c_x);
Chris@16 1310 if (is_neg(orientation)) {
Chris@16 1311 lower_x -= t * orientation;
Chris@16 1312 } else {
Chris@16 1313 lower_x += t * orientation;
Chris@16 1314 }
Chris@16 1315 recompute_c_x = c_x.dif().ulp() > ULPS;
Chris@16 1316 recompute_c_y = c_y.dif().ulp() > ULPS;
Chris@16 1317 recompute_lower_x = lower_x.dif().ulp() > ULPS;
Chris@16 1318 c_event = circle_type(
Chris@16 1319 c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv());
Chris@16 1320 }
Chris@16 1321 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
Chris@16 1322 exact_circle_formation_functor_.pss(
Chris@16 1323 site1, site2, site3, point_index, c_event,
Chris@16 1324 recompute_c_x, recompute_c_y, recompute_lower_x);
Chris@16 1325 }
Chris@16 1326 }
Chris@16 1327
Chris@16 1328 void sss(const site_type& site1,
Chris@16 1329 const site_type& site2,
Chris@16 1330 const site_type& site3,
Chris@16 1331 circle_type& c_event) {
Chris@16 1332 robust_fpt_type a1(to_fpt(site1.x1()) - to_fpt(site1.x0()));
Chris@16 1333 robust_fpt_type b1(to_fpt(site1.y1()) - to_fpt(site1.y0()));
Chris@16 1334 robust_fpt_type c1(robust_cross_product(
Chris@16 1335 site1.x0(), site1.y0(),
Chris@16 1336 site1.x1(), site1.y1()), to_fpt(1.0));
Chris@16 1337
Chris@16 1338 robust_fpt_type a2(to_fpt(site2.x1()) - to_fpt(site2.x0()));
Chris@16 1339 robust_fpt_type b2(to_fpt(site2.y1()) - to_fpt(site2.y0()));
Chris@16 1340 robust_fpt_type c2(robust_cross_product(
Chris@16 1341 site2.x0(), site2.y0(),
Chris@16 1342 site2.x1(), site2.y1()), to_fpt(1.0));
Chris@16 1343
Chris@16 1344 robust_fpt_type a3(to_fpt(site3.x1()) - to_fpt(site3.x0()));
Chris@16 1345 robust_fpt_type b3(to_fpt(site3.y1()) - to_fpt(site3.y0()));
Chris@16 1346 robust_fpt_type c3(robust_cross_product(
Chris@16 1347 site3.x0(), site3.y0(),
Chris@16 1348 site3.x1(), site3.y1()), to_fpt(1.0));
Chris@16 1349
Chris@16 1350 robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt();
Chris@16 1351 robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt();
Chris@16 1352 robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt();
Chris@16 1353 robust_fpt_type cross_12(robust_cross_product(
Chris@16 1354 static_cast<int_x2_type>(site1.x1()) -
Chris@16 1355 static_cast<int_x2_type>(site1.x0()),
Chris@16 1356 static_cast<int_x2_type>(site1.y1()) -
Chris@16 1357 static_cast<int_x2_type>(site1.y0()),
Chris@16 1358 static_cast<int_x2_type>(site2.x1()) -
Chris@16 1359 static_cast<int_x2_type>(site2.x0()),
Chris@16 1360 static_cast<int_x2_type>(site2.y1()) -
Chris@16 1361 static_cast<int_x2_type>(site2.y0())), to_fpt(1.0));
Chris@16 1362 robust_fpt_type cross_23(robust_cross_product(
Chris@16 1363 static_cast<int_x2_type>(site2.x1()) -
Chris@16 1364 static_cast<int_x2_type>(site2.x0()),
Chris@16 1365 static_cast<int_x2_type>(site2.y1()) -
Chris@16 1366 static_cast<int_x2_type>(site2.y0()),
Chris@16 1367 static_cast<int_x2_type>(site3.x1()) -
Chris@16 1368 static_cast<int_x2_type>(site3.x0()),
Chris@16 1369 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1370 static_cast<int_x2_type>(site3.y0())), to_fpt(1.0));
Chris@16 1371 robust_fpt_type cross_31(robust_cross_product(
Chris@16 1372 static_cast<int_x2_type>(site3.x1()) -
Chris@16 1373 static_cast<int_x2_type>(site3.x0()),
Chris@16 1374 static_cast<int_x2_type>(site3.y1()) -
Chris@16 1375 static_cast<int_x2_type>(site3.y0()),
Chris@16 1376 static_cast<int_x2_type>(site1.x1()) -
Chris@16 1377 static_cast<int_x2_type>(site1.x0()),
Chris@16 1378 static_cast<int_x2_type>(site1.y1()) -
Chris@16 1379 static_cast<int_x2_type>(site1.y0())), to_fpt(1.0));
Chris@16 1380
Chris@16 1381 // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2.
Chris@16 1382 robust_dif_type denom;
Chris@16 1383 denom += cross_12 * len3;
Chris@16 1384 denom += cross_23 * len1;
Chris@16 1385 denom += cross_31 * len2;
Chris@16 1386
Chris@16 1387 // denom * r = (b2 * c_x - a2 * c_y - c2 * denom) / len2.
Chris@16 1388 robust_dif_type r;
Chris@16 1389 r -= cross_12 * c3;
Chris@16 1390 r -= cross_23 * c1;
Chris@16 1391 r -= cross_31 * c2;
Chris@16 1392
Chris@16 1393 robust_dif_type c_x;
Chris@16 1394 c_x += a1 * c2 * len3;
Chris@16 1395 c_x -= a2 * c1 * len3;
Chris@16 1396 c_x += a2 * c3 * len1;
Chris@16 1397 c_x -= a3 * c2 * len1;
Chris@16 1398 c_x += a3 * c1 * len2;
Chris@16 1399 c_x -= a1 * c3 * len2;
Chris@16 1400
Chris@16 1401 robust_dif_type c_y;
Chris@16 1402 c_y += b1 * c2 * len3;
Chris@16 1403 c_y -= b2 * c1 * len3;
Chris@16 1404 c_y += b2 * c3 * len1;
Chris@16 1405 c_y -= b3 * c2 * len1;
Chris@16 1406 c_y += b3 * c1 * len2;
Chris@16 1407 c_y -= b1 * c3 * len2;
Chris@16 1408
Chris@16 1409 robust_dif_type lower_x = c_x + r;
Chris@16 1410
Chris@16 1411 robust_fpt_type denom_dif = denom.dif();
Chris@16 1412 robust_fpt_type c_x_dif = c_x.dif() / denom_dif;
Chris@16 1413 robust_fpt_type c_y_dif = c_y.dif() / denom_dif;
Chris@16 1414 robust_fpt_type lower_x_dif = lower_x.dif() / denom_dif;
Chris@16 1415
Chris@16 1416 bool recompute_c_x = c_x_dif.ulp() > ULPS;
Chris@16 1417 bool recompute_c_y = c_y_dif.ulp() > ULPS;
Chris@16 1418 bool recompute_lower_x = lower_x_dif.ulp() > ULPS;
Chris@16 1419 c_event = circle_type(c_x_dif.fpv(), c_y_dif.fpv(), lower_x_dif.fpv());
Chris@16 1420 if (recompute_c_x || recompute_c_y || recompute_lower_x) {
Chris@16 1421 exact_circle_formation_functor_.sss(
Chris@16 1422 site1, site2, site3, c_event,
Chris@16 1423 recompute_c_x, recompute_c_y, recompute_lower_x);
Chris@16 1424 }
Chris@16 1425 }
Chris@16 1426
Chris@16 1427 private:
Chris@16 1428 exact_circle_formation_functor_type exact_circle_formation_functor_;
Chris@16 1429 to_fpt_converter to_fpt;
Chris@16 1430 };
Chris@16 1431
Chris@16 1432 template <typename Site,
Chris@16 1433 typename Circle,
Chris@16 1434 typename CEP = circle_existence_predicate<Site>,
Chris@16 1435 typename CFF = lazy_circle_formation_functor<Site, Circle> >
Chris@16 1436 class circle_formation_predicate {
Chris@16 1437 public:
Chris@16 1438 typedef Site site_type;
Chris@16 1439 typedef Circle circle_type;
Chris@16 1440 typedef CEP circle_existence_predicate_type;
Chris@16 1441 typedef CFF circle_formation_functor_type;
Chris@16 1442
Chris@16 1443 // Create a circle event from the given three sites.
Chris@16 1444 // Returns true if the circle event exists, else false.
Chris@16 1445 // If exists circle event is saved into the c_event variable.
Chris@16 1446 bool operator()(const site_type& site1, const site_type& site2,
Chris@16 1447 const site_type& site3, circle_type& circle) {
Chris@16 1448 if (!site1.is_segment()) {
Chris@16 1449 if (!site2.is_segment()) {
Chris@16 1450 if (!site3.is_segment()) {
Chris@16 1451 // (point, point, point) sites.
Chris@16 1452 if (!circle_existence_predicate_.ppp(site1, site2, site3))
Chris@16 1453 return false;
Chris@16 1454 circle_formation_functor_.ppp(site1, site2, site3, circle);
Chris@16 1455 } else {
Chris@16 1456 // (point, point, segment) sites.
Chris@16 1457 if (!circle_existence_predicate_.pps(site1, site2, site3, 3))
Chris@16 1458 return false;
Chris@16 1459 circle_formation_functor_.pps(site1, site2, site3, 3, circle);
Chris@16 1460 }
Chris@16 1461 } else {
Chris@16 1462 if (!site3.is_segment()) {
Chris@16 1463 // (point, segment, point) sites.
Chris@16 1464 if (!circle_existence_predicate_.pps(site1, site3, site2, 2))
Chris@16 1465 return false;
Chris@16 1466 circle_formation_functor_.pps(site1, site3, site2, 2, circle);
Chris@16 1467 } else {
Chris@16 1468 // (point, segment, segment) sites.
Chris@16 1469 if (!circle_existence_predicate_.pss(site1, site2, site3, 1))
Chris@16 1470 return false;
Chris@16 1471 circle_formation_functor_.pss(site1, site2, site3, 1, circle);
Chris@16 1472 }
Chris@16 1473 }
Chris@16 1474 } else {
Chris@16 1475 if (!site2.is_segment()) {
Chris@16 1476 if (!site3.is_segment()) {
Chris@16 1477 // (segment, point, point) sites.
Chris@16 1478 if (!circle_existence_predicate_.pps(site2, site3, site1, 1))
Chris@16 1479 return false;
Chris@16 1480 circle_formation_functor_.pps(site2, site3, site1, 1, circle);
Chris@16 1481 } else {
Chris@16 1482 // (segment, point, segment) sites.
Chris@16 1483 if (!circle_existence_predicate_.pss(site2, site1, site3, 2))
Chris@16 1484 return false;
Chris@16 1485 circle_formation_functor_.pss(site2, site1, site3, 2, circle);
Chris@16 1486 }
Chris@16 1487 } else {
Chris@16 1488 if (!site3.is_segment()) {
Chris@16 1489 // (segment, segment, point) sites.
Chris@16 1490 if (!circle_existence_predicate_.pss(site3, site1, site2, 3))
Chris@16 1491 return false;
Chris@16 1492 circle_formation_functor_.pss(site3, site1, site2, 3, circle);
Chris@16 1493 } else {
Chris@16 1494 // (segment, segment, segment) sites.
Chris@16 1495 if (!circle_existence_predicate_.sss(site1, site2, site3))
Chris@16 1496 return false;
Chris@16 1497 circle_formation_functor_.sss(site1, site2, site3, circle);
Chris@16 1498 }
Chris@16 1499 }
Chris@16 1500 }
Chris@16 1501 if (lies_outside_vertical_segment(circle, site1) ||
Chris@16 1502 lies_outside_vertical_segment(circle, site2) ||
Chris@16 1503 lies_outside_vertical_segment(circle, site3)) {
Chris@16 1504 return false;
Chris@16 1505 }
Chris@16 1506 return true;
Chris@16 1507 }
Chris@16 1508
Chris@16 1509 private:
Chris@16 1510 bool lies_outside_vertical_segment(
Chris@16 1511 const circle_type& c, const site_type& s) {
Chris@16 1512 if (!s.is_segment() || !is_vertical(s)) {
Chris@16 1513 return false;
Chris@16 1514 }
Chris@16 1515 fpt_type y0 = to_fpt(s.is_inverse() ? s.y1() : s.y0());
Chris@16 1516 fpt_type y1 = to_fpt(s.is_inverse() ? s.y0() : s.y1());
Chris@16 1517 return ulp_cmp(c.y(), y0, ULPS) == ulp_cmp_type::LESS ||
Chris@16 1518 ulp_cmp(c.y(), y1, ULPS) == ulp_cmp_type::MORE;
Chris@16 1519 }
Chris@16 1520
Chris@16 1521 private:
Chris@16 1522 to_fpt_converter to_fpt;
Chris@16 1523 ulp_cmp_type ulp_cmp;
Chris@16 1524 circle_existence_predicate_type circle_existence_predicate_;
Chris@16 1525 circle_formation_functor_type circle_formation_functor_;
Chris@16 1526 };
Chris@16 1527 };
Chris@16 1528 } // detail
Chris@16 1529 } // polygon
Chris@16 1530 } // boost
Chris@16 1531
Chris@16 1532 #endif // BOOST_POLYGON_DETAIL_VORONOI_PREDICATES