|
25 | 25 | #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> |
26 | 26 |
|
27 | 27 | #include <boost/geometry/util/condition.hpp> |
| 28 | +#include <boost/geometry/util/math.hpp> |
| 29 | +#include <boost/geometry/util/select_coordinate_type.hpp> |
| 30 | +#include <boost/geometry/util/select_most_precise.hpp> |
28 | 31 |
|
29 | 32 | namespace boost { namespace geometry |
30 | 33 | { |
@@ -287,14 +290,29 @@ public : |
287 | 290 | add_segment_to(turn_index, op_index, point_to, op); |
288 | 291 | } |
289 | 292 |
|
| 293 | + // Returns true if two points are approximately equal, tuned by a giga-epsilon constant |
| 294 | + // (if constant is 1.0, for type double, the boundary is about 1.0e-7) |
290 | 295 | template <typename Point1, typename Point2, typename T> |
291 | 296 | static inline bool approximately_equals(Point1 const& a, Point2 const& b, |
292 | | - T const& limit) |
| 297 | + T const& limit_giga_epsilon) |
293 | 298 | { |
294 | 299 | // Including distance would introduce cyclic dependencies. |
295 | | - // This simple code works and is efficient for all coordinate systems. |
296 | | - return std::abs(geometry::get<0>(a) - geometry::get<0>(b)) <= limit |
297 | | - && std::abs(geometry::get<1>(a) - geometry::get<1>(b)) <= limit; |
| 300 | + using coor_t = typename select_coordinate_type<Point1, Point2>::type; |
| 301 | + using calc_t = typename geometry::select_most_precise <coor_t, T>::type; |
| 302 | + constexpr calc_t machine_giga_epsilon = 1.0e9 * std::numeric_limits<calc_t>::epsilon(); |
| 303 | + |
| 304 | + calc_t const& a0 = geometry::get<0>(a); |
| 305 | + calc_t const& b0 = geometry::get<0>(b); |
| 306 | + calc_t const& a1 = geometry::get<1>(a); |
| 307 | + calc_t const& b1 = geometry::get<1>(b); |
| 308 | + calc_t const one = 1.0; |
| 309 | + calc_t const c = math::detail::greatest(a0, b0, a1, b1, one); |
| 310 | + |
| 311 | + // The maximum limit is avoid, for floating point, large limits like 400 |
| 312 | + // (which are be calculated using eps) |
| 313 | + constexpr calc_t maxlimit = 1.0e-3; |
| 314 | + auto const limit = (std::min)(maxlimit, limit_giga_epsilon * machine_giga_epsilon * c); |
| 315 | + return std::abs(a0 - b0) <= limit && std::abs(a1 - b1) <= limit; |
298 | 316 | } |
299 | 317 |
|
300 | 318 | template <typename Operation, typename Geometry1, typename Geometry2> |
@@ -324,7 +342,7 @@ public : |
324 | 342 | // then take a point (or more) further back. |
325 | 343 | // The limit of offset avoids theoretical infinite loops. In practice it currently |
326 | 344 | // walks max 1 point back in all cases. |
327 | | - while (approximately_equals(point1, turn.point, 1.0e-6) && offset > -10) |
| 345 | + while (approximately_equals(point1, turn.point, 1.0) && offset > -10) |
328 | 346 | { |
329 | 347 | point1 = walk_back(op, --offset, geometry1, geometry2); |
330 | 348 | } |
|
0 commit comments