Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
// 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_ADD_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
#include <boost/geometry/algorithms/detail/overlay/convert_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename RingCollection
>
inline void convert_and_add(GeometryOut& result,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
ring_identifier id,
bool reversed, bool append)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
typedef typename geometry::tag<GeometryOut>::type tag_out;
if (id.source_index == 0)
{
convert_ring<tag_out>::apply(result,
get_ring<tag1>::apply(id, geometry1),
append, reversed);
}
else if (id.source_index == 1)
{
convert_ring<tag_out>::apply(result,
get_ring<tag2>::apply(id, geometry2),
append, reversed);
}
else if (id.source_index == 2)
{
convert_ring<tag_out>::apply(result,
get_ring<void>::apply(id, collection),
append, reversed);
}
}
template
<
typename GeometryOut,
typename SelectionMap,
typename Geometry1,
typename Geometry2,
typename RingCollection,
typename OutputIterator
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
OutputIterator out)
{
typedef typename SelectionMap::const_iterator iterator;
for (iterator it = boost::begin(map);
it != boost::end(map);
++it)
{
if (! it->second.discarded
&& it->second.parent.source_index == -1)
{
GeometryOut result;
convert_and_add(result, geometry1, geometry2, collection,
it->first, it->second.reversed, false);
// Add children
for (typename std::vector<ring_identifier>::const_iterator child_it
= it->second.children.begin();
child_it != it->second.children.end();
++child_it)
{
iterator mit = map.find(*child_it);
if (mit != map.end()
&& ! mit->second.discarded)
{
convert_and_add(result, geometry1, geometry2, collection,
*child_it, mit->second.reversed, true);
}
}
*out++ = result;
}
}
return out;
}
template
<
typename GeometryOut,
typename SelectionMap,
typename Geometry,
typename RingCollection,
typename OutputIterator
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry const& geometry,
RingCollection const& collection,
OutputIterator out)
{
Geometry empty;
return add_rings<GeometryOut>(map, geometry, empty, collection, out);
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP

View File

@@ -0,0 +1,53 @@
// 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_APPEND_NO_DUPLICATES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP
#include <boost/range.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename Range, typename Point>
inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
{
if (boost::size(range) == 0
|| force
|| ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
std::cout << " add: ("
<< geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
<< std::endl;
#endif
geometry::append(range, point);
}
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP

View File

@@ -0,0 +1,337 @@
// 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_ASSIGN_PARENTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template
<
typename Item,
typename Geometry1, typename Geometry2,
typename RingCollection
>
static inline bool within_selected_input(Item const& item2, ring_identifier const& ring_id,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
switch (ring_id.source_index)
{
case 0 :
return geometry::within(item2.point,
get_ring<tag1>::apply(ring_id, geometry1));
break;
case 1 :
return geometry::within(item2.point,
get_ring<tag2>::apply(ring_id, geometry2));
break;
case 2 :
return geometry::within(item2.point,
get_ring<void>::apply(ring_id, collection));
break;
}
return false;
}
template <typename Point>
struct ring_info_helper
{
typedef typename geometry::default_area_result<Point>::type area_type;
ring_identifier id;
area_type real_area;
area_type abs_area;
model::box<Point> envelope;
inline ring_info_helper()
: real_area(0), abs_area(0)
{}
inline ring_info_helper(ring_identifier i, area_type a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
struct ring_info_helper_get_box
{
template <typename Box, typename InputItem>
static inline void apply(Box& total, InputItem const& item)
{
geometry::expand(total, item.envelope);
}
};
struct ring_info_helper_ovelaps_box
{
template <typename Box, typename InputItem>
static inline bool apply(Box const& box, InputItem const& item)
{
return ! geometry::detail::disjoint::disjoint_box_box(box, item.envelope);
}
};
template <typename Geometry1, typename Geometry2, typename Collection, typename RingMap>
struct assign_visitor
{
typedef typename RingMap::mapped_type ring_info_type;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
Collection const& m_collection;
RingMap& m_ring_map;
bool m_check_for_orientation;
inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c,
RingMap& map, bool check)
: m_geometry1(g1)
, m_geometry2(g2)
, m_collection(c)
, m_ring_map(map)
, m_check_for_orientation(check)
{}
template <typename Item>
inline void apply(Item const& outer, Item const& inner, bool first = true)
{
if (first && outer.real_area < 0)
{
// Reverse arguments
apply(inner, outer, false);
return;
}
if (outer.real_area > 0)
{
if (inner.real_area < 0 || m_check_for_orientation)
{
ring_info_type& inner_in_map = m_ring_map[inner.id];
if (geometry::within(inner_in_map.point, outer.envelope)
&& within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
)
{
// Only assign parent if that parent is smaller (or if it is the first)
if (inner_in_map.parent.source_index == -1
|| outer.abs_area < inner_in_map.parent_area)
{
inner_in_map.parent = outer.id;
inner_in_map.parent_area = outer.abs_area;
}
}
}
}
}
};
template
<
typename Geometry1, typename Geometry2,
typename RingCollection,
typename RingMap
>
inline void assign_parents(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RingCollection const& collection,
RingMap& ring_map,
bool check_for_orientation = false)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
typedef typename RingMap::mapped_type ring_info_type;
typedef typename ring_info_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef typename RingMap::iterator map_iterator_type;
{
typedef ring_info_helper<point_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
boost::timer timer;
#endif
std::size_t count_total = ring_map.size();
std::size_t count_positive = 0;
std::size_t index_positive = 0; // only used if count_positive>0
std::size_t index = 0;
// Copy to vector (with new approach this might be obsolete as well, using the map directly)
vector_type vector(count_total);
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it, ++index)
{
vector[index] = helper(it->first, it->second.get_area());
helper& item = vector[index];
switch(it->first.source_index)
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
item.envelope);
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
item.envelope);
break;
case 2 :
geometry::envelope(get_ring<void>::apply(it->first, collection),
item.envelope);
break;
}
if (item.real_area > 0)
{
count_positive++;
index_positive = index;
}
}
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << " ap: created helper vector: " << timer.elapsed() << std::endl;
#endif
if (! check_for_orientation)
{
if (count_positive == count_total)
{
// Optimization for only positive rings
// -> no assignment of parents or reversal necessary, ready here.
return;
}
if (count_positive == 1)
{
// Optimization for one outer ring
// -> assign this as parent to all others (all interior rings)
// In unions, this is probably the most occuring case and gives
// a dramatic improvement (factor 5 for star_comb testcase)
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
std::size_t index = 0;
for (vector_iterator_type it = boost::begin(vector);
it != boost::end(vector); ++it, ++index)
{
if (index != index_positive)
{
ring_info_type& inner = ring_map[it->id];
inner.parent = id_of_positive;
outer.children.push_back(it->id);
}
}
return;
}
}
assign_visitor
<
Geometry1, Geometry2,
RingCollection, RingMap
> visitor(geometry1, geometry2, collection, ring_map, check_for_orientation);
geometry::partition
<
box_type, ring_info_helper_get_box, ring_info_helper_ovelaps_box
>::apply(vector, visitor);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << " ap: quadradic loop: " << timer.elapsed() << std::endl;
std::cout << " ap: check_for_orientation " << check_for_orientation << std::endl;
#endif
}
if (check_for_orientation)
{
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
{
if (geometry::math::equals(it->second.get_area(), 0))
{
it->second.discarded = true;
}
else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0)
{
// Discard positive inner ring with parent
it->second.discarded = true;
it->second.parent.source_index = -1;
}
else if (it->second.parent.source_index < 0 && it->second.get_area() < 0)
{
// Reverse negative ring without parent
it->second.reversed = true;
}
}
}
// Assign childlist
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
{
if (it->second.parent.source_index >= 0)
{
ring_map[it->second.parent].children.push_back(it->first);
}
}
}
template
<
typename Geometry,
typename RingCollection,
typename RingMap
>
inline void assign_parents(Geometry const& geometry,
RingCollection const& collection,
RingMap& ring_map)
{
// Call it with an empty geometry
// (ring_map should be empty for source_id==1)
Geometry empty;
assign_parents(geometry, empty, collection, ring_map, true);
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP

View File

@@ -0,0 +1,181 @@
// 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_BACKTRACK_CHECK_SI_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
#include <cstddef>
#include <string>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/core/access.hpp>
# include <boost/geometry/algorithms/detail/has_self_intersections.hpp>
#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT)
# 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 Turns>
inline void clear_visit_info(Turns& turns)
{
typedef typename boost::range_value<Turns>::type tp_type;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
for (typename boost::range_iterator
<
typename tp_type::container_type
>::type op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
++op_it)
{
op_it->visited.clear();
}
it->discarded = false;
}
}
struct backtrack_state
{
bool m_good;
inline backtrack_state() : m_good(true) {}
inline void reset() { m_good = true; }
inline bool good() const { return m_good; }
};
template
<
typename Geometry1,
typename Geometry2
>
class backtrack_check_self_intersections
{
struct state : public backtrack_state
{
bool m_checked;
inline state()
: m_checked()
{}
};
public :
typedef state state_type;
template <typename Operation, typename Rings, typename Turns>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& ,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
state_type& state
)
{
state.m_good = false;
// Check self-intersections and throw exception if appropriate
if (! state.m_checked)
{
state.m_checked = true;
has_self_intersections(geometry1);
has_self_intersections(geometry2);
}
// Make bad output clean
rings.resize(size_at_start);
ring.clear();
// Reject this as a starting point
operation.visited.set_rejected();
// And clear all visit info
clear_visit_info(turns);
}
};
#ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT
template
<
typename Geometry1,
typename Geometry2
>
class backtrack_debug
{
public :
typedef backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
state_type& state
)
{
std::cout << " REJECT " << reason << std::endl;
state.m_good = false;
rings.resize(size_at_start);
ring.clear();
operation.visited.set_rejected();
clear_visit_info(turns);
int c = 0;
for (int i = 0; i < turns.size(); i++)
{
for (int j = 0; j < 2; j++)
{
if (turns[i].operations[j].visited.rejected())
{
c++;
}
}
}
std::cout << "BACKTRACK (" << reason << " )"
<< " " << c << " of " << turns.size() << " rejected"
<< std::endl;
std::cout
<< geometry::wkt(geometry1) << std::endl
<< geometry::wkt(geometry2) << std::endl;
}
};
#endif // BOOST_GEOMETRY_OVERLAY_REPORT_WKT
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP

View File

@@ -0,0 +1,52 @@
// 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_CALCULATE_DISTANCE_POLICY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
#include <boost/geometry/algorithms/comparable_distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
/*!
\brief Policy calculating distance
\details get_turn_info has an optional policy to get some
extra information.
This policy calculates the distance (using default distance strategy)
*/
struct calculate_distance_policy
{
template <typename Point1, typename Point2, typename Info>
static inline void apply(Info& info, Point1 const& p1, Point2 const& p2)
{
info.operations[0].enriched.distance
= geometry::comparable_distance(info.point, p1);
info.operations[1].enriched.distance
= geometry::comparable_distance(info.point, p2);
}
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP

View File

@@ -0,0 +1,172 @@
// 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_CHECK_ENRICH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template<typename Turn>
struct meta_turn
{
int index;
Turn const* turn;
bool handled[2];
inline meta_turn(int i, Turn const& t)
: index(i), turn(&t)
{
handled[0] = false;
handled[1] = false;
}
};
template <typename MetaTurn>
inline void display(MetaTurn const& meta_turn, std::string const& reason = "")
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << meta_turn.index
<< "\tMethods: " << method_char(meta_turn.turn->method)
<< " operations: " << operation_char(meta_turn.turn->operations[0].operation)
<< operation_char(meta_turn.turn->operations[1].operation)
<< " travels to " << meta_turn.turn->operations[0].enriched.travels_to_ip_index
<< " and " << meta_turn.turn->operations[1].enriched.travels_to_ip_index
//<< " -> " << op_index
<< " " << reason
<< std::endl;
#endif
}
template <typename MetaTurns, typename MetaTurn>
inline void check_detailed(MetaTurns& meta_turns, MetaTurn const& meta_turn,
int op_index, int cycle, int start, operation_type for_operation,
bool& error)
{
display(meta_turn);
int const ip_index = meta_turn.turn->operations[op_index].enriched.travels_to_ip_index;
if (ip_index >= 0)
{
bool found = false;
if (ip_index == start)
{
display(meta_turns[ip_index], " FINISH");
return;
}
// check on continuing, or on same-operation-on-same-geometry
if (! meta_turns[ip_index].handled[op_index]
&& (meta_turns[ip_index].turn->operations[op_index].operation == operation_continue
|| meta_turns[ip_index].turn->operations[op_index].operation == for_operation)
)
{
meta_turns[ip_index].handled[op_index] = true;
check_detailed(meta_turns, meta_turns[ip_index], op_index, cycle, start, for_operation, error);
found = true;
}
// check on other geometry
if (! found)
{
int const other_index = 1 - op_index;
if (! meta_turns[ip_index].handled[other_index]
&& meta_turns[ip_index].turn->operations[other_index].operation == for_operation)
{
meta_turns[ip_index].handled[other_index] = true;
check_detailed(meta_turns, meta_turns[ip_index], other_index, cycle, start, for_operation, error);
found = true;
}
}
if (! found)
{
display(meta_turns[ip_index], " STOP");
error = true;
#ifndef BOOST_GEOMETRY_DEBUG_ENRICH
//std::cout << " STOP";
#endif
}
}
}
template <typename TurnPoints>
inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
bool error = false;
int index = 0;
std::vector<meta_turn<turn_point_type> > meta_turns;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it, ++index)
{
meta_turns.push_back(meta_turn<turn_point_type>(index, *it));
}
int cycle = 0;
for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::type
it = boost::begin(meta_turns);
it != boost::end(meta_turns);
++it)
{
if (! (it->turn->blocked() || it->turn->is_discarded()))
{
for (int i = 0 ; i < 2; i++)
{
if (! it->handled[i]
&& it->turn->operations[i].operation == for_operation)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "CYCLE " << cycle << std::endl;
#endif
it->handled[i] = true;
check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error);
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout <<" END CYCLE " << it->index << std::endl;
#endif
}
}
}
}
return error;
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP

View File

