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
|