[turns] if the touch-interior touches near the end (near the IP), then handle

it as if it is a touch
This commit is contained in:
Barend Gehrels 2020-07-22 14:06:03 +02:00
parent 9759656d2b
commit dfbbfc0a87
2 changed files with 162 additions and 116 deletions

View File

@ -272,6 +272,59 @@ template
> >
struct touch_interior : public base_turn_handler struct touch_interior : public base_turn_handler
{ {
template
<
typename IntersectionInfo,
typename UniqueSubRange
>
static bool handle_as_touch(IntersectionInfo const& info,
UniqueSubRange const& non_touching_range)
{
#if defined(BOOST_GEOMETRY_USE_RESCALING)
return false;
#endif
//
//
// ^ Q(i) ^ P(i)
// \ /
// \ /
// \ /
// \ /
// \ /
// \ /
// \ /
// \ /
// \ /
// \ / it is about buffer_rt_r
// P(k) v/ they touch here "in the middle", but at the intersection...
// <---------------->v there is no follow up IP
// /
// /
// /
// /
// /
// /
// v Q(k)
//
// Measure where the IP is located. If it is really close to the end,
// then there is no space for the next IP (on P(1)/Q(2). A "from"
// intersection will be generated, but those are never handled.
// Therefore handle it as a normal touch (two segments arrive at the
// intersection point). It currently checks for zero, but even a
// distance a little bit larger would do.
typedef typename geometry::coordinate_type
<
typename UniqueSubRange::point_type
>::type coor_t;
coor_t const location = distance_measure(info.intersections[0], non_touching_range.at(1));
coor_t const zero = 0;
bool const result = math::equals(location, zero);
return result;
}
// Index: 0, P is the interior, Q is touching and vice versa // Index: 0, P is the interior, Q is touching and vice versa
template template
< <
@ -1027,8 +1080,6 @@ public:
tp_model, out, intersection_info, side, empty_transformer); tp_model, out, intersection_info, side, empty_transformer);
} }
public:
template template
< <
typename UniqueSubRange1, typename UniqueSubRange1,
@ -1191,141 +1242,138 @@ struct get_turn_info
char const method = inters.d_info().how; char const method = inters.d_info().how;
if (method == 'd')
{
// Disjoint
return out;
}
// Copy, to copy possibly extended fields // Copy, to copy possibly extended fields
TurnInfo tp = tp_model; TurnInfo tp = tp_model;
bool do_only_convert = false; bool const handle_as_touch_interior = method == 'm';
bool const handle_as_cross = method == 'i';
bool handle_as_touch = method == 't';
bool handle_as_equal = method == 'e';
bool const handle_as_collinear = method == 'c';
bool const handle_as_degenerate = method == '0';
// Select method and apply // (angle, from, start)
switch(method) bool const do_only_convert = method == 'a' || method == 'f' || method == 's';
if (handle_as_touch_interior)
{ {
case 'a' : // "angle" typedef touch_interior<TurnInfo> handler;
case 'f' : // "from"
case 's' : // "start"
do_only_convert = true;
break;
case 'd' : // disjoint: never do anything if ( inters.d_info().arrival[1] == 1 )
break;
case 'm' :
{ {
typedef touch_interior // Q arrives
< if (handler::handle_as_touch(inters.i_info(), range_p))
TurnInfo {
> handler; handle_as_touch = true;
}
// If Q (1) arrives (1) else
if ( inters.d_info().arrival[1] == 1 )
{ {
handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
inters.sides(), umbrella_strategy); inters.sides(), umbrella_strategy);
*out++ = tp;
}
}
else
{
// P arrives, swap p/q
if (handler::handle_as_touch(inters.i_info(), range_q))
{
handle_as_touch = true;
} }
else else
{ {
// Swap p/q
handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
inters.get_swapped_sides(), umbrella_strategy); inters.get_swapped_sides(), umbrella_strategy);
}
*out++ = tp;
}
break;
case 'i' :
{
crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
*out++ = tp;
}
break;
case 'e':
{
if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
*out++ = tp;
}
else
{
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(range_p, range_q, tp, out, inters);
}
}
break;
case 'c' :
{
// Collinear
if ( ! inters.d_info().opposite )
{
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
// override assigned method
tp.method = method_collinear;
}
else
{
collinear<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
}
*out++ = tp;
}
else
{
collinear_opposite
<
TurnInfo,
AssignPolicy
>::apply(range_p, range_q,
tp, out, inters, inters.sides());
}
}
break;
case '0' :
{
// degenerate points
if (AssignPolicy::include_degenerate)
{
only_convert::apply(tp, inters.i_info());
*out++ = tp; *out++ = tp;
} }
} }
break;
default :
{
#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
std::cout << "TURN: Unknown method: " << method << std::endl;
#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
BOOST_THROW_EXCEPTION(turn_info_exception(method));
#endif
}
break;
} }
if (do_only_convert if (handle_as_cross)
&& AssignPolicy::include_no_turn
&& inters.i_info().count > 0)
{ {
only_convert::apply(tp, inters.i_info()); crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
*out++ = tp; *out++ = tp;
} }
if (handle_as_touch)
{
// Touch: both segments arrive at the intersection point
touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
*out++ = tp;
}
if (handle_as_collinear)
{
// Collinear
if ( ! inters.d_info().opposite )
{
if ( inters.d_info().arrival[0] == 0 )
{
handle_as_equal = true;
}
else
{
collinear<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
*out++ = tp;
}
}
else
{
collinear_opposite
<
TurnInfo,
AssignPolicy
>::apply(range_p, range_q, tp, out, inters, inters.sides());
// Zero, or two, turn points are assigned to *out++
}
}
if (handle_as_equal)
{
if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
if (handle_as_collinear)
{
// Keep info as collinear,
// so override already assigned method
tp.method = method_collinear;
}
*out++ = tp;
}
else
{
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(range_p, range_q, tp, out, inters);
// Zero, or two, turn points are assigned to *out++
}
}
if ((handle_as_degenerate && AssignPolicy::include_degenerate)
|| (do_only_convert && AssignPolicy::include_no_turn))
{
if (inters.i_info().count > 0)
{
only_convert::apply(tp, inters.i_info());
*out++ = tp;
}
}
return out; return out;
} }
}; };