@@ -0,0 +1,242 @@
// 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_CLIP_LINESTRING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
#include <boost/range.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
/*!
\brief Strategy: line clipping algorithm after Liang Barsky
\ingroup overlay
\details The Liang-Barsky line clipping algorithm clips a line with a clipping box.
It is slightly adapted in the sense that it returns which points are clipped
\tparam B input box type of clipping box
\tparam P input/output point-type of segments to be clipped
\note The algorithm is currently only implemented for 2D Cartesian points
\note Though it is implemented in namespace strategy, and theoretically another
strategy could be used, it is not (yet) updated to the general strategy concepts,
and not (yet) splitted into a file in folder strategies
\author Barend Gehrels, and the following recourses
- A tutorial: http://www.skytopia.com/project/articles/compsci/clipping.html
- a German applet (link broken): http://ls7-www.cs.uni-dortmund.de/students/projectgroups/acit/lineclip.shtml
*/
template<typename Box, typename Point>
class liang_barsky
{
private:
typedef model::referring_segment<Point> segment_type;
template <typename T>
inline bool check_edge(T const& p, T const& q, T& t1, T& t2) const
{
bool visible = true;
if(p < 0)
{
T const r = q / p;
if (r > t2)
visible = false;
else if (r > t1)
t1 = r;
}
else if(p > 0)
{
T const r = q / p;
if (r < t1)
visible = false;
else if (r < t2)
t2 = r;
}
else
{
if (q < 0)
visible = false;
}
return visible;
}
public:
inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const
{
typedef typename select_coordinate_type<Box, Point>::type coordinate_type;
coordinate_type t1 = 0;
coordinate_type t2 = 1;
coordinate_type const dx = get<1, 0>(s) - get<0, 0>(s);
coordinate_type const dy = get<1, 1>(s) - get<0, 1>(s);
coordinate_type const p1 = -dx;
coordinate_type const p2 = dx;
coordinate_type const p3 = -dy;
coordinate_type const p4 = dy;
coordinate_type const q1 = get<0, 0>(s) - get<min_corner, 0>(b);
coordinate_type const q2 = get<max_corner, 0>(b) - get<0, 0>(s);
coordinate_type const q3 = get<0, 1>(s) - get<min_corner, 1>(b);
coordinate_type const q4 = get<max_corner, 1>(b) - get<0, 1>(s);
if (check_edge(p1, q1, t1, t2) // left
&& check_edge(p2, q2, t1, t2) // right
&& check_edge(p3, q3, t1, t2) // bottom
&& check_edge(p4, q4, t1, t2)) // top
{
sp1_clipped = t1 > 0;
sp2_clipped = t2 < 1;
if (sp2_clipped)
{
set<1, 0>(s, get<0, 0>(s) + t2 * dx);
set<1, 1>(s, get<0, 1>(s) + t2 * dy);
}
if(sp1_clipped)
{
set<0, 0>(s, get<0, 0>(s) + t1 * dx);
set<0, 1>(s, get<0, 1>(s) + t1 * dy);
}
return true;
}
return false;
}
template<typename Linestring, typename OutputIterator>
inline void apply(Linestring& line_out, OutputIterator out) const
{
if (!boost::empty(line_out))
{
*out = line_out;
++out;
geometry::clear(line_out);
}
}
};
}} // namespace strategy::intersection
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersection
{
/*!
\brief Clips a linestring with a box
\details A linestring is intersected (clipped) by the specified box
and the resulting linestring, or pieces of linestrings, are sent to the specified output operator.
\tparam OutputLinestring type of the output linestrings
\tparam OutputIterator an output iterator which outputs linestrings
\tparam Linestring linestring-type, for example a vector of points, matching the output-iterator type,
the points should also match the input-iterator type
\tparam Box box type
\tparam Strategy strategy, a clipping strategy which should implement the methods "clip_segment" and "apply"
*/
template
<
typename OutputLinestring,
typename OutputIterator,
typename Range,
typename Box,
typename Strategy
>
OutputIterator clip_range_with_box(Box const& b, Range const& range,
OutputIterator out, Strategy const& strategy)
{
if (boost::begin(range) == boost::end(range))
{
return out;
}
typedef typename point_type<OutputLinestring>::type point_type;
OutputLinestring line_out;
typedef typename boost::range_iterator<Range const>::type iterator_type;
iterator_type vertex = boost::begin(range);
for(iterator_type previous = vertex++;
vertex != boost::end(range);
++previous, ++vertex)
{
point_type p1, p2;
geometry::convert(*previous, p1);
geometry::convert(*vertex, p2);
// Clip the segment. Five situations:
// 1. Segment is invisible, finish line if any (shouldn't occur)
// 2. Segment is completely visible. Add (p1)-p2 to line
// 3. Point 1 is invisible (clipped), point 2 is visible. Start new line from p1-p2...
// 4. Point 1 is visible, point 2 is invisible (clipped). End the line with ...p2
// 5. Point 1 and point 2 are both invisible (clipped). Start/finish an independant line p1-p2
//
// This results in:
// a. if p1 is clipped, start new line
// b. if segment is partly or completely visible, add the segment
// c. if p2 is clipped, end the line
bool c1 = false;
bool c2 = false;
model::referring_segment<point_type> s(p1, p2);
if (!strategy.clip_segment(b, s, c1, c2))
{
strategy.apply(line_out, out);
}
else
{
// a. If necessary, finish the line and add a start a new one
if (c1)
{
strategy.apply(line_out, out);
}
// b. Add p1 only if it is the first point, then add p2
if (boost::empty(line_out))
{
detail::overlay::append_no_duplicates(line_out, p1, true);
}
detail::overlay::append_no_duplicates(line_out, p2);
// c. If c2 is clipped, finish the line
if (c2)
{
strategy.apply(line_out, out);
}
}
}
// Add last part
strategy.apply(line_out, out);
return out;
}
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP

View File

@@ -0,0 +1,99 @@
// 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_CONVERT_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm/reverse.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/convert.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template<typename Tag>
struct convert_ring
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TAG
, (types<Tag>)
);
};
template<>
struct convert_ring<ring_tag>
{
template<typename Destination, typename Source>
static inline void apply(Destination& destination, Source const& source,
bool append, bool reverse)
{
if (! append)
{
geometry::convert(source, destination);
if (reverse)
{
boost::reverse(destination);
}
}
}
};
template<>
struct convert_ring<polygon_tag>
{
template<typename Destination, typename Source>
static inline void apply(Destination& destination, Source const& source,
bool append, bool reverse)
{
if (! append)
{
geometry::convert(source, exterior_ring(destination));
if (reverse)
{
boost::reverse(exterior_ring(destination));
}
}
else
{
interior_rings(destination).resize(
interior_rings(destination).size() + 1);
geometry::convert(source, interior_rings(destination).back());
if (reverse)
{
boost::reverse(interior_rings(destination).back());
}
}
}
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP

View File

@@ -0,0 +1,295 @@
// 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_COPY_SEGMENT_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
#include <boost/array.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace copy_segments
{
template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point_range
{
typedef typename closeable_view
<
Range const,
closure<Range>::value
>::type cview_type;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
static inline bool apply(Range const& range,
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
int index = seg_id.segment_index;
if (second)
{
index++;
if (index >= boost::size(range))
{
index = 0;
}
}
// Exception?
if (index >= boost::size(range))
{
return false;
}
cview_type cview(range);
rview_type view(cview);
geometry::convert(*(boost::begin(view) + index), point);
return true;
}
};
template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point_polygon
{
static inline bool apply(Polygon const& polygon,
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
// Call ring-version with the right ring
return copy_segment_point_range
<
typename geometry::ring_type<Polygon>::type,
Reverse,
SegmentIdentifier,
PointOut
>::apply
(
seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
: geometry::interior_rings(polygon)[seg_id.ring_index],
seg_id, second,
point
);
}
};
template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point_box
{
static inline bool apply(Box const& box,
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
int index = seg_id.segment_index;
if (second)
{
index++;
}
boost::array<typename point_type<Box>::type, 4> bp;
assign_box_corners_oriented<Reverse>(box, bp);
point = bp[index % 4];
return true;
}
};
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename GeometryIn,
bool Reverse,
typename SegmentIdentifier,
typename PointOut
>
struct copy_segment_point
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<GeometryIn>)
);
};
template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
: detail::copy_segments::copy_segment_point_range
<
LineString, Reverse, SegmentIdentifier, PointOut
>
{};
template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
: detail::copy_segments::copy_segment_point_range
<
Ring, Reverse, SegmentIdentifier, PointOut
>
{};
template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
: detail::copy_segments::copy_segment_point_polygon
<
Polygon, Reverse, SegmentIdentifier, PointOut
>
{};
template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
: detail::copy_segments::copy_segment_point_box
<
Box, Reverse, SegmentIdentifier, PointOut
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Helper function, copies a point from a segment
\ingroup overlay
*/
template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
inline bool copy_segment_point(Geometry const& geometry,
SegmentIdentifier const& seg_id, bool second,
PointOut& point_out)
{
concept::check<Geometry const>();
return dispatch::copy_segment_point
<
typename tag<Geometry>::type,
Geometry,
Reverse,
SegmentIdentifier,
PointOut
>::apply(geometry, seg_id, second, point_out);
}
/*!
\brief Helper function, to avoid the same construct several times,
copies a point, based on a source-index and two geometries
\ingroup overlay
*/
template
<
bool Reverse1, bool Reverse2,
typename Geometry1, typename Geometry2,
typename SegmentIdentifier,
typename PointOut
>
inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
SegmentIdentifier const& seg_id, bool second,
PointOut& point_out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
if (seg_id.source_index == 0)
{
return dispatch::copy_segment_point
<
typename tag<Geometry1>::type,
Geometry1,
Reverse1,
SegmentIdentifier,
PointOut
>::apply(geometry1, seg_id, second, point_out);
}
else if (seg_id.source_index == 1)
{
return dispatch::copy_segment_point
<
typename tag<Geometry2>::type,
Geometry2,
Reverse2,
SegmentIdentifier,
PointOut
>::apply(geometry2, seg_id, second, point_out);
}
// Exception?
return false;
}
/*!
\brief Helper function, to avoid the same construct several times,
copies a point, based on a source-index and two geometries
\ingroup overlay
*/
template
<
bool Reverse1, bool Reverse2,
typename Geometry1, typename Geometry2,
typename SegmentIdentifier,
typename PointOut
>
inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
SegmentIdentifier const& seg_id,
PointOut& point1, PointOut& point2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, false, point1)
&& copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, true, point2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP

View File

