|
| 1 | +// Boost.Geometry |
| 2 | +// Unit Test |
| 3 | + |
| 4 | +// Copyright (c) 2023 Barend Gehrels, Amsterdam, the Netherlands. |
| 5 | + |
| 6 | +// Use, modification and distribution is subject to the Boost Software License, |
| 7 | +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| 8 | +// http://www.boost.org/LICENSE_1_0.txt) |
| 9 | + |
| 10 | +#include <geometry_test_common.hpp> |
| 11 | + |
| 12 | +#include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp> |
| 13 | +#include <boost/geometry/strategy/cartesian/side_robust.hpp> |
| 14 | +#include <boost/geometry/strategies/strategies.hpp> |
| 15 | +#include <boost/geometry/geometries/geometries.hpp> |
| 16 | +#include <boost/geometry/io/wkt/wkt.hpp> |
| 17 | + |
| 18 | +// #define BOOST_GEOMETRY_TEST_WITH_COUT |
| 19 | +// #define BOOST_GEOMETRY_TEST_FAILURES |
| 20 | + |
| 21 | +template <typename Point> |
| 22 | +void do_test(std::string const& case_id, |
| 23 | + Point const& s1, |
| 24 | + Point const& s2, |
| 25 | + Point const& p, |
| 26 | + int expected_side, |
| 27 | + bool ignore_failure = false) |
| 28 | +{ |
| 29 | + using coor_t = typename bg::coordinate_type<Point>::type; |
| 30 | + typename bg::strategies::relate::services::default_strategy |
| 31 | + < |
| 32 | + Point, Point |
| 33 | + >::type strategy; |
| 34 | + |
| 35 | + auto const dm = bg::detail::get_distance_measure(s1, s2, p, strategy); |
| 36 | + auto const dm_side = dm.measure < 0.0 ? -1 : dm.measure > 0.0 ? 1 : 0; |
| 37 | + auto const tr_side = strategy.side().apply(s1, s2, p); |
| 38 | + auto const rob_side = bg::strategy::side::side_robust<coor_t>::apply(s1, s2, p); |
| 39 | + |
| 40 | + #if defined(BOOST_GEOMETRY_TEST_WITH_COUT) |
| 41 | + std::cout << " " << case_id << " " << string_from_type<coor_t>::name() |
| 42 | + << std::setprecision(20) |
| 43 | + << " " << dm.measure << " " << dm_side << " " << tr_side << " " << rob_side |
| 44 | + << (dm_side != rob_side ? " [*** DM WRONG]" : "") |
| 45 | + << (tr_side != rob_side ? " [*** TR WRONG]" : "") |
| 46 | + << std::endl; |
| 47 | + #endif |
| 48 | + |
| 49 | + BOOST_CHECK_MESSAGE(expected_side == -9 || expected_side == dm_side, |
| 50 | + "Case: " << case_id |
| 51 | + << " ctype: " << string_from_type<coor_t>::name() |
| 52 | + << " expected: " << expected_side |
| 53 | + << " detected: " << dm_side); |
| 54 | + |
| 55 | + // This is often wrong for float, and sometimes for double |
| 56 | + BOOST_CHECK_MESSAGE(ignore_failure || tr_side == dm_side, |
| 57 | + "Case: " << case_id |
| 58 | + << " ctype: " << string_from_type<coor_t>::name() |
| 59 | + << " tr_side: " << tr_side |
| 60 | + << " dm_side: " << dm_side); |
| 61 | + |
| 62 | + // This is always guaranteed for the tested values |
| 63 | + BOOST_CHECK_MESSAGE(tr_side == rob_side, |
| 64 | + "Case: " << case_id |
| 65 | + << " ctype: " << string_from_type<coor_t>::name() |
| 66 | + << " tr_side: " << tr_side |
| 67 | + << " rob_side: " << rob_side); |
| 68 | +} |
| 69 | + |
| 70 | +template <typename Point> |
| 71 | +void test_get_distance_measure() |
| 72 | +{ |
| 73 | + using coor_t = typename bg::coordinate_type<Point>::type; |
| 74 | + |
| 75 | + do_test<Point>("simplex_coll", {1.0, 0.0}, {1.0, 1.0}, {1.0, 0.5}, 0); |
| 76 | + do_test<Point>("simplex_left", {1.0, 0.0}, {1.0, 1.0}, {0.9, 0.5}, 1); |
| 77 | + do_test<Point>("simplex_right", {1.0, 0.0}, {1.0, 1.0}, {1.1, 0.5}, -1); |
| 78 | + |
| 79 | + bool const is_float = std::is_same<coor_t, float>::value; |
| 80 | + bool const is_double = std::is_same<coor_t, double>::value; |
| 81 | + |
| 82 | + // The issue 1183 where get_distance_measure failed for these coordinates. |
| 83 | + std::string const case_id = "issue_1183_"; |
| 84 | + Point const p1{38902.349206128216, 6721371.1493254723}; |
| 85 | + Point const p2{38937.993505971914, 6721407.9151819283}; |
| 86 | + Point const q1 = p1; |
| 87 | + Point const q2{38960.647313876834, 6721431.2817974398}; |
| 88 | + { |
| 89 | + do_test<Point>(case_id + "p", p1, p2, q2, 1, is_float); |
| 90 | + do_test<Point>(case_id + "q", q1, q2, p1, 0); |
| 91 | + } |
| 92 | + |
| 93 | + double const test_epsilon = 1.0e-9; |
| 94 | + |
| 95 | + // Walk along x axis to get the switch from left to right (between 2 and 3) |
| 96 | + for (int i = -5; i <= 15; i++) |
| 97 | + { |
| 98 | +#if defined(BOOST_GEOMETRY_TEST_FAILURES) |
| 99 | + bool const ignore_failure = false; |
| 100 | +#else |
| 101 | + bool const ignore_failure = is_float || (is_double && i >= 3 && i <= 12); |
| 102 | +#endif |
| 103 | + double const v = i / 10.0; |
| 104 | + Point q2a = q2; |
| 105 | + bg::set<0>(q2a, bg::get<0>(q2) + v * test_epsilon); |
| 106 | + do_test<Point>(case_id + std::to_string(i), p1, p2, q2a, -9, ignore_failure); |
| 107 | + } |
| 108 | + // Focus on the switch from left to right (between 0.251 and 0.252) |
| 109 | + for (int i = 250; i <= 260; i++) |
| 110 | + { |
| 111 | + double const v = i / 1000.0; |
| 112 | + Point q2a = q2; |
| 113 | + bg::set<0>(q2a, bg::get<0>(q2) + v * test_epsilon); |
| 114 | + do_test<Point>(case_id + std::to_string(i), p1, p2, q2, -9, is_float || is_double); |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +int test_main(int, char* []) |
| 119 | +{ |
| 120 | + using fp = bg::model::point<float, 2, bg::cs::cartesian>; |
| 121 | + using dp = bg::model::point<double, 2, bg::cs::cartesian>; |
| 122 | + using ep = bg::model::point<long double, 2, bg::cs::cartesian>; |
| 123 | + |
| 124 | + test_get_distance_measure<fp>(); |
| 125 | + test_get_distance_measure<dp>(); |
| 126 | + test_get_distance_measure<ep>(); |
| 127 | + |
| 128 | + return 0; |
| 129 | +} |
0 commit comments