mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-12 00:02:09 +00:00
re-arranged code so that linestrings are not transformed to multilinestrings;
added implementations for all four pairs of LS/MLS combinations; added unit tests that were missing for new combinations;
This commit is contained in:
@@ -30,6 +30,231 @@ namespace detail { namespace difference
|
||||
{
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
|
||||
|
||||
template <typename LineStringOut, typename Geometry, typename GeometryTag>
|
||||
struct difference_no_intersections;
|
||||
|
||||
|
||||
template <typename LineStringOut, typename LineString>
|
||||
struct difference_no_intersections<LineStringOut, LineString, linestring_tag>
|
||||
{
|
||||
template <typename OutputIterator>
|
||||
static inline OutputIterator apply(LineString const& linestring,
|
||||
OutputIterator oit)
|
||||
{
|
||||
LineStringOut ls_out;
|
||||
geometry::convert(linestring, ls_out);
|
||||
*oit++ = ls_out;
|
||||
return oit;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename LineStringOut, typename MultiLineString>
|
||||
struct difference_no_intersections
|
||||
<
|
||||
LineStringOut, MultiLineString, multi_linestring_tag
|
||||
>
|
||||
{
|
||||
template <typename OutputIterator>
|
||||
static inline OutputIterator apply(MultiLineString const& multilinestring,
|
||||
OutputIterator oit)
|
||||
{
|
||||
BOOST_AUTO_TPL(it, boost::begin(multilinestring));
|
||||
for (; it != boost::end(multilinestring); ++it)
|
||||
{
|
||||
LineStringOut ls_out;
|
||||
geometry::convert(*it, ls_out);
|
||||
*oit++ = ls_out;
|
||||
}
|
||||
return oit;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename LinestringOut>
|
||||
struct linear_linear_linestring
|
||||
{
|
||||
typedef typename point_type<LinestringOut>::type PointOut;
|
||||
typedef overlay::traversal_turn_info<PointOut> turn_info;
|
||||
typedef std::vector<turn_info> Turns;
|
||||
typedef typename Turns::iterator TurnIt;
|
||||
typedef detail::get_turns::no_interrupt_policy InterruptPolicy;
|
||||
|
||||
|
||||
struct AssignPolicy
|
||||
{
|
||||
static bool const include_no_turn = false;
|
||||
static bool const include_degenerate = false;
|
||||
static bool const include_opposite = false;
|
||||
|
||||
template
|
||||
<
|
||||
typename Info,
|
||||
typename Point1,
|
||||
typename Point2,
|
||||
typename IntersectionInfo,
|
||||
typename DirInfo
|
||||
>
|
||||
static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
|
||||
IntersectionInfo const& ii, DirInfo const& di)
|
||||
{
|
||||
overlay::calculate_distance_policy::apply(info, p1, p2, ii, di);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct IsContinueTurn
|
||||
{
|
||||
template <typename Turn>
|
||||
bool operator()(Turn const& turn) const
|
||||
{
|
||||
if ( turn.method != overlay::method_collinear &&
|
||||
turn.method != overlay::method_equal )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
overlay::operation_type op[2];
|
||||
op[0] = turn.operations[0].operation;
|
||||
op[1] = turn.operations[1].operation;
|
||||
|
||||
return
|
||||
(op[0] == overlay::operation_continue ||
|
||||
op[0] == overlay::operation_opposite) &&
|
||||
(op[1] == overlay::operation_continue ||
|
||||
op[1] == overlay::operation_opposite);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Turns>
|
||||
static inline void filter_turns(Turns& turns)
|
||||
{
|
||||
typedef typename Turns::iterator TurnIt;
|
||||
|
||||
TurnIt new_end = std::remove_if(turns.begin(), turns.end(),
|
||||
IsContinueTurn());
|
||||
turns.resize( std::distance(turns.begin(), new_end) );
|
||||
}
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Linear1, typename Linear2,
|
||||
typename OutputIterator, typename Strategy
|
||||
>
|
||||
static inline OutputIterator apply(Linear1 const& linear1,
|
||||
Linear2 const& linear2,
|
||||
OutputIterator oit,
|
||||
Strategy const& )
|
||||
{
|
||||
typedef geometry::model::multi_linestring
|
||||
<
|
||||
LinestringOut
|
||||
> MultiLinestringOut;
|
||||
|
||||
// MultiLinestringOut mls1, mls2;
|
||||
// geometry::convert(multilinestring1, mls1);
|
||||
// geometry::convert(multilinestring2, mls2);
|
||||
|
||||
// assert( boost::size(mls1) > 0 );
|
||||
// assert( boost::size(mls2) > 0 );
|
||||
|
||||
|
||||
// canonical<LinestringOut>::apply(ls1);
|
||||
// canonical<LinestringOut>::apply(ls2);
|
||||
|
||||
// typedef typename point_type<LinestringOut>::type PointOut;
|
||||
|
||||
#if 0
|
||||
typedef //overlay::assign_null_policy
|
||||
overlay::calculate_distance_policy AssignPolicy;
|
||||
#endif
|
||||
// typedef //overlay::assign_null_policy
|
||||
// detail::union_::assign_union_policy AssignPolicy;
|
||||
|
||||
// typedef detail::disjoint::disjoint_interrupt_policy InterruptPolicy;
|
||||
|
||||
Turns turns, reverse_turns;
|
||||
|
||||
geometry::detail::relate::turns::get_turns
|
||||
<
|
||||
Linear1,
|
||||
Linear2,
|
||||
detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Linear1,
|
||||
Linear2,
|
||||
AssignPolicy
|
||||
>
|
||||
>::apply(turns, linear1, linear2);
|
||||
|
||||
Linear2 linear2_reverse = linear2;
|
||||
geometry::reverse(linear2_reverse);
|
||||
geometry::detail::relate::turns::get_turns
|
||||
<
|
||||
Linear1,
|
||||
Linear2,
|
||||
detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Linear1,
|
||||
Linear2,
|
||||
AssignPolicy
|
||||
>
|
||||
>::apply(reverse_turns, linear1, linear2_reverse);
|
||||
|
||||
if ( turns.empty() )
|
||||
{
|
||||
// the two linestrings are disjoint; we return the first as is;
|
||||
// canonical<MultiLinestringOut>::apply(mls1);
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
std::cout << "NO INTERSECTIONS" << std::endl;
|
||||
#endif
|
||||
// MK:: need to think about this
|
||||
// std::copy(linear1.begin(), linear1.end(), oit);
|
||||
oit = difference_no_intersections
|
||||
<
|
||||
LinestringOut, Linear1, typename tag<Linear1>::type
|
||||
>::apply(linear1, oit);
|
||||
return oit;
|
||||
}
|
||||
|
||||
// remove turns that have no added value
|
||||
#if 1
|
||||
filter_turns(turns);
|
||||
filter_turns(reverse_turns);
|
||||
#endif
|
||||
|
||||
// sort by seg_id, distance, and operation
|
||||
typedef detail::turns::less_seg_dist_other_op<> less;
|
||||
std::sort(boost::begin(turns), boost::end(turns), less());
|
||||
|
||||
typedef
|
||||
detail::turns::less_seg_dist_other_op<std::greater<int> > rev_less;
|
||||
std::sort(boost::begin(reverse_turns), boost::end(reverse_turns),
|
||||
rev_less());
|
||||
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::turns::print_turns(linear1, linear2, turns);
|
||||
std::cout << std::endl << std::endl;
|
||||
detail::turns::print_turns(linear1, linear2_reverse, reverse_turns);
|
||||
#endif
|
||||
|
||||
return detail::turns::following::follow
|
||||
<
|
||||
LinestringOut,
|
||||
Linear1,
|
||||
Linear2,
|
||||
overlay_difference
|
||||
>::apply(linear1, linear2, turns, reverse_turns, oit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
//===========================================================================
|
||||
|
||||
@@ -527,7 +527,7 @@ struct intersection_insert
|
||||
Reverse1, Reverse2, ReverseOut,
|
||||
linestring_tag, linestring_tag, linestring_tag,
|
||||
false, false, false
|
||||
> : detail::difference::linestring_linestring_linestring<LineStringOut>
|
||||
> : detail::difference::linear_linear_linestring<LineStringOut>
|
||||
{};
|
||||
|
||||
|
||||
@@ -545,7 +545,25 @@ struct intersection_insert
|
||||
Reverse1, Reverse2, ReverseOut,
|
||||
linestring_tag, multi_linestring_tag, linestring_tag,
|
||||
false, false, false
|
||||
> : detail::difference::linestring_multilinestring_linestring<LineStringOut>
|
||||
> : detail::difference::linear_linear_linestring<LineStringOut>
|
||||
{};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename MultiLineString, typename LineString,
|
||||
typename LineStringOut,
|
||||
bool Reverse1, bool Reverse2, bool ReverseOut
|
||||
>
|
||||
struct intersection_insert
|
||||
<
|
||||
MultiLineString, LineString,
|
||||
LineStringOut,
|
||||
overlay_difference,
|
||||
Reverse1, Reverse2, ReverseOut,
|
||||
multi_linestring_tag, linestring_tag, linestring_tag,
|
||||
false, false, false
|
||||
> : detail::difference::linear_linear_linestring<LineStringOut>
|
||||
{};
|
||||
|
||||
|
||||
@@ -563,7 +581,7 @@ struct intersection_insert
|
||||
Reverse1, Reverse2, ReverseOut,
|
||||
multi_linestring_tag, multi_linestring_tag, linestring_tag,
|
||||
false, false, false
|
||||
> : detail::difference::multilinestring_multilinestring_linestring<LineStringOut>
|
||||
> : detail::difference::linear_linear_linestring<LineStringOut>
|
||||
{};
|
||||
|
||||
|
||||
|
||||
@@ -117,18 +117,184 @@ static inline bool is_leaving(Turn const& turn, Operation const& op,
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename MultiLineString1,
|
||||
typename MultiLineString2,
|
||||
typename LineString1,
|
||||
typename LineString2,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
class follow
|
||||
class follow_linestring_linestring_linestring
|
||||
{
|
||||
protected:
|
||||
typedef typename point_type<LineStringOut>::type PointOut;
|
||||
typedef overlay::traversal_turn_info<PointOut> turn_info;
|
||||
|
||||
typedef typename boost::range_value<MultiLineString1>::type LineString1;
|
||||
typedef typename boost::range_value<MultiLineString2>::type LineString2;
|
||||
typedef typename boost::range_iterator
|
||||
<
|
||||
typename turn_info::container_type
|
||||
>::type turn_operation_iterator_type;
|
||||
|
||||
typedef detail::overlay::following::action_selector<OverlayType> action;
|
||||
|
||||
template
|
||||
<
|
||||
typename TurnIt,
|
||||
typename TurnOpIt,
|
||||
typename SegmentIdentifier,
|
||||
typename OutputIterator
|
||||
>
|
||||
static inline OutputIterator
|
||||
process_turn(TurnIt it, TurnIt it_r,
|
||||
TurnOpIt iit, TurnOpIt iit_r,
|
||||
bool& first, bool& entered,
|
||||
std::size_t& enter_count,
|
||||
LineString1 const& ls1, LineString2 const& ls2,
|
||||
LineStringOut& current_piece,
|
||||
SegmentIdentifier& current_segment_id,
|
||||
OutputIterator oit)
|
||||
{
|
||||
if ( is_entering(*it, *iit) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Entering");
|
||||
#endif
|
||||
|
||||
entered = true;
|
||||
if ( enter_count == 0 )
|
||||
{
|
||||
action::enter(current_piece, ls1, current_segment_id,
|
||||
iit->seg_id.segment_index,
|
||||
it->point, *iit, oit);
|
||||
}
|
||||
++enter_count;
|
||||
}
|
||||
else if ( is_staying_inside(*it, *iit, entered, first, ls1, ls2) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Staying inside");
|
||||
#endif
|
||||
|
||||
entered = true;
|
||||
}
|
||||
else if ( is_leaving(*it, *iit, *iit_r, entered, first, ls1, ls2) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Leaving");
|
||||
#endif
|
||||
|
||||
--enter_count;
|
||||
if ( enter_count == 0 )
|
||||
{
|
||||
entered = false;
|
||||
action::leave(current_piece, ls1, current_segment_id,
|
||||
iit->seg_id.segment_index,
|
||||
it->point, *iit, oit);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
return oit;
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename SegmentIdentifier,
|
||||
typename OutputIterator
|
||||
>
|
||||
static inline OutputIterator
|
||||
process_end(bool entered,
|
||||
LineString1 const& linestring1,
|
||||
SegmentIdentifier const& current_segment_id,
|
||||
LineStringOut& current_piece,
|
||||
OutputIterator oit)
|
||||
{
|
||||
if ( action::is_entered(entered) )
|
||||
{
|
||||
geometry::copy_segments<false>(linestring1, current_segment_id,
|
||||
boost::size(linestring1) - 1,
|
||||
current_piece);
|
||||
}
|
||||
|
||||
// Output the last one, if applicable
|
||||
if (::boost::size(current_piece) > 1)
|
||||
{
|
||||
*oit++ = current_piece;
|
||||
}
|
||||
|
||||
return oit;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename Turns, typename OutputIterator>
|
||||
static inline OutputIterator apply(LineString1 const& linestring1,
|
||||
LineString2 const& linestring2,
|
||||
Turns& turns,
|
||||
Turns& reverse_turns,
|
||||
OutputIterator oit)
|
||||
{
|
||||
BOOST_CHECK( boost::size(turns) == boost::size(reverse_turns) );
|
||||
|
||||
typedef typename Turns::iterator TurnIt;
|
||||
|
||||
// Iterate through all intersection points (they are
|
||||
// ordered along the each line)
|
||||
|
||||
LineStringOut current_piece;
|
||||
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
|
||||
|
||||
bool entered = false;
|
||||
bool first = true;
|
||||
// bool first_turn = true;
|
||||
std::size_t enter_count = 0;
|
||||
|
||||
TurnIt it = boost::begin(turns);
|
||||
TurnIt it_r = boost::begin(reverse_turns);
|
||||
for (; it != boost::end(turns); ++it, ++it_r)
|
||||
{
|
||||
turn_operation_iterator_type iit = boost::begin(it->operations);
|
||||
turn_operation_iterator_type iit_r = boost::begin(it_r->operations);
|
||||
++iit_r;
|
||||
|
||||
oit = process_turn(it, it_r, iit, iit_r,
|
||||
first, entered, enter_count,
|
||||
linestring1, linestring2,
|
||||
current_piece, current_segment_id,
|
||||
oit);
|
||||
}
|
||||
|
||||
BOOST_CHECK( enter_count == 0 );
|
||||
|
||||
return process_end(entered, linestring1,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename LineString,
|
||||
typename MultiLineString,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
class follow_linestring_multilinestring_linestring
|
||||
: follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut,
|
||||
LineString,
|
||||
typename boost::range_value<MultiLineString>::type,
|
||||
OverlayType
|
||||
>
|
||||
{
|
||||
protected:
|
||||
typedef typename boost::range_value<MultiLineString>::type LineString2;
|
||||
|
||||
typedef follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut, LineString, LineString2, OverlayType
|
||||
> Base;
|
||||
|
||||
typedef typename point_type<LineStringOut>::type PointOut;
|
||||
typedef overlay::traversal_turn_info<PointOut> turn_info;
|
||||
|
||||
typedef typename boost::range_iterator
|
||||
<
|
||||
@@ -139,8 +305,94 @@ protected:
|
||||
|
||||
public:
|
||||
template <typename Turns, typename OutputIterator>
|
||||
static inline OutputIterator apply(MultiLineString1& multilinestring1,
|
||||
MultiLineString2& multilinestring2,
|
||||
static inline OutputIterator apply(LineString const& linestring,
|
||||
MultiLineString const& multilinestring,
|
||||
Turns& turns,
|
||||
Turns& reverse_turns,
|
||||
OutputIterator oit)
|
||||
{
|
||||
BOOST_CHECK( boost::size(turns) == boost::size(reverse_turns) );
|
||||
|
||||
typedef typename Turns::iterator TurnIt;
|
||||
|
||||
// Iterate through all intersection points (they are
|
||||
// ordered along the each line)
|
||||
|
||||
LineStringOut current_piece;
|
||||
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
|
||||
|
||||
bool entered = false;
|
||||
bool first = true;
|
||||
std::size_t enter_count = 0;
|
||||
|
||||
TurnIt it = boost::begin(turns);
|
||||
TurnIt it_r = boost::begin(reverse_turns);
|
||||
for (; it != boost::end(turns); ++it, ++it_r)
|
||||
{
|
||||
turn_operation_iterator_type iit = boost::begin(it->operations);
|
||||
turn_operation_iterator_type iit_r = boost::begin(it_r->operations);
|
||||
++iit_r;
|
||||
|
||||
LineString2 const* ls2 =
|
||||
&*(boost::begin(multilinestring) + iit->other_id.multi_index);
|
||||
|
||||
oit = Base::process_turn(it, it_r, iit, iit_r,
|
||||
first, entered, enter_count,
|
||||
linestring, *ls2,
|
||||
current_piece, current_segment_id,
|
||||
oit);
|
||||
}
|
||||
|
||||
BOOST_CHECK( enter_count == 0 );
|
||||
|
||||
return Base::process_end(entered, linestring,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename MultiLineString,
|
||||
typename LineString,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
class follow_multilinestring_linestring_linestring
|
||||
: follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut,
|
||||
typename boost::range_value<MultiLineString>::type,
|
||||
LineString,
|
||||
OverlayType
|
||||
>
|
||||
{
|
||||
protected:
|
||||
typedef typename boost::range_value<MultiLineString>::type LineString1;
|
||||
|
||||
typedef follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut, LineString1, LineString, OverlayType
|
||||
> Base;
|
||||
|
||||
typedef typename point_type<LineStringOut>::type PointOut;
|
||||
typedef overlay::traversal_turn_info<PointOut> turn_info;
|
||||
|
||||
typedef typename boost::range_iterator
|
||||
<
|
||||
typename turn_info::container_type
|
||||
>::type turn_operation_iterator_type;
|
||||
|
||||
typedef detail::overlay::following::action_selector<OverlayType> action;
|
||||
|
||||
public:
|
||||
template <typename Turns, typename OutputIterator>
|
||||
static inline OutputIterator apply(MultiLineString const& multilinestring,
|
||||
LineString const& linestring,
|
||||
Turns& turns,
|
||||
Turns& reverse_turns,
|
||||
OutputIterator oit)
|
||||
@@ -162,7 +414,7 @@ public:
|
||||
std::size_t enter_count = 0;
|
||||
|
||||
// dummy initialization
|
||||
LineString1& ls1 = *boost::begin(multilinestring1);
|
||||
LineString1 const* ls1 = &*boost::begin(multilinestring);
|
||||
|
||||
TurnIt it = boost::begin(turns);
|
||||
TurnIt it_r = boost::begin(reverse_turns);
|
||||
@@ -177,101 +429,256 @@ public:
|
||||
if ( first_turn )
|
||||
{
|
||||
first_turn = false;
|
||||
current_multi_id = iit->seg_id.multi_index;
|
||||
ls1 = *(boost::begin(multilinestring1) + current_multi_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (action::is_entered(entered))
|
||||
{
|
||||
geometry::copy_segments<false>(ls1, current_segment_id,
|
||||
boost::size(ls1) - 1,
|
||||
current_piece);
|
||||
}
|
||||
|
||||
// Output the last one, if applicable
|
||||
if (::boost::size(current_piece) > 1)
|
||||
{
|
||||
*oit++ = current_piece;
|
||||
}
|
||||
oit = Base::process_end(entered, *ls1,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
|
||||
// reset values
|
||||
first = true;
|
||||
entered = false;
|
||||
enter_count = 0;
|
||||
current_segment_id = geometry::segment_identifier(0, -1, -1, -1);
|
||||
current_segment_id
|
||||
= geometry::segment_identifier(0, -1, -1, -1);
|
||||
geometry::clear(current_piece);
|
||||
current_multi_id = iit->seg_id.multi_index;
|
||||
ls1 = *(boost::begin(multilinestring1) + current_multi_id);
|
||||
}
|
||||
current_multi_id = iit->seg_id.multi_index;
|
||||
ls1 = &*(boost::begin(multilinestring) + current_multi_id);
|
||||
}
|
||||
|
||||
LineString2 const& ls2 =
|
||||
*(boost::begin(multilinestring2) + iit->other_id.multi_index);
|
||||
|
||||
if ( is_entering(*it, *iit) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Entering");
|
||||
#endif
|
||||
|
||||
entered = true;
|
||||
if ( enter_count == 0 )
|
||||
{
|
||||
action::enter(current_piece, ls1, current_segment_id,
|
||||
iit->seg_id.segment_index,
|
||||
it->point, *iit, oit);
|
||||
}
|
||||
++enter_count;
|
||||
}
|
||||
else if ( is_staying_inside(*it, *iit, entered, first, ls1, ls2) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Staying inside");
|
||||
#endif
|
||||
|
||||
entered = true;
|
||||
}
|
||||
else if ( is_leaving(*it, *iit, *iit_r, entered, first, ls1, ls2) )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Leaving");
|
||||
#endif
|
||||
|
||||
--enter_count;
|
||||
if ( enter_count == 0 )
|
||||
{
|
||||
entered = false;
|
||||
action::leave(current_piece, ls1, current_segment_id,
|
||||
iit->seg_id.segment_index,
|
||||
it->point, *iit, oit);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
oit = Base::process_turn(it, it_r, iit, iit_r,
|
||||
first, entered, enter_count,
|
||||
*ls1, linestring,
|
||||
current_piece, current_segment_id,
|
||||
oit);
|
||||
}
|
||||
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
std::cout << "*** enter count: " << enter_count << std::endl;
|
||||
#endif
|
||||
BOOST_CHECK( enter_count == 0 );
|
||||
if (action::is_entered(entered))
|
||||
{
|
||||
geometry::copy_segments<false>(ls1, current_segment_id,
|
||||
boost::size(ls1) - 1,
|
||||
current_piece);
|
||||
}
|
||||
|
||||
// Output the last one, if applicable
|
||||
if (::boost::size(current_piece) > 1)
|
||||
{
|
||||
*oit++ = current_piece;
|
||||
}
|
||||
|
||||
return oit;
|
||||
return Base::process_end(entered, *ls1,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename MultiLineString1,
|
||||
typename MultiLineString2,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
class follow_multilinestring_multilinestring_linestring
|
||||
: follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut,
|
||||
typename boost::range_value<MultiLineString1>::type,
|
||||
typename boost::range_value<MultiLineString2>::type,
|
||||
OverlayType
|
||||
>
|
||||
{
|
||||
protected:
|
||||
typedef typename boost::range_value<MultiLineString1>::type LineString1;
|
||||
typedef typename boost::range_value<MultiLineString2>::type LineString2;
|
||||
|
||||
typedef follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut, LineString1, LineString2, OverlayType
|
||||
> Base;
|
||||
|
||||
typedef typename point_type<LineStringOut>::type PointOut;
|
||||
typedef overlay::traversal_turn_info<PointOut> turn_info;
|
||||
|
||||
typedef typename boost::range_iterator
|
||||
<
|
||||
typename turn_info::container_type
|
||||
>::type turn_operation_iterator_type;
|
||||
|
||||
typedef detail::overlay::following::action_selector<OverlayType> action;
|
||||
|
||||
public:
|
||||
template <typename Turns, typename OutputIterator>
|
||||
static inline OutputIterator apply(MultiLineString1 const& multilinestring1,
|
||||
MultiLineString2 const& multilinestring2,
|
||||
Turns& turns,
|
||||
Turns& reverse_turns,
|
||||
OutputIterator oit)
|
||||
{
|
||||
BOOST_CHECK( boost::size(turns) == boost::size(reverse_turns) );
|
||||
|
||||
typedef typename Turns::iterator TurnIt;
|
||||
|
||||
// Iterate through all intersection points (they are
|
||||
// ordered along the each line)
|
||||
|
||||
LineStringOut current_piece;
|
||||
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
|
||||
int current_multi_id = -1;
|
||||
|
||||
bool entered = false;
|
||||
bool first = true;
|
||||
bool first_turn = true;
|
||||
std::size_t enter_count = 0;
|
||||
|
||||
// dummy initialization
|
||||
LineString1 const* ls1 = &*boost::begin(multilinestring1);
|
||||
|
||||
TurnIt it = boost::begin(turns);
|
||||
TurnIt it_r = boost::begin(reverse_turns);
|
||||
for (; it != boost::end(turns); ++it, ++it_r)
|
||||
{
|
||||
turn_operation_iterator_type iit = boost::begin(it->operations);
|
||||
turn_operation_iterator_type iit_r = boost::begin(it_r->operations);
|
||||
++iit_r;
|
||||
|
||||
if ( iit->seg_id.multi_index != current_multi_id )
|
||||
{
|
||||
if ( first_turn )
|
||||
{
|
||||
first_turn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
oit = Base::process_end(entered, *ls1,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
|
||||
// reset values
|
||||
first = true;
|
||||
entered = false;
|
||||
enter_count = 0;
|
||||
current_segment_id
|
||||
= geometry::segment_identifier(0, -1, -1, -1);
|
||||
geometry::clear(current_piece);
|
||||
}
|
||||
current_multi_id = iit->seg_id.multi_index;
|
||||
ls1 = &*(boost::begin(multilinestring1) + current_multi_id);
|
||||
}
|
||||
|
||||
LineString2 const* ls2 =
|
||||
&*(boost::begin(multilinestring2) + iit->other_id.multi_index);
|
||||
|
||||
oit = Base::process_turn(it, it_r, iit, iit_r,
|
||||
first, entered, enter_count,
|
||||
*ls1, *ls2,
|
||||
current_piece, current_segment_id,
|
||||
oit);
|
||||
}
|
||||
|
||||
BOOST_CHECK( enter_count == 0 );
|
||||
|
||||
return Base::process_end(entered, *ls1,
|
||||
current_segment_id, current_piece,
|
||||
oit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
overlay_type OverlayType,
|
||||
typename Tag1 = typename tag<Geometry1>::type,
|
||||
typename Tag2 = typename tag<Geometry2>::type
|
||||
>
|
||||
struct follow_dispatch
|
||||
: not_implemented<LineStringOut, Geometry1, Geometry2>
|
||||
{};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename Linestring1,
|
||||
typename Linestring2,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
struct follow_dispatch
|
||||
<
|
||||
LineStringOut, Linestring1, Linestring2,
|
||||
OverlayType, linestring_tag, linestring_tag
|
||||
> : follow_linestring_linestring_linestring
|
||||
<
|
||||
LineStringOut, Linestring1, Linestring2, OverlayType
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename Linestring,
|
||||
typename MultiLinestring,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
struct follow_dispatch
|
||||
<
|
||||
LineStringOut, Linestring, MultiLinestring,
|
||||
OverlayType, linestring_tag, multi_linestring_tag
|
||||
> : follow_linestring_multilinestring_linestring
|
||||
<
|
||||
LineStringOut, Linestring, MultiLinestring, OverlayType
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename MultiLinestring,
|
||||
typename Linestring,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
struct follow_dispatch
|
||||
<
|
||||
LineStringOut, MultiLinestring, Linestring,
|
||||
OverlayType, multi_linestring_tag, linestring_tag
|
||||
> : follow_multilinestring_linestring_linestring
|
||||
<
|
||||
LineStringOut, MultiLinestring, Linestring, OverlayType
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename MultiLinestring1,
|
||||
typename MultiLinestring2,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
struct follow_dispatch
|
||||
<
|
||||
LineStringOut, MultiLinestring1, MultiLinestring2,
|
||||
OverlayType, multi_linestring_tag, multi_linestring_tag
|
||||
> : follow_multilinestring_multilinestring_linestring
|
||||
<
|
||||
LineStringOut, MultiLinestring1, MultiLinestring2, OverlayType
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename LineStringOut,
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
overlay_type OverlayType
|
||||
>
|
||||
struct follow
|
||||
: follow_dispatch<LineStringOut, Geometry1, Geometry2, OverlayType>
|
||||
{};
|
||||
|
||||
|
||||
} // namespace following
|
||||
|
||||
|
||||
@@ -545,6 +545,58 @@ BOOST_AUTO_TEST_CASE( test_difference_linestring_multilinestring )
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_difference_multilinestring_linestring )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
std::cout << std::endl << std::endl << std::endl;
|
||||
std::cout << "*** MULTILINESTRING / LINESTRING DIFFERENCE ***"
|
||||
<< std::endl;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
typedef linestring_type L;
|
||||
typedef multi_linestring_type ML;
|
||||
|
||||
typedef test_difference_of_geometries<ML, L, ML> tester;
|
||||
|
||||
// disjoint linestrings
|
||||
tester()
|
||||
(from_wkt<ML>("MULTILINESTRING((0 0,10 0,20 1),(1 0,7 0))"),
|
||||
from_wkt<L>("LINESTRING(1 1,2 2,4 3)"),
|
||||
from_wkt<ML>("MULTILINESTRING((0 0,10 0,20 1),(1 0,7 0))"),
|
||||
"mlldf01"
|
||||
);
|
||||
|
||||
tester()
|
||||
(from_wkt<ML>("MULTILINESTRING((0 0,10 0,20 1),(1 0,7 0))"),
|
||||
from_wkt<L>("LINESTRING(1 1,2 0,4 0)"),
|
||||
from_wkt<ML>("MULTILINESTRING((0 0,2 0),(4 0,10 0,20 1),\
|
||||
(1 0,2 0),(4 0,7 0))"),
|
||||
"mlldf02"
|
||||
);
|
||||
|
||||
tester()
|
||||
(from_wkt<ML>("MULTILINESTRING((0 0,101 0))"),
|
||||
from_wkt<L>("LINESTRING(-1 -1,1 0,101 0,200 -1)"),
|
||||
from_wkt<ML>("MULTILINESTRING((0 0,1 0))"),
|
||||
"mlldf03"
|
||||
);
|
||||
|
||||
tester()
|
||||
(from_wkt<ML>("MULTILINESTRING((0 0,20 0))"),
|
||||
from_wkt<L>("LINESTRING(0 1,1 0,19 0,20 1,19 1,18 0,2 0,\
|
||||
1 1,2 1,3 0,17 0,18 1,17 1,16 0,4 0,3 1)"),
|
||||
from_wkt<ML>("MULTILINESTRING((0 0,1 0),(19 0,20 0))"),
|
||||
"mlldf04"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_difference_multilinestring_multilinestring )
|
||||
{
|
||||
#ifdef GEOMETRY_TEST_DEBUG
|
||||
|
||||
Reference in New Issue
Block a user