@@ -0,0 +1,278 @@
// 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_COPY_SEGMENTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
#include <boost/array.hpp>
#include <boost/mpl/assert.hpp>
#include <vector>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace copy_segments
{
template
<
typename Ring,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments_ring
{
typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename boost::range_iterator<rview_type const>::type iterator;
typedef geometry::ever_circling_iterator<iterator> ec_iterator;
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id, int to_index,
RangeOut& current_output)
{
cview_type cview(ring);
rview_type view(cview);
// The problem: sometimes we want to from "3" to "2"
// -> end = "3" -> end == begin
// This is not convenient with iterators.
// So we use the ever-circling iterator and determine when to step out
int const from_index = seg_id.segment_index + 1;
// Sanity check
BOOST_ASSERT(from_index < boost::size(view));
ec_iterator it(boost::begin(view), boost::end(view),
boost::begin(view) + from_index);
// [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
// [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
// [1..1], travel the whole ring round
typedef typename boost::range_difference<Ring>::type size_type;
size_type const count = from_index <= to_index
? to_index - from_index + 1
: boost::size(view) - from_index + to_index + 1;
for (size_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_duplicates(current_output, *it);
}
}
};
template
<
typename Polygon,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments_polygon
{
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id, int to_index,
RangeOut& current_output)
{
// Call ring-version with the right ring
copy_segments_ring
<
typename geometry::ring_type<Polygon>::type,
Reverse,
SegmentIdentifier,
RangeOut
>::apply
(
seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
: geometry::interior_rings(polygon)[seg_id.ring_index],
seg_id, to_index,
current_output
);
}
};
template
<
typename Box,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments_box
{
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id, int to_index,
RangeOut& current_output)
{
int index = seg_id.segment_index + 1;
BOOST_ASSERT(index < 5);
int const count = index <= to_index
? to_index - index + 1
: 5 - index + to_index + 1;
// Create array of points, the fifth one closes it
boost::array<typename point_type<Box>::type, 5> bp;
assign_box_corners_oriented<Reverse>(box, bp);
bp[4] = bp[0];
// (possibly cyclic) copy to output
// (see comments in ring-version)
for (int i = 0; i < count; i++, index++)
{
detail::overlay::append_no_duplicates(current_output, bp[index % 5]);
}
}
};
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename GeometryIn,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<GeometryIn>)
);
};
template
<
typename Ring,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_ring
<
Ring, Reverse, SegmentIdentifier, RangeOut
>
{};
template
<
typename Polygon,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_polygon
<
Polygon, Reverse, SegmentIdentifier, RangeOut
>
{};
template
<
typename Box,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_box
<
Box, Reverse, SegmentIdentifier, RangeOut
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Copy segments from a geometry, starting with the specified segment (seg_id)
until the specified index (to_index)
\ingroup overlay
*/
template
<
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id, int to_index,
RangeOut& range_out)
{
concept::check<Geometry const>();
dispatch::copy_segments
<
typename tag<Geometry>::type,
Geometry,
Reverse,
SegmentIdentifier,
RangeOut
>::apply(geometry, seg_id, to_index, range_out);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP

View File

@@ -0,0 +1,64 @@
// 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_DEBUG_TURN_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/visit_info.hpp>
namespace boost { namespace geometry
{
inline char method_char(detail::overlay::method_type const& method)
{
using namespace detail::overlay;
switch(method)
{
case method_none : return '-';
case method_disjoint : return 'd';
case method_crosses : return 'i';
case method_touch : return 't';
case method_touch_interior : return 'm';
case method_collinear : return 'c';
case method_equal : return 'e';
default : return '?';
}
}
inline char operation_char(detail::overlay::operation_type const& operation)
{
using namespace detail::overlay;
switch(operation)
{
case operation_none : return '-';
case operation_union : return 'u';
case operation_intersection : return 'i';
case operation_blocked : return 'x';
case operation_continue : return 'c';
default : return '?';
}
}
inline char visited_char(detail::overlay::visit_info const& v)
{
if (v.rejected()) return 'R';
if (v.started()) return 's';
if (v.visited()) return 'v';
if (v.none()) return '-';
if (v.finished()) return 'f';
return '?';
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP

View File

@@ -0,0 +1,531 @@
// 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_ENRICH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
#include <cstddef>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <iostream>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/domains/gis/io/wkt/wkt.hpp>
# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
#endif
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// Wraps "turn_operation" from turn_info.hpp,
// giving it extra information
template <typename TurnOperation>
struct indexed_turn_operation
{
typedef TurnOperation type;
int index;
int operation_index;
bool discarded;
TurnOperation subject;
inline indexed_turn_operation(int i, int oi, TurnOperation const& s)
: index(i)
, operation_index(oi)
, discarded(false)
, subject(s)
{}
};
template <typename IndexedTurnOperation>
struct remove_discarded
{
inline bool operator()(IndexedTurnOperation const& operation) const
{
return operation.discarded;
}
};
template
<
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Strategy
>
struct sort_on_segment_and_distance
{
inline sort_on_segment_and_distance(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, Strategy const& strategy
, bool* clustered)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_strategy(strategy)
, m_clustered(clustered)
{
}
private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
mutable bool* m_clustered;
inline bool consider_relative_order(Indexed const& left,
Indexed const& right) const
{
typedef typename geometry::point_type<Geometry1>::type point_type;
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.other_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
int const order = get_relative_order
<
point_type
>::apply(pi, pj,ri, rj, si, sj);
//debug("r/o", order == -1);
return order == -1;
}
public :
// Note that left/right do NOT correspond to m_geometry1/m_geometry2
// but to the "indexed_turn_operation"
inline bool operator()(Indexed const& left, Indexed const& right) const
{
segment_identifier const& sl = left.subject.seg_id;
segment_identifier const& sr = right.subject.seg_id;
if (sl == sr
&& geometry::math::equals(left.subject.enriched.distance
, right.subject.enriched.distance))
{
// Both left and right are located on the SAME segment.
// First check "real" intersection (crosses)
// -> distance zero due to precision, solve it by sorting
if (m_turn_points[left.index].method == method_crosses
&& m_turn_points[right.index].method == method_crosses)
{
return consider_relative_order(left, right);
}
// If that is not the case, cluster it later on.
// Indicate that this is necessary.
*m_clustered = true;
return left.index < right.index;
}
return sl == sr
? left.subject.enriched.distance < right.subject.enriched.distance
: sl < sr;
}
};
template<typename Turns, typename Operations>
inline void update_discarded(Turns& turn_points, Operations& operations)
{
// Vice-versa, set discarded to true for discarded operations;
// AND set discarded points to true
for (typename boost::range_iterator<Operations>::type it = boost::begin(operations);
it != boost::end(operations);
++it)
{
if (turn_points[it->index].discarded)
{
it->discarded = true;
}
else if (it->discarded)
{
turn_points[it->index].discarded = true;
}
}
}
// Sorts IP-s of this ring on segment-identifier, and if on same segment,
// on distance.
// Then assigns for each IP which is the next IP on this segment,
// plus the vertex-index to travel to, plus the next IP
// (might be on another segment)
template
<
typename IndexType,
bool Reverse1, bool Reverse2,
typename Container,
typename TurnPoints,
typename Geometry1, typename Geometry2,
typename Strategy
>
inline void enrich_sort(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
bool clustered = false;
std::sort(boost::begin(operations),
boost::end(operations),
sort_on_segment_and_distance
<
TurnPoints,
IndexType,
Geometry1, Geometry2,
Reverse1, Reverse2,
Strategy
>(turn_points, geometry1, geometry2, strategy, &clustered));
// DONT'T discard xx / (for union) ix / ii / (for intersection) ux / uu here
// It would give way to "lonely" ui turn points, traveling all
// the way round. See #105
if (clustered)
{
typedef typename boost::range_iterator<Container>::type nc_iterator;
nc_iterator it = boost::begin(operations);
nc_iterator begin_cluster = boost::end(operations);
for (nc_iterator prev = it++;
it != boost::end(operations);
prev = it++)
{
operations_type& prev_op = turn_points[prev->index]
.operations[prev->operation_index];
operations_type& op = turn_points[it->index]
.operations[it->operation_index];
if (prev_op.seg_id == op.seg_id
&& (turn_points[prev->index].method != method_crosses
|| turn_points[it->index].method != method_crosses)
&& geometry::math::equals(prev_op.enriched.distance,
op.enriched.distance))
{
if (begin_cluster == boost::end(operations))
{
begin_cluster = prev;
}
}
else if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
for_operation, geometry1, geometry2, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
for_operation, geometry1, geometry2, strategy);
}
}
update_discarded(turn_points, operations);
}
template
<
typename IndexType,
typename Container,
typename TurnPoints
>
inline void enrich_discard(Container& operations, TurnPoints& turn_points)
{
update_discarded(turn_points, operations);
// Then delete discarded operations from vector
remove_discarded<IndexType> predicate;
operations.erase(
std::remove_if(boost::begin(operations),
boost::end(operations),
predicate),
boost::end(operations));
}
template
<
typename IndexType,
typename Container,
typename TurnPoints,
typename Geometry1,
typename Geometry2,
typename Strategy
>
inline void enrich_assign(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
typedef typename boost::range_iterator<Container const>::type iterator_type;
if (operations.size() > 0)
{
// Assign travel-to-vertex/ip index for each turning point.
// Because IP's are circular, PREV starts at the very last one,
// being assigned from the first one.
// "next ip on same segment" should not be considered circular.
bool first = true;
iterator_type it = boost::begin(operations);
for (iterator_type prev = it + (boost::size(operations) - 1);
it != boost::end(operations);
prev = it++)
{
operations_type& prev_op
= turn_points[prev->index].operations[prev->operation_index];
operations_type& op
= turn_points[it->index].operations[it->operation_index];
prev_op.enriched.travels_to_ip_index
= it->index;
prev_op.enriched.travels_to_vertex_index
= it->subject.seg_id.segment_index;
if (! first
&& prev_op.seg_id.segment_index == op.seg_id.segment_index)
{
prev_op.enriched.next_ip_index = it->index;
}
first = false;
}
}
// DEBUG
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
{
for (iterator_type it = boost::begin(operations);
it != boost::end(operations);
++it)
{
operations_type& op = turn_points[it->index]
.operations[it->operation_index];
std::cout << it->index
<< " meth: " << method_char(turn_points[it->index].method)
<< " seg: " << op.seg_id
<< " dst: " << boost::numeric_cast<double>(op.enriched.distance)
<< " op: " << operation_char(turn_points[it->index].operations[0].operation)
<< operation_char(turn_points[it->index].operations[1].operation)
<< " dsc: " << (turn_points[it->index].discarded ? "T" : "F")
<< " ->vtx " << op.enriched.travels_to_vertex_index
<< " ->ip " << op.enriched.travels_to_ip_index
<< " ->nxt ip " << op.enriched.next_ip_index
//<< " vis: " << visited_char(op.visited)
<< std::endl;
;
}
}
#endif
// END DEBUG
}
template <typename IndexedType, typename TurnPoints, typename MappedVector>
inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vector)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
int index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it, ++index)
{
// Add operations on this ring, but skip discarded ones
if (! it->discarded)
{
int op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
++op_it, ++op_index)
{
// We should NOT skip blocked operations here
// because they can be relevant for "the other side"
// NOT if (op_it->operation != operation_blocked)
ring_identifier ring_id
(
op_it->seg_id.source_index,
op_it->seg_id.multi_index,
op_it->seg_id.ring_index
);
mapped_vector[ring_id].push_back
(
IndexedType(index, op_index, *op_it)
);
}
}
}
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
/*!
\brief All intersection points are enriched with successor information
\ingroup overlay
\tparam TurnPoints type of intersection container
(e.g. vector of "intersection/turn point"'s)
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy side strategy type
\param turn_points container containing intersectionpoints
\param for_operation operation_type (union or intersection)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy strategy
*/
template
<
bool Reverse1, bool Reverse2,
typename TurnPoints,
typename Geometry1, typename Geometry2,
typename Strategy
>
inline void enrich_intersection_points(TurnPoints& turn_points,
detail::overlay::operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::turn_operation_type turn_operation_type;
typedef detail::overlay::indexed_turn_operation
<
turn_operation_type
> indexed_turn_operation;
typedef std::map
<
ring_identifier,
std::vector<indexed_turn_operation>
> mapped_vector_type;
// DISCARD ALL UU
// #76 is the reason that this is necessary...
// With uu, at all points there is the risk that rings are being traversed twice or more.
// Without uu, all rings having only uu will be untouched and gathered by assemble
for (typename boost::range_iterator<TurnPoints>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it)
{
if (it->both(detail::overlay::operation_union))
{
it->discarded = true;
}
}
// Create a map of vectors of indexed operation-types to be able
// to sort intersection points PER RING
mapped_vector_type mapped_vector;
detail::overlay::create_map<indexed_turn_operation>(turn_points, mapped_vector);
// No const-iterator; contents of mapped copy is temporary,
// and changed by enrich
for (typename mapped_vector_type::iterator mit
= mapped_vector.begin();
mit != mapped_vector.end();
++mit)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-sort Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
geometry1, geometry2, strategy);
}
for (typename mapped_vector_type::iterator mit
= mapped_vector.begin();
mit != mapped_vector.end();
++mit)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-discard Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_discard<indexed_turn_operation>(mit->second, turn_points);
}
for (typename mapped_vector_type::iterator mit
= mapped_vector.begin();
mit != mapped_vector.end();
++mit)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-assign Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_assign<indexed_turn_operation>(mit->second, turn_points, for_operation,
geometry1, geometry2, strategy);
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
//detail::overlay::check_graph(turn_points, for_operation);
#endif
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP

View File

