get_turns(L,A) handled front endpoint

This commit is contained in:
Adam Wulkiewicz
2014-03-03 13:36:23 +01:00
parent be1ac99a82
commit ebaf26c0ff
3 changed files with 191 additions and 57 deletions

View File

@@ -118,6 +118,7 @@ struct turn_operation_linear
template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
struct get_turn_info_for_endpoint
{
BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
template<typename Point1,
typename Point2,
@@ -135,11 +136,6 @@ struct get_turn_info_for_endpoint
method_type method,
OutputIterator out)
{
namespace ov = overlay;
//if ( !enable_first && !enable_last )
// return false;
std::size_t ip_count = result.template get<0>().count;
// no intersection points
if ( ip_count == 0 )
@@ -157,10 +153,10 @@ struct get_turn_info_for_endpoint
if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
return false;
ov::operation_type p_operation0 = ov::operation_none;
ov::operation_type q_operation0 = ov::operation_none;
ov::operation_type p_operation1 = ov::operation_none;
ov::operation_type q_operation1 = ov::operation_none;
operation_type p_operation0 = operation_none;
operation_type q_operation0 = operation_none;
operation_type p_operation1 = operation_none;
operation_type q_operation1 = operation_none;
bool p0i, p0j, q0i, q0j; // assign false?
bool p1i, p1j, q1i, q1j; // assign false?
@@ -197,7 +193,7 @@ struct get_turn_info_for_endpoint
(append0_last && (p0j || (is_q_last && q0j && q1i)));
// NOTE: based on how collinear is calculated for opposite segments
if ( p_operation1 == ov::operation_none )
if ( p_operation1 == operation_none )
return result_ignore_ip0;
bool append1_last
@@ -410,15 +406,19 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
bool opposite = result.template get<1>().opposite;
// NOTE: this conversion may be problematic
Point1 i21;
geometry::convert(i2, i21);
side_calculator<Point1, Point2> side_calc(i21, i1, j1, i2, j2, k2);
TurnInfo tp = tp_model;
side_calculator<Point1, Point2> side_calc(i2, i1, j1, i2, j2, k2);
equal<TurnInfo>::apply(i2, i1, j1, i2, j2, k2,
equal<TurnInfo>::apply(i21, i1, j1, i2, j2, k2,
tp, result.template get<0>(), result.template get<1>(), side_calc);
if ( tp.both(operation_continue) )
{
bool opposite = result.template get<1>().opposite;
op1 = operation_intersection;
op2 = opposite ? operation_union : operation_intersection;
}
@@ -449,15 +449,20 @@ struct get_turn_info_for_endpoint
}
else if ( ip_i2 )
{
bool opposite = result.template get<1>().opposite;
// NOTE: this conversion may be problematic
Point1 j21;
geometry::convert(j2, j21);
side_calculator<Point1, Point2> side_calc(j21, j1, i1, i2, j2, k2);
TurnInfo tp = tp_model;
side_calculator<Point1, Point2> side_calc(j2, j1, i1, i2, j2, k2);
equal<TurnInfo>::apply(j2, j1, i1, i2, j2, k2,
equal<TurnInfo>::apply(j21, j1, i1, i2, j2, k2,
tp, result.template get<0>(), result.template get<1>(), side_calc);
if ( tp.both(operation_continue) )
{
bool opposite = result.template get<1>().opposite;
op1 = operation_blocked;
op2 = opposite ? operation_intersection : operation_union;
}

View File

@@ -73,9 +73,9 @@ struct get_turn_info_linear_areal
case 'a' : // collinear, "at"
case 'f' : // collinear, "from"
case 's' : // starts from the middle
/*get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_none, out);*/
get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_none, out);
break;
case 'd' : // disjoint: never do anything
@@ -83,13 +83,13 @@ struct get_turn_info_linear_areal
case 'm' :
{
//if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
// ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
// tp_model, result, method_touch_interior, out) )
//{
// // do nothing
//}
//else
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_touch_interior, out) )
{
// do nothing
}
else
{
typedef touch_interior
<
@@ -133,13 +133,13 @@ struct get_turn_info_linear_areal
case 't' :
{
// Both touch (both arrive there)
//if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
// ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
// tp_model, result, method_touch, out) )
//{
// // do nothing
//}
//else
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_touch, out) )
{
// do nothing
}
else
{
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
@@ -153,13 +153,13 @@ struct get_turn_info_linear_areal
break;
case 'e':
{
/*if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_equal, out) )
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_equal, out) )
{
// do nothing
}
else */if ( ! result.template get<1>().opposite )
else if ( ! result.template get<1>().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
@@ -186,13 +186,13 @@ struct get_turn_info_linear_areal
case 'c' :
{
// Collinear
/*if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_collinear, out) )
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count,
tp_model, result, method_collinear, out) )
{
// do nothing
}
else*/ if (! result.template get<1>().opposite)
else if (! result.template get<1>().opposite)
{
if (result.template get<1>().arrival[0] == 0)
@@ -201,11 +201,6 @@ struct get_turn_info_linear_areal
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
// NOTE: don't change the method only if methods are WRT IPs, not segments!
// (currently this approach is used)
// override assigned method
//tp.method = method_collinear;
replacer_of_method_and_operations_ec replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
}
@@ -290,19 +285,18 @@ struct get_turn_info_linear_areal
operation_type & op0,
operation_type & op1) const
{
// NOTE: probably only if methods are WRT IPs, not segments!
if ( op0 == operation_intersection || op0 == operation_union
|| op1 == operation_intersection || op1 == operation_union )
{
method = m_method;
}
// assuming Linear is always the first one
if ( op0 == operation_blocked )
op0 = operation_continue;
if ( op1 != operation_continue )
op1 = operation_union;
// NOTE: probably only if methods are WRT IPs, not segments!
if ( op0 == operation_intersection || op0 == operation_union
|| op1 == operation_intersection || op1 == operation_union )
{
method = m_method;
}
op1 = operation_union;
}
private:
@@ -316,6 +310,128 @@ struct get_turn_info_linear_areal
}
template <bool EnableFirst,
bool EnableLast,
typename Point1,
typename Point2,
typename TurnInfo,
typename IntersectionResult,
typename OutputIterator>
static inline bool get_turn_info_for_endpoint(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
// TODO: should this always be std::size_t or replace with template parameter?
std::size_t p_segments_count,
std::size_t q_segments_count,
TurnInfo const& tp_model,
IntersectionResult const& result,
method_type method,
OutputIterator out)
{
namespace ov = overlay;
typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
std::size_t ip_count = result.template get<0>().count;
// no intersection points
if ( ip_count == 0 )
return false;
int segment_index0 = tp_model.operations[0].seg_id.segment_index;
int segment_index1 = tp_model.operations[1].seg_id.segment_index;
BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0);
bool is_p_first = segment_index0 == 0;
bool is_q_first = segment_index1 == 0; // not used
bool is_p_last = static_cast<std::size_t>(segment_index0) + 1 == p_segments_count;
bool is_q_last = static_cast<std::size_t>(segment_index1) + 1 == q_segments_count; // not used
if ( !is_p_first && !is_p_last )
return false;
ov::operation_type p_operation0 = ov::operation_none;
ov::operation_type q_operation0 = ov::operation_none;
ov::operation_type p_operation1 = ov::operation_none;
ov::operation_type q_operation1 = ov::operation_none;
bool p0i, p0j, q0i, q0j; // assign false?
bool p1i, p1j, q1i, q1j; // assign false?
bool opposite = result.template get<1>().opposite;
{
int p_how = result.template get<1>().how_a;
int q_how = result.template get<1>().how_b;
int p_arrival = result.template get<1>().arrival[0];
int q_arrival = result.template get<1>().arrival[1];
bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0;
get_info_e::handle_segment(
is_p_first, is_p_last, p_how, p_arrival,
is_q_first, is_q_last, q_how, q_arrival,
opposite, ip_count, same_dirs,
result.template get<0>().intersections[0],
result.template get<0>().intersections[1],
p_operation0, q_operation0, p_operation1, q_operation1,
p0i, p0j, q0i, q0j,
p1i, p1j, q1i, q1j,
pi, pj, pk, qi, qj, qk);
}
// IP on the first point of Linear Geometry
if ( EnableFirst && is_p_first && p0i && !q0i )
{
TurnInfo tp = tp_model;
tp.operations[0].position = position_front;
tp.operations[1].position = position_middle;
// NOTE: the conversion may be problematic
Point1 qi1;
geometry::convert(qi, qi1);
method_type replaced_method = method_touch_interior;
if ( q0j )
{
if ( !opposite )
{
side_calculator<Point1, Point2> side_calc(qi1, pi, pj, qi, qj, qk);
equal<TurnInfo>::apply(qi1, pi, pj, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
}
else // opposite -> collinear
{
tp.operations[0].operation = operation_continue;
tp.operations[1].operation = operation_union;
}
replaced_method = method_touch;
}
else
{
// NOTE: the conversion may be problematic
Point2 pi2;
geometry::convert(pi, pi2);
side_calculator<Point1, Point2> side_calc(qi1, pi, pj, qi, pi2, qj);
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(qi1, pi, pj, qi, pi2, qj,
tp, result.template get<0>(), result.template get<1>(), side_calc);
}
replacer_of_method_and_operations_ec replacer(replaced_method);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
geometry::convert(result.template get<0>().intersections[0], tp.point);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
}
// don't ignore anything for now
return false;
}
};
}} // namespace detail::overlay

View File

@@ -34,7 +34,20 @@ void test_all()
to_svg<ls, poly>("LINESTRING(15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"ls_poly.svg");
"ls_poly1.svg");
to_svg<ls, poly>("LINESTRING(15 3,15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"ls_poly2.svg");
to_svg<ls, poly>("LINESTRING(15 7,15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"ls_poly3.svg");
to_svg<ls, poly>("LINESTRING(15 5,15 7,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"ls_poly4.svg");
to_svg<ls, poly>("LINESTRING(15 5,15 3,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"ls_poly5.svg");
to_svg<poly, ls>("POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))",
"LINESTRING(15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)",
"poly_ls.svg");