Skip to content

Commit 4e8ff81

Browse files
committed
[sort_by_side] add epsilon to approximately_equals
1 parent 324249b commit 4e8ff81

2 files changed

Lines changed: 24 additions & 6 deletions

File tree

include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
2626

2727
#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>
2831

2932
namespace boost { namespace geometry
3033
{
@@ -287,14 +290,29 @@ public :
287290
add_segment_to(turn_index, op_index, point_to, op);
288291
}
289292

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)
290295
template <typename Point1, typename Point2, typename T>
291296
static inline bool approximately_equals(Point1 const& a, Point2 const& b,
292-
T const& limit)
297+
T const& limit_giga_epsilon)
293298
{
294299
// 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;
298316
}
299317

300318
template <typename Operation, typename Geometry1, typename Geometry2>
@@ -324,7 +342,7 @@ public :
324342
// then take a point (or more) further back.
325343
// The limit of offset avoids theoretical infinite loops. In practice it currently
326344
// 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)
328346
{
329347
point1 = walk_back(op, --offset, geometry1, geometry2);
330348
}

test/algorithms/set_operations/union/union_multi.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ int test_main(int, char* [])
489489
#endif
490490

491491
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
492-
BoostGeometryWriteExpectedFailures(9, 0, 1, 0);
492+
BoostGeometryWriteExpectedFailures(9, 0, 3, 0);
493493
#endif
494494

495495
return 0;

0 commit comments

Comments
 (0)