@@ -0,0 +1,76 @@
// 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_ENRICHMENT_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
/*!
\brief Keeps info to enrich intersection info (per source)
\details Class to keep information necessary for traversal phase (a phase
of the overlay process). The information is gathered during the
enrichment phase
*/
template<typename P>
struct enrichment_info
{
typedef typename strategy::distance::services::return_type
<
typename strategy::distance::services::comparable_type
<
typename strategy::distance::services::default_strategy
<
point_tag,
P
>::type
>::type
>::type distance_type;
inline enrichment_info()
: travels_to_vertex_index(-1)
, travels_to_ip_index(-1)
, next_ip_index(-1)
, distance(distance_type())
{}
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
int travels_to_vertex_index;
// same but now IP index, so "next IP index" but not on THIS segment
int travels_to_ip_index;
// index of next IP on this segment, -1 if there is no one
int next_ip_index;
distance_type distance; // distance-measurement from segment.first to IP
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP

View File

@@ -0,0 +1,146 @@
// 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_GET_INTERSECTION_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP
#include <cstddef>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_intersection_points
{
template
<
typename Point1,
typename Point2,
typename TurnInfo
>
struct get_turn_without_info
{
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
> si;
typedef typename si::segment_intersection_strategy_type strategy;
template <typename OutputIterator>
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo const& tp_model,
OutputIterator out)
{
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
//
typename strategy::return_type result = strategy::apply(p1, q1);
for (std::size_t i = 0; i < result.template get<0>().count; i++)
{
TurnInfo tp;
geometry::convert(result.template get<0>().intersections[i], tp.point);
*out++ = tp;
}
return out;
}
};
}} // namespace detail::get_intersection_points
#endif // DOXYGEN_NO_DETAIL
template
<
typename Geometry1,
typename Geometry2,
typename Turns
>
inline void get_intersection_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Turns& turns)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
typedef detail::get_intersection_points::get_turn_without_info
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
typename boost::range_value<Turns>::type
> TurnPolicy;
typedef typename strategy_intersection
<
typename cs_tag<Geometry1>::type,
Geometry1,
Geometry2,
typename boost::range_value<Turns>::type
>::segment_intersection_strategy_type segment_intersection_strategy_type;
detail::get_turns::no_interrupt_policy interrupt_policy;
boost::mpl::if_c
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::get_turns_reversed
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
Turns, TurnPolicy,
//segment_intersection_strategy_type,
detail::get_turns::no_interrupt_policy
>,
dispatch::get_turns
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
Turns, TurnPolicy,
//segment_intersection_strategy_type,
detail::get_turns::no_interrupt_policy
>
>::type::apply(
0, geometry1,
1, geometry2,
turns, interrupt_policy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP

View File

@@ -0,0 +1,108 @@
// 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_GET_RELATIVE_ORDER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/strategies/intersection.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
/*!
\brief Get relative order
\details Can indicate which of two segments R and S,
both crossing a common segment P, comes first.
If the two segments cross P very close (e.g. in a spike),
the distance between the intersection points can be zero,
but we still need to know which comes first.
Therefore, it is useful that using sides we are able to discover this.
*/
template <typename Point1>
struct get_relative_order
{
typedef strategy_intersection
<
typename cs_tag<Point1>::type,
Point1,
Point1,
Point1
> si;
typedef typename si::side_strategy_type strategy;
template <typename Point>
static inline int value_via_product(Point const& ti, Point const& tj,
Point const& ui, Point const& uj, int factor)
{
int const side_ti_u = strategy::apply(ti, tj, ui);
int const side_tj_u = strategy::apply(ti, tj, uj);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
std::cout << (factor == 1 ? " r//s " : " s//r ")
<< side_ti_u << " / " << side_tj_u;
#endif
return side_ti_u * side_tj_u >= 0
? factor * (side_ti_u != 0 ? side_ti_u : side_tj_u)
: 0;
}
static inline int apply(
Point1 const& pi, Point1 const& pj,
Point1 const& ri, Point1 const& rj,
Point1 const& si, Point1 const& sj)
{
int const side_ri_p = strategy::apply(pi, pj, ri);
int const side_si_p = strategy::apply(pi, pj, si);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
int const side_rj_p = strategy::apply(pi, pj, rj);
int const side_sj_p = strategy::apply(pi, pj, sj);
std::cout << "r//p: " << side_ri_p << " / " << side_rj_p;
std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
#endif
int value = value_via_product(si, sj, ri, rj, 1);
if (value == 0)
{
value = value_via_product(ri, rj, si, sj, -1);
}
int const order = side_ri_p * side_ri_p * side_si_p * value;
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
std::cout
<< " o: " << order
<< std::endl << std::endl;
#endif
return order;
}
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP

View File

@@ -0,0 +1,102 @@
// 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_GET_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template<typename Tag>
struct get_ring
{};
// A container of rings (multi-ring but that does not exist)
// gets the "void" tag and is dispatched here.
template<>
struct get_ring<void>
{
template<typename Container>
static inline typename boost::range_value<Container>::type const&
apply(ring_identifier const& id, Container const& container)
{
return container[id.multi_index];
}
};
template<>
struct get_ring<ring_tag>
{
template<typename Ring>
static inline Ring const& apply(ring_identifier const& , Ring const& ring)
{
return ring;
}
};
template<>
struct get_ring<box_tag>
{
template<typename Box>
static inline Box const& apply(ring_identifier const& ,
Box const& box)
{
return box;
}
};
template<>
struct get_ring<polygon_tag>
{
template<typename Polygon>
static inline typename ring_return_type<Polygon const>::type const apply(
ring_identifier const& id,
Polygon const& polygon)
{
BOOST_ASSERT
(
id.ring_index >= -1
&& id.ring_index < boost::size(interior_rings(polygon))
);
return id.ring_index < 0
? exterior_ring(polygon)
: interior_rings(polygon)[id.ring_index];
}
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP

View File

@@ -0,0 +1,897 @@
// 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_GET_TURN_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
#include <boost/assert.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
struct base_turn_handler
{
// Returns true if both sides are opposite
static inline bool opposite(int side1, int side2)
{
// We cannot state side1 == -side2, because 0 == -0
// So either side1*side2==-1 or side1==-side2 && side1 != 0
return side1 * side2 == -1;
}
// Same side of a segment (not being 0)
static inline bool same(int side1, int side2)
{
return side1 * side2 == 1;
}
// Both continue
template <typename TurnInfo>
static inline void both(TurnInfo& ti, operation_type const op)
{
ti.operations[0].operation = op;
ti.operations[1].operation = op;
}
// If condition, first union/second intersection, else vice versa
template <typename TurnInfo>
static inline void ui_else_iu(bool condition, TurnInfo& ti)
{
ti.operations[0].operation = condition
? operation_union : operation_intersection;
ti.operations[1].operation = condition
? operation_intersection : operation_union;
}
// If condition, both union, else both intersection
template <typename TurnInfo>
static inline void uu_else_ii(bool condition, TurnInfo& ti)
{
both(ti, condition ? operation_union : operation_intersection);
}
};
template
<
typename TurnInfo,
typename SideStrategy
>
struct touch_interior : public base_turn_handler
{
// Index: 0, P is the interior, Q is touching and vice versa
template
<
int Index,
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_touch_interior;
geometry::convert(intersection_info.intersections[0], ti.point);
// Both segments of q touch segment p somewhere in its interior
// 1) We know: if q comes from LEFT or RIGHT
// (i.e. dir_info.sides.get<Index,0>() == 1 or -1)
// 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
// and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
static int const index_p = Index;
static int const index_q = 1 - Index;
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
int const side_qk_p = SideStrategy::apply(pi, pj, qk);
if (side_qi_p == -side_qk_p)
{
// Q crosses P from left->right or from right->left (test "ML1")
// Union: folow P (left->right) or Q (right->left)
// Intersection: other turn
int index = side_qk_p == -1 ? index_p : index_q;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
return;
}
int const side_qk_q = SideStrategy::apply(qi, qj, qk);
if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
{
// Q turns left on the right side of P (test "MR3")
// Both directions for "intersection"
both(ti, operation_intersection);
}
else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
{
// Q turns right on the left side of P (test "ML3")
// Union: take both operation
// Intersection: skip
both(ti, operation_union);
}
else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
{
// Q turns left on the left side of P (test "ML2")
// or Q turns right on the right side of P (test "MR2")
// Union: take left turn (Q if Q turns left, P if Q turns right)
// Intersection: other turn
int index = side_qk_q == 1 ? index_q : index_p;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
}
else if (side_qk_p == 0)
{
// Q intersects on interior of P and continues collinearly
if (side_qk_q == side_qi_p)
{
// Collinearly in the same direction
// (Q comes from left of P and turns left,
// OR Q comes from right of P and turns right)
// Omit intersection point.
// Union: just continue
// Intersection: just continue
both(ti, operation_continue);
}
else
{
// Opposite direction, which is never travelled.
// If Q turns left, P continues for intersection
// If Q turns right, P continues for union
ti.operations[Index].operation = side_qk_q == 1
? operation_intersection
: operation_union;
ti.operations[1 - Index].operation = operation_blocked;
}
}
else
{
// Should not occur!
ti.method = method_error;
}
}
};
template
<
typename TurnInfo,
typename SideStrategy
>
struct touch : public base_turn_handler
{
static inline bool between(int side1, int side2, int turn)
{
return side1 == side2 && ! opposite(side1, turn);
}
/*static inline void block_second(bool block, TurnInfo& ti)
{
if (block)
{
ti.operations[1].operation = operation_blocked;
}
}*/
template
<
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_touch;
geometry::convert(intersection_info.intersections[0], ti.point);
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
int const side_qk_p1 = SideStrategy::apply(pi, pj, qk);
// If Qi and Qk are both at same side of Pi-Pj,
// or collinear (so: not opposite sides)
if (! opposite(side_qi_p1, side_qk_p1))
{
int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
int const side_pk_p = SideStrategy::apply(pi, pj, pk);
int const side_qk_q = SideStrategy::apply(qi, qj, qk);
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
&& ! same(side_qi_p1, side_qk_q);
// If Pk at same side as Qi/Qk
// (the "or" is for collinear case)
// or Q is fully collinear && P turns not to left
if (side_pk_p == side_qi_p1
|| side_pk_p == side_qk_p1
|| (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)
)
{
// Collinear -> lines join, continue
// (#BRL2)
if (side_pk_q2 == 0 && ! block_q)
{
both(ti, operation_continue);
return;
}
int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
// Collinear opposite case -> block P
// (#BRL4, #BLR8)
if (side_pk_q1 == 0)
{
ti.operations[0].operation = operation_blocked;
// Q turns right -> union (both independant),
// Q turns left -> intersection
ti.operations[1].operation = block_q ? operation_blocked
: q_turns_left ? operation_intersection
: operation_union;
return;
}
// Pk between Qi and Qk
// (#BRL3, #BRL7)
if (between(side_pk_q1, side_pk_q2, side_qk_q))
{
ui_else_iu(q_turns_left, ti);
if (block_q)
{
ti.operations[1].operation = operation_blocked;
}
//block_second(block_q, ti);
return;
}
// Pk between Qk and P, so left of Qk (if Q turns right) and vv
// (#BRL1)
if (side_pk_q2 == -side_qk_q)
{
ui_else_iu(! q_turns_left, ti);
return;
}
//
// (#BRL5, #BRL9)
if (side_pk_q1 == -side_qk_q)
{
uu_else_ii(! q_turns_left, ti);
if (block_q)
{
ti.operations[1].operation = operation_blocked;
}
//block_second(block_q, ti);
return;
}
}
else
{
// Pk at other side than Qi/Pk
int const side_qk_q = SideStrategy::apply(qi, qj, qk);
bool const q_turns_left = side_qk_q == 1;
ti.operations[0].operation = q_turns_left
? operation_intersection
: operation_union;
ti.operations[1].operation = block_q
? operation_blocked
: side_qi_p1 == 1 || side_qk_p1 == 1
? operation_union
: operation_intersection;
return;
}
}
else
{
// From left to right or from right to left
int const side_pk_p = SideStrategy::apply(pi, pj, pk);
bool const right_to_left = side_qk_p1 == 1;
// If p turns into direction of qi (1,2)
if (side_pk_p == side_qi_p1)
{
int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
// Collinear opposite case -> block P
if (side_pk_q1 == 0)
{
ti.operations[0].operation = operation_blocked;
ti.operations[1].operation = right_to_left
? operation_union : operation_intersection;
return;
}
if (side_pk_q1 == side_qk_p1)
{
uu_else_ii(right_to_left, ti);
return;
}
}
// If p turns into direction of qk (4,5)
if (side_pk_p == side_qk_p1)
{
int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
// Collinear case -> lines join, continue
if (side_pk_q2 == 0)
{
both(ti, operation_continue);
return;
}
if (side_pk_q2 == side_qk_p1)
{
ui_else_iu(right_to_left, ti);
return;
}
}
// otherwise (3)
ui_else_iu(! right_to_left, ti);
return;
}
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
// Normally a robustness issue.
// TODO: more research if still occuring
std::cout << "Not yet handled" << std::endl
<< "pi " << get<0>(pi) << " , " << get<1>(pi)
<< " pj " << get<0>(pj) << " , " << get<1>(pj)
<< " pk " << get<0>(pk) << " , " << get<1>(pk)
<< std::endl
<< "qi " << get<0>(qi) << " , " << get<1>(qi)
<< " qj " << get<0>(qj) << " , " << get<1>(qj)
<< " qk " << get<0>(qk) << " , " << get<1>(qk)
<< std::endl;
#endif
}
};
template
<
typename TurnInfo,
typename SideStrategy
>
struct equal : public base_turn_handler
{
template
<
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_equal;
// Copy the SECOND intersection point
geometry::convert(intersection_info.intersections[1], ti.point);
int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
int const side_pk_p = SideStrategy::apply(pi, pj, pk);
int const side_qk_p = SideStrategy::apply(pi, pj, qk);
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
// The second condition checks if they do not continue
// oppositely
if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
{
both(ti, operation_continue);
return;
}
// If they turn to same side (not opposite sides)
if (! opposite(side_pk_p, side_qk_p))
{
int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
// If pk is left of q2 or collinear: p: union, q: intersection
ui_else_iu(side_pk_q2 != -1, ti);
}
else
{
// They turn opposite sides. If p turns left (or collinear),
// p: union, q: intersection
ui_else_iu(side_pk_p != -1, ti);
}
}
};
template
<
typename TurnInfo,
typename SideStrategy
>
struct collinear : public base_turn_handler
{
/*
arrival P pk//p1 qk//q1 product* case result
1 1 1 CLL1 ui
-1 1 -1 CLL2 iu
1 1 1 CLR1 ui
-1 -1 1 CLR2 ui
1 -1 -1 CRL1 iu
-1 1 -1 CRL2 iu
1 -1 -1 CRR1 iu
-1 -1 1 CRR2 ui
1 0 0 CC1 cc
-1 0 0 CC2 cc
*product = arrival * (pk//p1 or qk//q1)
Stated otherwise:
- if P arrives: look at turn P
- if Q arrives: look at turn Q
- if P arrives and P turns left: union for P
- if P arrives and P turns right: intersection for P
- if Q arrives and Q turns left: union for Q (=intersection for P)
- if Q arrives and Q turns right: intersection for Q (=union for P)
*/
template
<
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_collinear;
geometry::convert(intersection_info.intersections[1], ti.point);
int const arrival = dir_info.arrival[0];
// Should not be 0, this is checked before
BOOST_ASSERT(arrival != 0);
// If p arrives, use p, else use q
int const side_p_or_q = arrival == 1
? SideStrategy::apply(pi, pj, pk)
: SideStrategy::apply(qi, qj, qk)
;
// See comments above,
// resulting in a strange sort of mathematic rule here:
// The arrival-info multiplied by the relevant side
// delivers a consistent result.
int const product = arrival * side_p_or_q;
if(product == 0)
{
both(ti, operation_continue);
}
else
{
ui_else_iu(product == 1, ti);
}
}
};
template
<
typename TurnInfo,
typename SideStrategy,
typename AssignPolicy
>
struct collinear_opposite : public base_turn_handler
{
private :
/*
arrival P arrival Q pk//p1 qk//q1 case result2 result
--------------------------------------------------------------
1 1 1 -1 CLO1 ix xu
1 1 1 0 CLO2 ix (xx)
1 1 1 1 CLO3 ix xi
1 1 0 -1 CCO1 (xx) xu
1 1 0 0 CCO2 (xx) (xx)
1 1 0 1 CCO3 (xx) xi
1 1 -1 -1 CRO1 ux xu
1 1 -1 0 CRO2 ux (xx)
1 1 -1 1 CRO3 ux xi
-1 1 -1 CXO1 xu
-1 1 0 CXO2 (xx)
-1 1 1 CXO3 xi
1 -1 1 CXO1 ix
1 -1 0 CXO2 (xx)
1 -1 -1 CXO3 ux
*/
template
<
int Index,
typename Point,
typename IntersectionInfo
>
static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
int const side_rk_r = SideStrategy::apply(ri, rj, rk);
switch(side_rk_r)
{
case 1 :
// Turning left on opposite collinear: intersection
tp.operations[Index].operation = operation_intersection;
break;
case -1 :
// Turning right on opposite collinear: union
tp.operations[Index].operation = operation_union;
break;
case 0 :
// No turn on opposite collinear: block, do not traverse
// But this "xx" is ignored here, it is useless to include
// two operation blocked, so the whole point does not need
// to be generated.
// So return false to indicate nothing is to be done.
return false;
}
// The other direction is always blocked when collinear opposite
tp.operations[1 - Index].operation = operation_blocked;
// If P arrives within Q, set info on P (which is done above, index=0),
// this turn-info belongs to the second intersection point, index=1
// (see e.g. figure CLO1)
geometry::convert(intersection_info.intersections[1 - Index], tp.point);
return true;
}
public:
template
<
typename Point1,
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
// Opposite collinear can deliver 2 intersection points,
TurnInfo const& tp_model,
OutputIterator& out,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
/*
std::cout << "arrivals: "
<< dir_info.arrival[0]
<< "/" << dir_info.arrival[1]
<< std::endl;
*/
TurnInfo tp = tp_model;
tp.method = method_collinear;
// If P arrives within Q, there is a turn dependant on P
if (dir_info.arrival[0] == 1
&& set_tp<0>(pi, pj, pk, tp, intersection_info))
{
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependant on Q
if (dir_info.arrival[1] == 1
&& set_tp<1>(qi, qj, qk, tp, intersection_info))
{
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
}
};
template
<
typename TurnInfo,
typename SideStrategy
>
struct crosses : public base_turn_handler
{
template
<
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_crosses;
geometry::convert(intersection_info.intersections[0], ti.point);
// In all casees:
// If Q crosses P from left to right
// Union: take P
// Intersection: take Q
// Otherwise: vice versa
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
int const index = side_qi_p1 == 1 ? 0 : 1;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
}
};
/*!
\brief Policy doing nothing
\details get_turn_info can have an optional policy to get/assign some
extra information. By default it does not, and this class
is that default.
*/
struct assign_null_policy
{
template <typename Point1, typename Point2, typename Info>
static inline void apply(Info& info, Point1 const& p1, Point2 const& p2)
{}
};
/*!
\brief Turn information: intersection point, method, and turn information
\details Information necessary for traversal phase (a phase
of the overlay process). The information is gathered during the
get_turns (segment intersection) phase.
\tparam Point1 point type of first segment
\tparam Point2 point type of second segment
\tparam TurnInfo type of class getting intersection and turn info
\tparam AssignPolicy policy to assign extra info,
e.g. to calculate distance from segment's first points
to intersection points
*/
template
<
typename Point1,
typename Point2,
typename TurnInfo,
typename AssignPolicy = assign_null_policy
>
struct get_turn_info
{
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
> si;
typedef typename si::segment_intersection_strategy_type strategy;
template <typename OutputIterator>
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
TurnInfo const& tp_model,
OutputIterator out)
{
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
typename strategy::return_type result = strategy::apply(p1, q1);
char const method = result.template get<1>().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
// Select method and apply
switch(method)
{
case 'a' :
case 'f' :
case 's' :
case 'd' :
break;
case 'm' :
{
typedef touch_interior
<
TurnInfo,
typename si::side_strategy_type
> policy;
// If Q (1) arrives (1)
if (result.template get<1>().arrival[1] == 1)
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
}
else
{
// Swap p/q
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, result.template get<0>(), result.template get<1>());
}
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
break;
case 'i' :
{
typedef crosses
<
TurnInfo,
typename si::side_strategy_type
> policy;
policy::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
typedef touch
<
TurnInfo,
typename si::side_strategy_type
> policy;
policy::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
break;
case 'e':
{
if (! result.template get<1>().opposite)
{
// Both equal
// or collinear-and-ending at intersection point
typedef equal
<
TurnInfo,
typename si::side_strategy_type
> policy;
policy::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
// If they ARE opposite, don't do anything.
}
break;
case 'c' :
{
// Collinear
if (! result.template get<1>().opposite)
{
if (result.template get<1>().arrival[0] == 0)
{
// Collinear, but similar thus handled as equal
equal
<
TurnInfo,
typename si::side_strategy_type
>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
// override assigned method
tp.method = method_collinear;
}
else
{
collinear
<
TurnInfo,
typename si::side_strategy_type
>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
}
AssignPolicy::apply(tp, pi, qi);
*out++ = tp;
}
else
{
collinear_opposite
<
TurnInfo,
typename si::side_strategy_type,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, result.template get<0>(), result.template get<1>());
}
}
break;
case '0' :
// degenerate points
break;
default :
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
std::cout << "get_turns, nyi: " << method << std::endl;
#endif
break;
}
return out;
}
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP

