relate(L,L) handled G1 last range point boundary in the exterior of G2

This commit is contained in:
Adam Wulkiewicz
2014-02-13 01:08:08 +01:00
parent 7429694b54
commit 9fe9d7259c

View File

@@ -248,13 +248,13 @@ struct linear_linear
// TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
// for linear geometries union operation must be detected which I guess would be quite often
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,0>());
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>());
analyse_turns<0, 1>(res, turns.begin(), turns.end(),
geometry1, geometry2,
boundary_checker1, boundary_checker2);
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,1>());
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,1>());
analyse_turns<1, 0>(res, turns.begin(), turns.end(),
geometry2, geometry1,
@@ -438,20 +438,27 @@ struct linear_linear
exit_watcher<point_type> exit_watcher;
segment_watcher seg_watcher;
bool last_union = false;
for ( TurnIt it = first ; it != last ; ++it )
{
overlay::operation_type op = it->operations[OpId].operation;
if ( op != overlay::operation_union
&& op != overlay::operation_intersection
&& op != overlay::operation_blocked )
{
continue;
}
segment_identifier const& seg_id = it->operations[OpId].seg_id;
segment_identifier const& other_id = it->operations[OtherOpId].seg_id;
bool first_in_range = seg_watcher.update(seg_id); // TODO: could be calculated only for i and u
bool first_in_range = seg_watcher.update(seg_id);
bool fake_enter_detected = false;
// handle possible exit
if ( exit_watcher.is_exit_detected() &&
( op == overlay::operation_union || op == overlay::operation_intersection
|| op == overlay::operation_continue || op == overlay::operation_blocked ) )
if ( exit_watcher.is_exit_detected() )
{
// real exit point - may be multiple
// we know that we entered and now we exit
@@ -471,6 +478,25 @@ struct linear_linear
}
}
if ( first_in_range && !fake_enter_detected && last_union )
{
BOOST_ASSERT(it != first);
TurnIt prev = it;
--prev;
segment_identifier const& prev_seg_id = prev->operations[OpId].seg_id;
// if there is a boundary on the last point
if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1
&& boundary_checker.template is_boundary<boundary_back_explicit>
(range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) )
{
update_result<boundary, exterior, '0', reverse_result>(res);
}
}
// reset state
last_union = (op == overlay::operation_union);
// i/i, i/x, i/u
if ( op == overlay::operation_intersection )
{
@@ -568,6 +594,7 @@ struct linear_linear
}
}
}
// method other than crosses, check more conditions
else
{
bool this_b =
@@ -584,9 +611,13 @@ struct linear_linear
other_boundary_checker.template is_boundary<boundary_any>(it->point, other_id);
// it's also the boundary of the other geometry
if ( other_b )
{
update_result<boundary, boundary, '0', reverse_result>(res);
}
else
{
update_result<boundary, interior, '0', reverse_result>(res);
}
// first IP on the last segment point - this means that the first point is outside
if ( first_in_range && op_blocked )
@@ -598,9 +629,6 @@ struct linear_linear
update_result<boundary, exterior, '0', reverse_result>(res);
}
}
// TODO symetric case
// last IP and the first segment point -> last IP and op == union
}
// boundaries don't overlap
else
@@ -620,157 +648,163 @@ struct linear_linear
}
}
}
else if ( op == overlay::operation_continue )
{
//update_result<interior, interior, '1', reverse_result>(res);
}
}
// here, the possible exit is the real one
// we know that we entered and now we exit
if ( exit_watcher.is_exit_detected() )
if ( exit_watcher.is_exit_detected() || last_union ) // THIS CHECK IS REDUNDANT
{
// for sure
update_result<interior, exterior, '1', reverse_result>(res);
// TODO: check if the last point is indeed the boundary
// For LS it's sufficient to check has_boundary
update_result<boundary, exterior, '0', reverse_result>(res);
BOOST_ASSERT(first != last);
TurnIt prev = last;
--prev;
segment_identifier const& prev_seg_id = prev->operations[OpId].seg_id;
// if there is a boundary on the last point
if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1
&& boundary_checker.template is_boundary<boundary_back_explicit>
(range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) )
{
update_result<boundary, exterior, '0', reverse_result>(res);
}
}
}
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'>();
}
//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_intersection) )
// res.template update<interior, interior, '1'>();
if ( it->has(overlay::operation_blocked) )
if ( !b )
res.template update<interior, interior, '0'>();
}
}
}
// 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);
//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;
}
// 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));
}
//// 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);
//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 ( 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'>();
}
// 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);
// 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 ( 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'>();
}
}
// 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