Added boost header
This commit is contained in:
394
test/external/boost/geometry/algorithms/detail/overlay/traverse.hpp
vendored
Normal file
394
test/external/boost/geometry/algorithms/detail/overlay/traverse.hpp
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/core/coordinate_dimension.hpp>
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT)
|
||||
# include <string>
|
||||
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
|
||||
# include <boost/geometry/domains/gis/io/wkt/wkt.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
template <typename Turn, typename Operation>
|
||||
inline void debug_traverse(Turn const& turn, Operation op,
|
||||
std::string const& header)
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
|
||||
std::cout << header
|
||||
<< " at " << op.seg_id
|
||||
<< " op: " << operation_char(op.operation)
|
||||
<< " vis: " << visited_char(op.visited)
|
||||
<< " of: " << operation_char(turn.operations[0].operation)
|
||||
<< operation_char(turn.operations[1].operation)
|
||||
<< std::endl;
|
||||
|
||||
if (boost::contains(header, "Finished"))
|
||||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <typename Info, typename Turn>
|
||||
inline void set_visited_for_continue(Info& info, Turn const& turn)
|
||||
{
|
||||
// On "continue", set "visited" for ALL directions
|
||||
if (turn.operation == detail::overlay::operation_continue)
|
||||
{
|
||||
for (typename boost::range_iterator
|
||||
<
|
||||
typename Info::container_type
|
||||
>::type it = boost::begin(info.operations);
|
||||
it != boost::end(info.operations);
|
||||
++it)
|
||||
{
|
||||
if (it->visited.none())
|
||||
{
|
||||
it->visited.set_visited();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse1, bool Reverse2,
|
||||
typename GeometryOut,
|
||||
typename G1,
|
||||
typename G2,
|
||||
typename Turns,
|
||||
typename IntersectionInfo
|
||||
>
|
||||
inline bool assign_next_ip(G1 const& g1, G2 const& g2,
|
||||
Turns& turns,
|
||||
typename boost::range_iterator<Turns>::type& ip,
|
||||
GeometryOut& current_output,
|
||||
IntersectionInfo& info,
|
||||
segment_identifier& seg_id)
|
||||
{
|
||||
info.visited.set_visited();
|
||||
set_visited_for_continue(*ip, info);
|
||||
|
||||
// If there is no next IP on this segment
|
||||
if (info.enriched.next_ip_index < 0)
|
||||
{
|
||||
if (info.enriched.travels_to_vertex_index < 0
|
||||
|| info.enriched.travels_to_ip_index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(info.enriched.travels_to_vertex_index >= 0);
|
||||
BOOST_ASSERT(info.enriched.travels_to_ip_index >= 0);
|
||||
|
||||
if (info.seg_id.source_index == 0)
|
||||
{
|
||||
geometry::copy_segments<Reverse1>(g1, info.seg_id,
|
||||
info.enriched.travels_to_vertex_index,
|
||||
current_output);
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry::copy_segments<Reverse2>(g2, info.seg_id,
|
||||
info.enriched.travels_to_vertex_index,
|
||||
current_output);
|
||||
}
|
||||
seg_id = info.seg_id;
|
||||
ip = boost::begin(turns) + info.enriched.travels_to_ip_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = boost::begin(turns) + info.enriched.next_ip_index;
|
||||
seg_id = info.seg_id;
|
||||
}
|
||||
|
||||
detail::overlay::append_no_duplicates(current_output, ip->point);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline bool select_source(operation_type operation, int source1, int source2)
|
||||
{
|
||||
return (operation == operation_intersection && source1 != source2)
|
||||
|| (operation == operation_union && source1 == source2)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Turn,
|
||||
typename Iterator
|
||||
>
|
||||
inline bool select_next_ip(operation_type operation,
|
||||
Turn& turn,
|
||||
segment_identifier const& seg_id,
|
||||
Iterator& selected)
|
||||
{
|
||||
if (turn.discarded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool has_tp = false;
|
||||
selected = boost::end(turn.operations);
|
||||
for (Iterator it = boost::begin(turn.operations);
|
||||
it != boost::end(turn.operations);
|
||||
++it)
|
||||
{
|
||||
if (it->visited.started())
|
||||
{
|
||||
selected = it;
|
||||
//std::cout << " RETURN";
|
||||
return true;
|
||||
}
|
||||
|
||||
// In some cases there are two alternatives.
|
||||
// For "ii", take the other one (alternate)
|
||||
// UNLESS the other one is already visited
|
||||
// For "uu", take the same one (see above);
|
||||
// For "cc", take either one, but if there is a starting one,
|
||||
// take that one.
|
||||
if ( (it->operation == operation_continue
|
||||
&& (! has_tp || it->visited.started()
|
||||
)
|
||||
)
|
||||
|| (it->operation == operation
|
||||
&& ! it->visited.finished()
|
||||
&& (! has_tp
|
||||
|| select_source(operation,
|
||||
it->seg_id.source_index, seg_id.source_index)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
selected = it;
|
||||
debug_traverse(turn, *it, " Candidate");
|
||||
has_tp = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_tp)
|
||||
{
|
||||
debug_traverse(turn, *selected, " Accepted");
|
||||
}
|
||||
|
||||
|
||||
return has_tp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief Traverses through intersection points / geometries
|
||||
\ingroup overlay
|
||||
*/
|
||||
template
|
||||
<
|
||||
bool Reverse1, bool Reverse2,
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename Backtrack = backtrack_check_self_intersections<Geometry1, Geometry2>
|
||||
>
|
||||
class traverse
|
||||
{
|
||||
public :
|
||||
template <typename Turns, typename Rings>
|
||||
static inline void apply(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
detail::overlay::operation_type operation,
|
||||
Turns& turns, Rings& rings)
|
||||
{
|
||||
typedef typename boost::range_iterator<Turns>::type turn_iterator;
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
typedef typename boost::range_iterator
|
||||
<
|
||||
typename turn_type::container_type
|
||||
>::type turn_operation_iterator_type;
|
||||
|
||||
std::size_t size_at_start = boost::size(rings);
|
||||
|
||||
typename Backtrack::state_type state;
|
||||
do
|
||||
{
|
||||
state.reset();
|
||||
|
||||
// Iterate through all unvisited points
|
||||
for (turn_iterator it = boost::begin(turns);
|
||||
state.good() && it != boost::end(turns);
|
||||
++it)
|
||||
{
|
||||
// Skip discarded ones
|
||||
if (! (it->is_discarded() || it->blocked()))
|
||||
{
|
||||
for (turn_operation_iterator_type iit = boost::begin(it->operations);
|
||||
state.good() && iit != boost::end(it->operations);
|
||||
++iit)
|
||||
{
|
||||
if (iit->visited.none()
|
||||
&& ! iit->visited.rejected()
|
||||
&& (iit->operation == operation
|
||||
|| iit->operation == detail::overlay::operation_continue)
|
||||
)
|
||||
{
|
||||
set_visited_for_continue(*it, *iit);
|
||||
|
||||
typename boost::range_value<Rings>::type current_output;
|
||||
detail::overlay::append_no_duplicates(current_output,
|
||||
it->point, true);
|
||||
|
||||
turn_iterator current = it;
|
||||
turn_operation_iterator_type current_iit = iit;
|
||||
segment_identifier current_seg_id;
|
||||
|
||||
if (! detail::overlay::assign_next_ip<Reverse1, Reverse2>(
|
||||
geometry1, geometry2,
|
||||
turns,
|
||||
current, current_output,
|
||||
*iit, current_seg_id))
|
||||
{
|
||||
Backtrack::apply(
|
||||
size_at_start,
|
||||
rings, current_output, turns, *current_iit,
|
||||
"No next IP",
|
||||
geometry1, geometry2, state);
|
||||
}
|
||||
|
||||
if (! detail::overlay::select_next_ip(
|
||||
operation,
|
||||
*current,
|
||||
current_seg_id,
|
||||
current_iit))
|
||||
{
|
||||
Backtrack::apply(
|
||||
size_at_start,
|
||||
rings, current_output, turns, *iit,
|
||||
"Dead end at start",
|
||||
geometry1, geometry2, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
iit->visited.set_started();
|
||||
detail::overlay::debug_traverse(*it, *iit, "-> Started");
|
||||
detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
|
||||
|
||||
|
||||
unsigned int i = 0;
|
||||
|
||||
while (current_iit != iit && state.good())
|
||||
{
|
||||
if (current_iit->visited.visited())
|
||||
{
|
||||
// It visits a visited node again, without passing the start node.
|
||||
// This makes it suspicious for endless loops
|
||||
Backtrack::apply(
|
||||
size_at_start,
|
||||
rings, current_output, turns, *iit,
|
||||
"Visit again",
|
||||
geometry1, geometry2, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// We assume clockwise polygons only, non self-intersecting, closed.
|
||||
// However, the input might be different, and checking validity
|
||||
// is up to the library user.
|
||||
|
||||
// Therefore we make here some sanity checks. If the input
|
||||
// violates the assumptions, the output polygon will not be correct
|
||||
// but the routine will stop and output the current polygon, and
|
||||
// will continue with the next one.
|
||||
|
||||
// Below three reasons to stop.
|
||||
detail::overlay::assign_next_ip<Reverse1, Reverse2>(
|
||||
geometry1, geometry2,
|
||||
turns, current, current_output,
|
||||
*current_iit, current_seg_id);
|
||||
|
||||
if (! detail::overlay::select_next_ip(
|
||||
operation,
|
||||
*current,
|
||||
current_seg_id,
|
||||
current_iit))
|
||||
{
|
||||
// Should not occur in valid (non-self-intersecting) polygons
|
||||
// Should not occur in self-intersecting polygons without spikes
|
||||
// Might occur in polygons with spikes
|
||||
Backtrack::apply(
|
||||
size_at_start,
|
||||
rings, current_output, turns, *iit,
|
||||
"Dead end",
|
||||
geometry1, geometry2, state);
|
||||
}
|
||||
detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
|
||||
|
||||
if (i++ > 2 + 2 * turns.size())
|
||||
{
|
||||
// Sanity check: there may be never more loops
|
||||
// than turn points.
|
||||
// Turn points marked as "ii" can be visited twice.
|
||||
Backtrack::apply(
|
||||
size_at_start,
|
||||
rings, current_output, turns, *iit,
|
||||
"Endless loop",
|
||||
geometry1, geometry2, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.good())
|
||||
{
|
||||
iit->visited.set_finished();
|
||||
detail::overlay::debug_traverse(*current, *iit, "->Finished");
|
||||
rings.push_back(current_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (! state.good());
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
|
||||
Reference in New Issue
Block a user