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,107 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_AS_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP
#include <boost/type_traits.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename GeometryTag, typename Geometry, typename Range, bool IsConst>
struct as_range
{
static inline typename add_const_if_c<IsConst, Range>::type& get(
typename add_const_if_c<IsConst, Geometry>::type& input)
{
return input;
}
};
template <typename Geometry, typename Range, bool IsConst>
struct as_range<polygon_tag, Geometry, Range, IsConst>
{
static inline typename add_const_if_c<IsConst, Range>::type& get(
typename add_const_if_c<IsConst, Geometry>::type& input)
{
return exterior_ring(input);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
// Will probably be replaced by the more generic "view_as", therefore in detail
namespace detail
{
/*!
\brief Function getting either the range (ring, linestring) itself
or the outer ring (polygon)
\details Utility to handle polygon's outer ring as a range
\ingroup utility
*/
template <typename Range, typename Geometry>
inline Range& as_range(Geometry& input)
{
return dispatch::as_range
<
typename tag<Geometry>::type,
Geometry,
Range,
false
>::get(input);
}
/*!
\brief Function getting either the range (ring, linestring) itself
or the outer ring (polygon), const version
\details Utility to handle polygon's outer ring as a range
\ingroup utility
*/
template <typename Range, typename Geometry>
inline Range const& as_range(Geometry const& input)
{
return dispatch::as_range
<
typename tag<Geometry>::type,
Geometry,
Range,
true
>::get(input);
}
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP

View File

@@ -0,0 +1,93 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_ASSIGN_BOX_CORNERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
#include <cstddef>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// Note: this is moved to namespace detail because the names and parameter orders
// are not yet 100% clear.
/*!
\brief Assign the four points of a 2D box
\ingroup assign
\note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT
so this is how it is implemented.
\tparam Box \tparam_box
\tparam Point \tparam_point
\param box \param_box
\param lower_left point being assigned to lower left coordinates of the box
\param lower_right point being assigned to lower right coordinates of the box
\param upper_left point being assigned to upper left coordinates of the box
\param upper_right point being assigned to upper right coordinates of the box
\qbk{
[heading Example]
[assign_box_corners] [assign_box_corners_output]
}
*/
template <typename Box, typename Point>
inline void assign_box_corners(Box const& box,
Point& lower_left, Point& lower_right,
Point& upper_left, Point& upper_right)
{
concept::check<Box const>();
concept::check<Point>();
detail::assign::assign_box_2d_corner
<min_corner, min_corner>(box, lower_left);
detail::assign::assign_box_2d_corner
<max_corner, min_corner>(box, lower_right);
detail::assign::assign_box_2d_corner
<min_corner, max_corner>(box, upper_left);
detail::assign::assign_box_2d_corner
<max_corner, max_corner>(box, upper_right);
}
template <bool Reverse, typename Box, typename Range>
inline void assign_box_corners_oriented(Box const& box, Range& corners)
{
if (Reverse)
{
// make counterclockwise ll,lr,ur,ul
assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]);
}
else
{
// make clockwise ll,ul,ur,lr
assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]);
}
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP

View File

