[set ops] update linear-linear set op computation based on Adam's modification of turn info that now contains the is_collinear member;

This commit is contained in:
Menelaos Karavelas
2014-03-21 13:46:49 +02:00
parent 2394873328
commit 44827bdb28
2 changed files with 228 additions and 119 deletions

View File

@@ -11,6 +11,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
namespace boost { namespace geometry
{
@@ -63,7 +64,6 @@ static inline bool is_staying_inside(Turn const& turn,
template <typename Turn, typename Operation>
static inline bool is_leaving(Turn const& turn,
Operation const& operation,
Operation const& reverse_operation,
bool entered)
{
if ( !entered )
@@ -89,29 +89,29 @@ static inline bool is_leaving(Turn const& turn,
return false;
}
if ( turn.operations[1].operation == operation_intersection )
{
return true;
}
BOOST_ASSERT( turn.operations[1].operation == operation_union
|| turn.operations[1].operation == operation_blocked );
return reverse_operation.operation == operation_intersection;
return operation.is_collinear;
}
template <typename Turn, typename Operation>
static inline bool is_isolated_point(Turn const& turn,
Operation const& operation,
Operation const& reverse_operation,
bool entered)
bool entered,
bool is_point1,
bool is_point2)
{
if ( entered )
{
return false;
}
if ( turn.method == method_collinear && (is_point1 || is_point2) )
{
BOOST_ASSERT( operation.operation == operation_continue );
return true;
}
if ( turn.method == method_crosses )
{
return true;
@@ -132,17 +132,42 @@ static inline bool is_isolated_point(Turn const& turn,
return false;
}
if ( turn.operations[1].operation == operation_intersection )
return !operation.is_collinear;
}
template <bool Enable>
struct is_point
{
template <typename Linestring>
static inline bool apply(Linestring const& linestring)
{
return false;
}
};
template<>
struct is_point<true>
{
template <typename Linestring>
static inline bool apply(Linestring const& linestring)
{
BOOST_ASSERT( boost::size(linestring) >= 2 );
return boost::size(linestring) == 2
&& geometry::equals(*boost::begin(linestring),
*(++boost::begin(linestring))
);
}
};
BOOST_ASSERT( turn.operations[1].operation == operation_union
|| turn.operations[1].operation == operation_blocked );
return reverse_operation.operation == operation_union
|| reverse_operation.operation == operation_blocked;
}
template
@@ -166,11 +191,14 @@ protected:
typename OutputIterator
>
static inline OutputIterator
process_turn(TurnIterator it, TurnIterator it_r,
TurnOperationIterator op_it, TurnOperationIterator op_it_r,
process_turn(TurnIterator it,
TurnOperationIterator op_it,
bool& first, bool& entered,
std::size_t& enter_count,
LineString1 const& linestring1, LineString2 const&,
LineString1 const& linestring1,
LineString2 const& linestring2,
bool is_point1,
bool is_point2,
LineStringOut& current_piece,
SegmentIdentifier& current_segment_id,
OutputIterator oit)
@@ -178,7 +206,7 @@ protected:
if ( is_entering(*it, *op_it) )
{
#ifdef GEOMETRY_TEST_DEBUG
detail::overlay::debug_traverse(*it, *op_it, "-> Entering");
detail::turns::debug_turn(*it, *op_it, "-> Entering");
#endif
entered = true;
@@ -191,18 +219,10 @@ protected:
}
++enter_count;
}
else if ( is_staying_inside(*it, *op_it, entered) )
else if ( is_leaving(*it, *op_it, entered) )
{
#ifdef GEOMETRY_TEST_DEBUG
detail::overlay::debug_traverse(*it, *op_it, "-> Staying inside");
#endif
entered = true;
}
else if ( is_leaving(*it, *op_it, *op_it_r, entered) )
{
#ifdef GEOMETRY_TEST_DEBUG
detail::overlay::debug_traverse(*it, *op_it, "-> Leaving");
detail::turns::debug_turn(*it, *op_it, "-> Leaving");
#endif
--enter_count;
@@ -216,11 +236,11 @@ protected:
}
}
#ifndef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS
else if ( FollowIsolatedPoints &&
is_isolated_point(*it, *op_it, *op_it_r, entered) )
else if ( FollowIsolatedPoints
&& is_isolated_point(*it, *op_it, entered, is_point1, is_point2) )
{
#ifdef GEOMETRY_TEST_DEBUG
detail::overlay::debug_traverse(*it, *op_it, "-> Isolated point");
detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
#endif
action::isolated_point(current_piece, linestring1,
@@ -229,6 +249,14 @@ protected:
it->point, *op_it, oit);
}
#endif
else if ( is_staying_inside(*it, *op_it, entered) )
{
#ifdef GEOMETRY_TEST_DEBUG
detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
#endif
entered = true;
}
first = false;
return oit;
}
@@ -267,11 +295,8 @@ public:
static inline OutputIterator apply(LineString1 const& linestring1,
LineString2 const& linestring2,
Turns const& turns,
Turns const& reverse_turns,
OutputIterator oit)
{
BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) );
typedef typename boost::range_iterator<Turns const>::type TurnIterator;
typedef typename boost::range_value<Turns>::type TurnInfo;
typedef typename boost::range_iterator
@@ -289,17 +314,17 @@ public:
bool first = true;
std::size_t enter_count = 0;
TurnIterator it = boost::begin(turns);
TurnIterator it_r = boost::begin(reverse_turns);
for (; it != boost::end(turns); ++it, ++it_r)
bool is_point1 = is_point<FollowIsolatedPoints>::apply(linestring1);
bool is_point2 = is_point<FollowIsolatedPoints>::apply(linestring2);
for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it)
{
TurnOperationIterator op_it = boost::begin(it->operations);
TurnOperationIterator op_it_r = boost::begin(it_r->operations);
++op_it_r;
oit = process_turn(it, it_r, op_it, op_it_r,
oit = process_turn(it, op_it,
first, entered, enter_count,
linestring1, linestring2,
is_point1, is_point2,
current_piece, current_segment_id,
oit);
}
@@ -348,11 +373,8 @@ public:
static inline OutputIterator apply(LineString const& linestring,
MultiLineString const& multilinestring,
Turns const& turns,
Turns const& reverse_turns,
OutputIterator oit)
{
BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) );
typedef typename boost::range_iterator<Turns const>::type TurnIterator;
typedef typename boost::range_value<Turns>::type TurnInfo;
typedef typename boost::range_iterator
@@ -370,20 +392,20 @@ public:
bool first = true;
std::size_t enter_count = 0;
TurnIterator it = boost::begin(turns);
TurnIterator it_r = boost::begin(reverse_turns);
for (; it != boost::end(turns); ++it, ++it_r)
bool is_point1 = is_point<FollowIsolatedPoints>::apply(linestring);
for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it)
{
TurnOperationIterator op_it = boost::begin(it->operations);
TurnOperationIterator op_it_r = boost::begin(it_r->operations);
++op_it_r;
LineString2 const* linestring2 =
&*(boost::begin(multilinestring) + op_it->other_id.multi_index);
oit = Base::process_turn(it, it_r, op_it, op_it_r,
oit = Base::process_turn(it, op_it,
first, entered, enter_count,
linestring, *linestring2,
is_point1,
is_point<FollowIsolatedPoints>::apply(*linestring2),
current_piece, current_segment_id,
oit);
}
@@ -434,11 +456,8 @@ public:
static inline OutputIterator apply(MultiLineString const& multilinestring,
LineString const& linestring,
Turns const& turns,
Turns const& reverse_turns,
OutputIterator oit)
{
BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) );
typedef typename boost::range_iterator<Turns const>::type TurnIterator;
typedef typename boost::range_value<Turns>::type TurnInfo;
typedef typename boost::range_iterator
@@ -461,13 +480,13 @@ public:
// dummy initialization
LineString1 const* linestring1 = &*boost::begin(multilinestring);
bool is_point1 = is_point<FollowIsolatedPoints>::apply(*linestring1);
bool is_point2 = is_point<FollowIsolatedPoints>::apply(linestring);
TurnIterator it = boost::begin(turns);
TurnIterator it_r = boost::begin(reverse_turns);
for (; it != boost::end(turns); ++it, ++it_r)
for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it)
{
TurnOperationIterator op_it = boost::begin(it->operations);
TurnOperationIterator op_it_r = boost::begin(it_r->operations);
++op_it_r;
if ( op_it->seg_id.multi_index != current_multi_id )
{
@@ -492,11 +511,13 @@ public:
current_multi_id = op_it->seg_id.multi_index;
linestring1 =
&*(boost::begin(multilinestring) + current_multi_id);
is_point1 = is_point<FollowIsolatedPoints>::apply(*linestring1);
}
oit = Base::process_turn(it, it_r, op_it, op_it_r,
oit = Base::process_turn(it, op_it,
first, entered, enter_count,
*linestring1, linestring,
is_point1, is_point2,
current_piece, current_segment_id,
oit);
}
@@ -546,11 +567,8 @@ public:
static inline OutputIterator apply(MultiLineString1 const& multilinestring1,
MultiLineString2 const& multilinestring2,
Turns const& turns,
Turns const& reverse_turns,
OutputIterator oit)
{
BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) );
typedef typename boost::range_iterator<Turns const>::type TurnIterator;
typedef typename boost::range_value<Turns>::type TurnInfo;
typedef typename boost::range_iterator
@@ -573,13 +591,11 @@ public:
// dummy initialization
LineString1 const* linestring1 = &*boost::begin(multilinestring1);
TurnIterator it = boost::begin(turns);
TurnIterator it_r = boost::begin(reverse_turns);
for (; it != boost::end(turns); ++it, ++it_r)
bool is_point1 = is_point<FollowIsolatedPoints>::apply(*linestring1);
for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it)
{
TurnOperationIterator op_it = boost::begin(it->operations);
TurnOperationIterator op_it_r = boost::begin(it_r->operations);
++op_it_r;
if ( op_it->seg_id.multi_index != current_multi_id )
{
@@ -604,14 +620,16 @@ public:
current_multi_id = op_it->seg_id.multi_index;
linestring1 =
&*(boost::begin(multilinestring1) + current_multi_id);
is_point1 = is_point<FollowIsolatedPoints>::apply(*linestring1);
}
LineString2 const* linestring2 =
&*(boost::begin(multilinestring2) + op_it->other_id.multi_index);
oit = Base::process_turn(it, it_r, op_it, op_it_r,
oit = Base::process_turn(it, op_it,
first, entered, enter_count,
*linestring1, *linestring2,
is_point1,
is_point<FollowIsolatedPoints>::apply(*linestring2),
current_piece, current_segment_id,
oit);
}

View File

@@ -13,20 +13,19 @@
#include <algorithm>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/unique.hpp>
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
#include <boost/geometry/algorithms/detail/turns/compare_turns.hpp>
#include <boost/geometry/algorithms/detail/turns/print_turns.hpp>
#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp>
#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp>
#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_FILTER_CONTINUE_TURNS
#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp>
#endif
#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_REMOVE_DUPLICATE_TURNS
#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp>
#endif
namespace boost { namespace geometry
@@ -111,6 +110,48 @@ struct linear_linear_no_intersections
};
template
<
typename Geometry,
bool Enable = false,
typename GeometryTag = typename tag<Geometry>::type
>
struct remove_extra_points
{
static inline void apply(Geometry& ) {}
};
template <typename Linestring>
struct remove_extra_points<Linestring, true, linestring_tag>
{
static inline void apply(Linestring& linestring)
{
geometry::unique(linestring);
if ( boost::size(linestring) == 1 )
{
geometry::append(linestring, *boost::begin(linestring));
}
}
};
template <typename MultiLinestring>
struct remove_extra_points<MultiLinestring, true, multi_linestring_tag>
{
static inline void apply(MultiLinestring& multilinestring)
{
BOOST_AUTO_TPL(it, boost::begin(multilinestring));
for (; it != boost::end(multilinestring); ++it)
{
remove_extra_points
<
typename boost::range_value<MultiLinestring>::type,
true
>::apply(*it);
}
}
};
@@ -126,7 +167,8 @@ template
typename Linear2,
typename LinestringOut,
overlay_type OverlayType,
bool EnableFilterContinueTurns = true,
bool EnableRemoveExtraPoints = true,
bool EnableFilterContinueTurns = false,
bool EnableRemoveDuplicateTurns = true,
bool EnableDegenerateTurns = true
>
@@ -136,11 +178,7 @@ protected:
struct AssignPolicy
{
static bool const include_no_turn = false;
#ifdef BOOST_GEOMETRY_DIFFERENCE_INCLUDE_DEGENERATE_TURNS
static bool const include_degenerate = true;
#else
static bool const include_degenerate = EnableDegenerateTurns;
#endif
static bool const include_opposite = false;
template
@@ -194,7 +232,6 @@ protected:
typename OutputIterator
>
static inline OutputIterator follow_turns(Turns const& turns,
Turns const& reverse_turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
OutputIterator oit)
@@ -206,7 +243,7 @@ protected:
LinearGeometry2,
OverlayTypeForFollow,
FollowIsolatedPoints
>::apply(linear1, linear2, turns, reverse_turns, oit);
>::apply(linear1, linear2, turns, oit);
}
@@ -221,54 +258,91 @@ protected:
>
static inline OutputIterator
sort_and_follow_turns(Turns& turns,
Turns& reverse_turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
OutputIterator oit)
{
#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_FILTER_CONTINUE_TURNS
// remove turns that have no added value
turns::filter_continue_turns
<
Turns, EnableFilterContinueTurns
>::apply(turns);
turns::filter_continue_turns
<
Turns, EnableFilterContinueTurns
>::apply(reverse_turns);
#endif
// sort by seg_id, distance, and operation
std::sort(boost::begin(turns), boost::end(turns),
detail::turns::less_seg_dist_other_op<>());
std::sort(boost::begin(reverse_turns), boost::end(reverse_turns),
detail::turns::less_seg_dist_other_op<std::greater<int> >());
#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_REMOVE_DUPLICATE_TURNS
// remove duplicate turns
turns::remove_duplicate_turns
<
Turns, EnableRemoveDuplicateTurns
>::apply(turns);
#ifdef GEOMETRY_TEST_DEBUG
Linear2 linear2_reverse(linear2);
geometry::reverse(linear2_reverse);
Turns reverse_turns;
compute_turns(reverse_turns, linear1, linear2_reverse);
Turns turns_copy(turns);
Turns reverse_turns_copy(reverse_turns);
turns::filter_continue_turns
<
Turns, true //EnableFilterContinueTurns
>::apply(turns_copy);
turns::filter_continue_turns
<
Turns, EnableFilterContinueTurns
>::apply(reverse_turns);
turns::filter_continue_turns
<
Turns, true //EnableFilterContinueTurns
>::apply(reverse_turns_copy);
std::sort(boost::begin(turns_copy), boost::end(turns_copy),
detail::turns::less_seg_dist_other_op<>());
std::sort(boost::begin(reverse_turns), boost::end(reverse_turns),
detail::turns::less_seg_dist_other_op<std::greater<int> >());
std::sort(boost::begin(reverse_turns_copy), boost::end(reverse_turns_copy),
detail::turns::less_seg_dist_other_op<std::greater<int> >());
turns::remove_duplicate_turns
<
Turns, EnableRemoveDuplicateTurns
>::apply(reverse_turns);
#endif
#ifdef GEOMETRY_TEST_DEBUG
turns::remove_duplicate_turns
<
Turns, EnableRemoveDuplicateTurns
>::apply(reverse_turns_copy);
BOOST_ASSERT( boost::size(turns_copy) == boost::size(reverse_turns_copy) );
std::cout << std::endl << std::endl;
std::cout << "### ORIGINAL TURNS ###" << std::endl;
detail::turns::print_turns(linear1, linear2, turns);
std::cout << std::endl << std::endl;
Linear2 linear2_reverse = linear2;
geometry::reverse(linear2_reverse);
detail::turns::print_turns(linear1, linear2_reverse, reverse_turns);
std::cout << "### ORIGINAL REVERSE TURNS ###" << std::endl;
detail::turns::print_turns(linear1, linear2, reverse_turns);
std::cout << std::endl << std::endl;
std::cout << "### TURNS W/O CONTINUE TURNS ###" << std::endl;
detail::turns::print_turns(linear1, linear2, turns_copy);
std::cout << std::endl << std::endl;
std::cout << "### REVERSE TURNS W/O CONTINUE TURNS ###" << std::endl;
detail::turns::print_turns(linear1, linear2_reverse, reverse_turns_copy);
std::cout << std::endl << std::endl;
#endif
return follow_turns
<
OverlayTypeForFollow, FollowIsolatedPoints
>(turns, reverse_turns, linear1, linear2, oit);
>(turns, linear1, linear2, oit);
}
public:
@@ -276,15 +350,21 @@ public:
<
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linear1 const& linear1,
Linear2 const& linear2,
static inline OutputIterator apply(Linear1 const& lineargeometry1,
Linear2 const& lineargeometry2,
OutputIterator oit,
Strategy const& )
{
typedef traversal_turn_info
Linear1 linear1(lineargeometry1);
Linear2 linear2(lineargeometry2);
remove_extra_points<Linear1, EnableRemoveExtraPoints>::apply(linear1);
remove_extra_points<Linear2, EnableRemoveExtraPoints>::apply(linear2);
typedef typename detail::relate::turns::get_turns
<
typename point_type<LinestringOut>::type
> turn_info;
Linear1, Linear2
>::turn_info turn_info;
typedef std::vector<turn_info> Turns;
@@ -306,16 +386,10 @@ public:
>::apply(linear1, oit);
}
Turns reverse_turns;
Linear2 linear2_reverse = linear2;
geometry::reverse(linear2_reverse);
compute_turns(reverse_turns, linear1, linear2_reverse);
return sort_and_follow_turns
<
OverlayType, OverlayType == overlay_intersection
>(turns, reverse_turns, linear1, linear2, oit);
>(turns, linear1, linear2, oit);
}
};
@@ -326,19 +400,34 @@ template
<
typename Linear1,
typename Linear2,
typename LinestringOut
typename LinestringOut,
bool EnableRemoveExtraPoints,
bool EnableFilterContinueTurns,
bool EnableRemoveDuplicateTurns,
bool EnableDegenerateTurns
>
struct linear_linear_linestring<Linear1, Linear2, LinestringOut, overlay_union>
struct linear_linear_linestring
<
Linear1, Linear2, LinestringOut, overlay_union,
EnableRemoveExtraPoints, EnableFilterContinueTurns,
EnableRemoveDuplicateTurns, EnableDegenerateTurns
>
{
template
<
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linear1 const& linear1,
Linear2 const& linear2,
static inline OutputIterator apply(Linear1 const& lineargeometry1,
Linear2 const& lineargeometry2,
OutputIterator oit,
Strategy const& strategy)
{
Linear1 linear1(lineargeometry1);
Linear2 linear2(lineargeometry2);
remove_extra_points<Linear1, EnableRemoveExtraPoints>::apply(linear1);
remove_extra_points<Linear2, EnableRemoveExtraPoints>::apply(linear2);
oit = linear_linear_no_intersections
<
LinestringOut,
@@ -349,7 +438,9 @@ struct linear_linear_linestring<Linear1, Linear2, LinestringOut, overlay_union>
return linear_linear_linestring
<
Linear2, Linear1, LinestringOut, overlay_difference
Linear2, Linear1, LinestringOut, overlay_difference,
false, EnableFilterContinueTurns,
EnableRemoveDuplicateTurns, EnableDegenerateTurns
>::apply(linear2, linear1, oit, strategy);
}
};