View File

@ -521,12 +521,10 @@ void test_areal()
1, 0, -1, 18.5710); 1, 0, -1, 18.5710);
test_one<Polygon, Polygon, Polygon>("buffer_rt_q_rev", buffer_rt_q[1], buffer_rt_q[0], test_one<Polygon, Polygon, Polygon>("buffer_rt_q_rev", buffer_rt_q[1], buffer_rt_q[0],
1, 0, -1, 18.5710); 1, 0, -1, 18.5710);
#if ! defined(BOOST_GEOMETRY_EXCLUDE)
test_one<Polygon, Polygon, Polygon>("buffer_rt_r", buffer_rt_r[0], buffer_rt_r[1], test_one<Polygon, Polygon, Polygon>("buffer_rt_r", buffer_rt_r[0], buffer_rt_r[1],
1, 0, -1, 21.07612); 1, 0, -1, 21.07612);
test_one<Polygon, Polygon, Polygon>("buffer_rt_r_rev", buffer_rt_r[1], buffer_rt_r[0], test_one<Polygon, Polygon, Polygon>("buffer_rt_r_rev", buffer_rt_r[1], buffer_rt_r[0],
1, 0, -1, 21.07612); 1, 0, -1, 21.07612);
#endif
test_one<Polygon, Polygon, Polygon>("buffer_rt_t", buffer_rt_t[0], buffer_rt_t[1], test_one<Polygon, Polygon, Polygon>("buffer_rt_t", buffer_rt_t[0], buffer_rt_t[1],
1, 0, -1, 15.6569); 1, 0, -1, 15.6569);
test_one<Polygon, Polygon, Polygon>("buffer_rt_t_rev", buffer_rt_t[1], buffer_rt_t[0], test_one<Polygon, Polygon, Polygon>("buffer_rt_t_rev", buffer_rt_t[1], buffer_rt_t[0],
@ -634,7 +632,7 @@ int test_main(int, char* [])
#endif #endif
#if defined(BOOST_GEOMETRY_TEST_FAILURES) #if defined(BOOST_GEOMETRY_TEST_FAILURES)
BoostGeometryWriteExpectedFailures(3, 6); BoostGeometryWriteExpectedFailures(3, 4);
#endif #endif
return 0; return 0;