@@ -0,0 +1,94 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_ASSIGN_INDEXED_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
#include <cstddef>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Assign a box or segment with the value of a point
\ingroup assign
\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
or which point of segment (0/1)
\tparam Point \tparam_point
\tparam Geometry \tparam_box_or_segment
\param point \param_point
\param geometry \param_box_or_segment
\qbk{
[heading Example]
[assign_point_to_index] [assign_point_to_index_output]
}
*/
template <std::size_t Index, typename Geometry, typename Point>
inline void assign_point_to_index(Point const& point, Geometry& geometry)
{
concept::check<Point const>();
concept::check<Geometry>();
detail::assign::assign_point_to_index
<
Geometry, Point, Index, 0, dimension<Geometry>::type::value
>::apply(point, geometry);
}
/*!
\brief Assign a point with a point of a box or segment
\ingroup assign
\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
or which point of segment (0/1)
\tparam Geometry \tparam_box_or_segment
\tparam Point \tparam_point
\param geometry \param_box_or_segment
\param point \param_point
\qbk{
[heading Example]
[assign_point_from_index] [assign_point_from_index_output]
}
*/
template <std::size_t Index, typename Point, typename Geometry>
inline void assign_point_from_index(Geometry const& geometry, Point& point)
{
concept::check<Geometry const>();
concept::check<Point>();
detail::assign::assign_point_from_index
<
Geometry, Point, Index, 0, dimension<Geometry>::type::value
>::apply(geometry, point);
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP

View File

@@ -0,0 +1,443 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_ASSIGN_VALUES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
#include <cstddef>
#include <boost/concept/requires.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/if.hpp>
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace assign
{
template
<
typename Box, std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct initialize
{
typedef typename coordinate_type<Box>::type coordinate_type;
static inline void apply(Box& box, coordinate_type const& value)
{
geometry::set<Index, Dimension>(box, value);
initialize<Box, Index, Dimension + 1, DimensionCount>::apply(box, value);
}
};
template <typename Box, std::size_t Index, std::size_t DimensionCount>
struct initialize<Box, Index, DimensionCount, DimensionCount>
{
typedef typename coordinate_type<Box>::type coordinate_type;
static inline void apply(Box&, coordinate_type const& )
{}
};
template <typename Point>
struct assign_zero_point
{
static inline void apply(Point& point)
{
geometry::assign_value(point, 0);
}
};
template <typename BoxOrSegment>
struct assign_inverse_box_or_segment
{
typedef typename point_type<BoxOrSegment>::type point_type;
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<point_type>::type bound_type;
initialize
<
BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
>::apply(
geometry, boost::numeric::bounds<bound_type>::highest());
initialize
<
BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
>::apply(
geometry, boost::numeric::bounds<bound_type>::lowest());
}
};
template <typename BoxOrSegment>
struct assign_zero_box_or_segment
{
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
initialize
<
BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
>::apply(geometry, coordinate_type());
initialize
<
BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
>::apply(geometry, coordinate_type());
}
};
template
<
std::size_t Corner1, std::size_t Corner2,
typename Box, typename Point
>
inline void assign_box_2d_corner(Box const& box, Point& point)
{
// Be sure both are 2-Dimensional
assert_dimension<Box, 2>();
assert_dimension<Point, 2>();
// Copy coordinates
typedef typename coordinate_type<Point>::type coordinate_type;
geometry::set<0>(point, boost::numeric_cast<coordinate_type>(get<Corner1, 0>(box)));
geometry::set<1>(point, boost::numeric_cast<coordinate_type>(get<Corner2, 1>(box)));
}
template
<
typename Geometry, typename Point,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct assign_point_to_index
{
static inline void apply(Point const& point, Geometry& geometry)
{
geometry::set<Index, Dimension>(geometry, boost::numeric_cast
<
typename coordinate_type<Geometry>::type
>(geometry::get<Dimension>(point)));
assign_point_to_index
<
Geometry, Point, Index, Dimension + 1, DimensionCount
>::apply(point, geometry);
}
};
template
<
typename Geometry, typename Point,
std::size_t Index,
std::size_t DimensionCount
>
struct assign_point_to_index
<
Geometry, Point,
Index,
DimensionCount, DimensionCount
>
{
static inline void apply(Point const& , Geometry& )
{
}
};
template
<
typename Geometry, typename Point,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct assign_point_from_index
{
static inline void apply(Geometry const& geometry, Point& point)
{
geometry::set<Dimension>( point, boost::numeric_cast
<
typename coordinate_type<Point>::type
>(geometry::get<Index, Dimension>(geometry)));
assign_point_from_index
<
Geometry, Point, Index, Dimension + 1, DimensionCount
>::apply(geometry, point);
}
};
template
<
typename Geometry, typename Point,
std::size_t Index,
std::size_t DimensionCount
>
struct assign_point_from_index
<
Geometry, Point,
Index,
DimensionCount, DimensionCount
>
{
static inline void apply(Geometry const&, Point&)
{
}
};
template <typename Geometry>
struct assign_2d_box_or_segment
{
typedef typename coordinate_type<Geometry>::type coordinate_type;
// Here we assign 4 coordinates to a box of segment
// -> Most logical is: x1,y1,x2,y2
// In case the user reverses x1/x2 or y1/y2, for a box, we could reverse them (THAT IS NOT IMPLEMENTED)
template <typename Type>
static inline void apply(Geometry& geometry,
Type const& x1, Type const& y1, Type const& x2, Type const& y2)
{
geometry::set<0, 0>(geometry, boost::numeric_cast<coordinate_type>(x1));
geometry::set<0, 1>(geometry, boost::numeric_cast<coordinate_type>(y1));
geometry::set<1, 0>(geometry, boost::numeric_cast<coordinate_type>(x2));
geometry::set<1, 1>(geometry, boost::numeric_cast<coordinate_type>(y2));
}
};
}} // namespace detail::assign
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename GeometryTag, typename Geometry, std::size_t DimensionCount>
struct assign
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template <typename Point>
struct assign<point_tag, Point, 2>
{
typedef typename coordinate_type<Point>::type coordinate_type;
template <typename T>
static inline void apply(Point& point, T const& c1, T const& c2)
{
set<0>(point, boost::numeric_cast<coordinate_type>(c1));
set<1>(point, boost::numeric_cast<coordinate_type>(c2));
}
};
template <typename Point>
struct assign<point_tag, Point, 3>
{
typedef typename coordinate_type<Point>::type coordinate_type;
template <typename T>
static inline void apply(Point& point, T const& c1, T const& c2, T const& c3)
{
set<0>(point, boost::numeric_cast<coordinate_type>(c1));
set<1>(point, boost::numeric_cast<coordinate_type>(c2));
set<2>(point, boost::numeric_cast<coordinate_type>(c3));
}
};
template <typename Box>
struct assign<box_tag, Box, 2>
: detail::assign::assign_2d_box_or_segment<Box>
{};
template <typename Segment>
struct assign<segment_tag, Segment, 2>
: detail::assign::assign_2d_box_or_segment<Segment>
{};
template <typename GeometryTag, typename Geometry>
struct assign_zero {};
template <typename Point>
struct assign_zero<point_tag, Point>
: detail::assign::assign_zero_point<Point>
{};
template <typename Box>
struct assign_zero<box_tag, Box>
: detail::assign::assign_zero_box_or_segment<Box>
{};
template <typename Segment>
struct assign_zero<segment_tag, Segment>
: detail::assign::assign_zero_box_or_segment<Segment>
{};
template <typename GeometryTag, typename Geometry>
struct assign_inverse {};
template <typename Box>
struct assign_inverse<box_tag, Box>
: detail::assign::assign_inverse_box_or_segment<Box>
{};
template <typename Segment>
struct assign_inverse<segment_tag, Segment>
: detail::assign::assign_inverse_box_or_segment<Segment>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Assign two coordinates to a geometry (usually a 2D point)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 \param_x
\param c2 \param_y
\qbk{distinguish, 2 coordinate values}
\qbk{
[heading Example]
[assign_2d_point] [assign_2d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
{
concept::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2);
}
/*!
\brief Assign three values to a geometry (usually a 3D point)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 \param_x
\param c2 \param_y
\param c3 \param_z
\qbk{distinguish, 3 coordinate values}
\qbk{
[heading Example]
[assign_3d_point] [assign_3d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry,
Type const& c1, Type const& c2, Type const& c3)
{
concept::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3);
}
/*!
\brief Assign four values to a geometry (usually a box or segment)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 First coordinate (usually x1)
\param c2 Second coordinate (usually y1)
\param c3 Third coordinate (usually x2)
\param c4 Fourth coordinate (usually y2)
\qbk{distinguish, 4 coordinate values}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry,
Type const& c1, Type const& c2, Type const& c3, Type const& c4)
{
concept::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3, c4);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP

View File

@@ -0,0 +1,38 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_CALCULATE_NULL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template<typename ReturnType, typename Geometry, typename Strategy>
struct calculate_null
{
static inline ReturnType apply(Geometry const& , Strategy const&)
{
return ReturnType();
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP

View File

@@ -0,0 +1,64 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_CALCULATE_SUM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template
<
typename ReturnType,
typename Polygon,
typename Strategy,
typename Policy
>
class calculate_polygon_sum
{
template <typename Rings>
static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy)
{
ReturnType sum = ReturnType();
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
sum += Policy::apply(*it, strategy);
}
return sum;
}
public :
static inline ReturnType apply(Polygon const& poly, Strategy const& strategy)
{
return Policy::apply(exterior_ring(poly), strategy)
+ sum_interior_rings(interior_rings(poly), strategy)
;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP

View File

@@ -0,0 +1,68 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_CONVERT_POINT_TO_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
// Note: extracted from "convert.hpp" to avoid circular references convert/append
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount>
struct point_to_point
{
static inline void apply(Source const& source, Destination& destination)
{
typedef typename coordinate_type<Destination>::type coordinate_type;
set<Dimension>(destination, boost::numeric_cast<coordinate_type>(get<Dimension>(source)));
point_to_point<Source, Destination, Dimension + 1, DimensionCount>::apply(source, destination);
}
};
template <typename Source, typename Destination, std::size_t DimensionCount>
struct point_to_point<Source, Destination, DimensionCount, DimensionCount>
{
static inline void apply(Source const& , Destination& )
{}
};
template <typename Source, typename Destination>
inline void convert_point_to_point(Source const& source, Destination& destination)
{
point_to_point<Source, Destination, 0, dimension<Destination>::value>::apply(source, destination);
}
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP

View File

@@ -0,0 +1,225 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_DISJOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
// Note: contrary to most files, the geometry::detail::disjoint namespace
// is partly implemented in a separate file, to avoid circular references
// disjoint -> get_turns -> disjoint
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
struct disjoint_interrupt_policy
{
static bool const enabled = true;
bool has_intersections;
inline disjoint_interrupt_policy()
: has_intersections(false)
{}
template <typename Range>
inline bool apply(Range const& range)
{
// If there is any IP in the range, it is NOT disjoint
if (boost::size(range) > 0)
{
has_intersections = true;
return true;
}
return false;
}
};
template
<
typename Point1, typename Point2,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_point
{
static inline bool apply(Point1 const& p1, Point2 const& p2)
{
if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
{
return true;
}
return point_point
<
Point1, Point2,
Dimension + 1, DimensionCount
>::apply(p1, p2);
}
};
template <typename Point1, typename Point2, std::size_t DimensionCount>
struct point_point<Point1, Point2, DimensionCount, DimensionCount>
{
static inline bool apply(Point1 const& , Point2 const& )
{
return false;
}
};
template
<
typename Point, typename Box,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_box
{
static inline bool apply(Point const& point, Box const& box)
{
if (get<Dimension>(point) < get<min_corner, Dimension>(box)
|| get<Dimension>(point) > get<max_corner, Dimension>(box))
{
return true;
}
return point_box
<
Point, Box,
Dimension + 1, DimensionCount
>::apply(point, box);
}
};
template <typename Point, typename Box, std::size_t DimensionCount>
struct point_box<Point, Box, DimensionCount, DimensionCount>
{
static inline bool apply(Point const& , Box const& )
{
return false;
}
};
template
<
typename Box1, typename Box2,
std::size_t Dimension, std::size_t DimensionCount
>
struct box_box
{
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
{
return true;
}
if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
{
return true;
}
return box_box
<
Box1, Box2,
Dimension + 1, DimensionCount
>::apply(box1, box2);
}
};
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct box_box<Box1, Box2, DimensionCount, DimensionCount>
{
static inline bool apply(Box1 const& , Box2 const& )
{
return false;
}
};
/*!
\brief Internal utility function to detect of boxes are disjoint
\note Is used from other algorithms, declared separately
to avoid circular references
*/
template <typename Box1, typename Box2>
inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
{
return box_box
<
Box1, Box2,
0, dimension<Box1>::type::value
>::apply(box1, box2);
}
/*!
\brief Internal utility function to detect of points are disjoint
\note To avoid circular references
*/
template <typename Point1, typename Point2>
inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
{
return point_point
<
Point1, Point2,
0, dimension<Point1>::type::value
>::apply(point1, point2);
}
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace equals
{
/*!
\brief Internal utility function to detect of points are disjoint
\note To avoid circular references
*/
template <typename Point1, typename Point2>
inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
{
return ! detail::disjoint::disjoint_point_point(point1, point2);
}
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP

View File

@@ -0,0 +1,315 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_EQUALS_COLLECT_VECTORS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
// TODO: if Boost.LA of Emil Dotchevski is accepted, adapt this
template <typename T>
struct collected_vector
{
typedef T type;
inline collected_vector()
{}
inline collected_vector(T const& px, T const& py,
T const& pdx, T const& pdy)
: x(px)
, y(py)
, dx(pdx)
, dy(pdy)
, dx_0(T())
, dy_0(T())
{}
T x, y;
T dx, dy;
T dx_0, dy_0;
// For sorting
inline bool operator<(collected_vector<T> const& other) const
{
if (math::equals(x, other.x))
{
if (math::equals(y, other.y))
{
if (math::equals(dx, other.dx))
{
return dy < other.dy;
}
return dx < other.dx;
}
return y < other.y;
}
return x < other.x;
}
inline bool same_direction(collected_vector<T> const& other) const
{
// For high precision arithmetic, we have to be
// more relaxed then using ==
// Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
// is not always true (at least, it is not for ttmath)
return math::equals_with_epsilon(dx, other.dx)
&& math::equals_with_epsilon(dy, other.dy);
}
// For std::equals
inline bool operator==(collected_vector<T> const& other) const
{
return math::equals(x, other.x)
&& math::equals(y, other.y)
&& same_direction(other);
}
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace collect_vectors
{
template <typename Range, typename Collection>
struct range_collect_vectors
{
typedef typename boost::range_value<Collection>::type item_type;
typedef typename item_type::type calculation_type;
static inline void apply(Collection& collection, Range const& range)
{
if (boost::size(range) < 2)
{
return;
}
typedef typename boost::range_iterator<Range const>::type iterator;
bool first = true;
iterator it = boost::begin(range);
for (iterator prev = it++;
it != boost::end(range);
prev = it++)
{
typename boost::range_value<Collection>::type v;
v.x = get<0>(*prev);
v.y = get<1>(*prev);
v.dx = get<0>(*it) - v.x;
v.dy = get<1>(*it) - v.y;
v.dx_0 = v.dx;
v.dy_0 = v.dy;
// Normalize the vector -> this results in points+direction
// and is comparible between geometries
calculation_type magnitude = sqrt(
boost::numeric_cast<calculation_type>(v.dx * v.dx + v.dy * v.dy));
// Avoid non-duplicate points (AND division by zero)
if (magnitude > 0)
{
v.dx /= magnitude;
v.dy /= magnitude;
// Avoid non-direction changing points
if (first || ! v.same_direction(collection.back()))
{
collection.push_back(v);
}
first = false;
}
}
// If first one has same direction as last one, remove first one
if (boost::size(collection) > 1
&& collection.front().same_direction(collection.back()))
{
collection.erase(collection.begin());
}
}
};
template <typename Box, typename Collection>
struct box_collect_vectors
{
// Calculate on coordinate type, but if it is integer,
// then use double
typedef typename boost::range_value<Collection>::type item_type;
typedef typename item_type::type calculation_type;
static inline void apply(Collection& collection, Box const& box)
{
typename point_type<Box>::type lower_left, lower_right,
upper_left, upper_right;
geometry::detail::assign_box_corners(box, lower_left, lower_right,
upper_left, upper_right);
typedef typename boost::range_value<Collection>::type item;
collection.push_back(item(get<0>(lower_left), get<1>(lower_left), 0, 1));
collection.push_back(item(get<0>(upper_left), get<1>(upper_left), 1, 0));
collection.push_back(item(get<0>(upper_right), get<1>(upper_right), 0, -1));
collection.push_back(item(get<0>(lower_right), get<1>(lower_right), -1, 0));
}
};
template <typename Polygon, typename Collection>
struct polygon_collect_vectors
{
static inline void apply(Collection& collection, Polygon const& polygon)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef range_collect_vectors<ring_type, Collection> per_range;
per_range::apply(collection, exterior_ring(polygon));
typename interior_return_type<Polygon const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
per_range::apply(collection, *it);
}
}
};
template <typename MultiGeometry, typename Collection, typename SinglePolicy>
struct multi_collect_vectors
{
static inline void apply(Collection& collection, MultiGeometry const& multi)
{
for (typename boost::range_iterator<MultiGeometry const>::type
it = boost::begin(multi);
it != boost::end(multi);
++it)
{
SinglePolicy::apply(collection, *it);
}
}
};
}} // namespace detail::collect_vectors
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Collection,
typename Geometry
>
struct collect_vectors
{
static inline void apply(Collection&, Geometry const&)
{}
};
template <typename Collection, typename Box>
struct collect_vectors<box_tag, Collection, Box>
: detail::collect_vectors::box_collect_vectors<Box, Collection>
{};
template <typename Collection, typename Ring>
struct collect_vectors<ring_tag, Collection, Ring>
: detail::collect_vectors::range_collect_vectors<Ring, Collection>
{};
template <typename Collection, typename LineString>
struct collect_vectors<linestring_tag, Collection, LineString>
: detail::collect_vectors::range_collect_vectors<LineString, Collection>
{};
template <typename Collection, typename Polygon>
struct collect_vectors<polygon_tag, Collection, Polygon>
: detail::collect_vectors::polygon_collect_vectors<Polygon, Collection>
{};
template <typename Collection, typename MultiPolygon>
struct collect_vectors<multi_polygon_tag, Collection, MultiPolygon>
: detail::collect_vectors::multi_collect_vectors
<
MultiPolygon,
Collection,
detail::collect_vectors::polygon_collect_vectors
<
typename boost::range_value<MultiPolygon>::type,
Collection
>
>
{};
} // namespace dispatch
#endif
/*!
\ingroup collect_vectors
\tparam Collection Collection type, should be e.g. std::vector<>
\tparam Geometry geometry type
\param collection the collection of vectors
\param geometry the geometry to make collect_vectors
*/
template <typename Collection, typename Geometry>
inline void collect_vectors(Collection& collection, Geometry const& geometry)
{
concept::check<Geometry const>();
dispatch::collect_vectors
<
typename tag<Geometry>::type,
Collection,
Geometry
>::apply(collection, geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP

View File

@@ -0,0 +1,125 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_FOR_EACH_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
#include <boost/concept/requires.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace for_each
{
template <typename Range, typename Actor, bool IsConst>
struct fe_range_range
{
static inline void apply(
typename add_const_if_c<IsConst, Range>::type& range,
Actor& actor)
{
actor.apply(range);
}
};
template <typename Polygon, typename Actor, bool IsConst>
struct fe_range_polygon
{
static inline void apply(
typename add_const_if_c<IsConst, Polygon>::type& polygon,
Actor& actor)
{
actor.apply(exterior_ring(polygon));
// TODO: If some flag says true, also do the inner rings.
// for convex hull, it's not necessary
}
};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename Actor,
bool IsConst
>
struct for_each_range {};
template <typename Linestring, typename Actor, bool IsConst>
struct for_each_range<linestring_tag, Linestring, Actor, IsConst>
: detail::for_each::fe_range_range<Linestring, Actor, IsConst>
{};
template <typename Ring, typename Actor, bool IsConst>
struct for_each_range<ring_tag, Ring, Actor, IsConst>
: detail::for_each::fe_range_range<Ring, Actor, IsConst>
{};
template <typename Polygon, typename Actor, bool IsConst>
struct for_each_range<polygon_tag, Polygon, Actor, IsConst>
: detail::for_each::fe_range_polygon<Polygon, Actor, IsConst>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace detail
{
template <typename Geometry, typename Actor>
inline void for_each_range(Geometry const& geometry, Actor& actor)
{
dispatch::for_each_range
<
typename tag<Geometry>::type,
Geometry,
Actor,
true
>::apply(geometry, actor);
}
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP

View File

@@ -0,0 +1,120 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 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_HAS_SELF_INTERSECTIONS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP
#include <deque>
#include <boost/range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/util/write_dsv.hpp>
#endif
namespace boost { namespace geometry
{
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
/*!
\brief Overlay Invalid Input Exception
\ingroup overlay
\details The overlay_invalid_input_exception is thrown at invalid input
*/
class overlay_invalid_input_exception : public geometry::exception
{
public:
inline overlay_invalid_input_exception() {}
virtual char const* what() const throw()
{
return "Boost.Geometry Overlay invalid input exception";
}
};
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename Geometry>
inline bool has_self_intersections(Geometry const& geometry)
{
typedef typename point_type<Geometry>::type point_type;
typedef detail::overlay::turn_info<point_type> turn_info;
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
geometry::self_turns<detail::overlay::assign_null_policy>(geometry, turns, policy);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
#endif
for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
it != boost::end(turns); ++it)
{
turn_info const& info = *it;
bool const both_union_turn =
info.operations[0].operation == detail::overlay::operation_union
&& info.operations[1].operation == detail::overlay::operation_union;
bool const both_intersection_turn =
info.operations[0].operation == detail::overlay::operation_intersection
&& info.operations[1].operation == detail::overlay::operation_intersection;
bool const valid = (both_union_turn || both_intersection_turn)
&& (info.method == detail::overlay::method_touch
|| info.method == detail::overlay::method_touch_interior);
if (! valid)
{
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
if (first)
{
std::cout << "turn points: " << std::endl;
first = false;
}
std::cout << method_char(info.method);
for (int i = 0; i < 2; i++)
{
std::cout << " " << operation_char(info.operations[i].operation);
}
std::cout << " " << geometry::dsv(info.point) << std::endl;
#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
throw overlay_invalid_input_exception();
#endif
}
}
return false;
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP

View File

@@ -0,0 +1,50 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_NOT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Structure negating the result of specified policy
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Policy
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return Negation of the result of the policy
*/
template <typename Geometry1, typename Geometry2, typename Policy>
struct not_
{
static inline bool apply(Geometry1 const &geometry1, Geometry2 const& geometry2)
{
return ! Policy::apply(geometry1, geometry2);
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP

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

View File

@@ -0,0 +1,389 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 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_PARTITION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
#include <vector>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace partition
{
typedef std::vector<std::size_t> index_vector_type;
template <int Dimension, typename Box>
inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
{
typedef typename coordinate_type<Box>::type ctype;
// Divide input box into two parts, e.g. left/right
ctype two = 2;
ctype mid = (geometry::get<min_corner, Dimension>(box)
+ geometry::get<max_corner, Dimension>(box)) / two;
lower_box = box;
upper_box = box;
geometry::set<max_corner, Dimension>(lower_box, mid);
geometry::set<min_corner, Dimension>(upper_box, mid);
}
// Divide collection into three subsets: lower, upper and oversized (not-fitting)
// (lower == left or bottom, upper == right or top)
template <typename OverlapsPolicy, typename InputCollection, typename Box>
static inline void divide_into_subsets(Box const& lower_box, Box const& upper_box,
InputCollection const& collection,
index_vector_type const& input,
index_vector_type& lower,
index_vector_type& upper,
index_vector_type& exceeding)
{
typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
for(index_iterator_type it = boost::begin(input);
it != boost::end(input);
++it)
{
bool const lower_overlapping = OverlapsPolicy::apply(lower_box, collection[*it]);
bool const upper_overlapping = OverlapsPolicy::apply(upper_box, collection[*it]);
if (lower_overlapping && upper_overlapping)
{
exceeding.push_back(*it);
}
else if (lower_overlapping)
{
lower.push_back(*it);
}
else if (upper_overlapping)
{
upper.push_back(*it);
}
else
{
// Is nowhere! Should not occur!
BOOST_ASSERT(true);
}
}
}
// Match collection with itself
template <typename InputCollection, typename Policy>
static inline void handle_one(InputCollection const& collection,
index_vector_type const& input,
Policy& policy)
{
typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
// Quadratic behaviour at lowest level (lowest quad, or all exceeding)
for(index_iterator_type it1 = boost::begin(input); it1 != boost::end(input); ++it1)
{
index_iterator_type it2 = it1;
for(++it2; it2 != boost::end(input); ++it2)
{
policy.apply(collection[*it1], collection[*it2]);
}
}
}
// Match collection 1 with collection 2
template <typename InputCollection, typename Policy>
static inline void handle_two(
InputCollection const& collection1, index_vector_type const& input1,
InputCollection const& collection2, index_vector_type const& input2,
Policy& policy)
{
typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
for(index_iterator_type it1 = boost::begin(input1); it1 != boost::end(input1); ++it1)
{
for(index_iterator_type it2 = boost::begin(input2); it2 != boost::end(input2); ++it2)
{
policy.apply(collection1[*it1], collection2[*it2]);
}
}
}
template
<
int Dimension,
typename Box,
typename OverlapsPolicy,
typename VisitBoxPolicy
>
class partition_one_collection
{
typedef std::vector<std::size_t> index_vector_type;
typedef typename coordinate_type<Box>::type ctype;
typedef partition_one_collection
<
1 - Dimension,
Box,
OverlapsPolicy,
VisitBoxPolicy
> sub_divide;
template <typename InputCollection, typename Policy>
static inline void next_level(Box const& box,
InputCollection const& collection,
index_vector_type const& input,
int level, int min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
if (boost::size(input) > 0)
{
if (boost::size(input) > min_elements && level < 100)
{
sub_divide::apply(box, collection, input, level + 1, min_elements, policy, box_policy);
}
else
{
handle_one(collection, input, policy);
}
}
}
public :
template <typename InputCollection, typename Policy>
static inline void apply(Box const& box,
InputCollection const& collection,
index_vector_type const& input,
int level,
int min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
box_policy.apply(box, level);
Box lower_box, upper_box;
divide_box<Dimension>(box, lower_box, upper_box);
index_vector_type lower, upper, exceeding;
divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection, input, lower, upper, exceeding);
if (boost::size(exceeding) > 0)
{
// All what is not fitting a partition should be combined
// with each other, and with all which is fitting.
handle_one(collection, exceeding, policy);
handle_two(collection, exceeding, collection, lower, policy);
handle_two(collection, exceeding, collection, upper, policy);
}
// Recursively call operation both parts
next_level(lower_box, collection, lower, level, min_elements, policy, box_policy);
next_level(upper_box, collection, upper, level, min_elements, policy, box_policy);
}
};
template
<
int Dimension,
typename Box,
typename OverlapsPolicy,
typename VisitBoxPolicy
>
class partition_two_collections
{
typedef std::vector<std::size_t> index_vector_type;
typedef typename coordinate_type<Box>::type ctype;
typedef partition_two_collections
<
1 - Dimension,
Box,
OverlapsPolicy,
VisitBoxPolicy
> sub_divide;
template <typename InputCollection, typename Policy>
static inline void next_level(Box const& box,
InputCollection const& collection1, index_vector_type const& input1,
InputCollection const& collection2, index_vector_type const& input2,
int level, int min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
if (boost::size(input1) > 0 && boost::size(input2) > 0)
{
if (boost::size(input1) > min_elements
&& boost::size(input2) > min_elements
&& level < 100)
{
sub_divide::apply(box, collection1, input1, collection2, input2, level + 1, min_elements, policy, box_policy);
}
else
{
box_policy.apply(box, level + 1);
handle_two(collection1, input1, collection2, input2, policy);
}
}
}
public :
template <typename InputCollection, typename Policy>
static inline void apply(Box const& box,
InputCollection const& collection1, index_vector_type const& input1,
InputCollection const& collection2, index_vector_type const& input2,
int level,
int min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
box_policy.apply(box, level);
Box lower_box, upper_box;
divide_box<Dimension>(box, lower_box, upper_box);
index_vector_type lower1, upper1, exceeding1;
index_vector_type lower2, upper2, exceeding2;
divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1, input1, lower1, upper1, exceeding1);
divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2, input2, lower2, upper2, exceeding2);
if (boost::size(exceeding1) > 0)
{
// All exceeding from 1 with 2:
handle_two(collection1, exceeding1, collection2, exceeding2, policy);
// All exceeding from 1 with lower and upper of 2:
handle_two(collection1, exceeding1, collection2, lower2, policy);
handle_two(collection1, exceeding1, collection2, upper2, policy);
}
if (boost::size(exceeding2) > 0)
{
// All exceeding from 2 with lower and upper of 1:
handle_two(collection1, lower1, collection2, exceeding2, policy);
handle_two(collection1, upper1, collection2, exceeding2, policy);
}
next_level(lower_box, collection1, lower1, collection2, lower2, level, min_elements, policy, box_policy);
next_level(upper_box, collection1, upper1, collection2, upper2, level, min_elements, policy, box_policy);
}
};
}} // namespace detail::partition
struct visit_no_policy
{
template <typename Box>
static inline void apply(Box const&, int )
{}
};
template
<
typename Box,
typename ExpandPolicy,
typename OverlapsPolicy,
typename VisitBoxPolicy = visit_no_policy
>
class partition
{
typedef std::vector<std::size_t> index_vector_type;
template <typename InputCollection>
static inline void expand_to_collection(InputCollection const& collection, Box& total, index_vector_type& index_vector)
{
std::size_t index = 0;
for(typename boost::range_iterator<InputCollection const>::type it
= boost::begin(collection);
it != boost::end(collection);
++it, ++index)
{
ExpandPolicy::apply(total, *it);
index_vector.push_back(index);
}
}
public :
template <typename InputCollection, typename VisitPolicy>
static inline void apply(InputCollection const& collection,
VisitPolicy& visitor,
int min_elements = 16,
VisitBoxPolicy box_visitor = visit_no_policy()
)
{
if (boost::size(collection) > min_elements)
{
index_vector_type index_vector;
Box total;
assign_inverse(total);
expand_to_collection(collection, total, index_vector);
detail::partition::partition_one_collection
<
0, Box,
OverlapsPolicy,
VisitBoxPolicy
>::apply(total, collection, index_vector, 0, min_elements, visitor, box_visitor);
}
else
{
typedef typename boost::range_iterator<InputCollection const>::type iterator_type;
for(iterator_type it1 = boost::begin(collection); it1 != boost::end(collection); ++it1)
{
iterator_type it2 = it1;
for(++it2; it2 != boost::end(collection); ++it2)
{
visitor.apply(*it1, *it2);
}
}
}
}
template <typename InputCollection, typename VisitPolicy>
static inline void apply(InputCollection const& collection1,
InputCollection const& collection2,
VisitPolicy& visitor,
int min_elements = 16,
VisitBoxPolicy box_visitor = visit_no_policy()
)
{
if (boost::size(collection1) > min_elements && boost::size(collection2) > min_elements)
{
index_vector_type index_vector1, index_vector2;
Box total;
assign_inverse(total);
expand_to_collection(collection1, total, index_vector1);
expand_to_collection(collection2, total, index_vector2);
detail::partition::partition_two_collections
<
0, Box, OverlapsPolicy, VisitBoxPolicy
>::apply(total,
collection1, index_vector1,
collection2, index_vector2,
0, min_elements, visitor, box_visitor);
}
else
{
typedef typename boost::range_iterator<InputCollection const>::type iterator_type;
for(iterator_type it1 = boost::begin(collection1); it1 != boost::end(collection1); ++it1)
{
for(iterator_type it2 = boost::begin(collection2); it2 != boost::end(collection2); ++it2)
{
visitor.apply(*it1, *it2);
}
}
}
}
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP

View File

@@ -0,0 +1,243 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.Dimension. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace point_on_border
{
template<typename Point>
struct get_point
{
static inline bool apply(Point& destination, Point const& source, bool)
{
destination = source;
return true;
}
};
template<typename Point, std::size_t Dimension, std::size_t DimensionCount>
struct midpoint_helper
{
static inline bool apply(Point& p, Point const& p1, Point const& p2)
{
typename coordinate_type<Point>::type const two = 2;
set<Dimension>(p,
(get<Dimension>(p1) + get<Dimension>(p2)) / two);
return midpoint_helper<Point, Dimension + 1, DimensionCount>::apply(p, p1, p2);
}
};
template <typename Point, std::size_t DimensionCount>
struct midpoint_helper<Point, DimensionCount, DimensionCount>
{
static inline bool apply(Point& , Point const& , Point const& )
{
return true;
}
};
template<typename Point, typename Range>
struct point_on_range
{
static inline bool apply(Point& point, Range const& range, bool midpoint)
{
const std::size_t n = boost::size(range);
if (midpoint && n > 1)
{
typedef typename boost::range_iterator
<
Range const
>::type iterator;
iterator it = boost::begin(range);
iterator prev = it++;
while (it != boost::end(range)
&& detail::equals::equals_point_point(*it, *prev))
{
prev = it++;
}
if (it != boost::end(range))
{
return midpoint_helper
<
Point,
0, dimension<Point>::value
>::apply(point, *prev, *it);
}
}
if (n > 0)
{
point = *boost::begin(range);
return true;
}
return false;
}
};
template<typename Point, typename Polygon>
struct point_on_polygon
{
static inline bool apply(Point& point, Polygon const& polygon, bool midpoint)
{
return point_on_range
<
Point,
typename ring_type<Polygon>::type
>::apply(point, exterior_ring(polygon), midpoint);
}
};
template<typename Point, typename Box>
struct point_on_box
{
static inline bool apply(Point& point, Box const& box, bool midpoint)
{
if (midpoint)
{
Point p1, p2;
detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, p1);
detail::assign::assign_box_2d_corner<max_corner, min_corner>(box, p2);
midpoint_helper
<
Point,
0, dimension<Point>::value
>::apply(point, p1, p2);
}
else
{
detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point);
}
return true;
}
};
}} // namespace detail::point_on_border
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename GeometryTag,
typename Point,
typename Geometry
>
struct point_on_border
{};
template<typename Point>
struct point_on_border<point_tag, Point, Point>
: detail::point_on_border::get_point<Point>
{};
template<typename Point, typename Linestring>
struct point_on_border<linestring_tag, Point, Linestring>
: detail::point_on_border::point_on_range<Point, Linestring>
{};
template<typename Point, typename Ring>
struct point_on_border<ring_tag, Point, Ring>
: detail::point_on_border::point_on_range<Point, Ring>
{};
template<typename Point, typename Polygon>
struct point_on_border<polygon_tag, Point, Polygon>
: detail::point_on_border::point_on_polygon<Point, Polygon>
{};
template<typename Point, typename Box>
struct point_on_border<box_tag, Point, Box>
: detail::point_on_border::point_on_box<Point, Box>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Take point on a border
\ingroup overlay
\tparam Geometry geometry type. This also defines the type of the output point
\param point to assign
\param geometry geometry to take point from
\param midpoint boolean flag, true if the point should not be a vertex, but some point
in between of two vertices
\return TRUE if successful, else false.
It is only false if polygon/line have no points
\note for a polygon, it is always a point on the exterior ring
\note for take_midpoint, it is not taken from two consecutive duplicate vertices,
(unless there are no other).
*/
template <typename Point, typename Geometry>
inline bool point_on_border(Point& point,
Geometry const& geometry,
bool midpoint = false)
{
concept::check<Point>();
concept::check<Geometry const>();
typedef typename point_type<Geometry>::type point_type;
return dispatch::point_on_border
<
typename tag<Geometry>::type,
Point,
Geometry
>::apply(point, geometry, midpoint);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP

View File

@@ -0,0 +1,70 @@
// 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_RING_IDENTIFIER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
namespace boost { namespace geometry
{
// Ring Identifier. It is currently: source,multi,ring
struct ring_identifier
{
inline ring_identifier()
: source_index(-1)
, multi_index(-1)
, ring_index(-1)
{}
inline ring_identifier(int src, int mul, int rin)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
{}
inline bool operator<(ring_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
;
}
inline bool operator==(ring_identifier const& other) const
{
return source_index == other.source_index
&& ring_index == other.ring_index
&& multi_index == other.multi_index
;
}
#if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
friend std::ostream& operator<<(std::ostream &os, ring_identifier const& ring_id)
{
os << "(s:" << ring_id.source_index;
if (ring_id.ring_index >= 0) os << ", r:" << ring_id.ring_index;
if (ring_id.multi_index >= 0) os << ", m:" << ring_id.multi_index;
os << ")";
return os;
}
#endif
int source_index;
int multi_index;
int ring_index;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP

View File

@@ -0,0 +1,131 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_SECTIONS_RANGE_BY_SECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace section
{
template <typename Range, typename Section>
struct full_section_range
{
static inline Range const& apply(Range const& range, Section const& section)
{
return range;
}
};
template <typename Polygon, typename Section>
struct full_section_polygon
{
static inline typename ring_return_type<Polygon const>::type apply(Polygon const& polygon, Section const& section)
{
return section.ring_id.ring_index < 0
? geometry::exterior_ring(polygon)
: geometry::interior_rings(polygon)[section.ring_id.ring_index];
}
};
}} // namespace detail::section
#endif
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename Section
>
struct range_by_section
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template <typename LineString, typename Section>
struct range_by_section<linestring_tag, LineString, Section>
: detail::section::full_section_range<LineString, Section>
{};
template <typename Ring, typename Section>
struct range_by_section<ring_tag, Ring, Section>
: detail::section::full_section_range<Ring, Section>
{};
template <typename Polygon, typename Section>
struct range_by_section<polygon_tag, Polygon, Section>
: detail::section::full_section_polygon<Polygon, Section>
{};
} // namespace dispatch
#endif
/*!
\brief Get full ring (exterior, one of interiors, one from multi)
indicated by the specified section
\ingroup sectionalize
\tparam Geometry type
\tparam Section type of section to get from
\param geometry geometry to take section of
\param section structure with section
*/
template <typename Geometry, typename Section>
inline typename ring_return_type<Geometry const>::type
range_by_section(Geometry const& geometry, Section const& section)
{
concept::check<Geometry const>();
return dispatch::range_by_section
<
typename tag<Geometry>::type,
Geometry,
Section
>::apply(geometry, section);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP

View File

@@ -0,0 +1,648 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_SECTIONS_SECTIONALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
#include <cstddef>
#include <vector>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/point_order.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/geometries/segment.hpp>
namespace boost { namespace geometry
{
/*!
\brief Structure containing section information
\details Section information consists of a bounding box, direction
information (if it is increasing or decreasing, per dimension),
index information (begin-end, ring, multi) and the number of
segments in this section
\tparam Box box-type
\tparam DimensionCount number of dimensions for this section
\ingroup sectionalize
*/
template <typename Box, std::size_t DimensionCount>
struct section
{
typedef Box box_type;
int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
int directions[DimensionCount];
ring_identifier ring_id;
Box bounding_box;
int begin_index;
int end_index;
std::size_t count;
std::size_t range_count;
bool duplicate;
int non_duplicate_index;
inline section()
: id(-1)
, begin_index(-1)
, end_index(-1)
, count(0)
, range_count(0)
, duplicate(false)
, non_duplicate_index(-1)
{
assign_inverse(bounding_box);
for (register std::size_t i = 0; i < DimensionCount; i++)
{
directions[i] = 0;
}
}
};
/*!
\brief Structure containing a collection of sections
\note Derived from a vector, proves to be faster than of deque
\note vector might be templated in the future
\ingroup sectionalize
*/
template <typename Box, std::size_t DimensionCount>
struct sections : std::vector<section<Box, DimensionCount> >
{
typedef Box box_type;
static std::size_t const value = DimensionCount;
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace sectionalize
{
template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
struct get_direction_loop
{
typedef typename coordinate_type<Segment>::type coordinate_type;
static inline void apply(Segment const& seg,
int directions[DimensionCount])
{
coordinate_type const diff =
geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
coordinate_type zero = coordinate_type();
directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
get_direction_loop
<
Segment, Dimension + 1, DimensionCount
>::apply(seg, directions);
}
};
template <typename Segment, std::size_t DimensionCount>
struct get_direction_loop<Segment, DimensionCount, DimensionCount>
{
static inline void apply(Segment const&, int [DimensionCount])
{}
};
template <typename T, std::size_t Dimension, std::size_t DimensionCount>
struct copy_loop
{
static inline void apply(T const source[DimensionCount],
T target[DimensionCount])
{
target[Dimension] = source[Dimension];
copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
}
};
template <typename T, std::size_t DimensionCount>
struct copy_loop<T, DimensionCount, DimensionCount>
{
static inline void apply(T const [DimensionCount], T [DimensionCount])
{}
};
template <typename T, std::size_t Dimension, std::size_t DimensionCount>
struct compare_loop
{
static inline bool apply(T const source[DimensionCount],
T const target[DimensionCount])
{
bool const not_equal = target[Dimension] != source[Dimension];
return not_equal
? false
: compare_loop
<
T, Dimension + 1, DimensionCount
>::apply(source, target);
}
};
template <typename T, std::size_t DimensionCount>
struct compare_loop<T, DimensionCount, DimensionCount>
{
static inline bool apply(T const [DimensionCount],
T const [DimensionCount])
{
return true;
}
};
template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
struct check_duplicate_loop
{
typedef typename coordinate_type<Segment>::type coordinate_type;
static inline bool apply(Segment const& seg)
{
if (! geometry::math::equals
(
geometry::get<0, Dimension>(seg),
geometry::get<1, Dimension>(seg)
)
)
{
return false;
}
return check_duplicate_loop
<
Segment, Dimension + 1, DimensionCount
>::apply(seg);
}
};
template <typename Segment, std::size_t DimensionCount>
struct check_duplicate_loop<Segment, DimensionCount, DimensionCount>
{
static inline bool apply(Segment const&)
{
return true;
}
};
template <typename T, std::size_t Dimension, std::size_t DimensionCount>
struct assign_loop
{
static inline void apply(T dims[DimensionCount], int const value)
{
dims[Dimension] = value;
assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
}
};
template <typename T, std::size_t DimensionCount>
struct assign_loop<T, DimensionCount, DimensionCount>
{
static inline void apply(T [DimensionCount], int const)
{
}
};
/// @brief Helper class to create sections of a part of a range, on the fly
template
<
typename Range, // Can be closeable_view
typename Point,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize_part
{
typedef model::referring_segment<Point const> segment_type;
typedef typename boost::range_value<Sections>::type section_type;
typedef typename boost::range_iterator<Range const>::type iterator_type;
static inline void apply(Sections& sections, section_type& section,
int& index, int& ndi,
Range const& range,
ring_identifier ring_id)
{
if (boost::size(range) <= index)
{
return;
}
if (index == 0)
{
ndi = 0;
}
iterator_type it = boost::begin(range);
it += index;
for(iterator_type previous = it++;
it != boost::end(range);
++previous, ++it, index++)
{
segment_type segment(*previous, *it);
int direction_classes[DimensionCount] = {0};
get_direction_loop
<
segment_type, 0, DimensionCount
>::apply(segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
// Those sections might be omitted, if wished, lateron
bool duplicate = false;
if (direction_classes[0] == 0)
{
// Recheck because ALL dimensions should be checked,
// not only first one.
// (DimensionCount might be < dimension<P>::value)
if (check_duplicate_loop
<
segment_type, 0, geometry::dimension<Point>::type::value
>::apply(segment)
)
{
duplicate = true;
// Change direction-info to force new section
// Note that wo consecutive duplicate segments will generate
// only one duplicate-section.
// Actual value is not important as long as it is not -1,0,1
assign_loop
<
int, 0, DimensionCount
>::apply(direction_classes, -99);
}
}
if (section.count > 0
&& (!compare_loop
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions)
|| section.count > MaxCount
)
)
{
sections.push_back(section);
section = section_type();
}
if (section.count == 0)
{
section.begin_index = index;
section.ring_id = ring_id;
section.duplicate = duplicate;
section.non_duplicate_index = ndi;
section.range_count = boost::size(range);
copy_loop
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions);
geometry::expand(section.bounding_box, *previous);
}
geometry::expand(section.bounding_box, *it);
section.end_index = index + 1;
section.count++;
if (! duplicate)
{
ndi++;
}
}
}
};
template
<
typename Range, closure_selector Closure, bool Reverse,
typename Point,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize_range
{
typedef typename closeable_view<Range const, Closure>::type cview_type;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type view_type;
static inline void apply(Range const& range, Sections& sections,
ring_identifier ring_id)
{
typedef model::referring_segment<Point const> segment_type;
cview_type cview(range);
view_type view(cview);
std::size_t const n = boost::size(view);
if (n == 0)
{
// Zero points, no section
return;
}
if (n == 1)
{
// Line with one point ==> no sections
return;
}
int index = 0;
int ndi = 0; // non duplicate index
typedef typename boost::range_value<Sections>::type section_type;
section_type section;
sectionalize_part
<
view_type, Point, Sections,
DimensionCount, MaxCount
>::apply(sections, section, index, ndi,
view, ring_id);
// Add last section if applicable
if (section.count > 0)
{
sections.push_back(section);
}
}
};
template
<
typename Polygon,
bool Reverse,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize_polygon
{
static inline void apply(Polygon const& poly, Sections& sections,
ring_identifier ring_id)
{
typedef typename point_type<Polygon>::type point_type;
typedef typename ring_type<Polygon>::type ring_type;
typedef sectionalize_range
<
ring_type, closure<Polygon>::value, Reverse,
point_type, Sections, DimensionCount, MaxCount
> sectionalizer_type;
ring_id.ring_index = -1;
sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index);
ring_id.ring_index++;
typename interior_return_type<Polygon const>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
++it, ++ring_id.ring_index)
{
sectionalizer_type::apply(*it, sections, ring_id);
}
}
};
template
<
typename Box,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize_box
{
static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id)
{
typedef typename point_type<Box>::type point_type;
assert_dimension<Box, 2>();
// Add all four sides of the 2D-box as separate section.
// Easiest is to convert it to a polygon.
// However, we don't have the polygon type
// (or polygon would be a helper-type).
// Therefore we mimic a linestring/std::vector of 5 points
// TODO: might be replaced by assign_box_corners_oriented
// or just "convert"
point_type ll, lr, ul, ur;
geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
std::vector<point_type> points;
points.push_back(ll);
points.push_back(ul);
points.push_back(ur);
points.push_back(lr);
points.push_back(ll);
sectionalize_range
<
std::vector<point_type>, closed, false,
point_type,
Sections,
DimensionCount,
MaxCount
>::apply(points, sections, ring_id);
}
};
template <typename Sections>
inline void set_section_unique_ids(Sections& sections)
{
// Set ID's.
int index = 0;
for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
it != boost::end(sections);
++it)
{
it->id = index++;
}
}
}} // namespace detail::sectionalize
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
bool Reverse,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template
<
typename Box,
bool Reverse,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount>
: detail::sectionalize::sectionalize_box
<
Box,
Sections,
DimensionCount,
MaxCount
>
{};
template
<
typename LineString,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize
<
linestring_tag,
LineString,
false,
Sections,
DimensionCount,
MaxCount
>
: detail::sectionalize::sectionalize_range
<
LineString, closed, false,
typename point_type<LineString>::type,
Sections,
DimensionCount,
MaxCount
>
{};
template
<
typename Ring,
bool Reverse,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount>
: detail::sectionalize::sectionalize_range
<
Ring, geometry::closure<Ring>::value, Reverse,
typename point_type<Ring>::type,
Sections,
DimensionCount,
MaxCount
>
{};
template
<
typename Polygon,
bool Reverse,
typename Sections,
std::size_t DimensionCount,
std::size_t MaxCount
>
struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount>
: detail::sectionalize::sectionalize_polygon
<
Polygon, Reverse, Sections, DimensionCount, MaxCount
>
{};
} // namespace dispatch
#endif
/*!
\brief Split a geometry into monotonic sections
\ingroup sectionalize
\tparam Geometry type of geometry to check
\tparam Sections type of sections to create
\param geometry geometry to create sections from
\param sections structure with sections
\param source_index index to assign to the ring_identifiers
*/
template<bool Reverse, typename Geometry, typename Sections>
inline void sectionalize(Geometry const& geometry, Sections& sections, int source_index = 0)
{
concept::check<Geometry const>();
// TODO: review use of this constant (see below) as causing problems with GCC 4.6 --mloskot
// A maximum of 10 segments per section seems to give the fastest results
//static std::size_t const max_segments_per_section = 10;
typedef dispatch::sectionalize
<
typename tag<Geometry>::type,
Geometry,
Reverse,
Sections,
Sections::value,
10 // TODO: max_segments_per_section
> sectionalizer_type;
sections.clear();
ring_identifier ring_id;
ring_id.source_index = source_index;
sectionalizer_type::apply(geometry, sections, ring_id);
detail::sectionalize::set_section_unique_ids(sections);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP