Merge branch 'develop' of https://github.com/boostorg/geometry into feature/point_iterator

This commit is contained in:
Menelaos Karavelas
2014-05-05 10:22:25 +03:00
11 changed files with 1120 additions and 587 deletions

View File

@@ -21,7 +21,7 @@
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@@ -60,36 +60,6 @@ public:
namespace detail { namespace overlay
{
template <typename PointP, typename PointQ,
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
>
struct side_calculator
{
typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
Qi const& qi, Qj const& qj, Qk const& qk)
: m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
{}
inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
Pi const& m_pi;
Pj const& m_pj;
Pk const& m_pk;
Qi const& m_qi;
Qj const& m_qj;
Qk const& m_qk;
};
struct base_turn_handler
{
// Returns true if both sides are opposite
@@ -741,7 +711,7 @@ private :
}
public:
static inline void empty_replacer(method_type &, operation_type &, operation_type &) {}
static inline void empty_transformer(TurnInfo &) {}
template
<
@@ -764,7 +734,7 @@ public:
DirInfo const& dir_info,
SidePolicy const& side)
{
apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_replacer);
apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
}
public:
@@ -776,7 +746,7 @@ public:
typename IntersectionInfo,
typename DirInfo,
typename SidePolicy,
typename MethodAndOperationsReplacer
typename TurnTransformer
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
@@ -789,7 +759,7 @@ public:
IntersectionInfo const& intersection_info,
DirInfo const& dir_info,
SidePolicy const& side,
MethodAndOperationsReplacer method_and_operations_replacer,
TurnTransformer turn_transformer,
bool const is_pk_valid = true, bool const is_qk_valid = true)
{
TurnInfo tp = tp_model;
@@ -799,7 +769,7 @@ public:
&& is_pk_valid
&& set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
{
method_and_operations_replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer(tp);
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
@@ -810,7 +780,7 @@ public:
&& is_qk_valid
&& set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
{
method_and_operations_replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer(tp);
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
@@ -947,41 +917,12 @@ struct get_turn_info
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
>::type robust_point_type;
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters_info;
robust_point_type pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob;
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(pk_rob, pk, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
geometry::recalculate(qk_rob, qk, robust_policy);
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
segment_type1 p1(pi, pj);
segment_type2 q1(qi, qj);
side_calculator<robust_point_type, robust_point_type> side_calc(pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob);
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type,
RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result = strategy::apply(p1, q1,
robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
char const method = result.template get<1>().how;
char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
@@ -993,11 +934,10 @@ struct get_turn_info
case 'f' : // collinear, "from"
case 's' : // starts from the middle
if (AssignPolicy::include_no_turn
&& result.template get<0>().count > 0)
&& inters.i_info().count > 0)
{
only_convert::apply(tp,
result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
only_convert::apply(tp, inters.i_info());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -1013,29 +953,34 @@ struct get_turn_info
> policy;
// If Q (1) arrives (1)
if (result.template get<1>().arrival[1] == 1)
if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(),
side_calc);
tp, inters.i_info(), inters.d_info(),
inters.sides());
}
else
{
// Swap p/q
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator
<
typename inters_info::robust_point2_type,
typename inters_info::robust_point1_type
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, result.template get<0>(), result.template get<1>(),
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
}
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'i' :
{
crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
tp, inters.i_info(), inters.d_info());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -1043,20 +988,20 @@ struct get_turn_info
{
// Both touch (both arrive there)
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
tp, inters.i_info(), inters.d_info(), inters.sides());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'e':
{
if (! result.template get<1>().opposite)
if ( ! inters.d_info().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);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
tp, inters.i_info(), inters.d_info(), inters.sides());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
else
@@ -1066,21 +1011,21 @@ struct get_turn_info
TurnInfo,
AssignPolicy
>::apply(pi, qi,
tp, out, result.template get<0>(), result.template get<1>());
tp, out, inters.i_info(), inters.d_info());
}
}
break;
case 'c' :
{
// Collinear
if (! result.template get<1>().opposite)
if ( ! inters.d_info().opposite )
{
if (result.template get<1>().arrival[0] == 0)
if ( inters.d_info().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);
tp, inters.i_info(), inters.d_info(), inters.sides());
// override assigned method
tp.method = method_collinear;
@@ -1088,10 +1033,10 @@ struct get_turn_info
else
{
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
}
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
else
@@ -1101,7 +1046,7 @@ struct get_turn_info
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, result.template get<0>(), result.template get<1>(), side_calc);
tp, out, inters.i_info(), inters.d_info(), inters.sides());
}
}
break;
@@ -1110,8 +1055,8 @@ struct get_turn_info
// degenerate points
if (AssignPolicy::include_degenerate)
{
only_convert::apply(tp, result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
only_convert::apply(tp, inters.i_info());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}

View File

@@ -15,177 +15,13 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay {
// TURN_OPERATION
enum turn_position { position_middle, position_front, position_back };
template <typename SegmentRatio>
struct turn_operation_linear
: public turn_operation<SegmentRatio>
{
turn_operation_linear()
: position(position_middle)
, is_collinear(false)
{}
turn_position position;
bool is_collinear; // valid only for Linear geometry
};
template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
class intersection_info
{
typedef typename strategy_intersection
<
typename cs_tag<TurnPoint>::type,
Point1,
Point2,
TurnPoint,
RobustPolicy
>::segment_intersection_strategy_type strategy;
public:
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
typedef side_calculator<Point1, Point2> side_calculator_type;
typedef typename strategy::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
RobustPolicy const& robust_policy)
: m_result(strategy::apply(segment_type1(pi, pj),
segment_type2(qi, qj),
robust_policy))
, m_side_calc(pi, pj, pk, qi, qj, qk)
, m_robust_policy(robust_policy)
{}
inline Point1 const& pi() const { return m_side_calc.m_pi; }
inline Point1 const& pj() const { return m_side_calc.m_pj; }
inline Point1 const& pk() const { return m_side_calc.m_pk; }
inline Point2 const& qi() const { return m_side_calc.m_qi; }
inline Point2 const& qj() const { return m_side_calc.m_qj; }
inline Point2 const& qk() const { return m_side_calc.m_qk; }
inline side_calculator_type const& sides() const { return m_side_calc; }
inline result_type const& result() const { return m_result; }
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
// TODO: not it's more like is_spike_ip_p
inline bool is_spike_p() const
{
if ( m_side_calc.pk_wrt_p1() == 0 )
{
if ( ! is_ip_j<0>() )
return false;
int const qk_p1 = m_side_calc.qk_wrt_p1();
int const qk_p2 = m_side_calc.qk_wrt_p2();
if ( qk_p1 == -qk_p2 )
{
if ( qk_p1 == 0 )
{
return is_spike_of_collinear(pi(), pj(), pk());
}
return true;
}
}
return false;
}
// TODO: not it's more like is_spike_ip_q
inline bool is_spike_q() const
{
if ( m_side_calc.qk_wrt_q1() == 0 )
{
if ( ! is_ip_j<1>() )
return false;
int const pk_q1 = m_side_calc.pk_wrt_q1();
int const pk_q2 = m_side_calc.pk_wrt_q2();
if ( pk_q1 == -pk_q2 )
{
if ( pk_q1 == 0 )
{
return is_spike_of_collinear(qi(), qj(), qk());
}
return true;
}
}
return false;
}
private:
template <typename Point>
inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
{
typedef model::referring_segment<Point const> seg_t;
typedef strategy_intersection
<
typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result
= strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
return result.template get<0>().count == 2;
}
template <std::size_t OpId>
bool is_ip_j() const
{
int arrival = d_info().arrival[OpId];
bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
if ( same_dirs )
{
if ( i_info().count == 2 )
{
if ( ! d_info().opposite )
{
return arrival != -1;
}
else
{
return arrival != -1;
}
}
else
{
return arrival == 0;
}
}
else
{
return arrival == 1;
}
}
result_type m_result;
side_calculator_type m_side_calc;
RobustPolicy const& m_robust_policy;
};
// SEGMENT_INTERSECTION RESULT
// C H0 H1 A0 A1 O IP1 IP2
@@ -484,20 +320,24 @@ struct get_turn_info_for_endpoint
if ( append_first || append_last )
{
bool handled = handle_internal(pi, pj, pk, qi, qj, qk,
is_p_first_ip, is_p_last_ip,
is_q_first_ip, is_q_last_ip,
ip_info.is_qi, ip_info.is_qj,
tp_model, inters.result(), ip_index,
p_operation, q_operation);
bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
inters.rpi(), inters.rpj(), inters.rpk(),
inters.rqi(), inters.rqj(), inters.rqk(),
is_p_first_ip, is_p_last_ip,
is_q_first_ip, is_q_last_ip,
ip_info.is_qi, ip_info.is_qj,
tp_model, inters, ip_index,
p_operation, q_operation);
if ( !handled )
{
handle_internal(qi, qj, qk, pi, pj, pk,
is_q_first_ip, is_q_last_ip,
is_p_first_ip, is_p_last_ip,
ip_info.is_pi, ip_info.is_pj,
tp_model, inters.result(), ip_index,
q_operation, p_operation);
handle_internal<1>(qi, qj, qk, pi, pj, pk,
inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk(),
is_q_first_ip, is_q_last_ip,
is_p_first_ip, is_p_last_ip,
ip_info.is_pi, ip_info.is_pj,
tp_model, inters, ip_index,
q_operation, p_operation);
}
if ( p_operation != operation_none )
@@ -516,9 +356,9 @@ struct get_turn_info_for_endpoint
&& inters.is_spike_p() )
{
assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
p_pos, q_pos, tp_model, out);
p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
p_pos, q_pos, tp_model, out);
p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
}
// Q is spike and should be handled
else if ( !is_q_last
@@ -527,15 +367,15 @@ struct get_turn_info_for_endpoint
&& inters.is_spike_q() )
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
p_pos, q_pos, tp_model, out);
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
p_pos, q_pos, tp_model, out);
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
}
// no spikes
else
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
p_pos, q_pos, tp_model, out);
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
}
}
}
@@ -546,16 +386,21 @@ struct get_turn_info_for_endpoint
// TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment
// however now it's lazily calculated and then it would be always calculated
template<typename Point1,
template<std::size_t G1Index,
typename Point1,
typename Point2,
typename RobustPoint1,
typename RobustPoint2,
typename TurnInfo,
typename IntersectionResult
typename IntersectionInfo
>
static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/,
Point2 const& i2, Point2 const& j2, Point2 const& k2,
RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
bool first1, bool last1, bool first2, bool last2,
bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
IntersectionResult const& result, int ip_index,
IntersectionInfo const& inters, int ip_index,
operation_type & op1, operation_type & op2)
{
boost::ignore_unused_variable_warning(ip_index);
@@ -568,7 +413,7 @@ struct get_turn_info_for_endpoint
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
inters_pt = inters.i_info().intersections[ip_index];
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
#endif
@@ -581,7 +426,8 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
side_calculator<Point1, Point2, Point2> side_calc(i2, i1, j1, i2, j2, k2);
side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
side_calc(ri2, ri1, rj1, ri2, rj2, rk2);
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
@@ -591,11 +437,16 @@ struct get_turn_info_for_endpoint
if ( operations_both(operations, operation_continue) )
{
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
bool opposite = result.template get<1>().opposite;
if ( op1 != operation_union
|| op2 != operation_union
|| ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
{
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
bool opposite = inters.d_info().opposite;
op1 = operation_intersection;
op2 = opposite ? operation_union : operation_intersection;
op1 = operation_intersection;
op2 = opposite ? operation_union : operation_intersection;
}
}
else
{
@@ -613,7 +464,7 @@ struct get_turn_info_for_endpoint
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
inters_pt = inters.i_info().intersections[ip_index];
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
#endif
@@ -626,7 +477,8 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
side_calculator<Point1, Point2, Point2> side_calc(i2, j1, i1, i2, j2, k2);
side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
side_calc(ri2, rj1, ri1, ri2, rj2, rk2);
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
@@ -636,11 +488,16 @@ struct get_turn_info_for_endpoint
if ( operations_both(operations, operation_continue) )
{
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
bool second_going_out = result.template get<0>().count > 1;
if ( op1 != operation_blocked
|| op2 != operation_union
|| ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
{
// THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
bool second_going_out = inters.i_info().count > 1;
op1 = operation_blocked;
op2 = second_going_out ? operation_union : operation_intersection;
op1 = operation_blocked;
op2 = second_going_out ? operation_union : operation_intersection;
}
}
else
{
@@ -684,6 +541,8 @@ struct get_turn_info_for_endpoint
method_type method,
operation_type op0, operation_type op1,
turn_position pos0, turn_position pos1,
bool is_p_first_ip, bool is_q_first_ip,
bool is_p_spike, bool is_q_spike,
TurnInfo const& tp_model,
OutputIterator out)
{
@@ -698,13 +557,23 @@ struct get_turn_info_for_endpoint
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 )
{
// NOTE: is_collinear is NOT set for the first endpoint
// for which there is no preceding segment
//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;
if ( ! is_p_first_ip )
{
tp.operations[0].is_collinear = op0 != operation_intersection
|| is_p_spike;
}
if ( ! is_q_first_ip )
{
tp.operations[1].is_collinear = op1 != operation_intersection
|| is_q_spike;
}
}
else //if ( result.template get<0>().count == 1 )
{

View File

@@ -0,0 +1,336 @@
// 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_OVERLAY_GET_TURN_INFO_HELPERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay {
enum turn_position { position_middle, position_front, position_back };
template <typename SegmentRatio>
struct turn_operation_linear
: public turn_operation<SegmentRatio>
{
turn_operation_linear()
: position(position_middle)
, is_collinear(false)
{}
turn_position position;
bool is_collinear; // valid only for Linear geometry
};
template <typename PointP, typename PointQ,
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
>
struct side_calculator
{
typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
Qi const& qi, Qj const& qj, Qk const& qk)
: m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
{}
inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
Pi const& m_pi;
Pj const& m_pj;
Pk const& m_pk;
Qi const& m_qi;
Qj const& m_qj;
Qk const& m_qk;
};
template <typename Point1, typename Point2, typename RobustPolicy>
struct robust_points
{
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
>::type robust_point1_type;
// TODO: define robust_point2_type using Point2?
typedef robust_point1_type robust_point2_type;
inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
RobustPolicy const& robust_policy)
{
geometry::recalculate(m_rpi, pi, robust_policy);
geometry::recalculate(m_rpj, pj, robust_policy);
geometry::recalculate(m_rpk, pk, robust_policy);
geometry::recalculate(m_rqi, qi, robust_policy);
geometry::recalculate(m_rqj, qj, robust_policy);
geometry::recalculate(m_rqk, qk, robust_policy);
}
robust_point1_type m_rpi, m_rpj, m_rpk;
robust_point2_type m_rqi, m_rqj, m_rqk;
};
template <typename Point1, typename Point2, typename RobustPolicy>
class intersection_info_base
: private robust_points<Point1, Point2, RobustPolicy>
{
typedef robust_points<Point1, Point2, RobustPolicy> base_t;
public:
typedef Point1 point1_type;
typedef Point2 point2_type;
typedef typename base_t::robust_point1_type robust_point1_type;
typedef typename base_t::robust_point2_type robust_point2_type;
typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type;
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
RobustPolicy const& robust_policy)
: base_t(pi, pj, pk, qi, qj, qk, robust_policy)
, m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk,
base_t::m_rqi, base_t::m_rqj, base_t::m_rqk)
, m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
{}
inline Point1 const& pi() const { return m_pi; }
inline Point1 const& pj() const { return m_pj; }
inline Point1 const& pk() const { return m_pk; }
inline Point2 const& qi() const { return m_qi; }
inline Point2 const& qj() const { return m_qj; }
inline Point2 const& qk() const { return m_qk; }
inline robust_point1_type const& rpi() const { return base_t::m_rpi; }
inline robust_point1_type const& rpj() const { return base_t::m_rpj; }
inline robust_point1_type const& rpk() const { return base_t::m_rpk; }
inline robust_point2_type const& rqi() const { return base_t::m_rqi; }
inline robust_point2_type const& rqj() const { return base_t::m_rqj; }
inline robust_point2_type const& rqk() const { return base_t::m_rqk; }
inline side_calculator_type const& sides() const { return m_side_calc; }
private:
side_calculator_type m_side_calc;
point1_type const& m_pi;
point1_type const& m_pj;
point1_type const& m_pk;
point2_type const& m_qi;
point2_type const& m_qj;
point2_type const& m_qk;
};
template <typename Point1, typename Point2>
class intersection_info_base<Point1, Point2, detail::no_rescale_policy>
{
public:
typedef Point1 point1_type;
typedef Point2 point2_type;
typedef Point1 robust_point1_type;
typedef Point2 robust_point2_type;
typedef side_calculator<Point1, Point2> side_calculator_type;
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
no_rescale_policy const& robust_policy)
: m_side_calc(pi, pj, pk, qi, qj, qk)
{}
inline Point1 const& pi() const { return m_side_calc.m_pi; }
inline Point1 const& pj() const { return m_side_calc.m_pj; }
inline Point1 const& pk() const { return m_side_calc.m_pk; }
inline Point2 const& qi() const { return m_side_calc.m_qi; }
inline Point2 const& qj() const { return m_side_calc.m_qj; }
inline Point2 const& qk() const { return m_side_calc.m_qk; }
inline Point1 const& rpi() const { return pi(); }
inline Point1 const& rpj() const { return pj(); }
inline Point1 const& rpk() const { return pk(); }
inline Point2 const& rqi() const { return qi(); }
inline Point2 const& rqj() const { return qj(); }
inline Point2 const& rqk() const { return qk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
private:
side_calculator_type m_side_calc;
};
template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
class intersection_info
: public intersection_info_base<Point1, Point2, RobustPolicy>
{
typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t;
typedef typename strategy_intersection
<
typename cs_tag<TurnPoint>::type,
Point1,
Point2,
TurnPoint,
RobustPolicy
>::segment_intersection_strategy_type strategy;
public:
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
typedef typename base_t::side_calculator_type side_calculator_type;
typedef typename strategy::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
RobustPolicy const& robust_policy)
: base_t(pi, pj, pk, qi, qj, qk, robust_policy)
, m_result(strategy::apply(segment_type1(pi, pj),
segment_type2(qi, qj),
robust_policy))
, m_robust_policy(robust_policy)
{}
inline result_type const& result() const { return m_result; }
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
// TODO: it's more like is_spike_ip_p
inline bool is_spike_p() const
{
if ( base_t::sides().pk_wrt_p1() == 0 )
{
if ( ! is_ip_j<0>() )
return false;
int const qk_p1 = base_t::sides().qk_wrt_p1();
int const qk_p2 = base_t::sides().qk_wrt_p2();
if ( qk_p1 == -qk_p2 )
{
if ( qk_p1 == 0 )
{
return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk());
}
return true;
}
}
return false;
}
// TODO: it's more like is_spike_ip_q
inline bool is_spike_q() const
{
if ( base_t::sides().qk_wrt_q1() == 0 )
{
if ( ! is_ip_j<1>() )
return false;
int const pk_q1 = base_t::sides().pk_wrt_q1();
int const pk_q2 = base_t::sides().pk_wrt_q2();
if ( pk_q1 == -pk_q2 )
{
if ( pk_q1 == 0 )
{
return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk());
}
return true;
}
}
return false;
}
private:
template <typename Point>
inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
{
typedef model::referring_segment<Point const> seg_t;
typedef strategy_intersection
<
typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result
= strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
return result.template get<0>().count == 2;
}
template <std::size_t OpId>
bool is_ip_j() const
{
int arrival = d_info().arrival[OpId];
bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
if ( same_dirs )
{
if ( i_info().count == 2 )
{
if ( ! d_info().opposite )
{
return arrival != -1;
}
else
{
return arrival != -1;
}
}
else
{
return arrival == 0;
}
}
else
{
return arrival == 1;
}
}
result_type m_result;
RobustPolicy const& m_robust_policy;
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP

View File

@@ -47,8 +47,10 @@ struct get_turn_info_linear_areal
RobustPolicy const& robust_policy,
OutputIterator out)
{
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters(pi, pj, pk, qi, qj, qk, robust_policy);
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters_info;
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
char const method = inters.d_info().how;
@@ -64,7 +66,7 @@ struct get_turn_info_linear_areal
get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, inters.result(), method_none, out);
tp_model, inters, method_none, out);
break;
case 'd' : // disjoint: never do anything
@@ -75,7 +77,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, inters.result(), method_touch_interior, out) )
tp_model, inters, method_touch_interior, out) )
{
// do nothing
}
@@ -96,7 +98,12 @@ struct get_turn_info_linear_areal
else
{
// Swap p/q
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator
<
typename inters_info::robust_point2_type,
typename inters_info::robust_point1_type
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
@@ -138,7 +145,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, inters.result(), method_touch, out) )
tp_model, inters, method_touch, out) )
{
// do nothing
}
@@ -152,11 +159,62 @@ struct get_turn_info_linear_areal
tp.operations[0].is_collinear = true;
}
// workarounds for touch<> not taking spikes into account starts here
// those was discovered empirically
// touch<> is not symmetrical!
// P spikes and Q spikes may produce various operations!
// Only P spikes are valid for L/A
// TODO: this is not optimal solution - think about rewriting touch<>
if ( tp.operations[0].operation == operation_blocked )
{
// a spike on P on the same line with Q1
if ( inters.is_spike_p() )
{
if ( inters.sides().qk_wrt_p1() == 0 )
{
tp.operations[0].is_collinear = true;
}
else
{
tp.operations[0].operation = operation_union;
}
}
}
else if ( tp.operations[0].operation == operation_continue
&& tp.operations[1].operation == operation_continue )
{
// P spike on the same line with Q2 (opposite)
if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
&& inters.is_spike_p() )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
}
}
else if ( tp.operations[0].operation == operation_none
&& tp.operations[1].operation == operation_none )
{
// spike not handled by touch<>
if ( inters.is_spike_p() )
{
tp.operations[0].operation = operation_intersection;
tp.operations[1].operation = operation_union;
if ( inters.sides().pk_wrt_q2() == 0 )
{
tp.operations[0].operation = operation_continue; // will be converted to i
tp.operations[0].is_collinear = true;
}
}
}
// workarounds for touch<> not taking spikes into account ends here
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
// this function assumes that 'u' must be set for a spike
bool ignore_spike
= calculate_spike_operation(tp.operations[0].operation,
inters, is_p_last);
@@ -166,7 +224,7 @@ struct get_turn_info_linear_areal
if ( ! handle_spikes
|| ignore_spike
|| ! append_opposite_spikes<append_touches>( // for 'i' or 'c'
|| ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i???
tp, inters, is_p_last, is_q_last, out) )
{
*out++ = tp;
@@ -179,7 +237,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, inters.result(), method_equal, out) )
tp_model, inters, method_equal, out) )
{
// do nothing
}
@@ -194,8 +252,8 @@ struct get_turn_info_linear_areal
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec<false> replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer_ec<false> transformer(method_touch);
transformer(tp);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
@@ -226,7 +284,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, inters.result(), method_collinear, out) )
tp_model, inters, method_collinear, out) )
{
// do nothing
}
@@ -257,8 +315,8 @@ struct get_turn_info_linear_areal
//version = append_collinear;
}
replacer_of_method_and_operations_ec<false> replacer(method_replace);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer_ec<false> transformer(method_replace);
transformer(tp);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
@@ -275,7 +333,7 @@ struct get_turn_info_linear_areal
else
{
// Is this always 'm' ?
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
turn_transformer_ec<false> transformer(method_touch_interior);
// conditionally handle spikes
if ( handle_spikes )
@@ -294,7 +352,7 @@ struct get_turn_info_linear_areal
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, inters.i_info(), inters.d_info(),
inters.sides(), replacer);
inters.sides(), transformer);
}
}
}
@@ -344,18 +402,38 @@ struct get_turn_info_linear_areal
IntersectionInfo const& inters,
bool is_p_last)
{
bool is_p_spike = op == operation_union
bool is_p_spike = ( op == operation_union || op == operation_intersection )
&& ! is_p_last
&& inters.is_spike_p();
// we don't know where the spike is going since for both directions 'u' is set
if ( is_p_spike )
{
if ( inters.sides().pk_wrt_q1() < 0 && inters.sides().pk_wrt_q2() < 0 )
bool going_in = false, going_out = false;
int const pk_q1 = inters.sides().pk_wrt_q1();
int const pk_q2 = inters.sides().pk_wrt_q2();
if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C
{
going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both
going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them
}
else
{
going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them
going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both
}
if ( going_in )
{
op = operation_intersection;
return true;
}
else if ( going_out )
{
op = operation_union;
return true;
}
}
return false;
@@ -416,7 +494,7 @@ struct get_turn_info_linear_areal
{
bool is_p_spike = ( Version == append_touches ?
( tp.operations[0].operation == operation_continue
|| tp.operations[0].operation == operation_intersection ) :
|| tp.operations[0].operation == operation_intersection ) : // i ???
true )
&& ! is_p_last
&& inters.is_spike_p();
@@ -433,13 +511,13 @@ struct get_turn_info_linear_areal
if ( Version == append_touches )
{
tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = ???
//tp.operations[1].is_collinear = false;
tp.method = method_touch;
}
else
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = false;
BOOST_ASSERT(inters.i_info().count > 1);
base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
@@ -495,25 +573,29 @@ struct get_turn_info_linear_areal
}
template <bool IsFront>
class replacer_of_method_and_operations_ec
class turn_transformer_ec
{
public:
explicit replacer_of_method_and_operations_ec(method_type method_t_or_m)
explicit turn_transformer_ec(method_type method_t_or_m)
: m_method(method_t_or_m)
{}
void operator()(method_type & method,
operation_type & op0,
operation_type & op1) const
template <typename Turn>
void operator()(Turn & turn) const
{
operation_type & op0 = turn.operations[0].operation;
operation_type & op1 = turn.operations[1].operation;
// NOTE: probably only if methods are WRT IPs, not segments!
if ( IsFront
|| op0 == operation_intersection || op0 == operation_union
|| op1 == operation_intersection || op1 == operation_union )
{
method = m_method;
turn.method = m_method;
}
turn.operations[0].is_collinear = op0 != operation_blocked;
// Assuming G1 is always Linear
if ( op0 == operation_blocked )
{
@@ -550,7 +632,7 @@ struct get_turn_info_linear_areal
typename Point1,
typename Point2,
typename TurnInfo,
typename IntersectionResult,
typename IntersectionInfo,
typename OutputIterator>
static inline bool get_turn_info_for_endpoint(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
@@ -558,14 +640,14 @@ struct get_turn_info_linear_areal
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
TurnInfo const& tp_model,
IntersectionResult const& result,
IntersectionInfo const& inters,
method_type /*method*/,
OutputIterator out)
{
namespace ov = overlay;
typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
const std::size_t ip_count = result.template get<0>().count;
const std::size_t ip_count = inters.i_info().count;
// no intersection points
if ( ip_count == 0 )
return false;
@@ -577,11 +659,11 @@ struct get_turn_info_linear_areal
if ( !is_p_first && !is_p_last )
return false;
linear_intersections intersections(pi, qi, result, is_p_last, is_q_last);
linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
linear_intersections::ip_info const& ip0 = intersections.template get<0>();
linear_intersections::ip_info const& ip1 = intersections.template get<1>();
const bool opposite = result.template get<1>().opposite;
const bool opposite = inters.d_info().opposite;
// ANALYSE AND ASSIGN FIRST
@@ -604,7 +686,13 @@ struct get_turn_info_linear_areal
if ( ip0.is_qj )
{
side_calculator<Point1, Point2, Point2> side_calc(qi, pi, pj, qi, qj, qk);
side_calculator
<
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point2_type,
typename IntersectionInfo::robust_point2_type
> side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
inters.rqi(), inters.rqj(), inters.rqk());
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -616,9 +704,18 @@ struct get_turn_info_linear_areal
}
else
{
side_calculator<Point1, Point2,
Point2, Point1, Point1,
Point2, Point1, Point2> side_calc(qi, pi, pj, qi, pi, qj);
side_calculator
<
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point2_type,
typename IntersectionInfo::robust_point2_type,
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point2_type,
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point2_type
> side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
inters.rqi(), inters.rpi(), inters.rqj());
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -627,23 +724,20 @@ struct get_turn_info_linear_areal
tp.operations[1].operation = operations.second;
}
replacer_of_method_and_operations_ec<true> replacer(replaced_method);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer_ec<true> transformer(replaced_method);
transformer(tp);
}
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), 0);
base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0);
// 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;
}
// NOTE: is_collinear is not set for the first endpoint of L
// for which there is no preceding segment
// here is_p_first_ip == true
tp.operations[0].is_collinear = false;
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
@@ -656,7 +750,7 @@ struct get_turn_info_linear_areal
{
TurnInfo tp = tp_model;
if ( result.template get<0>().count > 1 )
if ( inters.i_info().count > 1 )
{
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
tp.operations[0].is_collinear = true;
@@ -664,7 +758,13 @@ struct get_turn_info_linear_areal
}
else //if ( result.template get<0>().count == 1 )
{
side_calculator<Point1, Point2, Point2> side_calc(qi, pj, pi, qi, qj, qk);
side_calculator
<
typename IntersectionInfo::robust_point1_type,
typename IntersectionInfo::robust_point2_type,
typename IntersectionInfo::robust_point2_type
> side_calc(inters.rqi(), inters.rpj(), inters.rpi(),
inters.rqi(), inters.rqj(), inters.rqk());
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -672,13 +772,10 @@ struct get_turn_info_linear_areal
tp.operations[0].operation = operations.first;
tp.operations[1].operation = operations.second;
replacer_of_method_and_operations_ec<false> replacer(method_none);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
turn_transformer_ec<false> transformer(method_none);
transformer(tp);
if ( tp.both(operation_continue) )
{
tp.operations[0].is_collinear = true;
}
tp.operations[0].is_collinear = tp.both(operation_continue);
}
tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior;
@@ -689,9 +786,9 @@ struct get_turn_info_linear_areal
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
std::size_t ip_index = ip_count > 1 ? 1 : 0;
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), ip_index);
base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
return true;

View File

@@ -44,8 +44,10 @@ struct get_turn_info_linear_linear
RobustPolicy const& robust_policy,
OutputIterator out)
{
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters(pi, pj, pk, qi, qj, qk, robust_policy);
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters_info;
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
char const method = inters.d_info().how;
@@ -93,7 +95,13 @@ struct get_turn_info_linear_linear
else
{
// Swap p/q
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator
<
typename inters_info::robust_point2_type,
typename inters_info::robust_point1_type
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
@@ -143,14 +151,109 @@ struct get_turn_info_linear_linear
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
if ( tp.operations[0].operation == operation_blocked )
// workarounds for touch<> not taking spikes into account starts here
// those was discovered empirically
// touch<> is not symmetrical!
// P spikes and Q spikes may produce various operations!
// TODO: this is not optimal solution - think about rewriting touch<>
if ( tp.operations[0].operation == operation_blocked
&& tp.operations[1].operation == operation_blocked )
{
tp.operations[1].is_collinear = true;
// two touching spikes on the same line
if ( inters.is_spike_p() && inters.is_spike_q() )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
}
else
{
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = true;
}
}
if ( tp.operations[1].operation == operation_blocked )
else if ( tp.operations[0].operation == operation_blocked )
{
tp.operations[0].is_collinear = true;
// a spike on P on the same line with Q1
if ( inters.is_spike_p() )
{
if ( inters.sides().qk_wrt_p1() == 0 )
{
tp.operations[0].is_collinear = true;
}
else
{
tp.operations[0].operation = operation_union;
}
}
else
{
tp.operations[1].is_collinear = true;
}
}
else if ( tp.operations[1].operation == operation_blocked )
{
// a spike on Q on the same line with P1
if ( inters.is_spike_q() )
{
if ( inters.sides().pk_wrt_q1() == 0 )
{
tp.operations[1].is_collinear = true;
}
else
{
tp.operations[1].operation = operation_union;
}
}
else
{
tp.operations[0].is_collinear = true;
}
}
else if ( tp.operations[0].operation == operation_continue
&& tp.operations[1].operation == operation_continue )
{
// P spike on the same line with Q2 (opposite)
if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
&& inters.is_spike_p() )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
}
}
else if ( tp.operations[0].operation == operation_none
&& tp.operations[1].operation == operation_none )
{
// spike not handled by touch<>
bool const is_p = inters.is_spike_p();
bool const is_q = inters.is_spike_q();
if ( is_p || is_q )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
if ( inters.sides().pk_wrt_q2() == 0 )
{
tp.operations[0].operation = operation_continue; // will be converted to i
if ( is_p )
{
tp.operations[0].is_collinear = true;
}
}
if ( inters.sides().qk_wrt_p2() == 0 )
{
tp.operations[1].operation = operation_continue; // will be converted to i
if ( is_q )
{
tp.operations[1].is_collinear = true;
}
}
}
}
// workarounds for touch<> not taking spikes into account ends here
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
@@ -190,8 +293,9 @@ struct get_turn_info_linear_linear
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// transform turn
turn_transformer_ec transformer(method_touch);
transformer(tp);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
@@ -231,6 +335,7 @@ struct get_turn_info_linear_linear
}
else
{
// NOTE: this is for spikes since those are set in the turn_transformer_ec
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = true;
@@ -257,8 +362,9 @@ struct get_turn_info_linear_linear
//spike_op = operation_continue;
}
replacer_of_method_and_operations_ec replacer(method_replace);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// transform turn
turn_transformer_ec transformer(method_replace);
transformer(tp);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
@@ -277,7 +383,7 @@ struct get_turn_info_linear_linear
else
{
// If this always 'm' ?
replacer_of_method_and_operations_ec replacer(method_touch_interior);
turn_transformer_ec transformer(method_touch_interior);
// conditionally handle spikes
if ( handle_spikes )
@@ -297,7 +403,7 @@ struct get_turn_info_linear_linear
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, inters.i_info(), inters.d_info(), inters.sides(),
replacer, !is_p_last, !is_q_last);
transformer, !is_p_last, !is_q_last);
}
}
}
@@ -441,13 +547,13 @@ struct get_turn_info_linear_linear
if ( Version == append_touches )
{
tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = ???
tp.operations[1].is_collinear = false;
tp.method = method_touch;
}
else
else // Version == append_collinear_opposite
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = false;
BOOST_ASSERT(inters.i_info().count > 1);
@@ -472,14 +578,14 @@ struct get_turn_info_linear_linear
{
if ( Version == append_touches )
{
//tp.operations[0].is_collinear = ???
tp.operations[0].is_collinear = false;
tp.operations[1].is_collinear = true;
tp.method = method_touch;
}
else
else // Version == append_collinear_opposite
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
tp.operations[0].is_collinear = false;
tp.operations[1].is_collinear = true;
BOOST_ASSERT(inters.i_info().count > 0);
@@ -543,17 +649,19 @@ struct get_turn_info_linear_linear
}
}
class replacer_of_method_and_operations_ec
class turn_transformer_ec
{
public:
explicit replacer_of_method_and_operations_ec(method_type method_t_or_m)
explicit turn_transformer_ec(method_type method_t_or_m)
: m_method(method_t_or_m)
{}
void operator()(method_type & method,
operation_type & op0,
operation_type & op1) const
template <typename Turn>
void operator()(Turn & turn) const
{
operation_type & op0 = turn.operations[0].operation;
operation_type & op1 = turn.operations[1].operation;
BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
if ( op0 == operation_blocked )
@@ -577,8 +685,13 @@ struct get_turn_info_linear_linear
if ( op0 == operation_intersection || op0 == operation_union
|| op1 == operation_intersection || op1 == operation_union )
{
method = m_method;
turn.method = m_method;
}
// TODO: is this correct?
// it's equivalent to comparing to operation_blocked at the beginning of the function
turn.operations[0].is_collinear = op0 != operation_intersection;
turn.operations[1].is_collinear = op1 != operation_intersection;
}
private:

View File

@@ -38,7 +38,7 @@ struct points_end
} // namespace core_dispatch
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -99,6 +99,24 @@ struct segments_intersection_ratios
{
return return_type();
}
template <typename Segment, typename Ratio>
static inline return_type one_degenerate(Segment const& ,
Ratio const& ratio, bool a_degenerate)
{
return_type result;
if (a_degenerate)
{
// IP lies on ratio w.r.t. segment b
result.assign(Ratio::zero(), ratio);
}
else
{
result.assign(ratio, Ratio::zero());
}
return result;
}
};

View File

@@ -31,106 +31,132 @@ 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")("tcc")("tuu")("mcu")("mic")("muu")("tiu")("mcu")("mic")("mcc")("miu")("mxu").vec);
expected("miu+")("iuu+")("tcc+")("tuu=")("mcu+")("mic=")("muu+")
("tiu+")("mcu+")("mic=")("mcc+")("miu=")("mxu+"));
test_geometry<ls, poly>("LINESTRING(5 0,5 5,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
"miu", "mxu");
"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");
"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")("mic")("mcc")("txu").vec);
expected("tcu+")("mic=")("mcc+")("txu="));
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("tcc")("miu")("mcu")("txc").vec);
expected("tcc+")("miu=")("mcu+")("txc="));
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")("mic")("mcu")("mic")("mxu").vec);
expected("tcu+")("mic=")("mcu+")("mic=")("mxu+"));
test_geometry<ls, poly>("LINESTRING(11 1,10 0,0 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))",
"tcc", "txu");
"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");
"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");
"tcc+", "tuu=");
// 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);
expected("tiu+")("tiu+"));
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);
expected("mcu+")("ecc=")("tiu+")("mxc="));
// 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);
expected("tuu+")("tiu+"));
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);
expected("mcu+")("tuc=")("tcu+")("mxc="));
// true hole
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"));
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"));
expected("mcu+")("mic=")("tcc+")("txu="));
// SPIKE - NON-ENDPOINT - NON-OPPOSITE
// spike - neq eq
test_geometry<ls, poly>("LINESTRING(2 2,4 4,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))",
expected("mcc")("txu")("tcu")("mxc"));
expected("mcc+")("txu=")("tcu=")("mxc="));
// spike - eq eq
test_geometry<ls, poly>("LINESTRING(0 0,4 4,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))",
expected("tcc")("txu")("tcu")("mxc"));
expected("tcc+")("txu=")("tcu=")("mxc="));
// spike - eq neq
test_geometry<ls, poly>("LINESTRING(0 0,3 3,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))",
expected("tcc")("mxu")("mcu")("mxc"));
expected("tcc+")("mxu=")("mcu=")("mxc="));
// spike - neq neq
test_geometry<ls, poly>("LINESTRING(1 1,3 3,2 2)", "POLYGON((0 0,4 4,6 3,6 0,0 0))",
expected("mcc")("mxu")("mcu")("mxc"));
expected("mcc+")("mxu=")("mcu=")("mxc="));
// spike - out neq
test_geometry<ls, poly>("LINESTRING(0 0,3 3,2 2)", "POLYGON((1 1,4 4,6 3,6 0,1 1))",
expected("mcc")("mxu")("mcu")("mxc"));
expected("mcc+")("mxu=")("mcu=")("mxc="));
// spike - out eq
test_geometry<ls, poly>("LINESTRING(0 0,4 4,2 2)", "POLYGON((1 1,4 4,6 3,6 0,1 1))",
expected("mcc")("txu")("tcu")("mxc"));
expected("mcc+")("txu=")("tcu=")("mxc="));
// spike - out out/eq
test_geometry<ls, poly>("LINESTRING(0 0,4 4,2 2)", "POLYGON((1 0,4 4,6 3,1 0))",
expected("tuu"));
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(0 0,4 4,2 2)", "POLYGON((0 1,4 4,6 3,6 0,-1 -1,0 1))",
expected("tiu"));
expected("tiu+"));
// spike - out out/neq
test_geometry<ls, poly>("LINESTRING(0 0,4 4,2 2)", "POLYGON((4 0,4 5,6 3,4 0))",
expected("muu"));
expected("muu+"));
test_geometry<ls, poly>("LINESTRING(0 0,4 4,2 2)", "POLYGON((0 4,5 4,6 3,6 0,-1 -1,0 4))",
expected("miu"));
expected("miu+"));
test_geometry<ls, poly>("LINESTRING(0 1,1 1,0 1)", "POLYGON((0 0,3 3,3 0,0 0))",
expected("muu"));
expected("muu+"));
test_geometry<ls, poly>("LINESTRING(0 1,3 3,0 1)", "POLYGON((0 0,3 3,3 0,0 0))",
expected("tuu"));
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(0 1,0 0,0 1)", "POLYGON((0 0,3 3,3 0,0 0))",
expected("tuu"));
expected("tuu+"));
// SPIKE - NON-ENDPOINT - OPPOSITE
// opposite - eq eq
test_geometry<ls, poly>("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-1 -1,0 0,4 4,6 3,-1 -1))",
expected("tcu")("txc")("tcc")("mxu"));
expected("tcu+")("txc=")("tcc=")("mxu="));
// opposite - neq eq
test_geometry<ls, poly>("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-1 -1,0 0,5 5,6 3,-1 -1))",
expected("mcu")("txc")("tcc")("mxu"));
expected("mcu+")("txc=")("tcc=")("mxu="));
// opposite - eq, neq
test_geometry<ls, poly>("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,4 4,6 3,-2 -2))",
expected("tcu")("mxc")("mcc")("mxu"));
expected("tcu+")("mxc=")("mcc=")("mxu="));
// opposite - neq neq
test_geometry<ls, poly>("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,3 3,6 3,-2 -2))",
expected("mcu")("mxc")("mcc")("mxu"));
expected("mcu+")("mxc=")("mcc=")("mxu="));
// opposite - neq neq
test_geometry<ls, poly>("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,3 3,5 5,6 3,-2 -2))",
expected("mcu")("mxc")("mcc")("mxu"));
expected("mcu+")("mxc=")("mcc=")("mxu="));
// spike vs internal
test_geometry<ls, poly>("LINESTRING(0 1,1 1,0 1)", // --
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(1 2,1 1,1 2)", // |
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(0 2,1 1,0 2)",
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(2 0,1 1,2 0)",
"POLYGON((1 0,1 1,2 1,2 0,1 0))",
expected("tiu+")("tiu+")("txu+")); // TODO: should spike point be duplicated?
test_geometry<ls, poly>("LINESTRING(0 0,1 1,0 0)", // /
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(2 2,1 1,2 2)", // /
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tuu+"));
test_geometry<ls, poly>("LINESTRING(2 1,1 1,2 1)",
"POLYGON((1 0,1 1,2 1,1 0))",
expected("tcu+")("txc=")("tcc=")("txu="));
}
int test_main(int, char* [])

View File

@@ -32,179 +32,189 @@ void test_all()
typedef bg::model::linestring<pt> ls;
typedef bg::model::multi_linestring<ls> mls;
test_geometry<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "tii", "txx");
test_geometry<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "tix", "txi");
// NOTE: currently for the first endpoint of the Linestring on collinear segment
// is_collinear flags are set to FALSE!
// E.g. in the first test tii++, NOT tii==
test_geometry<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "tii++", "txx==");
test_geometry<ls, ls>("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "tix+=", "txi=+");
test_geometry<ls, ls>("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "tuu");
test_geometry<ls, ls>("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "txi", "tiu");
test_geometry<ls, ls>("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "tii", "txx");
test_geometry<ls, ls>("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "txu");
test_geometry<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "tii", "txu");
test_geometry<ls, ls>("LINESTRING(2 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "txi", "tix");
test_geometry<ls, ls>("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "tuu++");
test_geometry<ls, ls>("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "txi=+", "tiu+=");
test_geometry<ls, ls>("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "tii++", "txx==");
test_geometry<ls, ls>("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "txu++");
test_geometry<ls, ls>("LINESTRING(0 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "tii++", "txu==");
test_geometry<ls, ls>("LINESTRING(2 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "txi=+", "tix+=");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,1 1)", "tuu");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,0 0)", "tix", "tui");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,2 0)", "tii", "txx");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 1,1 0)", "tux");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(0 0,1 0)", "tii", "tux");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(2 0,1 0)", "tix", "txi");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,1 1)", "tuu++");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,0 0)", "tix+=", "tui=+");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,2 0)", "tii++", "txx==");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 1,1 0)", "tux++");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(0 0,1 0)", "tii++", "tux==");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 0)", "LINESTRING(2 0,1 0)", "tix+=", "txi=+");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,3 0,3 1)", "mii", "ccc", "muu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,3 0,3 -1)", "mii", "ccc", "muu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,1 0,1 1)", "miu", "mui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,1 0,1 -1)", "miu", "mui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,4 0,4 1)", "tii", "ccc", "tuu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,4 0,4 -1)", "tii", "ccc", "tuu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,2 0,2 1)", "tiu", "tui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,2 0,2 -1)", "tiu", "tui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,3 0,3 1)", "mii++", "ccc==", "muu==");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,3 0,3 -1)", "mii++", "ccc==", "muu==");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,1 0,1 1)", "miu+=", "mui=+");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,1 0,1 -1)", "miu+=", "mui=+");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,4 0,4 1)", "tii++", "ccc==", "tuu==");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,4 0,4 -1)", "tii++", "ccc==", "tuu==");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,2 0,2 1)", "tiu+=", "tui=+");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,2 0,2 -1)", "tiu+=", "tui=+");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,2 0,3 0,3 1)", "mii", "ecc", "muu");
// same as above - TODO: reverse manually or automatically for all tests
/*test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,2 0,3 0,3 1)", "mii", "ecc", "muu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,2 0,3 0,3 -1)", "mii", "ecc", "muu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,2 0,1 0,1 1)", "miu", "ecc", "mui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,2 0,1 0,1 -1)", "miu", "ecc", "mui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,3 0,4 0,4 1)", "tii", "ecc", "tuu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,3 0,4 0,4 -1)", "tii", "ecc", "tuu");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,3 0,2 0,2 1)", "tiu", "ecc", "tui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "tiu", "ecc", "tui");
test_geometry<ls, ls>("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "tiu", "ecc", "tui");*/
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "tii", "ecc", "tux");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "tix", "ecc", "tui");
test_geometry<ls, ls>("LINESTRING(1 0,2 1,3 5)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "txu", "ecc", "tii");
test_geometry<ls, ls>("LINESTRING(3 5,2 1,1 0)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "tiu", "ecc", "txi");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "tii++", "ecc==", "tux==");
test_geometry<ls, ls>("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "tix+=", "ecc==", "tui=+");
test_geometry<ls, ls>("LINESTRING(1 0,2 1,3 5)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "txu==", "ecc==", "tii++");
test_geometry<ls, ls>("LINESTRING(3 5,2 1,1 0)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "tiu+=", "ecc==", "txi=+");
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(-1 -1,1 0,10 0,20 -1)", "mii", "txu");
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(20 -1,10 0,1 0,-1 -1)", "miu", "txi");
test_geometry<ls, ls>("LINESTRING(-1 -1,1 0,10 0,20 -1)", "LINESTRING(0 0,10 0)", "mii", "tux");
test_geometry<ls, ls>("LINESTRING(20 -1,10 0,1 0,-1 -1)", "LINESTRING(0 0,10 0)", "mui", "tix");
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(-1 -1,1 0,10 0,20 -1)", "mii++", "txu==");
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(20 -1,10 0,1 0,-1 -1)", "miu+=", "txi=+");
test_geometry<ls, ls>("LINESTRING(-1 -1,1 0,10 0,20 -1)", "LINESTRING(0 0,10 0)", "mii++", "tux==");
test_geometry<ls, ls>("LINESTRING(20 -1,10 0,1 0,-1 -1)", "LINESTRING(0 0,10 0)", "mui=+", "tix+=");
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"));
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"));
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"));
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"));
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");
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==");
test_geometry<ls, ls>("LINESTRING(30 1,20 1,10 0,0 0)", "LINESTRING(1 1,2 0,3 1,20 1,25 1)", "mix", "tui", "muu");
test_geometry<ls, ls>("LINESTRING(1 1,2 0,3 1,20 1,25 1)", "LINESTRING(30 1,20 1,10 0,0 0)", "mxi", "tiu", "muu");
test_geometry<ls, ls>("LINESTRING(30 1,20 1,10 0,0 0)", "LINESTRING(1 1,2 0,3 1,20 1,25 1)", "mix+=", "tui=+", "muu++");
test_geometry<ls, ls>("LINESTRING(1 1,2 0,3 1,20 1,25 1)", "LINESTRING(30 1,20 1,10 0,0 0)", "mxi=+", "tiu+=", "muu++");
test_geometry<ls, ls>("LINESTRING(0 0,30 0)", "LINESTRING(4 0,4 1,20 1,5 0,1 0)", "muu", "mui", "mix");
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(0 0,30 0)", "LINESTRING(4 0,4 1,20 1,5 0,1 0)", "muu++", "mui=+", "mix+=");
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"));
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"));
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"));
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"));
expected("mii++")("muu++")("muu=="));
// non-collinear
test_geometry<ls, ls>("LINESTRING(0 1,0 0)", "LINESTRING(0 0,1 0,2 0)", "txu++");
test_geometry<ls, ls>("LINESTRING(0 1,0 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "tuu++");
test_geometry<ls, ls>("LINESTRING(0 1,1 0,2 1)", "LINESTRING(0 0,1 0,2 0)", "tuu++");
// SPIKE - NON-ENDPOINT - NON-OPPOSITE
// spike - neq eq
test_geometry<ls, ls>("LINESTRING(2 2,4 4,1 1)", "LINESTRING(0 0,4 4,6 3)",
expected("mii")("txu")("tiu")("mxi"));
expected("mii++")("txu==")("tiu==")("mxi=+"));
// spike - eq eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,1 1)", "LINESTRING(0 0,4 4,6 3)",
expected("tii")("txu")("tiu")("mxi"));
expected("tii++")("txu==")("tiu==")("mxi=+"));
// spike - eq neq
test_geometry<ls, ls>("LINESTRING(0 0,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)",
expected("tii")("mxu")("miu")("mxi"));
expected("tii++")("mxu==")("miu==")("mxi=+"));
// spike - neq neq
test_geometry<ls, ls>("LINESTRING(1 1,3 3,2 2)", "LINESTRING(0 0,4 4,6 3)",
expected("mii")("mxu")("miu")("mxi"));
expected("mii++")("mxu==")("miu==")("mxi=+"));
// spike - out neq
test_geometry<ls, ls>("LINESTRING(0 0,3 3,2 2)", "LINESTRING(1 1,4 4,6 3)",
expected("mii")("mxu")("miu")("mxi"));
expected("mii++")("mxu==")("miu==")("mxi=+"));
// spike - out eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 1,4 4,6 3)",
expected("mii")("txu")("tiu")("mxi"));
expected("mii++")("txu==")("tiu==")("mxi=+"));
// spike - out out/eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 0,4 4,6 3)",
expected("tuu"));
expected("tuu++"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 1,4 4,6 3)",
expected("tuu"));
expected("tuu++"));
// spike - out out/neq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 0,4 5,6 3)",
expected("muu"));
expected("muu++"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 4,5 4,6 3)",
expected("muu"));
expected("muu++"));
// SPIKE - NON-ENDPOINT - OPPOSITE
// opposite - eq eq
test_geometry<ls, ls>("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-1 -1,0 0,4 4,6 3)",
expected("tiu")("txi")("tii")("mxu"));
expected("tiu+=")("txi=+")("tii=+")("mxu=="));
test_geometry<ls, ls>("LINESTRING(-1 -1,0 0,4 4,6 3)", "LINESTRING(6 6,4 4,0 0,2 2)",
expected("tui")("tix")("tii")("mux"));
expected("tui=+")("tix+=")("tii+=")("mux=="));
// opposite - neq eq
test_geometry<ls, ls>("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-1 -1,0 0,5 5,6 3)",
expected("miu")("txi")("tii")("mxu"));
expected("miu+=")("txi=+")("tii=+")("mxu=="));
// opposite - eq neq
test_geometry<ls, ls>("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,4 4,6 3)",
expected("tiu")("mxi")("mii")("mxu"));
expected("tiu+=")("mxi=+")("mii=+")("mxu=="));
// opposite - neq neq
test_geometry<ls, ls>("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,3 3,6 3)",
expected("miu")("mxi")("mii")("mxu"));
expected("miu+=")("mxi=+")("mii=+")("mxu=="));
// opposite - neq neq
test_geometry<ls, ls>("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,3 3,5 5,6 3)",
expected("miu")("mxi")("mii")("mxu"));
expected("miu+=")("mxi=+")("mii=+")("mxu=="));
// opposite - neq eq
test_geometry<ls, ls>("LINESTRING(6 3,3 3,0 0)", "LINESTRING(0 0,2 2,3 3,1 1)",
expected("txi")("tix")("tii")("mux"));
expected("txi=+")("tix+=")("tii+=")("mux=="));
// SPIKE - ENDPOINT - NON-OPPOSITE
// spike - neq eq
test_geometry<ls, ls>("LINESTRING(2 2,4 4,1 1)", "LINESTRING(0 0,4 4)",
expected("mii")("txx")("tix")("mxi"));
expected("mii++")("txx==")("tix==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(2 2,4 4,1 1)", "LINESTRING(4 4,0 0)",
expected("miu")("txi")("tii")("mxu"));
expected("miu+=")("txi=+")("tii=+")("mxu=="));
// spike - eq eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,1 1)", "LINESTRING(0 0,4 4)",
expected("tii")("txx")("tix")("mxi"));
expected("tii++")("txx==")("tix==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,1 1)", "LINESTRING(4 4,0 0)",
expected("tix")("txi")("tii")("mxu"));
expected("tix+=")("txi=+")("tii=+")("mxu=="));
// spike - eq neq
test_geometry<ls, ls>("LINESTRING(0 0,3 3,1 1)", "LINESTRING(0 0,4 4)",
expected("tii")("mxu")("miu")("mxi"));
expected("tii++")("mxu==")("miu==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(0 0,3 3,1 1)", "LINESTRING(4 4,0 0)",
expected("tix")("mxi")("mii")("mxu"));
expected("tix+=")("mxi=+")("mii=+")("mxu=="));
// spike - neq neq
test_geometry<ls, ls>("LINESTRING(1 1,3 3,2 2)", "LINESTRING(0 0,4 4)",
expected("mii")("mxu")("miu")("mxi"));
expected("mii++")("mxu==")("miu==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(1 1,3 3,2 2)", "LINESTRING(4 4,0 0)",
expected("miu")("mxi")("mii")("mxu"));
expected("miu+=")("mxi=+")("mii=+")("mxu=="));
// spike - out neq
test_geometry<ls, ls>("LINESTRING(0 0,3 3,2 2)", "LINESTRING(1 1,4 4)",
expected("mii")("mxu")("miu")("mxi"));
expected("mii++")("mxu==")("miu==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(0 0,3 3,2 2)", "LINESTRING(4 4,1 1)",
expected("mix")("mxi")("mii")("mxu"));
expected("mix+=")("mxi=+")("mii=+")("mxu=="));
// spike - out eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 1,4 4)",
expected("mii")("txx")("tix")("mxi"));
expected("mii++")("txx==")("tix==")("mxi=+"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 4,1 1)",
expected("mix")("txi")("tii")("mxu"));
expected("mix+=")("txi=+")("tii=+")("mxu=="));
// spike - out out/eq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 0,4 4)",
expected("tux"));
expected("tux++"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 1,4 4)",
expected("tux"));
expected("tux++"));
// spike - out out/neq
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 0,4 5)",
expected("muu"));
expected("muu++"));
test_geometry<ls, ls>("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 4,5 4)",
expected("muu"));
expected("muu++"));
// TODO:
//test_geometry<ls, ls>("LINESTRING(0 0,2 0,1 0)", "LINESTRING(0 1,0 0,2 0)", "1FF00F102");
@@ -233,16 +243,16 @@ void test_all()
// duplicated
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0,30 0))",
"MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(2 0,2 0),(3 0,3 0,3 0))",
expected("mii")("ccc")("ccc")("txx"));
expected("mii++")("ccc==")("ccc==")("txx=="));
// spike
test_geometry<ls, ls>("LINESTRING(2 2,5 -1,15 2,18 0,20 0)",
"LINESTRING(30 0,19 0,18 0,0 0)",
expected("iuu")("iuu")("tiu")("mxi"));
expected("iuu++")("iuu++")("tiu+=")("mxi=+"));
// spike
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0,5 0))",
"MULTILINESTRING((1 0,8 0,4 0))",
expected("mii")("mix")("mux")("mui")("mix")("mii")("mxu")("mxi"));
expected("mii++")("mix+=")("mux==")("mui==")("mix+=")("mii+=")("mxu==")("mxi=+"));
/*test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0,5 0))",
"MULTILINESTRING((1 0,8 0,4 0),(2 0,9 0,5 0))",
@@ -251,20 +261,120 @@ void test_all()
// spike vs endpoint
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0))",
"MULTILINESTRING((-1 0,0 0,-2 0),(11 0,10 0,12 0))",
expected("tuu")("txu"));
expected("tuu++")("txu++"));
// internal turning R vs spike
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,2 1))",
"MULTILINESTRING((0 1,1 1,0 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,2 1))",
"MULTILINESTRING((1 2,1 1,1 2))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 0,0 0))",
"MULTILINESTRING((2 0,1 0,2 0))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,2 1))",
"MULTILINESTRING((0 2,1 1,0 2))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,2 1))",
"MULTILINESTRING((2 0,1 1,2 0))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,2 1))",
"MULTILINESTRING((2 1,1 1,2 1))",
expected("txi=+")("tix+=")("tii+=")("txx=="));
// internal turning L vs spike
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,0 1))",
"MULTILINESTRING((2 1,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,0 1))",
"MULTILINESTRING((1 2,1 1,1 2))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,0 1))",
"MULTILINESTRING((2 2,1 1,2 2))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,0 1))",
"MULTILINESTRING((0 0,1 1,0 0))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 0,1 1,0 1))",
"MULTILINESTRING((0 1,1 1,0 1))",
expected("txi=+")("tix+=")("tii+=")("txx=="));
// spike vs internal turning R
test_geometry<mls, mls>("MULTILINESTRING((0 1,1 1,0 1))",
"MULTILINESTRING((1 0,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 2,1 1,1 2))",
"MULTILINESTRING((1 0,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((2 0,1 0,2 0))",
"MULTILINESTRING((0 0,1 0,0 0))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 2,1 1,0 2))",
"MULTILINESTRING((1 0,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((2 0,1 1,2 0))",
"MULTILINESTRING((1 0,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((2 1,1 1,2 1))",
"MULTILINESTRING((1 0,1 1,2 1))",
expected("tix+=")("txi=+")("tii=+")("txx=="));
// spike vs internal turning L
test_geometry<mls, mls>("MULTILINESTRING((2 1,1 1,2 1))",
"MULTILINESTRING((1 0,1 1,0 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((1 2,1 1,1 2))",
"MULTILINESTRING((1 0,1 1,0 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((2 2,1 1,2 2))",
"MULTILINESTRING((1 0,1 1,0 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((1 0,1 1,0 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 1,1 1,0 1))",
"MULTILINESTRING((1 0,1 1,0 1))",
expected("tix+=")("txi=+")("tii=+")("txx=="));
// spike vs internal collinear
test_geometry<mls, mls>("MULTILINESTRING((0 1,1 1,0 1))",
"MULTILINESTRING((2 1,1 1,0 1))",
expected("tix+=")("txi=+")("tii=+")("txx=="));
// internal collinear vs spike
test_geometry<mls, mls>("MULTILINESTRING((2 1,1 1,0 1))",
"MULTILINESTRING((0 1,1 1,0 1))",
expected("txi=+")("tix+=")("tii+=")("txx=="));
// spike vs spike
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((2 2,1 1,2 2))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((2 0,1 1,2 0))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((2 1,1 1,2 1))",
expected("tuu++"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((0 1,1 1,0 1))",
expected("tuu++"));
// collinear spikes
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((0 0,1 1,0 0))",
expected("tii++")("tix+=")("txi=+")("txx==")
("ecc=="));
test_geometry<mls, mls>("MULTILINESTRING((0 0,1 1,0 0))",
"MULTILINESTRING((1 1,0 0,1 1))",
expected("tix+=")("tii+=")("txx==")("txi==")
("txi=+")("tii=+")("txx==")("tix=="));
// non-spike similar
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0))",
"MULTILINESTRING((-1 0,0 0,2 0))",
expected("tii")("mux"));
expected("tii++")("mux=="));
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0))",
"MULTILINESTRING((-1 -1,0 0,2 0))",
expected("tii")("mux"));
expected("tii++")("mux=="));
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0))",
"MULTILINESTRING((2 0,0 0,-1 0))",
expected("tiu")("mui"));
expected("tiu+=")("mui=+"));
test_geometry<mls, mls>("MULTILINESTRING((0 0,10 0))",
"MULTILINESTRING((2 0,0 0,-1 -1))",
expected("tiu")("mui"));
expected("tiu+=")("mui=+"));
}
int test_main(int, char* [])

View File

@@ -33,6 +33,36 @@
#include <boost/geometry/io/wkt/read.hpp>
#include <boost/geometry/io/wkt/write.hpp>
template <int Version = 0>
struct expected_pusher
{
static const int version = Version;
void push_back(std::string const& ex) { vec.push_back(ex); }
expected_pusher & operator()(std::string const& ex)
{
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;
};
expected_pusher<1> expected(std::string const& ex)
{
expected_pusher<1> res;
return res(ex);
}
template <int Version>
struct equal_turn
{
equal_turn(std::string const& s) : turn_ptr(&s) {}
@@ -49,13 +79,46 @@ struct equal_turn
const std::string * turn_ptr;
};
template <typename Geometry1, typename Geometry2, typename Range>
template <>
struct equal_turn<1>
{
equal_turn(std::string const& s) : turn_ptr(&s) {}
template <typename T>
bool operator()(T const& t) const
{
unsigned count = turn_ptr->size();
BOOST_ASSERT(turn_ptr && count >= 1);
return bg::method_char(t.method) == (*turn_ptr)[0]
&& ( count > 1
? bg::operation_char(t.operations[0].operation) == (*turn_ptr)[1]
: true )
&& ( count > 2
? bg::operation_char(t.operations[1].operation) == (*turn_ptr)[2]
: true )
&& ( count > 3
? is_colinear_char(t.operations[0].is_collinear) == (*turn_ptr)[3]
: true )
&& ( count > 4
? is_colinear_char(t.operations[1].is_collinear) == (*turn_ptr)[4]
: true );
}
static inline char is_colinear_char(bool is_collinear)
{
return is_collinear ? '=' : '+';
}
const std::string * turn_ptr;
};
template <typename Geometry1, typename Geometry2, typename Expected>
void check_geometry_range(
Geometry1 const& g1,
Geometry2 const& g2,
std::string const& wkt1,
std::string const& wkt2,
Range const& expected)
Expected const& expected)
{
typedef bg::detail::no_rescale_policy robust_policy_type;
typedef typename bg::point_type<Geometry2>::type point_type;
@@ -95,11 +158,11 @@ void check_geometry_range(
"get_turns: " << wkt1 << " and " << wkt2
<< " -> Expected turns #: " << boost::size(expected) << " detected turns #: " << turns.size());
for ( typename boost::range_iterator<Range const>::type sit = boost::begin(expected) ;
for ( typename boost::range_iterator<Expected 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(*sit));
it = std::find_if(turns.begin(), turns.end(), equal_turn<Expected::version>(*sit));
if ( it != turns.end() )
turns.erase(it);
@@ -112,9 +175,9 @@ void check_geometry_range(
}
}
template <typename Geometry1, typename Geometry2, typename Range>
template <typename Geometry1, typename Geometry2, typename Expected>
void test_geometry_range(std::string const& wkt1, std::string const& wkt2,
Range const& expected)
Expected const& expected)
{
Geometry1 geometry1;
Geometry2 geometry2;
@@ -127,67 +190,26 @@ template <typename G1, typename G2>
void test_geometry(std::string const& wkt1, std::string const& wkt2,
std::string const& ex0)
{
std::vector<std::string> expected;
expected.push_back(ex0);
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0));
}
template <typename G1, typename G2>
void test_geometry(std::string const& wkt1, std::string const& wkt2,
std::string const& ex0, std::string const& ex1)
{
std::vector<std::string> expected;
expected.push_back(ex0);
expected.push_back(ex1);
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0)(ex1));
}
template <typename G1, typename G2>
void test_geometry(std::string const& wkt1, std::string const& wkt2,
std::string const& ex0, std::string const& ex1, std::string const& ex2)
{
std::vector<std::string> expected;
expected.push_back(ex0);
expected.push_back(ex1);
expected.push_back(ex2);
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0)(ex1)(ex2));
}
struct expected_pusher
{
expected_pusher & operator()(std::string const& ex)
{
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;
};
expected_pusher expected(std::string const& ex)
{
expected_pusher res;
return res(ex);
}
template <typename G1, typename G2>
template <typename G1, typename G2, int Version>
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)
expected_pusher<Version> const& expected)
{
test_geometry_range<G1, G2>(wkt1, wkt2, expected);
}

View File

@@ -172,12 +172,11 @@ void test_linestring_linestring()
test_geometry<ls, ls>("LINESTRING(1 0,1 6)", "LINESTRING(0 0,5 0,5 5,0 5)", "0F10F0102");
// point-size Linestring
// FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS
/*test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102");
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102");
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(1 0,5 0)", "F0FFFF102");
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(0 0,1 0)", "F0FFFF102");
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(1 0,1 0)", "0FFFFFFF2");
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(0 0,0 0)", "FF0FFF0F2");*/
test_geometry<ls, ls>("LINESTRING(1 0,1 0)", "LINESTRING(0 0,0 0)", "FF0FFF0F2");
//to_svg<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "test_relate_00.svg");
@@ -238,32 +237,31 @@ 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");
// point-like
// FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((0 0, 1 0),(2 0, 2 0))", // |------| *
// "101F00FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((0 0, 1 0),(1 0, 1 0))", // |------*
// "101F00FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((5 0, 1 0),(1 0, 1 0))", // *-------|
// "101F00FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((0 0, 1 0),(5 0, 5 0))", // |------| *
// "10100FFF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((0 0, 1 0),(0 0, 0 0))", // *------|
// "101000FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((4 0, 5 0),(5 0, 5 0))", // |------*
// "101000FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((1 0, 2 0),(0 0, 0 0))", // * |------|
// "1010F0FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((0 0, 1 0),(2 0, 2 0))", // |------| *
"101F00FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((0 0, 1 0),(1 0, 1 0))", // |------*
"101F00FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((5 0, 1 0),(1 0, 1 0))", // *-------|
"101F00FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((0 0, 1 0),(5 0, 5 0))", // |------| *
"10100FFF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((0 0, 1 0),(0 0, 0 0))", // *------|
"101000FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((4 0, 5 0),(5 0, 5 0))", // |------*
"101000FF2");
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((1 0, 2 0),(0 0, 0 0))", // * |------|
"1010F0FF2");
//test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
// "MULTILINESTRING((2 0, 2 0),(2 0, 2 2))", // *
// "001FF0102"); // |
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
"MULTILINESTRING((2 0, 2 0),(2 0, 2 2))", // *
"001FF0102"); // |
// for consistency
test_geometry<ls, mls>("LINESTRING(0 0, 5 0)", // |--------------|
@@ -318,8 +316,7 @@ void test_multi_linestring_multi_linestring()
"1F1F0F1F2");
// point-like
// FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS
/*test_geometry<mls, mls>("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))",
test_geometry<mls, mls>("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))",
"MULTILINESTRING((0 0, 0 0))",
"0F0FFFFF2");
test_geometry<mls, mls>("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))",
@@ -327,7 +324,7 @@ void test_multi_linestring_multi_linestring()
"0FFFFFFF2");
test_geometry<mls, mls>("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))",
"MULTILINESTRING((2 2, 2 2),(3 3, 3 3))",
"FF0FFF0F2");*/
"FF0FFF0F2");
}
template <typename P>