mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-10 07:34:03 +00:00
[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:
parent
9759656d2b
commit
dfbbfc0a87
@ -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,65 +1242,115 @@ 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
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'm' :
|
|
||||||
{
|
|
||||||
typedef touch_interior
|
|
||||||
<
|
|
||||||
TurnInfo
|
|
||||||
> handler;
|
|
||||||
|
|
||||||
// If Q (1) arrives (1)
|
|
||||||
if ( inters.d_info().arrival[1] == 1 )
|
if ( inters.d_info().arrival[1] == 1 )
|
||||||
{
|
{
|
||||||
handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
|
// Q arrives
|
||||||
inters.sides(), umbrella_strategy);
|
if (handler::handle_as_touch(inters.i_info(), range_p))
|
||||||
|
{
|
||||||
|
handle_as_touch = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Swap p/q
|
handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
|
||||||
handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
|
inters.sides(), umbrella_strategy);
|
||||||
inters.get_swapped_sides(), umbrella_strategy);
|
|
||||||
}
|
|
||||||
*out++ = tp;
|
*out++ = tp;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case 'i' :
|
else
|
||||||
|
{
|
||||||
|
// P arrives, swap p/q
|
||||||
|
if (handler::handle_as_touch(inters.i_info(), range_q))
|
||||||
|
{
|
||||||
|
handle_as_touch = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
|
||||||
|
inters.get_swapped_sides(), umbrella_strategy);
|
||||||
|
*out++ = tp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle_as_cross)
|
||||||
{
|
{
|
||||||
crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
|
crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
|
||||||
*out++ = tp;
|
*out++ = tp;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 't' :
|
if (handle_as_touch)
|
||||||
{
|
{
|
||||||
// Both touch (both arrive there)
|
// 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);
|
touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
|
||||||
*out++ = tp;
|
*out++ = tp;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'e':
|
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 )
|
if ( ! inters.d_info().opposite )
|
||||||
{
|
{
|
||||||
// Both equal
|
// Both equal
|
||||||
// or collinear-and-ending at intersection point
|
// 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);
|
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;
|
*out++ = tp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1259,72 +1360,19 @@ struct get_turn_info
|
|||||||
TurnInfo,
|
TurnInfo,
|
||||||
AssignPolicy
|
AssignPolicy
|
||||||
>::apply(range_p, range_q, tp, out, inters);
|
>::apply(range_p, range_q, tp, out, inters);
|
||||||
|
// Zero, or two, turn points are assigned to *out++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
if ((handle_as_degenerate && AssignPolicy::include_degenerate)
|
||||||
}
|
|| (do_only_convert && AssignPolicy::include_no_turn))
|
||||||
else
|
|
||||||
{
|
{
|
||||||
collinear_opposite
|
if (inters.i_info().count > 0)
|
||||||
<
|
|
||||||
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());
|
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
|
|
||||||
&& AssignPolicy::include_no_turn
|
|
||||||
&& inters.i_info().count > 0)
|
|
||||||
{
|
|
||||||
only_convert::apply(tp, inters.i_info());
|
|
||||||
*out++ = tp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user