View File

@@ -0,0 +1,864 @@
// 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_GET_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
#include <cstddef>
#include <map>
#include <boost/array.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
# include <boost/geometry/util/write_dsv.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_turns
{
struct no_interrupt_policy
{
static bool const enabled = false;
template <typename Range>
static inline bool apply(Range const&)
{
return false;
}
};
template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Section1, typename Section2,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
class get_turns_in_sections
{
typedef typename closeable_view
<
typename range_type<Geometry1>::type const,
closure<Geometry1>::value
>::type cview_type1;
typedef typename closeable_view
<
typename range_type<Geometry2>::type const,
closure<Geometry2>::value
>::type cview_type2;
typedef typename reversible_view
<
cview_type1 const,
Reverse1 ? iterate_reverse : iterate_forward
>::type view_type1;
typedef typename reversible_view
<
cview_type2 const,
Reverse2 ? iterate_reverse : iterate_forward
>::type view_type2;
typedef typename boost::range_iterator
<
view_type1 const
>::type range1_iterator;
typedef typename boost::range_iterator
<
view_type2 const
>::type range2_iterator;
template <typename Geometry, typename Section>
static inline bool neighbouring(Section const& section,
int index1, int index2)
{
// About n-2:
// (square: range_count=5, indices 0,1,2,3
// -> 0-3 are adjacent, don't check on intersections)
// Also tested for open polygons, and/or duplicates
// About first condition: will be optimized by compiler (static)
// It checks if it is areal (box,ring,(multi)polygon
int const n = int(section.range_count);
return boost::is_same
<
typename tag_cast
<
typename geometry::point_type<Geometry1>::type,
areal_tag
>::type,
areal_tag
>::value
&& index1 == 0
&& index2 >= n - 2
;
}
public :
// Returns true if terminated, false if interrupted
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
cview_type1 cview1(range_by_section(geometry1, sec1));
cview_type2 cview2(range_by_section(geometry2, sec2));
view_type1 view1(cview1);
view_type2 view2(cview2);
range1_iterator begin_range_1 = boost::begin(view1);
range1_iterator end_range_1 = boost::end(view1);
range2_iterator begin_range_2 = boost::begin(view2);
range2_iterator end_range_2 = boost::end(view2);
int const dir1 = sec1.directions[0];
int const dir2 = sec2.directions[0];
int index1 = sec1.begin_index;
int ndi1 = sec1.non_duplicate_index;
bool const same_source =
source_id1 == source_id2
&& sec1.ring_id.multi_index == sec2.ring_id.multi_index
&& sec1.ring_id.ring_index == sec2.ring_id.ring_index;
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
index1, ndi1, dir1, sec2.bounding_box);
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true);
next1++;
// Walk through section and stop if we exceed the other box
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
begin_range_1, end_range_1, next1, true);
advance_to_non_duplicate_next(nd_next1, it1, sec1);
int index2 = sec2.begin_index;
int ndi2 = sec2.non_duplicate_index;
range2_iterator prev2, it2, end2;
get_start_point_iterator(sec2, view2, prev2, it2, end2,
index2, ndi2, dir2, sec1.bounding_box);
ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
next2++;
for (prev2 = it2++, next2++;
it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
if (skip)
{
// If sources are the same (possibly self-intersecting):
// skip if it is a neighbouring segment.
// (including first-last segment
// and two segments with one or more degenerate/duplicate
// (zero-length) segments in between)
// Also skip if index1 < index2 to avoid getting all
// intersections twice (only do this on same source!)
skip = index1 >= index2
|| ndi2 == ndi1 + 1
|| neighbouring<Geometry1>(sec1, index1, index2)
;
}
if (! skip)
{
// Move to the "non duplicate next"
ever_circling_iterator<range2_iterator> nd_next2(
begin_range_2, end_range_2, next2, true);
advance_to_non_duplicate_next(nd_next2, it2, sec2);
typedef typename boost::range_value<Turns>::type turn_info;
typedef typename turn_info::point_type ip;
turn_info ti;
ti.operations[0].seg_id = segment_identifier(source_id1,
sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1),
ti.operations[1].seg_id = segment_identifier(source_id2,
sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2),
ti.operations[0].other_id = ti.operations[1].seg_id;
ti.operations[1].other_id = ti.operations[0].seg_id;
std::size_t const size_before = boost::size(turns);
TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
ti, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
if (interrupt_policy.apply(
std::make_pair(boost::begin(turns) + size_before,
boost::end(turns))))
{
return false;
}
}
}
}
}
return true;
}
private :
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
template <size_t Dim, typename Point, typename Box>
static inline bool preceding(int dir, Point const& point, Box const& box)
{
return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
|| (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
}
template <size_t Dim, typename Point, typename Box>
static inline bool exceeding(int dir, Point const& point, Box const& box)
{
return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
|| (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
}
template <typename Iterator, typename RangeIterator, typename Section>
static inline void advance_to_non_duplicate_next(Iterator& next,
RangeIterator const& it, Section const& section)
{
// To see where the next segments bend to, in case of touch/intersections
// on end points, we need (in case of degenerate/duplicate points) an extra
// iterator which moves to the REAL next point, so non duplicate.
// This needs an extra comparison (disjoint).
// (Note that within sections, non duplicate points are already asserted,
// by the sectionalize process).
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
while(! detail::disjoint::disjoint_point_point(*it, *next)
&& check++ < section.range_count)
{
next++;
}
}
// It is NOT possible to have section-iterators here
// because of the logistics of "index" (the section-iterator automatically
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
template <typename Range, typename Section, typename Box>
static inline void get_start_point_iterator(Section & section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
typename boost::range_iterator<Range const>::type& end,
int& index, int& ndi,
int dir, Box const& other_bounding_box)
{
it = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
for(; it != end && preceding<0>(dir, *it, other_bounding_box);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
it = prev;
}
};
struct get_section_box
{
template <typename Box, typename InputItem>
static inline void apply(Box& total, InputItem const& item)
{
geometry::expand(total, item.bounding_box);
}
};
struct ovelaps_section_box
{
template <typename Box, typename InputItem>
static inline bool apply(Box const& box, InputItem const& item)
{
return ! detail::disjoint::disjoint_box_box(box, item.bounding_box);
}
};
template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct section_visitor
{
int m_source_id1;
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
Turns& turns, InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
template <typename Section>
inline bool apply(Section const& sec1, Section const& sec2)
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box))
{
return get_turns_in_sections
<
Geometry1,
Geometry2,
Reverse1, Reverse2,
Section, Section,
Turns,
TurnPolicy,
InterruptPolicy
>::apply(
m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
m_turns, m_interrupt_policy);
}
return true;
}
};
template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
class get_turns_generic
{
public:
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
Turns& turns, InterruptPolicy& interrupt_policy)
{
// First create monotonic sections...
typedef typename boost::range_value<Turns>::type ip_type;
typedef typename ip_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef typename geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
geometry::sectionalize<Reverse1>(geometry1, sec1, 0);
geometry::sectionalize<Reverse2>(geometry2, sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
<
Geometry1, Geometry2,
Reverse1, Reverse2,
Turns, TurnPolicy, InterruptPolicy
> visitor(source_id1, geometry1, source_id2, geometry2, turns, interrupt_policy);
geometry::partition
<
box_type, get_section_box, ovelaps_section_box
>::apply(sec1, sec2, visitor);
}
};
// Get turns for a range with a box, following Cohen-Sutherland (cs) approach
template
<
typename Range, typename Box,
bool ReverseRange, bool ReverseBox,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns_cs
{
typedef typename boost::range_value<Turns>::type turn_info;
typedef typename geometry::point_type<Range>::type point_type;
typedef typename geometry::point_type<Box>::type box_point_type;
typedef typename closeable_view
<
Range const,
closure<Range>::value
>::type cview_type;
typedef typename reversible_view
<
cview_type const,
ReverseRange ? iterate_reverse : iterate_forward
>::type view_type;
typedef typename boost::range_iterator
<
view_type const
>::type iterator_type;
static inline void apply(
int source_id1, Range const& range,
int source_id2, Box const& box,
Turns& turns,
InterruptPolicy& ,
int multi_index = -1, int ring_index = -1)
{
if (boost::size(range) <= 1)
{
return;
}
boost::array<box_point_type,4> bp;
assign_box_corners_oriented<ReverseBox>(box, bp);
cview_type cview(range);
view_type view(cview);
iterator_type it = boost::begin(view);
ever_circling_iterator<iterator_type> next(
boost::begin(view), boost::end(view), it, true);
next++;
next++;
//bool first = true;
//char previous_side[2] = {0, 0};
int index = 0;
for (iterator_type prev = it++;
it != boost::end(view);
prev = it++, next++, index++)
{
segment_identifier seg_id(source_id1,
multi_index, ring_index, index);
/*if (first)
{
previous_side[0] = get_side<0>(box, *prev);
previous_side[1] = get_side<1>(box, *prev);
}
char current_side[2];
current_side[0] = get_side<0>(box, *it);
current_side[1] = get_side<1>(box, *it);
// There can NOT be intersections if
// 1) EITHER the two points are lying on one side of the box (! 0 && the same)
// 2) OR same in Y-direction
// 3) OR all points are inside the box (0)
if (! (
(current_side[0] != 0 && current_side[0] == previous_side[0])
|| (current_side[1] != 0 && current_side[1] == previous_side[1])
|| (current_side[0] == 0
&& current_side[1] == 0
&& previous_side[0] == 0
&& previous_side[1] == 0)
)
)*/
if (true)
{
get_turns_with_box(seg_id, source_id2,
*prev, *it, *next,
bp[0], bp[1], bp[2], bp[3],
turns);
// Future performance enhancement:
// return if told by the interrupt policy
}
}
}
private:
template<std::size_t Index, typename Point>
static inline int get_side(Box const& box, Point const& point)
{
// Inside -> 0
// Outside -> -1 (left/below) or 1 (right/above)
// On border -> -2 (left/lower) or 2 (right/upper)
// The only purpose of the value is to not be the same,
// and to denote if it is inside (0)
typename coordinate_type<Point>::type const& c = get<Index>(point);
typename coordinate_type<Box>::type const& left = get<min_corner, Index>(box);
typename coordinate_type<Box>::type const& right = get<max_corner, Index>(box);
if (geometry::math::equals(c, left)) return -2;
else if (geometry::math::equals(c, right)) return 2;
else if (c < left) return -1;
else if (c > right) return 1;
else return 0;
}
static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
// Points from a range:
point_type const& rp0,
point_type const& rp1,
point_type const& rp2,
// Points from the box
box_point_type const& bp0,
box_point_type const& bp1,
box_point_type const& bp2,
box_point_type const& bp3,
// Output
Turns& turns)
{
// Depending on code some relations can be left out
typedef typename boost::range_value<Turns>::type turn_info;
turn_info ti;
ti.operations[0].seg_id = seg_id;
ti.operations[0].other_id = ti.operations[1].seg_id;
ti.operations[1].other_id = seg_id;
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
ti, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
ti, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
ti, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
ti, std::back_inserter(turns));
}
};
template
<
typename Polygon, typename Box,
bool Reverse, bool ReverseBox,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns_polygon_cs
{
static inline void apply(
int source_id1, Polygon const& polygon,
int source_id2, Box const& box,
Turns& turns, InterruptPolicy& interrupt_policy,
int multi_index = -1)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef detail::get_turns::get_turns_cs
<
ring_type, Box,
Reverse, ReverseBox,
Turns,
TurnPolicy,
InterruptPolicy
> intersector_type;
intersector_type::apply(
source_id1, geometry::exterior_ring(polygon),
source_id2, box, turns, interrupt_policy,
multi_index, -1);
int i = 0;
typename interior_return_type<Polygon const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
++it, ++i)
{
intersector_type::apply(
source_id1, *it,
source_id2, box, turns, interrupt_policy,
multi_index, i);
}
}
};
}} // namespace detail::get_turns
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// Because this is "detail" method, and most implementations will use "generic",
// we take the freedom to derive it from "generic".
template
<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns
: detail::get_turns::get_turns_generic
<
Geometry1, Geometry2,
Reverse1, Reverse2,
Turns,
TurnPolicy,
InterruptPolicy
>
{};
template
<
typename Polygon, typename Box,
bool ReversePolygon, bool ReverseBox,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns
<
polygon_tag, box_tag,
Polygon, Box,
ReversePolygon, ReverseBox,
Turns,
TurnPolicy,
InterruptPolicy
> : detail::get_turns::get_turns_polygon_cs
<
Polygon, Box,
ReversePolygon, ReverseBox,
Turns, TurnPolicy, InterruptPolicy
>
{};
template
<
typename Ring, typename Box,
bool ReverseRing, bool ReverseBox,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns
<
ring_tag, box_tag,
Ring, Box,
ReverseRing, ReverseBox,
Turns,
TurnPolicy,
InterruptPolicy
> : detail::get_turns::get_turns_cs
<
Ring, Box, ReverseRing, ReverseBox,
Turns, TurnPolicy, InterruptPolicy
>
{};
template
<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns_reversed
{
static inline void apply(
int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
Turns& turns, InterruptPolicy& interrupt_policy)
{
get_turns
<
GeometryTag2, GeometryTag1,
Geometry2, Geometry1,
Reverse2, Reverse1,
Turns, TurnPolicy,
InterruptPolicy
>::apply(source_id2, g2, source_id1, g1, turns, interrupt_policy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc2{turn points}
\ingroup overlay
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param turns container which will contain turn points
\param interrupt_policy policy determining if process is stopped
when intersection is found
*/
template
<
bool Reverse1, bool Reverse2,
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
typedef typename strategy_intersection
<
typename cs_tag<Geometry1>::type,
Geometry1,
Geometry2,
typename boost::range_value<Turns>::type
>::segment_intersection_strategy_type segment_intersection_strategy_type;
typedef detail::overlay::get_turn_info
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
typename boost::range_value<Turns>::type,
AssignPolicy
> TurnPolicy;
boost::mpl::if_c
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::get_turns_reversed
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
Turns, TurnPolicy,
InterruptPolicy
>,
dispatch::get_turns
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
Turns, TurnPolicy,
InterruptPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
turns, interrupt_policy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP

View File

@@ -0,0 +1,666 @@
// 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_HANDLE_TANGENCIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
#include <algorithm>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template
<
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Strategy
>
struct sort_in_cluster
{
inline sort_in_cluster(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, Strategy const& strategy)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_strategy(strategy)
{}
private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
typedef typename Indexed::type turn_operation_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef model::referring_segment<point_type const> segment_type;
// Determine how p/r and p/s are located.
template <typename P>
static inline void overlap_info(P const& pi, P const& pj,
P const& ri, P const& rj,
P const& si, P const& sj,
bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
{
// Determine how p/r and p/s are located.
// One of them is coming from opposite direction.
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
segment_type,
segment_type,
segment_intersection_points<point_type>
>
> policy;
segment_type p(pi, pj);
segment_type r(ri, rj);
segment_type s(si, sj);
// Get the intersection point (or two points)
segment_intersection_points<point_type> pr = policy::apply(p, r);
segment_intersection_points<point_type> ps = policy::apply(p, s);
segment_intersection_points<point_type> rs = policy::apply(r, s);
// Check on overlap
pr_overlap = pr.count == 2;
ps_overlap = ps.count == 2;
rs_overlap = rs.count == 2;
}
inline void debug_consider(int order, Indexed const& left,
Indexed const& right, std::string const& header,
bool skip = true,
std::string const& extra = "", bool ret = false
) const
{
if (skip) return;
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.other_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
bool prc = false, psc = false, rsc = false;
overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
int const side_si_p = m_strategy.apply(pi, pj, si);
int const side_sj_p = m_strategy.apply(pi, pj, sj);
int const side_si_r = m_strategy.apply(ri, rj, si);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH_MORE
std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl;
std::cout << " r//p: " << side_ri_p << " / " << side_rj_p << std::endl;
std::cout << " s//p: " << side_si_p << " / " << side_sj_p << std::endl;
std::cout << " s//r: " << side_si_r << " / " << side_sj_r << std::endl;
#endif
std::cout << header
//<< " order: " << order
<< " ops: " << operation_char(left.subject.operation)
<< "/" << operation_char(right.subject.operation)
<< " ri//p: " << side_ri_p
<< " si//p: " << side_si_p
<< " si//r: " << side_si_r
<< " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
//<< " idx: " << left.index << "/" << right.index
;
if (! extra.empty())
{
std::cout << " " << extra << " " << (ret ? "true" : "false");
}
std::cout << std::endl;
#endif
}
// ux/ux
inline bool consider_ux_ux(Indexed const& left,
Indexed const& right
, std::string const& header
) const
{
bool ret = left.index < right.index;
// In combination of u/x, x/u: take first union, then blocked.
// Solves #88, #61, #56, #80
if (left.subject.operation == operation_union
&& right.subject.operation == operation_blocked)
{
ret = true;
}
else if (left.subject.operation == operation_blocked
&& right.subject.operation == operation_union)
{
ret = false;
}
else
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ux/ux unhandled" << std::endl;
#endif
}
//debug_consider(0, left, right, header, false, "-> return ", ret);
return ret;
}
inline bool consider_iu_ux(Indexed const& left,
Indexed const& right,
int order // 1: iu first, -1: ux first
, std::string const& header
) const
{
bool ret = false;
if (left.subject.operation == operation_union
&& right.subject.operation == operation_union)
{
ret = order == 1;
}
else if (left.subject.operation == operation_union
&& right.subject.operation == operation_blocked)
{
ret = true;
}
else if (right.subject.operation == operation_union
&& left.subject.operation == operation_blocked)
{
ret = false;
}
else if (left.subject.operation == operation_union)
{
ret = true;
}
else if (right.subject.operation == operation_union)
{
ret = false;
}
else
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
// this still happens in the traverse.cpp test
std::cout << " iu/ux unhandled" << std::endl;
#endif
ret = order == 1;
}
//debug_consider(0, left, right, header, false, "-> return", ret);
return ret;
}
inline bool consider_iu_ix(Indexed const& left,
Indexed const& right,
int order // 1: iu first, -1: ix first
, std::string const& header
) const
{
//debug_consider(order, left, right, header, false, "iu/ix");
return left.subject.operation == operation_intersection
&& right.subject.operation == operation_intersection ? order == 1
: left.subject.operation == operation_intersection ? false
: right.subject.operation == operation_intersection ? true
: order == 1;
}
inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
std::string const& header) const
{
//debug_consider(0, left, right, header);
// In general, order it like "union, intersection".
if (left.subject.operation == operation_intersection
&& right.subject.operation == operation_union)
{
//debug_consider(0, left, right, header, false, "i,u", false);
return false;
}
else if (left.subject.operation == operation_union
&& right.subject.operation == operation_intersection)
{
//debug_consider(0, left, right, header, false, "u,i", true);
return true;
}
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.other_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
int const side_si_r = m_strategy.apply(ri, rj, si);
// Both located at same side (#58, pie_21_7_21_0_3)
if (side_ri_p * side_si_p == 1 && side_si_r != 0)
{
// Take the most left one
if (left.subject.operation == operation_union
&& right.subject.operation == operation_union)
{
bool ret = side_si_r == 1;
//debug_consider(0, left, right, header, false, "same side", ret);
return ret;
}
}
// Coming from opposite sides (#59, #99)
if (side_ri_p * side_si_p == -1)
{
bool ret = false;
{
ret = side_ri_p == 1; // #100
debug_consider(0, left, right, header, false, "opp.", ret);
return ret;
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << " iu/iu coming from opposite unhandled" << std::endl;
#endif
}
// We need EXTRA information here: are p/r/s overlapping?
bool pr_ov = false, ps_ov = false, rs_ov = false;
overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
// One coming from right (#83,#90)
// One coming from left (#90, #94, #95)
if (side_si_r != 0 && (side_ri_p != 0 || side_si_p != 0))
{
bool ret = false;
if (pr_ov || ps_ov)
{
int r = side_ri_p != 0 ? side_ri_p : side_si_p;
ret = r * side_si_r == 1;
}
else
{
ret = side_si_r == 1;
}
debug_consider(0, left, right, header, false, "left or right", ret);
return ret;
}
// All aligned (#92, #96)
if (side_ri_p == 0 && side_si_p == 0 && side_si_r == 0)
{
// One of them is coming from opposite direction.
// Take the one NOT overlapping
bool ret = false;
bool found = false;
if (pr_ov && ! ps_ov)
{
ret = true;
found = true;
}
else if (!pr_ov && ps_ov)
{
ret = false;
found = true;
}
debug_consider(0, left, right, header, false, "aligned", ret);
if (found)
{
return ret;
}
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << " iu/iu unhandled" << std::endl;
debug_consider(0, left, right, header, false, "unhandled", left.index < right.index);
#endif
return left.index < right.index;
}
inline bool consider_ii(Indexed const& left, Indexed const& right,
std::string const& header) const
{
debug_consider(0, left, right, header);
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
left.subject.other_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
// Two other points are (mostly) lying both right of the considered segment
// Take the most left one
int const side_si_r = m_strategy.apply(ri, rj, si);
if (side_ri_p == -1
&& side_si_p == -1
&& side_si_r != 0)
{
bool const ret = side_si_r != 1;
return ret;
}
return left.index < right.index;
}
public :
inline bool operator()(Indexed const& left, Indexed const& right) const
{
bool const default_order = left.index < right.index;
if ((m_turn_points[left.index].discarded || left.discarded)
&& (m_turn_points[right.index].discarded || right.discarded))
{
return default_order;
}
else if (m_turn_points[left.index].discarded || left.discarded)
{
// Be careful to sort discarded first, then all others
return true;
}
else if (m_turn_points[right.index].discarded || right.discarded)
{
// See above so return false here such that right (discarded)
// is sorted before left (not discarded)
return false;
}
else if (m_turn_points[left.index].combination(operation_blocked, operation_union)
&& m_turn_points[right.index].combination(operation_blocked, operation_union))
{
// ux/ux
return consider_ux_ux(left, right, "ux/ux");
}
else if (m_turn_points[left.index].both(operation_union)
&& m_turn_points[right.index].both(operation_union))
{
// uu/uu, Order is arbitrary
// Note: uu/uu is discarded now before so this point will
// not be reached.
return default_order;
}
else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
&& m_turn_points[right.index].combination(operation_intersection, operation_union))
{
return consider_iu_iu(left, right, "iu/iu");
}
else if (m_turn_points[left.index].both(operation_intersection)
&& m_turn_points[right.index].both(operation_intersection))
{
return consider_ii(left, right, "ii/ii");
}
else if (m_turn_points[left.index].combination(operation_union, operation_blocked)
&& m_turn_points[right.index].combination(operation_intersection, operation_union))
{
return consider_iu_ux(left, right, -1, "ux/iu");
}
else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
&& m_turn_points[right.index].combination(operation_union, operation_blocked))
{
return consider_iu_ux(left, right, 1, "iu/ux");
}
else if (m_turn_points[left.index].combination(operation_intersection, operation_blocked)
&& m_turn_points[right.index].combination(operation_intersection, operation_union))
{
return consider_iu_ix(left, right, 1, "ix/iu");
}
else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
&& m_turn_points[right.index].combination(operation_intersection, operation_blocked))
{
return consider_iu_ix(left, right, -1, "iu/ix");
}
else if (m_turn_points[left.index].method != method_equal
&& m_turn_points[right.index].method == method_equal
)
{
// If one of them was EQUAL or CONTINUES, it should always come first
return false;
}
else if (m_turn_points[left.index].method == method_equal
&& m_turn_points[right.index].method != method_equal
)
{
return true;
}
// Now we have no clue how to sort.
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation)
<< operation_char(m_turn_points[left.index].operations[1].operation)
<< "/" << operation_char(m_turn_points[right.index].operations[0].operation)
<< operation_char(m_turn_points[right.index].operations[1].operation)
<< " " << " Take " << left.index << " < " << right.index
<< std::cout;
#endif
return default_order;
}
};
template
<
typename IndexType,
typename Iterator,
typename TurnPoints,
typename Geometry1,
typename Geometry2,
typename Strategy
>
inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
int count = 0;
// Make an analysis about all occuring cases here.
std::map<std::pair<operation_type, operation_type>, int> inspection;
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
operation_type first = turn_points[it->index].operations[0].operation;
operation_type second = turn_points[it->index].operations[1].operation;
if (first > second)
{
std::swap(first, second);
}
inspection[std::make_pair(first, second)]++;
count++;
}
bool keep_cc = false;
// Decide about which is going to be discarded here.
if (inspection[std::make_pair(operation_union, operation_union)] == 1
&& inspection[std::make_pair(operation_continue, operation_continue)] == 1)
{
// In case of uu/cc, discard the uu, that indicates a tangency and
// inclusion would disturb the (e.g.) cc-cc-cc ordering
// NOTE: uu is now discarded anyhow.
keep_cc = true;
}
else if (count == 2
&& inspection[std::make_pair(operation_intersection, operation_intersection)] == 1
&& inspection[std::make_pair(operation_union, operation_intersection)] == 1)
{
// In case of ii/iu, discard the iu. The ii should always be visited,
// Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
if (turn_points[it->index].combination(operation_intersection, operation_union))
{
it->discarded = true;
}
}
}
// Discard any continue turn, unless it is the only thing left
// (necessary to avoid cc-only rings, all being discarded
// e.g. traversal case #75)
int nd_count= 0, cc_count = 0;
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
if (! it->discarded)
{
nd_count++;
if (turn_points[it->index].both(operation_continue))
{
cc_count++;
}
}
}
if (nd_count == cc_count)
{
keep_cc = true;
}
if (! keep_cc)
{
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
if (turn_points[it->index].both(operation_continue))
{
it->discarded = true;
}
}
}
}
template
<
typename IndexType,
bool Reverse1, bool Reverse2,
typename Iterator,
typename TurnPoints,
typename Geometry1,
typename Geometry2,
typename Strategy
>
inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
// First inspect and (possibly) discard rows
inspect_cluster<IndexType>(begin_cluster, end_cluster, turn_points,
for_operation, geometry1, geometry2, strategy);
// Then sort this range (discard rows will be ordered first and will be removed in enrich_assign)
std::sort(begin_cluster, end_cluster,
sort_in_cluster
<
TurnPoints,
IndexType,
Geometry1, Geometry2,
Reverse1, Reverse2,
Strategy
>(turn_points, geometry1, geometry2, strategy));
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
typedef typename IndexType::type operations_type;
operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index];
std::cout << "Clustered points on equal distance " << op.enriched.distance << std::endl;
std::cout << "->Indexes ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
std::cout << " " << it->index;
}
std::cout << std::endl << "->Methods: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
std::cout << " " << method_char(turn_points[it->index].method);
}
std::cout << std::endl << "->Operations: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
std::cout << " " << operation_char(turn_points[it->index].operations[0].operation)
<< operation_char(turn_points[it->index].operations[1].operation);
}
std::cout << std::endl << "->Discarded: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
std::cout << " " << (it->discarded ? "true" : "false");
}
std::cout << std::endl;
//<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id
//<< " and " << op.seg_id << " / " << op.other_id
//<< geometry::distance(turn_points[prev->index].point, turn_points[it->index].point)
#endif
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP

View File

@@ -0,0 +1,527 @@
// 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_INTERSECTION_INSERT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP
#include <cstddef>
#include <boost/mpl/if.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/geometry/core/is_areal.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/views/segment_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersection
{
template
<
typename Segment1, typename Segment2,
typename OutputIterator, typename PointOut,
typename Strategy
>
struct intersection_segment_segment_point
{
static inline OutputIterator apply(Segment1 const& segment1,
Segment2 const& segment2, OutputIterator out,
Strategy const& strategy)
{
typedef typename point_type<PointOut>::type point_type;
// Get the intersection point (or two points)
segment_intersection_points<point_type> is
= strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
Segment1,
Segment2,
segment_intersection_points<point_type>
>
>::apply(segment1, segment2);
for (std::size_t i = 0; i < is.count; i++)
{
PointOut p;
geometry::convert(is.intersections[i], p);
*out++ = p;
}
return out;
}
};
template
<
typename Linestring1, typename Linestring2,
typename OutputIterator, typename PointOut,
typename Strategy
>
struct intersection_linestring_linestring_point
{
static inline OutputIterator apply(Linestring1 const& linestring1,
Linestring2 const& linestring2, OutputIterator out,
Strategy const& strategy)
{
typedef typename point_type<PointOut>::type point_type;
typedef detail::overlay::turn_info<point_type> turn_info;
std::deque<turn_info> turns;
geometry::get_intersection_points(linestring1, linestring2, turns);
for (typename boost::range_iterator<std::deque<turn_info> const>::type
it = boost::begin(turns); it != boost::end(turns); ++it)
{
PointOut p;
geometry::convert(it->point, p);
*out++ = p;
}
return out;
}
};
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
// tag dispatching:
typename TagIn1, typename TagIn2, typename TagOut,
// orientation
// metafunction finetuning helpers:
bool Areal1, bool Areal2, bool ArealOut,
// real types
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES_OR_ORIENTATIONS
, (types<Geometry1, Geometry2, GeometryOut>)
);
};
template
<
typename TagIn1, typename TagIn2, typename TagOut,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
TagIn1, TagIn2, TagOut,
true, true, true,
Geometry1, Geometry2,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType,
Strategy
> : detail::overlay::overlay
<Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
{};
// Any areal type with box:
template
<
typename TagIn, typename TagOut,
typename Geometry, typename Box,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
TagIn, box_tag, TagOut,
true, true, true,
Geometry, Box,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType,
Strategy
> : detail::overlay::overlay
<Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
{};
template
<
typename Segment1, typename Segment2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
segment_tag, segment_tag, point_tag,
false, false, false,
Segment1, Segment2,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType, Strategy
> : detail::intersection::intersection_segment_segment_point
<
Segment1, Segment2,
OutputIterator, GeometryOut,
Strategy
>
{};
template
<
typename Linestring1, typename Linestring2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
linestring_tag, linestring_tag, point_tag,
false, false, false,
Linestring1, Linestring2,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType, Strategy
> : detail::intersection::intersection_linestring_linestring_point
<
Linestring1, Linestring2,
OutputIterator, GeometryOut,
Strategy
>
{};
template
<
typename Linestring, typename Box,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
linestring_tag, box_tag, linestring_tag,
false, true, false,
Linestring, Box,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType,
Strategy
>
{
static inline OutputIterator apply(Linestring const& linestring,
Box const& box, OutputIterator out, Strategy const& strategy)
{
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
return detail::intersection::clip_range_with_box
<GeometryOut>(box, linestring, out, lb_strategy);
}
};
template
<
typename Segment, typename Box,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
segment_tag, box_tag, linestring_tag,
false, true, false,
Segment, Box,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
OverlayType,
Strategy
>
{
static inline OutputIterator apply(Segment const& segment,
Box const& box, OutputIterator out, Strategy const& strategy)
{
geometry::segment_view<Segment> range(segment);
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
return detail::intersection::clip_range_with_box
<GeometryOut>(box, range, out, lb_strategy);
}
};
template
<
typename Tag1, typename Tag2,
bool Areal1, bool Areal2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename PointOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert
<
Tag1, Tag2, point_tag,
Areal1, Areal2, false,
Geometry1, Geometry2,
Reverse1, Reverse2, ReverseOut,
OutputIterator, PointOut,
OverlayType,
Strategy
>
{
static inline OutputIterator apply(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy)
{
typedef detail::overlay::turn_info<PointOut> turn_info;
std::vector<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
false, false, detail::overlay::assign_null_policy
>(geometry1, geometry2, turns, policy);
for (typename std::vector<turn_info>::const_iterator it
= turns.begin(); it != turns.end(); ++it)
{
*out++ = it->point;
}
return out;
}
};
template
<
typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
bool Areal1, bool Areal2, bool ArealOut,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type OverlayType,
typename Strategy
>
struct intersection_insert_reversed
{
static inline OutputIterator apply(Geometry1 const& g1,
Geometry2 const& g2, OutputIterator out,
Strategy const& strategy)
{
return intersection_insert
<
GeometryTag2, GeometryTag1, GeometryTag3,
Areal2, Areal1, ArealOut,
Geometry2, Geometry1,
Reverse2, Reverse1, ReverseOut,
OutputIterator, GeometryOut,
OverlayType,
Strategy
>::apply(g2, g1, out, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersection
{
template
<
typename GeometryOut,
bool ReverseSecond,
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out,
Strategy const& strategy)
{
return boost::mpl::if_c
<
geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
geometry::dispatch::intersection_insert_reversed
<
typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type,
typename geometry::tag<GeometryOut>::type,
geometry::is_areal<Geometry1>::value,
geometry::is_areal<Geometry2>::value,
geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
OutputIterator, GeometryOut,
OverlayType,
Strategy
>,
geometry::dispatch::intersection_insert
<
typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type,
typename geometry::tag<GeometryOut>::type,
geometry::is_areal<Geometry1>::value,
geometry::is_areal<Geometry2>::value,
geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
OutputIterator, GeometryOut,
OverlayType,
Strategy
>
>::type::apply(geometry1, geometry2, out, strategy);
}
/*!
\brief \brief_calc2{intersection} \brief_strategy
\ingroup intersection
\details \details_calc2{intersection_insert, spatial set theoretic intersection}
\brief_strategy. \details_insert{intersection}
\tparam GeometryOut \tparam_geometry{\p_l_or_c}
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator \tparam_out{\p_l_or_c}
\tparam Strategy \tparam_strategy_overlay
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{intersection}
\param strategy \param_strategy{intersection}
\return \return_out
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/intersection.qbk]}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator,
typename Strategy
>
inline OutputIterator intersection_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
return detail::intersection::insert
<
GeometryOut, false, overlay_intersection
>(geometry1, geometry2, out, strategy);
}
/*!
\brief \brief_calc2{intersection}
\ingroup intersection
\details \details_calc2{intersection_insert, spatial set theoretic intersection}.
\details_insert{intersection}
\tparam GeometryOut \tparam_geometry{\p_l_or_c}
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator \tparam_out{\p_l_or_c}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{intersection}
\return \return_out
\qbk{[include reference/algorithms/intersection.qbk]}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator
>
inline OutputIterator intersection_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
> strategy;
return intersection_insert<GeometryOut>(geometry1, geometry2, out,
strategy());
}
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP

View File

@@ -0,0 +1,300 @@
// 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_OVERLAY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
#include <deque>
#include <map>
#include <boost/range.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/util/write_dsv.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// Skip for assemble process
template <typename TurnInfo>
inline bool skip(TurnInfo const& turn_info)
{
return (turn_info.discarded || turn_info.both(operation_union))
&& ! turn_info.any_blocked()
&& ! turn_info.both(operation_intersection)
;
}
template <typename TurnPoints, typename Map>
inline void map_turns(Map& map, TurnPoints const& turn_points)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
int index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it, ++index)
{
if (! skip(*it))
{
int op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
++op_it, ++op_index)
{
ring_identifier ring_id
(
op_it->seg_id.source_index,
op_it->seg_id.multi_index,
op_it->seg_id.ring_index
);
map[ring_id]++;
}
}
}
}
template
<
typename GeometryOut, overlay_type Direction, bool ReverseOut,
typename Geometry1, typename Geometry2,
typename OutputIterator
>
inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out)
{
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
// Union: return either of them
// Intersection: return nothing
// Difference: return first of them
if (Direction == overlay_intersection
|| (Direction == overlay_difference
&& geometry::num_points(geometry1) == 0))
{
return out;
}
std::map<ring_identifier, int> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false);
ring_container_type rings;
assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
}
template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename OutputIterator, typename GeometryOut,
overlay_type Direction,
typename Strategy
>
struct overlay
{
static inline OutputIterator apply(
Geometry1 const& geometry1, Geometry2 const& geometry2,
OutputIterator out,
Strategy const& )
{
if (geometry::num_points(geometry1) == 0 && geometry::num_points(geometry2) == 0)
{
return out;
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
typedef detail::overlay::traversal_turn_info<point_type> turn_info;
typedef std::deque<turn_info> container_type;
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
if (geometry::num_points(geometry1) == 0
|| geometry::num_points(geometry2) == 0)
{
return return_if_one_input_is_empty
<
GeometryOut, Direction, ReverseOut
>(geometry1, geometry2, out);
}
container_type turn_points;
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
boost::timer timer;
#endif
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "get turns" << std::endl;
#endif
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
Reverse1, Reverse2,
detail::overlay::calculate_distance_policy
>(geometry1, geometry2, turn_points, policy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "get_turns: " << timer.elapsed() << std::endl;
#endif
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
typename Strategy::side_strategy_type side_strategy;
geometry::enrich_intersection_points<Reverse1, Reverse2>(turn_points,
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
geometry1, geometry2,
side_strategy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl;
#endif
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "traverse" << std::endl;
#endif
// Traverse through intersection/turn points and create rings of them.
// Note that these rings are always in clockwise order, even in CCW polygons,
// and are marked as "to be reversed" below
ring_container_type rings;
traverse<Reverse1, Reverse2, Geometry1, Geometry2>::apply
(
geometry1, geometry2,
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
turn_points, rings
);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "traverse: " << timer.elapsed() << std::endl;
#endif
std::map<ring_identifier, int> map;
map_turns(map, turn_points);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "map_turns: " << timer.elapsed() << std::endl;
#endif
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
std::map<ring_identifier, properties> selected;
select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty());
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "select_rings: " << timer.elapsed() << std::endl;
#endif
// Add rings created during traversal
{
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
selected[id] = properties(*it, true);
selected[id].reversed = ReverseOut;
id.multi_index++;
}
}
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "add traversal rings: " << timer.elapsed() << std::endl;
#endif
assign_parents(geometry1, geometry2, rings, selected);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "assign_parents: " << timer.elapsed() << std::endl;
#endif
return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out);
}
};
// Metafunction helper for intersection and union
template <order_selector Selector, bool Reverse = false>
struct do_reverse {};
template <>
struct do_reverse<clockwise, false> : boost::false_type {};
template <>
struct do_reverse<clockwise, true> : boost::true_type {};
template <>
struct do_reverse<counterclockwise, false> : boost::true_type {};
template <>
struct do_reverse<counterclockwise, true> : boost::false_type {};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP

View File

@@ -0,0 +1,29 @@
// 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_OVERLAY_TYPE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP
namespace boost { namespace geometry
{
enum overlay_type
{
overlay_union,
overlay_intersection,
overlay_difference,
overlay_dissolve
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP

View File

@@ -0,0 +1,78 @@
// 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_RING_PROPERTIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename Point>
struct ring_properties
{
typedef Point point_type;
typedef typename default_area_result<Point>::type area_type;
// Filled by "select_rings"
Point point;
area_type area;
// Filled by "update_selection_map"
int within_code;
bool reversed;
// Filled/used by "assign_rings"
bool discarded;
ring_identifier parent;
area_type parent_area;
std::vector<ring_identifier> children;
inline ring_properties()
: area(area_type())
, within_code(-1)
, reversed(false)
, discarded(false)
, parent_area(-1)
{}
template <typename RingOrBox>
inline ring_properties(RingOrBox const& ring_or_box, bool midpoint)
: within_code(-1)
, reversed(false)
, discarded(false)
, parent_area(-1)
{
this->area = geometry::area(ring_or_box);
geometry::point_on_border(this->point, ring_or_box, midpoint);
}
inline area_type get_area() const
{
return reversed ? -area : area;
}
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP

View File

@@ -0,0 +1,91 @@
// 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_SEGMENT_IDENTIFIER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP
#if defined(BOOST_GEOMETRY_DEBUG_OVERLAY)
# define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
#endif
#include <vector>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
namespace boost { namespace geometry
{
// Internal struct to uniquely identify a segment
// on a linestring,ring
// or polygon (needs ring_index)
// or multi-geometry (needs multi_index)
struct segment_identifier
{
inline segment_identifier()
: source_index(-1)
, multi_index(-1)
, ring_index(-1)
, segment_index(-1)
{}
inline segment_identifier(int src, int mul, int rin, int seg)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
, segment_index(seg)
{}
inline bool operator<(segment_identifier const& other) const
{
return source_index != other.source_index ? source_index < other.source_index
: multi_index !=other.multi_index ? multi_index < other.multi_index
: ring_index != other.ring_index ? ring_index < other.ring_index
: segment_index < other.segment_index
;
}
inline bool operator==(segment_identifier const& other) const
{
return source_index == other.source_index
&& segment_index == other.segment_index
&& ring_index == other.ring_index
&& multi_index == other.multi_index
;
}
#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id)
{
std::cout
<< "s:" << seg_id.source_index
<< ", v:" << seg_id.segment_index // ~vertex
;
if (seg_id.ring_index >= 0) std::cout << ", r:" << seg_id.ring_index;
if (seg_id.multi_index >= 0) std::cout << ", m:" << seg_id.multi_index;
return os;
}
#endif
int source_index;
int multi_index;
int ring_index;
int segment_index;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP

View File

@@ -0,0 +1,295 @@
// 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_SELECT_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
#include <map>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
namespace dispatch
{
template <typename Tag, typename Geometry>
struct select_rings
{};
template <typename Box>
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename Map>
static inline void apply(Box const& box, Geometry const& geometry,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
}
template <typename Map>
static inline void apply(Box const& box,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
template <typename Geometry, typename Map>
static inline void apply(Ring const& ring, Geometry const& geometry,
ring_identifier const& id, Map& map, bool midpoint)
{
if (boost::size(ring) > 0)
{
map[id] = typename Map::mapped_type(ring, midpoint);
}
}
template <typename Map>
static inline void apply(Ring const& ring,
ring_identifier const& id, Map& map, bool midpoint)
{
if (boost::size(ring) > 0)
{
map[id] = typename Map::mapped_type(ring, midpoint);
}
}
};
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
template <typename Geometry, typename Map>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
ring_identifier id, Map& map, bool midpoint)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
typename interior_return_type<Polygon const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, map, midpoint);
}
}
template <typename Map>
static inline void apply(Polygon const& polygon,
ring_identifier id, Map& map, bool midpoint)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), id, map, midpoint);
typename interior_return_type<Polygon const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, map, midpoint);
}
}
};
}
template<overlay_type OverlayType>
struct decide
{};
template<>
struct decide<overlay_union>
{
template <typename Code>
static bool include(ring_identifier const& id, Code const& code)
{
return code.within_code * -1 == 1;
}
template <typename Code>
static bool reversed(ring_identifier const& , Code const& )
{
return false;
}
};
template<>
struct decide<overlay_difference>
{
template <typename Code>
static bool include(ring_identifier const& id, Code const& code)
{
bool is_first = id.source_index == 0;
return code.within_code * -1 * (is_first ? 1 : -1) == 1;
}
template <typename Code>
static bool reversed(ring_identifier const& id, Code const& code)
{
return include(id, code) && id.source_index == 1;
}
};
template<>
struct decide<overlay_intersection>
{
template <typename Code>
static bool include(ring_identifier const& id, Code const& code)
{
return code.within_code * 1 == 1;
}
template <typename Code>
static bool reversed(ring_identifier const& , Code const& )
{
return false;
}
};
template
<
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
typename IntersectionMap, typename SelectionMap
>
inline void update_selection_map(Geometry1 const& geometry1,
Geometry2 const& geometry2,
IntersectionMap const& intersection_map,
SelectionMap const& map_with_all, SelectionMap& selection_map)
{
selection_map.clear();
for (typename SelectionMap::const_iterator it = boost::begin(map_with_all);
it != boost::end(map_with_all);
++it)
{
/*
int union_code = it->second.within_code * -1;
bool is_first = it->first.source_index == 0;
std::cout << it->first << " " << it->second.area
<< ": " << it->second.within_code
<< " union: " << union_code
<< " intersection: " << (it->second.within_code * 1)
<< " G1-G2: " << (union_code * (is_first ? 1 : -1))
<< " G2-G1: " << (union_code * (is_first ? -1 : 1))
<< " -> " << (decide<OverlayType>::include(it->first, it->second) ? "INC" : "")
<< decide<OverlayType>::reverse(it->first, it->second)
<< std::endl;
*/
bool found = intersection_map.find(it->first) != intersection_map.end();
if (! found)
{
ring_identifier const id = it->first;
typename SelectionMap::mapped_type properties = it->second; // Copy by value
// Calculate the "within code" (previously this was done earlier but is
// must efficienter here - it can be even more efficient doing it all at once,
// using partition, TODO)
// So though this is less elegant than before, it avoids many unused point-in-poly calculations
switch(id.source_index)
{
case 0 :
properties.within_code
= geometry::within(properties.point, geometry2) ? 1 : -1;
break;
case 1 :
properties.within_code
= geometry::within(properties.point, geometry1) ? 1 : -1;
break;
}
if (decide<OverlayType>::include(id, properties))
{
properties.reversed = decide<OverlayType>::reversed(id, properties);
selection_map[id] = properties;
}
}
}
}
/*!
\brief The function select_rings select rings based on the overlay-type (union,intersection)
*/
template
<
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
SelectionMap map_with_all;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
ring_identifier(0, -1, -1), map_with_all, midpoint);
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
ring_identifier(1, -1, -1), map_with_all, midpoint);
update_selection_map<OverlayType>(geometry1, geometry2, intersection_map,
map_with_all, selection_map);
}
template
<
overlay_type OverlayType,
typename Geometry,
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry const& geometry,
IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry>::type tag;
SelectionMap map_with_all;
dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), map_with_all, midpoint);
update_selection_map<OverlayType>(geometry, geometry, intersection_map,
map_with_all, selection_map);
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP

View File

@@ -0,0 +1,291 @@
// 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_SELF_TURN_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace self_get_turn_points
{
class self_ip_exception : public geometry::exception {};
template
<
typename Geometry,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
inline self_section_visitor(Geometry const& g,
Turns& turns, InterruptPolicy& ip)
: m_geometry(g)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
template <typename Section>
inline bool apply(Section const& sec1, Section const& sec2)
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box)
&& ! sec1.duplicate
&& ! sec2.duplicate)
{
detail::get_turns::get_turns_in_sections
<
Geometry, Geometry,
false, false,
Section, Section,
Turns, TurnPolicy,
InterruptPolicy
>::apply(
0, m_geometry, sec1,
0, m_geometry, sec2,
m_turns, m_interrupt_policy);
}
if (m_interrupt_policy.has_intersections)
{
// TODO: we should give partition an interrupt policy.
// Now we throw, and catch below, to stop the partition loop.
throw self_ip_exception();
}
return true;
}
};
template
<
typename Geometry,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct get_turns
{
static inline bool apply(
Geometry const& geometry,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
typedef model::box
<
typename geometry::point_type<Geometry>::type
> box_type;
typedef typename geometry::sections
<
box_type, 1
> sections_type;
sections_type sec;
geometry::sectionalize<false>(geometry, sec);
self_section_visitor
<
Geometry,
Turns, TurnPolicy, InterruptPolicy
> visitor(geometry, turns, interrupt_policy);
try
{
geometry::partition
<
box_type,
detail::get_turns::get_section_box,
detail::get_turns::ovelaps_section_box
>::apply(sec, visitor);
}
catch(self_ip_exception const& )
{
return false;
}
return true;
}
};
}} // namespace detail::self_get_turn_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename GeometryTag,
typename Geometry,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct self_get_turn_points
{
};
template
<
typename Ring,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct self_get_turn_points
<
ring_tag, Ring,
Turns,
TurnPolicy,
InterruptPolicy
>
: detail::self_get_turn_points::get_turns
<
Ring,
Turns,
TurnPolicy,
InterruptPolicy
>
{};
template
<
typename Box,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct self_get_turn_points
<
box_tag, Box,
Turns,
TurnPolicy,
InterruptPolicy
>
{
static inline bool apply(
Box const& ,
Turns& ,
InterruptPolicy& )
{
return true;
}
};
template
<
typename Polygon,
typename Turns,
typename TurnPolicy,
typename InterruptPolicy
>
struct self_get_turn_points
<
polygon_tag, Polygon,
Turns,
TurnPolicy,
InterruptPolicy
>
: detail::self_get_turn_points::get_turns
<
Polygon,
Turns,
TurnPolicy,
InterruptPolicy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Calculate self intersections of a geometry
\ingroup overlay
\tparam Geometry geometry type
\tparam Turns type of intersection container
(e.g. vector of "intersection/turn point"'s)
\param geometry geometry
\param turns container which will contain intersection points
\param interrupt_policy policy determining if process is stopped
when intersection is found
*/
template
<
typename AssignPolicy,
typename Geometry,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
Turns& turns, InterruptPolicy& interrupt_policy)
{
concept::check<Geometry const>();
typedef typename strategy_intersection
<
typename cs_tag<Geometry>::type,
Geometry,
Geometry,
typename boost::range_value<Turns>::type
>::segment_intersection_strategy_type strategy_type;
typedef detail::overlay::get_turn_info
<
typename point_type<Geometry>::type,
typename point_type<Geometry>::type,
typename boost::range_value<Turns>::type,
detail::overlay::assign_null_policy
> TurnPolicy;
dispatch::self_get_turn_points
<
typename tag<Geometry>::type,
Geometry,
Turns,
TurnPolicy,
InterruptPolicy
>::apply(geometry, turns, interrupt_policy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP

View File

@@ -0,0 +1,75 @@
// 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_STREAM_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP
#include <string>
#include <boost/array.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
static inline std::string dir(int d)
{
return d == 0 ? "-" : (d == 1 ? "L" : d == -1 ? "R" : "#");
}
static inline std::string how_str(int h)
{
return h == 0 ? "-" : (h == 1 ? "A" : "D");
}
template <typename P>
std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
{
typename geometry::coordinate_type<P>::type d = info.distance;
os << "\t"
<< " src " << info.seg_id.source_index
<< " seg " << info.seg_id.segment_index
<< " (// " << info.other_id.source_index
<< "." << info.other_id.segment_index << ")"
<< " how " << info.how
<< "[" << how_str(info.arrival)
<< " " << dir(info.direction)
<< (info.opposite ? " o" : "")
<< "]"
<< " sd "
<< dir(info.sides.get<0,0>())
<< dir(info.sides.get<0,1>())
<< dir(info.sides.get<1,0>())
<< dir(info.sides.get<1,1>())
<< " nxt seg " << info.travels_to_vertex_index
<< " , ip " << info.travels_to_ip_index
<< " , or " << info.next_ip_index
<< " dst " << double(d)
<< info.visit_state;
if (info.flagged)
{
os << " FLAGGED";
}
return os;
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP

View File

@@ -0,0 +1,47 @@
// 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_TRAVERSAL_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/visit_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename P>
struct traversal_turn_operation : public turn_operation
{
enrichment_info<P> enriched;
visit_info visited;
};
template <typename P>
struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
{};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP

View 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

View File

@@ -0,0 +1,142 @@
// 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_TURN_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP
#include <boost/array.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
enum operation_type
{
operation_none,
operation_union,
operation_intersection,
operation_blocked,
operation_continue
};
enum method_type
{
method_none,
method_disjoint,
method_crosses,
method_touch,
method_touch_interior,
method_collinear,
method_equal,
method_error
};
/*!
\brief Turn operation: operation
\details Information necessary for traversal phase (a phase
of the overlay process). The information is gathered during the
get_turns (segment intersection) phase.
The class is to be included in the turn_info class, either direct
or a derived or similar class with more (e.g. enrichment) information.
*/
struct turn_operation
{
operation_type operation;
segment_identifier seg_id;
segment_identifier other_id;
inline turn_operation()
: operation(operation_none)
{}
};
/*!
\brief Turn information: intersection point, method, and turn information
\details Information necessary for traversal phase (a phase
of the overlay process). The information is gathered during the
get_turns (segment intersection) phase.
\tparam Point point type of intersection point
\tparam Operation gives classes opportunity to add additional info
\tparam Container gives classes opportunity to define how operations are stored
*/
template
<
typename Point,
typename Operation = turn_operation,
typename Container = boost::array<Operation, 2>
>
struct turn_info
{
typedef Point point_type;
typedef Operation turn_operation_type;
typedef Container container_type;
Point point;
method_type method;
bool discarded;
Container operations;
inline turn_info()
: method(method_none)
, discarded(false)
{}
inline bool both(operation_type type) const
{
return has12(type, type);
}
inline bool combination(operation_type type1, operation_type type2) const
{
return has12(type1, type2) || has12(type2, type1);
}
inline bool is_discarded() const { return discarded; }
inline bool blocked() const
{
return both(operation_blocked);
}
inline bool any_blocked() const
{
return this->operations[0].operation == operation_blocked
|| this->operations[1].operation == operation_blocked;
}
private :
inline bool has12(operation_type type1, operation_type type2) const
{
return this->operations[0].operation == type1
&& this->operations[1].operation == type2
;
}
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP

View File

@@ -0,0 +1,136 @@
// 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_VISIT_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
#ifdef BOOST_GEOMETRY_USE_MSM
# include <boost/geometry/algorithms/detail/overlay/msm_state.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
#if ! defined(BOOST_GEOMETRY_USE_MSM)
class visit_info
{
private :
static const int NONE = 0;
static const int STARTED = 1;
static const int VISITED = 2;
static const int FINISHED = 3;
static const int REJECTED = 4;
int m_visit_code;
bool m_rejected;
public:
inline visit_info()
: m_visit_code(0)
, m_rejected(false)
{}
inline void set_visited() { m_visit_code = VISITED; }
inline void set_started() { m_visit_code = STARTED; }
inline void set_finished() { m_visit_code = FINISHED; }
inline void set_rejected()
{
m_visit_code = REJECTED;
m_rejected = true;
}
inline bool none() const { return m_visit_code == NONE; }
inline bool visited() const { return m_visit_code == VISITED; }
inline bool started() const { return m_visit_code == STARTED; }
inline bool finished() const { return m_visit_code == FINISHED; }
inline bool rejected() const { return m_rejected; }
inline void clear()
{
if (! rejected())
{
m_visit_code = NONE;
}
}
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
{
if (v.m_visit_code != 0)
{
os << " VIS: " << int(v.m_visit_code);
}
return os;
}
#endif
};
#else
class visit_info
{
private :
#ifndef USE_MSM_MINI
mutable
#endif
traverse_state state;
public :
inline visit_info()
{
state.start();
}
inline void set_none() { state.process_event(none()); } // Not Yet Implemented!
inline void set_visited() { state.process_event(visit()); }
inline void set_started() { state.process_event(starting()); }
inline void set_finished() { state.process_event(finish()); }
#ifdef USE_MSM_MINI
inline bool none() const { return state.flag_none(); }
inline bool visited() const { return state.flag_visited(); }
inline bool started() const { return state.flag_started(); }
#else
inline bool none() const { return state.is_flag_active<is_init>(); }
inline bool visited() const { return state.is_flag_active<is_visited>(); }
inline bool started() const { return state.is_flag_active<is_started>(); }
#endif
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
{
return os;
}
#endif
};
#endif
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP