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,230 @@
// 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_APPEND_HPP
#define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace append
{
template <typename Geometry, typename Point>
struct append_no_action
{
static inline void apply(Geometry& geometry, Point const& point,
int = 0, int = 0)
{
}
};
template <typename Geometry, typename Point>
struct append_point
{
static inline void apply(Geometry& geometry, Point const& point,
int = 0, int = 0)
{
typename geometry::point_type<Geometry>::type copy;
geometry::detail::conversion::convert_point_to_point(point, copy);
traits::push_back<Geometry>::apply(geometry, copy);
}
};
template <typename Geometry, typename Range>
struct append_range
{
typedef typename boost::range_value<Range>::type point_type;
static inline void apply(Geometry& geometry, Range const& range,
int = 0, int = 0)
{
for (typename boost::range_iterator<Range const>::type
it = boost::begin(range);
it != boost::end(range);
++it)
{
append_point<Geometry, point_type>::apply(geometry, *it);
}
}
};
template <typename Polygon, typename Point>
struct point_to_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon& polygon, Point const& point,
int ring_index, int = 0)
{
if (ring_index == -1)
{
append_point<ring_type, Point>::apply(
exterior_ring(polygon), point);
}
else if (ring_index < int(num_interior_rings(polygon)))
{
append_point<ring_type, Point>::apply(
interior_rings(polygon)[ring_index], point);
}
}
};
template <typename Polygon, typename Range>
struct range_to_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon& polygon, Range const& range,
int ring_index, int )
{
if (ring_index == -1)
{
append_range<ring_type, Range>::apply(
exterior_ring(polygon), range);
}
else if (ring_index < int(num_interior_rings(polygon)))
{
append_range<ring_type, Range>::apply(
interior_rings(polygon)[ring_index], range);
}
}
};
}} // namespace detail::append
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
namespace splitted_dispatch
{
template <typename Tag, typename Geometry, typename Point>
struct append_point
: detail::append::append_no_action<Geometry, Point>
{};
template <typename Geometry, typename Point>
struct append_point<linestring_tag, Geometry, Point>
: detail::append::append_point<Geometry, Point>
{};
template <typename Geometry, typename Point>
struct append_point<ring_tag, Geometry, Point>
: detail::append::append_point<Geometry, Point>
{};
template <typename Polygon, typename Point>
struct append_point<polygon_tag, Polygon, Point>
: detail::append::point_to_polygon<Polygon, Point>
{};
template <typename Tag, typename Geometry, typename Range>
struct append_range
: detail::append::append_no_action<Geometry, Range>
{};
template <typename Geometry, typename Range>
struct append_range<linestring_tag, Geometry, Range>
: detail::append::append_range<Geometry, Range>
{};
template <typename Geometry, typename Range>
struct append_range<ring_tag, Geometry, Range>
: detail::append::append_range<Geometry, Range>
{};
template <typename Polygon, typename Range>
struct append_range<polygon_tag, Polygon, Range>
: detail::append::range_to_polygon<Polygon, Range>
{};
}
// Default: append a range (or linestring or ring or whatever) to any geometry
template <typename TagRangeOrPoint, typename Geometry, typename RangeOrPoint>
struct append
: splitted_dispatch::append_range<typename tag<Geometry>::type, Geometry, RangeOrPoint>
{};
// Specialization for point to append a point to any geometry
template <typename Geometry, typename RangeOrPoint>
struct append<point_tag, Geometry, RangeOrPoint>
: splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Appends one or more points to a linestring, ring, polygon, multi-geometry
\ingroup append
\tparam Geometry \tparam_geometry
\tparam RangeOrPoint Either a range or a point, fullfilling Boost.Range concept or Boost.Geometry Point Concept
\param geometry \param_geometry
\param range_or_point The point or range to add
\param ring_index The index of the ring in case of a polygon:
exterior ring (-1, the default) or interior ring index
\param multi_index Reserved for multi polygons or multi linestrings
\qbk{[include reference/algorithms/append.qbk]}
}
*/
template <typename Geometry, typename RangeOrPoint>
inline void append(Geometry& geometry, RangeOrPoint const& range_or_point,
int ring_index = -1, int multi_index = 0)
{
concept::check<Geometry>();
dispatch::append
<
typename tag<RangeOrPoint>::type,
Geometry,
RangeOrPoint
>::apply(geometry, range_or_point, ring_index, multi_index);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP

View File

@@ -0,0 +1,287 @@
// 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_AREA_HPP
#define BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/default_area_result.hpp>
#include <boost/geometry/strategies/concepts/area_concept.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/order_as_direction.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 area
{
template<typename Box, typename Strategy>
struct box_area
{
typedef typename coordinate_type<Box>::type return_type;
static inline return_type apply(Box const& box, Strategy const&)
{
// Currently only works for 2D Cartesian boxes
assert_dimension<Box, 2>();
return_type const dx = get<max_corner, 0>(box)
- get<min_corner, 0>(box);
return_type const dy = get<max_corner, 1>(box)
- get<min_corner, 1>(box);
return dx * dy;
}
};
template
<
typename Ring,
iterate_direction Direction,
closure_selector Closure,
typename Strategy
>
struct ring_area
{
BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
typedef typename Strategy::return_type type;
static inline type apply(Ring const& ring, Strategy const& strategy)
{
assert_dimension<Ring, 2>();
// Ignore warning (because using static method sometimes) on strategy
boost::ignore_unused_variable_warning(strategy);
// An open ring has at least three points,
// A closed ring has at least four points,
// if not, there is no (zero) area
if (boost::size(ring)
< core_detail::closure::minimum_ring_size<Closure>::value)
{
return type();
}
typedef typename reversible_view<Ring const, Direction>::type rview_type;
typedef typename closeable_view
<
rview_type const, Closure
>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator_type;
rview_type rview(ring);
view_type view(rview);
typename Strategy::state_type state;
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
for (iterator_type previous = it++;
it != end;
++previous, ++it)
{
strategy.apply(*previous, *it, state);
}
return strategy.result(state);
}
};
}} // namespace detail::area
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename Strategy
>
struct area
: detail::calculate_null
<
typename Strategy::return_type,
Geometry,
Strategy
> {};
template
<
typename Geometry,
typename Strategy
>
struct area<box_tag, Geometry, Strategy>
: detail::area::box_area<Geometry, Strategy>
{};
template
<
typename Ring,
typename Strategy
>
struct area<ring_tag, Ring, Strategy>
: detail::area::ring_area
<
Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value,
Strategy
>
{};
template
<
typename Polygon,
typename Strategy
>
struct area<polygon_tag, Polygon, Strategy>
: detail::calculate_polygon_sum
<
typename Strategy::return_type,
Polygon,
Strategy,
detail::area::ring_area
<
typename ring_type<Polygon const>::type,
order_as_direction<geometry::point_order<Polygon>::value>::value,
geometry::closure<Polygon>::value,
Strategy
>
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc{area}
\ingroup area
\details \details_calc{area}. \details_default_strategy
The area algorithm calculates the surface area of all geometries having a surface, namely
box, polygon, ring, multipolygon. The units are the square of the units used for the points
defining the surface. If subject geometry is defined in meters, then area is calculated
in square meters.
The area calculation can be done in all three common coordinate systems, Cartesian, Spherical
and Geographic as well.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{area}
\qbk{[include reference/algorithms/area.qbk]}
\qbk{[heading Examples]}
\qbk{[area] [area_output]}
*/
template <typename Geometry>
inline typename default_area_result<Geometry>::type area(Geometry const& geometry)
{
concept::check<Geometry const>();
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
return dispatch::area
<
typename tag<Geometry>::type,
Geometry,
strategy_type
>::apply(geometry, strategy_type());
}
/*!
\brief \brief_calc{area} \brief_strategy
\ingroup area
\details \details_calc{area} \brief_strategy. \details_strategy_reasons
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry
\param strategy \param_strategy{area}
\return \return_calc{area}
\qbk{distinguish,with strategy}
\qbk{
[include reference/algorithms/area.qbk]
[heading Example]
[area_with_strategy]
[area_with_strategy_output]
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_area_surveyor Surveyor (cartesian)]
\* [link geometry.reference.strategies.strategy_area_huiller Huiller (spherical)]
}
*/
template <typename Geometry, typename Strategy>
inline typename Strategy::return_type area(
Geometry const& geometry, Strategy const& strategy)
{
concept::check<Geometry const>();
return dispatch::area
<
typename tag<Geometry>::type,
Geometry,
Strategy
>::apply(geometry, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP

View File

@@ -0,0 +1,182 @@
// 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_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_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/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/convert.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
{
/*!
\brief Assign a range of points to a linestring, ring or polygon
\note The point-type of the range might be different from the point-type of the geometry
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Range \tparam_range_point
\param geometry \param_geometry
\param range \param_range_point
\qbk{
[heading Notes]
[note Assign automatically clears the geometry before assigning (use append if you don't want that)]
[heading Example]
[assign_points] [assign_points_output]
[heading See also]
\* [link geometry.reference.algorithms.append append]
}
*/
template <typename Geometry, typename Range>
inline void assign_points(Geometry& geometry, Range const& range)
{
concept::check<Geometry>();
clear(geometry);
geometry::append(geometry, range, -1, 0);
}
/*!
\brief assign to a box inverse infinite
\details The assign_inverse function initialize a 2D or 3D box with large coordinates, the
min corner is very large, the max corner is very small. This is a convenient starting point to
collect the minimum bounding box of a geometry.
\ingroup assign
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\qbk{
[heading Example]
[assign_inverse] [assign_inverse_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_inverse make_inverse]
}
*/
template <typename Geometry>
inline void assign_inverse(Geometry& geometry)
{
concept::check<Geometry>();
dispatch::assign_inverse
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
/*!
\brief assign zero values to a box, point
\ingroup assign
\details The assign_zero function initializes a 2D or 3D point or box with coordinates of zero
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
*/
template <typename Geometry>
inline void assign_zero(Geometry& geometry)
{
concept::check<Geometry>();
dispatch::assign_zero
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
/*!
\brief Assigns one geometry to another geometry
\details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only
if it is possible and applicable.
\ingroup assign
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry (target)
\param geometry2 \param_geometry (source)
\qbk{
[heading Example]
[assign] [assign_output]
[heading See also]
\* [link geometry.reference.algorithms.convert convert]
}
*/
template <typename Geometry1, typename Geometry2>
inline void assign(Geometry1& geometry1, Geometry2 const& geometry2)
{
concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
bool const same_point_order =
point_order<Geometry1>::value == point_order<Geometry2>::value;
bool const same_closure =
closure<Geometry1>::value == closure<Geometry2>::value;
BOOST_MPL_ASSERT_MSG
(
same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER
, (types<Geometry1, Geometry2>)
);
BOOST_MPL_ASSERT_MSG
(
same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE
, (types<Geometry1, Geometry2>)
);
dispatch::convert
<
false,
typename tag<Geometry2>::type,
typename tag<Geometry1>::type,
dimension<Geometry1>::type::value,
Geometry2,
Geometry1
>::apply(geometry2, geometry1);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP

View File

@@ -0,0 +1,167 @@
// 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_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
struct box_loop
{
typedef typename coordinate_type<BoxOut>::type coordinate_type;
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
coordinate_type d = distance;
set<C, D>(box_out, get<C, D>(box_in) + d);
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
}
};
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
struct box_loop<BoxIn, BoxOut, T, C, N, N>
{
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
};
// Extends a box with the same amount in all directions
template<typename BoxIn, typename BoxOut, typename T>
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
assert_dimension_equal<BoxIn, BoxOut>();
static const std::size_t N = dimension<BoxIn>::value;
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename TagIn, typename TagOut, typename Input, typename T, typename Output>
struct buffer {};
template <typename BoxIn, typename T, typename BoxOut>
struct buffer<box_tag, box_tag, BoxIn, T, BoxOut>
{
static inline void apply(BoxIn const& box_in, T const& distance,
T const& chord_length, BoxIn& box_out)
{
detail::buffer::buffer_box(box_in, distance, box_out);
}
};
// Many things to do. Point is easy, other geometries require self intersections
// For point, note that it should output as a polygon (like the rest). Buffers
// of a set of geometries are often lateron combined using a "dissolve" operation.
// Two points close to each other get a combined kidney shaped buffer then.
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc{buffer}
\ingroup buffer
\details \details_calc{buffer, \det_buffer}.
\tparam Input \tparam_geometry
\tparam Output \tparam_geometry
\tparam Distance \tparam_numeric
\param geometry_in \param_geometry
\param geometry_out \param_geometry
\param distance The distance to be used for the buffer
\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
\note Currently only implemented for box, the trivial case, but still useful
\qbk{[include reference/algorithms/buffer.qbk]}
*/
template <typename Input, typename Output, typename Distance>
inline void buffer(Input const& geometry_in, Output& geometry_out,
Distance const& distance, Distance const& chord_length = -1)
{
concept::check<Input const>();
concept::check<Output>();
dispatch::buffer
<
typename tag<Input>::type,
typename tag<Output>::type,
Input,
Distance,
Output
>::apply(geometry_in, distance, chord_length, geometry_out);
}
/*!
\brief \brief_calc{buffer}
\ingroup buffer
\details \details_calc{return_buffer, \det_buffer}. \details_return{buffer}.
\tparam Input \tparam_geometry
\tparam Output \tparam_geometry
\tparam Distance \tparam_numeric
\param geometry \param_geometry
\param distance The distance to be used for the buffer
\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
\return \return_calc{buffer}
*/
template <typename Output, typename Input, typename T>
Output return_buffer(Input const& geometry, T const& distance, T const& chord_length = -1)
{
concept::check<Input const>();
concept::check<Output>();
Output geometry_out;
dispatch::buffer
<
typename tag<Input>::type,
typename tag<Output>::type,
Input,
T,
Output
>::apply(geometry, distance, chord_length, geometry_out);
return geometry_out;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP

View File

@@ -0,0 +1,470 @@
// 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_CENTROID_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/concepts/centroid_concept.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
namespace boost { namespace geometry
{
#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
/*!
\brief Centroid Exception
\ingroup centroid
\details The centroid_exception is thrown if the free centroid function is called with
geometries for which the centroid cannot be calculated. For example: a linestring
without points, a polygon without points, an empty multi-geometry.
\qbk{
[heading See also]
\* [link geometry.reference.algorithms.centroid the centroid function]
}
*/
class centroid_exception : public geometry::exception
{
public:
inline centroid_exception() {}
virtual char const* what() const throw()
{
return "Boost.Geometry Centroid calculation exception";
}
};
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace centroid
{
template<typename Point, typename PointCentroid, typename Strategy>
struct centroid_point
{
static inline void apply(Point const& point, PointCentroid& centroid,
Strategy const&)
{
geometry::convert(point, centroid);
}
};
template
<
typename Box,
typename Point,
std::size_t Dimension,
std::size_t DimensionCount
>
struct centroid_box_calculator
{
typedef typename select_coordinate_type
<
Box, Point
>::type coordinate_type;
static inline void apply(Box const& box, Point& centroid)
{
coordinate_type const c1 = get<min_corner, Dimension>(box);
coordinate_type const c2 = get<max_corner, Dimension>(box);
coordinate_type m = c1 + c2;
m /= 2.0;
set<Dimension>(centroid, m);
centroid_box_calculator
<
Box, Point,
Dimension + 1, DimensionCount
>::apply(box, centroid);
}
};
template<typename Box, typename Point, std::size_t DimensionCount>
struct centroid_box_calculator<Box, Point, DimensionCount, DimensionCount>
{
static inline void apply(Box const& , Point& )
{
}
};
template<typename Box, typename Point, typename Strategy>
struct centroid_box
{
static inline void apply(Box const& box, Point& centroid,
Strategy const&)
{
centroid_box_calculator
<
Box, Point,
0, dimension<Box>::type::value
>::apply(box, centroid);
}
};
// There is one thing where centroid is different from e.g. within.
// If the ring has only one point, it might make sense that
// that point is the centroid.
template<typename Point, typename Range>
inline bool range_ok(Range const& range, Point& centroid)
{
std::size_t const n = boost::size(range);
if (n > 1)
{
return true;
}
else if (n <= 0)
{
#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
throw centroid_exception();
#endif
return false;
}
else // if (n == 1)
{
// Take over the first point in a "coordinate neutral way"
geometry::convert(*boost::begin(range), centroid);
return false;
}
return true;
}
/*!
\brief Calculate the centroid of a ring.
*/
template<typename Ring, closure_selector Closure, typename Strategy>
struct centroid_range_state
{
static inline void apply(Ring const& ring,
Strategy const& strategy, typename Strategy::state_type& state)
{
typedef typename closeable_view<Ring const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator_type;
view_type view(ring);
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
for (iterator_type previous = it++;
it != end;
++previous, ++it)
{
Strategy::apply(*previous, *it, state);
}
}
};
template<typename Range, typename Point, closure_selector Closure, typename Strategy>
struct centroid_range
{
static inline void apply(Range const& range, Point& centroid,
Strategy const& strategy)
{
if (range_ok(range, centroid))
{
typename Strategy::state_type state;
centroid_range_state
<
Range,
Closure,
Strategy
>::apply(range, strategy, state);
Strategy::result(state, centroid);
}
}
};
/*!
\brief Centroid of a polygon.
\note Because outer ring is clockwise, inners are counter clockwise,
triangle approach is OK and works for polygons with rings.
*/
template<typename Polygon, typename Strategy>
struct centroid_polygon_state
{
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon const& poly,
Strategy const& strategy, typename Strategy::state_type& state)
{
typedef centroid_range_state
<
ring_type,
geometry::closure<ring_type>::value,
Strategy
> per_ring;
per_ring::apply(exterior_ring(poly), strategy, state);
typename interior_return_type<Polygon const>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
per_ring::apply(*it, strategy, state);
}
}
};
template<typename Polygon, typename Point, typename Strategy>
struct centroid_polygon
{
static inline void apply(Polygon const& poly, Point& centroid,
Strategy const& strategy)
{
if (range_ok(exterior_ring(poly), centroid))
{
typename Strategy::state_type state;
centroid_polygon_state
<
Polygon,
Strategy
>::apply(poly, strategy, state);
Strategy::result(state, centroid);
}
}
};
}} // namespace detail::centroid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename Point,
typename Strategy
>
struct centroid {};
template
<
typename Geometry,
typename Point,
typename Strategy
>
struct centroid<point_tag, Geometry, Point, Strategy>
: detail::centroid::centroid_point<Geometry, Point, Strategy>
{};
template
<
typename Box,
typename Point,
typename Strategy
>
struct centroid<box_tag, Box, Point, Strategy>
: detail::centroid::centroid_box<Box, Point, Strategy>
{};
template <typename Ring, typename Point, typename Strategy>
struct centroid<ring_tag, Ring, Point, Strategy>
: detail::centroid::centroid_range
<
Ring,
Point,
geometry::closure<Ring>::value,
Strategy
>
{};
template <typename Linestring, typename Point, typename Strategy>
struct centroid<linestring_tag, Linestring, Point, Strategy>
: detail::centroid::centroid_range
<
Linestring,
Point,
closed,
Strategy
>
{};
template <typename Polygon, typename Point, typename Strategy>
struct centroid<polygon_tag, Polygon, Point, Strategy>
: detail::centroid::centroid_polygon<Polygon, Point, Strategy>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_strategy_reasons
\tparam Geometry \tparam_geometry
\tparam Point \tparam_point
\tparam Strategy \tparam_strategy{Centroid}
\param geometry \param_geometry
\param c \param_point \param_set{centroid}
\param strategy \param_strategy{centroid}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{[include reference/algorithms/centroid_strategies.qbk]}
}
*/
template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
{
//BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
typedef typename point_type<Geometry>::type point_type;
// Call dispatch apply method. That one returns true if centroid
// should be taken from state.
dispatch::centroid
<
typename tag<Geometry>::type,
Geometry,
Point,
Strategy
>::apply(geometry, c, strategy);
}
/*!
\brief \brief_calc{centroid}
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_default_strategy
\tparam Geometry \tparam_geometry
\tparam Point \tparam_point
\param geometry \param_geometry
\param c The calculated centroid will be assigned to this point reference
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{
[heading Example]
[centroid]
[centroid_output]
}
*/
template<typename Geometry, typename Point>
inline void centroid(Geometry const& geometry, Point& c)
{
concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
typedef typename strategy::centroid::services::default_strategy
<
typename cs_tag<Geometry>::type,
typename tag_cast
<
typename tag<Geometry>::type,
pointlike_tag,
linear_tag,
areal_tag
>::type,
dimension<Geometry>::type::value,
Point,
Geometry
>::type strategy_type;
centroid(geometry, c, strategy_type());
}
/*!
\brief \brief_calc{centroid}
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}.
\tparam Point \tparam_point
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{centroid}
\qbk{[include reference/algorithms/centroid.qbk]}
*/
template<typename Point, typename Geometry>
inline Point return_centroid(Geometry const& geometry)
{
concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
Point c;
centroid(geometry, c);
return c;
}
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}. \details_strategy_reasons
\tparam Point \tparam_point
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{centroid}
\param geometry \param_geometry
\param strategy \param_strategy{centroid}
\return \return_calc{centroid}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{[include reference/algorithms/centroid_strategies.qbk]}
*/
template<typename Point, typename Geometry, typename Strategy>
inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
{
//BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
Point c;
centroid(geometry, c, strategy);
return c;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP

View File

@@ -0,0 +1,159 @@
// 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_CLEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace clear
{
template <typename Geometry>
struct collection_clear
{
static inline void apply(Geometry& geometry)
{
traits::clear<Geometry>::apply(geometry);
}
};
template <typename Polygon>
struct polygon_clear
{
static inline void apply(Polygon& polygon)
{
traits::clear
<
typename boost::remove_reference
<
typename traits::interior_mutable_type<Polygon>::type
>::type
>::apply(interior_rings(polygon));
traits::clear
<
typename boost::remove_reference
<
typename traits::ring_mutable_type<Polygon>::type
>::type
>::apply(exterior_ring(polygon));
}
};
template <typename Geometry>
struct no_action
{
static inline void apply(Geometry& )
{
}
};
}} // namespace detail::clear
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry>
struct clear
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
// Point/box/segment do not have clear. So specialize to do nothing.
template <typename Geometry>
struct clear<point_tag, Geometry>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<box_tag, Geometry>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<segment_tag, Geometry>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<linestring_tag, Geometry>
: detail::clear::collection_clear<Geometry>
{};
template <typename Geometry>
struct clear<ring_tag, Geometry>
: detail::clear::collection_clear<Geometry>
{};
// Polygon can (indirectly) use std for clear
template <typename Polygon>
struct clear<polygon_tag, Polygon>
: detail::clear::polygon_clear<Polygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Clears a linestring, ring or polygon (exterior+interiors) or multi*
\details Generic function to clear a geometry. All points will be removed from the collection or collections
making up the geometry. In most cases this is equivalent to the .clear() method of a std::vector<...>. In
the case of a polygon, this clear functionality is automatically called for the exterior ring, and for the
interior ring collection. In the case of a point, boxes and segments, nothing will happen.
\ingroup clear
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be cleared
\note points and boxes cannot be cleared, instead they can be set to zero by "assign_zero"
\qbk{[include reference/algorithms/clear.qbk]}
*/
template <typename Geometry>
inline void clear(Geometry& geometry)
{
concept::check<Geometry>();
dispatch::clear
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry
>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP

View File

@@ -0,0 +1,74 @@
// 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_COMPARABLE_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
#include <boost/geometry/algorithms/distance.hpp>
namespace boost { namespace geometry
{
/*!
\brief \brief_calc2{comparable distance measurement}
\ingroup distance
\details The free function comparable_distance does not necessarily calculate the distance,
but it calculates a distance measure such that two distances are comparable to each other.
For example: for the Cartesian coordinate system, Pythagoras is used but the square root
is not taken, which makes it faster and the results of two point pairs can still be
compared to each other.
\tparam Geometry1 first geometry type
\tparam Geometry2 second geometry type
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_calc{comparable distance}
\qbk{[include reference/algorithms/comparable_distance.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline typename default_distance_result<Geometry1, Geometry2>::type comparable_distance(
Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename point_type<Geometry1>::type point1_type;
typedef typename point_type<Geometry2>::type point2_type;
// Define a point-point-distance-strategy
// for either the normal case, either the reversed case
typedef typename strategy::distance::services::comparable_type
<
typename boost::mpl::if_c
<
geometry::reverse_dispatch
<Geometry1, Geometry2>::type::value,
typename strategy::distance::services::default_strategy
<point_tag, point2_type, point1_type>::type,
typename strategy::distance::services::default_strategy
<point_tag, point1_type, point2_type>::type
>::type
>::type strategy_type;
return distance(geometry1, geometry2, strategy_type());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP

View File

@@ -0,0 +1,400 @@
// 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_CONVERT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
template
<
typename Point,
typename Box,
std::size_t Index,
std::size_t Dimension,
std::size_t DimensionCount
>
struct point_to_box
{
static inline void apply(Point const& point, Box& box)
{
typedef typename coordinate_type<Box>::type coordinate_type;
set<Index, Dimension>(box,
boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
point_to_box
<
Point, Box,
Index, Dimension + 1, DimensionCount
>::apply(point, box);
}
};
template
<
typename Point,
typename Box,
std::size_t Index,
std::size_t DimensionCount
>
struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
{
static inline void apply(Point const& , Box& )
{}
};
template <typename Box, typename Range, bool Close, bool Reverse>
struct box_to_range
{
static inline void apply(Box const& box, Range& range)
{
traits::resize<Range>::apply(range, Close ? 5 : 4);
assign_box_corners_oriented<Reverse>(box, range);
if (Close)
{
range[4] = range[0];
}
}
};
template <typename Segment, typename Range>
struct segment_to_range
{
static inline void apply(Segment const& segment, Range& range)
{
traits::resize<Range>::apply(range, 2);
typename boost::range_iterator<Range>::type it = boost::begin(range);
assign_point_from_index<0>(segment, *it);
++it;
assign_point_from_index<1>(segment, *it);
}
};
template
<
typename Range1,
typename Range2,
bool Reverse = false
>
struct range_to_range
{
typedef typename reversible_view
<
Range1 const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename closeable_view
<
rview_type const,
geometry::closure<Range1>::value
>::type view_type;
static inline void apply(Range1 const& source, Range2& destination)
{
geometry::clear(destination);
rview_type rview(source);
// We consider input always as closed, and skip last
// point for open output.
view_type view(rview);
int n = boost::size(view);
if (geometry::closure<Range2>::value == geometry::open)
{
n--;
}
int i = 0;
for (typename boost::range_iterator<view_type const>::type it
= boost::begin(view);
it != boost::end(view) && i < n;
++it, ++i)
{
geometry::append(destination, *it);
}
}
};
template <typename Polygon1, typename Polygon2>
struct polygon_to_polygon
{
typedef range_to_range
<
typename geometry::ring_type<Polygon1>::type,
typename geometry::ring_type<Polygon2>::type,
geometry::point_order<Polygon1>::value
!= geometry::point_order<Polygon2>::value
> per_ring;
static inline void apply(Polygon1 const& source, Polygon2& destination)
{
// Clearing managed per ring, and in the resizing of interior rings
per_ring::apply(geometry::exterior_ring(source),
geometry::exterior_ring(destination));
// Container should be resizeable
traits::resize
<
typename boost::remove_reference
<
typename traits::interior_mutable_type<Polygon2>::type
>::type
>::apply(interior_rings(destination), num_interior_rings(source));
typename interior_return_type<Polygon1 const>::type rings_source
= interior_rings(source);
typename interior_return_type<Polygon2>::type rings_dest
= interior_rings(destination);
BOOST_AUTO_TPL(it_source, boost::begin(rings_source));
BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest));
for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
{
per_ring::apply(*it_source, *it_dest);
}
}
};
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
bool UseAssignment,
typename Tag1, typename Tag2,
std::size_t DimensionCount,
typename Geometry1, typename Geometry2
>
struct convert
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES
, (types<Geometry1, Geometry2>)
);
};
template
<
typename Tag,
std::size_t DimensionCount,
typename Geometry1, typename Geometry2
>
struct convert<true, Tag, Tag, DimensionCount, Geometry1, Geometry2>
{
// Same geometry type -> copy whole geometry
static inline void apply(Geometry1 const& source, Geometry2& destination)
{
destination = source;
}
};
template
<
std::size_t DimensionCount,
typename Geometry1, typename Geometry2
>
struct convert<false, point_tag, point_tag, DimensionCount, Geometry1, Geometry2>
: detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
{};
template <std::size_t DimensionCount, typename Segment, typename LineString>
struct convert<false, segment_tag, linestring_tag, DimensionCount, Segment, LineString>
: detail::conversion::segment_to_range<Segment, LineString>
{};
template <std::size_t DimensionCount, typename Ring1, typename Ring2>
struct convert<false, ring_tag, ring_tag, DimensionCount, Ring1, Ring2>
: detail::conversion::range_to_range
<
Ring1,
Ring2,
geometry::point_order<Ring1>::value
!= geometry::point_order<Ring2>::value
>
{};
template <std::size_t DimensionCount, typename LineString1, typename LineString2>
struct convert<false, linestring_tag, linestring_tag, DimensionCount, LineString1, LineString2>
: detail::conversion::range_to_range<LineString1, LineString2>
{};
template <std::size_t DimensionCount, typename Polygon1, typename Polygon2>
struct convert<false, polygon_tag, polygon_tag, DimensionCount, Polygon1, Polygon2>
: detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
{};
template <typename Box, typename Ring>
struct convert<false, box_tag, ring_tag, 2, Box, Ring>
: detail::conversion::box_to_range
<
Box,
Ring,
geometry::closure<Ring>::value == closed,
geometry::point_order<Ring>::value == counterclockwise
>
{};
template <typename Box, typename Polygon>
struct convert<false, box_tag, polygon_tag, 2, Box, Polygon>
{
static inline void apply(Box const& box, Polygon& polygon)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
false, box_tag, ring_tag,
2, Box, ring_type
>::apply(box, exterior_ring(polygon));
}
};
template <typename Point, std::size_t DimensionCount, typename Box>
struct convert<false, point_tag, box_tag, DimensionCount, Point, Box>
{
static inline void apply(Point const& point, Box& box)
{
detail::conversion::point_to_box
<
Point, Box, min_corner, 0, DimensionCount
>::apply(point, box);
detail::conversion::point_to_box
<
Point, Box, max_corner, 0, DimensionCount
>::apply(point, box);
}
};
template <typename Ring, std::size_t DimensionCount, typename Polygon>
struct convert<false, ring_tag, polygon_tag, DimensionCount, Ring, Polygon>
{
static inline void apply(Ring const& ring, Polygon& polygon)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
false, ring_tag, ring_tag, DimensionCount,
Ring, ring_type
>::apply(ring, exterior_ring(polygon));
}
};
template <typename Polygon, std::size_t DimensionCount, typename Ring>
struct convert<false, polygon_tag, ring_tag, DimensionCount, Polygon, Ring>
{
static inline void apply(Polygon const& polygon, Ring& ring)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
false,
ring_tag, ring_tag, DimensionCount,
ring_type, Ring
>::apply(exterior_ring(polygon), ring);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Converts one geometry to another geometry
\details The convert algorithm converts one geometry, e.g. a BOX, to another
geometry, e.g. a RING. This only if it is possible and applicable.
If the point-order is different, or the closure is different between two
geometry types, it will be converted correctly by explicitly reversing the
points or closing or opening the polygon rings.
\ingroup convert
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry (source)
\param geometry2 \param_geometry (target)
\qbk{[include reference/algorithms/convert.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
dispatch::convert
<
boost::is_same<Geometry1, Geometry2>::value
// && boost::has_assign<Geometry2>::value, -- type traits extensions
&& ! boost::is_array<Geometry1>::value,
typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
dimension<Geometry1>::type::value,
Geometry1,
Geometry2
>::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP

View File

@@ -0,0 +1,247 @@
// 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_CONVEX_HULL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/concepts/convex_hull_concept.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/algorithms/detail/as_range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace convex_hull
{
template
<
typename Geometry,
order_selector Order,
typename Strategy
>
struct hull_insert
{
// Member template function (to avoid inconvenient declaration
// of output-iterator-type, from hull_to_geometry)
template <typename OutputIterator>
static inline OutputIterator apply(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
typename Strategy::state_type state;
strategy.apply(geometry, state);
strategy.result(state, out, Order == clockwise);
return out;
}
};
template
<
typename Geometry,
typename OutputGeometry,
typename Strategy
>
struct hull_to_geometry
{
static inline void apply(Geometry const& geometry, OutputGeometry& out,
Strategy const& strategy)
{
hull_insert
<
Geometry,
geometry::point_order<OutputGeometry>::value,
Strategy
>::apply(geometry,
std::back_inserter(
// Handle linestring, ring and polygon the same:
detail::as_range
<
typename range_type<OutputGeometry>::type
>(out)), strategy);
}
};
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1,
typename Geometry,
typename Output,
typename Strategy
>
struct convex_hull
: detail::convex_hull::hull_to_geometry<Geometry, Output, Strategy>
{};
template
<
typename GeometryTag,
order_selector Order,
typename GeometryIn, typename Strategy
>
struct convex_hull_insert
: detail::convex_hull::hull_insert<GeometryIn, Order, Strategy>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template<typename Geometry1, typename Geometry2, typename Strategy>
inline void convex_hull(Geometry1 const& geometry,
Geometry2& out, Strategy const& strategy)
{
concept::check_concepts_and_equal_dimensions
<
const Geometry1,
Geometry2
>();
BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
dispatch::convex_hull
<
typename tag<Geometry1>::type,
Geometry1,
Geometry2,
Strategy
>::apply(geometry, out, strategy);
}
/*!
\brief \brief_calc{convex hull}
\ingroup convex_hull
\details \details_calc{convex_hull,convex hull}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry \param_geometry, input geometry
\param hull \param_geometry \param_set{convex hull}
\qbk{[include reference/algorithms/convex_hull.qbk]}
*/
template<typename Geometry1, typename Geometry2>
inline void convex_hull(Geometry1 const& geometry,
Geometry2& hull)
{
concept::check_concepts_and_equal_dimensions
<
const Geometry1,
Geometry2
>();
typedef typename point_type<Geometry2>::type point_type;
typedef typename strategy_convex_hull
<
typename cs_tag<point_type>::type,
Geometry1,
point_type
>::type strategy_type;
convex_hull(geometry, hull, strategy_type());
}
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace convex_hull
{
template<typename Geometry, typename OutputIterator, typename Strategy>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<typename point_type<Geometry>::type>();
BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
return dispatch::convex_hull_insert
<
typename tag<Geometry>::type,
geometry::point_order<Geometry>::value,
Geometry, Strategy
>::apply(geometry, out, strategy);
}
/*!
\brief Calculate the convex hull of a geometry, output-iterator version
\ingroup convex_hull
\tparam Geometry the input geometry type
\tparam OutputIterator: an output-iterator
\param geometry the geometry to calculate convex hull from
\param out an output iterator outputing points of the convex hull
\note This overloaded version outputs to an output iterator.
In this case, nothing is known about its point-type or
about its clockwise order. Therefore, the input point-type
and order are copied
*/
template<typename Geometry, typename OutputIterator>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out)
{
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<typename point_type<Geometry>::type>();
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy_convex_hull
<
typename cs_tag<point_type>::type,
Geometry,
point_type
>::type strategy_type;
return convex_hull_insert(geometry, out, strategy_type());
}
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP

View File

@@ -0,0 +1,270 @@
// 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_CORRECT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
#include <algorithm>
#include <cstddef>
#include <functional>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/mutable_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/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct
{
template <typename Geometry>
struct correct_nop
{
static inline void apply(Geometry& )
{}
};
template <typename Box, std::size_t Dimension, std::size_t DimensionCount>
struct correct_box_loop
{
typedef typename coordinate_type<Box>::type coordinate_type;
static inline void apply(Box& box)
{
if (get<min_corner, Dimension>(box) > get<max_corner, Dimension>(box))
{
// Swap the coordinates
coordinate_type max_value = get<min_corner, Dimension>(box);
coordinate_type min_value = get<max_corner, Dimension>(box);
set<min_corner, Dimension>(box, min_value);
set<max_corner, Dimension>(box, max_value);
}
correct_box_loop
<
Box, Dimension + 1, DimensionCount
>::apply(box);
}
};
template <typename Box, std::size_t DimensionCount>
struct correct_box_loop<Box, DimensionCount, DimensionCount>
{
static inline void apply(Box& box)
{}
};
// Correct a box: make min/max correct
template <typename Box>
struct correct_box
{
static inline void apply(Box& box)
{
// Currently only for Cartesian coordinates
// (or spherical without crossing dateline)
// Future version: adapt using strategies
correct_box_loop
<
Box, 0, dimension<Box>::type::value
>::apply(box);
}
};
// Close a ring, if not closed
template <typename Ring, typename Predicate>
struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename coordinate_type<Ring>::type coordinate_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef detail::area::ring_area
<
Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value,
strategy_type
> ring_area_type;
static inline void apply(Ring& r)
{
// Check close-ness
if (boost::size(r) > 2)
{
// check if closed, if not, close it
bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1));
closure_selector const s = geometry::closure<Ring>::value;
if (disjoint && (s == closed))
{
geometry::append(r, *boost::begin(r));
}
if (! disjoint && geometry::closure<Ring>::value != closed)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
}
}
// Check area
Predicate predicate;
coordinate_type const zero = 0;
if (predicate(ring_area_type::apply(r, strategy_type()), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
}
};
// Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all
// inner rings counter clockwise (or vice versa depending on orientation)
template <typename Polygon>
struct correct_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename coordinate_type<Polygon>::type coordinate_type;
static inline void apply(Polygon& poly)
{
correct_ring
<
ring_type,
std::less<coordinate_type>
>::apply(exterior_ring(poly));
typename interior_return_type<Polygon>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
correct_ring
<
ring_type,
std::greater<coordinate_type>
>::apply(*it);
}
}
};
}} // namespace detail::correct
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry>
struct correct
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template <typename Point>
struct correct<point_tag, Point>
: detail::correct::correct_nop<Point>
{};
template <typename LineString>
struct correct<linestring_tag, LineString>
: detail::correct::correct_nop<LineString>
{};
template <typename Segment>
struct correct<segment_tag, Segment>
: detail::correct::correct_nop<Segment>
{};
template <typename Box>
struct correct<box_tag, Box>
: detail::correct::correct_box<Box>
{};
template <typename Ring>
struct correct<ring_tag, Ring>
: detail::correct::correct_ring
<
Ring,
std::less<typename coordinate_type<Ring>::type>
>
{};
template <typename Polygon>
struct correct<polygon_tag, Polygon>
: detail::correct::correct_polygon<Polygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be corrected if necessary
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry>
inline void correct(Geometry& geometry)
{
concept::check<Geometry const>();
dispatch::correct<typename tag<Geometry>::type, Geometry>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP

View File

@@ -0,0 +1,206 @@
// 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_COVERED_BY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#include <cstddef>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1,
typename Tag2,
typename Geometry1,
typename Geometry2,
typename Strategy
>
struct covered_by
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry1, Geometry2>)
);
};
template <typename Point, typename Box, typename Strategy>
struct covered_by<point_tag, box_tag, Point, Box, Strategy>
{
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
return strategy.apply(point, box);
}
};
template <typename Box1, typename Box2, typename Strategy>
struct covered_by<box_tag, box_tag, Box1, Box2, Strategy>
{
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
return strategy.apply(box1, box2);
}
};
template <typename Point, typename Ring, typename Strategy>
struct covered_by<point_tag, ring_tag, Point, Ring, Strategy>
{
static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
{
return detail::within::point_in_ring
<
Point,
Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value,
Strategy
>::apply(point, ring) >= 0;
}
};
template <typename Point, typename Polygon, typename Strategy>
struct covered_by<point_tag, polygon_tag, Point, Polygon, Strategy>
{
static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
{
return detail::within::point_in_polygon
<
Point,
Polygon,
order_as_direction<geometry::point_order<Polygon>::value>::value,
geometry::closure<Polygon>::value,
Strategy
>::apply(point, polygon, strategy) >= 0;
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check12{is inside or on border}
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry1 geometry which might be covered_by the second geometry
\param geometry2 geometry which might contain the first geometry
\return true if geometry1 is completely contained covered_by geometry2,
else false
\note The default strategy is used for covered_by detection
*/
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
typedef typename point_type<Geometry1>::type point_type1;
typedef typename point_type<Geometry2>::type point_type2;
typedef typename strategy::covered_by::services::default_strategy
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename tag<Geometry1>::type,
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
typename tag_cast
<
typename cs_tag<point_type1>::type, spherical_tag
>::type,
typename tag_cast
<
typename cs_tag<point_type2>::type, spherical_tag
>::type,
Geometry1,
Geometry2
>::type strategy_type;
return dispatch::covered_by
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
/*!
\brief \brief_check12{is inside or on border} \brief_strategy
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry1 \param_geometry geometry which might be covered_by the second geometry
\param geometry2 \param_geometry which might contain the first geometry
\param strategy strategy to be used
\return true if geometry1 is completely contained covered_by geometry2,
else false
\qbk{distinguish,with strategy}
*/
template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
concept::within::check
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
>();
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::covered_by
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
Strategy
>::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP

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

View File

@@ -0,0 +1,148 @@
// 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_DIFFERENCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
#include <algorithm>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace difference
{
/*!
\brief_calc2{difference} \brief_strategy
\ingroup difference
\details \details_calc2{difference_insert, spatial set theoretic difference}
\brief_strategy. \details_inserter{difference}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator output iterator
\tparam Strategy \tparam_strategy_overlay
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{difference}
\param strategy \param_strategy{difference}
\return \return_out
\qbk{distinguish,with strategy}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator,
typename Strategy
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
return detail::intersection::insert<GeometryOut, true, overlay_difference>(
geometry1, geometry2,
out,
strategy);
}
/*!
\brief_calc2{difference}
\ingroup difference
\details \details_calc2{difference_insert, spatial set theoretic difference}.
\details_insert{difference}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator output iterator
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{difference}
\return \return_out
\qbk{[include reference/algorithms/difference_insert.qbk]}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
> strategy;
return difference_insert<GeometryOut>(geometry1, geometry2,
out, strategy());
}
}} // namespace detail::difference
#endif // DOXYGEN_NO_DETAIL
/*!
\brief_calc2{difference}
\ingroup difference
\details \details_calc2{difference, spatial set theoretic difference}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection \tparam_output_collection
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\qbk{[include reference/algorithms/difference.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection
>
inline void difference(Geometry1 const& geometry1,
Geometry2 const& geometry2, Collection& output_collection)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
detail::difference::difference_insert<geometry_out>(
geometry1, geometry2,
std::back_inserter(output_collection));
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP

View File

@@ -0,0 +1,253 @@
// 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_DISJOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
#include <cstddef>
#include <deque>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
#include <boost/static_assert.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename Geometry1, typename Geometry2>
struct disjoint_linear
{
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef overlay::turn_info<point_type> turn_info;
std::deque<turn_info> turns;
// Get (and stop on) any intersection
disjoint_interrupt_policy policy;
geometry::get_turns
<
false, false,
overlay::assign_null_policy
>(geometry1, geometry2, turns, policy);
if (policy.has_intersections)
{
return false;
}
return true;
}
};
template <typename Segment1, typename Segment2>
struct disjoint_segment
{
static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
{
typedef typename point_type<Segment1>::type point_type;
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);
return is.count == 0;
}
};
template <typename Geometry1, typename Geometry2>
struct general_areal
{
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
if (! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2))
{
return false;
}
typedef typename geometry::point_type<Geometry1>::type point_type;
// If there is no intersection of segments, they might located
// inside each other
point_type p1;
geometry::point_on_border(p1, geometry1);
if (geometry::within(p1, geometry2))
{
return false;
}
typename geometry::point_type<Geometry1>::type p2;
geometry::point_on_border(p2, geometry2);
if (geometry::within(p2, geometry1))
{
return false;
}
return true;
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
std::size_t DimensionCount
>
struct disjoint
: detail::disjoint::general_areal<Geometry1, Geometry2>
{};
template <typename Point1, typename Point2, std::size_t DimensionCount>
struct disjoint<point_tag, point_tag, Point1, Point2, DimensionCount>
: detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
{};
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct disjoint<box_tag, box_tag, Box1, Box2, DimensionCount>
: detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
{};
template <typename Point, typename Box, std::size_t DimensionCount>
struct disjoint<point_tag, box_tag, Point, Box, DimensionCount>
: detail::disjoint::point_box<Point, Box, 0, DimensionCount>
{};
template <typename Linestring1, typename Linestring2>
struct disjoint<linestring_tag, linestring_tag, Linestring1, Linestring2, 2>
: detail::disjoint::disjoint_linear<Linestring1, Linestring2>
{};
template <typename Linestring1, typename Linestring2>
struct disjoint<segment_tag, segment_tag, Linestring1, Linestring2, 2>
: detail::disjoint::disjoint_segment<Linestring1, Linestring2>
{};
template <typename Linestring, typename Segment>
struct disjoint<linestring_tag, segment_tag, Linestring, Segment, 2>
: detail::disjoint::disjoint_linear<Linestring, Segment>
{};
template
<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
std::size_t DimensionCount
>
struct disjoint_reversed
{
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
{
return disjoint
<
GeometryTag2, GeometryTag1,
Geometry2, Geometry1,
DimensionCount
>::apply(g2, g1);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check2{are disjoint}
\ingroup disjoint
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{are disjoint}
*/
template <typename Geometry1, typename Geometry2>
inline bool disjoint(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
concept::check_concepts_and_equal_dimensions
<
Geometry1 const,
Geometry2 const
>();
return boost::mpl::if_c
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::disjoint_reversed
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
dimension<Geometry1>::type::value
>,
dispatch::disjoint
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
dimension<Geometry1>::type::value
>
>::type::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP

View File

@@ -0,0 +1,569 @@
// 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_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/default_distance_result.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
// To avoid spurious namespaces here:
using strategy::distance::services::return_type;
template <typename P1, typename P2, typename Strategy>
struct point_to_point
{
static inline typename return_type<Strategy>::type apply(P1 const& p1,
P2 const& p2, Strategy const& strategy)
{
return strategy.apply(p1, p2);
}
};
template<typename Point, typename Segment, typename Strategy>
struct point_to_segment
{
static inline typename return_type<Strategy>::type apply(Point const& point,
Segment const& segment, Strategy const& strategy)
{
typename strategy::distance::services::default_strategy
<
segment_tag,
Point,
typename point_type<Segment>::type,
typename cs_tag<Point>::type,
typename cs_tag<typename point_type<Segment>::type>::type,
Strategy
>::type segment_strategy;
typename point_type<Segment>::type p[2];
geometry::detail::assign_point_from_index<0>(segment, p[0]);
geometry::detail::assign_point_from_index<1>(segment, p[1]);
return segment_strategy.apply(point, p[0], p[1]);
}
};
template
<
typename Point,
typename Range,
closure_selector Closure,
typename PPStrategy,
typename PSStrategy
>
struct point_to_range
{
typedef typename return_type<PSStrategy>::type return_type;
static inline return_type apply(Point const& point, Range const& range,
PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
{
return_type const zero = return_type(0);
if (boost::size(range) == 0)
{
return zero;
}
typedef typename closeable_view<Range const, Closure>::type view_type;
view_type view(range);
// line of one point: return point distance
typedef typename boost::range_iterator<view_type const>::type iterator_type;
iterator_type it = boost::begin(view);
iterator_type prev = it++;
if (it == boost::end(view))
{
return pp_strategy.apply(point, *boost::begin(view));
}
// Create comparable (more efficient) strategy
typedef typename strategy::distance::services::comparable_type<PSStrategy>::type eps_strategy_type;
eps_strategy_type eps_strategy = strategy::distance::services::get_comparable<PSStrategy>::apply(ps_strategy);
// start with first segment distance
return_type d = eps_strategy.apply(point, *prev, *it);
return_type rd = ps_strategy.apply(point, *prev, *it);
// check if other segments are closer
for (++prev, ++it; it != boost::end(view); ++prev, ++it)
{
return_type const ds = ps_strategy.apply(point, *prev, *it);
if (geometry::math::equals(ds, zero))
{
return ds;
}
else if (ds < d)
{
d = ds;
rd = ps_strategy.apply(point, *prev, *it);
}
}
return rd;
}
};
template
<
typename Point,
typename Ring,
closure_selector Closure,
typename PPStrategy,
typename PSStrategy
>
struct point_to_ring
{
typedef std::pair
<
typename return_type<PPStrategy>::type, bool
> distance_containment;
static inline distance_containment apply(Point const& point,
Ring const& ring,
PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
{
return distance_containment
(
point_to_range
<
Point,
Ring,
Closure,
PPStrategy,
PSStrategy
>::apply(point, ring, pp_strategy, ps_strategy),
geometry::within(point, ring)
);
}
};
template
<
typename Point,
typename Polygon,
closure_selector Closure,
typename PPStrategy,
typename PSStrategy
>
struct point_to_polygon
{
typedef typename return_type<PPStrategy>::type return_type;
typedef std::pair<return_type, bool> distance_containment;
static inline distance_containment apply(Point const& point,
Polygon const& polygon,
PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
{
// Check distance to all rings
typedef point_to_ring
<
Point,
typename ring_type<Polygon>::type,
Closure,
PPStrategy,
PSStrategy
> per_ring;
distance_containment dc = per_ring::apply(point,
exterior_ring(polygon), pp_strategy, ps_strategy);
typename interior_return_type<Polygon const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
distance_containment dcr = per_ring::apply(point,
*it, pp_strategy, ps_strategy);
if (dcr.first < dc.first)
{
dc.first = dcr.first;
}
// If it was inside, and also inside inner ring,
// turn off the inside-flag, it is outside the polygon
if (dc.second && dcr.second)
{
dc.second = false;
}
}
return dc;
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
using strategy::distance::services::return_type;
template
<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
typename StrategyTag, typename Strategy
>
struct distance
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry1, Geometry2>)
);
};
template <typename P1, typename P2, typename Strategy>
struct distance
<
point_tag, point_tag,
P1, P2,
strategy_tag_distance_point_point, Strategy
>
: detail::distance::point_to_point<P1, P2, Strategy>
{};
// Point-line version 1, where point-point strategy is specified
template <typename Point, typename Linestring, typename Strategy>
struct distance
<
point_tag, linestring_tag,
Point, Linestring,
strategy_tag_distance_point_point, Strategy
>
{
static inline typename return_type<Strategy>::type apply(Point const& point,
Linestring const& linestring,
Strategy const& strategy)
{
typedef typename strategy::distance::services::default_strategy
<
segment_tag,
Point,
typename point_type<Linestring>::type
>::type ps_strategy_type;
return detail::distance::point_to_range
<
Point, Linestring, closed, Strategy, ps_strategy_type
>::apply(point, linestring, strategy, ps_strategy_type());
}
};
// Point-line version 2, where point-segment strategy is specified
template <typename Point, typename Linestring, typename Strategy>
struct distance
<
point_tag, linestring_tag,
Point, Linestring,
strategy_tag_distance_point_segment, Strategy
>
{
static inline typename return_type<Strategy>::type apply(Point const& point,
Linestring const& linestring,
Strategy const& strategy)
{
typedef typename Strategy::point_strategy_type pp_strategy_type;
return detail::distance::point_to_range
<
Point, Linestring, closed, pp_strategy_type, Strategy
>::apply(point, linestring, pp_strategy_type(), strategy);
}
};
// Point-ring , where point-segment strategy is specified
template <typename Point, typename Ring, typename Strategy>
struct distance
<
point_tag, ring_tag,
Point, Ring,
strategy_tag_distance_point_point, Strategy
>
{
typedef typename return_type<Strategy>::type return_type;
static inline return_type apply(Point const& point,
Ring const& ring,
Strategy const& strategy)
{
typedef typename strategy::distance::services::default_strategy
<
segment_tag,
Point,
typename point_type<Ring>::type
>::type ps_strategy_type;
std::pair<return_type, bool>
dc = detail::distance::point_to_ring
<
Point, Ring,
geometry::closure<Ring>::value,
Strategy, ps_strategy_type
>::apply(point, ring, strategy, ps_strategy_type());
return dc.second ? return_type(0) : dc.first;
}
};
// Point-polygon , where point-segment strategy is specified
template <typename Point, typename Polygon, typename Strategy>
struct distance
<
point_tag, polygon_tag,
Point, Polygon,
strategy_tag_distance_point_point, Strategy
>
{
typedef typename return_type<Strategy>::type return_type;
static inline return_type apply(Point const& point,
Polygon const& polygon,
Strategy const& strategy)
{
typedef typename strategy::distance::services::default_strategy
<
segment_tag,
Point,
typename point_type<Polygon>::type
>::type ps_strategy_type;
std::pair<return_type, bool>
dc = detail::distance::point_to_polygon
<
Point, Polygon,
geometry::closure<Polygon>::value,
Strategy, ps_strategy_type
>::apply(point, polygon, strategy, ps_strategy_type());
return dc.second ? return_type(0) : dc.first;
}
};
// Point-segment version 1, with point-point strategy
template <typename Point, typename Segment, typename Strategy>
struct distance
<
point_tag, segment_tag,
Point, Segment,
strategy_tag_distance_point_point, Strategy
> : detail::distance::point_to_segment<Point, Segment, Strategy>
{};
// Point-segment version 2, with point-segment strategy
template <typename Point, typename Segment, typename Strategy>
struct distance
<
point_tag, segment_tag,
Point, Segment,
strategy_tag_distance_point_segment, Strategy
>
{
static inline typename return_type<Strategy>::type apply(Point const& point,
Segment const& segment, Strategy const& strategy)
{
typename point_type<Segment>::type p[2];
geometry::detail::assign_point_from_index<0>(segment, p[0]);
geometry::detail::assign_point_from_index<1>(segment, p[1]);
return strategy.apply(point, p[0], p[1]);
}
};
// Strictly spoken this might be in namespace <impl> again
template
<
typename GeometryTag1, typename GeometryTag2,
typename G1, typename G2,
typename StrategyTag, typename Strategy
>
struct distance_reversed
{
static inline typename return_type<Strategy>::type apply(G1 const& g1,
G2 const& g2, Strategy const& strategy)
{
return distance
<
GeometryTag2, GeometryTag1,
G2, G1,
StrategyTag, Strategy
>::apply(g2, g1, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc2{distance} \brief_strategy
\ingroup distance
\details
\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Distance}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{distance}
\return \return_calc{distance}
\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
it may also be a point-segment strategy.
\qbk{distinguish,with strategy}
\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
\* more (currently extensions): Vincenty\, Andoyer (geographic)
}
*/
/*
Note, in case of a Compilation Error:
if you get:
- "Failed to specialize function template ..."
- "error: no matching function for call to ..."
for distance, it is probably so that there is no specialization
for return_type<...> for your strategy.
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline typename strategy::distance::services::return_type<Strategy>::type distance(
Geometry1 const& geometry1,
Geometry2 const& geometry2, Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
return boost::mpl::if_
<
typename geometry::reverse_dispatch<Geometry1, Geometry2>::type,
dispatch::distance_reversed
<
typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
Geometry1,
Geometry2,
typename strategy::distance::services::tag<Strategy>::type,
Strategy
>,
dispatch::distance
<
typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
Geometry1,
Geometry2,
typename strategy::distance::services::tag<Strategy>::type,
Strategy
>
>::type::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_calc2{distance}
\ingroup distance
\details The default strategy is used, corresponding to the coordinate system of the geometries
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_calc{distance}
\qbk{[include reference/algorithms/distance.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline typename default_distance_result<Geometry1, Geometry2>::type distance(
Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename point_type<Geometry1>::type point1_type;
typedef typename point_type<Geometry2>::type point2_type;
// Define a point-point-distance-strategy
// for either the normal case, either the reversed case
typedef typename boost::mpl::if_c
<
geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
typename strategy::distance::services::default_strategy
<
point_tag,
point2_type,
point1_type
>::type,
typename strategy::distance::services::default_strategy
<
point_tag,
point1_type,
point2_type
>::type
>::type strategy;
return distance(geometry1, geometry2, strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP

View File

@@ -0,0 +1,279 @@
// 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_ENVELOPE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
/// Calculate envelope of an 2D or 3D segment
template<typename Geometry, typename Box>
struct envelope_expand_one
{
static inline void apply(Geometry const& geometry, Box& mbr)
{
assign_inverse(mbr);
geometry::expand(mbr, geometry);
}
};
/// Iterate through range (also used in multi*)
template<typename Range, typename Box>
inline void envelope_range_additional(Range const& range, Box& mbr)
{
typedef typename boost::range_iterator<Range const>::type iterator_type;
for (iterator_type it = boost::begin(range);
it != boost::end(range);
++it)
{
geometry::expand(mbr, *it);
}
}
/// Generic range dispatching struct
template <typename Range, typename Box>
struct envelope_range
{
/// Calculate envelope of range using a strategy
static inline void apply(Range const& range, Box& mbr)
{
assign_inverse(mbr);
envelope_range_additional(range, mbr);
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// Note, the strategy is for future use (less/greater -> compare spherical
// using other methods), defaults are OK for now.
// However, they are already in the template methods
template
<
typename Tag1, typename Tag2,
typename Geometry, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template
<
typename Point, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
point_tag, box_tag,
Point, Box,
StrategyLess, StrategyGreater
>
: detail::envelope::envelope_expand_one<Point, Box>
{};
template
<
typename BoxIn, typename BoxOut,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
box_tag, box_tag,
BoxIn, BoxOut,
StrategyLess, StrategyGreater
>
: detail::envelope::envelope_expand_one<BoxIn, BoxOut>
{};
template
<
typename Segment, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
segment_tag, box_tag,
Segment, Box,
StrategyLess, StrategyGreater
>
: detail::envelope::envelope_expand_one<Segment, Box>
{};
template
<
typename Linestring, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
linestring_tag, box_tag,
Linestring, Box,
StrategyLess, StrategyGreater
>
: detail::envelope::envelope_range<Linestring, Box>
{};
template
<
typename Ring, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
ring_tag, box_tag,
Ring, Box,
StrategyLess, StrategyGreater
>
: detail::envelope::envelope_range<Ring, Box>
{};
template
<
typename Polygon, typename Box,
typename StrategyLess, typename StrategyGreater
>
struct envelope
<
polygon_tag, box_tag,
Polygon, Box,
StrategyLess, StrategyGreater
>
{
static inline void apply(Polygon const& poly, Box& mbr)
{
// For polygon, inspecting outer ring is sufficient
detail::envelope::envelope_range
<
typename ring_type<Polygon>::type,
Box
>::apply(exterior_ring(poly), mbr);
}
};
} // namespace dispatch
#endif
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{envelope,\det_envelope}.
\tparam Geometry \tparam_geometry
\tparam Box \tparam_box
\param geometry \param_geometry
\param mbr \param_box \param_set{envelope}
\par Example:
Example showing envelope calculation, using point_ll latlong points
\dontinclude doxygen_1.cpp
\skip example_envelope_polygon
\line {
\until }
\qbk{
[heading Example]
[envelope] [envelope_output]
}
*/
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
concept::check<Geometry const>();
concept::check<Box>();
dispatch::envelope
<
typename tag<Geometry>::type, typename tag<Box>::type,
Geometry, Box,
void, void
>::apply(geometry, mbr);
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{return_envelope,\det_envelope}. \details_return{envelope}
\tparam Box \tparam_box
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{envelope}
\qbk{
[heading Example]
[return_envelope] [return_envelope_output]
}
*/
template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
concept::check<Geometry const>();
concept::check<Box>();
Box mbr;
dispatch::envelope
<
typename tag<Geometry>::type, typename tag<Box>::type,
Geometry, Box,
void, void
>::apply(geometry, mbr);
return mbr;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP

View File

@@ -0,0 +1,319 @@
// 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_EQUALS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
#include <cstddef>
#include <vector>
#include <boost/mpl/if.hpp>
#include <boost/static_assert.hpp>
#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/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/algorithms/detail/not.hpp>
// For trivial checks
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace equals
{
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 (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
|| !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
{
return false;
}
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 true;
}
};
struct area_check
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return geometry::math::equals(
geometry::area(geometry1),
geometry::area(geometry2));
}
};
struct length_check
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return geometry::math::equals(
geometry::length(geometry1),
geometry::length(geometry2));
}
};
template <typename Geometry1, typename Geometry2, typename TrivialCheck>
struct equals_by_collection
{
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
if (! TrivialCheck::apply(geometry1, geometry2))
{
return false;
}
typedef typename geometry::select_most_precise
<
typename select_coordinate_type
<
Geometry1, Geometry2
>::type,
double
>::type calculation_type;
typedef std::vector<collected_vector<calculation_type> > v;
v c1, c2;
geometry::collect_vectors(c1, geometry1);
geometry::collect_vectors(c2, geometry2);
if (boost::size(c1) != boost::size(c2))
{
return false;
}
std::sort(c1.begin(), c1.end());
std::sort(c2.begin(), c2.end());
// Just check if these vectors are equal.
return std::equal(c1.begin(), c1.end(), c2.begin());
}
};
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1, typename Tag2,
typename Geometry1,
typename Geometry2,
std::size_t DimensionCount
>
struct equals
{};
template <typename P1, typename P2, std::size_t DimensionCount>
struct equals<point_tag, point_tag, P1, P2, DimensionCount>
: geometry::detail::not_
<
P1,
P2,
detail::disjoint::point_point<P1, P2, 0, DimensionCount>
>
{};
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct equals<box_tag, box_tag, Box1, Box2, DimensionCount>
: detail::equals::box_box<Box1, Box2, 0, DimensionCount>
{};
template <typename Ring1, typename Ring2>
struct equals<ring_tag, ring_tag, Ring1, Ring2, 2>
: detail::equals::equals_by_collection
<
Ring1, Ring2,
detail::equals::area_check
>
{};
template <typename Polygon1, typename Polygon2>
struct equals<polygon_tag, polygon_tag, Polygon1, Polygon2, 2>
: detail::equals::equals_by_collection
<
Polygon1, Polygon2,
detail::equals::area_check
>
{};
template <typename LineString1, typename LineString2>
struct equals<linestring_tag, linestring_tag, LineString1, LineString2, 2>
: detail::equals::equals_by_collection
<
LineString1, LineString2,
detail::equals::length_check
>
{};
template <typename Polygon, typename Ring>
struct equals<polygon_tag, ring_tag, Polygon, Ring, 2>
: detail::equals::equals_by_collection
<
Polygon, Ring,
detail::equals::area_check
>
{};
template <typename Ring, typename Box>
struct equals<ring_tag, box_tag, Ring, Box, 2>
: detail::equals::equals_by_collection
<
Ring, Box,
detail::equals::area_check
>
{};
template <typename Polygon, typename Box>
struct equals<polygon_tag, box_tag, Polygon, Box, 2>
: detail::equals::equals_by_collection
<
Polygon, Box,
detail::equals::area_check
>
{};
template
<
typename Tag1, typename Tag2,
typename Geometry1,
typename Geometry2,
std::size_t DimensionCount
>
struct equals_reversed
{
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
{
return equals
<
Tag2, Tag1,
Geometry2, Geometry1,
DimensionCount
>::apply(g2, g1);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check{are spatially equal}
\details \details_check12{equals, is spatially equal}. Spatially equal means
that the same point set is included. A box can therefore be spatially equal
to a ring or a polygon, or a linestring can be spatially equal to a
multi-linestring or a segment. This only theoretically, not all combinations
are implemented yet.
\ingroup equals
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{are spatially equal}
\qbk{[include reference/algorithms/equals.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check_concepts_and_equal_dimensions
<
Geometry1 const,
Geometry2 const
>();
return boost::mpl::if_c
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::equals_reversed
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
dimension<Geometry1>::type::value
>,
dispatch::equals
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
dimension<Geometry1>::type::value
>
>::type::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP

View File

@@ -0,0 +1,319 @@
// 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_EXPAND_HPP
#define BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace expand
{
template
<
typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_loop
{
typedef typename strategy::compare::detail::select_strategy
<
StrategyLess, 1, Point, Dimension
>::type less_type;
typedef typename strategy::compare::detail::select_strategy
<
StrategyGreater, -1, Point, Dimension
>::type greater_type;
typedef typename select_coordinate_type<Point, Box>::type coordinate_type;
static inline void apply(Box& box, Point const& source)
{
less_type less;
greater_type greater;
coordinate_type const coord = get<Dimension>(source);
if (less(coord, get<min_corner, Dimension>(box)))
{
set<min_corner, Dimension>(box, coord);
}
if (greater(coord, get<max_corner, Dimension>(box)))
{
set<max_corner, Dimension>(box, coord);
}
point_loop
<
Box, Point,
StrategyLess, StrategyGreater,
Dimension + 1, DimensionCount
>::apply(box, source);
}
};
template
<
typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t DimensionCount
>
struct point_loop
<
Box, Point,
StrategyLess, StrategyGreater,
DimensionCount, DimensionCount
>
{
static inline void apply(Box&, Point const&) {}
};
template
<
typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct indexed_loop
{
typedef typename strategy::compare::detail::select_strategy
<
StrategyLess, 1, Box, Dimension
>::type less_type;
typedef typename strategy::compare::detail::select_strategy
<
StrategyGreater, -1, Box, Dimension
>::type greater_type;
typedef typename select_coordinate_type
<
Box,
Geometry
>::type coordinate_type;
static inline void apply(Box& box, Geometry const& source)
{
less_type less;
greater_type greater;
coordinate_type const coord = get<Index, Dimension>(source);
if (less(coord, get<min_corner, Dimension>(box)))
{
set<min_corner, Dimension>(box, coord);
}
if (greater(coord, get<max_corner, Dimension>(box)))
{
set<max_corner, Dimension>(box, coord);
}
indexed_loop
<
Box, Geometry,
StrategyLess, StrategyGreater,
Index, Dimension + 1, DimensionCount
>::apply(box, source);
}
};
template
<
typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index, std::size_t DimensionCount
>
struct indexed_loop
<
Box, Geometry,
StrategyLess, StrategyGreater,
Index, DimensionCount, DimensionCount
>
{
static inline void apply(Box&, Geometry const&) {}
};
// Changes a box such that the other box is also contained by the box
template
<
typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
struct expand_indexed
{
static inline void apply(Box& box, Geometry const& geometry)
{
indexed_loop
<
Box, Geometry,
StrategyLess, StrategyGreater,
0, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
indexed_loop
<
Box, Geometry,
StrategyLess, StrategyGreater,
1, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
}
};
}} // namespace detail::expand
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename BoxOut, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
struct expand
{};
// Box + point -> new box containing also point
template
<
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater
>
struct expand<point_tag, BoxOut, Point, StrategyLess, StrategyGreater>
: detail::expand::point_loop
<
BoxOut, Point,
StrategyLess, StrategyGreater,
0, dimension<Point>::type::value
>
{};
// Box + box -> new box containing two input boxes
template
<
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater
>
struct expand<box_tag, BoxOut, BoxIn, StrategyLess, StrategyGreater>
: detail::expand::expand_indexed
<BoxOut, BoxIn, StrategyLess, StrategyGreater>
{};
template
<
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater
>
struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater>
: detail::expand::expand_indexed
<Box, Segment, StrategyLess, StrategyGreater>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/***
*!
\brief Expands a box using the extend (envelope) of another geometry (box, point)
\ingroup expand
\tparam Box type of the box
\tparam Geometry of second geometry, to be expanded with the box
\param box box to expand another geometry with, might be changed
\param geometry other geometry
\param strategy_less
\param strategy_greater
\note Strategy is currently ignored
*
template
<
typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
inline void expand(Box& box, Geometry const& geometry,
StrategyLess const& strategy_less,
StrategyGreater const& strategy_greater)
{
concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
dispatch::expand
<
typename tag<Geometry>::type,
Box,
Geometry,
StrategyLess, StrategyGreater
>::apply(box, geometry);
}
***/
/*!
\brief Expands a box using the bounding box (envelope) of another geometry (box, point)
\ingroup expand
\tparam Box type of the box
\tparam Geometry \tparam_geometry
\param box box to be expanded using another geometry, mutable
\param geometry \param_geometry geometry which envelope (bounding box) will be added to the box
\qbk{[include reference/algorithms/expand.qbk]}
*/
template <typename Box, typename Geometry>
inline void expand(Box& box, Geometry const& geometry)
{
concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
dispatch::expand
<
typename tag<Geometry>::type,
Box, Geometry,
strategy::compare::default_strategy,
strategy::compare::default_strategy
>::apply(box, geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP

View File

@@ -0,0 +1,351 @@
// 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_FOR_EACH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_FOR_EACH_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/segment.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 Point, typename Functor, bool IsConst>
struct fe_point_per_point
{
static inline Functor apply(
typename add_const_if_c<IsConst, Point>::type& point, Functor f)
{
f(point);
return f;
}
};
template <typename Point, typename Functor, bool IsConst>
struct fe_point_per_segment
{
static inline Functor apply(
typename add_const_if_c<IsConst, Point>::type& point, Functor f)
{
return f;
}
};
template <typename Range, typename Functor, bool IsConst>
struct fe_range_per_point
{
static inline Functor apply(
typename add_const_if_c<IsConst, Range>::type& range,
Functor f)
{
return (std::for_each(boost::begin(range), boost::end(range), f));
}
};
template <typename Range, typename Functor, bool IsConst>
struct fe_range_per_segment
{
static inline Functor apply(
typename add_const_if_c<IsConst, Range>::type& range,
Functor f)
{
typedef typename add_const_if_c
<
IsConst,
typename point_type<Range>::type
>::type point_type;
BOOST_AUTO_TPL(it, boost::begin(range));
BOOST_AUTO_TPL(previous, it++);
while(it != boost::end(range))
{
model::referring_segment<point_type> s(*previous, *it);
f(s);
previous = it++;
}
return f;
}
};
template <typename Polygon, typename Functor, bool IsConst>
struct fe_polygon_per_point
{
typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
static inline Functor apply(poly_type& poly, Functor f)
{
typedef fe_range_per_point
<
typename ring_type<Polygon>::type,
Functor,
IsConst
> per_ring;
f = per_ring::apply(exterior_ring(poly), f);
typename interior_return_type<poly_type>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
f = per_ring::apply(*it, f);
}
return f;
}
};
template <typename Polygon, typename Functor, bool IsConst>
struct fe_polygon_per_segment
{
typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
static inline Functor apply(poly_type& poly, Functor f)
{
typedef fe_range_per_segment
<
typename ring_type<Polygon>::type,
Functor,
IsConst
> per_ring;
f = per_ring::apply(exterior_ring(poly), f);
typename interior_return_type<poly_type>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
f = per_ring::apply(*it, f);
}
return f;
}
};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename Functor,
bool IsConst
>
struct for_each_point {};
template <typename Point, typename Functor, bool IsConst>
struct for_each_point<point_tag, Point, Functor, IsConst>
: detail::for_each::fe_point_per_point<Point, Functor, IsConst>
{};
template <typename Linestring, typename Functor, bool IsConst>
struct for_each_point<linestring_tag, Linestring, Functor, IsConst>
: detail::for_each::fe_range_per_point<Linestring, Functor, IsConst>
{};
template <typename Ring, typename Functor, bool IsConst>
struct for_each_point<ring_tag, Ring, Functor, IsConst>
: detail::for_each::fe_range_per_point<Ring, Functor, IsConst>
{};
template <typename Polygon, typename Functor, bool IsConst>
struct for_each_point<polygon_tag, Polygon, Functor, IsConst>
: detail::for_each::fe_polygon_per_point<Polygon, Functor, IsConst>
{};
template
<
typename Tag,
typename Geometry,
typename Functor,
bool IsConst
>
struct for_each_segment {};
template <typename Point, typename Functor, bool IsConst>
struct for_each_segment<point_tag, Point, Functor, IsConst>
: detail::for_each::fe_point_per_segment<Point, Functor, IsConst>
{};
template <typename Linestring, typename Functor, bool IsConst>
struct for_each_segment<linestring_tag, Linestring, Functor, IsConst>
: detail::for_each::fe_range_per_segment<Linestring, Functor, IsConst>
{};
template <typename Ring, typename Functor, bool IsConst>
struct for_each_segment<ring_tag, Ring, Functor, IsConst>
: detail::for_each::fe_range_per_segment<Ring, Functor, IsConst>
{};
template <typename Polygon, typename Functor, bool IsConst>
struct for_each_segment<polygon_tag, Polygon, Functor, IsConst>
: detail::for_each::fe_polygon_per_segment<Polygon, Functor, IsConst>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brf_for_each{point}
\details \det_for_each{point}
\ingroup for_each
\param geometry \param_geometry
\param f \par_for_each_f{const point}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
\qbk{distinguish,const version}
\qbk{[heading Example]}
\qbk{[for_each_point_const] [for_each_point_const_output]}
*/
template<typename Geometry, typename Functor>
inline Functor for_each_point(Geometry const& geometry, Functor f)
{
concept::check<Geometry const>();
return dispatch::for_each_point
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry,
Functor,
true
>::apply(geometry, f);
}
/*!
\brief \brf_for_each{point}
\details \det_for_each{point}
\ingroup for_each
\param geometry \param_geometry
\param f \par_for_each_f{point}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
\qbk{[heading Example]}
\qbk{[for_each_point] [for_each_point_output]}
*/
template<typename Geometry, typename Functor>
inline Functor for_each_point(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
return dispatch::for_each_point
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry,
Functor,
false
>::apply(geometry, f);
}
/*!
\brief \brf_for_each{segment}
\details \det_for_each{segment}
\ingroup for_each
\param geometry \param_geometry
\param f \par_for_each_f{const segment}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
\qbk{distinguish,const version}
\qbk{[heading Example]}
\qbk{[for_each_segment_const] [for_each_segment_const_output]}
*/
template<typename Geometry, typename Functor>
inline Functor for_each_segment(Geometry const& geometry, Functor f)
{
concept::check<Geometry const>();
return dispatch::for_each_segment
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry,
Functor,
true
>::apply(geometry, f);
}
/*!
\brief \brf_for_each{segment}
\details \det_for_each{segment}
\ingroup for_each
\param geometry \param_geometry
\param f \par_for_each_f{segment}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
*/
template<typename Geometry, typename Functor>
inline Functor for_each_segment(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
return dispatch::for_each_segment
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry,
Functor,
false
>::apply(geometry, f);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_FOR_EACH_HPP

View File

@@ -0,0 +1,237 @@
// 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_INTERSECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersection
{
template
<
typename Box1, typename Box2,
typename BoxOut,
typename Strategy,
std::size_t Dimension, std::size_t DimensionCount
>
struct intersection_box_box
{
static inline bool apply(Box1 const& box1,
Box2 const& box2, BoxOut& box_out,
Strategy const& strategy)
{
typedef typename coordinate_type<BoxOut>::type ct;
ct min1 = get<min_corner, Dimension>(box1);
ct min2 = get<min_corner, Dimension>(box2);
ct max1 = get<max_corner, Dimension>(box1);
ct max2 = get<max_corner, Dimension>(box2);
if (max1 < min2 || max2 < min1)
{
return false;
}
// Set dimensions of output coordinate
set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
return intersection_box_box
<
Box1, Box2, BoxOut, Strategy,
Dimension + 1, DimensionCount
>::apply(box1, box2, box_out, strategy);
}
};
template
<
typename Box1, typename Box2,
typename BoxOut,
typename Strategy,
std::size_t DimensionCount
>
struct intersection_box_box<Box1, Box2, BoxOut, Strategy, DimensionCount, DimensionCount>
{
static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&)
{
return true;
}
};
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// By default, all is forwarded to the intersection_insert-dispatcher
template
<
typename Tag1, typename Tag2, typename TagOut,
typename Geometry1, typename Geometry2,
typename GeometryOut,
typename Strategy
>
struct intersection
{
typedef std::back_insert_iterator<GeometryOut> output_iterator;
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
typedef typename boost::range_value<GeometryOut>::type OneOut;
intersection_insert
<
Tag1, Tag2, typename geometry::tag<OneOut>::type,
geometry::is_areal<Geometry1>::value,
geometry::is_areal<Geometry2>::value,
geometry::is_areal<OneOut>::value,
Geometry1, Geometry2,
detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, false>::value,
detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, false>::value,
detail::overlay::do_reverse<geometry::point_order<OneOut>::value>::value,
output_iterator, OneOut,
overlay_intersection,
Strategy
>::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy);
return true;
}
};
template
<
typename Box1, typename Box2,
typename BoxOut,
typename Strategy
>
struct intersection
<
box_tag, box_tag, box_tag,
Box1, Box2, BoxOut,
Strategy
> : public detail::intersection::intersection_box_box
<
Box1, Box2, BoxOut,
Strategy,
0, geometry::dimension<Box1>::value
>
{};
template
<
typename Tag1, typename Tag2, typename TagOut,
typename Geometry1, typename Geometry2,
typename GeometryOut,
typename Strategy
>
struct intersection_reversed
{
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
return intersection
<
Tag2, Tag1, TagOut,
Geometry2, Geometry1,
GeometryOut, Strategy
>::apply(geometry2, geometry1, geometry_out, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc2{intersection}
\ingroup intersection
\details \details_calc2{intersection, spatial set theoretic intersection}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry_out The output geometry, either a multi_point, multi_polygon,
multi_linestring, or a box (for intersection of two boxes)
\qbk{[include reference/algorithms/intersection.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename GeometryOut
>
inline bool intersection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef strategy_intersection
<
typename cs_tag<Geometry1>::type,
Geometry1,
Geometry2,
typename geometry::point_type<Geometry1>::type
> strategy;
return boost::mpl::if_c
<
geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::intersection_reversed
<
typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type,
typename geometry::tag<GeometryOut>::type,
Geometry1, Geometry2, GeometryOut, strategy
>,
dispatch::intersection
<
typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type,
typename geometry::tag<GeometryOut>::type,
Geometry1, Geometry2, GeometryOut, strategy
>
>::type::apply(geometry1, geometry2, geometry_out, strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP

View File

@@ -0,0 +1,105 @@
// 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_INTERSECTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP
#include <deque>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
namespace boost { namespace geometry
{
/*!
\brief \brief_check{has at least one intersection (crossing or self-tangency)}
\note This function can be called for one geometry (self-intersection) and
also for two geometries (intersection)
\ingroup intersects
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_check{is self-intersecting}
\qbk{distinguish,one geometry}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry>
inline bool intersects(Geometry const& geometry)
{
concept::check<Geometry const>();
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry>::type
> turn_info;
std::deque<turn_info> turns;
typedef typename strategy_intersection
<
typename cs_tag<Geometry>::type,
Geometry,
Geometry,
typename geometry::point_type<Geometry>::type
>::segment_intersection_strategy_type segment_intersection_strategy_type;
typedef detail::overlay::get_turn_info
<
typename point_type<Geometry>::type,
typename point_type<Geometry>::type,
turn_info,
detail::overlay::assign_null_policy
> TurnPolicy;
detail::disjoint::disjoint_interrupt_policy policy;
detail::self_get_turn_points::get_turns
<
Geometry,
std::deque<turn_info>,
TurnPolicy,
detail::disjoint::disjoint_interrupt_policy
>::apply(geometry, turns, policy);
return policy.has_intersections;
}
/*!
\brief \brief_check2{have at least one intersection}
\ingroup intersects
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{intersect each other}
\qbk{distinguish,two geometries}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
return ! geometry::disjoint(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP

View File

@@ -0,0 +1,199 @@
// 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_LENGTH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP
#include <iterator>
#include <boost/range.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/default_length_result.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace length
{
template<typename Segment, typename Strategy>
struct segment_length
{
static inline typename default_length_result<Segment>::type apply(
Segment const& segment, Strategy const& strategy)
{
typedef typename point_type<Segment>::type point_type;
point_type p1, p2;
geometry::detail::assign_point_from_index<0>(segment, p1);
geometry::detail::assign_point_from_index<1>(segment, p2);
return strategy.apply(p1, p2);
}
};
/*!
\brief Internal, calculates length of a linestring using iterator pairs and
specified strategy
\note for_each could be used here, now that point_type is changed by boost
range iterator
*/
template<typename Range, typename Strategy, closure_selector Closure>
struct range_length
{
typedef typename default_length_result<Range>::type return_type;
static inline return_type apply(
Range const& range, Strategy const& strategy)
{
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator
<
view_type const
>::type iterator_type;
return_type sum = return_type();
view_type view(range);
iterator_type it = boost::begin(view), end = boost::end(view);
if(it != end)
{
for(iterator_type previous = it++;
it != end;
++previous, ++it)
{
// Add point-point distance using the return type belonging
// to strategy
sum += strategy.apply(*previous, *it);
}
}
return sum;
}
};
}} // namespace detail::length
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry, typename Strategy>
struct length : detail::calculate_null
<
typename default_length_result<Geometry>::type,
Geometry,
Strategy
>
{};
template <typename Geometry, typename Strategy>
struct length<linestring_tag, Geometry, Strategy>
: detail::length::range_length<Geometry, Strategy, closed>
{};
// RING: length is currently 0; it might be argued that it is the "perimeter"
template <typename Geometry, typename Strategy>
struct length<segment_tag, Geometry, Strategy>
: detail::length::segment_length<Geometry, Strategy>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc{length}
\ingroup length
\details \details_calc{length, length (the sum of distances between consecutive points)}. \details_default_strategy
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{length}
\qbk{[include reference/algorithms/length.qbk]}
\qbk{[length] [length_output]}
*/
template<typename Geometry>
inline typename default_length_result<Geometry>::type length(
Geometry const& geometry)
{
concept::check<Geometry const>();
typedef typename strategy::distance::services::default_strategy
<
point_tag, typename point_type<Geometry>::type
>::type strategy_type;
return dispatch::length
<
typename tag<Geometry>::type,
Geometry,
strategy_type
>::apply(geometry, strategy_type());
}
/*!
\brief \brief_calc{length} \brief_strategy
\ingroup length
\details \details_calc{length, length (the sum of distances between consecutive points)} \brief_strategy. \details_strategy_reasons
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{distance}
\param geometry \param_geometry
\param strategy \param_strategy{distance}
\return \return_calc{length}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/length.qbk]}
\qbk{[length_with_strategy] [length_with_strategy_output]}
*/
template<typename Geometry, typename Strategy>
inline typename default_length_result<Geometry>::type length(
Geometry const& geometry, Strategy const& strategy)
{
concept::check<Geometry const>();
return dispatch::length
<
typename tag<Geometry>::type,
Geometry,
Strategy
>::apply(geometry, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP

View File

@@ -0,0 +1,200 @@
// 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_MAKE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_MAKE_HPP
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace make
{
/*!
\brief Construct a geometry
\ingroup make
\tparam Geometry \tparam_geometry
\tparam Range \tparam_range_point
\param range \param_range_point
\return The constructed geometry, here: a linestring or a ring
\qbk{distinguish, with a range}
\qbk{
[heading Example]
[make_with_range] [make_with_range_output]
[heading See also]
\* [link geometry.reference.algorithms.assign.assign_points assign]
}
*/
template <typename Geometry, typename Range>
inline Geometry make_points(Range const& range)
{
concept::check<Geometry>();
Geometry geometry;
geometry::append(geometry, range);
return geometry;
}
}} // namespace detail::make
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Construct a geometry
\ingroup make
\details
\note It does not work with array-point types, like int[2]
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param c1 \param_x
\param c2 \param_y
\return The constructed geometry, here: a 2D point
\qbk{distinguish, 2 coordinate values}
\qbk{
[heading Example]
[make_2d_point] [make_2d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.assign.assign_values_3_2_coordinate_values assign]
}
*/
template <typename Geometry, typename Type>
inline Geometry make(Type const& c1, Type const& c2)
{
concept::check<Geometry>();
Geometry geometry;
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2);
return geometry;
}
/*!
\brief Construct a geometry
\ingroup make
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param c1 \param_x
\param c2 \param_y
\param c3 \param_z
\return The constructed geometry, here: a 3D point
\qbk{distinguish, 3 coordinate values}
\qbk{
[heading Example]
[make_3d_point] [make_3d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.assign.assign_values_4_3_coordinate_values assign]
}
*/
template <typename Geometry, typename Type>
inline Geometry make(Type const& c1, Type const& c2, Type const& c3)
{
concept::check<Geometry>();
Geometry geometry;
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3);
return geometry;
}
template <typename Geometry, typename Type>
inline Geometry make(Type const& c1, Type const& c2, Type const& c3, Type const& c4)
{
concept::check<Geometry>();
Geometry geometry;
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3, c4);
return geometry;
}
/*!
\brief Construct a box with inverse infinite coordinates
\ingroup make
\details The make_inverse function initializes a 2D or 3D box with large coordinates, the
min corner is very large, the max corner is very small. This is useful e.g. in combination
with the expand function, to determine the bounding box of a series of geometries.
\tparam Geometry \tparam_geometry
\return The constructed geometry, here: a box
\qbk{
[heading Example]
[make_inverse] [make_inverse_output]
[heading See also]
\* [link geometry.reference.algorithms.assign.assign_inverse assign_inverse]
}
*/
template <typename Geometry>
inline Geometry make_inverse()
{
concept::check<Geometry>();
Geometry geometry;
dispatch::assign_inverse
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
return geometry;
}
/*!
\brief Construct a geometry with its coordinates initialized to zero
\ingroup make
\details The make_zero function initializes a 2D or 3D point or box with coordinates of zero
\tparam Geometry \tparam_geometry
\return The constructed and zero-initialized geometry
*/
template <typename Geometry>
inline Geometry make_zero()
{
concept::check<Geometry>();
Geometry geometry;
dispatch::assign_zero
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
return geometry;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_MAKE_HPP

View File

@@ -0,0 +1,95 @@
// 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_NUM_GEOMETRIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_NUM_GEOMETRIES_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry>
struct num_geometries
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template <typename Geometry>
struct num_geometries<single_tag, Geometry>
{
static inline std::size_t apply(Geometry const&)
{
return 1;
}
};
} // namespace dispatch
#endif
/*!
\brief \brief_calc{number of geometries}
\ingroup num_geometries
\details \details_calc{num_geometries, number of geometries}.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{number of geometries}
\qbk{[include reference/algorithms/num_geometries.qbk]}
*/
template <typename Geometry>
inline std::size_t num_geometries(Geometry const& geometry)
{
concept::check<Geometry const>();
return dispatch::num_geometries
<
typename tag_cast
<
typename tag<Geometry>::type,
single_tag,
multi_tag
>::type,
Geometry
>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_GEOMETRIES_HPP

View File

@@ -0,0 +1,88 @@
// 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_NUM_INTERIOR_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_NUM_INTERIOR_RINGS_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/interior_rings.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry>
struct num_interior_rings
{
static inline std::size_t apply(Geometry const& )
{
return 0;
}
};
template <typename Polygon>
struct num_interior_rings<polygon_tag, Polygon>
{
static inline std::size_t apply(Polygon const& polygon)
{
return boost::size(geometry::interior_rings(polygon));
}
};
} // namespace dispatch
#endif
/*!
\brief \brief_calc{number of interior rings}
\ingroup num_interior_rings
\details \details_calc{num_interior_rings, number of interior rings}.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{number of interior rings}
\qbk{[include reference/algorithms/num_interior_rings.qbk]}
\note Defined by OGC as "numInteriorRing". To be consistent with "numPoints"
letter "s" is appended
*/
template <typename Geometry>
inline std::size_t num_interior_rings(Geometry const& geometry)
{
return dispatch::num_interior_rings
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_INTERIOR_RINGS_HPP

View File

@@ -0,0 +1,171 @@
// 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_NUM_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_NUM_POINTS_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/closure.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/core/tag_cast.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace num_points
{
template <typename Range>
struct range_count
{
static inline std::size_t apply(Range const& range, bool add_for_open)
{
std::size_t n = boost::size(range);
if (add_for_open && n > 0)
{
closure_selector const s = geometry::closure<Range>::value;
if (s == open)
{
if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1)))
{
return n + 1;
}
}
}
return n;
}
};
template <typename Geometry, std::size_t D>
struct other_count
{
static inline std::size_t apply(Geometry const&, bool)
{
return D;
}
};
template <typename Polygon>
struct polygon_count
{
static inline std::size_t apply(Polygon const& poly, bool add_for_open)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
std::size_t n = range_count<ring_type>::apply(
exterior_ring(poly), add_for_open);
typename interior_return_type<Polygon const>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
n += range_count<ring_type>::apply(*it, add_for_open);
}
return n;
}
};
}} // namespace detail::num_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename GeometryTag, typename Geometry>
struct num_points
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
};
template <typename Geometry>
struct num_points<point_tag, Geometry>
: detail::num_points::other_count<Geometry, 1>
{};
template <typename Geometry>
struct num_points<box_tag, Geometry>
: detail::num_points::other_count<Geometry, 4>
{};
template <typename Geometry>
struct num_points<segment_tag, Geometry>
: detail::num_points::other_count<Geometry, 2>
{};
template <typename Geometry>
struct num_points<linestring_tag, Geometry>
: detail::num_points::range_count<Geometry>
{};
template <typename Geometry>
struct num_points<ring_tag, Geometry>
: detail::num_points::range_count<Geometry>
{};
template <typename Geometry>
struct num_points<polygon_tag, Geometry>
: detail::num_points::polygon_count<Geometry>
{};
} // namespace dispatch
#endif
/*!
\brief \brief_calc{number of points}
\ingroup num_points
\details \details_calc{num_points, number of points}.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\param add_for_open add one for open geometries (i.e. polygon types which are not closed)
\return \return_calc{number of points}
\qbk{[include reference/algorithms/num_points.qbk]}
*/
template <typename Geometry>
inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false)
{
concept::check<Geometry const>();
return dispatch::num_points
<
typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
Geometry
>::apply(geometry, add_for_open);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_POINTS_HPP

View File

@@ -0,0 +1,200 @@
// 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_OVERLAPS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlaps
{
template
<
typename Box1,
typename Box2,
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box_loop
{
static inline void apply(Box1 const& b1, Box2 const& b2,
bool& overlaps, bool& one_in_two, bool& two_in_one)
{
assert_dimension_equal<Box1, Box2>();
typedef typename coordinate_type<Box1>::type coordinate_type1;
typedef typename coordinate_type<Box2>::type coordinate_type2;
coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
// We might use the (not yet accepted) Boost.Interval
// submission in the future
// If:
// B1: |-------|
// B2: |------|
// in any dimension -> no overlap
if (max1 <= min2 || min1 >= max2)
{
overlaps = false;
return;
}
// If:
// B1: |--------------------|
// B2: |-------------|
// in all dimensions -> within, then no overlap
// B1: |--------------------|
// B2: |-------------|
// this is "within-touch" -> then no overlap. So use < and >
if (min1 < min2 || max1 > max2)
{
one_in_two = false;
}
// Same other way round
if (min2 < min1 || max2 > max1)
{
two_in_one = false;
}
box_box_loop
<
Box1,
Box2,
Dimension + 1,
DimensionCount
>::apply(b1, b2, overlaps, one_in_two, two_in_one);
}
};
template
<
typename Box1,
typename Box2,
std::size_t DimensionCount
>
struct box_box_loop<Box1, Box2, DimensionCount, DimensionCount>
{
static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
{
}
};
template
<
typename Box1,
typename Box2
>
struct box_box
{
static inline bool apply(Box1 const& b1, Box2 const& b2)
{
bool overlaps = true;
bool within1 = true;
bool within2 = true;
box_box_loop
<
Box1,
Box2,
0,
dimension<Box1>::type::value
>::apply(b1, b2, overlaps, within1, within2);
/*
\see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps
where is stated that "inside" is not an "overlap",
this is true and is implemented as such.
*/
return overlaps && ! within1 && ! within2;
}
};
}} // namespace detail::overlaps
#endif // DOXYGEN_NO_DETAIL
//struct not_implemented_for_this_geometry_type : public boost::false_type {};
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1,
typename Tag2,
typename Geometry1,
typename Geometry2
>
struct overlaps
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry1, Geometry2>)
);
};
template <typename Box1, typename Box2>
struct overlaps<box_tag, box_tag, Box1, Box2>
: detail::overlaps::box_box<Box1, Box2>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check2{overlap}
\ingroup overlaps
\return \return_check2{overlap}
*/
template <typename Geometry1, typename Geometry2>
inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
return dispatch::overlaps
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP

View File

@@ -0,0 +1,139 @@
// 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_PERIMETER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_length_result.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// Default perimeter is 0.0, specializations implement calculated values
template <typename Tag, typename Geometry, typename Strategy>
struct perimeter : detail::calculate_null
<
typename default_length_result<Geometry>::type,
Geometry,
Strategy
>
{};
template <typename Geometry, typename Strategy>
struct perimeter<ring_tag, Geometry, Strategy>
: detail::length::range_length
<
Geometry,
Strategy,
closure<Geometry>::value
>
{};
template <typename Polygon, typename Strategy>
struct perimeter<polygon_tag, Polygon, Strategy>
: detail::calculate_polygon_sum
<
typename default_length_result<Polygon>::type,
Polygon,
Strategy,
detail::length::range_length
<
typename ring_type<Polygon>::type,
Strategy,
closure<Polygon>::value
>
>
{};
// box,n-sphere: to be implemented
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_calc{perimeter}
\ingroup perimeter
\details The function perimeter returns the perimeter of a geometry,
using the default distance-calculation-strategy
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{perimeter}
\qbk{[include reference/algorithms/perimeter.qbk]}
*/
template<typename Geometry>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry)
{
concept::check<Geometry const>();
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::distance::services::default_strategy
<
point_tag, point_type
>::type strategy_type;
return dispatch::perimeter
<
typename tag<Geometry>::type,
Geometry,
strategy_type
>::apply(geometry, strategy_type());
}
/*!
\brief \brief_calc{perimeter} \brief_strategy
\ingroup perimeter
\details The function perimeter returns the perimeter of a geometry,
using specified strategy
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{distance}
\param geometry \param_geometry
\param strategy strategy to be used for distance calculations.
\return \return_calc{perimeter}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/perimeter.qbk]}
*/
template<typename Geometry, typename Strategy>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry, Strategy const& strategy)
{
concept::check<Geometry const>();
return dispatch::perimeter
<
typename tag<Geometry>::type,
Geometry,
Strategy
>::apply(geometry, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP

View File

@@ -0,0 +1,134 @@
// 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_REVERSE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_REVERSE_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace reverse
{
template <typename Range>
struct range_reverse
{
static inline void apply(Range& range)
{
std::reverse(boost::begin(range), boost::end(range));
}
};
template <typename Polygon>
struct polygon_reverse
{
static inline void apply(Polygon& polygon)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef range_reverse<ring_type> per_range;
per_range::apply(exterior_ring(polygon));
typename interior_return_type<Polygon>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
per_range::apply(*it);
}
}
};
}} // namespace detail::reverse
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry
>
struct reverse
{
static inline void apply(Geometry&)
{}
};
template <typename Ring>
struct reverse<ring_tag, Ring>
: detail::reverse::range_reverse<Ring>
{};
template <typename LineString>
struct reverse<linestring_tag, LineString>
: detail::reverse::range_reverse<LineString>
{};
template <typename Polygon>
struct reverse<polygon_tag, Polygon>
: detail::reverse::polygon_reverse<Polygon>
{};
} // namespace dispatch
#endif
/*!
\brief Reverses the points within a geometry
\details Generic function to reverse a geometry. It resembles the std::reverse
functionality, but it takes the geometry type into account. Only for a ring
or for a linestring it is the same as the std::reverse.
\ingroup reverse
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be reversed
\qbk{[include reference/algorithms/reverse.qbk]}
*/
template <typename Geometry>
inline void reverse(Geometry& geometry)
{
concept::check<Geometry>();
dispatch::reverse
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_REVERSE_HPP

View File

@@ -0,0 +1,405 @@
// 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_SIMPLIFY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.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/core/mutable_range.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
#include <boost/geometry/strategies/concepts/simplify_concept.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace simplify
{
template<typename Range, typename Strategy>
struct simplify_range_insert
{
template <typename OutputIterator, typename Distance>
static inline void apply(Range const& range, OutputIterator out,
Distance const& max_distance, Strategy const& strategy)
{
if (boost::size(range) <= 2 || max_distance < 0)
{
std::copy(boost::begin(range), boost::end(range), out);
}
else
{
strategy.apply(range, out, max_distance);
}
}
};
template<typename Range, typename Strategy>
struct simplify_copy
{
template <typename Distance>
static inline void apply(Range const& range, Range& out,
Distance const& max_distance, Strategy const& strategy)
{
std::copy
(
boost::begin(range), boost::end(range), std::back_inserter(out)
);
}
};
template<typename Range, typename Strategy, std::size_t Minimum>
struct simplify_range
{
template <typename Distance>
static inline void apply(Range const& range, Range& out,
Distance const& max_distance, Strategy const& strategy)
{
// Call do_container for a linestring / ring
/* For a RING:
The first/last point (the closing point of the ring) should maybe
be excluded because it lies on a line with second/one but last.
Here it is never excluded.
Note also that, especially if max_distance is too large,
the output ring might be self intersecting while the input ring is
not, although chances are low in normal polygons
Finally the inputring might have 3 (open) or 4 (closed) points (=correct),
the output < 3 or 4(=wrong)
*/
if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
{
simplify_copy<Range, Strategy>::apply
(
range, out, max_distance, strategy
);
}
else
{
simplify_range_insert<Range, Strategy>::apply
(
range, std::back_inserter(out), max_distance, strategy
);
}
}
};
template<typename Polygon, typename Strategy>
struct simplify_polygon
{
template <typename Distance>
static inline void apply(Polygon const& poly_in, Polygon& poly_out,
Distance const& max_distance, Strategy const& strategy)
{
typedef typename ring_type<Polygon>::type ring_type;
int const Minimum = core_detail::closure::minimum_ring_size
<
geometry::closure<Polygon>::value
>::value;
// Note that if there are inner rings, and distance is too large,
// they might intersect with the outer ring in the output,
// while it didn't in the input.
simplify_range<ring_type, Strategy, Minimum>::apply(exterior_ring(poly_in),
exterior_ring(poly_out),
max_distance, strategy);
traits::resize
<
typename boost::remove_reference
<
typename traits::interior_mutable_type<Polygon>::type
>::type
>::apply(interior_rings(poly_out), num_interior_rings(poly_in));
typename interior_return_type<Polygon const>::type rings_in
= interior_rings(poly_in);
typename interior_return_type<Polygon>::type rings_out
= interior_rings(poly_out);
BOOST_AUTO_TPL(it_out, boost::begin(rings_out));
for (BOOST_AUTO_TPL(it_in, boost::begin(rings_in));
it_in != boost::end(rings_in);
++it_in, ++it_out)
{
simplify_range<ring_type, Strategy, Minimum>::apply(*it_in,
*it_out, max_distance, strategy);
}
}
};
}} // namespace detail::simplify
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Tag, typename Geometry, typename Strategy>
struct simplify
{
};
template <typename Point, typename Strategy>
struct simplify<point_tag, Point, Strategy>
{
template <typename Distance>
static inline void apply(Point const& point, Point& out,
Distance const& max_distance, Strategy const& strategy)
{
geometry::convert(point, out);
}
};
template <typename Linestring, typename Strategy>
struct simplify<linestring_tag, Linestring, Strategy>
: detail::simplify::simplify_range
<
Linestring,
Strategy,
2
>
{};
template <typename Ring, typename Strategy>
struct simplify<ring_tag, Ring, Strategy>
: detail::simplify::simplify_range
<
Ring,
Strategy,
core_detail::closure::minimum_ring_size
<
geometry::closure<Ring>::value
>::value
>
{};
template <typename Polygon, typename Strategy>
struct simplify<polygon_tag, Polygon, Strategy>
: detail::simplify::simplify_polygon
<
Polygon,
Strategy
>
{};
template <typename Tag, typename Geometry, typename Strategy>
struct simplify_insert
{
};
template <typename Linestring, typename Strategy>
struct simplify_insert<linestring_tag, Linestring, Strategy>
: detail::simplify::simplify_range_insert
<
Linestring,
Strategy
>
{};
template <typename Ring, typename Strategy>
struct simplify_insert<ring_tag, Ring, Strategy>
: detail::simplify::simplify_range_insert
<
Ring,
Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Simplify a geometry using a specified strategy
\ingroup simplify
\tparam Geometry \tparam_geometry
\tparam Distance A numerical distance measure
\tparam Strategy A type fulfilling a SimplifyStrategy concept
\param strategy A strategy to calculate simplification
\param geometry input geometry, to be simplified
\param out output geometry, simplified version of the input geometry
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\param strategy simplify strategy to be used for simplification, might
include point-distance strategy
\image html svg_simplify_country.png "The image below presents the simplified country"
\qbk{distinguish,with strategy}
*/
template<typename Geometry, typename Distance, typename Strategy>
inline void simplify(Geometry const& geometry, Geometry& out,
Distance const& max_distance, Strategy const& strategy)
{
concept::check<Geometry>();
BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
geometry::clear(out);
dispatch::simplify
<
typename tag<Geometry>::type,
Geometry,
Strategy
>::apply(geometry, out, max_distance, strategy);
}
/*!
\brief Simplify a geometry
\ingroup simplify
\tparam Geometry \tparam_geometry
\tparam Distance \tparam_numeric
\note This version of simplify simplifies a geometry using the default
strategy (Douglas Peucker),
\param geometry input geometry, to be simplified
\param out output geometry, simplified version of the input geometry
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\qbk{[include reference/algorithms/simplify.qbk]}
*/
template<typename Geometry, typename Distance>
inline void simplify(Geometry const& geometry, Geometry& out,
Distance const& max_distance)
{
concept::check<Geometry>();
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::distance::services::default_strategy
<
segment_tag, point_type
>::type ds_strategy_type;
typedef strategy::simplify::douglas_peucker
<
point_type, ds_strategy_type
> strategy_type;
simplify(geometry, out, max_distance, strategy_type());
}
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace simplify
{
/*!
\brief Simplify a geometry, using an output iterator
and a specified strategy
\ingroup simplify
\tparam Geometry \tparam_geometry
\param geometry input geometry, to be simplified
\param out output iterator, outputs all simplified points
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\param strategy simplify strategy to be used for simplification,
might include point-distance strategy
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/simplify.qbk]}
*/
template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
Distance const& max_distance, Strategy const& strategy)
{
concept::check<Geometry const>();
BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
dispatch::simplify_insert
<
typename tag<Geometry>::type,
Geometry,
Strategy
>::apply(geometry, out, max_distance, strategy);
}
/*!
\brief Simplify a geometry, using an output iterator
\ingroup simplify
\tparam Geometry \tparam_geometry
\param geometry input geometry, to be simplified
\param out output iterator, outputs all simplified points
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\qbk{[include reference/algorithms/simplify_insert.qbk]}
*/
template<typename Geometry, typename OutputIterator, typename Distance>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
Distance const& max_distance)
{
typedef typename point_type<Geometry>::type point_type;
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<point_type>();
typedef typename strategy::distance::services::default_strategy
<
segment_tag, point_type
>::type ds_strategy_type;
typedef strategy::simplify::douglas_peucker
<
point_type, ds_strategy_type
> strategy_type;
dispatch::simplify_insert
<
typename tag<Geometry>::type,
Geometry,
strategy_type
>::apply(geometry, out, max_distance, strategy_type());
}
}} // namespace detail::simplify
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP

View File

@@ -0,0 +1,149 @@
// 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_SYM_DIFFERENCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP
#include <algorithm>
#include <boost/geometry/algorithms/intersection.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace sym_difference
{
/*!
\brief \brief_calc2{symmetric difference} \brief_strategy
\ingroup sym_difference
\details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}
\brief_strategy. \details_insert{sym_difference}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy_overlay
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{difference}
\param strategy \param_strategy{difference}
\return \return_out
\qbk{distinguish,with strategy}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator,
typename Strategy
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
out = detail::intersection::insert<GeometryOut, true, overlay_difference>(
geometry1, geometry2, out, strategy);
out = detail::intersection::insert<GeometryOut, true, overlay_difference>(
geometry2, geometry1, out, strategy);
return out;
}
/*!
\brief \brief_calc2{symmetric difference}
\ingroup sym_difference
\details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}
\details_insert{sym_difference}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{difference}
\return \return_out
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
> strategy_type;
return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type());
}
}} // namespace detail::sym_difference
#endif // DOXYGEN_NO_DETAIL
/*!
\brief \brief_calc2{symmetric difference}
\ingroup sym_difference
\details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection output collection, either a multi-geometry,
or a std::vector<Geometry> / std::deque<Geometry> etc
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\qbk{[include reference/algorithms/sym_difference.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection
>
inline void sym_difference(Geometry1 const& geometry1,
Geometry2 const& geometry2, Collection& output_collection)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
detail::sym_difference::sym_difference_insert<geometry_out>(
geometry1, geometry2,
std::back_inserter(output_collection));
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP

View File

@@ -0,0 +1,351 @@
// 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_TRANSFORM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP
#include <cmath>
#include <iterator>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/transform.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace transform
{
template <typename Point1, typename Point2, typename Strategy>
struct transform_point
{
static inline bool apply(Point1 const& p1, Point2& p2,
Strategy const& strategy)
{
return strategy.apply(p1, p2);
}
};
template <typename Box1, typename Box2, typename Strategy>
struct transform_box
{
static inline bool apply(Box1 const& b1, Box2& b2,
Strategy const& strategy)
{
typedef typename point_type<Box1>::type point_type1;
typedef typename point_type<Box2>::type point_type2;
point_type1 lower_left, upper_right;
detail::assign::assign_box_2d_corner<min_corner, min_corner>(
b1, lower_left);
detail::assign::assign_box_2d_corner<max_corner, max_corner>(
b1, upper_right);
point_type2 p1, p2;
if (strategy.apply(lower_left, p1) && strategy.apply(upper_right, p2))
{
// Create a valid box and therefore swap if necessary
typedef typename coordinate_type<point_type2>::type coordinate_type;
coordinate_type x1 = geometry::get<0>(p1)
, y1 = geometry::get<1>(p1)
, x2 = geometry::get<0>(p2)
, y2 = geometry::get<1>(p2);
if (x1 > x2) { std::swap(x1, x2); }
if (y1 > y2) { std::swap(y1, y2); }
set<min_corner, 0>(b2, x1);
set<min_corner, 1>(b2, y1);
set<max_corner, 0>(b2, x2);
set<max_corner, 1>(b2, y2);
return true;
}
return false;
}
};
template <typename Geometry1, typename Geometry2, typename Strategy>
struct transform_box_or_segment
{
static inline bool apply(Geometry1 const& source, Geometry2& target,
Strategy const& strategy)
{
typedef typename point_type<Geometry1>::type point_type1;
typedef typename point_type<Geometry2>::type point_type2;
point_type1 source_point[2];
geometry::detail::assign_point_from_index<0>(source, source_point[0]);
geometry::detail::assign_point_from_index<1>(source, source_point[1]);
point_type2 target_point[2];
if (strategy.apply(source_point[0], target_point[0])
&& strategy.apply(source_point[1], target_point[1]))
{
geometry::detail::assign_point_to_index<0>(target_point[0], target);
geometry::detail::assign_point_to_index<1>(target_point[1], target);
return true;
}
return false;
}
};
template
<
typename PointOut,
typename OutputIterator,
typename Range,
typename Strategy
>
inline bool transform_range_out(Range const& range,
OutputIterator out, Strategy const& strategy)
{
PointOut point_out;
for(typename boost::range_iterator<Range const>::type
it = boost::begin(range);
it != boost::end(range);
++it)
{
if (! transform_point
<
typename point_type<Range>::type,
PointOut,
Strategy
>::apply(*it, point_out, strategy))
{
return false;
}
*out++ = point_out;
}
return true;
}
template <typename Polygon1, typename Polygon2, typename Strategy>
struct transform_polygon
{
static inline bool apply(Polygon1 const& poly1, Polygon2& poly2,
Strategy const& strategy)
{
typedef typename ring_type<Polygon1>::type ring1_type;
typedef typename ring_type<Polygon2>::type ring2_type;
typedef typename point_type<Polygon2>::type point2_type;
geometry::clear(poly2);
if (!transform_range_out<point2_type>(exterior_ring(poly1),
std::back_inserter(exterior_ring(poly2)), strategy))
{
return false;
}
// Note: here a resizeable container is assumed.
traits::resize
<
typename boost::remove_reference
<
typename traits::interior_mutable_type<Polygon2>::type
>::type
>::apply(interior_rings(poly2), num_interior_rings(poly1));
typename interior_return_type<Polygon1 const>::type rings1
= interior_rings(poly1);
typename interior_return_type<Polygon2>::type rings2
= interior_rings(poly2);
BOOST_AUTO_TPL(it1, boost::begin(rings1));
BOOST_AUTO_TPL(it2, boost::begin(rings2));
for ( ; it1 != boost::end(interior_rings(poly1)); ++it1, ++it2)
{
if (!transform_range_out<point2_type>(*it1,
std::back_inserter(*it2), strategy))
{
return false;
}
}
return true;
}
};
template <typename Point1, typename Point2>
struct select_strategy
{
typedef typename strategy::transform::services::default_strategy
<
typename cs_tag<Point1>::type,
typename cs_tag<Point2>::type,
typename coordinate_system<Point1>::type,
typename coordinate_system<Point2>::type,
dimension<Point1>::type::value,
dimension<Point2>::type::value,
typename point_type<Point1>::type,
typename point_type<Point2>::type
>::type type;
};
template <typename Range1, typename Range2, typename Strategy>
struct transform_range
{
static inline bool apply(Range1 const& range1,
Range2& range2, Strategy const& strategy)
{
typedef typename point_type<Range2>::type point_type;
// Should NOT be done here!
// geometry::clear(range2);
return transform_range_out<point_type>(range1,
std::back_inserter(range2), strategy);
}
};
}} // namespace detail::transform
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1, typename Tag2,
typename Geometry1, typename Geometry2,
typename Strategy
>
struct transform {};
template <typename Point1, typename Point2, typename Strategy>
struct transform<point_tag, point_tag, Point1, Point2, Strategy>
: detail::transform::transform_point<Point1, Point2, Strategy>
{
};
template <typename Linestring1, typename Linestring2, typename Strategy>
struct transform
<
linestring_tag, linestring_tag,
Linestring1, Linestring2, Strategy
>
: detail::transform::transform_range<Linestring1, Linestring2, Strategy>
{
};
template <typename Range1, typename Range2, typename Strategy>
struct transform<ring_tag, ring_tag, Range1, Range2, Strategy>
: detail::transform::transform_range<Range1, Range2, Strategy>
{
};
template <typename Polygon1, typename Polygon2, typename Strategy>
struct transform<polygon_tag, polygon_tag, Polygon1, Polygon2, Strategy>
: detail::transform::transform_polygon<Polygon1, Polygon2, Strategy>
{
};
template <typename Box1, typename Box2, typename Strategy>
struct transform<box_tag, box_tag, Box1, Box2, Strategy>
: detail::transform::transform_box<Box1, Box2, Strategy>
{
};
template <typename Segment1, typename Segment2, typename Strategy>
struct transform<segment_tag, segment_tag, Segment1, Segment2, Strategy>
: detail::transform::transform_box_or_segment<Segment1, Segment2, Strategy>
{
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Transforms from one geometry to another geometry \brief_strategy
\ingroup transform
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy strategy
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy The strategy to be used for transformation
\return True if the transformation could be done
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/transform_with_strategy.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2>();
typedef dispatch::transform
<
typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
Geometry1,
Geometry2,
Strategy
> transform_type;
return transform_type::apply(geometry1, geometry2, strategy);
}
/*!
\brief Transforms from one geometry to another geometry using a strategy
\ingroup transform
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return True if the transformation could be done
\qbk{[include reference/algorithms/transform.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2>();
typename detail::transform::select_strategy<Geometry1, Geometry2>::type strategy;
return transform(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP

View File

@@ -0,0 +1,284 @@
// 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_UNION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_UNION_HPP
#include <boost/mpl/if.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/detail/overlay/overlay.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
// tag dispatching:
typename TagIn1, typename TagIn2, typename TagOut,
// 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,
typename Strategy
>
struct union_insert
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES
, (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,
typename Strategy
>
struct union_insert
<
TagIn1, TagIn2, TagOut,
true, true, true,
Geometry1, Geometry2,
Reverse1, Reverse2, ReverseOut,
OutputIterator, GeometryOut,
Strategy
> : detail::overlay::overlay
<Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, overlay_union, Strategy>
{};
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,
typename Strategy
>
struct union_insert_reversed
{
static inline OutputIterator apply(Geometry1 const& g1,
Geometry2 const& g2, OutputIterator out,
Strategy const& strategy)
{
return union_insert
<
GeometryTag2, GeometryTag1, GeometryTag3,
Areal2, Areal1, ArealOut,
Geometry2, Geometry1,
Reverse2, Reverse1, ReverseOut,
OutputIterator, GeometryOut,
Strategy
>::apply(g2, g1, out, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace union_
{
template
<
typename GeometryOut,
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,
dispatch::union_insert_reversed
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename 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>::value,
overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
OutputIterator, GeometryOut,
Strategy
>,
dispatch::union_insert
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename 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>::value,
overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
OutputIterator, GeometryOut,
Strategy
>
>::type::apply(geometry1, geometry2, out, strategy);
}
/*!
\brief_calc2{union} \brief_strategy
\ingroup union
\details \details_calc2{union_insert, spatial set theoretic union}
\brief_strategy. details_insert{union}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator output iterator
\tparam Strategy \tparam_strategy_overlay
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{union}
\param strategy \param_strategy{union}
\return \return_out
\qbk{distinguish,with strategy}
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator,
typename Strategy
>
inline OutputIterator union_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
return detail::union_::insert<GeometryOut>(geometry1, geometry2, out, strategy);
}
/*!
\brief_calc2{union}
\ingroup union
\details \details_calc2{union_insert, spatial set theoretic union}.
\details_insert{union}
\tparam GeometryOut output geometry type, must be specified
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam OutputIterator output iterator
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param out \param_out{union}
\return \return_out
*/
template
<
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename OutputIterator
>
inline OutputIterator union_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
> strategy;
return union_insert<GeometryOut>(geometry1, geometry2, out, strategy());
}
}} // namespace detail::union_
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Combines two geometries which each other
\ingroup union
\details \details_calc2{union, spatial set theoretic union}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection output collection, either a multi-geometry,
or a std::vector<Geometry> / std::deque<Geometry> etc
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\note Called union_ because union is a reserved word.
\qbk{[include reference/algorithms/union.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection
>
inline void union_(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
detail::union_::union_insert<geometry_out>(geometry1, geometry2,
std::back_inserter(output_collection));
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_UNION_HPP

View File

@@ -0,0 +1,153 @@
// 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_UNIQUE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_UNIQUE_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace unique
{
template <typename Range, typename ComparePolicy>
struct range_unique
{
static inline void apply(Range& range, ComparePolicy const& policy)
{
typename boost::range_iterator<Range>::type it
= std::unique
(
boost::begin(range),
boost::end(range),
policy
);
traits::resize<Range>::apply(range, it - boost::begin(range));
}
};
template <typename Polygon, typename ComparePolicy>
struct polygon_unique
{
static inline void apply(Polygon& polygon, ComparePolicy const& policy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef range_unique<ring_type, ComparePolicy> per_range;
per_range::apply(exterior_ring(polygon), policy);
typename interior_return_type<Polygon>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
per_range::apply(*it, policy);
}
}
};
}} // namespace detail::unique
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename Geometry,
typename ComparePolicy
>
struct unique
{
static inline void apply(Geometry&, ComparePolicy const& )
{}
};
template <typename Ring, typename ComparePolicy>
struct unique<ring_tag, Ring, ComparePolicy>
: detail::unique::range_unique<Ring, ComparePolicy>
{};
template <typename LineString, typename ComparePolicy>
struct unique<linestring_tag, LineString, ComparePolicy>
: detail::unique::range_unique<LineString, ComparePolicy>
{};
template <typename Polygon, typename ComparePolicy>
struct unique<polygon_tag, Polygon, ComparePolicy>
: detail::unique::polygon_unique<Polygon, ComparePolicy>
{};
} // namespace dispatch
#endif
/*!
\brief \brief_calc{minimal set}
\ingroup unique
\details \details_calc{unique,minimal set (where duplicate consecutive points are removed)}.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be made unique
\qbk{[include reference/algorithms/unique.qbk]}
*/
template <typename Geometry>
inline void unique(Geometry& geometry)
{
concept::check<Geometry>();
// Default strategy is the default point-comparison policy
typedef geometry::equal_to
<
typename geometry::point_type<Geometry>::type
> policy;
dispatch::unique
<
typename tag<Geometry>::type,
Geometry,
policy
>::apply(geometry, policy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_UNIQUE_HPP

View File

@@ -0,0 +1,357 @@
// 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_WITHIN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/concepts/within_concept.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/order_as_direction.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 within
{
template
<
typename Point,
typename Ring,
iterate_direction Direction,
closure_selector Closure,
typename Strategy
>
struct point_in_ring
{
BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
static inline int apply(Point const& point, Ring const& ring,
Strategy const& strategy)
{
if (boost::size(ring)
< core_detail::closure::minimum_ring_size<Closure>::value)
{
return -1;
}
typedef typename reversible_view<Ring const, Direction>::type rev_view_type;
typedef typename closeable_view
<
rev_view_type const, Closure
>::type cl_view_type;
typedef typename boost::range_iterator<cl_view_type const>::type iterator_type;
rev_view_type rev_view(ring);
cl_view_type view(rev_view);
typename Strategy::state_type state;
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
bool stop = false;
for (iterator_type previous = it++;
it != end && ! stop;
++previous, ++it)
{
if (! strategy.apply(point, *previous, *it, state))
{
stop = true;
}
}
return strategy.result(state);
}
};
// Polygon: in exterior ring, and if so, not within interior ring(s)
template
<
typename Point,
typename Polygon,
iterate_direction Direction,
closure_selector Closure,
typename Strategy
>
struct point_in_polygon
{
BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
static inline int apply(Point const& point, Polygon const& poly,
Strategy const& strategy)
{
int const code = point_in_ring
<
Point,
typename ring_type<Polygon>::type,
Direction,
Closure,
Strategy
>::apply(point, exterior_ring(poly), strategy);
if (code == 1)
{
typename interior_return_type<Polygon const>::type rings
= interior_rings(poly);
for (BOOST_AUTO_TPL(it, boost::begin(rings));
it != boost::end(rings);
++it)
{
int const interior_code = point_in_ring
<
Point,
typename ring_type<Polygon>::type,
Direction,
Closure,
Strategy
>::apply(point, *it, strategy);
if (interior_code != -1)
{
// If 0, return 0 (touch)
// If 1 (inside hole) return -1 (outside polygon)
// If -1 (outside hole) check other holes if any
return -interior_code;
}
}
}
return code;
}
};
}} // namespace detail::within
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag1,
typename Tag2,
typename Geometry1,
typename Geometry2,
typename Strategy
>
struct within
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry1, Geometry2>)
);
};
template <typename Point, typename Box, typename Strategy>
struct within<point_tag, box_tag, Point, Box, Strategy>
{
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
return strategy.apply(point, box);
}
};
template <typename Box1, typename Box2, typename Strategy>
struct within<box_tag, box_tag, Box1, Box2, Strategy>
{
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
return strategy.apply(box1, box2);
}
};
template <typename Point, typename Ring, typename Strategy>
struct within<point_tag, ring_tag, Point, Ring, Strategy>
{
static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
{
return detail::within::point_in_ring
<
Point,
Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value,
Strategy
>::apply(point, ring, strategy) == 1;
}
};
template <typename Point, typename Polygon, typename Strategy>
struct within<point_tag, polygon_tag, Point, Polygon, Strategy>
{
static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
{
return detail::within::point_in_polygon
<
Point,
Polygon,
order_as_direction<geometry::point_order<Polygon>::value>::value,
geometry::closure<Polygon>::value,
Strategy
>::apply(point, polygon, strategy) == 1;
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check12{is completely inside}
\ingroup within
\details \details_check12{within, is completely inside}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry1 geometry which might be within the second geometry
\param geometry2 geometry which might contain the first geometry
\return true if geometry1 is completely contained within geometry2,
else false
\note The default strategy is used for within detection
\qbk{[include reference/algorithms/within.qbk]}
\qbk{
[heading Example]
[within]
[within_output]
}
*/
template<typename Geometry1, typename Geometry2>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
typedef typename point_type<Geometry1>::type point_type1;
typedef typename point_type<Geometry2>::type point_type2;
typedef typename strategy::within::services::default_strategy
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename tag<Geometry1>::type,
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
typename tag_cast
<
typename cs_tag<point_type1>::type, spherical_tag
>::type,
typename tag_cast
<
typename cs_tag<point_type2>::type, spherical_tag
>::type,
Geometry1,
Geometry2
>::type strategy_type;
return dispatch::within
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
/*!
\brief \brief_check12{is completely inside} \brief_strategy
\ingroup within
\details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry1 \param_geometry geometry which might be within the second geometry
\param geometry2 \param_geometry which might contain the first geometry
\param strategy strategy to be used
\return true if geometry1 is completely contained within geometry2,
else false
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/within.qbk]}
\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)]
\* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)]
\* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)]
[heading Example]
[within_strategy]
[within_strategy_output]
}
*/
template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
concept::within::check
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
>();
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::within
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
Geometry1,
Geometry2,
Strategy
>::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP