summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay/get_turn_info.hpp')
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp294
1 files changed, 248 insertions, 46 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index 6d92b1bd3c..c6429bc558 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -21,11 +21,12 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
+#include <boost/geometry/core/config.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
-#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -142,6 +143,72 @@ struct base_turn_handler
ctype const dy = get<1>(a) - get<1>(b);
return dx * dx + dy * dy;
}
+
+ template
+ <
+ std::size_t IndexP,
+ std::size_t IndexQ,
+ typename UniqueSubRange1,
+ typename UniqueSubRange2,
+ typename UmbrellaStrategy,
+ typename TurnInfo
+ >
+ static inline void both_collinear(
+ UniqueSubRange1 const& range_p,
+ UniqueSubRange2 const& range_q,
+ UmbrellaStrategy const&,
+ std::size_t index_p, std::size_t index_q,
+ TurnInfo& ti)
+ {
+ boost::ignore_unused(range_p, range_q);
+ BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1);
+ BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2);
+ BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2);
+
+#if ! defined(BOOST_GEOMETRY_USE_RESCALING)
+ ti.operations[IndexP].remaining_distance = distance_measure(ti.point, range_p.at(index_p));
+ ti.operations[IndexQ].remaining_distance = distance_measure(ti.point, range_q.at(index_q));
+
+ // pk/q2 is considered as collinear, but there might be
+ // a tiny measurable difference. If so, use that.
+ // Calculate pk // qj-qk
+ typedef detail::distance_measure
+ <
+ typename select_coordinate_type
+ <
+ typename UniqueSubRange1::point_type,
+ typename UniqueSubRange2::point_type
+ >::type
+ > dm_type;
+
+ const bool p_closer =
+ ti.operations[IndexP].remaining_distance
+ < ti.operations[IndexQ].remaining_distance;
+ dm_type const dm
+ = p_closer
+ ? get_distance_measure<typename UmbrellaStrategy::cs_tag>(range_q.at(index_q - 1),
+ range_q.at(index_q), range_p.at(index_p))
+ : get_distance_measure<typename UmbrellaStrategy::cs_tag>(range_p.at(index_p - 1),
+ range_p.at(index_p), range_q.at(index_q));
+
+ if (! dm.is_zero())
+ {
+ // Not truely collinear, distinguish for union/intersection
+ // If p goes left (positive), take that for a union
+
+ bool p_left = p_closer ? dm.is_positive() : dm.is_negative();
+
+ ti.operations[IndexP].operation = p_left
+ ? operation_union : operation_intersection;
+ ti.operations[IndexQ].operation = p_left
+ ? operation_intersection : operation_union;
+ return;
+ }
+#endif
+
+ both(ti, operation_continue);
+ }
+
};
@@ -159,14 +226,16 @@ struct touch_interior : public base_turn_handler
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
- typename SidePolicy
+ typename SidePolicy,
+ typename UmbrellaStrategy
>
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info,
- SidePolicy const& side)
+ SidePolicy const& side,
+ UmbrellaStrategy const& umbrella_strategy)
{
assign_point(ti, method_touch_interior, intersection_info, 0);
@@ -266,19 +335,8 @@ struct touch_interior : public base_turn_handler
// Q intersects on interior of P and continues collinearly
if (side_qk_q == side_qi_p)
{
- // Collinearly in the same direction
- // (Q comes from left of P and turns left,
- // OR Q comes from right of P and turns right)
- // Omit second intersection point.
- // Union: just continue
- // Intersection: just continue
- both(ti, operation_continue);
-
- // Calculate remaining distance.
- // Q arrives at p, at point qj, so use qk for q
- // and use pj for p
- ti.operations[index_p].remaining_distance = distance_measure(ti.point, range_p.at(1));
- ti.operations[index_q].remaining_distance = distance_measure(ti.point, range_q.at(2));
+ both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy, 1, 2, ti);
+ return;
}
else
{
@@ -326,14 +384,16 @@ struct touch : public base_turn_handler
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
- typename SidePolicy
+ typename SideCalculator,
+ typename UmbrellaStrategy
>
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info,
- SidePolicy const& side)
+ SideCalculator const& side,
+ UmbrellaStrategy const& umbrella_strategy)
{
assign_point(ti, method_touch, intersection_info, 0);
@@ -369,13 +429,12 @@ struct touch : public base_turn_handler
// (#BRL2)
if (side_pk_q2 == 0 && ! block_q)
{
- both(ti, operation_continue);
+ both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti);
return;
}
int const side_pk_q1 = has_pk && has_qk ? side.pk_wrt_q1() : 0;
-
// Collinear opposite case -> block P
// (#BRL4, #BLR8)
if (side_pk_q1 == 0)
@@ -513,14 +572,16 @@ struct equal : public base_turn_handler
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
- typename SidePolicy
+ typename SideCalculator,
+ typename UmbrellaStrategy
>
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& info,
DirInfo const& ,
- SidePolicy const& side)
+ SideCalculator const& side,
+ UmbrellaStrategy const& umbrella_strategy)
{
// Copy the intersection point in TO direction
assign_point(ti, method_equal, info, non_opposite_to_index(info));
@@ -538,8 +599,7 @@ struct equal : public base_turn_handler
// oppositely
if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
{
- both(ti, operation_continue);
-
+ both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti);
return;
}
@@ -562,6 +622,132 @@ struct equal : public base_turn_handler
template
<
+ typename TurnInfo
+>
+struct start : public base_turn_handler
+{
+ template
+ <
+ typename UniqueSubRange1,
+ typename UniqueSubRange2,
+ typename IntersectionInfo,
+ typename DirInfo,
+ typename SideCalculator,
+ typename UmbrellaStrategy
+ >
+ static inline bool apply(UniqueSubRange1 const& range_p,
+ UniqueSubRange2 const& range_q,
+ TurnInfo& ti,
+ IntersectionInfo const& info,
+ DirInfo const& dir_info,
+ SideCalculator const& side,
+ UmbrellaStrategy const& )
+ {
+ // For now disabled. TODO: remove all code or fix inconsistencies
+ // within validity and relations
+ return false;
+
+ if (dir_info.opposite)
+ {
+ // They should not be collinear
+ return false;
+ }
+
+ int const side_pj_q1 = side.pj_wrt_q1();
+ int const side_qj_p1 = side.qj_wrt_p1();
+
+ // Get side values at starting point
+ typedef detail::distance_measure
+ <
+ typename select_coordinate_type
+ <
+ typename UniqueSubRange1::point_type,
+ typename UniqueSubRange2::point_type
+ >::type
+ > dm_type;
+
+ typedef typename UmbrellaStrategy::cs_tag cs_tag;
+ dm_type const dm_pi_q1 = get_distance_measure<cs_tag>(range_q.at(0), range_q.at(1), range_p.at(0));
+ dm_type const dm_qi_p1 = get_distance_measure<cs_tag>(range_p.at(0), range_p.at(1), range_q.at(0));
+
+ if (dir_info.how_a == -1 && dir_info.how_b == -1)
+ {
+ // Both p and q leave
+ if (dm_pi_q1.is_zero() && dm_qi_p1.is_zero())
+ {
+ // Exactly collinear, not necessary to handle it
+ return false;
+ }
+
+ if (! (dm_pi_q1.is_small() && dm_qi_p1.is_small()))
+ {
+ // Not nearly collinear
+ return false;
+ }
+
+ if (side_qj_p1 == 0)
+ {
+ // Collinear is not handled
+ return false;
+ }
+
+ ui_else_iu(side_qj_p1 == -1, ti);
+ }
+ else if (dir_info.how_b == -1)
+ {
+ // p --------------->
+ // |
+ // | q q leaves
+ // v
+ //
+
+ if (dm_qi_p1.is_zero() || ! dm_qi_p1.is_small())
+ {
+ // Exactly collinear
+ return false;
+ }
+
+ if (side_qj_p1 == 0)
+ {
+ // Collinear is not handled
+ return false;
+ }
+
+ ui_else_iu(side_qj_p1 == -1, ti);
+ }
+ else if (dir_info.how_a == -1)
+ {
+ if (dm_pi_q1.is_zero() || ! dm_pi_q1.is_small())
+ {
+ // It starts exactly, not necessary to handle it
+ return false;
+ }
+
+ // p leaves
+ if (side_pj_q1 == 0)
+ {
+ // Collinear is not handled
+ return false;
+ }
+
+ ui_else_iu(side_pj_q1 == 1, ti);
+ }
+ else
+ {
+ // Not supported
+ return false;
+ }
+
+ // Copy intersection point
+ assign_point(ti, method_start, info, 0);
+ return true;
+ }
+
+};
+
+
+template
+<
typename TurnInfo,
typename AssignPolicy
>
@@ -950,7 +1136,7 @@ struct get_turn_info
typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
- typename IntersectionStrategy,
+ typename UmbrellaStrategy,
typename RobustPolicy,
typename OutputIterator
>
@@ -958,7 +1144,7 @@ struct get_turn_info
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& tp_model,
- IntersectionStrategy const& intersection_strategy,
+ UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
@@ -966,30 +1152,24 @@ struct get_turn_info
<
UniqueSubRange1, UniqueSubRange2,
typename TurnInfo::point_type,
- IntersectionStrategy,
+ UmbrellaStrategy,
RobustPolicy
> inters_info;
- inters_info inters(range_p, range_q,
- intersection_strategy, robust_policy);
+ inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
+ bool do_only_convert = false;
+
// Select method and apply
switch(method)
{
- case 'a' : // collinear, "at"
- case 'f' : // collinear, "from"
- case 's' : // starts from the middle
- if (AssignPolicy::include_no_turn
- && inters.i_info().count > 0)
- {
- only_convert::apply(tp, inters.i_info());
- *out++ = tp;
- }
+ case 'a' : // "angle"
+ do_only_convert = true;
break;
case 'd' : // disjoint: never do anything
@@ -1000,19 +1180,19 @@ struct get_turn_info
typedef touch_interior
<
TurnInfo
- > policy;
+ > handler;
// If Q (1) arrives (1)
if ( inters.d_info().arrival[1] == 1 )
{
- policy::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
- inters.sides());
+ handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
+ inters.sides(), umbrella_strategy);
}
else
{
// Swap p/q
- policy::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
- inters.get_swapped_sides());
+ handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
+ inters.get_swapped_sides(), umbrella_strategy);
}
*out++ = tp;
}
@@ -1026,17 +1206,31 @@ struct get_turn_info
case 't' :
{
// Both touch (both arrive there)
- touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides());
+ touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
*out++ = tp;
}
break;
+ case 'f' :
+ case 's' :
+ {
+ // "from" or "start" without rescaling, it is in some cases necessary to handle
+ if (start<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy))
+ {
+ *out++ = tp;
+ }
+ else
+ {
+ do_only_convert = true;
+ }
+ }
+ break;
case 'e':
{
if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
- equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides());
+ equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
*out++ = tp;
}
else
@@ -1059,7 +1253,7 @@ struct get_turn_info
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(range_p, range_q, tp,
- inters.i_info(), inters.d_info(), inters.sides());
+ inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy);
// override assigned method
tp.method = method_collinear;
@@ -1105,6 +1299,14 @@ struct get_turn_info
break;
}
+ if (do_only_convert
+ && AssignPolicy::include_no_turn
+ && inters.i_info().count > 0)
+ {
+ only_convert::apply(tp, inters.i_info());
+ *out++ = tp;
+ }
+
return out;
}
};