mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-15 13:12:10 +00:00
Merge branch 'feature/relate' of https://github.com/boostorg/geometry into feature/setops
Conflicts: include/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp include/boost/geometry/algorithms/detail/relate/turns.hpp
This commit is contained in:
@@ -28,9 +28,11 @@ struct turn_operation_linear
|
||||
{
|
||||
turn_operation_linear()
|
||||
: position(position_middle)
|
||||
, is_collinear(false)
|
||||
{}
|
||||
|
||||
turn_position position;
|
||||
bool is_collinear; // valid only for Linear geometry
|
||||
};
|
||||
|
||||
// SEGMENT_INTERSECTION RESULT
|
||||
@@ -347,12 +349,16 @@ struct get_turn_info_for_endpoint
|
||||
if ( append_first || append_last )
|
||||
{
|
||||
bool handled = handle_internal(pi, pj, pk, qi, qj, qk, ip,
|
||||
is_p_first_ip, is_p_last_ip, is_q_first_ip, is_q_last_ip, is_qi_ip, is_qj_ip,
|
||||
is_p_first_ip, is_p_last_ip,
|
||||
is_q_first_ip, is_q_last_ip,
|
||||
is_qi_ip, is_qj_ip,
|
||||
tp_model, result, p_operation, q_operation);
|
||||
if ( !handled )
|
||||
{
|
||||
handle_internal(qi, qj, qk, pi, pj, pk, ip,
|
||||
is_q_first_ip, is_q_last_ip, is_p_first_ip, is_p_last_ip, is_pi_ip, is_pj_ip,
|
||||
is_q_first_ip, is_q_last_ip,
|
||||
is_p_first_ip, is_p_last_ip,
|
||||
is_pi_ip, is_pj_ip,
|
||||
tp_model, result, q_operation, p_operation);
|
||||
}
|
||||
|
||||
@@ -382,7 +388,8 @@ struct get_turn_info_for_endpoint
|
||||
static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/,
|
||||
Point2 const& i2, Point2 const& j2, Point2 const& k2,
|
||||
Point const& ip,
|
||||
bool first1, bool last1, bool first2, bool last2,
|
||||
bool first1, bool last1,
|
||||
bool first2, bool last2,
|
||||
bool ip_i2, bool ip_j2,
|
||||
TurnInfo const& tp_model,
|
||||
IntersectionResult const& result,
|
||||
@@ -420,6 +427,7 @@ struct get_turn_info_for_endpoint
|
||||
|
||||
if ( tp.both(operation_continue) )
|
||||
{
|
||||
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
|
||||
bool opposite = result.template get<1>().opposite;
|
||||
|
||||
op1 = operation_intersection;
|
||||
@@ -443,23 +451,23 @@ struct get_turn_info_for_endpoint
|
||||
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip));
|
||||
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip));
|
||||
#endif
|
||||
if ( ip_j2 )
|
||||
if ( ip_i2 )
|
||||
{
|
||||
// don't output this IP - for the first point of other geometry segment
|
||||
op1 = operation_none;
|
||||
op2 = operation_none;
|
||||
return true;
|
||||
}
|
||||
else if ( ip_i2 )
|
||||
else if ( ip_j2 )
|
||||
{
|
||||
// NOTE: this conversion may be problematic
|
||||
Point1 j2_conv;
|
||||
geometry::convert(j2, j2_conv);
|
||||
Point1 i2_conv;
|
||||
geometry::convert(i2, i2_conv);
|
||||
|
||||
side_calculator<Point1, Point2> side_calc(j2_conv, j1, i1, i2, j2, k2);
|
||||
side_calculator<Point1, Point2> side_calc(i2_conv, j1, i1, i2, j2, k2);
|
||||
|
||||
TurnInfo tp = tp_model;
|
||||
equal<TurnInfo>::apply(j2_conv, j1, i1, i2, j2, k2,
|
||||
equal<TurnInfo>::apply(i2_conv, j1, i1, i2, j2, k2,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
// TODO: must the above be calculated?
|
||||
@@ -467,10 +475,11 @@ struct get_turn_info_for_endpoint
|
||||
|
||||
if ( tp.both(operation_continue) )
|
||||
{
|
||||
bool opposite = result.template get<1>().opposite;
|
||||
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
|
||||
bool second_going_out = result.template get<0>().count > 1;
|
||||
|
||||
op1 = operation_blocked;
|
||||
op2 = opposite ? operation_intersection : operation_union;
|
||||
op2 = second_going_out ? operation_union : operation_intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -523,8 +532,29 @@ struct get_turn_info_for_endpoint
|
||||
tp.method = method;
|
||||
tp.operations[0].operation = op0;
|
||||
tp.operations[1].operation = op1;
|
||||
// tp.operations[0].position = pos0;
|
||||
// tp.operations[1].position = pos1;
|
||||
tp.operations[0].position = pos0;
|
||||
tp.operations[1].position = pos1;
|
||||
|
||||
// NOTE: this probably shouldn't be set for the first point
|
||||
// for which there is no preceding segment
|
||||
if ( result.template get<0>().count > 1 )
|
||||
{
|
||||
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
|
||||
tp.operations[0].is_collinear = true;
|
||||
tp.operations[1].is_collinear = true;
|
||||
}
|
||||
else //if ( result.template get<0>().count == 1 )
|
||||
{
|
||||
if ( op0 == operation_blocked && op1 == operation_intersection )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
else if ( op0 == operation_intersection && op1 == operation_blocked )
|
||||
{
|
||||
tp.operations[1].is_collinear = true;
|
||||
}
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,11 @@ struct get_turn_info_linear_areal
|
||||
swapped_side_calc);
|
||||
}
|
||||
|
||||
if ( tp.operations[1].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
@@ -144,6 +149,11 @@ struct get_turn_info_linear_areal
|
||||
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
if ( tp.operations[1].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
@@ -159,27 +169,32 @@ struct get_turn_info_linear_areal
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if ( ! result.template get<1>().opposite )
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
equal_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
tp.operations[0].is_collinear = true;
|
||||
|
||||
if ( ! result.template get<1>().opposite )
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
equal_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -192,42 +207,46 @@ struct get_turn_info_linear_areal
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (! result.template get<1>().opposite)
|
||||
else
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
if (! result.template get<1>().opposite)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
// Is this always 'm' ?
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
collinear_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
|
||||
replacer);
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is this always 'm' ?
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
|
||||
|
||||
collinear_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
|
||||
replacer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -267,11 +286,14 @@ struct get_turn_info_linear_areal
|
||||
method = (method == method_touch ? method_equal : method_collinear);
|
||||
}
|
||||
|
||||
// assuming Linear is always the first one
|
||||
// Assuming G1 is always Linear
|
||||
if ( op0 == operation_blocked )
|
||||
op0 = operation_continue;
|
||||
|
||||
op1 = operation_union;
|
||||
if ( op1 == operation_blocked )
|
||||
op1 = operation_continue;
|
||||
else if ( op1 == operation_intersection )
|
||||
op1 = operation_union;
|
||||
}
|
||||
|
||||
template <bool IsFront>
|
||||
@@ -294,11 +316,14 @@ struct get_turn_info_linear_areal
|
||||
method = m_method;
|
||||
}
|
||||
|
||||
// assuming Linear is always the first one
|
||||
// Assuming G1 is always Linear
|
||||
if ( op0 == operation_blocked )
|
||||
op0 = operation_continue;
|
||||
|
||||
op1 = operation_union;
|
||||
if ( op1 == operation_blocked )
|
||||
op1 = operation_continue;
|
||||
else if ( op1 == operation_intersection )
|
||||
op1 = operation_union;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -387,61 +412,99 @@ struct get_turn_info_linear_areal
|
||||
tp.operations[0].position = position_front;
|
||||
tp.operations[1].position = position_middle;
|
||||
|
||||
// NOTE: the conversion may be problematic
|
||||
Point1 qi_conv;
|
||||
geometry::convert(qi, qi_conv);
|
||||
|
||||
method_type replaced_method = method_touch_interior;
|
||||
|
||||
if ( q0j )
|
||||
if ( opposite ) // opposite -> collinear
|
||||
{
|
||||
if ( !opposite )
|
||||
{
|
||||
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, qj, qk);
|
||||
equal<TurnInfo>::apply(qi_conv, 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;
|
||||
tp.operations[0].operation = operation_continue;
|
||||
tp.operations[1].operation = operation_union;
|
||||
tp.method = q0j ? method_touch : method_touch_interior;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: the conversion may be problematic
|
||||
Point1 qi_conv;
|
||||
geometry::convert(qi, qi_conv);
|
||||
|
||||
method_type replaced_method = method_touch_interior;
|
||||
|
||||
if ( q0j )
|
||||
{
|
||||
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, qj, qk);
|
||||
|
||||
equal<TurnInfo>::apply(qi_conv, pi, pj, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replaced_method = method_touch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: the conversion may be problematic
|
||||
Point2 pi_conv;
|
||||
geometry::convert(pi, pi_conv);
|
||||
Point2 pi_conv;
|
||||
geometry::convert(pi, pi_conv);
|
||||
|
||||
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, pi_conv, qj);
|
||||
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, pi_conv, qj);
|
||||
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(qi_conv, pi, pj, qi, pi_conv, qj,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(qi_conv, pi, pj, qi, pi_conv, qj,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
}
|
||||
|
||||
replacer_of_method_and_operations_ec<true> replacer(replaced_method);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
}
|
||||
|
||||
replacer_of_method_and_operations_ec<true> 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);
|
||||
|
||||
// NOTE: not really needed especially for the first point
|
||||
// for which there is no preceding segment (but consistent with the L/L)
|
||||
if ( result.template get<0>().count > 1 )
|
||||
{
|
||||
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
|
||||
// ANALYSE AND ASSIGN LAST
|
||||
|
||||
// IP on the first point of Linear Geometry
|
||||
if ( EnableLast && is_p_last && ( ip_count > 1 ? p1j : p0j ) && !q0i && !q1i ) // !q0i && !q1i prevents duplication
|
||||
// IP on the last point of Linear Geometry
|
||||
if ( EnableLast
|
||||
&& is_p_last
|
||||
&& ( ip_count > 1 ? p1j : p0j )
|
||||
&& (!q0i || (q0i && q1j)) // prevents duplication
|
||||
&& !q1i ) // prevents duplication
|
||||
{
|
||||
TurnInfo tp = tp_model;
|
||||
|
||||
if ( result.template get<0>().count > 1 )
|
||||
{
|
||||
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
|
||||
tp.operations[0].is_collinear = true;
|
||||
tp.operations[1].operation = opposite ? operation_continue : operation_union;
|
||||
}
|
||||
else //if ( result.template get<0>().count == 1 )
|
||||
{
|
||||
Point1 qi_conv;
|
||||
geometry::convert(qi, qi_conv);
|
||||
side_calculator<Point1, Point2> side_calc(qi_conv, pj, pi, qi, qj, qk);
|
||||
|
||||
equal<TurnInfo>::apply(qi_conv, pj, pi, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec<false> replacer(method_none);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
if ( tp.both(operation_continue) )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
}
|
||||
|
||||
tp.method = ( ip_count > 1 ? q1j : q0j ) ? method_touch : method_touch_interior;
|
||||
tp.operations[0].operation = operation_blocked;
|
||||
tp.operations[1].operation = operation_union;
|
||||
tp.operations[0].position = position_back;
|
||||
tp.operations[1].position = position_middle;
|
||||
|
||||
|
||||
@@ -112,6 +112,15 @@ struct get_turn_info_linear_linear
|
||||
swapped_side_calc);
|
||||
}
|
||||
|
||||
if ( tp.operations[0].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[1].is_collinear = true;
|
||||
}
|
||||
if ( tp.operations[1].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
@@ -144,6 +153,15 @@ struct get_turn_info_linear_linear
|
||||
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
if ( tp.operations[0].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[1].is_collinear = true;
|
||||
}
|
||||
if ( tp.operations[1].operation == operation_blocked )
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
@@ -159,27 +177,33 @@ struct get_turn_info_linear_linear
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if ( ! result.template get<1>().opposite )
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
equal_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
tp.operations[0].is_collinear = true;
|
||||
tp.operations[1].is_collinear = true;
|
||||
|
||||
if ( ! result.template get<1>().opposite )
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
equal_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -192,47 +216,52 @@ struct get_turn_info_linear_linear
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (! result.template get<1>().opposite)
|
||||
else
|
||||
{
|
||||
tp.operations[0].is_collinear = true;
|
||||
tp.operations[1].is_collinear = true;
|
||||
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
if (! result.template get<1>().opposite)
|
||||
{
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
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;
|
||||
// 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);
|
||||
replacer_of_method_and_operations_ec replacer(method_touch);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
replacer_of_method_and_operations_ec replacer(method_touch_interior);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
// If this always 'm' ?
|
||||
replacer_of_method_and_operations_ec replacer(method_touch_interior);
|
||||
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
|
||||
|
||||
collinear_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
|
||||
replacer);
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this always 'm' ?
|
||||
replacer_of_method_and_operations_ec replacer(method_touch_interior);
|
||||
|
||||
collinear_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
|
||||
replacer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -735,29 +735,76 @@ struct get_turns_polygon_cs
|
||||
}
|
||||
};
|
||||
|
||||
// GET_TURN_INFO_TYPE
|
||||
}} // namespace detail::get_turns
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
template <typename Tag,
|
||||
// TODO: move group_tag and group_dim to separate file
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail {
|
||||
|
||||
template <typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type,
|
||||
bool IsPoint = boost::is_base_of<pointlike_tag, Tag>::value,
|
||||
bool IsLinear = boost::is_base_of<linear_tag, Tag>::value,
|
||||
bool IsAreal = boost::is_base_of<areal_tag, Tag>::value>
|
||||
struct tag_base : not_implemented<Tag>
|
||||
struct group_tag
|
||||
: not_implemented<Tag>
|
||||
{};
|
||||
|
||||
template <typename Tag>
|
||||
struct tag_base<Tag, true, false>
|
||||
template <typename Geometry, typename Tag>
|
||||
struct group_tag<Geometry, Tag, true, false, false>
|
||||
{
|
||||
typedef pointlike_tag type;
|
||||
};
|
||||
|
||||
template <typename Geometry, typename Tag>
|
||||
struct group_tag<Geometry, Tag, false, true, false>
|
||||
{
|
||||
typedef linear_tag type;
|
||||
};
|
||||
|
||||
template <typename Tag>
|
||||
struct tag_base<Tag, false, true>
|
||||
template <typename Geometry, typename Tag>
|
||||
struct group_tag<Geometry, Tag, false, false, true>
|
||||
{
|
||||
typedef areal_tag type;
|
||||
};
|
||||
|
||||
template <typename Geometry,
|
||||
typename GroupTag = typename group_tag<Geometry>::type>
|
||||
struct group_dim
|
||||
: not_implemented<GroupTag>
|
||||
{};
|
||||
|
||||
template <typename Geometry>
|
||||
struct group_dim<Geometry, pointlike_tag>
|
||||
{
|
||||
static const int value = 0;
|
||||
};
|
||||
|
||||
template <typename Geometry>
|
||||
struct group_dim<Geometry, linear_tag>
|
||||
{
|
||||
static const int value = 1;
|
||||
};
|
||||
|
||||
template <typename Geometry>
|
||||
struct group_dim<Geometry, areal_tag>
|
||||
{
|
||||
static const int value = 2;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace get_turns {
|
||||
|
||||
// GET_TURN_INFO_TYPE
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename AssignPolicy,
|
||||
typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
|
||||
typename TagBase1 = typename tag_base<Tag1>::type, typename TagBase2 = typename tag_base<Tag2>::type>
|
||||
typename TagBase1 = typename group_tag<Geometry1>::type, typename TagBase2 = typename group_tag<Geometry2>::type>
|
||||
struct get_turn_info_type
|
||||
: overlay::get_turn_info<AssignPolicy>
|
||||
{};
|
||||
@@ -774,7 +821,7 @@ struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear
|
||||
|
||||
template <typename Geometry1, typename Geometry2,
|
||||
typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
|
||||
typename TagBase1 = typename tag_base<Tag1>::type, typename TagBase2 = typename tag_base<Tag2>::type>
|
||||
typename TagBase1 = typename group_tag<Geometry1>::type, typename TagBase2 = typename group_tag<Geometry2>::type>
|
||||
struct turn_operation_type
|
||||
{
|
||||
typedef overlay::turn_operation type;
|
||||
|
||||
@@ -22,6 +22,22 @@ namespace boost { namespace geometry
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace range {
|
||||
|
||||
template <typename Range>
|
||||
inline typename boost::range_value<Range>::type const&
|
||||
at(Range const& rng, typename boost::range_size<Range>::type i)
|
||||
{
|
||||
BOOST_ASSERT(i < boost::size(rng));
|
||||
return *(boost::begin(rng) + i);
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
inline typename boost::range_value<Range>::type &
|
||||
at(Range & rng, typename boost::range_size<Range>::type i)
|
||||
{
|
||||
BOOST_ASSERT(i < boost::size(rng));
|
||||
return *(boost::begin(rng) + i);
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
inline typename boost::range_value<Range>::type const&
|
||||
front(Range const& rng)
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_endpoint_boundary(point_type const& pt) const
|
||||
{
|
||||
boost::ignore_unused_variable_warning(pt);
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
|
||||
// may give false positives for INT
|
||||
BOOST_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
|
||||
@@ -95,13 +96,13 @@ public:
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_endpoint_boundary(point_type const& pt)
|
||||
bool is_endpoint_boundary(point_type const& pt) const
|
||||
{
|
||||
return is_boundary_point(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid)
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid) const
|
||||
{
|
||||
if ( BoundaryQuery == boundary_front )
|
||||
{
|
||||
@@ -128,7 +129,7 @@ public:
|
||||
private:
|
||||
// First call O(NlogN)
|
||||
// Each next call O(logN)
|
||||
bool is_boundary_point(point_type const& pt)
|
||||
bool is_boundary_point(point_type const& pt) const
|
||||
{
|
||||
typedef typename boost::range_size<Geometry>::type size_type;
|
||||
size_type multi_count = boost::size(geometry);
|
||||
@@ -173,9 +174,10 @@ private:
|
||||
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
|
||||
}
|
||||
|
||||
bool is_filled;
|
||||
mutable bool is_filled;
|
||||
// TODO: store references/pointers instead of points?
|
||||
std::vector<point_type> boundary_points;
|
||||
mutable std::vector<point_type> boundary_points;
|
||||
|
||||
Geometry const& geometry;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014.
|
||||
// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// TODO:
|
||||
// For 1-point linestrings or with all equal points turns won't be generated!
|
||||
// Check for those degenerated cases may be connected with this one!
|
||||
|
||||
template <std::size_t OpId,
|
||||
typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type,
|
||||
bool IsMulti = boost::is_base_of<multi_tag, Tag>::value
|
||||
>
|
||||
struct for_each_disjoint_geometry_if
|
||||
: public not_implemented<Tag>
|
||||
{};
|
||||
|
||||
template <std::size_t OpId, typename Geometry, typename Tag>
|
||||
struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
if ( first != last )
|
||||
return false;
|
||||
pred(geometry);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename Geometry, typename Tag>
|
||||
struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
BOOST_ASSERT(first != last);
|
||||
|
||||
const std::size_t count = boost::size(geometry);
|
||||
boost::ignore_unused_variable_warning(count);
|
||||
|
||||
// O(I)
|
||||
// gather info about turns generated for contained geometries
|
||||
std::vector<bool> detected_intersections(count, false);
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
int multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_ASSERT(multi_index >= 0);
|
||||
std::size_t index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_ASSERT(index < count);
|
||||
detected_intersections[index] = true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
// O(N)
|
||||
// check predicate for each contained geometry without generated turn
|
||||
for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
|
||||
it != detected_intersections.end() ; ++it )
|
||||
{
|
||||
// if there were no intersections for this multi_index
|
||||
if ( *it == false )
|
||||
{
|
||||
found = true;
|
||||
bool cont = pred(
|
||||
*(boost::begin(geometry)
|
||||
+ std::distance(detected_intersections.begin(), it)));
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: rename to point_id_ref?
|
||||
template <typename Point>
|
||||
class point_identifier
|
||||
{
|
||||
public:
|
||||
point_identifier() : sid_ptr(0), pt_ptr(0) {}
|
||||
point_identifier(segment_identifier const& sid, Point const& pt)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
, pt_ptr(boost::addressof(pt))
|
||||
{}
|
||||
segment_identifier const& seg_id() const
|
||||
{
|
||||
BOOST_ASSERT(sid_ptr);
|
||||
return *sid_ptr;
|
||||
}
|
||||
Point const& point() const
|
||||
{
|
||||
BOOST_ASSERT(pt_ptr);
|
||||
return *pt_ptr;
|
||||
}
|
||||
|
||||
//friend bool operator==(point_identifier const& l, point_identifier const& r)
|
||||
//{
|
||||
// return l.seg_id() == r.seg_id()
|
||||
// && detail::equals::equals_point_point(l.point(), r.point());
|
||||
//}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
const Point * pt_ptr;
|
||||
};
|
||||
|
||||
class same_multi_index
|
||||
{
|
||||
public:
|
||||
same_multi_index(segment_identifier const& sid)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
{}
|
||||
|
||||
bool operator()(segment_identifier const& sid) const
|
||||
{
|
||||
return sid.multi_index == sid_ptr->multi_index;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool operator()(point_identifier<Point> const& pid) const
|
||||
{
|
||||
return operator()(pid.seg_id());
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
class segment_watcher
|
||||
{
|
||||
public:
|
||||
segment_watcher()
|
||||
: m_seg_id_ptr(0)
|
||||
{}
|
||||
|
||||
bool update(segment_identifier const& seg_id)
|
||||
{
|
||||
bool result = m_seg_id_ptr == 0 || !same_multi_index(*m_seg_id_ptr)(seg_id);
|
||||
m_seg_id_ptr = boost::addressof(seg_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * m_seg_id_ptr;
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
class exit_watcher
|
||||
{
|
||||
typedef point_identifier<Point> point_info;
|
||||
|
||||
public:
|
||||
exit_watcher()
|
||||
: exit_operation(overlay::operation_none)
|
||||
{}
|
||||
|
||||
void enter(Point const& point, segment_identifier const& other_id)
|
||||
{
|
||||
other_entry_points.push_back(point_info(other_id, point));
|
||||
}
|
||||
|
||||
void exit(Point const& point,
|
||||
segment_identifier const& other_id,
|
||||
overlay::operation_type exit_op)
|
||||
{
|
||||
typedef typename std::vector<point_info>::iterator point_iterator;
|
||||
// search for the entry point in the same range of other geometry
|
||||
point_iterator entry_it = std::find_if(other_entry_points.begin(),
|
||||
other_entry_points.end(),
|
||||
same_multi_index(other_id));
|
||||
|
||||
// this end point has corresponding entry point
|
||||
if ( entry_it != other_entry_points.end() )
|
||||
{
|
||||
// here we know that we possibly left LS
|
||||
// we must still check if we didn't get back on the same point
|
||||
exit_operation = exit_op;
|
||||
exit_id = point_info(other_id, point);
|
||||
|
||||
// erase the corresponding entry point
|
||||
other_entry_points.erase(entry_it);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_outside() const
|
||||
{
|
||||
// if we didn't entered anything in the past, we're outside
|
||||
return other_entry_points.empty();
|
||||
}
|
||||
|
||||
overlay::operation_type get_exit_operation() const
|
||||
{
|
||||
return exit_operation;
|
||||
}
|
||||
|
||||
Point const& get_exit_point() const
|
||||
{
|
||||
BOOST_ASSERT(exit_operation != overlay::operation_none);
|
||||
return exit_id.point();
|
||||
}
|
||||
|
||||
void reset_detected_exit()
|
||||
{
|
||||
exit_operation = overlay::operation_none;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
exit_operation = overlay::operation_none;
|
||||
other_entry_points.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
overlay::operation_type exit_operation;
|
||||
point_info exit_id;
|
||||
std::vector<point_info> other_entry_points; // TODO: use map here or sorted vector?
|
||||
};
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename Point,
|
||||
typename BoundaryChecker>
|
||||
static inline bool is_endpoint_on_boundary(Point const& pt,
|
||||
BoundaryChecker & boundary_checker)
|
||||
{
|
||||
return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename IntersectionPoint,
|
||||
typename OperationInfo,
|
||||
typename BoundaryChecker>
|
||||
static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
|
||||
OperationInfo const& operation_info,
|
||||
BoundaryChecker & boundary_checker,
|
||||
segment_identifier const& seg_id)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(seg_id);
|
||||
|
||||
bool res = false;
|
||||
|
||||
// IP on the last point of the linestring
|
||||
if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& operation_info.operation == overlay::operation_blocked )
|
||||
{
|
||||
BOOST_ASSERT(operation_info.position == overlay::position_back);
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP on the last point of the linestring
|
||||
else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
|
||||
&& operation_info.position == overlay::position_front )
|
||||
{
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP somewhere in the interior
|
||||
else
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
819
include/boost/geometry/algorithms/detail/relate/linear_areal.hpp
Normal file
819
include/boost/geometry/algorithms/detail/relate/linear_areal.hpp
Normal file
@@ -0,0 +1,819 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014.
|
||||
// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/sub_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/range_helpers.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
template <typename Geometry,
|
||||
bool IsMulti = boost::is_base_of
|
||||
<
|
||||
multi_tag,
|
||||
typename geometry::tag<Geometry>::type
|
||||
>::value
|
||||
>
|
||||
struct simple_geometry
|
||||
{
|
||||
template <typename Id>
|
||||
static inline Geometry & apply(Geometry & g, Id const& ) { return g; }
|
||||
};
|
||||
|
||||
template <typename Geometry>
|
||||
struct simple_geometry<Geometry, true>
|
||||
{
|
||||
template <typename Id>
|
||||
static inline
|
||||
typename boost::mpl::if_c
|
||||
<
|
||||
boost::is_const<Geometry>::value,
|
||||
typename boost::range_value<Geometry>::type const&,
|
||||
typename boost::range_value<Geometry>::type
|
||||
>::type
|
||||
apply(Geometry & g, Id const& id)
|
||||
{
|
||||
BOOST_ASSERT(id.multi_index >= 0);
|
||||
return *(boost::begin(g) + id.multi_index);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: In the worst case for MultiLinestring/MultiPolygon this is O(NM)
|
||||
// Use the rtree in this case!
|
||||
template <typename Geometry2, typename Result, typename BoundaryChecker, bool TransposeResult>
|
||||
class no_turns_la_linestring_pred
|
||||
{
|
||||
public:
|
||||
no_turns_la_linestring_pred(Geometry2 const& geometry2,
|
||||
Result & res,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
: m_geometry2(geometry2)
|
||||
, m_result_ptr(boost::addressof(res))
|
||||
, m_boundary_checker_ptr(boost::addressof(boundary_checker))
|
||||
, m_interrupt_flags(0)
|
||||
{}
|
||||
|
||||
template <typename Linestring>
|
||||
bool operator()(Linestring const& linestring)
|
||||
{
|
||||
std::size_t count = boost::size(linestring);
|
||||
|
||||
// invalid input
|
||||
if ( count < 2 )
|
||||
{
|
||||
// ignore
|
||||
// TODO: throw an exception?
|
||||
return true;
|
||||
}
|
||||
|
||||
int pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2);
|
||||
BOOST_ASSERT_MSG(pig != 0, "There should be no IPs");
|
||||
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<interior, interior, '1', TransposeResult>(*m_result_ptr);
|
||||
m_interrupt_flags |= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '1', TransposeResult>(*m_result_ptr);
|
||||
m_interrupt_flags |= 2;
|
||||
}
|
||||
|
||||
// check if there is a boundary
|
||||
if ( m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
|| m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) )
|
||||
{
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<boundary, interior, '0', TransposeResult>(*m_result_ptr);
|
||||
m_interrupt_flags |= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
update<boundary, exterior, '0', TransposeResult>(*m_result_ptr);
|
||||
m_interrupt_flags |= 8;
|
||||
}
|
||||
|
||||
return m_interrupt_flags != 0xF;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Geometry2 const& m_geometry2;
|
||||
Result * m_result_ptr;
|
||||
const BoundaryChecker * m_boundary_checker_ptr;
|
||||
unsigned m_interrupt_flags;
|
||||
};
|
||||
|
||||
template <typename Result, bool TransposeResult>
|
||||
class no_turns_la_areal_pred
|
||||
{
|
||||
public:
|
||||
no_turns_la_areal_pred(Result & res)
|
||||
: m_result_ptr(boost::addressof(res))
|
||||
{}
|
||||
|
||||
template <typename Areal>
|
||||
bool operator()(Areal const& areal)
|
||||
{
|
||||
// TODO:
|
||||
// add an assertion for empty/invalid geometries
|
||||
|
||||
update<interior, exterior, '2', TransposeResult>(*m_result_ptr);
|
||||
update<boundary, exterior, '1', TransposeResult>(*m_result_ptr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Result * m_result_ptr;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
|
||||
struct linear_areal
|
||||
{
|
||||
// check Linear / Areal
|
||||
BOOST_STATIC_ASSERT(detail::group_dim<Geometry1>::value == 1
|
||||
&& detail::group_dim<Geometry2>::value == 2);
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
typedef typename geometry::point_type<Geometry1>::type point1_type;
|
||||
typedef typename geometry::point_type<Geometry2>::type point2_type;
|
||||
|
||||
template <typename Result>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
|
||||
{
|
||||
// The result should be FFFFFFFFF
|
||||
set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
// get and analyse turns
|
||||
typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
|
||||
typedef typename std::vector<turn_type>::iterator turn_iterator;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
boundary_checker<Geometry1> boundary_checker1(geometry1);
|
||||
no_turns_la_linestring_pred
|
||||
<
|
||||
Geometry2,
|
||||
Result,
|
||||
boundary_checker<Geometry1>,
|
||||
TransposeResult
|
||||
> pred1(geometry2, result, boundary_checker1);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
|
||||
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
if ( turns.empty() )
|
||||
return;
|
||||
|
||||
// This is set here because in the case if empty Areal geometry were passed
|
||||
// those shouldn't be set
|
||||
set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
|
||||
// TODO: NEED TO SUPPORT exterior, boundary
|
||||
// FOR THIS WE MUST CHECK IF THE BOUNDARY OF THE POLYGON TREATED LIKE LINEAR RING GOES OUT OF THE LINESTRING G1
|
||||
// THIS WON'T WORK IN ALL CASES!
|
||||
set<exterior, boundary, '1', TransposeResult>(result);// FFFFFF21d
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
// for different multi and same ring id: x, u, i, c
|
||||
// for same multi and different ring id: c, i, u, x
|
||||
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>());
|
||||
|
||||
turns_analyser<turn_type> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
turns.begin(), turns.end(),
|
||||
geometry1, geometry2,
|
||||
boundary_checker1);
|
||||
|
||||
// TODO check if this is required by the result
|
||||
if ( interrupt_policy.is_boundary_found )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Areal, typename Result>
|
||||
class interrupt_policy_linear_areal
|
||||
{
|
||||
public:
|
||||
static bool const enabled = true;
|
||||
|
||||
interrupt_policy_linear_areal(Areal const& areal, Result & result)
|
||||
: m_result(result), m_areal(areal)
|
||||
, is_boundary_found(false)
|
||||
{}
|
||||
|
||||
// TODO: since we update result for some operations here, we must not do it in the analyser!
|
||||
|
||||
template <typename Range>
|
||||
inline bool apply(Range const& turns)
|
||||
{
|
||||
typedef typename boost::range_iterator<Range const>::type iterator;
|
||||
|
||||
for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
{
|
||||
if ( it->operations[0].operation == overlay::operation_intersection )
|
||||
{
|
||||
bool const no_interior_rings
|
||||
= boost::empty(
|
||||
geometry::interior_rings(
|
||||
simple_geometry<Areal const>::apply(m_areal, it->operations[1].seg_id)));
|
||||
|
||||
// WARNING! THIS IS TRUE ONLY IF THE POLYGON IS SIMPLE!
|
||||
// OR WITHOUT INTERIOR RINGS (AND OF COURSE VALID)
|
||||
if ( no_interior_rings )
|
||||
update<interior, interior, '1', TransposeResult>(m_result);
|
||||
}
|
||||
else if ( it->operations[0].operation == overlay::operation_continue )
|
||||
{
|
||||
update<interior, boundary, '1', TransposeResult>(m_result);
|
||||
is_boundary_found = true;
|
||||
}
|
||||
else if ( ( it->operations[0].operation == overlay::operation_union
|
||||
|| it->operations[0].operation == overlay::operation_blocked )
|
||||
&& it->operations[0].position == overlay::position_middle )
|
||||
{
|
||||
// TODO: here we could also check the boundaries and set BB at this point
|
||||
update<interior, boundary, '0', TransposeResult>(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
return m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
Result & m_result;
|
||||
Areal const& m_areal;
|
||||
|
||||
public:
|
||||
bool is_boundary_found;
|
||||
};
|
||||
|
||||
// This analyser should be used like Input or SinglePass Iterator
|
||||
template <typename TurnInfo>
|
||||
class turns_analyser
|
||||
{
|
||||
typedef typename TurnInfo::point_type turn_point_type;
|
||||
|
||||
static const std::size_t op_id = 0;
|
||||
static const std::size_t other_op_id = 1;
|
||||
|
||||
public:
|
||||
turns_analyser()
|
||||
: m_previous_turn_ptr(0)
|
||||
, m_previous_operation(overlay::operation_none)
|
||||
, m_boundary_counter(0)
|
||||
, m_interior_detected(false)
|
||||
{}
|
||||
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker>
|
||||
void apply(Result & res,
|
||||
TurnIt first, TurnIt it, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
{
|
||||
if ( it != last )
|
||||
{
|
||||
overlay::operation_type op = it->operations[op_id].operation;
|
||||
|
||||
if ( op != overlay::operation_union
|
||||
&& op != overlay::operation_intersection
|
||||
&& op != overlay::operation_blocked
|
||||
&& op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
segment_identifier const& seg_id = it->operations[op_id].seg_id;
|
||||
segment_identifier const& other_id = it->operations[other_op_id].seg_id;
|
||||
|
||||
const bool first_in_range = m_seg_watcher.update(seg_id);
|
||||
|
||||
// handle possible exit
|
||||
bool fake_enter_detected = false;
|
||||
if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
|
||||
{
|
||||
// real exit point - may be multiple
|
||||
// we know that we entered and now we exit
|
||||
if ( !detail::equals::equals_point_point(it->point, m_exit_watcher.get_exit_point()) )
|
||||
{
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
|
||||
// not the last IP
|
||||
update<interior, exterior, '1', TransposeResult>(res);
|
||||
}
|
||||
// fake exit point, reset state
|
||||
else if ( op == overlay::operation_intersection
|
||||
|| op == overlay::operation_continue ) // operation_boundary
|
||||
{
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
fake_enter_detected = true;
|
||||
}
|
||||
}
|
||||
else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
|
||||
{
|
||||
// ignore multiple BLOCKs
|
||||
if ( op == overlay::operation_blocked )
|
||||
return;
|
||||
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
}
|
||||
|
||||
// NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY)
|
||||
// BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES
|
||||
// IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE
|
||||
// TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED
|
||||
|
||||
// TODO: THIS IS POTENTIALLY ERROREOUS!
|
||||
// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS
|
||||
// IT WOULD GIVE WRONG RESULTS E.G.
|
||||
// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u'
|
||||
|
||||
// handle the interior overlap
|
||||
if ( m_interior_detected )
|
||||
{
|
||||
// real interior overlap
|
||||
if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point) )
|
||||
{
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
m_interior_detected = false;
|
||||
}
|
||||
// fake interior overlap
|
||||
else if ( op == overlay::operation_continue )
|
||||
{
|
||||
m_interior_detected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if the new linestring started just now,
|
||||
// but the previous one went out on the previous point,
|
||||
// we must check if the boundary of the previous segment is outside
|
||||
// NOTE: couldn't it be integrated with the handling of the union above?
|
||||
// THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE
|
||||
//if ( first_in_range
|
||||
// && ! fake_enter_detected
|
||||
// && m_previous_operation == overlay::operation_union )
|
||||
//{
|
||||
// BOOST_ASSERT(it != first);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
// boundary_checker);
|
||||
|
||||
// // if there is a boundary on the last point
|
||||
// if ( prev_back_b )
|
||||
// {
|
||||
// update<boundary, exterior, '0', TransposeResult>(res);
|
||||
// }
|
||||
//}
|
||||
|
||||
// i/u, c/u
|
||||
if ( op == overlay::operation_intersection
|
||||
|| op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
|
||||
{
|
||||
bool no_enters_detected = m_exit_watcher.is_outside();
|
||||
m_exit_watcher.enter(it->point, other_id);
|
||||
|
||||
if ( op == overlay::operation_intersection )
|
||||
{
|
||||
if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
|
||||
--m_boundary_counter;
|
||||
|
||||
if ( m_boundary_counter == 0 )
|
||||
{
|
||||
// interiors overlaps
|
||||
//update<interior, interior, '1', TransposeResult>(res);
|
||||
|
||||
// don't update now
|
||||
// we might enter a boundary of some other ring on the same IP
|
||||
m_interior_detected = true;
|
||||
}
|
||||
}
|
||||
else // operation_boundary
|
||||
{
|
||||
// don't add to the count for all met boundaries
|
||||
// only if this is the "new" boundary
|
||||
if ( first_in_range || !it->operations[op_id].is_collinear )
|
||||
++m_boundary_counter;
|
||||
|
||||
update<interior, boundary, '1', TransposeResult>(res);
|
||||
}
|
||||
|
||||
bool this_b = is_ip_on_boundary<boundary_front>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
// going inside on boundary point
|
||||
if ( this_b )
|
||||
{
|
||||
update<boundary, boundary, '0', TransposeResult>(res);
|
||||
}
|
||||
// going inside on non-boundary point
|
||||
else
|
||||
{
|
||||
update<interior, boundary, '0', TransposeResult>(res);
|
||||
|
||||
// if we didn't enter in the past, we were outside
|
||||
if ( no_enters_detected
|
||||
&& !fake_enter_detected
|
||||
&& it->operations[op_id].position != overlay::position_front )
|
||||
{
|
||||
bool from_inside = first_in_range
|
||||
&& calculate_from_inside(geometry,
|
||||
other_geometry,
|
||||
*it);
|
||||
|
||||
if ( from_inside )
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
else
|
||||
update<interior, exterior, '1', TransposeResult>(res);
|
||||
|
||||
// if it's the first IP then the first point is outside
|
||||
if ( first_in_range )
|
||||
{
|
||||
bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_geometry::get(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
{
|
||||
if ( from_inside )
|
||||
update<boundary, interior, '0', TransposeResult>(res);
|
||||
else
|
||||
update<boundary, exterior, '0', TransposeResult>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// u/u, x/u
|
||||
else if ( op == overlay::operation_union || op == overlay::operation_blocked )
|
||||
{
|
||||
bool op_blocked = op == overlay::operation_blocked;
|
||||
bool no_enters_detected = m_exit_watcher.is_outside();
|
||||
|
||||
if ( op == overlay::operation_union )
|
||||
{
|
||||
if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
|
||||
--m_boundary_counter;
|
||||
}
|
||||
else // overlay::operation_blocked
|
||||
{
|
||||
m_boundary_counter = 0;
|
||||
}
|
||||
|
||||
// we're inside, possibly going out right now
|
||||
if ( ! no_enters_detected )
|
||||
{
|
||||
if ( op_blocked )
|
||||
{
|
||||
// check if this is indeed the boundary point
|
||||
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
|
||||
if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
|
||||
{
|
||||
update<boundary, boundary, '0', TransposeResult>(res);
|
||||
}
|
||||
}
|
||||
// union, inside, but no exit -> collinear on self-intersection point
|
||||
// not needed since we're already inside the boundary
|
||||
/*else if ( !exit_detected )
|
||||
{
|
||||
update<interior, boundary, '0', TransposeResult>(res);
|
||||
}*/
|
||||
}
|
||||
// we're outside or inside and this is the first turn
|
||||
else
|
||||
{
|
||||
bool this_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
// if current IP is on boundary of the geometry
|
||||
if ( this_b )
|
||||
{
|
||||
update<boundary, boundary, '0', TransposeResult>(res);
|
||||
}
|
||||
// if current IP is not on boundary of the geometry
|
||||
else
|
||||
{
|
||||
update<interior, boundary, '0', TransposeResult>(res);
|
||||
}
|
||||
|
||||
// TODO: very similar code is used in the handling of intersection
|
||||
if ( it->operations[op_id].position != overlay::position_front )
|
||||
{
|
||||
bool first_from_inside = first_in_range
|
||||
&& calculate_from_inside(geometry,
|
||||
other_geometry,
|
||||
*it);
|
||||
if ( first_from_inside )
|
||||
{
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
|
||||
// notify the exit_watcher that we started inside
|
||||
m_exit_watcher.enter(it->point, other_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '1', TransposeResult>(res);
|
||||
}
|
||||
|
||||
// first IP on the last segment point - this means that the first point is outside or inside
|
||||
if ( first_in_range && ( !this_b || op_blocked ) )
|
||||
{
|
||||
bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_geometry::get(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
{
|
||||
if ( first_from_inside )
|
||||
update<boundary, interior, '0', TransposeResult>(res);
|
||||
else
|
||||
update<boundary, exterior, '0', TransposeResult>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we're going along a boundary, we exit only if the linestring was collinear
|
||||
if ( m_boundary_counter == 0
|
||||
|| it->operations[op_id].is_collinear )
|
||||
{
|
||||
// notify the exit watcher about the possible exit
|
||||
m_exit_watcher.exit(it->point, other_id, op);
|
||||
}
|
||||
}
|
||||
|
||||
// store ref to previously analysed (valid) turn
|
||||
m_previous_turn_ptr = boost::addressof(*it);
|
||||
// and previously analysed (valid) operation
|
||||
m_previous_operation = op;
|
||||
}
|
||||
// it == last
|
||||
else
|
||||
{
|
||||
// here, the possible exit is the real one
|
||||
// we know that we entered and now we exit
|
||||
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
|
||||
||*/ m_previous_operation == overlay::operation_union )
|
||||
{
|
||||
// for sure
|
||||
update<interior, exterior, '1', TransposeResult>(res);
|
||||
|
||||
BOOST_ASSERT(first != last);
|
||||
BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
{
|
||||
update<boundary, exterior, '0', TransposeResult>(res);
|
||||
}
|
||||
}
|
||||
// we might enter some Areal and didn't go out,
|
||||
else if ( m_previous_operation == overlay::operation_intersection )
|
||||
{
|
||||
// just in case
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
|
||||
BOOST_ASSERT(first != last);
|
||||
BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
{
|
||||
update<boundary, interior, '0', TransposeResult>(res);
|
||||
}
|
||||
}
|
||||
|
||||
// handle the interior overlap
|
||||
if ( m_interior_detected )
|
||||
{
|
||||
// just in case
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
m_interior_detected = false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
|
||||
"Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
|
||||
|
||||
// Reset exit watcher before the analysis of the next Linestring
|
||||
m_exit_watcher.reset();
|
||||
m_boundary_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename Turn>
|
||||
static inline bool calculate_from_inside(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Turn const& turn)
|
||||
{
|
||||
if ( turn.operations[op_id].position == overlay::position_front )
|
||||
return false;
|
||||
|
||||
static const bool reverse2 = detail::overlay::do_reverse<
|
||||
geometry::point_order<Geometry2>::value
|
||||
>::value;
|
||||
|
||||
typedef typename closeable_view
|
||||
<
|
||||
typename range_type<Geometry2>::type const,
|
||||
closure<Geometry2>::value
|
||||
>::type range2_cview;
|
||||
|
||||
typedef typename reversible_view
|
||||
<
|
||||
range2_cview const,
|
||||
reverse2 ? iterate_reverse : iterate_forward
|
||||
>::type range2_view;
|
||||
|
||||
typedef typename sub_geometry::result_type<Geometry1 const>::type range1_ref;
|
||||
|
||||
range1_ref range1 = sub_geometry::get(geometry1, turn.operations[op_id].seg_id);
|
||||
range2_cview const cview(sub_geometry::get(geometry2, turn.operations[other_op_id].seg_id));
|
||||
range2_view const range2(cview);
|
||||
|
||||
std::size_t s1 = boost::size(range1);
|
||||
std::size_t s2 = boost::size(range2);
|
||||
BOOST_ASSERT(s1 > 1 && s2 > 2);
|
||||
std::size_t seg_count2 = s2 - 1;
|
||||
|
||||
std::size_t p_seg_ij = turn.operations[op_id].seg_id.segment_index;
|
||||
std::size_t q_seg_ij = turn.operations[other_op_id].seg_id.segment_index;
|
||||
|
||||
BOOST_ASSERT(p_seg_ij + 1 < s1 && q_seg_ij + 1 < s2);
|
||||
|
||||
point1_type const& pi = range::at(range1, p_seg_ij);
|
||||
point2_type const& qi = range::at(range2, q_seg_ij);
|
||||
point2_type const& qj = range::at(range2, q_seg_ij + 1);
|
||||
point1_type qi_conv;
|
||||
geometry::convert(qi, qi_conv);
|
||||
bool is_ip_qj = equals::equals_point_point(turn.point, qj);
|
||||
// TODO: test this!
|
||||
BOOST_ASSERT(!equals::equals_point_point(turn.point, pi));
|
||||
BOOST_ASSERT(!equals::equals_point_point(turn.point, qi));
|
||||
point1_type new_pj;
|
||||
geometry::convert(turn.point, new_pj);
|
||||
|
||||
if ( is_ip_qj )
|
||||
{
|
||||
std::size_t q_seg_jk = (q_seg_ij + 1) % seg_count2;
|
||||
BOOST_ASSERT(q_seg_jk + 1 < s2);
|
||||
point2_type const& qk = range::at(range2, q_seg_jk + 1);
|
||||
// Will this sequence of point be always correct?
|
||||
overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, qk);
|
||||
|
||||
return calculate_from_inside_sides(side_calc);
|
||||
}
|
||||
else
|
||||
{
|
||||
point1_type new_qj;
|
||||
geometry::convert(turn.point, new_qj);
|
||||
|
||||
overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj);
|
||||
|
||||
return calculate_from_inside_sides(side_calc);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SideCalc>
|
||||
static inline bool calculate_from_inside_sides(SideCalc const& side_calc)
|
||||
{
|
||||
// From equal<>
|
||||
|
||||
int const side_pk_p = side_calc.pk_wrt_p1();
|
||||
int const side_qk_p = side_calc.qk_wrt_p1();
|
||||
// If they turn to same side (not opposite sides)
|
||||
if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
|
||||
{
|
||||
int const side_pk_q2 = side_calc.pk_wrt_q2();
|
||||
return side_pk_q2 == -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return side_pk_p == -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
exit_watcher<turn_point_type> m_exit_watcher;
|
||||
segment_watcher m_seg_watcher;
|
||||
TurnInfo * m_previous_turn_ptr;
|
||||
overlay::operation_type m_previous_operation;
|
||||
unsigned m_boundary_counter;
|
||||
bool m_interior_detected;
|
||||
};
|
||||
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
typename Analyser,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker>
|
||||
static inline void analyse_each_turn(Result & res,
|
||||
Analyser & analyser,
|
||||
TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
analyser.apply(res, first, it, last,
|
||||
geometry, other_geometry,
|
||||
boundary_checker);
|
||||
|
||||
if ( res.interrupt )
|
||||
return;
|
||||
}
|
||||
|
||||
analyser.apply(res, first, last, last,
|
||||
geometry, other_geometry,
|
||||
boundary_checker);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct areal_linear
|
||||
{
|
||||
template <typename Result>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
|
||||
{
|
||||
linear_areal<Geometry2, Geometry1, true>::apply(geometry2, geometry1, result);
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
@@ -27,113 +28,12 @@ namespace boost { namespace geometry
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open };
|
||||
|
||||
template <typename Linestring>
|
||||
linestring_kind check_linestring_kind(Linestring const& ls)
|
||||
{
|
||||
std::size_t count = boost::size(ls);
|
||||
if ( count == 0 )
|
||||
return linestring_exterior;
|
||||
else if ( count == 1 )
|
||||
return linestring_point;
|
||||
else
|
||||
{
|
||||
bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls));
|
||||
if ( equal_fb )
|
||||
{
|
||||
typedef typename boost::range_iterator<Linestring const>::type iterator;
|
||||
iterator first = boost::begin(ls);
|
||||
++first;
|
||||
iterator last = boost::end(ls);
|
||||
--last;
|
||||
for ( iterator it = first ; it != last ; ++it )
|
||||
{
|
||||
if ( !equals::equals_point_point(range::front(ls), *it) )
|
||||
return linestring_closed;
|
||||
}
|
||||
|
||||
return linestring_point;
|
||||
}
|
||||
else
|
||||
return linestring_open;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// For 1-point linestrings or with all equal points turns won't be generated!
|
||||
// Check for those degenerated cases may be connected with this one!
|
||||
|
||||
template <std::size_t OpId,
|
||||
typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type>
|
||||
struct for_each_disjoint_linestring_if {};
|
||||
|
||||
template <std::size_t OpId, typename Geometry>
|
||||
struct for_each_disjoint_linestring_if<OpId, Geometry, linestring_tag>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
if ( first != last )
|
||||
return false;
|
||||
pred(geometry);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename Geometry>
|
||||
struct for_each_disjoint_linestring_if<OpId, Geometry, multi_linestring_tag>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
BOOST_ASSERT(first != last);
|
||||
|
||||
std::size_t count = boost::size(geometry);
|
||||
std::vector<bool> detected_intersections(count, false);
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
int multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_ASSERT(multi_index >= 0);
|
||||
std::size_t index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_ASSERT(index < count);
|
||||
detected_intersections[index] = true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
|
||||
it != detected_intersections.end() ; ++it )
|
||||
{
|
||||
// if there were no intersections for this multi_index
|
||||
if ( *it == false )
|
||||
{
|
||||
found = true;
|
||||
bool cont = pred(
|
||||
*(boost::begin(geometry)
|
||||
+ std::distance(detected_intersections.begin(), it)));
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename Result, typename BoundaryChecker>
|
||||
template <typename Result, typename BoundaryChecker, bool TransposeResult>
|
||||
class disjoint_linestring_pred
|
||||
{
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
disjoint_linestring_pred(Result & res,
|
||||
BoundaryChecker & boundary_checker)
|
||||
BoundaryChecker const& boundary_checker)
|
||||
: m_result_ptr(boost::addressof(res))
|
||||
, m_boundary_checker_ptr(boost::addressof(boundary_checker))
|
||||
{}
|
||||
@@ -151,7 +51,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
update<interior, exterior, '1', transpose_result>(*m_result_ptr);
|
||||
update<interior, exterior, '1', TransposeResult>(*m_result_ptr);
|
||||
|
||||
// check if there is a boundary
|
||||
if ( m_boundary_checker_ptr->template
|
||||
@@ -159,7 +59,7 @@ public:
|
||||
|| m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
update<boundary, exterior, '0', TransposeResult>(*m_result_ptr);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -169,95 +69,128 @@ public:
|
||||
|
||||
private:
|
||||
Result * m_result_ptr;
|
||||
BoundaryChecker * m_boundary_checker_ptr;
|
||||
const BoundaryChecker * m_boundary_checker_ptr;
|
||||
};
|
||||
|
||||
//enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open };
|
||||
//
|
||||
//template <typename Linestring>
|
||||
//linestring_kind check_linestring_kind(Linestring const& ls)
|
||||
//{
|
||||
// std::size_t count = boost::size(ls);
|
||||
// if ( count == 0 )
|
||||
// return linestring_exterior;
|
||||
// else if ( count == 1 )
|
||||
// return linestring_point;
|
||||
// else
|
||||
// {
|
||||
// bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls));
|
||||
// if ( equal_fb )
|
||||
// {
|
||||
// typedef typename boost::range_iterator<Linestring const>::type iterator;
|
||||
// iterator first = boost::begin(ls);
|
||||
// ++first;
|
||||
// iterator last = boost::end(ls);
|
||||
// --last;
|
||||
// for ( iterator it = first ; it != last ; ++it )
|
||||
// {
|
||||
// if ( !equals::equals_point_point(range::front(ls), *it) )
|
||||
// return linestring_closed;
|
||||
// }
|
||||
//
|
||||
// return linestring_point;
|
||||
// }
|
||||
// else
|
||||
// return linestring_open;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Called in a loop for:
|
||||
// Ls/Ls - worst O(N) - 1x point_in_geometry(MLs)
|
||||
// Ls/MLs - worst O(N) - 1x point_in_geometry(MLs)
|
||||
// MLs/Ls - worst O(N^2) - Bx point_in_geometry(Ls)
|
||||
// MLs/MLs - worst O(N^2) - Bx point_in_geometry(Ls)
|
||||
// TODO: later use spatial index
|
||||
template <std::size_t OpId, typename Result, typename BoundaryChecker, typename OtherGeometry>
|
||||
class disjoint_linestring_pred_with_point_size_handling
|
||||
{
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
disjoint_linestring_pred_with_point_size_handling(Result & res,
|
||||
BoundaryChecker & boundary_checker,
|
||||
OtherGeometry const& other_geometry)
|
||||
: m_result_ptr(boost::addressof(res))
|
||||
, m_boundary_checker_ptr(boost::addressof(boundary_checker))
|
||||
, m_other_geometry(boost::addressof(other_geometry))
|
||||
, m_detected_mask_point(0)
|
||||
, m_detected_open_boundary(false)
|
||||
{}
|
||||
|
||||
template <typename Linestring>
|
||||
bool operator()(Linestring const& linestring)
|
||||
{
|
||||
linestring_kind lk = check_linestring_kind(linestring);
|
||||
|
||||
if ( lk == linestring_point ) // just an optimization
|
||||
{
|
||||
if ( m_detected_mask_point != 7 )
|
||||
{
|
||||
// check the relation
|
||||
int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry);
|
||||
|
||||
// point inside
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 1;
|
||||
}
|
||||
// point on boundary
|
||||
else if ( pig == 0 )
|
||||
{
|
||||
update<interior, boundary, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 2;
|
||||
}
|
||||
// point outside
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: For closed Linestrings I/I=1 could be set automatically
|
||||
// but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary
|
||||
else if ( lk == linestring_open || lk == linestring_closed )
|
||||
{
|
||||
if ( !m_detected_open_boundary ) // just an optimization
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(*m_result_ptr);
|
||||
|
||||
// check if there is a boundary
|
||||
if ( m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
|| m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
|
||||
m_detected_open_boundary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary;
|
||||
return !all_detected && !m_result_ptr->interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
Result * m_result_ptr;
|
||||
BoundaryChecker * m_boundary_checker_ptr;
|
||||
const OtherGeometry * m_other_geometry;
|
||||
char m_detected_mask_point;
|
||||
bool m_detected_open_boundary;
|
||||
};
|
||||
//template <std::size_t OpId, typename Result, typename BoundaryChecker, typename OtherGeometry>
|
||||
//class disjoint_linestring_pred_with_point_size_handling
|
||||
//{
|
||||
// static const bool transpose_result = OpId != 0;
|
||||
//
|
||||
//public:
|
||||
// disjoint_linestring_pred_with_point_size_handling(Result & res,
|
||||
// BoundaryChecker & boundary_checker,
|
||||
// OtherGeometry const& other_geometry)
|
||||
// : m_result_ptr(boost::addressof(res))
|
||||
// , m_boundary_checker_ptr(boost::addressof(boundary_checker))
|
||||
// , m_other_geometry(boost::addressof(other_geometry))
|
||||
// , m_detected_mask_point(0)
|
||||
// , m_detected_open_boundary(false)
|
||||
// {}
|
||||
//
|
||||
// template <typename Linestring>
|
||||
// bool operator()(Linestring const& linestring)
|
||||
// {
|
||||
// linestring_kind lk = check_linestring_kind(linestring);
|
||||
//
|
||||
// if ( lk == linestring_point ) // just an optimization
|
||||
// {
|
||||
// if ( m_detected_mask_point != 7 )
|
||||
// {
|
||||
// // check the relation
|
||||
// int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry);
|
||||
//
|
||||
// // point inside
|
||||
// if ( pig > 0 )
|
||||
// {
|
||||
// update<interior, interior, '0', transpose_result>(*m_result_ptr);
|
||||
// m_detected_mask_point |= 1;
|
||||
// }
|
||||
// // point on boundary
|
||||
// else if ( pig == 0 )
|
||||
// {
|
||||
// update<interior, boundary, '0', transpose_result>(*m_result_ptr);
|
||||
// m_detected_mask_point |= 2;
|
||||
// }
|
||||
// // point outside
|
||||
// else
|
||||
// {
|
||||
// update<interior, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
// m_detected_mask_point |= 4;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // NOTE: For closed Linestrings I/I=1 could be set automatically
|
||||
// // but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary
|
||||
// else if ( lk == linestring_open || lk == linestring_closed )
|
||||
// {
|
||||
// if ( !m_detected_open_boundary ) // just an optimization
|
||||
// {
|
||||
// update<interior, exterior, '1', transpose_result>(*m_result_ptr);
|
||||
//
|
||||
// // check if there is a boundary
|
||||
// if ( m_boundary_checker_ptr->template
|
||||
// is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
// || m_boundary_checker_ptr->template
|
||||
// is_endpoint_boundary<boundary_back>(range::back(linestring)) )
|
||||
// {
|
||||
// update<boundary, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
//
|
||||
// m_detected_open_boundary = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary;
|
||||
// return !all_detected && !m_result_ptr->interrupt;
|
||||
// }
|
||||
//
|
||||
//private:
|
||||
// Result * m_result_ptr;
|
||||
// BoundaryChecker * m_boundary_checker_ptr;
|
||||
// const OtherGeometry * m_other_geometry;
|
||||
// char m_detected_mask_point;
|
||||
// bool m_detected_open_boundary;
|
||||
//};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct linear_linear
|
||||
@@ -280,19 +213,22 @@ struct linear_linear
|
||||
typedef typename std::vector<turn_type>::iterator turn_iterator;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
// TODO: INTEGRATE INTERRUPT POLICY WITH THE PASSED RESULT
|
||||
interrupt_policy_linear_linear<Result> interrupt_policy(result);
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2);
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
|
||||
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
boundary_checker<Geometry1> boundary_checker1(geometry1);
|
||||
disjoint_linestring_pred<0, Result, boundary_checker<Geometry1> > pred1(result, boundary_checker1);
|
||||
for_each_disjoint_linestring_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
boundary_checker<Geometry2> boundary_checker2(geometry2);
|
||||
disjoint_linestring_pred<1, Result, boundary_checker<Geometry2> > pred2(result, boundary_checker2);
|
||||
for_each_disjoint_linestring_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2);
|
||||
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
@@ -305,6 +241,7 @@ struct linear_linear
|
||||
// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
|
||||
|
||||
{
|
||||
// x, u, i, c
|
||||
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>());
|
||||
|
||||
turns_analyser<0, turn_type> analyser;
|
||||
@@ -318,6 +255,7 @@ struct linear_linear
|
||||
return;
|
||||
|
||||
{
|
||||
// x, u, i, c
|
||||
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,1>());
|
||||
|
||||
turns_analyser<1, turn_type> analyser;
|
||||
@@ -328,147 +266,47 @@ struct linear_linear
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rename to point_id_ref?
|
||||
template <typename Point>
|
||||
class point_identifier
|
||||
template <typename Result>
|
||||
class interrupt_policy_linear_linear
|
||||
{
|
||||
public:
|
||||
point_identifier() : sid_ptr(0), pt_ptr(0) {}
|
||||
point_identifier(segment_identifier const& sid, Point const& pt)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
, pt_ptr(boost::addressof(pt))
|
||||
{}
|
||||
segment_identifier const& seg_id() const
|
||||
{
|
||||
BOOST_ASSERT(sid_ptr);
|
||||
return *sid_ptr;
|
||||
}
|
||||
Point const& point() const
|
||||
{
|
||||
BOOST_ASSERT(pt_ptr);
|
||||
return *pt_ptr;
|
||||
}
|
||||
static bool const enabled = true;
|
||||
|
||||
//friend bool operator==(point_identifier const& l, point_identifier const& r)
|
||||
//{
|
||||
// return l.seg_id() == r.seg_id()
|
||||
// && detail::equals::equals_point_point(l.point(), r.point());
|
||||
//}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
const Point * pt_ptr;
|
||||
};
|
||||
|
||||
class same_ranges
|
||||
{
|
||||
public:
|
||||
same_ranges(segment_identifier const& sid)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
explicit interrupt_policy_linear_linear(Result & result)
|
||||
: m_result(result)
|
||||
{}
|
||||
|
||||
bool operator()(segment_identifier const& sid) const
|
||||
// TODO: since we update result for some operations here, we must not do it in the analyser!
|
||||
|
||||
template <typename Range>
|
||||
inline bool apply(Range const& turns)
|
||||
{
|
||||
return sid.multi_index == sid_ptr->multi_index
|
||||
&& sid.ring_index == sid_ptr->ring_index;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool operator()(point_identifier<Point> const& pid) const
|
||||
{
|
||||
return operator()(pid.seg_id());
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
class segment_watcher
|
||||
{
|
||||
public:
|
||||
segment_watcher()
|
||||
: m_seg_id_ptr(0)
|
||||
{}
|
||||
|
||||
bool update(segment_identifier const& seg_id)
|
||||
{
|
||||
bool result = m_seg_id_ptr == 0 || !same_ranges(*m_seg_id_ptr)(seg_id);
|
||||
m_seg_id_ptr = boost::addressof(seg_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * m_seg_id_ptr;
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
class exit_watcher
|
||||
{
|
||||
typedef point_identifier<Point> point_info;
|
||||
|
||||
public:
|
||||
exit_watcher()
|
||||
: exit_operation(overlay::operation_none)
|
||||
{}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool enter(Point const& point, segment_identifier const& other_id)
|
||||
{
|
||||
bool result = other_entry_points.empty();
|
||||
other_entry_points.push_back(point_info(other_id, point));
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool exit(Point const& point,
|
||||
segment_identifier const& other_id,
|
||||
overlay::operation_type exit_op)
|
||||
{
|
||||
// if we didn't entered anything in the past, we're outside
|
||||
if ( other_entry_points.empty() )
|
||||
return true;
|
||||
|
||||
typedef typename std::vector<point_info>::iterator point_iterator;
|
||||
// search for the entry point in the same range of other geometry
|
||||
point_iterator entry_it = std::find_if(other_entry_points.begin(),
|
||||
other_entry_points.end(),
|
||||
same_ranges(other_id));
|
||||
|
||||
// this end point has corresponding entry point
|
||||
if ( entry_it != other_entry_points.end() )
|
||||
typedef typename boost::range_iterator<Range const>::type iterator;
|
||||
|
||||
for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
{
|
||||
// here we know that we possibly left LS
|
||||
// we must still check if we didn't get back on the same point
|
||||
exit_operation = exit_op;
|
||||
exit_id = point_info(other_id, point);
|
||||
|
||||
// erase the corresponding entry point
|
||||
other_entry_points.erase(entry_it);
|
||||
if ( it->operations[0].operation == overlay::operation_intersection
|
||||
|| it->operations[1].operation == overlay::operation_intersection )
|
||||
{
|
||||
update<interior, interior, '1'>(m_result);
|
||||
}
|
||||
else if ( ( it->operations[0].operation == overlay::operation_union
|
||||
|| it->operations[0].operation == overlay::operation_blocked
|
||||
|| it->operations[1].operation == overlay::operation_union
|
||||
|| it->operations[1].operation == overlay::operation_blocked )
|
||||
&& it->operations[0].position == overlay::position_middle
|
||||
&& it->operations[1].position == overlay::position_middle )
|
||||
{
|
||||
// TODO: here we could also check the boundaries and set IB,BI,BB at this point
|
||||
update<interior, interior, '0'>(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay::operation_type get_exit_operation() const
|
||||
{
|
||||
return exit_operation;
|
||||
}
|
||||
|
||||
Point const& get_exit_point() const
|
||||
{
|
||||
BOOST_ASSERT(exit_operation != overlay::operation_none);
|
||||
return exit_id.point();
|
||||
}
|
||||
|
||||
void reset_detected_exit()
|
||||
{
|
||||
exit_operation = overlay::operation_none;
|
||||
return m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
overlay::operation_type exit_operation;
|
||||
point_info exit_id;
|
||||
std::vector<point_info> other_entry_points; // TODO: use map here or sorted vector?
|
||||
Result & m_result;
|
||||
};
|
||||
|
||||
// This analyser should be used like Input or SinglePass Iterator
|
||||
@@ -497,8 +335,8 @@ struct linear_linear
|
||||
TurnIt first, TurnIt it, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker & boundary_checker,
|
||||
OtherBoundaryChecker & other_boundary_checker)
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& other_boundary_checker)
|
||||
{
|
||||
if ( it != last )
|
||||
{
|
||||
@@ -549,30 +387,32 @@ struct linear_linear
|
||||
// but the previous one went out on the previous point,
|
||||
// we must check if the boundary of the previous segment is outside
|
||||
// NOTE: couldn't it be integrated with the handling of the union above?
|
||||
if ( first_in_range
|
||||
&& ! fake_enter_detected
|
||||
&& m_previous_operation == overlay::operation_union )
|
||||
{
|
||||
BOOST_ASSERT(it != first);
|
||||
BOOST_ASSERT(m_previous_turn_ptr);
|
||||
// THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE
|
||||
//if ( first_in_range
|
||||
// && ! fake_enter_detected
|
||||
// && m_previous_operation == overlay::operation_union )
|
||||
//{
|
||||
// BOOST_ASSERT(it != first);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
// boundary_checker);
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
// // if there is a boundary on the last point
|
||||
// if ( prev_back_b )
|
||||
// {
|
||||
// update<boundary, exterior, '0', transpose_result>(res);
|
||||
// }
|
||||
//}
|
||||
|
||||
// i/i, i/x, i/u
|
||||
if ( op == overlay::operation_intersection )
|
||||
{
|
||||
bool was_outside = m_exit_watcher.enter(it->point, other_id);
|
||||
bool was_outside = m_exit_watcher.is_outside();
|
||||
m_exit_watcher.enter(it->point, other_id);
|
||||
|
||||
// interiors overlaps
|
||||
update<interior, interior, '1', transpose_result>(res);
|
||||
@@ -629,11 +469,23 @@ struct linear_linear
|
||||
// u/i, u/u, u/x, x/i, x/u, x/x
|
||||
else if ( op == overlay::operation_union || op == overlay::operation_blocked )
|
||||
{
|
||||
bool op_blocked = op == overlay::operation_blocked;
|
||||
bool was_outside = m_exit_watcher.exit(it->point, other_id, op);
|
||||
// TODO: is exit watcher still needed?
|
||||
// couldn't is_collinear and some going inside counter be used instead?
|
||||
|
||||
// we're inside, possibly going out right now
|
||||
if ( ! was_outside )
|
||||
bool is_collinear = it->operations[op_id].is_collinear;
|
||||
bool was_outside = m_exit_watcher.is_outside();
|
||||
|
||||
// to exit we must be currently inside and the current segment must be collinear
|
||||
if ( !was_outside && is_collinear )
|
||||
{
|
||||
m_exit_watcher.exit(it->point, other_id, op);
|
||||
}
|
||||
|
||||
bool op_blocked = op == overlay::operation_blocked;
|
||||
|
||||
// we're inside and going out from inside
|
||||
// possibly going out right now
|
||||
if ( ! was_outside && is_collinear )
|
||||
{
|
||||
if ( op_blocked )
|
||||
{
|
||||
@@ -658,14 +510,19 @@ struct linear_linear
|
||||
}
|
||||
}
|
||||
}
|
||||
// we're outside
|
||||
// we're outside or intersects some segment from the outside
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
// if we are truly outside
|
||||
if ( was_outside /*&& !is_collinear*/ )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
}
|
||||
|
||||
// boundaries don't overlap - just an optimization
|
||||
if ( it->method == overlay::method_crosses )
|
||||
{
|
||||
// the L1 is going from one side of the L2 to the other through the point
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
|
||||
// it's the first point in range
|
||||
@@ -715,7 +572,7 @@ struct linear_linear
|
||||
}
|
||||
|
||||
// first IP on the last segment point - this means that the first point is outside
|
||||
if ( first_in_range && ( !this_b || op_blocked ) )
|
||||
if ( first_in_range && ( !this_b || op_blocked ) && was_outside /*&& !is_collinear*/ )
|
||||
{
|
||||
bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_geometry::get(geometry, seg_id)),
|
||||
@@ -742,8 +599,8 @@ struct linear_linear
|
||||
{
|
||||
// here, the possible exit is the real one
|
||||
// we know that we entered and now we exit
|
||||
if ( m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
|
||||
|| m_previous_operation == overlay::operation_union )
|
||||
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
|
||||
||*/ m_previous_operation == overlay::operation_union )
|
||||
{
|
||||
// for sure
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
@@ -751,7 +608,7 @@ struct linear_linear
|
||||
BOOST_ASSERT(first != last);
|
||||
BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[OpId].seg_id;
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
@@ -763,67 +620,14 @@ struct linear_linear
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
|
||||
// Just in case,
|
||||
// reset exit watcher before the analysis of the next Linestring
|
||||
// note that if there are some enters stored there may be some error above
|
||||
m_exit_watcher.reset();
|
||||
}
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename Point,
|
||||
typename BoundaryChecker>
|
||||
static inline
|
||||
bool is_endpoint_on_boundary(Point const& pt,
|
||||
BoundaryChecker & boundary_checker)
|
||||
{
|
||||
return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename IntersectionPoint,
|
||||
typename OperationInfo,
|
||||
typename BoundaryChecker>
|
||||
static inline
|
||||
bool is_ip_on_boundary(IntersectionPoint const& ip,
|
||||
OperationInfo const& operation_info,
|
||||
BoundaryChecker & boundary_checker,
|
||||
segment_identifier const& seg_id)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(seg_id);
|
||||
|
||||
bool res = false;
|
||||
|
||||
// IP on the last point of the linestring
|
||||
if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& operation_info.operation == overlay::operation_blocked )
|
||||
{
|
||||
BOOST_ASSERT(operation_info.position == overlay::position_back);
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP on the last point of the linestring
|
||||
else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
|
||||
&& operation_info.position == overlay::position_front )
|
||||
{
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP somewhere in the interior
|
||||
else
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
exit_watcher<turn_point_type> m_exit_watcher;
|
||||
segment_watcher m_seg_watcher;
|
||||
@@ -843,8 +647,8 @@ struct linear_linear
|
||||
TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker & boundary_checker,
|
||||
OtherBoundaryChecker & other_boundary_checker)
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& other_boundary_checker)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
@@ -863,140 +667,6 @@ struct linear_linear
|
||||
geometry, other_geometry,
|
||||
boundary_checker, other_boundary_checker);
|
||||
}
|
||||
|
||||
//template <typename TurnIt>
|
||||
//static inline void analyse_turns_simple(result & res,
|
||||
// TurnIt first, TurnIt last,
|
||||
// Geometry1 const& geometry1,
|
||||
// Geometry2 const& geometry2,
|
||||
// bool has_boundary1, bool has_boundary2)
|
||||
//{
|
||||
// for ( TurnIt it = first ; it != last ; ++it )
|
||||
// {
|
||||
// // 'i'
|
||||
// if ( it->method == overlay::method_crosses )
|
||||
// {
|
||||
// res.template update<interior, interior, '0'>(); // always true
|
||||
// res.template update<interior, exterior, '1'>(); // not always true
|
||||
// res.template update<exterior, interior, '1'>(); // not always true
|
||||
// }
|
||||
// // 'e' 'c'
|
||||
// else if ( it->method == overlay::method_equal
|
||||
// || it->method == overlay::method_collinear )
|
||||
// {
|
||||
// res.template update<interior, interior, '1'>(); // always true
|
||||
// }
|
||||
// // 't' 'm'
|
||||
// else if ( it->method == overlay::method_touch
|
||||
// || it->method == overlay::method_touch_interior )
|
||||
// {
|
||||
// bool b = handle_boundary_point(res, *it, geometry1, geometry2, has_boundary1, has_boundary2);
|
||||
//
|
||||
// if ( it->has(overlay::operation_union) )
|
||||
// {
|
||||
// if ( !b )
|
||||
// res.template update<interior, interior, '0'>();
|
||||
// if ( it->operations[0].operation == overlay::operation_union )
|
||||
// res.template update<interior, exterior, '1'>();
|
||||
// if ( it->operations[1].operation == overlay::operation_union )
|
||||
// res.template update<exterior, interior, '1'>();
|
||||
// }
|
||||
|
||||
// if ( it->has(overlay::operation_intersection) )
|
||||
// res.template update<interior, interior, '1'>();
|
||||
|
||||
// if ( it->has(overlay::operation_blocked) )
|
||||
// if ( !b )
|
||||
// res.template update<interior, interior, '0'>();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
||||
|
||||
//template <typename Turn>
|
||||
//static inline bool handle_boundary_point(result & res,
|
||||
// Turn const& turn,
|
||||
// Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
// bool has_boundary1, bool has_boundary2)
|
||||
//{
|
||||
// bool pt_on_boundary1 = has_boundary1 && equals_terminal_point(turn.point, geometry1);
|
||||
// bool pt_on_boundary2 = has_boundary2 && equals_terminal_point(turn.point, geometry2);
|
||||
|
||||
// if ( pt_on_boundary1 && pt_on_boundary2 )
|
||||
// res.template update<boundary, boundary, '0'>();
|
||||
// else if ( pt_on_boundary1 )
|
||||
// res.template update<boundary, interior, '0'>();
|
||||
// else if ( pt_on_boundary2 )
|
||||
// res.template update<interior, boundary, '0'>();
|
||||
// else
|
||||
// return false;
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//// TODO: replace with generic point_in_boundary working also for multilinestrings
|
||||
//template <typename Point, typename Geometry>
|
||||
//static inline bool equals_terminal_point(Point const& point, Geometry const& geometry)
|
||||
//{
|
||||
// return detail::equals::equals_point_point(point, range::front(geometry))
|
||||
// || detail::equals::equals_point_point(point, range::back(geometry));
|
||||
//}
|
||||
|
||||
//static inline void handle_boundaries(result & res,
|
||||
// Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
// bool has_boundary1, bool has_boundary2)
|
||||
//{
|
||||
// int pig_front = detail::within::point_in_geometry(range::front(geometry1), geometry2);
|
||||
|
||||
// if ( has_boundary1 )
|
||||
// {
|
||||
// int pig_back = detail::within::point_in_geometry(range::back(geometry1), geometry2);
|
||||
|
||||
// if ( pig_front > 0 || pig_back > 0 )
|
||||
// res.template set<boundary, interior, '0'>();
|
||||
// if ( pig_front == 0 || pig_back == 0 )
|
||||
// res.template set<boundary, boundary, '0'>();
|
||||
// if ( pig_front < 0 || pig_back < 0 )
|
||||
// {
|
||||
// res.template set<boundary, exterior, '0'>();
|
||||
// res.template set<interior, exterior, '1'>();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if ( pig_front > 0 )
|
||||
// res.template set<interior, interior, '0'>();
|
||||
// else if ( pig_front == 0 )
|
||||
// res.template set<interior, boundary, '0'>();
|
||||
// else if ( pig_front < 0 )
|
||||
// res.template set<interior, exterior, '0'>();
|
||||
// }
|
||||
|
||||
// pig_front = detail::within::point_in_geometry(range::front(geometry2), geometry1);
|
||||
|
||||
// if ( has_boundary2 )
|
||||
// {
|
||||
// int pig_back = detail::within::point_in_geometry(range::back(geometry2), geometry1);
|
||||
|
||||
// if ( pig_front > 0 || pig_back > 0 )
|
||||
// res.template set<interior, boundary, '0'>();
|
||||
// if ( pig_front == 0 || pig_back == 0 )
|
||||
// res.template set<boundary, boundary, '0'>();
|
||||
// if ( pig_front < 0 || pig_back < 0 )
|
||||
// {
|
||||
// res.template set<exterior, boundary, '0'>();
|
||||
// res.template set<exterior, interior, '1'>();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if ( pig_front > 0 )
|
||||
// res.template set<interior, interior, '0'>();
|
||||
// else if ( pig_front == 0 )
|
||||
// res.template set<boundary, interior, '0'>();
|
||||
// else if ( pig_front < 0 )
|
||||
// res.template set<exterior, interior, '0'>();
|
||||
// }
|
||||
//}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <boost/geometry/algorithms/detail/relate/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
@@ -120,6 +121,26 @@ struct relate<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_li
|
||||
: detail::relate::linear_linear<MultiLinestring1, MultiLinestring2>
|
||||
{};
|
||||
|
||||
template <typename Linestring, typename Polygon>
|
||||
struct relate<Linestring, Polygon, linestring_tag, polygon_tag>
|
||||
: detail::relate::linear_areal<Linestring, Polygon>
|
||||
{};
|
||||
|
||||
template <typename Polygon, typename Linestring>
|
||||
struct relate<Polygon, Linestring, polygon_tag, linestring_tag>
|
||||
: detail::relate::areal_linear<Polygon, Linestring>
|
||||
{};
|
||||
|
||||
template <typename Linestring, typename MultiPolygon>
|
||||
struct relate<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
|
||||
: detail::relate::linear_areal<Linestring, MultiPolygon>
|
||||
{};
|
||||
|
||||
template <typename MultiPolygon, typename Linestring>
|
||||
struct relate<MultiPolygon, Linestring, multi_polygon_tag, linestring_tag>
|
||||
: detail::relate::areal_linear<MultiPolygon, Linestring>
|
||||
{};
|
||||
|
||||
}} // namespace detail_dispatch::relate
|
||||
|
||||
namespace detail { namespace relate {
|
||||
@@ -132,9 +153,83 @@ struct interruption_enabled
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename Result>
|
||||
inline void relate(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
|
||||
struct result_handler_type
|
||||
: not_implemented<Result>
|
||||
{};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct result_handler_type<Geometry1, Geometry2, matrix9>
|
||||
{
|
||||
return detail_dispatch::relate::relate<Geometry1, Geometry2>::apply(geometry1, geometry2, result);
|
||||
typedef matrix_handler<matrix9> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct result_handler_type<Geometry1, Geometry2, mask9>
|
||||
{
|
||||
typedef mask_handler
|
||||
<
|
||||
mask9,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
|
||||
struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail> >
|
||||
{
|
||||
typedef mask_handler
|
||||
<
|
||||
boost::tuples::cons<Head, Tail>,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2,
|
||||
char II, char IB, char IE,
|
||||
char BI, char BB, char BE,
|
||||
char EI, char EB, char EE>
|
||||
struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> >
|
||||
{
|
||||
typedef static_mask_handler
|
||||
<
|
||||
static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename MatrixOrMask, typename Geometry1, typename Geometry2>
|
||||
inline
|
||||
typename result_handler_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
MatrixOrMask
|
||||
>::type::result_type
|
||||
relate(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
MatrixOrMask const& matrix_or_mask = MatrixOrMask())
|
||||
{
|
||||
typedef typename result_handler_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
MatrixOrMask
|
||||
>::type handler_type;
|
||||
|
||||
handler_type handler(matrix_or_mask);
|
||||
detail_dispatch::relate::relate<Geometry1, Geometry2>::apply(geometry1, geometry2, handler);
|
||||
return handler.result();
|
||||
}
|
||||
|
||||
}} // namespace detail::relate
|
||||
|
||||
@@ -2,16 +2,25 @@
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013.
|
||||
// Modifications copyright (c) 2013, Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013, 2014.
|
||||
// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
#include <boost/mpl/at.hpp>
|
||||
|
||||
// TEMP - move this header to geometry/detail
|
||||
#include <boost/geometry/index/detail/tuples.hpp>
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
@@ -19,128 +28,866 @@ namespace detail { namespace relate {
|
||||
|
||||
enum field { interior = 0, boundary = 1, exterior = 2 };
|
||||
|
||||
// With DE9IM only Dimension < 10 is supported
|
||||
class result
|
||||
// TODO add height?
|
||||
|
||||
template <std::size_t Width>
|
||||
class matrix
|
||||
{
|
||||
BOOST_STATIC_ASSERT(Width == 2 || Width == 3);
|
||||
|
||||
public:
|
||||
|
||||
static const bool interrupt = false;
|
||||
|
||||
// TODO: replace with std::string?
|
||||
inline result()
|
||||
static const std::size_t size = Width * Width;
|
||||
|
||||
inline matrix()
|
||||
{
|
||||
::memset(m_array, 'F', 9);
|
||||
::memset(m_array, 'F', size);
|
||||
}
|
||||
|
||||
template <field F1, field F2>
|
||||
inline char get() const
|
||||
{
|
||||
return m_array[F1 * 3 + F2];
|
||||
static const bool in_bounds = F1 * Width + F2 < size;
|
||||
return get_dispatch<F1, F2>(integral_constant<bool, in_bounds>());
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set()
|
||||
{
|
||||
m_array[F1 * 3 + F2] = V;
|
||||
static const bool in_bounds = F1 * Width + F2 < size;
|
||||
set_dispatch<F1, F2, V>(integral_constant<bool, in_bounds>());
|
||||
}
|
||||
|
||||
inline std::pair<const char*, const char*> get_code() const
|
||||
template <field F1, field F2, char D>
|
||||
inline void update()
|
||||
{
|
||||
return std::make_pair(m_array, m_array+9);
|
||||
static const bool in_bounds = F1 * Width + F2 < size;
|
||||
update_dispatch<F1, F2, D>(integral_constant<bool, in_bounds>());
|
||||
}
|
||||
|
||||
inline const char * data() const
|
||||
{
|
||||
return m_array;
|
||||
}
|
||||
|
||||
private:
|
||||
char m_array[9];
|
||||
template <field F1, field F2>
|
||||
inline char get_dispatch(integral_constant<bool, true>) const
|
||||
{
|
||||
return m_array[F1 * Width + F2];
|
||||
}
|
||||
template <field F1, field F2>
|
||||
inline char get_dispatch(integral_constant<bool, false>) const
|
||||
{
|
||||
return 'F';
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set_dispatch(integral_constant<bool, true>)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F');
|
||||
m_array[F1 * Width + F2] = V;
|
||||
}
|
||||
template <field F1, field F2, char V>
|
||||
inline void set_dispatch(integral_constant<bool, false>)
|
||||
{}
|
||||
|
||||
template <field F1, field F2, char D>
|
||||
inline void update_dispatch(integral_constant<bool, true>)
|
||||
{
|
||||
BOOST_STATIC_ASSERT('0' <= D && D <= '9');
|
||||
char c = m_array[F1 * Width + F2];
|
||||
if ( D > c || c > '9')
|
||||
m_array[F1 * Width + F2] = D;
|
||||
}
|
||||
template <field F1, field F2, char D>
|
||||
inline void update_dispatch(integral_constant<bool, false>)
|
||||
{}
|
||||
|
||||
char m_array[size];
|
||||
};
|
||||
|
||||
// TODO: possible optimizations
|
||||
// 1. interrupt in a template xxx<Interrupt> make it static const if Interrupt == false
|
||||
// 2. static_mask<II, IB, IE, ...> setting interrupt in compile-time
|
||||
// TODO add EnableDimensions parameter?
|
||||
|
||||
template <bool Interrupt>
|
||||
class mask
|
||||
: public result
|
||||
struct matrix9 {};
|
||||
//struct matrix4 {};
|
||||
|
||||
template <typename MatrixOrMask>
|
||||
struct matrix_width
|
||||
: not_implemented<MatrixOrMask>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct matrix_width<matrix9>
|
||||
{
|
||||
static const std::size_t value = 3;
|
||||
};
|
||||
|
||||
template <typename Matrix>
|
||||
class matrix_handler
|
||||
: private matrix<matrix_width<Matrix>::value>
|
||||
{
|
||||
typedef matrix<matrix_width<Matrix>::value> base_t;
|
||||
|
||||
public:
|
||||
typedef std::string result_type;
|
||||
|
||||
static const bool interrupt = false;
|
||||
|
||||
matrix_handler(Matrix const&)
|
||||
{}
|
||||
|
||||
result_type result() const
|
||||
{
|
||||
return std::string(this->data(),
|
||||
this->data() + base_t::size);
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set()
|
||||
{
|
||||
static_cast<base_t&>(*this).template set<F1, F2, V>();
|
||||
}
|
||||
|
||||
template <field F1, field F2, char D>
|
||||
inline void update()
|
||||
{
|
||||
static_cast<base_t&>(*this).template update<F1, F2, D>();
|
||||
}
|
||||
};
|
||||
|
||||
// RUN-TIME MASKS
|
||||
|
||||
class mask9
|
||||
{
|
||||
public:
|
||||
static const std::size_t width = 3; // TEMP
|
||||
|
||||
bool interrupt;
|
||||
|
||||
inline mask(std::string const& de9im_mask)
|
||||
: interrupt(false)
|
||||
inline mask9(std::string const& de9im_mask)
|
||||
{
|
||||
// TODO: throw an exception here?
|
||||
BOOST_ASSERT(de9im_mask.size() == 9);
|
||||
::memcpy(m_mask, de9im_mask.c_str(), 9);
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set()
|
||||
{
|
||||
handle_interrupt_dispatch<F1, F2, V>(boost::integral_constant<bool, Interrupt>());
|
||||
|
||||
result::set<F1, F2, V>();
|
||||
}
|
||||
|
||||
inline bool check() const
|
||||
{
|
||||
if ( interrupt )
|
||||
return false;
|
||||
|
||||
std::pair<const char*, const char*> range = result::get_code();
|
||||
const char* m_it = m_mask;
|
||||
const char* a_it = range.first;
|
||||
for ( ; a_it != range.second ; ++a_it, ++m_it )
|
||||
{
|
||||
if ( *m_it == 'F' )
|
||||
{
|
||||
if ( *a_it != 'F' )
|
||||
return false;
|
||||
}
|
||||
else if ( *m_it == 'T' )
|
||||
{
|
||||
if ( *a_it != 'T' && ( *a_it < '0' || *a_it > '9' ) )
|
||||
return false;
|
||||
}
|
||||
else if ( *m_it >= '0' && *m_it <= '9' )
|
||||
{
|
||||
if ( *a_it != *m_it )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
template <field F1, field F2, char V>
|
||||
void handle_interrupt_dispatch(boost::integral_constant<bool, false>)
|
||||
{}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
void handle_interrupt_dispatch(boost::integral_constant<bool, true>)
|
||||
{
|
||||
char m = get_mask<F1, F2>();
|
||||
|
||||
if ( V >= '0' && V <= '9' )
|
||||
{
|
||||
if ( m == 'F' || ( m < V && m >= '0' && m <= '9' ) )
|
||||
interrupt = true;
|
||||
}
|
||||
else if ( V == 'T' )
|
||||
{
|
||||
if ( m == 'F' )
|
||||
interrupt = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <field F1, field F2>
|
||||
inline char get_mask() const
|
||||
inline char get() const
|
||||
{
|
||||
return m_mask[F1 * 3 + F2];
|
||||
}
|
||||
|
||||
private:
|
||||
char m_mask[9];
|
||||
};
|
||||
|
||||
template <typename Mask, bool InterruptEnabled>
|
||||
struct interrupt_dispatch
|
||||
{
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(Mask const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mask>
|
||||
struct interrupt_dispatch<Mask, true>
|
||||
{
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(Mask const& mask)
|
||||
{
|
||||
char m = mask.template get<F1, F2>();
|
||||
return check<V>(m);
|
||||
}
|
||||
|
||||
template <char V>
|
||||
static inline bool check(char m)
|
||||
{
|
||||
if ( V >= '0' && V <= '9' )
|
||||
{
|
||||
return m == 'F' || ( m < V && m >= '0' && m <= '9' );
|
||||
}
|
||||
else if ( V == 'T' )
|
||||
{
|
||||
return m == 'F';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
|
||||
struct interrupt_dispatch_tuple
|
||||
{
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(Masks const& masks)
|
||||
{
|
||||
typedef typename boost::tuples::element<I, Masks>::type mask_type;
|
||||
mask_type const& mask = boost::get<I>(masks);
|
||||
return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask)
|
||||
&& interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Masks, int N>
|
||||
struct interrupt_dispatch_tuple<Masks, N, N>
|
||||
{
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(Masks const& )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8, typename T9>
|
||||
struct interrupt_dispatch<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, true>
|
||||
{
|
||||
typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(mask_type const& mask)
|
||||
{
|
||||
return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Head, typename Tail>
|
||||
struct interrupt_dispatch<boost::tuples::cons<Head, Tail>, true>
|
||||
{
|
||||
typedef boost::tuples::cons<Head, Tail> mask_type;
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
static inline bool apply(mask_type const& mask)
|
||||
{
|
||||
return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <field F1, field F2, char V, bool InterruptEnabled, typename Mask>
|
||||
inline bool interrupt(Mask const& mask)
|
||||
{
|
||||
return interrupt_dispatch<Mask, InterruptEnabled>
|
||||
::template apply<F1, F2, V>(mask);
|
||||
}
|
||||
|
||||
template <typename Mask>
|
||||
struct check_dispatch
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Mask const& mask, Matrix const& matrix)
|
||||
{
|
||||
return per_one<interior, interior>(mask, matrix)
|
||||
&& per_one<interior, boundary>(mask, matrix)
|
||||
&& per_one<interior, exterior>(mask, matrix)
|
||||
&& per_one<boundary, interior>(mask, matrix)
|
||||
&& per_one<boundary, boundary>(mask, matrix)
|
||||
&& per_one<boundary, exterior>(mask, matrix)
|
||||
&& per_one<exterior, interior>(mask, matrix)
|
||||
&& per_one<exterior, boundary>(mask, matrix)
|
||||
&& per_one<exterior, exterior>(mask, matrix);
|
||||
}
|
||||
|
||||
template <field F1, field F2, typename Matrix>
|
||||
static inline bool per_one(Mask const& mask, Matrix const& matrix)
|
||||
{
|
||||
const char mask_el = mask.template get<F1, F2>();
|
||||
const char el = matrix.template get<F1, F2>();
|
||||
|
||||
if ( mask_el == 'F' )
|
||||
{
|
||||
return el == 'F';
|
||||
}
|
||||
else if ( mask_el == 'T' )
|
||||
{
|
||||
return el == 'T' || ( el >= '0' && el <= '9' );
|
||||
}
|
||||
else if ( mask_el >= '0' && mask_el <= '9' )
|
||||
{
|
||||
return el == mask_el;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
|
||||
struct check_dispatch_tuple
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Masks const& masks, Matrix const& matrix)
|
||||
{
|
||||
typedef typename boost::tuples::element<I, Masks>::type mask_type;
|
||||
mask_type const& mask = boost::get<I>(masks);
|
||||
return check_dispatch<mask_type>::apply(mask, matrix)
|
||||
|| check_dispatch_tuple<Masks, I+1>::apply(masks, matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Masks, int N>
|
||||
struct check_dispatch_tuple<Masks, N, N>
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Masks const&, Matrix const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8, typename T9>
|
||||
struct check_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
|
||||
{
|
||||
typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
|
||||
|
||||
template <typename Matrix>
|
||||
static inline bool apply(mask_type const& mask, Matrix const& matrix)
|
||||
{
|
||||
return check_dispatch_tuple<mask_type>::template apply(mask, matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Head, typename Tail>
|
||||
struct check_dispatch< boost::tuples::cons<Head, Tail> >
|
||||
{
|
||||
typedef boost::tuples::cons<Head, Tail> mask_type;
|
||||
|
||||
template <typename Matrix>
|
||||
static inline bool apply(mask_type const& mask, Matrix const& matrix)
|
||||
{
|
||||
return check_dispatch_tuple<mask_type>::template apply(mask, matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mask, typename Matrix>
|
||||
inline bool check(Mask const& mask, Matrix const& matrix)
|
||||
{
|
||||
return check_dispatch<Mask>::apply(mask, matrix);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct matrix_width<mask9>
|
||||
{
|
||||
static const std::size_t value = 3;
|
||||
};
|
||||
|
||||
template <typename Tuple,
|
||||
int I = 0,
|
||||
int N = boost::tuples::length<Tuple>::value>
|
||||
struct matrix_width_tuple
|
||||
{
|
||||
static const std::size_t
|
||||
current = matrix_width<typename boost::tuples::element<I, Tuple>::type>::value;
|
||||
static const std::size_t
|
||||
next = matrix_width_tuple<Tuple, I+1>::value;
|
||||
|
||||
static const std::size_t
|
||||
value = current > next ? current : next;
|
||||
};
|
||||
|
||||
template <typename Tuple, int N>
|
||||
struct matrix_width_tuple<Tuple, N, N>
|
||||
{
|
||||
static const std::size_t value = 0;
|
||||
};
|
||||
|
||||
template <typename Head, typename Tail>
|
||||
struct matrix_width< boost::tuples::cons<Head, Tail> >
|
||||
{
|
||||
static const std::size_t
|
||||
value = matrix_width_tuple< boost::tuples::cons<Head, Tail> >::value;
|
||||
};
|
||||
|
||||
template <typename Mask, bool Interrupt>
|
||||
class mask_handler
|
||||
: private matrix<matrix_width<Mask>::value>
|
||||
{
|
||||
typedef matrix<matrix_width<Mask>::value> base_t;
|
||||
|
||||
public:
|
||||
typedef bool result_type;
|
||||
|
||||
bool interrupt;
|
||||
|
||||
inline mask_handler(Mask const& m)
|
||||
: interrupt(false)
|
||||
, m_mask(m)
|
||||
{}
|
||||
|
||||
result_type result() const
|
||||
{
|
||||
return !interrupt
|
||||
&& check(m_mask, static_cast<base_t const&>(*this));
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set()
|
||||
{
|
||||
if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
|
||||
{
|
||||
interrupt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
base_t::template set<F1, F2, V>();
|
||||
}
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void update()
|
||||
{
|
||||
if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
|
||||
{
|
||||
interrupt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
base_t::template update<F1, F2, V>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Mask const& m_mask;
|
||||
};
|
||||
|
||||
// STATIC MASK
|
||||
|
||||
template <char II, char IB, char IE,
|
||||
char BI, char BB, char BE,
|
||||
char EI, char EB, char EE>
|
||||
class static_mask
|
||||
{
|
||||
typedef boost::mpl::vector_c
|
||||
<
|
||||
char, II, IB, IE, BI, BB, BE, EI, EB, EE
|
||||
> vector_type;
|
||||
|
||||
public:
|
||||
template <field F1, field F2>
|
||||
struct get
|
||||
{
|
||||
BOOST_STATIC_ASSERT(F1 * 3 + F2 < boost::mpl::size<vector_type>::value);
|
||||
|
||||
static const char value
|
||||
= boost::mpl::at_c<vector_type, F1 * 3 + F2>::type::value;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename StaticMask, field F1, field F2>
|
||||
struct static_should_handle_element
|
||||
{
|
||||
static const char mask_el = StaticMask::template get<F1, F2>::value;
|
||||
static const bool value = mask_el == 'F'
|
||||
|| mask_el == 'T'
|
||||
|| ( mask_el >= '0' && mask_el <= '9' );
|
||||
};
|
||||
|
||||
template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsNotSequence>
|
||||
struct static_interrupt_dispatch
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename StaticMask, char V, field F1, field F2, bool IsNotSequence>
|
||||
struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsNotSequence>
|
||||
{
|
||||
static const char mask_el = StaticMask::template get<F1, F2>::value;
|
||||
|
||||
static const bool value
|
||||
= ( V >= '0' && V <= '9' ) ?
|
||||
( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) :
|
||||
( ( V == 'T' ) ? mask_el == 'F' : false );
|
||||
};
|
||||
|
||||
template <typename First, typename Last, char V, field F1, field F2>
|
||||
struct static_interrupt_sequence
|
||||
{
|
||||
typedef typename boost::mpl::deref<First>::type StaticMask;
|
||||
|
||||
static const bool value
|
||||
= static_interrupt_dispatch
|
||||
<
|
||||
StaticMask,
|
||||
V, F1, F2,
|
||||
true,
|
||||
!boost::mpl::is_sequence<StaticMask>::value
|
||||
>::value
|
||||
&& static_interrupt_sequence
|
||||
<
|
||||
typename boost::mpl::next<First>::type,
|
||||
Last,
|
||||
V, F1, F2
|
||||
>::value;
|
||||
};
|
||||
|
||||
template <typename Last, char V, field F1, field F2>
|
||||
struct static_interrupt_sequence<Last, Last, V, F1, F2>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename StaticMask, char V, field F1, field F2>
|
||||
struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, false>
|
||||
{
|
||||
static const bool value
|
||||
= static_interrupt_sequence
|
||||
<
|
||||
typename boost::mpl::begin<StaticMask>::type,
|
||||
typename boost::mpl::end<StaticMask>::type,
|
||||
V, F1, F2
|
||||
>::value;
|
||||
};
|
||||
|
||||
template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt>
|
||||
struct static_interrupt
|
||||
{
|
||||
static const bool value
|
||||
= static_interrupt_dispatch
|
||||
<
|
||||
StaticMask,
|
||||
V, F1, F2,
|
||||
EnableInterrupt,
|
||||
!boost::mpl::is_sequence<StaticMask>::value
|
||||
>::value;
|
||||
};
|
||||
|
||||
template <typename StaticMask, bool IsNotSequence>
|
||||
struct static_check_dispatch
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
return per_one<interior, interior>::apply(matrix)
|
||||
&& per_one<interior, boundary>::apply(matrix)
|
||||
&& per_one<interior, exterior>::apply(matrix)
|
||||
&& per_one<boundary, interior>::apply(matrix)
|
||||
&& per_one<boundary, boundary>::apply(matrix)
|
||||
&& per_one<boundary, exterior>::apply(matrix)
|
||||
&& per_one<exterior, interior>::apply(matrix)
|
||||
&& per_one<exterior, boundary>::apply(matrix)
|
||||
&& per_one<exterior, exterior>::apply(matrix);
|
||||
}
|
||||
|
||||
template <field F1, field F2>
|
||||
struct per_one
|
||||
{
|
||||
static const char mask_el = StaticMask::template get<F1, F2>::value;
|
||||
static const int version
|
||||
= mask_el == 'F' ? 0
|
||||
: mask_el == 'T' ? 1
|
||||
: mask_el >= '0' && mask_el <= '9' ? 2
|
||||
: 3;
|
||||
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
const char el = matrix.template get<F1, F2>();
|
||||
return apply_dispatch(el, integral_constant<int, version>());
|
||||
}
|
||||
|
||||
// mask_el == 'F'
|
||||
static inline bool apply_dispatch(char el, integral_constant<int, 0>)
|
||||
{
|
||||
return el == 'F';
|
||||
}
|
||||
// mask_el == 'T'
|
||||
static inline bool apply_dispatch(char el, integral_constant<int, 1>)
|
||||
{
|
||||
return el == 'T' || ( el >= '0' && el <= '9' );
|
||||
}
|
||||
// mask_el >= '0' && mask_el <= '9'
|
||||
static inline bool apply_dispatch(char el, integral_constant<int, 2>)
|
||||
{
|
||||
return el == mask_el;
|
||||
}
|
||||
// else
|
||||
static inline bool apply_dispatch(char el, integral_constant<int, 3>)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename First, typename Last>
|
||||
struct static_check_sequence
|
||||
{
|
||||
typedef typename boost::mpl::deref<First>::type StaticMask;
|
||||
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
return static_check_dispatch
|
||||
<
|
||||
StaticMask,
|
||||
!boost::mpl::is_sequence<StaticMask>::value
|
||||
>::apply(matrix)
|
||||
|| static_check_sequence
|
||||
<
|
||||
typename boost::mpl::next<First>::type,
|
||||
Last
|
||||
>::apply(matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Last>
|
||||
struct static_check_sequence<Last, Last>
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StaticMask>
|
||||
struct static_check_dispatch<StaticMask, false>
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
return static_check_sequence
|
||||
<
|
||||
typename boost::mpl::begin<StaticMask>::type,
|
||||
typename boost::mpl::end<StaticMask>::type
|
||||
>::apply(matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StaticMask>
|
||||
struct static_check
|
||||
{
|
||||
template <typename Matrix>
|
||||
static inline bool apply(Matrix const& matrix)
|
||||
{
|
||||
return static_check_dispatch
|
||||
<
|
||||
StaticMask,
|
||||
!boost::mpl::is_sequence<StaticMask>::value
|
||||
>::apply(matrix);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StaticMask, bool Interrupt>
|
||||
class static_mask_handler
|
||||
: private matrix<3>
|
||||
{
|
||||
typedef matrix<3> base_t;
|
||||
|
||||
public:
|
||||
typedef bool result_type;
|
||||
|
||||
bool interrupt;
|
||||
|
||||
inline static_mask_handler(StaticMask const& /*dummy*/)
|
||||
: interrupt(false)
|
||||
{}
|
||||
|
||||
result_type result() const
|
||||
{
|
||||
return (!Interrupt || !interrupt)
|
||||
&& static_check<StaticMask>::apply(static_cast<base_t const&>(*this));
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void set()
|
||||
{
|
||||
static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
|
||||
static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
|
||||
static const int version = interrupt_c ? 0
|
||||
: should_handle ? 1
|
||||
: 2;
|
||||
|
||||
set_dispatch<F1, F2, V>(integral_constant<int, version>());
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
inline void update()
|
||||
{
|
||||
static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
|
||||
static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
|
||||
static const int version = interrupt_c ? 0
|
||||
: should_handle ? 1
|
||||
: 2;
|
||||
|
||||
update_dispatch<F1, F2, V>(integral_constant<int, version>());
|
||||
}
|
||||
|
||||
private:
|
||||
// Interrupt && interrupt
|
||||
template <field F1, field F2, char V>
|
||||
inline void set_dispatch(integral_constant<int, 0>)
|
||||
{
|
||||
interrupt = true;
|
||||
}
|
||||
// else should_handle
|
||||
template <field F1, field F2, char V>
|
||||
inline void set_dispatch(integral_constant<int, 1>)
|
||||
{
|
||||
base_t::template set<F1, F2, V>();
|
||||
}
|
||||
// else
|
||||
template <field F1, field F2, char V>
|
||||
inline void set_dispatch(integral_constant<int, 2>)
|
||||
{}
|
||||
|
||||
// Interrupt && interrupt
|
||||
template <field F1, field F2, char V>
|
||||
inline void update_dispatch(integral_constant<int, 0>)
|
||||
{
|
||||
interrupt = true;
|
||||
}
|
||||
// else should_handle
|
||||
template <field F1, field F2, char V>
|
||||
inline void update_dispatch(integral_constant<int, 1>)
|
||||
{
|
||||
base_t::template update<F1, F2, V>();
|
||||
}
|
||||
// else
|
||||
template <field F1, field F2, char V>
|
||||
inline void update_dispatch(integral_constant<int, 2>)
|
||||
{}
|
||||
};
|
||||
|
||||
// OPERATORS
|
||||
|
||||
template <typename Mask1, typename Mask2> inline
|
||||
boost::tuples::cons<
|
||||
Mask1,
|
||||
boost::tuples::cons<Mask2, boost::tuples::null_type>
|
||||
>
|
||||
operator||(Mask1 const& m1, Mask2 const& m2)
|
||||
{
|
||||
namespace bt = boost::tuples;
|
||||
|
||||
return
|
||||
bt::cons< Mask1, bt::cons<Mask2, bt::null_type> >
|
||||
( m1, bt::cons<Mask2, bt::null_type>(m2, bt::null_type()) );
|
||||
}
|
||||
|
||||
template <typename Head, typename Tail, typename Mask> inline
|
||||
typename index::detail::tuples::push_back<
|
||||
boost::tuples::cons<Head, Tail>, Mask
|
||||
>::type
|
||||
operator||(boost::tuples::cons<Head, Tail> const& t, Mask const& m)
|
||||
{
|
||||
namespace bt = boost::tuples;
|
||||
|
||||
return
|
||||
index::detail::tuples::push_back<
|
||||
bt::cons<Head, Tail>, Mask
|
||||
>::apply(t, m);
|
||||
}
|
||||
|
||||
// PREDEFINED MASKS
|
||||
|
||||
// TODO:
|
||||
// 1. specialize for simplified masks if available
|
||||
// e.g. for TOUCHES use 1 mask for A/A
|
||||
// 2. Think about dimensions > 2 e.g. should TOUCHES be true
|
||||
// if the interior of the Areal overlaps the boundary of the Volumetric
|
||||
// like it's true for Linear/Areal
|
||||
|
||||
// EQUALS
|
||||
//typedef static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> static_mask_equals; // wikipedia
|
||||
typedef static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> static_mask_equals; // OGC
|
||||
|
||||
// DISJOINT
|
||||
typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_disjoint;
|
||||
|
||||
// TOUCHES - NOT P/P
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = detail::group_dim<Geometry1>::value,
|
||||
std::size_t Dim2 = detail::group_dim<Geometry2>::value>
|
||||
struct static_mask_touches_type
|
||||
{
|
||||
typedef boost::mpl::vector<
|
||||
static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>,
|
||||
static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>,
|
||||
static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'>
|
||||
> type;
|
||||
};
|
||||
// According to OGC, doesn't apply to P/P
|
||||
// Using the above mask the result would be always false
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_touches_type<Geometry1, Geometry2, 0, 0>
|
||||
: not_implemented<typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type>
|
||||
{};
|
||||
|
||||
// WITHIN
|
||||
typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within;
|
||||
|
||||
// COVERED_BY (non OGC)
|
||||
typedef boost::mpl::vector<
|
||||
static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>,
|
||||
static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>,
|
||||
static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>,
|
||||
static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'>
|
||||
> static_mask_covered_by;
|
||||
|
||||
// CROSSES
|
||||
// dim(G1) < dim(G2) - P/L P/A L/A
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = detail::group_dim<Geometry1>::value,
|
||||
std::size_t Dim2 = detail::group_dim<Geometry2>::value,
|
||||
bool D1LessD2 = (Dim1 < Dim2)
|
||||
>
|
||||
struct static_mask_crosses_type
|
||||
{
|
||||
typedef static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type;
|
||||
};
|
||||
// TODO: I'm not sure if this one below should be available!
|
||||
// dim(G1) > dim(G2) - L/P A/P A/L
|
||||
template <typename Geometry1, typename Geometry2,
|
||||
std::size_t Dim1, std::size_t Dim2
|
||||
>
|
||||
struct static_mask_crosses_type<Geometry1, Geometry2, Dim1, Dim2, false>
|
||||
{
|
||||
typedef static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
// dim(G1) == dim(G2) - P/P A/A
|
||||
template <typename Geometry1, typename Geometry2,
|
||||
std::size_t Dim, bool D1LessD2
|
||||
>
|
||||
struct static_mask_crosses_type<Geometry1, Geometry2, Dim, Dim, D1LessD2/*false*/>
|
||||
: not_implemented<typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type>
|
||||
{};
|
||||
// dim(G1) == 1 && dim(G2) == 1 - L/L
|
||||
template <typename Geometry1, typename Geometry2, bool D1LessD2>
|
||||
struct static_mask_crosses_type<Geometry1, Geometry2, 1, 1, D1LessD2>
|
||||
{
|
||||
typedef static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type;
|
||||
};
|
||||
|
||||
// OVERLAPS
|
||||
|
||||
// dim(G1) != dim(G2) - NOT P/P, L/L, A/A
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = detail::group_dim<Geometry1>::value,
|
||||
std::size_t Dim2 = detail::group_dim<Geometry2>::value
|
||||
>
|
||||
struct static_mask_overlaps_type
|
||||
: not_implemented<typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type>
|
||||
{};
|
||||
// dim(G1) == D && dim(G2) == D - P/P A/A
|
||||
template <typename Geometry1, typename Geometry2, std::size_t Dim>
|
||||
struct static_mask_overlaps_type<Geometry1, Geometry2, Dim, Dim>
|
||||
{
|
||||
typedef static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
// dim(G1) == 1 && dim(G2) == 1 - L/L
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_overlaps_type<Geometry1, Geometry2, 1, 1>
|
||||
{
|
||||
typedef static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
|
||||
// RESULTS/HANDLERS UTILS
|
||||
|
||||
template <field F1, field F2, char V, typename Result>
|
||||
inline void set(Result & res)
|
||||
{
|
||||
@@ -204,10 +951,7 @@ inline void set(Result & res)
|
||||
template <field F1, field F2, char D, typename Result>
|
||||
inline void update(Result & res)
|
||||
{
|
||||
BOOST_STATIC_ASSERT('0' <= D && D <= '9');
|
||||
char c = res.template get<F1, F2>();
|
||||
if ( D > c || c > '9')
|
||||
res.template set<F1, F2, D>();
|
||||
res.template update<F1, F2, D>();
|
||||
}
|
||||
|
||||
template <field F1, field F2, char D, bool Transpose>
|
||||
|
||||
@@ -83,17 +83,32 @@ struct get_turns
|
||||
> turn_info;
|
||||
|
||||
template <typename Turns>
|
||||
static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2)
|
||||
static inline void apply(Turns & turns,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2)
|
||||
{
|
||||
detail::get_turns::no_interrupt_policy interrupt_policy;
|
||||
|
||||
apply(turns, geometry1, geometry2, interrupt_policy);
|
||||
}
|
||||
|
||||
template <typename Turns, typename InterruptPolicy>
|
||||
static inline void apply(Turns & turns,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
InterruptPolicy & interrupt_policy)
|
||||
{
|
||||
static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
|
||||
static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
|
||||
|
||||
dispatch::get_turns
|
||||
<
|
||||
typename tag<Geometry1>::type, typename tag<Geometry2>::type,
|
||||
Geometry1, Geometry2, reverse1, reverse2,
|
||||
typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type,
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
reverse1,
|
||||
reverse2,
|
||||
GetTurnPolicy
|
||||
>::apply(0, geometry1, 1, geometry2, detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
}
|
||||
@@ -124,47 +139,68 @@ struct less_seg_dist_op
|
||||
}
|
||||
|
||||
template <typename Op> static inline
|
||||
bool use_operation(Op const& left, Op const& right)
|
||||
bool less_operation(Op const& left, Op const& right)
|
||||
{
|
||||
return order_op(left) < order_op(right);
|
||||
}
|
||||
|
||||
template <typename Op> static inline
|
||||
bool greater_operation(Op const& left, Op const& right)
|
||||
{
|
||||
return order_op(left) > order_op(right);
|
||||
}
|
||||
|
||||
template <typename Op> static inline
|
||||
bool use_other_multi_ring_id(Op const& left, Op const& right)
|
||||
{
|
||||
// VER1
|
||||
//return left.other_id.ring_index < right.other_id.ring_index;
|
||||
|
||||
if ( left.other_id.ring_index == -1 )
|
||||
{
|
||||
if ( right.other_id.ring_index == -1 )
|
||||
return use_operation(left, right); // sort by operation
|
||||
else
|
||||
return true; // right always greater
|
||||
}
|
||||
else // left.other_id.ring_index != -1
|
||||
{
|
||||
if ( right.other_id.ring_index == -1 )
|
||||
return false; // left always greater
|
||||
// VER2
|
||||
//if ( left.other_id.ring_index == -1 )
|
||||
//{
|
||||
// if ( right.other_id.ring_index == -1 )
|
||||
// return less_operation(left, right); // sort by operation
|
||||
// else
|
||||
// return true; // right always greater
|
||||
//}
|
||||
//else // left.other_id.ring_index != -1
|
||||
//{
|
||||
// if ( right.other_id.ring_index == -1 )
|
||||
// return false; // left always greater
|
||||
|
||||
// here both ring_indexes are greater than -1
|
||||
// so first, sort also by multi_index
|
||||
return left.other_id.multi_index < right.other_id.multi_index || (
|
||||
left.other_id.multi_index == right.other_id.multi_index && (
|
||||
left.other_id.ring_index < right.other_id.ring_index || (
|
||||
left.other_id.ring_index == right.other_id.ring_index &&
|
||||
use_operation(left, right) )
|
||||
)
|
||||
);
|
||||
// // here both ring_indexes are greater than -1
|
||||
// // so first, sort also by multi_index
|
||||
// return left.other_id.multi_index < right.other_id.multi_index || (
|
||||
// left.other_id.multi_index == right.other_id.multi_index && (
|
||||
// left.other_id.ring_index < right.other_id.ring_index || (
|
||||
// left.other_id.ring_index == right.other_id.ring_index &&
|
||||
// less_operation(left, right) )
|
||||
// )
|
||||
// );
|
||||
//}
|
||||
|
||||
// VER3
|
||||
if ( left.other_id.multi_index == right.other_id.multi_index )
|
||||
{
|
||||
if ( left.other_id.ring_index == right.other_id.ring_index )
|
||||
return less_operation(left, right);
|
||||
else
|
||||
return greater_operation(left, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
return less_operation(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Op> static inline
|
||||
bool use_distance(Op const& left, Op const& right)
|
||||
{
|
||||
return left.enriched.distance < right.enriched.distance || (
|
||||
geometry::math::equals(left.enriched.distance, right.enriched.distance) &&
|
||||
use_other_multi_ring_id(left, right)
|
||||
);
|
||||
if ( geometry::math::equals(left.enriched.distance, right.enriched.distance) )
|
||||
return use_other_multi_ring_id(left, right);
|
||||
else
|
||||
return left.enriched.distance < right.enriched.distance;
|
||||
}
|
||||
|
||||
template <typename Turn>
|
||||
|
||||
@@ -70,12 +70,15 @@ struct get<Geometry, polygon_tag, false>
|
||||
result_type apply(Geometry & geometry, Id const& id)
|
||||
{
|
||||
if ( id.ring_index < 0 )
|
||||
{
|
||||
return geometry::exterior_ring(geometry);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT( id.ring_index < boost::size(geometry::interior_rings(geometry)) );
|
||||
std::size_t ri = static_cast<std::size_t>(id.ring_index);
|
||||
BOOST_ASSERT( ri < boost::size(geometry::interior_rings(geometry)) );
|
||||
|
||||
return *(boost::begin(geometry::interior_rings(geometry)) + id.ring_index);
|
||||
return *(boost::begin(geometry::interior_rings(geometry)) + ri);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -164,13 +164,16 @@ struct add_unique
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename T, size_t I, size_t N>
|
||||
struct push_back_impl
|
||||
template <typename Tuple,
|
||||
typename T,
|
||||
size_t I = 0,
|
||||
size_t N = boost::tuples::length<Tuple>::value>
|
||||
struct push_back
|
||||
{
|
||||
typedef
|
||||
boost::tuples::cons<
|
||||
typename boost::tuples::element<I, Tuple>::type,
|
||||
typename push_back_impl<Tuple, T, I+1, N>::type
|
||||
typename push_back<Tuple, T, I+1, N>::type
|
||||
> type;
|
||||
|
||||
static type apply(Tuple const& tup, T const& t)
|
||||
@@ -178,13 +181,13 @@ struct push_back_impl
|
||||
return
|
||||
type(
|
||||
boost::get<I>(tup),
|
||||
push_back_impl<Tuple, T, I+1, N>::apply(tup, t)
|
||||
push_back<Tuple, T, I+1, N>::apply(tup, t)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tuple, typename T, size_t N>
|
||||
struct push_back_impl<Tuple, T, N, N>
|
||||
struct push_back<Tuple, T, N, N>
|
||||
{
|
||||
typedef boost::tuples::cons<T, boost::tuples::null_type> type;
|
||||
|
||||
|
||||
@@ -362,11 +362,8 @@ operator&&(Pred1 const& p1, Pred2 const& p2)
|
||||
}
|
||||
|
||||
template <typename Head, typename Tail, typename Pred> inline
|
||||
typename tuples::push_back_impl<
|
||||
boost::tuples::cons<Head, Tail>,
|
||||
Pred,
|
||||
0,
|
||||
boost::tuples::length<boost::tuples::cons<Head, Tail> >::value
|
||||
typename tuples::push_back<
|
||||
boost::tuples::cons<Head, Tail>, Pred
|
||||
>::type
|
||||
operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p)
|
||||
{
|
||||
@@ -374,8 +371,8 @@ operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p)
|
||||
namespace bt = boost::tuples;
|
||||
|
||||
return
|
||||
tuples::push_back_impl<
|
||||
bt::cons<Head, Tail>, Pred, 0, bt::length< bt::cons<Head, Tail> >::value
|
||||
tuples::push_back<
|
||||
bt::cons<Head, Tail>, Pred
|
||||
>::apply(t, p);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
#include "test_get_turns.hpp"
|
||||
#include <boost/geometry/geometries/geometries.hpp>
|
||||
|
||||
//TEST
|
||||
#include <to_svg.hpp>
|
||||
//#include <boost/geometry.hpp>
|
||||
//#include <boost/geometry/multi/geometries/multi_linestring.hpp>
|
||||
//#include "to_svg.hpp"
|
||||
|
||||
template <typename T>
|
||||
void test_all()
|
||||
@@ -34,41 +31,50 @@ void test_all()
|
||||
|
||||
test_geometry<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))",
|
||||
expected("miu")("iuu")("tcu")("tuu")("mcu")("miu")("muu")("tiu")("mcu")("miu")("mcu")("miu")("mxu").vec);
|
||||
expected("miu")("iuu")("tcc")("tuu")("mcu")("mic")("muu")("tiu")("mcu")("mic")("mcc")("miu")("mxu").vec);
|
||||
|
||||
test_geometry<ls, poly>("LINESTRING(5 0,5 5,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"miu", "mxu");
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,5 5,10 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"tiu", "txu");
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,5 0,5 5,10 5,10 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
expected("tcu")("miu")("mcu")("txu").vec);
|
||||
expected("tcu")("mic")("mcc")("txu").vec);
|
||||
test_geometry<ls, poly>("LINESTRING(10 0,5 0,5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
expected("tcu")("miu")("mcu")("txu").vec);
|
||||
expected("tcc")("miu")("mcu")("txc").vec);
|
||||
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,10 0,10 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))",
|
||||
expected("tcu")("miu")("mcu")("miu")("mxu").vec);
|
||||
expected("tcu")("mic")("mcu")("mic")("mxu").vec);
|
||||
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 0,0 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"tcc", "txu");
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,10 0,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"tcu", "tuc");
|
||||
test_geometry<ls, poly>("LINESTRING(10 0,0 0,-1 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"tcc", "tuu");
|
||||
|
||||
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_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");
|
||||
// true hole
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,10 0,0 0)(2 2,10 5,2 8,2 2))",
|
||||
expected("tiu")("tiu").vec);
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,10 0,0 0)(2 2,10 5,2 8,2 2))",
|
||||
expected("mcu")("ecc")("tiu")("mxc").vec);
|
||||
|
||||
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");
|
||||
// fake hole
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
expected("tuu")("tiu").vec);
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
expected("mcu")("tuc")("tcu")("mxc").vec);
|
||||
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,2 2)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
expected("mcu")("mic")("tcu")("txc"));
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,2 8)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
expected("mcu")("mic")("tcc")("txu"));
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
@@ -85,142 +91,3 @@ int test_main(int, char* [])
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 0,3 0)", "lsls0000.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,3 0)", "LINESTRING(2 0,0 0)", "lsls0001.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(3 0,1 0)", "lsls0002.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(1 0,2 0)", "lsls0003.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(2 0,1 0)", "lsls0004.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,2 0)", "LINESTRING(1 0,0 0)", "lsls0005.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "lsls0006.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "lsls0007.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,3 0)", "LINESTRING(1 0,2 0)", "lsls0008.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,3 0)", "LINESTRING(2 0,1 0)", "lsls0009.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(1 0,1 1)", "lsls00010.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(1 1,1 0)", "lsls00011.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(0 0,0 1)", "lsls00012.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(0 1,0 0)", "lsls00013.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 0,1 1)", "lsls00014.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 1,1 0)", "lsls00015.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 0,3 1)", "lsls00016.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(2 0,1 0)", "lsls00017.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(0 0,1 0)", "lsls00018.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 0,0 0)", "lsls00019.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(1 0,2 0)", "lsls00020.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "lsls000.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,2 0,3 0)", "LINESTRING(0 0,2 0)", "lsls001.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "lsls0020.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0021.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0022.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0023.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0024.svg");
|
||||
to_svg<ls, ls>("LINESTRING(2 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0025.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,1 1)", "lsls00200.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,0 0)", "lsls00211.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,2 0)", "lsls00222.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 1,1 0)", "lsls00233.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(0 0,1 0)", "lsls00244.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(2 0,1 0)", "lsls00255.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,6 0,8 0)", "LINESTRING(1 0,3 0,5 0,6 0,9 0)", "lsls01.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,3 0,4 0,4 2,4 5)", "lsls02.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 4)", "lsls031.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 0,0 0)", "lsls032.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 2,0 2)", "lsls0321.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 0)", "lsls033.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,4 4)", "lsls034.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,3 1)", "lsls035.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,4 -1)", "lsls036.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 3)", "lsls04.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,2 0,4 0,6 0,8 0)", "LINESTRING(0 0,3 0,5 0,6 0,9 0)", "lsls05.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,10 9)", "lsls061.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,10 -9)", "lsls062.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-10 9)", "lsls063.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-10 -9)", "lsls064.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,10 9,10 10)", "LINESTRING(1 0,10 9)", "lsls065.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls071.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 -9)", "lsls072.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-9 9)", "lsls073.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-9 -9)", "lsls074.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls081.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(0 0,9 9)", "lsls082.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(1 0,9 9)", "lsls083.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(9 9,1 0)", "lsls084.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(1 0,2 0)", "lsls085.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(2 0,1 0)", "lsls086.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 1,10 5)", "lsls091.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 5,10 10)", "LINESTRING(1 1,10 5)", "lsls092.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(19 1,10 5)", "lsls093.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 5,10 10)", "LINESTRING(19 1,10 5)", "lsls094.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(0 0,3 3,6 3)", "1F100F10T.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,3 0,3 1)", "lsls_01.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,3 0,3 -1)", "lsls_02.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,1 0,1 1)", "lsls_03.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,1 0,1 -1)", "lsls_04.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,4 0,4 1)", "lsls_05.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,4 0,4 -1)", "lsls_06.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,2 0,2 1)", "lsls_07.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,2 0,2 -1)", "lsls_08.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,2 0,3 0,3 1)", "lsls_11.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,2 0,3 0,3 -1)", "lsls_12.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,2 0,1 0,1 1)", "lsls_13.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,2 0,1 0,1 -1)", "lsls_14.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,3 0,4 0,4 1)", "lsls_15.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,3 0,4 0,4 -1)", "lsls_16.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,3 0,2 0,2 1)", "lsls_17.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "lsls_18.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls11.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(5 0,5 5,10 5,10 10,5 10,5 5,0 5)", "lsls12.svg");
|
||||
to_svg<ls, ls>("LINESTRING(5 0,5 5,5 10,10 10,10 5,5 5,0 5)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls13.svg");
|
||||
to_svg<ls, ls>("LINESTRING(5 0,5 5,5 10,10 10,10 5,5 5,0 5)", "LINESTRING(5 0,5 5,10 5,10 10,5 10,5 5,0 5)", "lsls14.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls15.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls16.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls161.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls162.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1631.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1632.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 10,10 10,10 5,0 5)", "lsls1633.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1641.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 6)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1642.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1643.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1644.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls165.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls166.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 5)", "LINESTRING(0 10,10 0,5 0,5 10,10 10,10 5,0 5)", "lsls167.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 5)", "LINESTRING(0 10,5 5,10 0,5 0,5 5,5 10,10 10,10 5,0 5)", "lsls168.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,0 10,10 10,10 0,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8,0 2)", "lsls1690.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10,0 10,0 0)", "LINESTRING(0 8,0 0,10 0,10 10,0 10,0 8)", "lsls1691.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10,0 10,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "lsls1692.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,0 10,10 10,10 0,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "lsls1693.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "LINESTRING(0 0,10 0,10 10,0 10,0 0)", "lsls1694.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "LINESTRING(0 0,0 10,10 10,10 0,0 0)", "lsls1695.svg");
|
||||
|
||||
to_svg<ls>("LINESTRING(0 8,0 0,10 0,10 10,0 10,0 2)", "ls1.svg");
|
||||
to_svg<ls>("LINESTRING(8 8,0 0,10 0,10 10,0 10,8 2)", "ls2.svg");
|
||||
|
||||
typedef bg::model::multi_linestring<ls> mls;
|
||||
to_svg<ls, mls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 7),(5 8,5 10,10 10,10 5,0 5))", "lsls17.svg");
|
||||
to_svg<ls, mls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 4,5 6,5 7),(5 8,5 10,10 10,10 5,0 5))", "lsls18.svg");
|
||||
to_svg<ls, mls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 8),(5 7,5 10,10 10,10 5,0 5))", "lsls19.svg");
|
||||
to_svg<mls, ls>("MULTILINESTRING((5 0,5 7),(5 8,5 10,10 10,10 5,0 5))", "LINESTRING(0 5,10 5,10 10,5 10,5 0)", "lsls20.svg");
|
||||
to_svg<mls, ls>("MULTILINESTRING((5 0,5 8),(5 7,5 10,10 10,10 5,0 5))", "LINESTRING(0 5,10 5,10 10,5 10,5 0)", "lsls21.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(0 5,5 5,0 10,10 10,10 5,5 5,5 0)", "lsls100.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(5 0,5 5,5 0)", "LINESTRING(0 5,5 5,0 10,2 10,5 5,5 10,10 10,10 5,5 5,10 2,10 0,8 0,5 5,5 0)", "lsls101.svg");
|
||||
*/
|
||||
|
||||
@@ -78,16 +78,16 @@ void test_all()
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,31 0)",
|
||||
"LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)",
|
||||
expected("tii")("ecc")("muu")("mii")("muu")("mii")("mux").vec);
|
||||
expected("tii")("ecc")("muu")("mii")("muu")("mii")("mux"));
|
||||
test_geometry<ls, ls>("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,31 0)",
|
||||
"LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)",
|
||||
expected("tiu")("ecc")("mui")("miu")("mui")("miu")("mui").vec);
|
||||
expected("tiu")("ecc")("mui")("miu")("mui")("miu")("mui"));
|
||||
test_geometry<ls, ls>("LINESTRING(31 0,15 0,10 5,5 5,4 0,1 0,0 0,-1 1)",
|
||||
"LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)",
|
||||
expected("tui")("ecc")("miu")("mui")("miu")("mui")("mix").vec);
|
||||
expected("tui")("ecc")("miu")("mui")("miu")("mui")("mix"));
|
||||
test_geometry<ls, ls>("LINESTRING(31 0,15 0,10 5,5 5,4 0,1 0,0 0,-1 1)",
|
||||
"LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)",
|
||||
expected("tuu")("ecc")("mii")("muu")("mii")("muu")("mii").vec);
|
||||
expected("tuu")("ecc")("mii")("muu")("mii")("muu")("mii"));
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(-1 0,1 0,2 1,3 2)", "LINESTRING(4 5,3 2,1 0,0 0)", "mix", "txi", "ecc");
|
||||
test_geometry<ls, ls>("LINESTRING(4 5,3 2,1 0,0 0)", "LINESTRING(-1 0,1 0,2 1,3 2)", "mxi", "tix", "ecc");
|
||||
@@ -99,9 +99,14 @@ void test_all()
|
||||
test_geometry<ls, ls>("LINESTRING(4 0,4 1,20 1,5 0,1 0)", "LINESTRING(0 0,30 0)", "muu", "miu", "mxi");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(30 0,0 0)", "LINESTRING(1 0,5 0,20 1,4 1,4 0,5 0)",
|
||||
expected("mui")("miu")("mui")("mix").vec);
|
||||
expected("mui")("miu")("mui")("mix"));
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,20 1,4 1,4 0,5 0)", "LINESTRING(30 0,0 0)",
|
||||
expected("miu")("mui")("miu")("mxi").vec);
|
||||
expected("miu")("mui")("miu")("mxi"));
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)",
|
||||
expected("mii")("iuu")("muu"));
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,5 0,4 1)",
|
||||
expected("mii")("muu")("muu"));
|
||||
|
||||
//if ( boost::is_same<T, double>::value )
|
||||
//{
|
||||
|
||||
@@ -49,13 +49,13 @@ struct equal_turn
|
||||
const std::string * turn_ptr;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
void check_geometry(
|
||||
template <typename Geometry1, typename Geometry2, typename Range>
|
||||
void check_geometry_range(
|
||||
Geometry1 const& g1,
|
||||
Geometry2 const& g2,
|
||||
std::string const& wkt1,
|
||||
std::string const& wkt2,
|
||||
std::vector<std::string> const& expected)
|
||||
Range const& expected)
|
||||
{
|
||||
typedef bg::detail::overlay::turn_info
|
||||
<
|
||||
@@ -77,16 +77,17 @@ void check_geometry(
|
||||
turn_policy_t
|
||||
>::apply(0, g1, 1, g2, bg::detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
|
||||
bool ok = expected.size() == turns.size();
|
||||
bool ok = boost::size(expected) == turns.size();
|
||||
|
||||
BOOST_CHECK_MESSAGE(ok,
|
||||
"get_turns: " << wkt1 << " and " << wkt2
|
||||
<< " -> Expected turns #: " << expected.size() << " detected turns #: " << turns.size());
|
||||
<< " -> Expected turns #: " << boost::size(expected) << " detected turns #: " << turns.size());
|
||||
|
||||
BOOST_FOREACH(std::string const& s, expected)
|
||||
for ( typename boost::range_iterator<Range const>::type sit = boost::begin(expected) ;
|
||||
sit != boost::end(expected) ; ++sit)
|
||||
{
|
||||
typename std::vector<turn_info>::iterator
|
||||
it = std::find_if(turns.begin(), turns.end(), equal_turn(s));
|
||||
it = std::find_if(turns.begin(), turns.end(), equal_turn(*sit));
|
||||
|
||||
if ( it != turns.end() )
|
||||
turns.erase(it);
|
||||
@@ -94,20 +95,20 @@ void check_geometry(
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(false,
|
||||
"get_turns: " << wkt1 << " and " << wkt2
|
||||
<< " -> Expected turn: " << s << " not found");
|
||||
<< " -> Expected turn: " << *sit << " not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
std::vector<std::string> const& expected)
|
||||
template <typename Geometry1, typename Geometry2, typename Range>
|
||||
void test_geometry_range(std::string const& wkt1, std::string const& wkt2,
|
||||
Range const& expected)
|
||||
{
|
||||
Geometry1 geometry1;
|
||||
Geometry2 geometry2;
|
||||
bg::read_wkt(wkt1, geometry1);
|
||||
bg::read_wkt(wkt2, geometry2);
|
||||
check_geometry(geometry1, geometry2, wkt1, wkt2, expected);
|
||||
check_geometry_range(geometry1, geometry2, wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
@@ -116,7 +117,7 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
{
|
||||
std::vector<std::string> expected;
|
||||
expected.push_back(ex0);
|
||||
test_geometry<G1, G2>(wkt1, wkt2, expected);
|
||||
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
@@ -126,7 +127,7 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
std::vector<std::string> expected;
|
||||
expected.push_back(ex0);
|
||||
expected.push_back(ex1);
|
||||
test_geometry<G1, G2>(wkt1, wkt2, expected);
|
||||
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
@@ -137,7 +138,7 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
expected.push_back(ex0);
|
||||
expected.push_back(ex1);
|
||||
expected.push_back(ex2);
|
||||
test_geometry<G1, G2>(wkt1, wkt2, expected);
|
||||
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
struct expected_pusher
|
||||
@@ -147,6 +148,15 @@ struct expected_pusher
|
||||
vec.push_back(ex);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef std::vector<std::string>::iterator iterator;
|
||||
typedef std::vector<std::string>::const_iterator const_iterator;
|
||||
|
||||
//iterator begin() { return vec.begin(); }
|
||||
//iterator end() { return vec.end(); }
|
||||
const_iterator begin() const { return vec.begin(); }
|
||||
const_iterator end() const { return vec.end(); }
|
||||
|
||||
std::vector<std::string> vec;
|
||||
};
|
||||
|
||||
@@ -156,4 +166,18 @@ expected_pusher expected(std::string const& ex)
|
||||
return res(ex);
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
std::vector<std::string> const& expected)
|
||||
{
|
||||
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
void test_geometry(std::string const& wkt1, std::string const& wkt2,
|
||||
expected_pusher const& expected)
|
||||
{
|
||||
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
|
||||
}
|
||||
|
||||
#endif // BOOST_GEOMETRY_TEST_ALGORITHMS_OVERLAY_TEST_GET_TURNS_HPP
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <boost/geometry.hpp>
|
||||
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
|
||||
#include <boost/geometry/multi/geometries/multi_point.hpp>
|
||||
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
|
||||
|
||||
//TEST
|
||||
#include <to_svg.hpp>
|
||||
@@ -59,9 +60,7 @@ void check_geometry(Geometry1 const& geometry1,
|
||||
std::string const& expected)
|
||||
{
|
||||
{
|
||||
bgdr::result res;
|
||||
bgdr::relate(geometry1, geometry2, res);
|
||||
std::string res_str(boost::begin(res.get_code()), boost::end(res.get_code()));
|
||||
std::string res_str = bgdr::relate<bgdr::matrix9>(geometry1, geometry2);
|
||||
bool ok = boost::equal(res_str, expected);
|
||||
BOOST_CHECK_MESSAGE(ok,
|
||||
"relate: " << wkt1
|
||||
@@ -72,9 +71,7 @@ void check_geometry(Geometry1 const& geometry1,
|
||||
|
||||
// changed sequence of geometries - transposed result
|
||||
{
|
||||
bgdr::result res;
|
||||
bgdr::relate(geometry2, geometry1, res);
|
||||
std::string res_str(boost::begin(res.get_code()), boost::end(res.get_code()));
|
||||
std::string res_str = bgdr::relate(geometry2, geometry1, bgdr::matrix9());
|
||||
std::string expected_tr = transposed(expected);
|
||||
bool ok = boost::equal(res_str, expected_tr);
|
||||
BOOST_CHECK_MESSAGE(ok,
|
||||
@@ -84,20 +81,16 @@ void check_geometry(Geometry1 const& geometry1,
|
||||
<< " detected: " << res_str);
|
||||
}
|
||||
|
||||
static const bool int_en = bgdr::interruption_enabled<Geometry1, Geometry2>::value;
|
||||
|
||||
{
|
||||
bgdr::mask<int_en> mask(expected);
|
||||
bgdr::relate(geometry1, geometry2, mask);
|
||||
std::string res_str(boost::begin(mask.get_code()), boost::end(mask.get_code()));
|
||||
BOOST_CHECK_MESSAGE((!mask.interrupt && mask.check()),
|
||||
bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected));
|
||||
// TODO: SHOULD BE !interrupted - CHECK THIS!
|
||||
BOOST_CHECK_MESSAGE(result,
|
||||
"relate: " << wkt1
|
||||
<< " and " << wkt2
|
||||
<< " -> Expected: " << expected
|
||||
<< " detected: " << res_str);
|
||||
<< " -> Expected: " << expected);
|
||||
}
|
||||
|
||||
if ( int_en )
|
||||
if ( bg::detail::relate::interruption_enabled<Geometry1, Geometry2>::value )
|
||||
{
|
||||
// brake the expected output
|
||||
std::string expected_interrupt = expected;
|
||||
@@ -117,14 +110,12 @@ void check_geometry(Geometry1 const& geometry1,
|
||||
|
||||
if ( changed )
|
||||
{
|
||||
bgdr::mask<int_en> mask(expected_interrupt);
|
||||
bgdr::relate(geometry1, geometry2, mask);
|
||||
std::string res_str(boost::begin(mask.get_code()), boost::end(mask.get_code()));
|
||||
BOOST_CHECK_MESSAGE(mask.interrupt,
|
||||
bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected_interrupt));
|
||||
// TODO: SHOULD BE interrupted - CHECK THIS!
|
||||
BOOST_CHECK_MESSAGE(!result,
|
||||
"relate: " << wkt1
|
||||
<< " and " << wkt2
|
||||
<< " -> Expected interrupt for:" << expected_interrupt
|
||||
<< " detected: " << res_str);
|
||||
<< " -> Expected interrupt for:" << expected_interrupt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,6 +291,28 @@ void test_linestring_linestring()
|
||||
"LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)",
|
||||
"101FF0102");
|
||||
|
||||
// self-IP
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 0,0 10)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 0,0 10)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 10,5 -1)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,5 0,5 5)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)",
|
||||
"1F10F0102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)",
|
||||
"1F10F0102");
|
||||
|
||||
// linear ring
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2");
|
||||
@@ -318,6 +331,24 @@ void test_linestring_linestring()
|
||||
//test_geometry<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0,1 0)", "0F1FF0FF2");
|
||||
// Point/Point
|
||||
//test_geometry<ls, ls>("LINESTRING(0 0)", "LINESTRING(0 0)", "0FFFFFFF2");
|
||||
|
||||
// OTHER MASKS
|
||||
{
|
||||
namespace bgdr = bg::detail::relate;
|
||||
ls ls1, ls2, ls3;
|
||||
bg::read_wkt("LINESTRING(0 0,2 0)", ls1);
|
||||
bg::read_wkt("LINESTRING(2 0,4 0)", ls2);
|
||||
bg::read_wkt("LINESTRING(1 0,1 1)", ls3);
|
||||
BOOST_CHECK(bgdr::relate(ls1, ls2, bgdr::mask9("FT*******")
|
||||
|| bgdr::mask9("F**T*****")
|
||||
|| bgdr::mask9("F***T****")));
|
||||
BOOST_CHECK(bgdr::relate(ls1, ls3, bgdr::mask9("FT*******")
|
||||
|| bgdr::mask9("F**T*****")
|
||||
|| bgdr::mask9("F***T****")));
|
||||
BOOST_CHECK(bgdr::relate(ls3, ls1, bgdr::mask9("FT*******")
|
||||
|| bgdr::mask9("F**T*****")
|
||||
|| bgdr::mask9("F***T****")));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
@@ -344,6 +375,184 @@ void test_linestring_multi_linestring()
|
||||
//test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0,2 0))", "101FF0FF2");
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void test_linestring_polygon()
|
||||
{
|
||||
typedef bg::model::linestring<P> ls;
|
||||
typedef bg::model::polygon<P> poly;
|
||||
|
||||
// LS disjoint
|
||||
test_geometry<ls, poly>("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212");
|
||||
|
||||
// II BB
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(5 0,5 5,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(5 1,5 5,9 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FF0FF212");
|
||||
|
||||
// IE
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,11 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212");
|
||||
// IE IB0
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1F00212");
|
||||
// IE IB1
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 10,0 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 0,0 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
test_geometry<ls, poly>("LINESTRING(0 -1,1 0,2 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
// IE IB0 II
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212");
|
||||
// IE IB0 lring
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 5,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F01FFF212");
|
||||
// IE IB1 lring
|
||||
test_geometry<ls, poly>("LINESTRING(11 1,10 5,10 10,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11FFF212");
|
||||
|
||||
// IB1 II
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,5 0,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212");
|
||||
// BI0 II IB1
|
||||
test_geometry<ls, poly>("LINESTRING(5 0,5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212");
|
||||
|
||||
// IB1 II IB1
|
||||
test_geometry<ls, poly>("LINESTRING(1 0,2 0,3 1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212");
|
||||
// IB1 IE IB1
|
||||
test_geometry<ls, poly>("LINESTRING(1 0,2 0,3 -1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F0F212");
|
||||
|
||||
// II IB1
|
||||
test_geometry<ls, poly>("LINESTRING(5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212");
|
||||
// IB1 II
|
||||
test_geometry<ls, poly>("LINESTRING(10 10,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212");
|
||||
// IE IB1
|
||||
test_geometry<ls, poly>("LINESTRING(15 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
// IB1 IE
|
||||
test_geometry<ls, poly>("LINESTRING(10 10,10 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212");
|
||||
|
||||
// II IB0 IE
|
||||
test_geometry<ls, poly>("LINESTRING(5 5,10 5,15 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212");
|
||||
|
||||
// non-simple polygon with hole
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"10F0FF212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(2 8,10 5,2 2)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,2 2)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,2 8)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F1FF0F212");
|
||||
|
||||
// non-simple polygon with hole, linear ring
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"10FFFF212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 5,10 9,11 5,10 1,10 5)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F11FFF212");
|
||||
test_geometry<ls, poly>("LINESTRING(11 5,10 1,10 5,10 9,11 5)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))",
|
||||
"F11FFF212");
|
||||
|
||||
// non-simple polygon with self-touching holes
|
||||
test_geometry<ls, poly>("LINESTRING(7 1,8 5,7 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))",
|
||||
"10F0FF212");
|
||||
test_geometry<ls, poly>("LINESTRING(8 2,8 5,8 8)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(2 8,8 5,2 2)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))",
|
||||
"F1FF0F212");
|
||||
|
||||
// non-simple polygon self-touching
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"10F0FF212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, poly>("LINESTRING(2 8,10 5,2 2)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"F1FF0F212");
|
||||
|
||||
// non-simple polygon self-touching, linear ring
|
||||
test_geometry<ls, poly>("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"10FFFF212");
|
||||
test_geometry<ls, poly>("LINESTRING(10 5,10 9,11 5,10 1,10 5)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"F11FFF212");
|
||||
test_geometry<ls, poly>("LINESTRING(11 5,10 1,10 5,10 9,11 5)",
|
||||
"POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))",
|
||||
"F11FFF212");
|
||||
|
||||
// polygons with exterior ring equals the linestring
|
||||
test_geometry<ls, poly>("LINESTRING(0 0,10 0,10 10,0 10,0 0)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"F1FFFF2F2");
|
||||
to_svg<ls, poly>("LINESTRING(0 0,10 0,10 10,0 10,0 0)",
|
||||
"POLYGON((0 0,0 10,10 10,10 0,0 0))",
|
||||
"F1FFFF2F2.svg");
|
||||
|
||||
// ccw
|
||||
{
|
||||
typedef bg::model::polygon<P, false> ccwpoly;
|
||||
|
||||
// IE IB0 II
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212");
|
||||
// IE IB1 II
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(11 1,10 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212");
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(11 1,10 5,10 1,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212");
|
||||
// II IB0 IE
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(5 1,10 5,11 1)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212");
|
||||
// IE IB1 II
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(5 5,10 1,10 5,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212");
|
||||
test_geometry<ls, ccwpoly>("LINESTRING(5 5,10 5,10 1,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void test_linestring_multi_polygon()
|
||||
{
|
||||
typedef bg::model::linestring<P> ls;
|
||||
typedef bg::model::polygon<P> poly;
|
||||
typedef bg::model::multi_polygon<poly> mpoly;
|
||||
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,10 9)",
|
||||
"MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))",
|
||||
"F1FF0F212");
|
||||
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,2 2)",
|
||||
"MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,2 2)",
|
||||
"MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))",
|
||||
"11F00F212");
|
||||
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,2 2)",
|
||||
"MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,2 8)",
|
||||
"MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,3 3)",
|
||||
"MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,3 7)",
|
||||
"MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))",
|
||||
"F1FF0F212");
|
||||
test_geometry<ls, mpoly>("LINESTRING(10 1,10 5,5 5)",
|
||||
"MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))",
|
||||
"11F00F212");
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void test_all()
|
||||
{
|
||||
@@ -354,6 +563,8 @@ void test_all()
|
||||
test_point_multilinestring<P>();
|
||||
test_linestring_linestring<P>();
|
||||
test_linestring_multi_linestring<P>();
|
||||
test_linestring_polygon<P>();
|
||||
test_linestring_multi_polygon<P>();
|
||||
}
|
||||
|
||||
int test_main( int , char* [] )
|
||||
|
||||
Reference in New Issue
Block a user