[intersection] check for disjoint-by-range.

Without it, in FP calculations, for nearly collinear segments, it might happen that an intersection is calculated even if the ranges are farther apart from each other
This commit is contained in:
Barend Gehrels 2020-07-15 12:45:34 +02:00
parent cc0643941a
commit 761170b0b4
3 changed files with 42 additions and 8 deletions

View File

@ -371,6 +371,38 @@ struct cartesian_segments
return unified<ratio_type>(sinfo, p, q, policy, modelled_range_p, modelled_range_q);
}
//! Returns true if two segments do not overlap.
//! If not, then no further calculations need to be done.
template
<
std::size_t Dimension,
typename CoordinateType,
typename PointP,
typename PointQ
>
static inline bool disjoint_by_range(PointP const& p1, PointP const& p2,
PointQ const& q1, PointQ const& q2)
{
CoordinateType minp = get<Dimension>(p1);
CoordinateType maxp = get<Dimension>(p2);
CoordinateType minq = get<Dimension>(q1);
CoordinateType maxq = get<Dimension>(q2);
if (minp > maxp)
{
std::swap(minp, maxp);
}
if (minq > maxq)
{
std::swap(minq, maxq);
}
// In this case, max(p) < min(q)
// P Q
// <-------> <------->
// (and the space in between is not extremely small)
return math::smaller(maxp, minq) || math::smaller(maxq, minp);
}
// Implementation for either rescaled or non rescaled versions.
template
<
@ -413,6 +445,12 @@ struct cartesian_segments
;
}
if (disjoint_by_range<0, coordinate_type>(p1, p2, q1, q2)
|| disjoint_by_range<1, coordinate_type>(p1, p2, q1, q2))
{
return Policy::disjoint();
}
side_info sides;
sides.set<0>(side_strategy_type::apply(q1, q2, p1),
side_strategy_type::apply(q1, q2, p2));
@ -467,8 +505,8 @@ struct cartesian_segments
{
// If this is the case, no rescaling is done for FP precision.
// We set it to collinear, but it indicates a robustness issue.
sides.set<0>(0,0);
sides.set<1>(0,0);
sides.set<0>(0, 0);
sides.set<1>(0, 0);
collinear = true;
}
else

View File

@ -483,8 +483,8 @@ int test_main(int, char* [])
test_aimes<bg::model::point<default_test_type, 2, bg::cs::cartesian> >();
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
// Non-rescaled reports 22 failures (failures in validity only)
BoostGeometryWriteExpectedFailures(BG_NO_FAILURES, 22);
// Non-rescaled reports failures, but in validity only
BoostGeometryWriteExpectedFailures(BG_NO_FAILURES, 4);
#endif
return 0;

View File

@ -281,9 +281,7 @@ void test_areal()
TEST_UNION(case_precision_17, 1, 1, -1, 73.0);
TEST_UNION(case_precision_18, 1, 1, -1, 73.0);
TEST_UNION(case_precision_19, 1, 1, -1, 73.0);
#if ! defined(BOOST_GEOMETRY_EXCLUDE)
TEST_UNION(case_precision_20, 1, 0, -1, 22.0);
#endif
TEST_UNION(case_precision_21, 1, 0, -1, 22.0);
TEST_UNION(case_precision_22, 1, 1, -1, 73.0);
TEST_UNION(case_precision_23, 1, 1, -1, 73.0);
@ -310,9 +308,7 @@ void test_areal()
TEST_UNION_REV(case_precision_17, 1, 1, -1, 73.0);
TEST_UNION_REV(case_precision_18, 1, 1, -1, 73.0);
TEST_UNION_REV(case_precision_19, 1, 1, -1, 73.0);
#if ! defined(BOOST_GEOMETRY_EXCLUDE)
TEST_UNION_REV(case_precision_20, 1, 0, -1, 22.0);
#endif
TEST_UNION_REV(case_precision_21, 1, 0, -1, 22.0);
TEST_UNION_REV(case_precision_22, 1, 1, -1, 73.0);
TEST_UNION_REV(case_precision_23, 1, 1, -1, 73.0);