Chris@16: // Boost.Polygon library detail/voronoi_predicates.hpp header file Chris@16: Chris@16: // Copyright Andrii Sydorchuk 2010-2012. Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See http://www.boost.org for updates, documentation, and revision history. Chris@16: Chris@16: #ifndef BOOST_POLYGON_DETAIL_VORONOI_PREDICATES Chris@16: #define BOOST_POLYGON_DETAIL_VORONOI_PREDICATES Chris@16: Chris@16: #include Chris@16: Chris@16: #include "voronoi_robust_fpt.hpp" Chris@16: Chris@16: namespace boost { Chris@16: namespace polygon { Chris@16: namespace detail { Chris@16: Chris@16: // Predicate utilities. Operates with the coordinate types that could Chris@16: // be converted to the 32-bit signed integer without precision loss. Chris@16: template Chris@16: class voronoi_predicates { Chris@16: public: Chris@16: typedef typename CTYPE_TRAITS::int_type int_type; Chris@16: typedef typename CTYPE_TRAITS::int_x2_type int_x2_type; Chris@16: typedef typename CTYPE_TRAITS::uint_x2_type uint_x2_type; Chris@16: typedef typename CTYPE_TRAITS::big_int_type big_int_type; Chris@16: typedef typename CTYPE_TRAITS::fpt_type fpt_type; Chris@16: typedef typename CTYPE_TRAITS::efpt_type efpt_type; Chris@16: typedef typename CTYPE_TRAITS::ulp_cmp_type ulp_cmp_type; Chris@16: typedef typename CTYPE_TRAITS::to_fpt_converter_type to_fpt_converter; Chris@16: typedef typename CTYPE_TRAITS::to_efpt_converter_type to_efpt_converter; Chris@16: Chris@16: enum { Chris@16: ULPS = 64, Chris@16: ULPSx2 = 128 Chris@16: }; Chris@16: Chris@16: template Chris@16: static bool is_vertical(const Point& point1, const Point& point2) { Chris@16: return point1.x() == point2.x(); Chris@16: } Chris@16: Chris@16: template Chris@16: static bool is_vertical(const Site& site) { Chris@16: return is_vertical(site.point0(), site.point1()); Chris@16: } Chris@16: Chris@16: // Compute robust cross_product: a1 * b2 - b1 * a2. Chris@16: // It was mathematically proven that the result is correct Chris@16: // with epsilon relative error equal to 1EPS. Chris@16: static fpt_type robust_cross_product(int_x2_type a1_, Chris@16: int_x2_type b1_, Chris@16: int_x2_type a2_, Chris@16: int_x2_type b2_) { Chris@16: static to_fpt_converter to_fpt; Chris@16: uint_x2_type a1 = static_cast(is_neg(a1_) ? -a1_ : a1_); Chris@16: uint_x2_type b1 = static_cast(is_neg(b1_) ? -b1_ : b1_); Chris@16: uint_x2_type a2 = static_cast(is_neg(a2_) ? -a2_ : a2_); Chris@16: uint_x2_type b2 = static_cast(is_neg(b2_) ? -b2_ : b2_); Chris@16: Chris@16: uint_x2_type l = a1 * b2; Chris@16: uint_x2_type r = b1 * a2; Chris@16: Chris@16: if (is_neg(a1_) ^ is_neg(b2_)) { Chris@16: if (is_neg(a2_) ^ is_neg(b1_)) Chris@16: return (l > r) ? -to_fpt(l - r) : to_fpt(r - l); Chris@16: else Chris@16: return -to_fpt(l + r); Chris@16: } else { Chris@16: if (is_neg(a2_) ^ is_neg(b1_)) Chris@16: return to_fpt(l + r); Chris@16: else Chris@16: return (l < r) ? -to_fpt(r - l) : to_fpt(l - r); Chris@16: } Chris@16: } Chris@16: Chris@16: typedef struct orientation_test { Chris@16: public: Chris@16: // Represents orientation test result. Chris@16: enum Orientation { Chris@16: RIGHT = -1, Chris@16: COLLINEAR = 0, Chris@16: LEFT = 1 Chris@16: }; Chris@16: Chris@16: // Value is a determinant of two vectors (e.g. x1 * y2 - x2 * y1). Chris@16: // Return orientation based on the sign of the determinant. Chris@16: template Chris@16: static Orientation eval(T value) { Chris@16: if (is_zero(value)) return COLLINEAR; Chris@16: return (is_neg(value)) ? RIGHT : LEFT; Chris@16: } Chris@16: Chris@16: static Orientation eval(int_x2_type dif_x1_, Chris@16: int_x2_type dif_y1_, Chris@16: int_x2_type dif_x2_, Chris@16: int_x2_type dif_y2_) { Chris@16: return eval(robust_cross_product(dif_x1_, dif_y1_, dif_x2_, dif_y2_)); Chris@16: } Chris@16: Chris@16: template Chris@16: static Orientation eval(const Point& point1, Chris@16: const Point& point2, Chris@16: const Point& point3) { Chris@16: int_x2_type dx1 = static_cast(point1.x()) - Chris@16: static_cast(point2.x()); Chris@16: int_x2_type dx2 = static_cast(point2.x()) - Chris@16: static_cast(point3.x()); Chris@16: int_x2_type dy1 = static_cast(point1.y()) - Chris@16: static_cast(point2.y()); Chris@16: int_x2_type dy2 = static_cast(point2.y()) - Chris@16: static_cast(point3.y()); Chris@16: return eval(robust_cross_product(dx1, dy1, dx2, dy2)); Chris@16: } Chris@16: } ot; Chris@16: Chris@16: template Chris@16: class point_comparison_predicate { Chris@16: public: Chris@16: typedef Point point_type; Chris@16: Chris@16: bool operator()(const point_type& lhs, const point_type& rhs) const { Chris@16: if (lhs.x() == rhs.x()) Chris@16: return lhs.y() < rhs.y(); Chris@16: return lhs.x() < rhs.x(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: class event_comparison_predicate { Chris@16: public: Chris@16: typedef Site site_type; Chris@16: typedef Circle circle_type; Chris@16: Chris@16: bool operator()(const site_type& lhs, const site_type& rhs) const { Chris@16: if (lhs.x0() != rhs.x0()) Chris@16: return lhs.x0() < rhs.x0(); Chris@16: if (!lhs.is_segment()) { Chris@16: if (!rhs.is_segment()) Chris@16: return lhs.y0() < rhs.y0(); Chris@16: if (is_vertical(rhs)) Chris@16: return lhs.y0() <= rhs.y0(); Chris@16: return true; Chris@16: } else { Chris@16: if (is_vertical(rhs)) { Chris@16: if (is_vertical(lhs)) Chris@16: return lhs.y0() < rhs.y0(); Chris@16: return false; Chris@16: } Chris@16: if (is_vertical(lhs)) Chris@16: return true; Chris@16: if (lhs.y0() != rhs.y0()) Chris@16: return lhs.y0() < rhs.y0(); Chris@16: return ot::eval(lhs.point1(), lhs.point0(), rhs.point1()) == ot::LEFT; Chris@16: } Chris@16: } Chris@16: Chris@16: bool operator()(const site_type& lhs, const circle_type& rhs) const { Chris@16: typename ulp_cmp_type::Result xCmp = Chris@16: ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPS); Chris@16: return xCmp == ulp_cmp_type::LESS; Chris@16: } Chris@16: Chris@16: bool operator()(const circle_type& lhs, const site_type& rhs) const { Chris@16: typename ulp_cmp_type::Result xCmp = Chris@16: ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPS); Chris@16: return xCmp == ulp_cmp_type::LESS; Chris@16: } Chris@16: Chris@16: bool operator()(const circle_type& lhs, const circle_type& rhs) const { Chris@16: if (lhs.lower_x() != rhs.lower_x()) { Chris@16: return lhs.lower_x() < rhs.lower_x(); Chris@16: } Chris@16: return lhs.y() < rhs.y(); Chris@16: } Chris@16: Chris@16: private: Chris@16: ulp_cmp_type ulp_cmp; Chris@16: to_fpt_converter to_fpt; Chris@16: }; Chris@16: Chris@16: template Chris@16: class distance_predicate { Chris@16: public: Chris@16: typedef Site site_type; Chris@16: typedef typename site_type::point_type point_type; Chris@16: Chris@16: // Returns true if a horizontal line going through a new site intersects Chris@16: // right arc at first, else returns false. If horizontal line goes Chris@16: // through intersection point of the given two arcs returns false also. Chris@16: bool operator()(const site_type& left_site, Chris@16: const site_type& right_site, Chris@16: const point_type& new_point) const { Chris@16: if (!left_site.is_segment()) { Chris@16: if (!right_site.is_segment()) { Chris@16: return pp(left_site, right_site, new_point); Chris@16: } else { Chris@16: return ps(left_site, right_site, new_point, false); Chris@16: } Chris@16: } else { Chris@16: if (!right_site.is_segment()) { Chris@16: return ps(right_site, left_site, new_point, true); Chris@16: } else { Chris@16: return ss(left_site, right_site, new_point); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: // Represents the result of the epsilon robust predicate. If the Chris@16: // result is undefined some further processing is usually required. Chris@16: enum kPredicateResult { Chris@16: LESS = -1, Chris@16: UNDEFINED = 0, Chris@16: MORE = 1 Chris@16: }; Chris@16: Chris@16: // Robust predicate, avoids using high-precision libraries. Chris@16: // Returns true if a horizontal line going through the new point site Chris@16: // intersects right arc at first, else returns false. If horizontal line Chris@16: // goes through intersection point of the given two arcs returns false. Chris@16: bool pp(const site_type& left_site, Chris@16: const site_type& right_site, Chris@16: const point_type& new_point) const { Chris@16: const point_type& left_point = left_site.point0(); Chris@16: const point_type& right_point = right_site.point0(); Chris@16: if (left_point.x() > right_point.x()) { Chris@16: if (new_point.y() <= left_point.y()) Chris@16: return false; Chris@16: } else if (left_point.x() < right_point.x()) { Chris@16: if (new_point.y() >= right_point.y()) Chris@16: return true; Chris@16: } else { Chris@16: return static_cast(left_point.y()) + Chris@16: static_cast(right_point.y()) < Chris@16: static_cast(new_point.y()) * 2; Chris@16: } Chris@16: Chris@16: fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); Chris@16: fpt_type dist2 = find_distance_to_point_arc(right_site, new_point); Chris@16: Chris@16: // The undefined ulp range is equal to 3EPS + 3EPS <= 6ULP. Chris@16: return dist1 < dist2; Chris@16: } Chris@16: Chris@16: bool ps(const site_type& left_site, const site_type& right_site, Chris@16: const point_type& new_point, bool reverse_order) const { Chris@16: kPredicateResult fast_res = fast_ps( Chris@16: left_site, right_site, new_point, reverse_order); Chris@16: if (fast_res != UNDEFINED) { Chris@16: return fast_res == LESS; Chris@16: } Chris@16: Chris@16: fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); Chris@16: fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); Chris@16: Chris@16: // The undefined ulp range is equal to 3EPS + 7EPS <= 10ULP. Chris@16: return reverse_order ^ (dist1 < dist2); Chris@16: } Chris@16: Chris@16: bool ss(const site_type& left_site, Chris@16: const site_type& right_site, Chris@16: const point_type& new_point) const { Chris@16: // Handle temporary segment sites. Chris@16: if (left_site.sorted_index() == right_site.sorted_index()) { Chris@16: return ot::eval( Chris@16: left_site.point0(), left_site.point1(), new_point) == ot::LEFT; Chris@16: } Chris@16: Chris@16: fpt_type dist1 = find_distance_to_segment_arc(left_site, new_point); Chris@16: fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); Chris@16: Chris@16: // The undefined ulp range is equal to 7EPS + 7EPS <= 14ULP. Chris@16: return dist1 < dist2; Chris@16: } Chris@16: Chris@16: fpt_type find_distance_to_point_arc( Chris@16: const site_type& site, const point_type& point) const { Chris@16: fpt_type dx = to_fpt(site.x()) - to_fpt(point.x()); Chris@16: fpt_type dy = to_fpt(site.y()) - to_fpt(point.y()); Chris@16: // The relative error is at most 3EPS. Chris@16: return (dx * dx + dy * dy) / (to_fpt(2.0) * dx); Chris@16: } Chris@16: Chris@16: fpt_type find_distance_to_segment_arc( Chris@16: const site_type& site, const point_type& point) const { Chris@16: if (is_vertical(site)) { Chris@16: return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5); Chris@16: } else { Chris@16: const point_type& segment0 = site.point0(); Chris@16: const point_type& segment1 = site.point1(); Chris@16: fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x()); Chris@16: fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y()); Chris@16: fpt_type k = get_sqrt(a1 * a1 + b1 * b1); Chris@16: // Avoid subtraction while computing k. Chris@16: if (!is_neg(b1)) { Chris@16: k = to_fpt(1.0) / (b1 + k); Chris@16: } else { Chris@16: k = (k - b1) / (a1 * a1); Chris@16: } Chris@16: // The relative error is at most 7EPS. Chris@16: return k * robust_cross_product( Chris@16: static_cast(segment1.x()) - Chris@16: static_cast(segment0.x()), Chris@16: static_cast(segment1.y()) - Chris@16: static_cast(segment0.y()), Chris@16: static_cast(point.x()) - Chris@16: static_cast(segment0.x()), Chris@16: static_cast(point.y()) - Chris@16: static_cast(segment0.y())); Chris@16: } Chris@16: } Chris@16: Chris@16: kPredicateResult fast_ps( Chris@16: const site_type& left_site, const site_type& right_site, Chris@16: const point_type& new_point, bool reverse_order) const { Chris@16: const point_type& site_point = left_site.point0(); Chris@16: const point_type& segment_start = right_site.point0(); Chris@16: const point_type& segment_end = right_site.point1(); Chris@16: Chris@16: if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT) Chris@16: return (!right_site.is_inverse()) ? LESS : MORE; Chris@16: Chris@16: fpt_type dif_x = to_fpt(new_point.x()) - to_fpt(site_point.x()); Chris@16: fpt_type dif_y = to_fpt(new_point.y()) - to_fpt(site_point.y()); Chris@16: fpt_type a = to_fpt(segment_end.x()) - to_fpt(segment_start.x()); Chris@16: fpt_type b = to_fpt(segment_end.y()) - to_fpt(segment_start.y()); Chris@16: Chris@16: if (is_vertical(right_site)) { Chris@16: if (new_point.y() < site_point.y() && !reverse_order) Chris@16: return MORE; Chris@16: else if (new_point.y() > site_point.y() && reverse_order) Chris@16: return LESS; Chris@16: return UNDEFINED; Chris@16: } else { Chris@16: typename ot::Orientation orientation = ot::eval( Chris@16: static_cast(segment_end.x()) - Chris@16: static_cast(segment_start.x()), Chris@16: static_cast(segment_end.y()) - Chris@16: static_cast(segment_start.y()), Chris@16: static_cast(new_point.x()) - Chris@16: static_cast(site_point.x()), Chris@16: static_cast(new_point.y()) - Chris@16: static_cast(site_point.y())); Chris@16: if (orientation == ot::LEFT) { Chris@16: if (!right_site.is_inverse()) Chris@16: return reverse_order ? LESS : UNDEFINED; Chris@16: return reverse_order ? UNDEFINED : MORE; Chris@16: } Chris@16: } Chris@16: Chris@16: fpt_type fast_left_expr = a * (dif_y + dif_x) * (dif_y - dif_x); Chris@16: fpt_type fast_right_expr = (to_fpt(2.0) * b) * dif_x * dif_y; Chris@16: typename ulp_cmp_type::Result expr_cmp = Chris@16: ulp_cmp(fast_left_expr, fast_right_expr, 4); Chris@16: if (expr_cmp != ulp_cmp_type::EQUAL) { Chris@16: if ((expr_cmp == ulp_cmp_type::MORE) ^ reverse_order) Chris@16: return reverse_order ? LESS : MORE; Chris@16: return UNDEFINED; Chris@16: } Chris@16: return UNDEFINED; Chris@16: } Chris@16: Chris@16: private: Chris@16: ulp_cmp_type ulp_cmp; Chris@16: to_fpt_converter to_fpt; Chris@16: }; Chris@16: Chris@16: template Chris@16: class node_comparison_predicate { Chris@16: public: Chris@16: typedef Node node_type; Chris@16: typedef typename Node::site_type site_type; Chris@16: typedef typename site_type::point_type point_type; Chris@16: typedef typename point_type::coordinate_type coordinate_type; Chris@16: typedef point_comparison_predicate point_comparison_type; Chris@16: typedef distance_predicate distance_predicate_type; Chris@16: Chris@16: // Compares nodes in the balanced binary search tree. Nodes are Chris@16: // compared based on the y coordinates of the arcs intersection points. Chris@16: // Nodes with less y coordinate of the intersection point go first. Chris@16: // Comparison is only called during the new site events processing. Chris@16: // That's why one of the nodes will always lie on the sweepline and may Chris@16: // be represented as a straight horizontal line. Chris@16: bool operator() (const node_type& node1, Chris@16: const node_type& node2) const { Chris@16: // Get x coordinate of the rightmost site from both nodes. Chris@16: const site_type& site1 = get_comparison_site(node1); Chris@16: const site_type& site2 = get_comparison_site(node2); Chris@16: const point_type& point1 = get_comparison_point(site1); Chris@16: const point_type& point2 = get_comparison_point(site2); Chris@16: Chris@16: if (point1.x() < point2.x()) { Chris@16: // The second node contains a new site. Chris@16: return distance_predicate_( Chris@16: node1.left_site(), node1.right_site(), point2); Chris@16: } else if (point1.x() > point2.x()) { Chris@16: // The first node contains a new site. Chris@16: return !distance_predicate_( Chris@16: node2.left_site(), node2.right_site(), point1); Chris@16: } else { Chris@16: // This checks were evaluated experimentally. Chris@16: if (site1.sorted_index() == site2.sorted_index()) { Chris@16: // Both nodes are new (inserted during same site event processing). Chris@16: return get_comparison_y(node1) < get_comparison_y(node2); Chris@16: } else if (site1.sorted_index() < site2.sorted_index()) { Chris@16: std::pair y1 = get_comparison_y(node1, false); Chris@16: std::pair y2 = get_comparison_y(node2, true); Chris@16: if (y1.first != y2.first) return y1.first < y2.first; Chris@16: return (!site1.is_segment()) ? (y1.second < 0) : false; Chris@16: } else { Chris@16: std::pair y1 = get_comparison_y(node1, true); Chris@16: std::pair y2 = get_comparison_y(node2, false); Chris@16: if (y1.first != y2.first) return y1.first < y2.first; Chris@16: return (!site2.is_segment()) ? (y2.second > 0) : true; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: // Get the newer site. Chris@16: const site_type& get_comparison_site(const node_type& node) const { Chris@16: if (node.left_site().sorted_index() > node.right_site().sorted_index()) { Chris@16: return node.left_site(); Chris@16: } Chris@16: return node.right_site(); Chris@16: } Chris@16: Chris@16: const point_type& get_comparison_point(const site_type& site) const { Chris@16: return point_comparison_(site.point0(), site.point1()) ? Chris@16: site.point0() : site.point1(); Chris@16: } Chris@16: Chris@16: // Get comparison pair: y coordinate and direction of the newer site. Chris@16: std::pair get_comparison_y( Chris@16: const node_type& node, bool is_new_node = true) const { Chris@16: if (node.left_site().sorted_index() == Chris@16: node.right_site().sorted_index()) { Chris@16: return std::make_pair(node.left_site().y0(), 0); Chris@16: } Chris@16: if (node.left_site().sorted_index() > node.right_site().sorted_index()) { Chris@16: if (!is_new_node && Chris@16: node.left_site().is_segment() && Chris@16: is_vertical(node.left_site())) { Chris@16: return std::make_pair(node.left_site().y0(), 1); Chris@16: } Chris@16: return std::make_pair(node.left_site().y1(), 1); Chris@16: } Chris@16: return std::make_pair(node.right_site().y0(), -1); Chris@16: } Chris@16: Chris@16: point_comparison_type point_comparison_; Chris@16: distance_predicate_type distance_predicate_; Chris@16: }; Chris@16: Chris@16: template Chris@16: class circle_existence_predicate { Chris@16: public: Chris@16: typedef typename Site::point_type point_type; Chris@16: typedef Site site_type; Chris@16: Chris@16: bool ppp(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3) const { Chris@16: return ot::eval(site1.point0(), Chris@16: site2.point0(), Chris@16: site3.point0()) == ot::RIGHT; Chris@16: } Chris@16: Chris@16: bool pps(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int segment_index) const { Chris@16: if (segment_index != 2) { Chris@16: typename ot::Orientation orient1 = ot::eval( Chris@16: site1.point0(), site2.point0(), site3.point0()); Chris@16: typename ot::Orientation orient2 = ot::eval( Chris@16: site1.point0(), site2.point0(), site3.point1()); Chris@16: if (segment_index == 1 && site1.x0() >= site2.x0()) { Chris@16: if (orient1 != ot::RIGHT) Chris@16: return false; Chris@16: } else if (segment_index == 3 && site2.x0() >= site1.x0()) { Chris@16: if (orient2 != ot::RIGHT) Chris@16: return false; Chris@16: } else if (orient1 != ot::RIGHT && orient2 != ot::RIGHT) { Chris@16: return false; Chris@16: } Chris@16: } else { Chris@16: return (site3.point0() != site1.point0()) || Chris@16: (site3.point1() != site2.point0()); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: bool pss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int point_index) const { Chris@16: if (site2.sorted_index() == site3.sorted_index()) { Chris@16: return false; Chris@16: } Chris@16: if (point_index == 2) { Chris@16: if (!site2.is_inverse() && site3.is_inverse()) Chris@16: return false; Chris@16: if (site2.is_inverse() == site3.is_inverse() && Chris@16: ot::eval(site2.point0(), Chris@16: site1.point0(), Chris@16: site3.point1()) != ot::RIGHT) Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: bool sss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3) const { Chris@16: return (site1.sorted_index() != site2.sorted_index()) && Chris@16: (site2.sorted_index() != site3.sorted_index()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: class mp_circle_formation_functor { Chris@16: public: Chris@16: typedef typename Site::point_type point_type; Chris@16: typedef Site site_type; Chris@16: typedef Circle circle_type; Chris@16: typedef robust_sqrt_expr Chris@16: robust_sqrt_expr_type; Chris@16: Chris@16: void ppp(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: circle_type& circle, Chris@16: bool recompute_c_x = true, Chris@16: bool recompute_c_y = true, Chris@16: bool recompute_lower_x = true) { Chris@16: big_int_type dif_x[3], dif_y[3], sum_x[2], sum_y[2]; Chris@16: dif_x[0] = static_cast(site1.x()) - Chris@16: static_cast(site2.x()); Chris@16: dif_x[1] = static_cast(site2.x()) - Chris@16: static_cast(site3.x()); Chris@16: dif_x[2] = static_cast(site1.x()) - Chris@16: static_cast(site3.x()); Chris@16: dif_y[0] = static_cast(site1.y()) - Chris@16: static_cast(site2.y()); Chris@16: dif_y[1] = static_cast(site2.y()) - Chris@16: static_cast(site3.y()); Chris@16: dif_y[2] = static_cast(site1.y()) - Chris@16: static_cast(site3.y()); Chris@16: sum_x[0] = static_cast(site1.x()) + Chris@16: static_cast(site2.x()); Chris@16: sum_x[1] = static_cast(site2.x()) + Chris@16: static_cast(site3.x()); Chris@16: sum_y[0] = static_cast(site1.y()) + Chris@16: static_cast(site2.y()); Chris@16: sum_y[1] = static_cast(site2.y()) + Chris@16: static_cast(site3.y()); Chris@16: fpt_type inv_denom = to_fpt(0.5) / to_fpt(static_cast( Chris@16: dif_x[0] * dif_y[1] - dif_x[1] * dif_y[0])); Chris@16: big_int_type numer1 = dif_x[0] * sum_x[0] + dif_y[0] * sum_y[0]; Chris@16: big_int_type numer2 = dif_x[1] * sum_x[1] + dif_y[1] * sum_y[1]; Chris@16: Chris@16: if (recompute_c_x || recompute_lower_x) { Chris@16: big_int_type c_x = numer1 * dif_y[1] - numer2 * dif_y[0]; Chris@16: circle.x(to_fpt(c_x) * inv_denom); Chris@16: Chris@16: if (recompute_lower_x) { Chris@16: // Evaluate radius of the circle. Chris@16: big_int_type sqr_r = (dif_x[0] * dif_x[0] + dif_y[0] * dif_y[0]) * Chris@16: (dif_x[1] * dif_x[1] + dif_y[1] * dif_y[1]) * Chris@16: (dif_x[2] * dif_x[2] + dif_y[2] * dif_y[2]); Chris@16: fpt_type r = get_sqrt(to_fpt(sqr_r)); Chris@16: Chris@16: // If c_x >= 0 then lower_x = c_x + r, Chris@16: // else lower_x = (c_x * c_x - r * r) / (c_x - r). Chris@16: // To guarantee epsilon relative error. Chris@16: if (!is_neg(circle.x())) { Chris@16: if (!is_neg(inv_denom)) { Chris@16: circle.lower_x(circle.x() + r * inv_denom); Chris@16: } else { Chris@16: circle.lower_x(circle.x() - r * inv_denom); Chris@16: } Chris@16: } else { Chris@16: big_int_type numer = c_x * c_x - sqr_r; Chris@16: fpt_type lower_x = to_fpt(numer) * inv_denom / (to_fpt(c_x) + r); Chris@16: circle.lower_x(lower_x); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: if (recompute_c_y) { Chris@16: big_int_type c_y = numer2 * dif_x[0] - numer1 * dif_x[1]; Chris@16: circle.y(to_fpt(c_y) * inv_denom); Chris@16: } Chris@16: } Chris@16: Chris@16: // Recompute parameters of the circle event using high-precision library. Chris@16: void pps(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int segment_index, Chris@16: circle_type& c_event, Chris@16: bool recompute_c_x = true, Chris@16: bool recompute_c_y = true, Chris@16: bool recompute_lower_x = true) { Chris@16: big_int_type cA[4], cB[4]; Chris@16: big_int_type line_a = static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()); Chris@16: big_int_type line_b = static_cast(site3.x0()) - Chris@16: static_cast(site3.x1()); Chris@16: big_int_type segm_len = line_a * line_a + line_b * line_b; Chris@16: big_int_type vec_x = static_cast(site2.y()) - Chris@16: static_cast(site1.y()); Chris@16: big_int_type vec_y = static_cast(site1.x()) - Chris@16: static_cast(site2.x()); Chris@16: big_int_type sum_x = static_cast(site1.x()) + Chris@16: static_cast(site2.x()); Chris@16: big_int_type sum_y = static_cast(site1.y()) + Chris@16: static_cast(site2.y()); Chris@16: big_int_type teta = line_a * vec_x + line_b * vec_y; Chris@16: big_int_type denom = vec_x * line_b - vec_y * line_a; Chris@16: Chris@16: big_int_type dif0 = static_cast(site3.y1()) - Chris@16: static_cast(site1.y()); Chris@16: big_int_type dif1 = static_cast(site1.x()) - Chris@16: static_cast(site3.x1()); Chris@16: big_int_type A = line_a * dif1 - line_b * dif0; Chris@16: dif0 = static_cast(site3.y1()) - Chris@16: static_cast(site2.y()); Chris@16: dif1 = static_cast(site2.x()) - Chris@16: static_cast(site3.x1()); Chris@16: big_int_type B = line_a * dif1 - line_b * dif0; Chris@16: big_int_type sum_AB = A + B; Chris@16: Chris@16: if (is_zero(denom)) { Chris@16: big_int_type numer = teta * teta - sum_AB * sum_AB; Chris@101: denom = teta * sum_AB; Chris@16: cA[0] = denom * sum_x * 2 + numer * vec_x; Chris@16: cB[0] = segm_len; Chris@16: cA[1] = denom * sum_AB * 2 + numer * teta; Chris@16: cB[1] = 1; Chris@16: cA[2] = denom * sum_y * 2 + numer * vec_y; Chris@16: fpt_type inv_denom = to_fpt(1.0) / to_fpt(denom); Chris@16: if (recompute_c_x) Chris@16: c_event.x(to_fpt(0.25) * to_fpt(cA[0]) * inv_denom); Chris@16: if (recompute_c_y) Chris@16: c_event.y(to_fpt(0.25) * to_fpt(cA[2]) * inv_denom); Chris@16: if (recompute_lower_x) { Chris@16: c_event.lower_x(to_fpt(0.25) * to_fpt(sqrt_expr_.eval2(cA, cB)) * Chris@16: inv_denom / get_sqrt(to_fpt(segm_len))); Chris@16: } Chris@16: return; Chris@16: } Chris@16: Chris@16: big_int_type det = (teta * teta + denom * denom) * A * B * 4; Chris@16: fpt_type inv_denom_sqr = to_fpt(1.0) / to_fpt(denom); Chris@16: inv_denom_sqr *= inv_denom_sqr; Chris@16: Chris@16: if (recompute_c_x || recompute_lower_x) { Chris@16: cA[0] = sum_x * denom * denom + teta * sum_AB * vec_x; Chris@16: cB[0] = 1; Chris@16: cA[1] = (segment_index == 2) ? -vec_x : vec_x; Chris@16: cB[1] = det; Chris@16: if (recompute_c_x) { Chris@16: c_event.x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(cA, cB)) * Chris@16: inv_denom_sqr); Chris@16: } Chris@16: } Chris@16: Chris@16: if (recompute_c_y || recompute_lower_x) { Chris@16: cA[2] = sum_y * denom * denom + teta * sum_AB * vec_y; Chris@16: cB[2] = 1; Chris@16: cA[3] = (segment_index == 2) ? -vec_y : vec_y; Chris@16: cB[3] = det; Chris@16: if (recompute_c_y) { Chris@16: c_event.y(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(&cA[2], &cB[2])) * Chris@16: inv_denom_sqr); Chris@16: } Chris@16: } Chris@16: Chris@16: if (recompute_lower_x) { Chris@16: cB[0] = cB[0] * segm_len; Chris@16: cB[1] = cB[1] * segm_len; Chris@16: cA[2] = sum_AB * (denom * denom + teta * teta); Chris@16: cB[2] = 1; Chris@16: cA[3] = (segment_index == 2) ? -teta : teta; Chris@16: cB[3] = det; Chris@16: c_event.lower_x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval4(cA, cB)) * Chris@16: inv_denom_sqr / get_sqrt(to_fpt(segm_len))); Chris@16: } Chris@16: } Chris@16: Chris@16: // Recompute parameters of the circle event using high-precision library. Chris@16: void pss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int point_index, Chris@16: circle_type& c_event, Chris@16: bool recompute_c_x = true, Chris@16: bool recompute_c_y = true, Chris@16: bool recompute_lower_x = true) { Chris@16: big_int_type a[2], b[2], c[2], cA[4], cB[4]; Chris@16: const point_type& segm_start1 = site2.point1(); Chris@16: const point_type& segm_end1 = site2.point0(); Chris@16: const point_type& segm_start2 = site3.point0(); Chris@16: const point_type& segm_end2 = site3.point1(); Chris@16: a[0] = static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()); Chris@16: b[0] = static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()); Chris@16: a[1] = static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x()); Chris@16: b[1] = static_cast(segm_end2.y()) - Chris@16: static_cast(segm_start2.y()); Chris@16: big_int_type orientation = a[1] * b[0] - a[0] * b[1]; Chris@16: if (is_zero(orientation)) { Chris@16: fpt_type denom = to_fpt(2.0) * to_fpt( Chris@16: static_cast(a[0] * a[0] + b[0] * b[0])); Chris@16: c[0] = b[0] * (static_cast(segm_start2.x()) - Chris@16: static_cast(segm_start1.x())) - Chris@16: a[0] * (static_cast(segm_start2.y()) - Chris@16: static_cast(segm_start1.y())); Chris@16: big_int_type dx = a[0] * (static_cast(site1.y()) - Chris@16: static_cast(segm_start1.y())) - Chris@16: b[0] * (static_cast(site1.x()) - Chris@16: static_cast(segm_start1.x())); Chris@16: big_int_type dy = b[0] * (static_cast(site1.x()) - Chris@16: static_cast(segm_start2.x())) - Chris@16: a[0] * (static_cast(site1.y()) - Chris@16: static_cast(segm_start2.y())); Chris@16: cB[0] = dx * dy; Chris@16: cB[1] = 1; Chris@16: Chris@16: if (recompute_c_y) { Chris@16: cA[0] = b[0] * ((point_index == 2) ? 2 : -2); Chris@16: cA[1] = a[0] * a[0] * (static_cast(segm_start1.y()) + Chris@16: static_cast(segm_start2.y())) - Chris@16: a[0] * b[0] * (static_cast(segm_start1.x()) + Chris@16: static_cast(segm_start2.x()) - Chris@16: static_cast(site1.x()) * 2) + Chris@16: b[0] * b[0] * (static_cast(site1.y()) * 2); Chris@16: fpt_type c_y = to_fpt(sqrt_expr_.eval2(cA, cB)); Chris@16: c_event.y(c_y / denom); Chris@16: } Chris@16: Chris@16: if (recompute_c_x || recompute_lower_x) { Chris@16: cA[0] = a[0] * ((point_index == 2) ? 2 : -2); Chris@16: cA[1] = b[0] * b[0] * (static_cast(segm_start1.x()) + Chris@16: static_cast(segm_start2.x())) - Chris@16: a[0] * b[0] * (static_cast(segm_start1.y()) + Chris@16: static_cast(segm_start2.y()) - Chris@16: static_cast(site1.y()) * 2) + Chris@16: a[0] * a[0] * (static_cast(site1.x()) * 2); Chris@16: Chris@16: if (recompute_c_x) { Chris@16: fpt_type c_x = to_fpt(sqrt_expr_.eval2(cA, cB)); Chris@16: c_event.x(c_x / denom); Chris@16: } Chris@16: Chris@16: if (recompute_lower_x) { Chris@16: cA[2] = is_neg(c[0]) ? -c[0] : c[0]; Chris@16: cB[2] = a[0] * a[0] + b[0] * b[0]; Chris@16: fpt_type lower_x = to_fpt(sqrt_expr_.eval3(cA, cB)); Chris@16: c_event.lower_x(lower_x / denom); Chris@16: } Chris@16: } Chris@16: return; Chris@16: } Chris@16: c[0] = b[0] * segm_end1.x() - a[0] * segm_end1.y(); Chris@16: c[1] = a[1] * segm_end2.y() - b[1] * segm_end2.x(); Chris@16: big_int_type ix = a[0] * c[1] + a[1] * c[0]; Chris@16: big_int_type iy = b[0] * c[1] + b[1] * c[0]; Chris@16: big_int_type dx = ix - orientation * site1.x(); Chris@16: big_int_type dy = iy - orientation * site1.y(); Chris@16: if (is_zero(dx) && is_zero(dy)) { Chris@16: fpt_type denom = to_fpt(orientation); Chris@16: fpt_type c_x = to_fpt(ix) / denom; Chris@16: fpt_type c_y = to_fpt(iy) / denom; Chris@16: c_event = circle_type(c_x, c_y, c_x); Chris@16: return; Chris@16: } Chris@16: Chris@16: big_int_type sign = ((point_index == 2) ? 1 : -1) * Chris@16: (is_neg(orientation) ? 1 : -1); Chris@16: cA[0] = a[1] * -dx + b[1] * -dy; Chris@16: cA[1] = a[0] * -dx + b[0] * -dy; Chris@16: cA[2] = sign; Chris@16: cA[3] = 0; Chris@16: cB[0] = a[0] * a[0] + b[0] * b[0]; Chris@16: cB[1] = a[1] * a[1] + b[1] * b[1]; Chris@16: cB[2] = a[0] * a[1] + b[0] * b[1]; Chris@16: cB[3] = (a[0] * dy - b[0] * dx) * (a[1] * dy - b[1] * dx) * -2; Chris@16: fpt_type temp = to_fpt( Chris@16: sqrt_expr_evaluator_pss4(cA, cB)); Chris@16: fpt_type denom = temp * to_fpt(orientation); Chris@16: Chris@16: if (recompute_c_y) { Chris@16: cA[0] = b[1] * (dx * dx + dy * dy) - iy * (dx * a[1] + dy * b[1]); Chris@16: cA[1] = b[0] * (dx * dx + dy * dy) - iy * (dx * a[0] + dy * b[0]); Chris@16: cA[2] = iy * sign; Chris@16: fpt_type cy = to_fpt( Chris@16: sqrt_expr_evaluator_pss4(cA, cB)); Chris@16: c_event.y(cy / denom); Chris@16: } Chris@16: Chris@16: if (recompute_c_x || recompute_lower_x) { Chris@16: cA[0] = a[1] * (dx * dx + dy * dy) - ix * (dx * a[1] + dy * b[1]); Chris@16: cA[1] = a[0] * (dx * dx + dy * dy) - ix * (dx * a[0] + dy * b[0]); Chris@16: cA[2] = ix * sign; Chris@16: Chris@16: if (recompute_c_x) { Chris@16: fpt_type cx = to_fpt( Chris@16: sqrt_expr_evaluator_pss4(cA, cB)); Chris@16: c_event.x(cx / denom); Chris@16: } Chris@16: Chris@16: if (recompute_lower_x) { Chris@16: cA[3] = orientation * (dx * dx + dy * dy) * (is_neg(temp) ? -1 : 1); Chris@16: fpt_type lower_x = to_fpt( Chris@16: sqrt_expr_evaluator_pss4(cA, cB)); Chris@16: c_event.lower_x(lower_x / denom); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // Recompute parameters of the circle event using high-precision library. Chris@16: void sss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: circle_type& c_event, Chris@16: bool recompute_c_x = true, Chris@16: bool recompute_c_y = true, Chris@16: bool recompute_lower_x = true) { Chris@16: big_int_type a[3], b[3], c[3], cA[4], cB[4]; Chris@16: // cA - corresponds to the cross product. Chris@16: // cB - corresponds to the squared length. Chris@16: a[0] = static_cast(site1.x1()) - Chris@16: static_cast(site1.x0()); Chris@16: a[1] = static_cast(site2.x1()) - Chris@16: static_cast(site2.x0()); Chris@16: a[2] = static_cast(site3.x1()) - Chris@16: static_cast(site3.x0()); Chris@16: Chris@16: b[0] = static_cast(site1.y1()) - Chris@16: static_cast(site1.y0()); Chris@16: b[1] = static_cast(site2.y1()) - Chris@16: static_cast(site2.y0()); Chris@16: b[2] = static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()); Chris@16: Chris@16: c[0] = static_cast(site1.x0()) * Chris@16: static_cast(site1.y1()) - Chris@16: static_cast(site1.y0()) * Chris@16: static_cast(site1.x1()); Chris@16: c[1] = static_cast(site2.x0()) * Chris@16: static_cast(site2.y1()) - Chris@16: static_cast(site2.y0()) * Chris@16: static_cast(site2.x1()); Chris@16: c[2] = static_cast(site3.x0()) * Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()) * Chris@16: static_cast(site3.x1()); Chris@16: Chris@16: for (int i = 0; i < 3; ++i) Chris@16: cB[i] = a[i] * a[i] + b[i] * b[i]; Chris@16: Chris@16: for (int i = 0; i < 3; ++i) { Chris@16: int j = (i+1) % 3; Chris@16: int k = (i+2) % 3; Chris@16: cA[i] = a[j] * b[k] - a[k] * b[j]; Chris@16: } Chris@16: fpt_type denom = to_fpt(sqrt_expr_.eval3(cA, cB)); Chris@16: Chris@16: if (recompute_c_y) { Chris@16: for (int i = 0; i < 3; ++i) { Chris@16: int j = (i+1) % 3; Chris@16: int k = (i+2) % 3; Chris@16: cA[i] = b[j] * c[k] - b[k] * c[j]; Chris@16: } Chris@16: fpt_type c_y = to_fpt(sqrt_expr_.eval3(cA, cB)); Chris@16: c_event.y(c_y / denom); Chris@16: } Chris@16: Chris@16: if (recompute_c_x || recompute_lower_x) { Chris@16: cA[3] = 0; Chris@16: for (int i = 0; i < 3; ++i) { Chris@16: int j = (i+1) % 3; Chris@16: int k = (i+2) % 3; Chris@16: cA[i] = a[j] * c[k] - a[k] * c[j]; Chris@16: if (recompute_lower_x) { Chris@16: cA[3] = cA[3] + cA[i] * b[i]; Chris@16: } Chris@16: } Chris@16: Chris@16: if (recompute_c_x) { Chris@16: fpt_type c_x = to_fpt(sqrt_expr_.eval3(cA, cB)); Chris@16: c_event.x(c_x / denom); Chris@16: } Chris@16: Chris@16: if (recompute_lower_x) { Chris@16: cB[3] = 1; Chris@16: fpt_type lower_x = to_fpt(sqrt_expr_.eval4(cA, cB)); Chris@16: c_event.lower_x(lower_x / denom); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: // Evaluates A[3] + A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + Chris@16: // A[2] * sqrt(B[3] * (sqrt(B[0] * B[1]) + B[2])). Chris@16: template Chris@16: _fpt sqrt_expr_evaluator_pss4(_int *A, _int *B) { Chris@16: _int cA[4], cB[4]; Chris@16: if (is_zero(A[3])) { Chris@16: _fpt lh = sqrt_expr_.eval2(A, B); Chris@16: cA[0] = 1; Chris@16: cB[0] = B[0] * B[1]; Chris@16: cA[1] = B[2]; Chris@16: cB[1] = 1; Chris@16: _fpt rh = sqrt_expr_.eval1(A+2, B+3) * Chris@16: get_sqrt(sqrt_expr_.eval2(cA, cB)); Chris@16: if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) Chris@16: return lh + rh; Chris@16: cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - Chris@16: A[2] * A[2] * B[3] * B[2]; Chris@16: cB[0] = 1; Chris@16: cA[1] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; Chris@16: cB[1] = B[0] * B[1]; Chris@16: _fpt numer = sqrt_expr_.eval2(cA, cB); Chris@16: return numer / (lh - rh); Chris@16: } Chris@16: cA[0] = 1; Chris@16: cB[0] = B[0] * B[1]; Chris@16: cA[1] = B[2]; Chris@16: cB[1] = 1; Chris@16: _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB)); Chris@16: cA[0] = A[0]; Chris@16: cB[0] = B[0]; Chris@16: cA[1] = A[1]; Chris@16: cB[1] = B[1]; Chris@16: cA[2] = A[3]; Chris@16: cB[2] = 1; Chris@16: _fpt lh = sqrt_expr_.eval3(cA, cB); Chris@16: if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) Chris@16: return lh + rh; Chris@16: cA[0] = A[3] * A[0] * 2; Chris@16: cA[1] = A[3] * A[1] * 2; Chris@16: cA[2] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] + Chris@16: A[3] * A[3] - A[2] * A[2] * B[2] * B[3]; Chris@16: cA[3] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; Chris@16: cB[3] = B[0] * B[1]; Chris@16: _fpt numer = sqrt_expr_evaluator_pss3<_int, _fpt>(cA, cB); Chris@16: return numer / (lh - rh); Chris@16: } Chris@16: Chris@16: template Chris@16: // Evaluates A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + Chris@16: // A[2] + A[3] * sqrt(B[0] * B[1]). Chris@16: // B[3] = B[0] * B[1]. Chris@16: _fpt sqrt_expr_evaluator_pss3(_int *A, _int *B) { Chris@16: _int cA[2], cB[2]; Chris@16: _fpt lh = sqrt_expr_.eval2(A, B); Chris@16: _fpt rh = sqrt_expr_.eval2(A+2, B+2); Chris@16: if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) Chris@16: return lh + rh; Chris@16: cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - Chris@16: A[2] * A[2] - A[3] * A[3] * B[0] * B[1]; Chris@16: cB[0] = 1; Chris@16: cA[1] = (A[0] * A[1] - A[2] * A[3]) * 2; Chris@16: cB[1] = B[3]; Chris@16: _fpt numer = sqrt_expr_.eval2(cA, cB); Chris@16: return numer / (lh - rh); Chris@16: } Chris@16: Chris@16: robust_sqrt_expr_type sqrt_expr_; Chris@16: to_fpt_converter to_fpt; Chris@16: }; Chris@16: Chris@16: template Chris@16: class lazy_circle_formation_functor { Chris@16: public: Chris@16: typedef robust_fpt robust_fpt_type; Chris@16: typedef robust_dif robust_dif_type; Chris@16: typedef typename Site::point_type point_type; Chris@16: typedef Site site_type; Chris@16: typedef Circle circle_type; Chris@16: typedef mp_circle_formation_functor Chris@16: exact_circle_formation_functor_type; Chris@16: Chris@16: void ppp(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: circle_type& c_event) { Chris@16: fpt_type dif_x1 = to_fpt(site1.x()) - to_fpt(site2.x()); Chris@16: fpt_type dif_x2 = to_fpt(site2.x()) - to_fpt(site3.x()); Chris@16: fpt_type dif_y1 = to_fpt(site1.y()) - to_fpt(site2.y()); Chris@16: fpt_type dif_y2 = to_fpt(site2.y()) - to_fpt(site3.y()); Chris@16: fpt_type orientation = robust_cross_product( Chris@16: static_cast(site1.x()) - Chris@16: static_cast(site2.x()), Chris@16: static_cast(site2.x()) - Chris@16: static_cast(site3.x()), Chris@16: static_cast(site1.y()) - Chris@16: static_cast(site2.y()), Chris@16: static_cast(site2.y()) - Chris@16: static_cast(site3.y())); Chris@16: robust_fpt_type inv_orientation(to_fpt(0.5) / orientation, to_fpt(2.0)); Chris@16: fpt_type sum_x1 = to_fpt(site1.x()) + to_fpt(site2.x()); Chris@16: fpt_type sum_x2 = to_fpt(site2.x()) + to_fpt(site3.x()); Chris@16: fpt_type sum_y1 = to_fpt(site1.y()) + to_fpt(site2.y()); Chris@16: fpt_type sum_y2 = to_fpt(site2.y()) + to_fpt(site3.y()); Chris@16: fpt_type dif_x3 = to_fpt(site1.x()) - to_fpt(site3.x()); Chris@16: fpt_type dif_y3 = to_fpt(site1.y()) - to_fpt(site3.y()); Chris@16: robust_dif_type c_x, c_y; Chris@16: c_x += robust_fpt_type(dif_x1 * sum_x1 * dif_y2, to_fpt(2.0)); Chris@16: c_x += robust_fpt_type(dif_y1 * sum_y1 * dif_y2, to_fpt(2.0)); Chris@16: c_x -= robust_fpt_type(dif_x2 * sum_x2 * dif_y1, to_fpt(2.0)); Chris@16: c_x -= robust_fpt_type(dif_y2 * sum_y2 * dif_y1, to_fpt(2.0)); Chris@16: c_y += robust_fpt_type(dif_x2 * sum_x2 * dif_x1, to_fpt(2.0)); Chris@16: c_y += robust_fpt_type(dif_y2 * sum_y2 * dif_x1, to_fpt(2.0)); Chris@16: c_y -= robust_fpt_type(dif_x1 * sum_x1 * dif_x2, to_fpt(2.0)); Chris@16: c_y -= robust_fpt_type(dif_y1 * sum_y1 * dif_x2, to_fpt(2.0)); Chris@16: robust_dif_type lower_x(c_x); Chris@16: lower_x -= robust_fpt_type(get_sqrt( Chris@16: (dif_x1 * dif_x1 + dif_y1 * dif_y1) * Chris@16: (dif_x2 * dif_x2 + dif_y2 * dif_y2) * Chris@16: (dif_x3 * dif_x3 + dif_y3 * dif_y3)), to_fpt(5.0)); Chris@16: c_event = circle_type( Chris@16: c_x.dif().fpv() * inv_orientation.fpv(), Chris@16: c_y.dif().fpv() * inv_orientation.fpv(), Chris@16: lower_x.dif().fpv() * inv_orientation.fpv()); Chris@16: bool recompute_c_x = c_x.dif().ulp() > ULPS; Chris@16: bool recompute_c_y = c_y.dif().ulp() > ULPS; Chris@16: bool recompute_lower_x = lower_x.dif().ulp() > ULPS; Chris@16: if (recompute_c_x || recompute_c_y || recompute_lower_x) { Chris@16: exact_circle_formation_functor_.ppp( Chris@16: site1, site2, site3, c_event, Chris@16: recompute_c_x, recompute_c_y, recompute_lower_x); Chris@16: } Chris@16: } Chris@16: Chris@16: void pps(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int segment_index, Chris@16: circle_type& c_event) { Chris@16: fpt_type line_a = to_fpt(site3.y1()) - to_fpt(site3.y0()); Chris@16: fpt_type line_b = to_fpt(site3.x0()) - to_fpt(site3.x1()); Chris@16: fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y()); Chris@16: fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x()); Chris@16: robust_fpt_type teta(robust_cross_product( Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()), Chris@16: static_cast(site3.x0()) - Chris@16: static_cast(site3.x1()), Chris@16: static_cast(site2.x()) - Chris@16: static_cast(site1.x()), Chris@16: static_cast(site2.y()) - Chris@16: static_cast(site1.y())), to_fpt(1.0)); Chris@16: robust_fpt_type A(robust_cross_product( Chris@16: static_cast(site3.y0()) - Chris@16: static_cast(site3.y1()), Chris@16: static_cast(site3.x0()) - Chris@16: static_cast(site3.x1()), Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site1.y()), Chris@16: static_cast(site3.x1()) - Chris@16: static_cast(site1.x())), to_fpt(1.0)); Chris@16: robust_fpt_type B(robust_cross_product( Chris@16: static_cast(site3.y0()) - Chris@16: static_cast(site3.y1()), Chris@16: static_cast(site3.x0()) - Chris@16: static_cast(site3.x1()), Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site2.y()), Chris@16: static_cast(site3.x1()) - Chris@16: static_cast(site2.x())), to_fpt(1.0)); Chris@16: robust_fpt_type denom(robust_cross_product( Chris@16: static_cast(site1.y()) - Chris@16: static_cast(site2.y()), Chris@16: static_cast(site1.x()) - Chris@16: static_cast(site2.x()), Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()), Chris@16: static_cast(site3.x1()) - Chris@16: static_cast(site3.x0())), to_fpt(1.0)); Chris@16: robust_fpt_type inv_segm_len(to_fpt(1.0) / Chris@16: get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0)); Chris@16: robust_dif_type t; Chris@16: if (ot::eval(denom) == ot::COLLINEAR) { Chris@16: t += teta / (robust_fpt_type(to_fpt(8.0)) * A); Chris@16: t -= A / (robust_fpt_type(to_fpt(2.0)) * teta); Chris@16: } else { Chris@16: robust_fpt_type det = ((teta * teta + denom * denom) * A * B).sqrt(); Chris@16: if (segment_index == 2) { Chris@16: t -= det / (denom * denom); Chris@16: } else { Chris@16: t += det / (denom * denom); Chris@16: } Chris@16: t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom); Chris@16: } Chris@16: robust_dif_type c_x, c_y; Chris@16: c_x += robust_fpt_type(to_fpt(0.5) * Chris@16: (to_fpt(site1.x()) + to_fpt(site2.x()))); Chris@16: c_x += robust_fpt_type(vec_x) * t; Chris@16: c_y += robust_fpt_type(to_fpt(0.5) * Chris@16: (to_fpt(site1.y()) + to_fpt(site2.y()))); Chris@16: c_y += robust_fpt_type(vec_y) * t; Chris@16: robust_dif_type r, lower_x(c_x); Chris@16: r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0()); Chris@16: r -= robust_fpt_type(line_b) * robust_fpt_type(site3.y0()); Chris@16: r += robust_fpt_type(line_a) * c_x; Chris@16: r += robust_fpt_type(line_b) * c_y; Chris@16: if (r.pos().fpv() < r.neg().fpv()) Chris@16: r = -r; Chris@16: lower_x += r * inv_segm_len; Chris@16: c_event = circle_type( Chris@16: c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); Chris@16: bool recompute_c_x = c_x.dif().ulp() > ULPS; Chris@16: bool recompute_c_y = c_y.dif().ulp() > ULPS; Chris@16: bool recompute_lower_x = lower_x.dif().ulp() > ULPS; Chris@16: if (recompute_c_x || recompute_c_y || recompute_lower_x) { Chris@16: exact_circle_formation_functor_.pps( Chris@16: site1, site2, site3, segment_index, c_event, Chris@16: recompute_c_x, recompute_c_y, recompute_lower_x); Chris@16: } Chris@16: } Chris@16: Chris@16: void pss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: int point_index, Chris@16: circle_type& c_event) { Chris@16: const point_type& segm_start1 = site2.point1(); Chris@16: const point_type& segm_end1 = site2.point0(); Chris@16: const point_type& segm_start2 = site3.point0(); Chris@16: const point_type& segm_end2 = site3.point1(); Chris@16: fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x()); Chris@16: fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y()); Chris@16: fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x()); Chris@16: fpt_type b2 = to_fpt(segm_end2.y()) - to_fpt(segm_start2.y()); Chris@16: bool recompute_c_x, recompute_c_y, recompute_lower_x; Chris@16: robust_fpt_type orientation(robust_cross_product( Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end2.y()) - Chris@16: static_cast(segm_start2.y()), Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x())), to_fpt(1.0)); Chris@16: if (ot::eval(orientation) == ot::COLLINEAR) { Chris@16: robust_fpt_type a(a1 * a1 + b1 * b1, to_fpt(2.0)); Chris@16: robust_fpt_type c(robust_cross_product( Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_start2.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_start2.x()) - Chris@16: static_cast(segm_start1.x())), to_fpt(1.0)); Chris@16: robust_fpt_type det( Chris@16: robust_cross_product( Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(site1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(site1.y()) - Chris@16: static_cast(segm_start1.y())) * Chris@16: robust_cross_product( Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(site1.y()) - Chris@16: static_cast(segm_start2.y()), Chris@16: static_cast(site1.x()) - Chris@16: static_cast(segm_start2.x())), Chris@16: to_fpt(3.0)); Chris@16: robust_dif_type t; Chris@16: t -= robust_fpt_type(a1) * robust_fpt_type(( Chris@16: to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())) * to_fpt(0.5) - Chris@16: to_fpt(site1.x())); Chris@16: t -= robust_fpt_type(b1) * robust_fpt_type(( Chris@16: to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())) * to_fpt(0.5) - Chris@16: to_fpt(site1.y())); Chris@16: if (point_index == 2) { Chris@16: t += det.sqrt(); Chris@16: } else { Chris@16: t -= det.sqrt(); Chris@16: } Chris@16: t /= a; Chris@16: robust_dif_type c_x, c_y; Chris@16: c_x += robust_fpt_type(to_fpt(0.5) * ( Chris@16: to_fpt(segm_start1.x()) + to_fpt(segm_start2.x()))); Chris@16: c_x += robust_fpt_type(a1) * t; Chris@16: c_y += robust_fpt_type(to_fpt(0.5) * ( Chris@16: to_fpt(segm_start1.y()) + to_fpt(segm_start2.y()))); Chris@16: c_y += robust_fpt_type(b1) * t; Chris@16: robust_dif_type lower_x(c_x); Chris@16: if (is_neg(c)) { Chris@16: lower_x -= robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); Chris@16: } else { Chris@16: lower_x += robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); Chris@16: } Chris@16: recompute_c_x = c_x.dif().ulp() > ULPS; Chris@16: recompute_c_y = c_y.dif().ulp() > ULPS; Chris@16: recompute_lower_x = lower_x.dif().ulp() > ULPS; Chris@16: c_event = Chris@16: circle_type(c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); Chris@16: } else { Chris@16: robust_fpt_type sqr_sum1(get_sqrt(a1 * a1 + b1 * b1), to_fpt(2.0)); Chris@16: robust_fpt_type sqr_sum2(get_sqrt(a2 * a2 + b2 * b2), to_fpt(2.0)); Chris@16: robust_fpt_type a(robust_cross_product( Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_start2.y()) - Chris@16: static_cast(segm_end2.y()), Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x())), to_fpt(1.0)); Chris@16: if (!is_neg(a)) { Chris@16: a += sqr_sum1 * sqr_sum2; Chris@16: } else { Chris@16: a = (orientation * orientation) / (sqr_sum1 * sqr_sum2 - a); Chris@16: } Chris@16: robust_fpt_type or1(robust_cross_product( Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(site1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(site1.x())), to_fpt(1.0)); Chris@16: robust_fpt_type or2(robust_cross_product( Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x()), Chris@16: static_cast(segm_end2.y()) - Chris@16: static_cast(segm_start2.y()), Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(site1.x()), Chris@16: static_cast(segm_end2.y()) - Chris@16: static_cast(site1.y())), to_fpt(1.0)); Chris@16: robust_fpt_type det = robust_fpt_type(to_fpt(2.0)) * a * or1 * or2; Chris@16: robust_fpt_type c1(robust_cross_product( Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end1.y()), Chris@16: static_cast(segm_end1.x())), to_fpt(1.0)); Chris@16: robust_fpt_type c2(robust_cross_product( Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x()), Chris@16: static_cast(segm_end2.y()) - Chris@16: static_cast(segm_start2.y()), Chris@16: static_cast(segm_end2.x()), Chris@16: static_cast(segm_end2.y())), to_fpt(1.0)); Chris@16: robust_fpt_type inv_orientation = Chris@16: robust_fpt_type(to_fpt(1.0)) / orientation; Chris@16: robust_dif_type t, b, ix, iy; Chris@16: ix += robust_fpt_type(a2) * c1 * inv_orientation; Chris@16: ix += robust_fpt_type(a1) * c2 * inv_orientation; Chris@16: iy += robust_fpt_type(b1) * c2 * inv_orientation; Chris@16: iy += robust_fpt_type(b2) * c1 * inv_orientation; Chris@16: Chris@16: b += ix * (robust_fpt_type(a1) * sqr_sum2); Chris@16: b += ix * (robust_fpt_type(a2) * sqr_sum1); Chris@16: b += iy * (robust_fpt_type(b1) * sqr_sum2); Chris@16: b += iy * (robust_fpt_type(b2) * sqr_sum1); Chris@16: b -= sqr_sum1 * robust_fpt_type(robust_cross_product( Chris@16: static_cast(segm_end2.x()) - Chris@16: static_cast(segm_start2.x()), Chris@16: static_cast(segm_end2.y()) - Chris@16: static_cast(segm_start2.y()), Chris@16: static_cast(-site1.y()), Chris@16: static_cast(site1.x())), to_fpt(1.0)); Chris@16: b -= sqr_sum2 * robust_fpt_type(robust_cross_product( Chris@16: static_cast(segm_end1.x()) - Chris@16: static_cast(segm_start1.x()), Chris@16: static_cast(segm_end1.y()) - Chris@16: static_cast(segm_start1.y()), Chris@16: static_cast(-site1.y()), Chris@16: static_cast(site1.x())), to_fpt(1.0)); Chris@16: t -= b; Chris@16: if (point_index == 2) { Chris@16: t += det.sqrt(); Chris@16: } else { Chris@16: t -= det.sqrt(); Chris@16: } Chris@16: t /= (a * a); Chris@16: robust_dif_type c_x(ix), c_y(iy); Chris@16: c_x += t * (robust_fpt_type(a1) * sqr_sum2); Chris@16: c_x += t * (robust_fpt_type(a2) * sqr_sum1); Chris@16: c_y += t * (robust_fpt_type(b1) * sqr_sum2); Chris@16: c_y += t * (robust_fpt_type(b2) * sqr_sum1); Chris@16: if (t.pos().fpv() < t.neg().fpv()) { Chris@16: t = -t; Chris@16: } Chris@16: robust_dif_type lower_x(c_x); Chris@16: if (is_neg(orientation)) { Chris@16: lower_x -= t * orientation; Chris@16: } else { Chris@16: lower_x += t * orientation; Chris@16: } Chris@16: recompute_c_x = c_x.dif().ulp() > ULPS; Chris@16: recompute_c_y = c_y.dif().ulp() > ULPS; Chris@16: recompute_lower_x = lower_x.dif().ulp() > ULPS; Chris@16: c_event = circle_type( Chris@16: c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); Chris@16: } Chris@16: if (recompute_c_x || recompute_c_y || recompute_lower_x) { Chris@16: exact_circle_formation_functor_.pss( Chris@16: site1, site2, site3, point_index, c_event, Chris@16: recompute_c_x, recompute_c_y, recompute_lower_x); Chris@16: } Chris@16: } Chris@16: Chris@16: void sss(const site_type& site1, Chris@16: const site_type& site2, Chris@16: const site_type& site3, Chris@16: circle_type& c_event) { Chris@16: robust_fpt_type a1(to_fpt(site1.x1()) - to_fpt(site1.x0())); Chris@16: robust_fpt_type b1(to_fpt(site1.y1()) - to_fpt(site1.y0())); Chris@16: robust_fpt_type c1(robust_cross_product( Chris@16: site1.x0(), site1.y0(), Chris@16: site1.x1(), site1.y1()), to_fpt(1.0)); Chris@16: Chris@16: robust_fpt_type a2(to_fpt(site2.x1()) - to_fpt(site2.x0())); Chris@16: robust_fpt_type b2(to_fpt(site2.y1()) - to_fpt(site2.y0())); Chris@16: robust_fpt_type c2(robust_cross_product( Chris@16: site2.x0(), site2.y0(), Chris@16: site2.x1(), site2.y1()), to_fpt(1.0)); Chris@16: Chris@16: robust_fpt_type a3(to_fpt(site3.x1()) - to_fpt(site3.x0())); Chris@16: robust_fpt_type b3(to_fpt(site3.y1()) - to_fpt(site3.y0())); Chris@16: robust_fpt_type c3(robust_cross_product( Chris@16: site3.x0(), site3.y0(), Chris@16: site3.x1(), site3.y1()), to_fpt(1.0)); Chris@16: Chris@16: robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt(); Chris@16: robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt(); Chris@16: robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt(); Chris@16: robust_fpt_type cross_12(robust_cross_product( Chris@16: static_cast(site1.x1()) - Chris@16: static_cast(site1.x0()), Chris@16: static_cast(site1.y1()) - Chris@16: static_cast(site1.y0()), Chris@16: static_cast(site2.x1()) - Chris@16: static_cast(site2.x0()), Chris@16: static_cast(site2.y1()) - Chris@16: static_cast(site2.y0())), to_fpt(1.0)); Chris@16: robust_fpt_type cross_23(robust_cross_product( Chris@16: static_cast(site2.x1()) - Chris@16: static_cast(site2.x0()), Chris@16: static_cast(site2.y1()) - Chris@16: static_cast(site2.y0()), Chris@16: static_cast(site3.x1()) - Chris@16: static_cast(site3.x0()), Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site3.y0())), to_fpt(1.0)); Chris@16: robust_fpt_type cross_31(robust_cross_product( Chris@16: static_cast(site3.x1()) - Chris@16: static_cast(site3.x0()), Chris@16: static_cast(site3.y1()) - Chris@16: static_cast(site3.y0()), Chris@16: static_cast(site1.x1()) - Chris@16: static_cast(site1.x0()), Chris@16: static_cast(site1.y1()) - Chris@16: static_cast(site1.y0())), to_fpt(1.0)); Chris@16: Chris@16: // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2. Chris@16: robust_dif_type denom; Chris@16: denom += cross_12 * len3; Chris@16: denom += cross_23 * len1; Chris@16: denom += cross_31 * len2; Chris@16: Chris@16: // denom * r = (b2 * c_x - a2 * c_y - c2 * denom) / len2. Chris@16: robust_dif_type r; Chris@16: r -= cross_12 * c3; Chris@16: r -= cross_23 * c1; Chris@16: r -= cross_31 * c2; Chris@16: Chris@16: robust_dif_type c_x; Chris@16: c_x += a1 * c2 * len3; Chris@16: c_x -= a2 * c1 * len3; Chris@16: c_x += a2 * c3 * len1; Chris@16: c_x -= a3 * c2 * len1; Chris@16: c_x += a3 * c1 * len2; Chris@16: c_x -= a1 * c3 * len2; Chris@16: Chris@16: robust_dif_type c_y; Chris@16: c_y += b1 * c2 * len3; Chris@16: c_y -= b2 * c1 * len3; Chris@16: c_y += b2 * c3 * len1; Chris@16: c_y -= b3 * c2 * len1; Chris@16: c_y += b3 * c1 * len2; Chris@16: c_y -= b1 * c3 * len2; Chris@16: Chris@16: robust_dif_type lower_x = c_x + r; Chris@16: Chris@16: robust_fpt_type denom_dif = denom.dif(); Chris@16: robust_fpt_type c_x_dif = c_x.dif() / denom_dif; Chris@16: robust_fpt_type c_y_dif = c_y.dif() / denom_dif; Chris@16: robust_fpt_type lower_x_dif = lower_x.dif() / denom_dif; Chris@16: Chris@16: bool recompute_c_x = c_x_dif.ulp() > ULPS; Chris@16: bool recompute_c_y = c_y_dif.ulp() > ULPS; Chris@16: bool recompute_lower_x = lower_x_dif.ulp() > ULPS; Chris@16: c_event = circle_type(c_x_dif.fpv(), c_y_dif.fpv(), lower_x_dif.fpv()); Chris@16: if (recompute_c_x || recompute_c_y || recompute_lower_x) { Chris@16: exact_circle_formation_functor_.sss( Chris@16: site1, site2, site3, c_event, Chris@16: recompute_c_x, recompute_c_y, recompute_lower_x); Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: exact_circle_formation_functor_type exact_circle_formation_functor_; Chris@16: to_fpt_converter to_fpt; Chris@16: }; Chris@16: Chris@16: template , Chris@16: typename CFF = lazy_circle_formation_functor > Chris@16: class circle_formation_predicate { Chris@16: public: Chris@16: typedef Site site_type; Chris@16: typedef Circle circle_type; Chris@16: typedef CEP circle_existence_predicate_type; Chris@16: typedef CFF circle_formation_functor_type; Chris@16: Chris@16: // Create a circle event from the given three sites. Chris@16: // Returns true if the circle event exists, else false. Chris@16: // If exists circle event is saved into the c_event variable. Chris@16: bool operator()(const site_type& site1, const site_type& site2, Chris@16: const site_type& site3, circle_type& circle) { Chris@16: if (!site1.is_segment()) { Chris@16: if (!site2.is_segment()) { Chris@16: if (!site3.is_segment()) { Chris@16: // (point, point, point) sites. Chris@16: if (!circle_existence_predicate_.ppp(site1, site2, site3)) Chris@16: return false; Chris@16: circle_formation_functor_.ppp(site1, site2, site3, circle); Chris@16: } else { Chris@16: // (point, point, segment) sites. Chris@16: if (!circle_existence_predicate_.pps(site1, site2, site3, 3)) Chris@16: return false; Chris@16: circle_formation_functor_.pps(site1, site2, site3, 3, circle); Chris@16: } Chris@16: } else { Chris@16: if (!site3.is_segment()) { Chris@16: // (point, segment, point) sites. Chris@16: if (!circle_existence_predicate_.pps(site1, site3, site2, 2)) Chris@16: return false; Chris@16: circle_formation_functor_.pps(site1, site3, site2, 2, circle); Chris@16: } else { Chris@16: // (point, segment, segment) sites. Chris@16: if (!circle_existence_predicate_.pss(site1, site2, site3, 1)) Chris@16: return false; Chris@16: circle_formation_functor_.pss(site1, site2, site3, 1, circle); Chris@16: } Chris@16: } Chris@16: } else { Chris@16: if (!site2.is_segment()) { Chris@16: if (!site3.is_segment()) { Chris@16: // (segment, point, point) sites. Chris@16: if (!circle_existence_predicate_.pps(site2, site3, site1, 1)) Chris@16: return false; Chris@16: circle_formation_functor_.pps(site2, site3, site1, 1, circle); Chris@16: } else { Chris@16: // (segment, point, segment) sites. Chris@16: if (!circle_existence_predicate_.pss(site2, site1, site3, 2)) Chris@16: return false; Chris@16: circle_formation_functor_.pss(site2, site1, site3, 2, circle); Chris@16: } Chris@16: } else { Chris@16: if (!site3.is_segment()) { Chris@16: // (segment, segment, point) sites. Chris@16: if (!circle_existence_predicate_.pss(site3, site1, site2, 3)) Chris@16: return false; Chris@16: circle_formation_functor_.pss(site3, site1, site2, 3, circle); Chris@16: } else { Chris@16: // (segment, segment, segment) sites. Chris@16: if (!circle_existence_predicate_.sss(site1, site2, site3)) Chris@16: return false; Chris@16: circle_formation_functor_.sss(site1, site2, site3, circle); Chris@16: } Chris@16: } Chris@16: } Chris@16: if (lies_outside_vertical_segment(circle, site1) || Chris@16: lies_outside_vertical_segment(circle, site2) || Chris@16: lies_outside_vertical_segment(circle, site3)) { Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: private: Chris@16: bool lies_outside_vertical_segment( Chris@16: const circle_type& c, const site_type& s) { Chris@16: if (!s.is_segment() || !is_vertical(s)) { Chris@16: return false; Chris@16: } Chris@16: fpt_type y0 = to_fpt(s.is_inverse() ? s.y1() : s.y0()); Chris@16: fpt_type y1 = to_fpt(s.is_inverse() ? s.y0() : s.y1()); Chris@16: return ulp_cmp(c.y(), y0, ULPS) == ulp_cmp_type::LESS || Chris@16: ulp_cmp(c.y(), y1, ULPS) == ulp_cmp_type::MORE; Chris@16: } Chris@16: Chris@16: private: Chris@16: to_fpt_converter to_fpt; Chris@16: ulp_cmp_type ulp_cmp; Chris@16: circle_existence_predicate_type circle_existence_predicate_; Chris@16: circle_formation_functor_type circle_formation_functor_; Chris@16: }; Chris@16: }; Chris@16: } // detail Chris@16: } // polygon Chris@16: } // boost Chris@16: Chris@16: #endif // BOOST_POLYGON_DETAIL_VORONOI_PREDICATES