diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/geometry | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/geometry')
301 files changed, 46987 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp new file mode 100644 index 0000000000..72b2bbadab --- /dev/null +++ b/boost/geometry/algorithms/append.hpp @@ -0,0 +1,233 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& , Point const& , + 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 Geometry, typename RangeOrPoint, + typename TagRangeOrPoint = typename tag<RangeOrPoint>::type +> +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<Geometry, RangeOrPoint, point_tag> + : 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 + < + Geometry, + RangeOrPoint + >::apply(geometry, range_or_point, ring_index, multi_index); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp new file mode 100644 index 0000000000..919ab66fe1 --- /dev/null +++ b/boost/geometry/algorithms/area.hpp @@ -0,0 +1,295 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/algorithms/detail/throw_on_empty_input.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 Geometry, + typename Strategy = typename strategy::area::services::default_strategy + < + typename cs_tag + < + typename point_type<Geometry>::type + >::type, + typename point_type<Geometry>::type + >::type, + typename Tag = typename tag<Geometry>::type +> +struct area + : detail::calculate_null + < + typename Strategy::return_type, + Geometry, + Strategy + > {}; + + +template +< + typename Geometry, + typename Strategy +> +struct area<Geometry, Strategy, box_tag> + : detail::area::box_area<Geometry, Strategy> +{}; + + +template +< + typename Ring, + typename Strategy +> +struct area<Ring, Strategy, ring_tag> + : 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, Strategy, polygon_tag> + : 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; + + // detail::throw_on_empty_input(geometry); + + return dispatch::area + < + Geometry + >::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>(); + + // detail::throw_on_empty_input(geometry); + + return dispatch::area + < + Geometry, + Strategy + >::apply(geometry, strategy); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP diff --git a/boost/geometry/algorithms/assign.hpp b/boost/geometry/algorithms/assign.hpp new file mode 100644 index 0000000000..8c153c878d --- /dev/null +++ b/boost/geometry/algorithms/assign.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/algorithms/append.hpp> +#include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/arithmetic/arithmetic.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<Geometry2, Geometry1>::apply(geometry2, geometry1); +} + + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp new file mode 100644 index 0000000000..e22e36addc --- /dev/null +++ b/boost/geometry/algorithms/buffer.hpp @@ -0,0 +1,167 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& , 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 diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp new file mode 100644 index 0000000000..69ad9fe829 --- /dev/null +++ b/boost/geometry/algorithms/centroid.hpp @@ -0,0 +1,470 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/clear.hpp b/boost/geometry/algorithms/clear.hpp new file mode 100644 index 0000000000..d7336587ee --- /dev/null +++ b/boost/geometry/algorithms/clear.hpp @@ -0,0 +1,159 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 Geometry, + typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type +> +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<Geometry, point_tag> + : detail::clear::no_action<Geometry> +{}; + +template <typename Geometry> +struct clear<Geometry, box_tag> + : detail::clear::no_action<Geometry> +{}; + +template <typename Geometry> +struct clear<Geometry, segment_tag> + : detail::clear::no_action<Geometry> +{}; + +template <typename Geometry> +struct clear<Geometry, linestring_tag> + : detail::clear::collection_clear<Geometry> +{}; + +template <typename Geometry> +struct clear<Geometry, ring_tag> + : detail::clear::collection_clear<Geometry> +{}; + + +// Polygon can (indirectly) use std for clear +template <typename Polygon> +struct clear<Polygon, polygon_tag> + : 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<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP diff --git a/boost/geometry/algorithms/comparable_distance.hpp b/boost/geometry/algorithms/comparable_distance.hpp new file mode 100644 index 0000000000..3467045ca2 --- /dev/null +++ b/boost/geometry/algorithms/comparable_distance.hpp @@ -0,0 +1,74 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/convert.hpp b/boost/geometry/algorithms/convert.hpp new file mode 100644 index 0000000000..fbbf74c17f --- /dev/null +++ b/boost/geometry/algorithms/convert.hpp @@ -0,0 +1,411 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/not_implemented.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/algorithms/detail/convert_indexed_to_indexed.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 +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type, + typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type, + std::size_t DimensionCount = dimension<Geometry1>::type::value, + bool UseAssignment = boost::is_same<Geometry1, Geometry2>::value + && !boost::is_array<Geometry1>::value +> +struct convert: not_implemented<Tag1, Tag2, mpl::int_<DimensionCount> > +{}; + + +template +< + typename Geometry1, typename Geometry2, + typename Tag, + std::size_t DimensionCount +> +struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true> +{ + // Same geometry type -> copy whole geometry + static inline void apply(Geometry1 const& source, Geometry2& destination) + { + destination = source; + } +}; + + +template +< + typename Geometry1, typename Geometry2, + std::size_t DimensionCount +> +struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false> + : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount> +{}; + + +template +< + typename Box1, typename Box2, + std::size_t DimensionCount +> +struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false> + : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount> +{}; + + +template +< + typename Segment1, typename Segment2, + std::size_t DimensionCount +> +struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false> + : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount> +{}; + + +template <typename Segment, typename LineString, std::size_t DimensionCount> +struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false> + : detail::conversion::segment_to_range<Segment, LineString> +{}; + + +template <typename Ring1, typename Ring2, std::size_t DimensionCount> +struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false> + : detail::conversion::range_to_range + < + Ring1, + Ring2, + geometry::point_order<Ring1>::value + != geometry::point_order<Ring2>::value + > +{}; + +template <typename LineString1, typename LineString2, std::size_t DimensionCount> +struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false> + : detail::conversion::range_to_range<LineString1, LineString2> +{}; + +template <typename Polygon1, typename Polygon2, std::size_t DimensionCount> +struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false> + : detail::conversion::polygon_to_polygon<Polygon1, Polygon2> +{}; + +template <typename Box, typename Ring> +struct convert<Box, Ring, box_tag, ring_tag, 2, false> + : 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<Box, Polygon, box_tag, polygon_tag, 2, false> +{ + static inline void apply(Box const& box, Polygon& polygon) + { + typedef typename ring_type<Polygon>::type ring_type; + + convert + < + Box, ring_type, + box_tag, ring_tag, + 2, false + >::apply(box, exterior_ring(polygon)); + } +}; + + +template <typename Point, typename Box, std::size_t DimensionCount> +struct convert<Point, Box, point_tag, box_tag, DimensionCount, false> +{ + 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, typename Polygon, std::size_t DimensionCount> +struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false> +{ + static inline void apply(Ring const& ring, Polygon& polygon) + { + typedef typename ring_type<Polygon>::type ring_type; + convert + < + Ring, ring_type, + ring_tag, ring_tag, + DimensionCount, false + >::apply(ring, exterior_ring(polygon)); + } +}; + + +template <typename Polygon, typename Ring, std::size_t DimensionCount> +struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false> +{ + static inline void apply(Polygon const& polygon, Ring& ring) + { + typedef typename ring_type<Polygon>::type ring_type; + + convert + < + ring_type, Ring, + ring_tag, ring_tag, + DimensionCount, false + >::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<Geometry1, Geometry2>::apply(geometry1, geometry2); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP diff --git a/boost/geometry/algorithms/convex_hull.hpp b/boost/geometry/algorithms/convex_hull.hpp new file mode 100644 index 0000000000..56b87c8c15 --- /dev/null +++ b/boost/geometry/algorithms/convex_hull.hpp @@ -0,0 +1,275 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/array.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/num_points.hpp> +#include <boost/geometry/algorithms/detail/as_range.hpp> +#include <boost/geometry/algorithms/detail/assign_box_corners.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 Strategy +> +struct hull_to_geometry +{ + template <typename OutputGeometry> + 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); + } +}; + + +// Helper metafunction for default strategy retrieval +template <typename Geometry> +struct default_strategy + : strategy_convex_hull + < + Geometry, + typename point_type<Geometry>::type + > +{}; + + +}} // namespace detail::convex_hull +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, + typename Strategy = typename detail::convex_hull::default_strategy<Geometry>::type, + typename Tag = typename tag<Geometry>::type +> +struct convex_hull + : detail::convex_hull::hull_to_geometry<Geometry, Strategy> +{}; + +template +< + typename Box, + typename Strategy +> +struct convex_hull<Box, Strategy, box_tag> +{ + template <typename OutputGeometry> + static inline void apply(Box const& box, OutputGeometry& out, + Strategy const& ) + { + static bool const Close + = geometry::closure<OutputGeometry>::value == closed; + static bool const Reverse + = geometry::point_order<OutputGeometry>::value == counterclockwise; + + // A hull for boxes is trivial. Any strategy is (currently) skipped. + boost::array<typename point_type<Box>::type, 4> range; + geometry::detail::assign_box_corners_oriented<Reverse>(box, range); + geometry::append(out, range); + if (Close) + { + geometry::append(out, *boost::begin(range)); + } + } +}; + + + +template +< + order_selector Order, + typename Geometry, typename Strategy +> +struct convex_hull_insert + : detail::convex_hull::hull_insert<Geometry, Order, Strategy> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +template<typename Geometry, typename OutputGeometry, typename Strategy> +inline void convex_hull(Geometry const& geometry, + OutputGeometry& out, Strategy const& strategy) +{ + concept::check_concepts_and_equal_dimensions + < + const Geometry, + OutputGeometry + >(); + + BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) ); + + if (geometry::num_points(geometry) == 0) + { + // Leave output empty + return; + } + + dispatch::convex_hull + < + Geometry, + 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 Geometry, typename OutputGeometry> +inline void convex_hull(Geometry const& geometry, + OutputGeometry& hull) +{ + concept::check_concepts_and_equal_dimensions + < + const Geometry, + OutputGeometry + >(); + + typedef typename detail::convex_hull::default_strategy<Geometry>::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 + < + 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 detail::convex_hull::default_strategy<Geometry>::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 diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp new file mode 100644 index 0000000000..583e395f8e --- /dev/null +++ b/boost/geometry/algorithms/correct.hpp @@ -0,0 +1,265 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& ) + {} + +}; + + +// 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; + typedef typename default_area_result<Ring>::type area_result_type; + area_result_type const zero = area_result_type(); + 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 default_area_result<Polygon>::type area_result_type; + + static inline void apply(Polygon& poly) + { + correct_ring + < + ring_type, + std::less<area_result_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<area_result_type> + >::apply(*it); + } + } +}; + + +}} // namespace detail::correct +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct correct: not_implemented<Tag> +{}; + +template <typename Point> +struct correct<Point, point_tag> + : detail::correct::correct_nop<Point> +{}; + +template <typename LineString> +struct correct<LineString, linestring_tag> + : detail::correct::correct_nop<LineString> +{}; + +template <typename Segment> +struct correct<Segment, segment_tag> + : detail::correct::correct_nop<Segment> +{}; + + +template <typename Box> +struct correct<Box, box_tag> + : detail::correct::correct_box<Box> +{}; + +template <typename Ring> +struct correct<Ring, ring_tag> + : detail::correct::correct_ring + < + Ring, + std::less<typename default_area_result<Ring>::type> + > +{}; + +template <typename Polygon> +struct correct<Polygon, polygon_tag> + : 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<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp new file mode 100644 index 0000000000..c3c406c4ca --- /dev/null +++ b/boost/geometry/algorithms/covered_by.hpp @@ -0,0 +1,195 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/not_implemented.hpp> +#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 Geometry1, + typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type +> +struct covered_by: not_implemented<Tag1, Tag2> +{}; + + +template <typename Point, typename Box> +struct covered_by<Point, Box, point_tag, box_tag> +{ + template <typename Strategy> + static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + { + return strategy.apply(point, box); + } +}; + +template <typename Box1, typename Box2> +struct covered_by<Box1, Box2, box_tag, box_tag> +{ + template <typename 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> +struct covered_by<Point, Ring, point_tag, ring_tag> +{ + template <typename 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) >= 0; + } +}; + +template <typename Point, typename Polygon> +struct covered_by<Point, Polygon, point_tag, polygon_tag> +{ + template <typename 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 which might be inside or on the border of the second geometry +\param geometry2 \param_geometry which might cover the first geometry +\return true if geometry1 is inside of or on the border of geometry2, + else false +\note The default strategy is used for covered_by detection + +\qbk{[include reference/algorithms/covered_by.qbk]} + + */ +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 + < + Geometry1, + Geometry2 + >::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 which might be inside or on the border of the second geometry +\param geometry2 \param_geometry which might cover the first geometry +\param strategy strategy to be used +\return true if geometry1 is inside of or on the border of geometry2, + else false + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/covered_by.qbk]} + +*/ +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 + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP diff --git a/boost/geometry/algorithms/detail/as_range.hpp b/boost/geometry/algorithms/detail/as_range.hpp new file mode 100644 index 0000000000..d0dfb07e43 --- /dev/null +++ b/boost/geometry/algorithms/detail/as_range.hpp @@ -0,0 +1,107 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/assign_box_corners.hpp b/boost/geometry/algorithms/detail/assign_box_corners.hpp new file mode 100644 index 0000000000..1fd41733f2 --- /dev/null +++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/boost/geometry/algorithms/detail/assign_indexed_point.hpp new file mode 100644 index 0000000000..a1cffb80a7 --- /dev/null +++ b/boost/geometry/algorithms/detail/assign_indexed_point.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/assign_values.hpp b/boost/geometry/algorithms/detail/assign_values.hpp new file mode 100644 index 0000000000..ed4713493f --- /dev/null +++ b/boost/geometry/algorithms/detail/assign_values.hpp @@ -0,0 +1,443 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/calculate_null.hpp b/boost/geometry/algorithms/detail/calculate_null.hpp new file mode 100644 index 0000000000..4b48d62fc2 --- /dev/null +++ b/boost/geometry/algorithms/detail/calculate_null.hpp @@ -0,0 +1,38 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp new file mode 100644 index 0000000000..2ad349080b --- /dev/null +++ b/boost/geometry/algorithms/detail/calculate_sum.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp new file mode 100644 index 0000000000..d39824a61d --- /dev/null +++ b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp @@ -0,0 +1,80 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_INDEXED_TO_INDEXED_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP + + +#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 indexed_to_indexed +{ + static inline void apply(Source const& source, Destination& destination) + { + typedef typename coordinate_type<Destination>::type coordinate_type; + + geometry::set<min_corner, Dimension>(destination, + boost::numeric_cast<coordinate_type>( + geometry::get<min_corner, Dimension>(source))); + geometry::set<max_corner, Dimension>(destination, + boost::numeric_cast<coordinate_type>( + geometry::get<max_corner, Dimension>(source))); + + indexed_to_indexed + < + Source, Destination, + Dimension + 1, DimensionCount + >::apply(source, destination); + } +}; + +template +< + typename Source, + typename Destination, + std::size_t DimensionCount +> +struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount> +{ + static inline void apply(Source const& , Destination& ) + {} +}; + + +}} // namespace detail::conversion +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP diff --git a/boost/geometry/algorithms/detail/convert_point_to_point.hpp b/boost/geometry/algorithms/detail/convert_point_to_point.hpp new file mode 100644 index 0000000000..c7d37b6ca4 --- /dev/null +++ b/boost/geometry/algorithms/detail/convert_point_to_point.hpp @@ -0,0 +1,68 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/disjoint.hpp b/boost/geometry/algorithms/detail/disjoint.hpp new file mode 100644 index 0000000000..2ced5b1ce3 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint.hpp @@ -0,0 +1,225 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp new file mode 100644 index 0000000000..9c2fe28057 --- /dev/null +++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -0,0 +1,315 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/for_each_range.hpp b/boost/geometry/algorithms/detail/for_each_range.hpp new file mode 100644 index 0000000000..b10017c209 --- /dev/null +++ b/boost/geometry/algorithms/detail/for_each_range.hpp @@ -0,0 +1,148 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/mpl/assert.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 + } +}; + +template <typename Box, typename Actor, bool IsConst> +struct fe_range_box +{ + static inline void apply( + typename add_const_if_c<IsConst, Box>::type& box, + Actor& actor) + { + actor.apply(box_view<Box>(box)); + } +}; + + +}} // 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 +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +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> +{}; + +template <typename Box, typename Actor, bool IsConst> +struct for_each_range<box_tag, Box, Actor, IsConst> + : detail::for_each::fe_range_box<Box, 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 diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp new file mode 100644 index 0000000000..1e6215ed93 --- /dev/null +++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -0,0 +1,120 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 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/io/dsv/write.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 + diff --git a/boost/geometry/algorithms/detail/not.hpp b/boost/geometry/algorithms/detail/not.hpp new file mode 100644 index 0000000000..abc3a4e168 --- /dev/null +++ b/boost/geometry/algorithms/detail/not.hpp @@ -0,0 +1,50 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp new file mode 100644 index 0000000000..eb3e60e483 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp new file mode 100644 index 0000000000..2c0f88e2aa --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp new file mode 100644 index 0000000000..133530563e --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -0,0 +1,337 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp new file mode 100644 index 0000000000..012b3aca30 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -0,0 +1,170 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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/core/access.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.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/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 diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp new file mode 100644 index 0000000000..3e6a8897f5 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 +{ + static bool const include_no_turn = false; + static bool const include_degenerate = false; + + 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 diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp new file mode 100644 index 0000000000..b210fd04b1 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp new file mode 100644 index 0000000000..fc4f657322 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp @@ -0,0 +1,242 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp new file mode 100644 index 0000000000..05bd721e7f --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp @@ -0,0 +1,99 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp new file mode 100644 index 0000000000..379444428f --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp @@ -0,0 +1,295 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp new file mode 100644 index 0000000000..b0183a3ac2 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -0,0 +1,328 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 LineString, + bool Reverse, + typename SegmentIdentifier, + typename RangeOut +> +struct copy_segments_linestring +{ + + typedef typename boost::range_iterator<LineString const>::type iterator; + + static inline void apply(LineString const& ls, + SegmentIdentifier const& seg_id, int to_index, + RangeOut& current_output) + { + int const from_index = seg_id.segment_index + 1; + + // Sanity check + if (from_index > to_index || from_index < 0 || to_index >= boost::size(ls)) + { + return; + } + + typedef typename boost::range_difference<LineString>::type size_type; + size_type const count = to_index - from_index + 1; + + typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index; + + 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 LineString, + bool Reverse, + typename SegmentIdentifier, + typename RangeOut +> +struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut> + : detail::copy_segments::copy_segments_linestring + < + LineString, 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 diff --git a/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp new file mode 100644 index 0000000000..0bec816946 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp new file mode 100644 index 0000000000..e4842d35f1 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -0,0 +1,523 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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/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 , + Geometry1 const& , Geometry2 const& , + Strategy const& ) +{ + 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 diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp new file mode 100644 index 0000000000..8c8ed96189 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp @@ -0,0 +1,76 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp new file mode 100644 index 0000000000..087092a5f2 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -0,0 +1,416 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_FOLLOW_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP + +#include <cstddef> + +#include <boost/range.hpp> +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +namespace following +{ + +template <typename Turn, typename Operation> +static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op) +{ + // (Blocked means: blocked for polygon/polygon intersection, because + // they are reversed. But for polygon/line it is similar to continue) + return op.operation == operation_intersection + || op.operation == operation_continue + || op.operation == operation_blocked + ; +} + +template +< + typename Turn, + typename Operation, + typename LineString, + typename Polygon +> +static inline bool last_covered_by(Turn const& turn, Operation const& op, + LineString const& linestring, Polygon const& polygon) +{ + // Check any point between the this one and the first IP + typedef typename geometry::point_type<LineString>::type point_type; + point_type point_in_between; + detail::point_on_border::midpoint_helper + < + point_type, + 0, dimension<point_type>::value + >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point); + + return geometry::covered_by(point_in_between, polygon); +} + + +template +< + typename Turn, + typename Operation, + typename LineString, + typename Polygon +> +static inline bool is_leaving(Turn const& turn, Operation const& op, + bool entered, bool first, + LineString const& linestring, Polygon const& polygon) +{ + if (op.operation == operation_union) + { + return entered + || turn.method == method_crosses + || (first && last_covered_by(turn, op, linestring, polygon)) + ; + } + return false; +} + + +template +< + typename Turn, + typename Operation, + typename LineString, + typename Polygon +> +static inline bool is_staying_inside(Turn const& turn, Operation const& op, + bool entered, bool first, + LineString const& linestring, Polygon const& polygon) +{ + if (turn.method == method_crosses) + { + // The normal case, this is completely covered with entering/leaving + // so stay out of this time consuming "covered_by" + return false; + } + + if (is_entering(turn, op)) + { + return entered || (first && last_covered_by(turn, op, linestring, polygon)); + } + + return false; +} + +template +< + typename Turn, + typename Operation, + typename Linestring, + typename Polygon +> +static inline bool was_entered(Turn const& turn, Operation const& op, bool first, + Linestring const& linestring, Polygon const& polygon) +{ + if (first && (turn.method == method_collinear || turn.method == method_equal)) + { + return last_covered_by(turn, op, linestring, polygon); + } + return false; +} + + +// Template specialization structure to call the right actions for the right type +template<overlay_type OverlayType> +struct action_selector +{ + // If you get here the overlay type is not intersection or difference + // BOOST_MPL_ASSERT(false); +}; + +// Specialization for intersection, containing the implementation +template<> +struct action_selector<overlay_intersection> +{ + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void enter(LineStringOut& current_piece, + LineString const& , + segment_identifier& segment_id, + int , Point const& point, + Operation const& operation, OutputIterator& ) + { + // On enter, append the intersection point and remember starting point + detail::overlay::append_no_duplicates(current_piece, point); + segment_id = operation.seg_id; + } + + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void leave(LineStringOut& current_piece, + LineString const& linestring, + segment_identifier& segment_id, + int index, Point const& point, + Operation const& , OutputIterator& out) + { + // On leave, copy all segments from starting point, append the intersection point + // and add the output piece + geometry::copy_segments<false>(linestring, segment_id, index, current_piece); + detail::overlay::append_no_duplicates(current_piece, point); + if (current_piece.size() > 1) + { + *out++ = current_piece; + } + current_piece.clear(); + } + + static inline bool is_entered(bool entered) + { + return entered; + } + + template <typename Point, typename Geometry> + static inline bool included(Point const& point, Geometry const& geometry) + { + return geometry::covered_by(point, geometry); + } + +}; + +// Specialization for difference, which reverses these actions +template<> +struct action_selector<overlay_difference> +{ + typedef action_selector<overlay_intersection> normal_action; + + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void enter(LineStringOut& current_piece, + LineString const& linestring, + segment_identifier& segment_id, + int index, Point const& point, + Operation const& operation, OutputIterator& out) + { + normal_action::leave(current_piece, linestring, segment_id, index, + point, operation, out); + } + + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void leave(LineStringOut& current_piece, + LineString const& linestring, + segment_identifier& segment_id, + int index, Point const& point, + Operation const& operation, OutputIterator& out) + { + normal_action::enter(current_piece, linestring, segment_id, index, + point, operation, out); + } + + static inline bool is_entered(bool entered) + { + return ! normal_action::is_entered(entered); + } + + template <typename Point, typename Geometry> + static inline bool included(Point const& point, Geometry const& geometry) + { + return ! normal_action::included(point, geometry); + } + +}; + +} + +/*! +\brief Follows a linestring from intersection point to intersection point, outputting which + is inside, or outside, a ring or polygon +\ingroup overlay + */ +template +< + typename LineStringOut, + typename LineString, + typename Polygon, + overlay_type OverlayType +> +class follow +{ + + template<typename Turn> + struct sort_on_segment + { + // In case of turn point at the same location, we want to have continue/blocked LAST + // because that should be followed (intersection) or skipped (difference). + // By chance the enumeration is ordered like that but we keep the safe way here. + inline int operation_order(Turn const& turn) const + { + operation_type const& operation = turn.operations[0].operation; + switch(operation) + { + case operation_none : return 0; + case operation_union : return 1; + case operation_intersection : return 2; + case operation_blocked : return 3; + case operation_continue : return 4; + } + return -1; + }; + + inline bool use_operation(Turn const& left, Turn const& right) const + { + // If they are the same, OK. + return operation_order(left) < operation_order(right); + } + + inline bool use_distance(Turn const& left, Turn const& right) const + { + return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance) + ? use_operation(left, right) + : left.operations[0].enriched.distance < right.operations[0].enriched.distance + ; + } + + inline bool operator()(Turn const& left, Turn const& right) const + { + segment_identifier const& sl = left.operations[0].seg_id; + segment_identifier const& sr = right.operations[0].seg_id; + + return sl == sr + ? use_distance(left, right) + : sl < sr + ; + + } + }; + + + +public : + + template <typename Point, typename Geometry> + static inline bool included(Point const& point, Geometry const& geometry) + { + return following::action_selector<OverlayType>::included(point, geometry); + } + + template<typename Turns, typename OutputIterator> + static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon, + detail::overlay::operation_type , // TODO: this parameter might be redundant + Turns& turns, OutputIterator out) + { + 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; + + typedef following::action_selector<OverlayType> action; + + // Sort intersection points on segments-along-linestring, and distance + // (like in enrich is done for poly/poly) + std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>()); + + LineStringOut current_piece; + geometry::segment_identifier current_segment_id(0, -1, -1, -1); + + // Iterate through all intersection points (they are ordered along the line) + bool entered = false; + bool first = true; + for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it) + { + turn_operation_iterator_type iit = boost::begin(it->operations); + + if (following::was_entered(*it, *iit, first, linestring, polygon)) + { + debug_traverse(*it, *iit, "-> Was entered"); + entered = true; + } + + if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon)) + { + debug_traverse(*it, *iit, "-> Staying inside"); + + entered = true; + } + else if (following::is_entering(*it, *iit)) + { + debug_traverse(*it, *iit, "-> Entering"); + + entered = true; + action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); + } + else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon)) + { + debug_traverse(*it, *iit, "-> Leaving"); + + entered = false; + action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); + } + first = false; + } + + if (action::is_entered(entered)) + { + geometry::copy_segments<false>(linestring, current_segment_id, + boost::size(linestring) - 1, + current_piece); + } + + // Output the last one, if applicable + if (current_piece.size() > 1) + { + *out++ = current_piece; + } + return out; + } + +}; + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp new file mode 100644 index 0000000000..019c3ba3f9 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -0,0 +1,146 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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& , + 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 diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp new file mode 100644 index 0000000000..522ef68382 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp @@ -0,0 +1,108 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp new file mode 100644 index 0000000000..ad47665500 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp new file mode 100644 index 0000000000..663d70d9af --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -0,0 +1,956 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 +{ + +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) +class turn_info_exception : public geometry::exception +{ + std::string message; +public: + + // NOTE: "char" will be replaced by enum in future version + inline turn_info_exception(char const method) + { + message = "Boost.Geometry Turn exception: "; + message += method; + } + + virtual ~turn_info_exception() throw() + {} + + virtual char const* what() const throw() + { + return message.c_str(); + } +}; +#endif + +#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& , + 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& , Point2 const& qj, Point2 const& qk, + TurnInfo& ti, + IntersectionInfo const& intersection_info, + DirInfo const& ) + { + 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& , Point1 const& , Point1 const& , + Point2 const& , Point2 const& , Point2 const& , + 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; + } +}; + +template<typename TurnInfo> +struct only_convert +{ + template<typename IntersectionInfo> + static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info) + { + ti.method = method_collinear; + geometry::convert(intersection_info.intersections[0], ti.point); + ti.operations[0].operation = operation_continue; + ti.operations[1].operation = operation_continue; + } +}; + +/*! +\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 +{ + static bool const include_no_turn = false; + static bool const include_degenerate = false; + + template <typename Point1, typename Point2, typename Info> + static inline void apply(Info& , Point1 const& , Point2 const& ) + {} + +}; + + +/*! + \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. + It also defines if a certain class of points + (degenerate, non-turns) should be included. + */ +template +< + typename Point1, + typename Point2, + typename TurnInfo, + typename AssignPolicy +> +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' : // collinear, "at" + case 'f' : // collinear, "from" + case 's' : // starts from the middle + if (AssignPolicy::include_no_turn + && result.template get<0>().count > 0) + { + only_convert<TurnInfo>::apply(tp, + result.template get<0>()); + AssignPolicy::apply(tp, pi, qi); + *out++ = tp; + } + break; + + case 'd' : // disjoint: never do anything + 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 + if (AssignPolicy::include_degenerate) + { + only_convert<TurnInfo>::apply(tp, result.template get<0>()); + AssignPolicy::apply(tp, pi, qi); + *out++ = tp; + } + } + break; + default : + { +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) + throw turn_info_exception(method); +#endif + } + break; + } + + return out; + } +}; + + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp new file mode 100644 index 0000000000..5740a8b7ba --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -0,0 +1,866 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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/io/dsv/write.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, + bool skip_larger, + 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 = (skip_larger && 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, + false, + 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 diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp new file mode 100644 index 0000000000..1e878ca525 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -0,0 +1,672 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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; + } + + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + 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; + + 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; + } +#else + inline void debug_consider(int, Indexed const& , + Indexed const& , std::string const& , + bool = true, + std::string const& = "", bool = false + ) const + {} +#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 , + Geometry1 const& , Geometry2 const& , + Strategy const& ) +{ + 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 diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp new file mode 100644 index 0000000000..8bca790d74 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -0,0 +1,690 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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/point_on_border.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/algorithms/detail/overlay/follow.hpp> +#include <boost/geometry/views/segment_view.hpp> + +#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) +#include <boost/foreach.hpp> +#endif + +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& ) + { + 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& ) + { + 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; + } +}; + +/*! +\brief Version of linestring with an areal feature (polygon or multipolygon) +*/ +template +< + typename LineString, typename Areal, + bool ReverseAreal, + typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_of_linestring_with_areal +{ + typedef detail::overlay::follow + < + LineStringOut, + LineString, + Areal, + OverlayType + > follower; + +#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) + template <typename Turn, typename Operation> + static inline void debug_follow(Turn const& turn, Operation op, + int index) + { + std::cout << index + << " at " << op.seg_id + << " meth: " << method_char(turn.method) + << " op: " << operation_char(op.operation) + << " vis: " << visited_char(op.visited) + << " of: " << operation_char(turn.operations[0].operation) + << operation_char(turn.operations[1].operation) + << " " << geometry::wkt(turn.point) + << std::endl; + } +#endif + + static inline OutputIterator apply(LineString const& linestring, Areal const& areal, + OutputIterator out, + Strategy const& ) + { + if (boost::size(linestring) == 0) + { + return out; + } + + typedef typename point_type<LineStringOut>::type point_type; + + typedef detail::overlay::traversal_turn_info<point_type> turn_info; + std::deque<turn_info> turns; + + detail::get_turns::no_interrupt_policy policy; + geometry::get_turns + < + false, + (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), + detail::overlay::calculate_distance_policy + >(linestring, areal, turns, policy); + + if (turns.empty()) + { + // No intersection points, it is either completely + // inside (interior + borders) + // or completely outside + + // Use border point (on a segment) to check this + // (because turn points might skip some cases) + point_type border_point; + if (! geometry::point_on_border(border_point, linestring, true)) + { + return out; + } + + + if (follower::included(border_point, areal)) + { + LineStringOut copy; + geometry::convert(linestring, copy); + *out++ = copy; + } + return out; + } + +#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) + int index = 0; + BOOST_FOREACH(turn_info const& turn, turns) + { + debug_follow(turn, turn.operations[0], index++); + } +#endif + + return follower::apply + ( + linestring, areal, + geometry::detail::overlay::operation_intersection, + turns, 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& ) + { + 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 Linestring, typename Polygon, + bool ReverseLinestring, bool ReversePolygon, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + linestring_tag, polygon_tag, linestring_tag, + false, true, false, + Linestring, Polygon, + ReverseLinestring, ReversePolygon, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_linestring_with_areal + < + Linestring, Polygon, + ReversePolygon, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + + +template +< + typename Linestring, typename Ring, + bool ReverseLinestring, bool ReverseRing, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + linestring_tag, ring_tag, linestring_tag, + false, true, false, + Linestring, Ring, + ReverseLinestring, ReverseRing, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_linestring_with_areal + < + Linestring, Ring, + ReverseRing, + OutputIterator, GeometryOut, + OverlayType, + 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& ) + { + 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& ) + { + + 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 diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp new file mode 100644 index 0000000000..ab5b6d123d --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -0,0 +1,301 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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/io/dsv/write.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; + } + + if (geometry::num_points(geometry1) == 0 + || geometry::num_points(geometry2) == 0) + { + return return_if_one_input_is_empty + < + GeometryOut, Direction, ReverseOut + >(geometry1, geometry2, 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; + + 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 diff --git a/boost/geometry/algorithms/detail/overlay/overlay_type.hpp b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp new file mode 100644 index 0000000000..af62131f0e --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp @@ -0,0 +1,29 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp new file mode 100644 index 0000000000..a6088694da --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp new file mode 100644 index 0000000000..007113ffba --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp @@ -0,0 +1,91 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp new file mode 100644 index 0000000000..f664b19514 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -0,0 +1,295 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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& , + 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& , + 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& , 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& , 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 diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp new file mode 100644 index 0000000000..9c4c99394e --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -0,0 +1,308 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 +{ + +struct no_interrupt_policy +{ + static bool const enabled = false; + static bool const has_intersections = false; + + + template <typename Range> + static inline bool apply(Range const&) + { + return false; + } +}; + + + + +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, + false, + 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 diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp new file mode 100644 index 0000000000..eebe381944 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp @@ -0,0 +1,75 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp new file mode 100644 index 0000000000..810a27af04 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp new file mode 100644 index 0000000000..12daafa0cf --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -0,0 +1,395 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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) \ + || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) +# include <string> +# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +# include <boost/geometry/io/wkt/wkt.hpp> +#endif + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +template <typename Turn, typename Operation> +#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE +inline void debug_traverse(Turn const& turn, Operation op, + std::string const& header) +{ + std::cout << header + << " at " << op.seg_id + << " meth: " << method_char(turn.method) + << " op: " << operation_char(op.operation) + << " vis: " << visited_char(op.visited) + << " of: " << operation_char(turn.operations[0].operation) + << operation_char(turn.operations[1].operation) + << " " << geometry::wkt(turn.point) + << std::endl; + + if (boost::contains(header, "Finished")) + { + std::cout << std::endl; + } +} +#else +inline void debug_traverse(Turn const& , Operation, std::string const& ) +{ +} +#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 diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp new file mode 100644 index 0000000000..aa6b428f19 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -0,0 +1,142 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp new file mode 100644 index 0000000000..6be63f42b4 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp @@ -0,0 +1,136 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp new file mode 100644 index 0000000000..7a7de2cdd3 --- /dev/null +++ b/boost/geometry/algorithms/detail/partition.hpp @@ -0,0 +1,425 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 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/range/algorithm/copy.hpp> +#include <boost/geometry/algorithms/assign.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_PARTITION_HPP diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp new file mode 100644 index 0000000000..33177924aa --- /dev/null +++ b/boost/geometry/algorithms/detail/point_on_border.hpp @@ -0,0 +1,243 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/ring_identifier.hpp b/boost/geometry/algorithms/detail/ring_identifier.hpp new file mode 100644 index 0000000000..9209ee0304 --- /dev/null +++ b/boost/geometry/algorithms/detail/ring_identifier.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp new file mode 100644 index 0000000000..ad62f232bd --- /dev/null +++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp @@ -0,0 +1,131 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& ) + { + 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 diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp new file mode 100644 index 0000000000..36bcbdd6e7 --- /dev/null +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -0,0 +1,648 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp new file mode 100644 index 0000000000..62328a0d87 --- /dev/null +++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// 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_THROW_ON_EMPTY_INPUT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP + +#include <boost/geometry/core/exception.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + +// BSG 2012-02-06: we use this currently only for distance. +// For other scalar results area,length,perimeter it is commented on purpose. +// Reason is that for distance there is no other choice. distance of two +// empty geometries (or one empty) should NOT return any value. +// But for area it is no problem to be 0. +// Suppose: area(intersection(a,b)). We (probably) don't want a throw there... + +// So decided that at least for Boost 1.49 this is commented for +// scalar results, except distance. + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Geometry> +inline void throw_on_empty_input(Geometry const& geometry) +{ +#if ! defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) + if (geometry::num_points(geometry) == 0) + { + throw empty_input_exception(); + } +#endif +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP + diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp new file mode 100644 index 0000000000..480dd928de --- /dev/null +++ b/boost/geometry/algorithms/difference.hpp @@ -0,0 +1,160 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 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, true>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, + OutputIterator, GeometryOut, + overlay_difference, + Strategy + >::apply(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 diff --git a/boost/geometry/algorithms/disjoint.hpp b/boost/geometry/algorithms/disjoint.hpp new file mode 100644 index 0000000000..f36b8dbdd0 --- /dev/null +++ b/boost/geometry/algorithms/disjoint.hpp @@ -0,0 +1,270 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 +{ + +struct assign_disjoint_policy +{ + // We want to include all points: + static bool const include_no_turn = true; + static bool const include_degenerate = true; + + // We don't assign extra info: + template <typename Point1, typename Point2, typename Info> + static inline void apply(Info& , Point1 const& , Point2 const& ) + {} +}; + + +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; + + // Specify two policies: + // 1) Stop at any intersection + // 2) In assignment, include also degenerate points (which are normally skipped) + disjoint_interrupt_policy policy; + geometry::get_turns + < + false, false, + assign_disjoint_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} + +\qbk{[include reference/algorithms/disjoint.qbk]} +*/ +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 diff --git a/boost/geometry/algorithms/distance.hpp b/boost/geometry/algorithms/distance.hpp new file mode 100644 index 0000000000..eca3b03c7b --- /dev/null +++ b/boost/geometry/algorithms/distance.hpp @@ -0,0 +1,591 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/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/algorithms/not_implemented.hpp> +#include <boost/geometry/algorithms/detail/throw_on_empty_input.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& ) + { + 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; + } +}; + + +// Helper metafunction for default strategy retrieval +template <typename Geometry1, typename Geometry2> +struct default_strategy + : strategy::distance::services::default_strategy + < + point_tag, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + > +{}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +using strategy::distance::services::return_type; + + +template +< + typename Geometry1, typename Geometry2, + typename Strategy = typename detail::distance::default_strategy<Geometry1, Geometry2>::type, + typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type, + typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type, + typename StrategyTag = typename strategy::distance::services::tag<Strategy>::type, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct distance: not_implemented<Tag1, Tag2> +{}; + + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, typename Strategy, + typename Tag1, typename Tag2, typename StrategyTag +> +struct distance +< + Geometry1, Geometry2, Strategy, + Tag1, Tag2, StrategyTag, + true +> + : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false> +{ + static inline typename return_type<Strategy>::type apply( + Geometry1 const& g1, + Geometry2 const& g2, + Strategy const& strategy) + { + return distance + < + Geometry2, Geometry1, Strategy, + Tag2, Tag1, StrategyTag, + false + >::apply(g2, g1, strategy); + } +}; + +// If reversal is needed and we got the strategy by default, invert it before +// proceeding to the reversal. +template +< + typename Geometry1, typename Geometry2, + typename Tag1, typename Tag2, typename StrategyTag +> +struct distance +< + Geometry1, Geometry2, + typename detail::distance::default_strategy<Geometry1, Geometry2>::type, + Tag1, Tag2, StrategyTag, + true +> + : distance + < + Geometry2, Geometry1, + typename detail::distance::default_strategy<Geometry2, Geometry1>::type, + Tag2, Tag1, StrategyTag, + false + > +{ + typedef typename detail::distance::default_strategy<Geometry2, Geometry1>::type reversed_strategy; + + static inline typename strategy::distance::services::return_type<reversed_strategy>::type apply( + Geometry1 const& g1, + Geometry2 const& g2, + typename detail::distance::default_strategy<Geometry1, Geometry2>::type const&) + { + return distance + < + Geometry2, Geometry1, reversed_strategy, + Tag2, Tag1, StrategyTag, + false + >::apply(g2, g1, reversed_strategy()); + } +}; + + +// Point-point +template <typename P1, typename P2, typename Strategy> +struct distance + < + P1, P2, Strategy, + point_tag, point_tag, strategy_tag_distance_point_point, + false + > + : 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, Linestring, Strategy, + point_tag, linestring_tag, strategy_tag_distance_point_point, + false +> +{ + + 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, Linestring, Strategy, + point_tag, linestring_tag, strategy_tag_distance_point_segment, + false +> +{ + 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, Ring, Strategy, + point_tag, ring_tag, strategy_tag_distance_point_point, + false +> +{ + 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, Polygon, Strategy, + point_tag, polygon_tag, strategy_tag_distance_point_point, + false +> +{ + 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, Segment, Strategy, + point_tag, segment_tag, strategy_tag_distance_point_point, + false +> : 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, Segment, Strategy, + point_tag, segment_tag, strategy_tag_distance_point_segment, + false +> +{ + 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]); + } +}; + + + +} // 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>(); + + detail::throw_on_empty_input(geometry1); + detail::throw_on_empty_input(geometry2); + + return dispatch::distance + < + Geometry1, + Geometry2, + Strategy + >::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>(); + + return distance(geometry1, geometry2, + typename detail::distance::default_strategy<Geometry1, Geometry2>::type()); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP diff --git a/boost/geometry/algorithms/envelope.hpp b/boost/geometry/algorithms/envelope.hpp new file mode 100644 index 0000000000..da34f6a783 --- /dev/null +++ b/boost/geometry/algorithms/envelope.hpp @@ -0,0 +1,273 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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} + +\qbk{[include reference/algorithms/envelope.qbk]} +\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{[include reference/algorithms/envelope.qbk]} +\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 diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp new file mode 100644 index 0000000000..6b094f76d0 --- /dev/null +++ b/boost/geometry/algorithms/equals.hpp @@ -0,0 +1,319 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 + diff --git a/boost/geometry/algorithms/expand.hpp b/boost/geometry/algorithms/expand.hpp new file mode 100644 index 0000000000..da7442b593 --- /dev/null +++ b/boost/geometry/algorithms/expand.hpp @@ -0,0 +1,319 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/for_each.hpp b/boost/geometry/algorithms/for_each.hpp new file mode 100644 index 0000000000..671f26a70d --- /dev/null +++ b/boost/geometry/algorithms/for_each.hpp @@ -0,0 +1,358 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& , Functor f) + { + // TODO: if non-const, we should extract the points from the segment + // and call the functor on those two points + 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{[include reference/algorithms/for_each_point.qbk]} +\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{[include reference/algorithms/for_each_point.qbk]} +\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{[include reference/algorithms/for_each_segment.qbk]} +\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 + +\qbk{[include reference/algorithms/for_each_segment.qbk]} +*/ +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 diff --git a/boost/geometry/algorithms/intersection.hpp b/boost/geometry/algorithms/intersection.hpp new file mode 100644 index 0000000000..8d3dd68b3a --- /dev/null +++ b/boost/geometry/algorithms/intersection.hpp @@ -0,0 +1,237 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp new file mode 100644 index 0000000000..f367f2e258 --- /dev/null +++ b/boost/geometry/algorithms/intersects.hpp @@ -0,0 +1,106 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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{[def __one_parameter__]} +\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 diff --git a/boost/geometry/algorithms/length.hpp b/boost/geometry/algorithms/length.hpp new file mode 100644 index 0000000000..de53a39e8f --- /dev/null +++ b/boost/geometry/algorithms/length.hpp @@ -0,0 +1,204 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/algorithms/detail/throw_on_empty_input.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>(); + + // detail::throw_on_empty_input(geometry); + + 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>(); + + // detail::throw_on_empty_input(geometry); + + return dispatch::length + < + typename tag<Geometry>::type, + Geometry, + Strategy + >::apply(geometry, strategy); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP diff --git a/boost/geometry/algorithms/make.hpp b/boost/geometry/algorithms/make.hpp new file mode 100644 index 0000000000..d0e3092492 --- /dev/null +++ b/boost/geometry/algorithms/make.hpp @@ -0,0 +1,200 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/not_implemented.hpp b/boost/geometry/algorithms/not_implemented.hpp new file mode 100644 index 0000000000..008f111cc8 --- /dev/null +++ b/boost/geometry/algorithms/not_implemented.hpp @@ -0,0 +1,117 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_NOT_IMPLEMENTED_HPP +#define BOOST_GEOMETRY_ALGORITHMS_NOT_IMPLEMENTED_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +namespace info +{ + struct UNRECOGNIZED_GEOMETRY_TYPE {}; + struct POINT {}; + struct LINESTRING {}; + struct POLYGON {}; + struct RING {}; + struct BOX {}; + struct SEGMENT {}; + struct MULTI_POINT {}; + struct MULTI_LINESTRING {}; + struct MULTI_POLYGON {}; + struct GEOMETRY_COLLECTION {}; + template <size_t D> struct DIMENSION {}; +} + + +namespace nyi +{ + + +struct not_implemented_tag {}; + +template +< + typename Term1, + typename Term2, + typename Term3 +> +struct not_implemented_error +{ + +#ifndef BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD +# define BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD false +#endif + + BOOST_MPL_ASSERT_MSG + ( + BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD, + THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED, + ( + types<Term1, Term2, Term3> + ) + ); +}; + +template <typename Tag> +struct tag_to_term +{ + typedef Tag type; +}; + +template <> struct tag_to_term<geometry_not_recognized_tag> { typedef info::UNRECOGNIZED_GEOMETRY_TYPE type; }; +template <> struct tag_to_term<point_tag> { typedef info::POINT type; }; +template <> struct tag_to_term<linestring_tag> { typedef info::LINESTRING type; }; +template <> struct tag_to_term<polygon_tag> { typedef info::POLYGON type; }; +template <> struct tag_to_term<ring_tag> { typedef info::RING type; }; +template <> struct tag_to_term<box_tag> { typedef info::BOX type; }; +template <> struct tag_to_term<segment_tag> { typedef info::SEGMENT type; }; +template <> struct tag_to_term<multi_point_tag> { typedef info::MULTI_POINT type; }; +template <> struct tag_to_term<multi_linestring_tag> { typedef info::MULTI_LINESTRING type; }; +template <> struct tag_to_term<multi_polygon_tag> { typedef info::MULTI_POLYGON type; }; +template <> struct tag_to_term<geometry_collection_tag> { typedef info::GEOMETRY_COLLECTION type; }; +template <int D> struct tag_to_term<mpl::int_<D> > { typedef info::DIMENSION<D> type; }; + + +} + + +template +< + typename Term1 = void, + typename Term2 = void, + typename Term3 = void +> +struct not_implemented + : nyi::not_implemented_tag, + nyi::not_implemented_error + < + typename mpl::identity<typename nyi::tag_to_term<Term1>::type>::type, + typename mpl::identity<typename nyi::tag_to_term<Term2>::type>::type, + typename mpl::identity<typename nyi::tag_to_term<Term3>::type>::type + > +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_NOT_IMPLEMENTED_HPP diff --git a/boost/geometry/algorithms/num_geometries.hpp b/boost/geometry/algorithms/num_geometries.hpp new file mode 100644 index 0000000000..20f35e90d2 --- /dev/null +++ b/boost/geometry/algorithms/num_geometries.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/num_interior_rings.hpp b/boost/geometry/algorithms/num_interior_rings.hpp new file mode 100644 index 0000000000..2149f46576 --- /dev/null +++ b/boost/geometry/algorithms/num_interior_rings.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/num_points.hpp b/boost/geometry/algorithms/num_points.hpp new file mode 100644 index 0000000000..c480068f43 --- /dev/null +++ b/boost/geometry/algorithms/num_points.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp new file mode 100644 index 0000000000..2f854b4fdd --- /dev/null +++ b/boost/geometry/algorithms/overlaps.hpp @@ -0,0 +1,202 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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} + +\qbk{[include reference/algorithms/overlaps.qbk]} +*/ +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 diff --git a/boost/geometry/algorithms/perimeter.hpp b/boost/geometry/algorithms/perimeter.hpp new file mode 100644 index 0000000000..adeb0b05b0 --- /dev/null +++ b/boost/geometry/algorithms/perimeter.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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> +// #include <boost/geometry/algorithms/detail/throw_on_empty_input.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; + + // detail::throw_on_empty_input(geometry); + + 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>(); + + // detail::throw_on_empty_input(geometry); + + return dispatch::perimeter + < + typename tag<Geometry>::type, + Geometry, + Strategy + >::apply(geometry, strategy); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP + diff --git a/boost/geometry/algorithms/reverse.hpp b/boost/geometry/algorithms/reverse.hpp new file mode 100644 index 0000000000..bf0ef2d9a9 --- /dev/null +++ b/boost/geometry/algorithms/reverse.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/simplify.hpp b/boost/geometry/algorithms/simplify.hpp new file mode 100644 index 0000000000..225321d303 --- /dev/null +++ b/boost/geometry/algorithms/simplify.hpp @@ -0,0 +1,405 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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& , Strategy const& ) + { + 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& , Strategy const& ) + { + 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 diff --git a/boost/geometry/algorithms/sym_difference.hpp b/boost/geometry/algorithms/sym_difference.hpp new file mode 100644 index 0000000000..6394576de4 --- /dev/null +++ b/boost/geometry/algorithms/sym_difference.hpp @@ -0,0 +1,177 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 = 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, true>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, + OutputIterator, GeometryOut, + overlay_difference, + Strategy + >::apply(geometry1, geometry2, out, strategy); + out = geometry::dispatch::intersection_insert + < + typename geometry::tag<Geometry2>::type, + typename geometry::tag<Geometry1>::type, + typename geometry::tag<GeometryOut>::type, + geometry::is_areal<Geometry2>::value, + geometry::is_areal<Geometry1>::value, + geometry::is_areal<GeometryOut>::value, + Geometry2, Geometry1, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, true>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, + OutputIterator, GeometryOut, + overlay_difference, + Strategy + >::apply(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 diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp new file mode 100644 index 0000000000..22b45dc77e --- /dev/null +++ b/boost/geometry/algorithms/transform.hpp @@ -0,0 +1,351 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/union.hpp b/boost/geometry/algorithms/union.hpp new file mode 100644 index 0000000000..28d8e5dc0b --- /dev/null +++ b/boost/geometry/algorithms/union.hpp @@ -0,0 +1,284 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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 diff --git a/boost/geometry/algorithms/unique.hpp b/boost/geometry/algorithms/unique.hpp new file mode 100644 index 0000000000..3bbf479f9b --- /dev/null +++ b/boost/geometry/algorithms/unique.hpp @@ -0,0 +1,153 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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 diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp new file mode 100644 index 0000000000..0e0cb68d53 --- /dev/null +++ b/boost/geometry/algorithms/within.hpp @@ -0,0 +1,344 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/make.hpp> +#include <boost/geometry/algorithms/not_implemented.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 Geometry1, + typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type +> +struct within: not_implemented<Tag1, Tag2> +{}; + + +template <typename Point, typename Box> +struct within<Point, Box, point_tag, box_tag> +{ + template <typename Strategy> + static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + { + return strategy.apply(point, box); + } +}; + +template <typename Box1, typename Box2> +struct within<Box1, Box2, box_tag, box_tag> +{ + template <typename 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> +struct within<Point, Ring, point_tag, ring_tag> +{ + template <typename 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> +struct within<Point, Polygon, point_tag, polygon_tag> +{ + template <typename 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 which might be within the second geometry +\param geometry2 \param_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 + < + Geometry1, + Geometry2 + >::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 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 + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP diff --git a/boost/geometry/arithmetic/arithmetic.hpp b/boost/geometry/arithmetic/arithmetic.hpp new file mode 100644 index 0000000000..6479ecc4a6 --- /dev/null +++ b/boost/geometry/arithmetic/arithmetic.hpp @@ -0,0 +1,281 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_ARITHMETIC_ARITHMETIC_HPP +#define BOOST_GEOMETRY_ARITHMETIC_ARITHMETIC_HPP + +#include <functional> + +#include <boost/call_traits.hpp> +#include <boost/concept/requires.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/util/for_each_coordinate.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename P> +struct param +{ + typedef typename boost::call_traits + < + typename coordinate_type<P>::type + >::param_type type; +}; + + +template <typename C, template <typename> class Function> +struct value_operation +{ + C m_value; + + inline value_operation(C const &value) + : m_value(value) + {} + + template <typename P, int I> + inline void apply(P& point) const + { + set<I>(point, Function<C>()(get<I>(point), m_value)); + } +}; + +template <typename PointSrc, template <typename> class Function> +struct point_operation +{ + typedef typename coordinate_type<PointSrc>::type coordinate_type; + PointSrc const& m_source_point; + + inline point_operation(PointSrc const& point) + : m_source_point(point) + {} + + template <typename PointDst, int I> + inline void apply(PointDst& dest_point) const + { + set<I>(dest_point, + Function<coordinate_type>()(get<I>(dest_point), get<I>(m_source_point))); + } +}; + + +template <typename C> +struct value_assignment +{ + C m_value; + + inline value_assignment(C const &value) + : m_value(value) + {} + + template <typename P, int I> + inline void apply(P& point) const + { + set<I>(point, m_value); + } +}; + +template <typename PointSrc> +struct point_assignment +{ + PointSrc const& m_source_point; + + inline point_assignment(PointSrc const& point) + : m_source_point(point) + {} + + template <typename PointDst, int I> + inline void apply(PointDst& dest_point) const + { + set<I>(dest_point, get<I>(m_source_point)); + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +/*! + \brief Adds the same value to each coordinate of a point + \ingroup arithmetic + \details + \param p point + \param value value to add + */ +template <typename Point> +inline void add_value(Point& p, typename detail::param<Point>::type value) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + for_each_coordinate(p, detail::value_operation<typename coordinate_type<Point>::type, std::plus>(value)); +} + +/*! + \brief Adds a point to another + \ingroup arithmetic + \details The coordinates of the second point will be added to those of the first point. + The second point is not modified. + \param p1 first point + \param p2 second point + */ +template <typename Point1, typename Point2> +inline void add_point(Point1& p1, Point2 const& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + for_each_coordinate(p1, detail::point_operation<Point2, std::plus>(p2)); +} + +/*! + \brief Subtracts the same value to each coordinate of a point + \ingroup arithmetic + \details + \param p point + \param value value to subtract + */ +template <typename Point> +inline void subtract_value(Point& p, typename detail::param<Point>::type value) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + for_each_coordinate(p, detail::value_operation<typename coordinate_type<Point>::type, std::minus>(value)); +} + +/*! + \brief Subtracts a point to another + \ingroup arithmetic + \details The coordinates of the second point will be subtracted to those of the first point. + The second point is not modified. + \param p1 first point + \param p2 second point + */ +template <typename Point1, typename Point2> +inline void subtract_point(Point1& p1, Point2 const& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + for_each_coordinate(p1, detail::point_operation<Point2, std::minus>(p2)); +} + +/*! + \brief Multiplies each coordinate of a point by the same value + \ingroup arithmetic + \details + \param p point + \param value value to multiply by + */ +template <typename Point> +inline void multiply_value(Point& p, typename detail::param<Point>::type value) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + for_each_coordinate(p, detail::value_operation<typename coordinate_type<Point>::type, std::multiplies>(value)); +} + +/*! + \brief Multiplies a point by another + \ingroup arithmetic + \details The coordinates of the first point will be multiplied by those of the second point. + The second point is not modified. + \param p1 first point + \param p2 second point + \note This is *not* a dot, cross or wedge product. It is a mere field-by-field multiplication. + */ +template <typename Point1, typename Point2> +inline void multiply_point(Point1& p1, Point2 const& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + for_each_coordinate(p1, detail::point_operation<Point2, std::multiplies>(p2)); +} + +/*! + \brief Divides each coordinate of the same point by a value + \ingroup arithmetic + \details + \param p point + \param value value to divide by + */ +template <typename Point> +inline void divide_value(Point& p, typename detail::param<Point>::type value) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + for_each_coordinate(p, detail::value_operation<typename coordinate_type<Point>::type, std::divides>(value)); +} + +/*! + \brief Divides a point by another + \ingroup arithmetic + \details The coordinates of the first point will be divided by those of the second point. + The second point is not modified. + \param p1 first point + \param p2 second point + */ +template <typename Point1, typename Point2> +inline void divide_point(Point1& p1, Point2 const& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + for_each_coordinate(p1, detail::point_operation<Point2, std::divides>(p2)); +} + +/*! + \brief Assign each coordinate of a point the same value + \ingroup arithmetic + \details + \param p point + \param value value to assign + */ +template <typename Point> +inline void assign_value(Point& p, typename detail::param<Point>::type value) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + for_each_coordinate(p, detail::value_assignment<typename coordinate_type<Point>::type>(value)); +} + +/*! + \brief Assign a point with another + \ingroup arithmetic + \details The coordinates of the first point will be assigned those of the second point. + The second point is not modified. + \param p1 first point + \param p2 second point + */ +template <typename Point1, typename Point2> +inline void assign_point(Point1& p1, const Point2& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + for_each_coordinate(p1, detail::point_assignment<Point2>(p2)); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ARITHMETIC_ARITHMETIC_HPP diff --git a/boost/geometry/arithmetic/determinant.hpp b/boost/geometry/arithmetic/determinant.hpp new file mode 100644 index 0000000000..db3b867096 --- /dev/null +++ b/boost/geometry/arithmetic/determinant.hpp @@ -0,0 +1,76 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. + +// 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_ARITHMETIC_DETERMINANT_HPP +#define BOOST_GEOMETRY_ARITHMETIC_DETERMINANT_HPP + + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename ReturnType, typename U, typename V> +class calculate_determinant +{ + template <typename T> + static inline ReturnType rt(T const& v) + { + return boost::numeric_cast<ReturnType>(v); + } + +public : + + static inline ReturnType apply(U const& ux, U const& uy + , V const& vx, V const& vy) + { + return rt(ux) * rt(vy) - rt(uy) * rt(vx); + } +}; + +template <typename ReturnType, typename U, typename V> +inline ReturnType determinant(U const& ux, U const& uy + , V const& vx, V const& vy) +{ + return calculate_determinant + < + ReturnType, U, V + >::apply(ux, uy, vx, vy); +} + + +template <typename ReturnType, typename U, typename V> +inline ReturnType determinant(U const& u, V const& v) +{ + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<U>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<V>) ); + + return calculate_determinant + < + ReturnType, + typename geometry::coordinate_type<U>::type, + typename geometry::coordinate_type<V>::type + >::apply(get<0>(u), get<1>(u), get<0>(v), get<1>(v)); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ARITHMETIC_DETERMINANT_HPP diff --git a/boost/geometry/arithmetic/dot_product.hpp b/boost/geometry/arithmetic/dot_product.hpp new file mode 100644 index 0000000000..13fe968779 --- /dev/null +++ b/boost/geometry/arithmetic/dot_product.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_ARITHMETIC_DOT_PRODUCT_HPP +#define BOOST_GEOMETRY_ARITHMETIC_DOT_PRODUCT_HPP + + +#include <cstddef> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename P1, typename P2, std::size_t Dimension, std::size_t DimensionCount> +struct dot_product_maker +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + + static inline coordinate_type apply(P1 const& p1, P2 const& p2) + { + return get<Dimension>(p1) * get<Dimension>(p2) + + dot_product_maker<P1, P2, Dimension+1, DimensionCount>::apply(p1, p2); + } +}; + +template <typename P1, typename P2, std::size_t DimensionCount> +struct dot_product_maker<P1, P2, DimensionCount, DimensionCount> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + + static inline coordinate_type apply(P1 const& p1, P2 const& p2) + { + return get<DimensionCount>(p1) * get<DimensionCount>(p2); + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! + \brief Computes the dot product (or scalar product) of 2 vectors (points). + \ingroup arithmetic + \param p1 first point + \param p2 second point + \return the dot product + */ +template <typename P1, typename P2> +inline typename select_coordinate_type<P1, P2>::type dot_product( + P1 const& p1, P2 const& p2) +{ + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P1>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P2>) ); + + return detail::dot_product_maker + < + P1, P2, + 0, dimension<P1>::type::value - 1 + >::apply(p1, p2); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ARITHMETIC_DOT_PRODUCT_HPP diff --git a/boost/geometry/core/access.hpp b/boost/geometry/core/access.hpp new file mode 100644 index 0000000000..a463b8cdc3 --- /dev/null +++ b/boost/geometry/core/access.hpp @@ -0,0 +1,324 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_CORE_ACCESS_HPP +#define BOOST_GEOMETRY_CORE_ACCESS_HPP + + +#include <cstddef> + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/concept_check.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> + + +namespace boost { namespace geometry +{ + +/// Index of minimum corner of the box. +int const min_corner = 0; + +/// Index of maximum corner of the box. +int const max_corner = 1; + +namespace traits +{ + +/*! +\brief Traits class which gives access (get,set) to points. +\ingroup traits +\par Geometries: +/// @li point +\par Specializations should provide, per Dimension +/// @li static inline T get(G const&) +/// @li static inline void set(G&, T const&) +\tparam Geometry geometry-type +\tparam Dimension dimension to access +*/ +template <typename Geometry, std::size_t Dimension, typename Enable = void> +struct access +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE, (types<Geometry>) + ); +}; + + +/*! +\brief Traits class defining "get" and "set" to get + and set point coordinate values +\tparam Geometry geometry (box, segment) +\tparam Index index (min_corner/max_corner for box, 0/1 for segment) +\tparam Dimension dimension +\par Geometries: + - box + - segment +\par Specializations should provide: + - static inline T get(G const&) + - static inline void set(G&, T const&) +\ingroup traits +*/ +template <typename Geometry, std::size_t Index, std::size_t Dimension> +struct indexed_access {}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template +< + typename Tag, + typename Geometry, + typename + CoordinateType, std::size_t Dimension +> +struct access +{ + //static inline T get(G const&) {} + //static inline void set(G& g, T const& value) {} +}; + +template +< + typename Tag, + typename Geometry, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access +{ + //static inline T get(G const&) {} + //static inline void set(G& g, T const& value) {} +}; + +template <typename Point, typename CoordinateType, std::size_t Dimension> +struct access<point_tag, Point, CoordinateType, Dimension> +{ + static inline CoordinateType get(Point const& point) + { + return traits::access<Point, Dimension>::get(point); + } + static inline void set(Point& p, CoordinateType const& value) + { + traits::access<Point, Dimension>::set(p, value); + } +}; + +template +< + typename Box, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access<box_tag, Box, CoordinateType, Index, Dimension> +{ + static inline CoordinateType get(Box const& box) + { + return traits::indexed_access<Box, Index, Dimension>::get(box); + } + static inline void set(Box& b, CoordinateType const& value) + { + traits::indexed_access<Box, Index, Dimension>::set(b, value); + } +}; + +template +< + typename Segment, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access<segment_tag, Segment, CoordinateType, Index, Dimension> +{ + static inline CoordinateType get(Segment const& segment) + { + return traits::indexed_access<Segment, Index, Dimension>::get(segment); + } + static inline void set(Segment& segment, CoordinateType const& value) + { + traits::indexed_access<Segment, Index, Dimension>::set(segment, value); + } +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Two dummy tags to distinguish get/set variants below. +// They don't have to be specified by the user. The functions are distinguished +// by template signature also, but for e.g. GCC this is not enough. So give them +// a different signature. +struct signature_getset_dimension {}; +struct signature_getset_index_dimension {}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Get coordinate value of a geometry (usually a point) +\details \details_get_set +\ingroup get +\tparam Dimension \tparam_dimension_required +\tparam Geometry \tparam_geometry (usually a Point Concept) +\param geometry \param_geometry (usually a point) +\param dummy \qbk_skip +\return The coordinate value of specified dimension of specified geometry +\qbk{[include reference/core/get_point.qbk]} +*/ +template <std::size_t Dimension, typename Geometry> +inline typename coordinate_type<Geometry>::type get(Geometry const& geometry + , detail::signature_getset_dimension* dummy = 0 + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef typename boost::remove_const<Geometry>::type ncg_type; + + typedef core_dispatch::access + < + typename tag<Geometry>::type, + ncg_type, + typename coordinate_type<ncg_type>::type, + Dimension + > coord_access_type; + + return coord_access_type::get(geometry); +} + + +/*! +\brief Set coordinate value of a geometry (usually a point) +\details \details_get_set +\tparam Dimension \tparam_dimension_required +\tparam Geometry \tparam_geometry (usually a Point Concept) +\param geometry geometry to assign coordinate to +\param geometry \param_geometry (usually a point) +\param value The coordinate value to set +\param dummy \qbk_skip +\ingroup set + +\qbk{[include reference/core/set_point.qbk]} +*/ +template <std::size_t Dimension, typename Geometry> +inline void set(Geometry& geometry + , typename coordinate_type<Geometry>::type const& value + , detail::signature_getset_dimension* dummy = 0 + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef typename boost::remove_const<Geometry>::type ncg_type; + + typedef core_dispatch::access + < + typename tag<Geometry>::type, + ncg_type, + typename coordinate_type<ncg_type>::type, + Dimension + > coord_access_type; + + coord_access_type::set(geometry, value); +} + + +/*! +\brief get coordinate value of a Box or Segment +\details \details_get_set +\tparam Index \tparam_index_required +\tparam Dimension \tparam_dimension_required +\tparam Geometry \tparam_box_or_segment +\param geometry \param_geometry +\param dummy \qbk_skip +\return coordinate value +\ingroup get + +\qbk{distinguish,with index} +\qbk{[include reference/core/get_box.qbk]} +*/ +template <std::size_t Index, std::size_t Dimension, typename Geometry> +inline typename coordinate_type<Geometry>::type get(Geometry const& geometry + , detail::signature_getset_index_dimension* dummy = 0 + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef typename boost::remove_const<Geometry>::type ncg_type; + + typedef core_dispatch::indexed_access + < + typename tag<Geometry>::type, + ncg_type, + typename coordinate_type<ncg_type>::type, + Index, + Dimension + > coord_access_type; + + return coord_access_type::get(geometry); +} + +/*! +\brief set coordinate value of a Box / Segment +\details \details_get_set +\tparam Index \tparam_index_required +\tparam Dimension \tparam_dimension_required +\tparam Geometry \tparam_box_or_segment +\param geometry geometry to assign coordinate to +\param geometry \param_geometry +\param value The coordinate value to set +\param dummy \qbk_skip +\ingroup set + +\qbk{distinguish,with index} +\qbk{[include reference/core/set_box.qbk]} +*/ +template <std::size_t Index, std::size_t Dimension, typename Geometry> +inline void set(Geometry& geometry + , typename coordinate_type<Geometry>::type const& value + , detail::signature_getset_index_dimension* dummy = 0 + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef typename boost::remove_const<Geometry>::type ncg_type; + + typedef core_dispatch::indexed_access + < + typename tag<Geometry>::type, ncg_type, + typename coordinate_type<ncg_type>::type, + Index, + Dimension + > coord_access_type; + + coord_access_type::set(geometry, value); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_ACCESS_HPP diff --git a/boost/geometry/core/closure.hpp b/boost/geometry/core/closure.hpp new file mode 100644 index 0000000000..aab02e7871 --- /dev/null +++ b/boost/geometry/core/closure.hpp @@ -0,0 +1,180 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_CLOSURE_HPP +#define BOOST_GEOMETRY_CORE_CLOSURE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/mpl/int.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + + +/*! +\brief Enumerates options for defining if polygons are open or closed +\ingroup enum +\details The enumeration closure_selector describes options for if a polygon is + open or closed. In a closed polygon the very first point (per ring) should + be equal to the very last point. + The specific closing property of a polygon type is defined by the closure + metafunction. The closure metafunction defines a value, which is one of the + values enumerated in the closure_selector + +\qbk{ +[heading See also] +[link geometry.reference.core.closure The closure metafunction] +} +*/ +enum closure_selector +{ + /// Rings are open: first point and last point are different, algorithms + /// close them explicitly on the fly + open = 0, + /// Rings are closed: first point and last point must be the same + closed = 1, + /// (Not yet implemented): algorithms first figure out if ring must be + /// closed on the fly + closure_undertermined = -1 +}; + +namespace traits +{ + +/*! + \brief Traits class indicating if points within a + ring or (multi)polygon are closed (last point == first point), + open or not known. + \ingroup traits + \par Geometries: + - ring + \tparam G geometry +*/ +template <typename G> +struct closure +{ + static const closure_selector value = closed; +}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DETAIL +namespace core_detail { namespace closure +{ + +struct closed +{ + static const closure_selector value = geometry::closed; +}; + + +/// Metafunction to define the minimum size of a ring: +/// 3 for open rings, 4 for closed rings +template <closure_selector Closure> +struct minimum_ring_size {}; + +template <> +struct minimum_ring_size<geometry::closed> : boost::mpl::int_<4> {}; + +template <> +struct minimum_ring_size<geometry::open> : boost::mpl::int_<3> {}; + + +}} // namespace detail::point_order +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Tag, typename Geometry> +struct closure +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + +template <typename Box> +struct closure<point_tag, Box> : public core_detail::closure::closed {}; + +template <typename Box> +struct closure<box_tag, Box> : public core_detail::closure::closed {}; + +template <typename Box> +struct closure<segment_tag, Box> : public core_detail::closure::closed {}; + +template <typename LineString> +struct closure<linestring_tag, LineString> + : public core_detail::closure::closed {}; + + +template <typename Ring> +struct closure<ring_tag, Ring> +{ + static const closure_selector value + = geometry::traits::closure<Ring>::value; +}; + +// Specialization for polygon: the closure is the closure of its rings +template <typename Polygon> +struct closure<polygon_tag, Polygon> +{ + static const closure_selector value = core_dispatch::closure + < + ring_tag, + typename ring_type<polygon_tag, Polygon>::type + >::value ; +}; + + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief \brief_meta{value, closure (clockwise\, counterclockwise), + \meta_geometry_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/closure.qbk]} +*/ +template <typename Geometry> +struct closure +{ + static const closure_selector value = core_dispatch::closure + < + typename tag<Geometry>::type, + typename boost::remove_const<Geometry>::type + >::value; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_CLOSURE_HPP diff --git a/boost/geometry/core/coordinate_dimension.hpp b/boost/geometry/core/coordinate_dimension.hpp new file mode 100644 index 0000000000..84c11e2a55 --- /dev/null +++ b/boost/geometry/core/coordinate_dimension.hpp @@ -0,0 +1,126 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_CORE_COORDINATE_DIMENSION_HPP +#define BOOST_GEOMETRY_CORE_COORDINATE_DIMENSION_HPP + + +#include <cstddef> + +#include <boost/mpl/assert.hpp> +#include <boost/mpl/equal_to.hpp> +#include <boost/static_assert.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/point_type.hpp> + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! +\brief Traits class indicating the number of dimensions of a point +\par Geometries: + - point +\par Specializations should provide: + - value (should be derived from boost::mpl::int_<D> +\ingroup traits +*/ +template <typename Point, typename Enable = void> +struct dimension +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE, (types<Point>) + ); +}; + +} // namespace traits + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +// Base class derive from its own specialization of point-tag +template <typename T, typename G> +struct dimension : dimension<point_tag, typename point_type<T, G>::type> {}; + +template <typename P> +struct dimension<point_tag, P> : traits::dimension<P> {}; + +} // namespace core_dispatch +#endif + +/*! +\brief \brief_meta{value, number of coordinates (the number of axes of any geometry), \meta_point_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/coordinate_dimension.qbk]} +*/ +template <typename Geometry> +struct dimension + : core_dispatch::dimension + < + typename tag<Geometry>::type, + typename boost::remove_const<Geometry>::type + > +{}; + +/*! +\brief assert_dimension, enables compile-time checking if coordinate dimensions are as expected +\ingroup utility +*/ +template <typename Geometry, int Dimensions> +inline void assert_dimension() +{ + BOOST_STATIC_ASSERT(( + boost::mpl::equal_to + < + geometry::dimension<Geometry>, + boost::mpl::int_<Dimensions> + >::type::value + )); +} + +/*! +\brief assert_dimension, enables compile-time checking if coordinate dimensions are as expected +\ingroup utility +*/ +template <typename Geometry, int Dimensions> +inline void assert_dimension_less_equal() +{ + BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value <= Dimensions )); +} + +template <typename Geometry, int Dimensions> +inline void assert_dimension_greater_equal() +{ + BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value >= Dimensions )); +} + +/*! +\brief assert_dimension_equal, enables compile-time checking if coordinate dimensions of two geometries are equal +\ingroup utility +*/ +template <typename G1, typename G2> +inline void assert_dimension_equal() +{ + BOOST_STATIC_ASSERT(( dimension<G1>::type::value == dimension<G2>::type::value )); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_COORDINATE_DIMENSION_HPP diff --git a/boost/geometry/core/coordinate_system.hpp b/boost/geometry/core/coordinate_system.hpp new file mode 100644 index 0000000000..c23b8af15c --- /dev/null +++ b/boost/geometry/core/coordinate_system.hpp @@ -0,0 +1,97 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_CORE_COORDINATE_SYSTEM_HPP +#define BOOST_GEOMETRY_CORE_COORDINATE_SYSTEM_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/geometry/core/point_type.hpp> + + +namespace boost { namespace geometry +{ + + +namespace traits +{ + +/*! +\brief Traits class defining the coordinate system of a point, important for strategy selection +\ingroup traits +\par Geometries: + - point +\par Specializations should provide: + - typedef CS type; (cs::cartesian, cs::spherical, etc) +*/ +template <typename Point, typename Enable = void> +struct coordinate_system +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE, (types<Point>) + ); +}; + +} // namespace traits + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + template <typename GeometryTag, typename G> + struct coordinate_system + { + typedef typename point_type<GeometryTag, G>::type P; + + // Call its own specialization on point-tag + typedef typename coordinate_system<point_tag, P>::type type; + }; + + + template <typename P> + struct coordinate_system<point_tag, P> + { + typedef typename traits::coordinate_system<P>::type type; + }; + + +} // namespace core_dispatch +#endif + + +/*! +\brief \brief_meta{type, coordinate system (cartesian\, spherical\, etc), \meta_point_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/coordinate_system.qbk]} +*/ +template <typename Geometry> +struct coordinate_system +{ + typedef typename boost::remove_const<Geometry>::type ncg; + typedef typename core_dispatch::coordinate_system + < + typename tag<Geometry>::type, + ncg + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_COORDINATE_SYSTEM_HPP diff --git a/boost/geometry/core/coordinate_type.hpp b/boost/geometry/core/coordinate_type.hpp new file mode 100644 index 0000000000..0f901d3f19 --- /dev/null +++ b/boost/geometry/core/coordinate_type.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_CORE_COORDINATE_TYPE_HPP +#define BOOST_GEOMETRY_CORE_COORDINATE_TYPE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! +\brief Traits class which indicate the coordinate type (double,float,...) of a point +\ingroup traits +\par Geometries: + - point +\par Specializations should provide: + - typedef T type; (double,float,int,etc) +*/ +template <typename Point, typename Enable = void> +struct coordinate_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE, (types<Point>) + ); +}; + +} // namespace traits + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename GeometryTag, typename Geometry> +struct coordinate_type +{ + typedef typename point_type<GeometryTag, Geometry>::type point_type; + + // Call its own specialization on point-tag + typedef typename coordinate_type<point_tag, point_type>::type type; +}; + +template <typename Point> +struct coordinate_type<point_tag, Point> +{ + typedef typename traits::coordinate_type<Point>::type type; +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + +/*! +\brief \brief_meta{type, coordinate type (int\, float\, double\, etc), \meta_point_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/coordinate_type.qbk]} +*/ +template <typename Geometry> +struct coordinate_type +{ + typedef typename core_dispatch::coordinate_type + < + typename tag<Geometry>::type, + typename boost::remove_const<Geometry>::type + >::type type; +}; + +template <typename Geometry> +struct fp_coordinate_type +{ + typedef typename promote_floating_point + < + typename coordinate_type<Geometry>::type + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_COORDINATE_TYPE_HPP diff --git a/boost/geometry/core/cs.hpp b/boost/geometry/core/cs.hpp new file mode 100644 index 0000000000..3588ed1a86 --- /dev/null +++ b/boost/geometry/core/cs.hpp @@ -0,0 +1,220 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_CS_HPP +#define BOOST_GEOMETRY_CORE_CS_HPP + +#include <cstddef> + +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +/*! +\brief Unit of plane angle: Degrees +\details Tag defining the unit of plane angle for spherical coordinate systems. + This tag specifies that coordinates are defined in degrees (-180 .. 180). + It has to be specified for some coordinate systems. +\qbk{[include reference/core/degree_radian.qbk]} +*/ +struct degree {}; + + +/*! +\brief Unit of plane angle: Radians +\details Tag defining the unit of plane angle for spherical coordinate systems. + This tag specifies that coordinates are defined in radians (-PI .. PI). + It has to be specified for some coordinate systems. +\qbk{[include reference/core/degree_radian.qbk]} +*/ +struct radian {}; + + +namespace cs +{ + +/*! +\brief Cartesian coordinate system +\details Defines the Cartesian or rectangular coordinate system + where points are defined in 2 or 3 (or more) +dimensions and usually (but not always) known as x,y,z +\see http://en.wikipedia.org/wiki/Cartesian_coordinate_system +\ingroup cs +*/ +struct cartesian {}; + + + + +/*! +\brief Geographic coordinate system, in degree or in radian +\details Defines the geographic coordinate system where points + are defined in two angles and usually +known as lat,long or lo,la or phi,lambda +\see http://en.wikipedia.org/wiki/Geographic_coordinate_system +\ingroup cs +\note might be moved to extensions/gis/geographic +*/ +template<typename DegreeOrRadian> +struct geographic +{ + typedef DegreeOrRadian units; +}; + + + +/*! +\brief Spherical (polar) coordinate system, in degree or in radian +\details Defines the spherical coordinate system where points are + defined in two angles + and an optional radius usually known as r, theta, phi +\par Coordinates: +- coordinate 0: + 0 <= phi < 2pi is the angle between the positive x-axis and the + line from the origin to the P projected onto the xy-plane. +- coordinate 1: + 0 <= theta <= pi is the angle between the positive z-axis and the + line formed between the origin and P. +- coordinate 2 (if specified): + r >= 0 is the distance from the origin to a given point P. + +\see http://en.wikipedia.org/wiki/Spherical_coordinates +\ingroup cs +*/ +template<typename DegreeOrRadian> +struct spherical +{ + typedef DegreeOrRadian units; +}; + + +/*! +\brief Spherical equatorial coordinate system, in degree or in radian +\details This one resembles the geographic coordinate system, and has latitude + up from zero at the equator, to 90 at the pole + (opposite to the spherical(polar) coordinate system). + Used in astronomy and in GIS (but there is also the geographic) + +\see http://en.wikipedia.org/wiki/Spherical_coordinates +\ingroup cs +*/ +template<typename DegreeOrRadian> +struct spherical_equatorial +{ + typedef DegreeOrRadian units; +}; + + + +/*! +\brief Polar coordinate system +\details Defines the polar coordinate system "in which each point + on a plane is determined by an angle and a distance" +\see http://en.wikipedia.org/wiki/Polar_coordinates +\ingroup cs +*/ +template<typename DegreeOrRadian> +struct polar +{ + typedef DegreeOrRadian units; +}; + + +} // namespace cs + + +namespace traits +{ + +/*! +\brief Traits class defining coordinate system tag, bound to coordinate system +\ingroup traits +\tparam CoordinateSystem coordinate system +*/ +template <typename CoordinateSystem> +struct cs_tag +{ +}; + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +template<typename DegreeOrRadian> +struct cs_tag<cs::geographic<DegreeOrRadian> > +{ + typedef geographic_tag type; +}; + +template<typename DegreeOrRadian> +struct cs_tag<cs::spherical<DegreeOrRadian> > +{ + typedef spherical_polar_tag type; +}; + +template<typename DegreeOrRadian> +struct cs_tag<cs::spherical_equatorial<DegreeOrRadian> > +{ + typedef spherical_equatorial_tag type; +}; + + +template<> +struct cs_tag<cs::cartesian> +{ + typedef cartesian_tag type; +}; + + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS +} // namespace traits + +/*! +\brief Meta-function returning coordinate system tag (cs family) of any geometry +\ingroup core +*/ +template <typename G> +struct cs_tag +{ + typedef typename traits::cs_tag + < + typename geometry::coordinate_system<G>::type + >::type type; +}; + + +/*! +\brief Meta-function to verify if a coordinate system is radian +\ingroup core +*/ +template <typename CoordinateSystem> +struct is_radian : boost::true_type {}; + + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + +// Specialization for any degree coordinate systems +template <template<typename> class CoordinateSystem> +struct is_radian< CoordinateSystem<degree> > : boost::false_type +{ +}; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_CS_HPP diff --git a/boost/geometry/core/exception.hpp b/boost/geometry/core/exception.hpp new file mode 100644 index 0000000000..97d249e938 --- /dev/null +++ b/boost/geometry/core/exception.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_EXCEPTION_HPP +#define BOOST_GEOMETRY_CORE_EXCEPTION_HPP + +#include <exception> + +namespace boost { namespace geometry +{ + +/*! +\brief Base exception class for Boost.Geometry algorithms +\ingroup core +\details This class is never thrown. All exceptions thrown in Boost.Geometry + are derived from exception, so it might be convenient to catch it. +*/ +class exception : public std::exception +{}; + + +/*! +\brief Empty Input Exception +\ingroup core +\details The empty_input_exception is thrown if free functions, e.g. distance, + are called with empty geometries, e.g. a linestring + without points, a polygon without points, an empty multi-geometry. +\qbk{ +[heading See also] +\* [link geometry.reference.algorithms.area the area function] +\* [link geometry.reference.algorithms.distance the distance function] +\* [link geometry.reference.algorithms.length the length function] +} + */ +class empty_input_exception : public geometry::exception +{ +public: + + inline empty_input_exception() {} + + virtual char const* what() const throw() + { + return "Boost.Geometry Empty-Input exception"; + } +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_EXCEPTION_HPP diff --git a/boost/geometry/core/exterior_ring.hpp b/boost/geometry/core/exterior_ring.hpp new file mode 100644 index 0000000000..70012c22db --- /dev/null +++ b/boost/geometry/core/exterior_ring.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_EXTERIOR_RING_HPP +#define BOOST_GEOMETRY_CORE_EXTERIOR_RING_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> + + +#include <boost/geometry/core/ring_type.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 +{ + +namespace traits +{ + + +/*! + \brief Traits class defining access to exterior_ring of a polygon + \details Should define const and non const access + \ingroup traits + \tparam Polygon the polygon type + \par Geometries: + - polygon + \par Specializations should provide: + - static inline RING& get(POLY& ) + - static inline RING const& get(POLY const& ) +*/ +template <typename Polygon> +struct exterior_ring +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POLYGON_TYPE + , (types<Polygon>) + ); +}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + + +template <typename Tag, typename Geometry> +struct exterior_ring +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +template <typename Polygon> +struct exterior_ring<polygon_tag, Polygon> +{ + static + typename geometry::ring_return_type<Polygon>::type + apply(typename add_const_if_c + < + boost::is_const<Polygon>::type::value, + Polygon + >::type& polygon) + { + return traits::exterior_ring + < + typename boost::remove_const<Polygon>::type + >::get(polygon); + } +}; + + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! + \brief Function to get the exterior_ring ring of a polygon + \ingroup exterior_ring + \note OGC compliance: instead of ExteriorRing + \tparam P polygon type + \param polygon the polygon to get the exterior ring from + \return a reference to the exterior ring +*/ +template <typename Polygon> +inline typename ring_return_type<Polygon>::type exterior_ring(Polygon& polygon) +{ + return core_dispatch::exterior_ring + < + typename tag<Polygon>::type, + Polygon + >::apply(polygon); +} + + +/*! +\brief Function to get the exterior ring of a polygon (const version) +\ingroup exterior_ring +\note OGC compliance: instead of ExteriorRing +\tparam Polygon polygon type +\param polygon the polygon to get the exterior ring from +\return a const reference to the exterior ring + +\qbk{distinguish,const version} +*/ +template <typename Polygon> +inline typename ring_return_type<Polygon const>::type exterior_ring( + Polygon const& polygon) +{ + return core_dispatch::exterior_ring + < + typename tag<Polygon>::type, + Polygon const + >::apply(polygon); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_EXTERIOR_RING_HPP diff --git a/boost/geometry/core/geometry_id.hpp b/boost/geometry/core/geometry_id.hpp new file mode 100644 index 0000000000..369c5cfa1a --- /dev/null +++ b/boost/geometry/core/geometry_id.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_GEOMETRY_ID_HPP +#define BOOST_GEOMETRY_CORE_GEOMETRY_ID_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/mpl/int.hpp> +#include <boost/type_traits.hpp> + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename GeometryTag> +struct geometry_id +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<GeometryTag>) + ); +}; + + +template <> +struct geometry_id<point_tag> : boost::mpl::int_<1> {}; + + +template <> +struct geometry_id<linestring_tag> : boost::mpl::int_<2> {}; + + +template <> +struct geometry_id<polygon_tag> : boost::mpl::int_<3> {}; + + +template <> +struct geometry_id<segment_tag> : boost::mpl::int_<92> {}; + + +template <> +struct geometry_id<ring_tag> : boost::mpl::int_<93> {}; + + +template <> +struct geometry_id<box_tag> : boost::mpl::int_<94> {}; + + + +} // namespace core_dispatch +#endif + + + +/*! +\brief Meta-function returning the id of a geometry type +\details The meta-function geometry_id defines a numerical ID (based on + boost::mpl::int_<...> ) for each geometry concept. A numerical ID is + sometimes useful, and within Boost.Geometry it is used for the + reverse_dispatch metafuntion. +\note Used for e.g. reverse meta-function +\ingroup core +*/ +template <typename Geometry> +struct geometry_id : core_dispatch::geometry_id<typename tag<Geometry>::type> +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_GEOMETRY_ID_HPP diff --git a/boost/geometry/core/interior_rings.hpp b/boost/geometry/core/interior_rings.hpp new file mode 100644 index 0000000000..10af2ae4ee --- /dev/null +++ b/boost/geometry/core/interior_rings.hpp @@ -0,0 +1,139 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_INTERIOR_RINGS_HPP +#define BOOST_GEOMETRY_CORE_INTERIOR_RINGS_HPP + +#include <cstddef> + +#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/interior_type.hpp> + +namespace boost { namespace geometry +{ + +namespace traits +{ + + +/*! + \brief Traits class defining access to interior_rings of a polygon + \details defines access (const and non const) to interior ring + \ingroup traits + \par Geometries: + - polygon + \par Specializations should provide: + - static inline INTERIOR& get(POLY&) + - static inline const INTERIOR& get(POLY const&) + \tparam Geometry geometry +*/ +template <typename Geometry> +struct interior_rings +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +} // namespace traits + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template +< + typename GeometryTag, + typename Geometry +> +struct interior_rings {}; + + +template <typename Polygon> +struct interior_rings<polygon_tag, Polygon> +{ + static inline + typename geometry::interior_return_type<Polygon>::type + apply(Polygon& polygon) + { + return traits::interior_rings + < + typename boost::remove_const<Polygon>::type + >::get(polygon); + } +}; + + +} // namespace core_dispatch +#endif + + + +/*! +\brief Function to get the interior rings of a polygon (non const version) +\ingroup interior_rings +\note OGC compliance: instead of InteriorRingN +\tparam Polygon polygon type +\param polygon the polygon to get the interior rings from +\return the interior rings (possibly a reference) +*/ + +template <typename Polygon> +inline typename interior_return_type<Polygon>::type interior_rings(Polygon& polygon) +{ + return core_dispatch::interior_rings + < + typename tag<Polygon>::type, + Polygon + >::apply(polygon); +} + + +/*! +\brief Function to get the interior rings of a polygon (const version) +\ingroup interior_rings +\note OGC compliance: instead of InteriorRingN +\tparam Polygon polygon type +\param polygon the polygon to get the interior rings from +\return the interior rings (possibly a const reference) + +\qbk{distinguish,const version} +*/ +template <typename Polygon> +inline typename interior_return_type<Polygon const>::type interior_rings( + Polygon const& polygon) +{ + return core_dispatch::interior_rings + < + typename tag<Polygon>::type, + Polygon const + >::apply(polygon); +} + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_INTERIOR_RINGS_HPP diff --git a/boost/geometry/core/interior_type.hpp b/boost/geometry/core/interior_type.hpp new file mode 100644 index 0000000000..02328372f0 --- /dev/null +++ b/boost/geometry/core/interior_type.hpp @@ -0,0 +1,161 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_INTERIOR_TYPE_HPP +#define BOOST_GEOMETRY_CORE_INTERIOR_TYPE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! +\brief Traits class indicating interior container type of a polygon +\details defines inner container type, so the container containing + the interior rings +\ingroup traits +\par Geometries: + - polygon +\par Specializations should provide: + - typedef X type ( e.g. std::vector<myring<P>> ) +\tparam Geometry geometry +*/ +template <typename Geometry> +struct interior_const_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + +template <typename Geometry> +struct interior_mutable_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +} // namespace traits + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + + +template <typename GeometryTag, typename Geometry> +struct interior_return_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +template <typename Polygon> +struct interior_return_type<polygon_tag, Polygon> +{ + typedef typename boost::remove_const<Polygon>::type nc_polygon_type; + + typedef typename mpl::if_ + < + boost::is_const<Polygon>, + typename traits::interior_const_type<nc_polygon_type>::type, + typename traits::interior_mutable_type<nc_polygon_type>::type + >::type type; +}; + + + + +template <typename GeometryTag, typename Geometry> +struct interior_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +template <typename Polygon> +struct interior_type<polygon_tag, Polygon> +{ + typedef typename boost::remove_reference + < + typename interior_return_type<polygon_tag, Polygon>::type + >::type type; +}; + + +} // namespace core_dispatch +#endif + + +/*! +\brief \brief_meta{type, interior_type (container type + of inner rings), \meta_geometry_type} +\details Interior rings should be organized as a container + (std::vector, std::deque, boost::array) with + Boost.Range support. This metafunction defines the type + of the container. +\tparam Geometry A type fullfilling the Polygon or MultiPolygon concept. +\ingroup core + +\qbk{[include reference/core/interior_type.qbk]} +*/ +template <typename Geometry> +struct interior_type +{ + typedef typename core_dispatch::interior_type + < + typename tag<Geometry>::type, + Geometry + >::type type; +}; + +template <typename Geometry> +struct interior_return_type +{ + typedef typename core_dispatch::interior_return_type + < + typename tag<Geometry>::type, + Geometry + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_INTERIOR_TYPE_HPP diff --git a/boost/geometry/core/is_areal.hpp b/boost/geometry/core/is_areal.hpp new file mode 100644 index 0000000000..5ddfa753bc --- /dev/null +++ b/boost/geometry/core/is_areal.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_IS_AREAL_HPP +#define BOOST_GEOMETRY_CORE_IS_AREAL_HPP + + +#include <boost/type_traits.hpp> + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename GeometryTag> struct is_areal : boost::false_type {}; + +template <> struct is_areal<ring_tag> : boost::true_type {}; +template <> struct is_areal<box_tag> : boost::true_type {}; +template <> struct is_areal<polygon_tag> : boost::true_type {}; + + +} // namespace core_dispatch +#endif + + + +/*! + \brief Meta-function defining "true" for areal types (box, (multi)polygon, ring), + \note Used for tag dispatching and meta-function finetuning + \note Also a "ring" has areal properties within Boost.Geometry + \ingroup core +*/ +template <typename Geometry> +struct is_areal : core_dispatch::is_areal<typename tag<Geometry>::type> +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_IS_AREAL_HPP diff --git a/boost/geometry/core/mutable_range.hpp b/boost/geometry/core/mutable_range.hpp new file mode 100644 index 0000000000..9b53e40577 --- /dev/null +++ b/boost/geometry/core/mutable_range.hpp @@ -0,0 +1,98 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_MUTABLE_RANGE_HPP +#define BOOST_GEOMETRY_CORE_MUTABLE_RANGE_HPP + + +#include <cstddef> + +#include <boost/type_traits/remove_reference.hpp> +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + + +namespace traits +{ + +/*! +\brief Metafunction to define the argument passed to the three + traits classes clear, push_back and resize +\ingroup mutable_range + */ +template <typename Range> +struct rvalue_type +{ + typedef typename boost::remove_reference<Range>::type& type; +}; + + +/*! +\brief Traits class to clear a geometry +\ingroup mutable_range + */ +template <typename Range> +struct clear +{ + static inline void apply(typename rvalue_type<Range>::type range) + { + range.clear(); + } +}; + + +/*! +\brief Traits class to append a point to a range (ring, linestring, multi*) +\ingroup mutable_range + */ +template <typename Range> +struct push_back +{ + typedef typename boost::range_value + < + typename boost::remove_reference<Range>::type + >::type item_type; + + static inline void apply(typename rvalue_type<Range>::type range, + item_type const& item) + { + range.push_back(item); + } +}; + + +/*! +\brief Traits class to append a point to a range (ring, linestring, multi*) +\ingroup mutable_range + */ +template <typename Range> +struct resize +{ + static inline void apply(typename rvalue_type<Range>::type range, + std::size_t new_size) + { + range.resize(new_size); + } +}; + + +} // namespace traits + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_MUTABLE_RANGE_HPP diff --git a/boost/geometry/core/point_order.hpp b/boost/geometry/core/point_order.hpp new file mode 100644 index 0000000000..f09086a9d4 --- /dev/null +++ b/boost/geometry/core/point_order.hpp @@ -0,0 +1,162 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_POINT_ORDER_HPP +#define BOOST_GEOMETRY_CORE_POINT_ORDER_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +/*! +\brief Enumerates options for the order of points within polygons +\ingroup enum +\details The enumeration order_selector describes options for the order of + points within a polygon. Polygons can be ordered either clockwise or + counterclockwise. The specific order of a polygon type is defined by the + point_order metafunction. The point_order metafunction defines a value, + which is one of the values enumerated in the order_selector + +\qbk{ +[heading See also] +[link geometry.reference.core.point_order The point_order metafunction] +} +*/ +enum order_selector +{ + /// Points are ordered clockwise + clockwise = 1, + /// Points are ordered counter clockwise + counterclockwise = 2, + /// Points might be stored in any order, algorithms will determine it on the + /// fly (not yet supported) + order_undetermined = 0 +}; + +namespace traits +{ + +/*! +\brief Traits class indicating the order of contained points within a + ring or (multi)polygon, clockwise, counter clockwise or not known. +\ingroup traits +\tparam Ring ring +*/ +template <typename Ring> +struct point_order +{ + static const order_selector value = clockwise; +}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_order +{ + +struct clockwise +{ + static const order_selector value = geometry::clockwise; +}; + + +}} // namespace detail::point_order +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Tag, typename Geometry> +struct point_order +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + +template <typename Point> +struct point_order<point_tag, Point> + : public detail::point_order::clockwise {}; + +template <typename Segment> +struct point_order<segment_tag, Segment> + : public detail::point_order::clockwise {}; + + +template <typename Box> +struct point_order<box_tag, Box> + : public detail::point_order::clockwise {}; + +template <typename LineString> +struct point_order<linestring_tag, LineString> + : public detail::point_order::clockwise {}; + + +template <typename Ring> +struct point_order<ring_tag, Ring> +{ + static const order_selector value + = geometry::traits::point_order<Ring>::value; +}; + +// Specialization for polygon: the order is the order of its rings +template <typename Polygon> +struct point_order<polygon_tag, Polygon> +{ + static const order_selector value = core_dispatch::point_order + < + ring_tag, + typename ring_type<polygon_tag, Polygon>::type + >::value ; +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief \brief_meta{value, point order (clockwise\, counterclockwise), + \meta_geometry_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/point_order.qbk]} +*/ +template <typename Geometry> +struct point_order +{ + static const order_selector value = core_dispatch::point_order + < + typename tag<Geometry>::type, + typename boost::remove_const<Geometry>::type + >::value; +}; + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_POINT_ORDER_HPP diff --git a/boost/geometry/core/point_type.hpp b/boost/geometry/core/point_type.hpp new file mode 100644 index 0000000000..f49a43c56a --- /dev/null +++ b/boost/geometry/core/point_type.hpp @@ -0,0 +1,130 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_POINT_TYPE_HPP +#define BOOST_GEOMETRY_CORE_POINT_TYPE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! +\brief Traits class indicating the type of contained points +\ingroup traits +\par Geometries: + - all geometries except point +\par Specializations should provide: + - typedef P type (where P should fulfil the Point concept) +\tparam Geometry geometry +*/ +template <typename Geometry> +struct point_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE, (types<Geometry>) + ); +}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Tag, typename Geometry> +struct point_type +{ + // Default: call traits to get point type + typedef typename boost::remove_const + < + typename traits::point_type<Geometry>::type + >::type type; +}; + + +// Specialization for point: the point itself +template <typename Point> +struct point_type<point_tag, Point> +{ + typedef Point type; +}; + + +// Specializations for linestring/ring, via boost::range +template <typename Linestring> +struct point_type<linestring_tag, Linestring> +{ + typedef typename boost::range_value<Linestring>::type type; +}; + + +template <typename Ring> +struct point_type<ring_tag, Ring> +{ + typedef typename boost::range_value<Ring>::type type; +}; + + +// Specialization for polygon: the point-type is the point-type of its rings +template <typename Polygon> +struct point_type<polygon_tag, Polygon> +{ + typedef typename point_type + < + ring_tag, + typename ring_type<polygon_tag, Polygon>::type + >::type type; +}; + + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief \brief_meta{type, point_type, \meta_geometry_type} +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/point_type.qbk]} +*/ +template <typename Geometry> +struct point_type +{ + typedef typename boost::remove_const<Geometry>::type ncg; + typedef typename core_dispatch::point_type + < + typename tag<Geometry>::type, + ncg + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_POINT_TYPE_HPP diff --git a/boost/geometry/core/radian_access.hpp b/boost/geometry/core/radian_access.hpp new file mode 100644 index 0000000000..bac77d7bc7 --- /dev/null +++ b/boost/geometry/core/radian_access.hpp @@ -0,0 +1,152 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_RADIAN_ACCESS_HPP +#define BOOST_GEOMETRY_CORE_RADIAN_ACCESS_HPP + + +#include <cstddef> + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_type.hpp> + + +#include <boost/geometry/util/math.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template<std::size_t Dimension, typename Geometry> +struct degree_radian_converter +{ + typedef typename fp_coordinate_type<Geometry>::type coordinate_type; + + static inline coordinate_type get(Geometry const& geometry) + { + return boost::numeric_cast + < + coordinate_type + >(geometry::get<Dimension>(geometry) * geometry::math::d2r); + } + + static inline void set(Geometry& geometry, coordinate_type const& radians) + { + geometry::set<Dimension>(geometry, boost::numeric_cast + < + coordinate_type + >(radians * geometry::math::r2d)); + } + +}; + + +// Default, radian (or any other coordinate system) just works like "get" +template <std::size_t Dimension, typename Geometry, typename DegreeOrRadian> +struct radian_access +{ + typedef typename fp_coordinate_type<Geometry>::type coordinate_type; + + static inline coordinate_type get(Geometry const& geometry) + { + return geometry::get<Dimension>(geometry); + } + + static inline void set(Geometry& geometry, coordinate_type const& radians) + { + geometry::set<Dimension>(geometry, radians); + } +}; + +// Specialize, any "degree" coordinate system will be converted to radian +// but only for dimension 0,1 (so: dimension 2 and heigher are untouched) + +template +< + typename Geometry, + template<typename> class CoordinateSystem +> +struct radian_access<0, Geometry, CoordinateSystem<degree> > + : degree_radian_converter<0, Geometry> +{}; + + +template +< + typename Geometry, + template<typename> class CoordinateSystem +> +struct radian_access<1, Geometry, CoordinateSystem<degree> > + : degree_radian_converter<1, Geometry> +{}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief get coordinate value of a point, result is in Radian +\details Result is in Radian, even if source coordinate system + is in Degrees +\return coordinate value +\ingroup get +\tparam Dimension dimension +\tparam Geometry geometry +\param geometry geometry to get coordinate value from +\note Only applicable to coordinate systems templatized by units, + e.g. spherical or geographic coordinate systems +*/ +template <std::size_t Dimension, typename Geometry> +inline typename fp_coordinate_type<Geometry>::type get_as_radian(Geometry const& geometry) +{ + return detail::radian_access<Dimension, Geometry, + typename coordinate_system<Geometry>::type>::get(geometry); +} + + +/*! +\brief set coordinate value (in radian) to a point +\details Coordinate value will be set correctly, if coordinate system of + point is in Degree, Radian value will be converted to Degree +\ingroup set +\tparam Dimension dimension +\tparam Geometry geometry +\param geometry geometry to assign coordinate to +\param radians coordinate value to assign +\note Only applicable to coordinate systems templatized by units, + e.g. spherical or geographic coordinate systems +*/ +template <std::size_t Dimension, typename Geometry> +inline void set_from_radian(Geometry& geometry, + typename fp_coordinate_type<Geometry>::type const& radians) +{ + detail::radian_access<Dimension, Geometry, + typename coordinate_system<Geometry>::type>::set(geometry, radians); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_RADIAN_ACCESS_HPP diff --git a/boost/geometry/core/reverse_dispatch.hpp b/boost/geometry/core/reverse_dispatch.hpp new file mode 100644 index 0000000000..2e4fb8005f --- /dev/null +++ b/boost/geometry/core/reverse_dispatch.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_REVERSE_DISPATCH_HPP +#define BOOST_GEOMETRY_CORE_REVERSE_DISPATCH_HPP + + +#include <cstddef> + +#include <boost/type_traits.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/greater.hpp> + +#include <boost/geometry/core/geometry_id.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Different geometries: reverse_dispatch if second ID < first ID +template <std::size_t GeometryId1, std::size_t GeometryId2> +struct reverse_dispatch : boost::mpl::if_c + < + (GeometryId1 > GeometryId2), + boost::true_type, + boost::false_type + > +{}; + + +// Same geometry: never reverse_dispatch +template <std::size_t GeometryId> +struct reverse_dispatch<GeometryId, GeometryId> : boost::false_type {}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +template <typename Geometry1, typename Geometry2> +struct reverse_dispatch : detail::reverse_dispatch + < + geometry_id<Geometry1>::type::value, + geometry_id<Geometry2>::type::value + > +{}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_REVERSE_DISPATCH_HPP diff --git a/boost/geometry/core/ring_type.hpp b/boost/geometry/core/ring_type.hpp new file mode 100644 index 0000000000..9b984faf3c --- /dev/null +++ b/boost/geometry/core/ring_type.hpp @@ -0,0 +1,170 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_RING_TYPE_HPP +#define BOOST_GEOMETRY_CORE_RING_TYPE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/remove_const.hpp> + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + + +/*! +\brief Traits class to indicate ring-type of a polygon's exterior ring/interior rings +\ingroup traits +\par Geometries: + - polygon +\par Specializations should provide: + - typedef XXX type ( e.g. ring<P> ) +\tparam Geometry geometry +*/ +template <typename Geometry> +struct ring_const_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + +template <typename Geometry> +struct ring_mutable_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +} // namespace traits + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename GeometryTag, typename Geometry> +struct ring_return_type +{}; + + +template <typename LineString> +struct ring_return_type<linestring_tag, LineString> +{ + typedef LineString& type; +}; + + +template <typename Ring> +struct ring_return_type<ring_tag, Ring> +{ + typedef Ring& type; +}; + + +template <typename Polygon> +struct ring_return_type<polygon_tag, Polygon> +{ + typedef typename boost::remove_const<Polygon>::type nc_polygon_type; + + typedef typename mpl::if_ + < + boost::is_const<Polygon>, + typename traits::ring_const_type<nc_polygon_type>::type, + typename traits::ring_mutable_type<nc_polygon_type>::type + >::type type; +}; + + +template <typename GeometryTag, typename Geometry> +struct ring_type +{}; + + +template <typename Ring> +struct ring_type<ring_tag, Ring> +{ + typedef Ring type; +}; + + +template <typename Polygon> +struct ring_type<polygon_tag, Polygon> +{ + typedef typename boost::remove_reference + < + typename ring_return_type<polygon_tag, Polygon>::type + >::type type; +}; + + + + + +} // namespace core_dispatch +#endif + + +/*! +\brief \brief_meta{type, ring_type, \meta_geometry_type} +\details A polygon contains one exterior ring + and zero or more interior rings (holes). + This metafunction retrieves the type of the rings. + Exterior ring and each of the interior rings all have the same ring_type. +\tparam Geometry A type fullfilling the Ring, Polygon or MultiPolygon concept. +\ingroup core + +\qbk{[include reference/core/ring_type.qbk]} +*/ +template <typename Geometry> +struct ring_type +{ + typedef typename core_dispatch::ring_type + < + typename tag<Geometry>::type, + Geometry + >::type type; +}; + + +template <typename Geometry> +struct ring_return_type +{ + typedef typename core_dispatch::ring_return_type + < + typename tag<Geometry>::type, + Geometry + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_RING_TYPE_HPP diff --git a/boost/geometry/core/tag.hpp b/boost/geometry/core/tag.hpp new file mode 100644 index 0000000000..5a99c97071 --- /dev/null +++ b/boost/geometry/core/tag.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_TAG_HPP +#define BOOST_GEOMETRY_CORE_TAG_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! +\brief Traits class to attach a tag to a geometry +\details All geometries should implement a traits::tag<G>::type metafunction to indicate their + own geometry type. +\ingroup traits +\par Geometries: + - all geometries +\par Specializations should provide: + - typedef XXX_tag type; (point_tag, box_tag, ...) +\tparam Geometry geometry +*/ +template <typename Geometry, typename Enable = void> +struct tag +{ + typedef void type; +}; + +} // namespace traits + + +/*! +\brief \brief_meta{type, tag, \meta_geometry_type} +\details With Boost.Geometry, tags are the driving force of the tag dispatching + mechanism. The tag metafunction is therefore used in every free function. +\tparam Geometry \tparam_geometry +\ingroup core + +\qbk{[include reference/core/tag.qbk]} +*/ +template <typename Geometry> +struct tag +{ + typedef typename traits::tag + < + typename boost::remove_const<Geometry>::type + >::type type; +}; + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_TAG_HPP diff --git a/boost/geometry/core/tag_cast.hpp b/boost/geometry/core/tag_cast.hpp new file mode 100644 index 0000000000..47a2e834f1 --- /dev/null +++ b/boost/geometry/core/tag_cast.hpp @@ -0,0 +1,84 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_TAG_CAST_HPP +#define BOOST_GEOMETRY_CORE_TAG_CAST_HPP + + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +namespace boost { namespace geometry +{ + +/*! +\brief Metafunction defining a type being either the specified tag, or one + of the specified basetags if the type inherits from them. +\details Tags can inherit each other. A multi_point inherits, for example, + both the multi_tag and the pointlike tag. Often behaviour can be shared + between different geometry types. A tag, found by the metafunction tag, + can be casted to a more basic tag, and then dispatched by that tag. +\ingroup core +\tparam Tag The tag to be casted to one of the base tags +\tparam BaseTag First base tag +\tparam BaseTag2 Optional second base tag +\tparam BaseTag3 Optional third base tag +\tparam BaseTag4 Optional fourth base tag +\tparam BaseTag5 Optional fifth base tag +\tparam BaseTag6 Optional sixth base tag +\tparam BaseTag7 Optional seventh base tag + +\qbk{[include reference/core/tag_cast.qbk]} +*/ +template +< + typename Tag, + typename BaseTag, + typename BaseTag2 = void, + typename BaseTag3 = void, + typename BaseTag4 = void, + typename BaseTag5 = void, + typename BaseTag6 = void, + typename BaseTag7 = void +> +struct tag_cast +{ + typedef typename boost::mpl::if_ + < + typename boost::is_base_of<BaseTag, Tag>::type, + BaseTag, + // Try next one in line: + typename tag_cast + < + Tag, BaseTag2, BaseTag3, BaseTag4, + BaseTag5, BaseTag6, BaseTag7, void + >::type + >::type type; +}; + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + +// Specialization for last one +template <typename Tag> +struct tag_cast<Tag, void, void, void, void, void, void, void> +{ + // If not found, take specified tag, so do not cast + typedef Tag type; +}; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_TAG_CAST_HPP diff --git a/boost/geometry/core/tags.hpp b/boost/geometry/core/tags.hpp new file mode 100644 index 0000000000..9272858ed2 --- /dev/null +++ b/boost/geometry/core/tags.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_TAGS_HPP +#define BOOST_GEOMETRY_CORE_TAGS_HPP + + +namespace boost { namespace geometry +{ + +// Tags defining strategies linked to coordinate systems + +/// Tag used for casting spherical/geographic coordinate systems +struct spherical_tag {}; + + +/// Tag indicating Cartesian coordinate system family (cartesian,epsg) +struct cartesian_tag {}; + +/// Tag indicating Spherical polar coordinate system family +struct spherical_polar_tag : spherical_tag {}; + +/// Tag indicating Spherical equatorial coordinate system family +struct spherical_equatorial_tag : spherical_tag {}; + +/// Tag indicating Geographic coordinate system family (geographic) +struct geographic_tag : spherical_tag {}; + + + +// Tags defining tag hierarchy + +/// For single-geometries (point, linestring, polygon, box, ring, segment) +struct single_tag {}; + + +/// For multiple-geometries (multi_point, multi_linestring, multi_polygon) +struct multi_tag {}; + +/// For point-like types (point, multi_point) +struct pointlike_tag {}; + +/// For linear types (linestring, multi-linestring, segment) +struct linear_tag {}; + +/// For areal types (polygon, multi_polygon, box, ring) +struct areal_tag {}; + +// Subset of areal types (polygon, multi_polygon, ring) +struct polygonal_tag : areal_tag {}; + +/// For volume types (also box (?), polyhedron) +struct volumetric_tag {}; + + +// Tags defining geometry types + + +/// "default" tag +struct geometry_not_recognized_tag {}; + +/// OGC Point identifying tag +struct point_tag : single_tag, pointlike_tag {}; + +/// OGC Linestring identifying tag +struct linestring_tag : single_tag, linear_tag {}; + +/// OGC Polygon identifying tag +struct polygon_tag : single_tag, polygonal_tag {}; + +/// Convenience (linear) ring identifying tag +struct ring_tag : single_tag, polygonal_tag {}; + +/// Convenience 2D or 3D box (mbr / aabb) identifying tag +struct box_tag : single_tag, areal_tag {}; + +/// Convenience segment (2-points) identifying tag +struct segment_tag : single_tag, linear_tag {}; + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_CORE_TAGS_HPP diff --git a/boost/geometry/core/topological_dimension.hpp b/boost/geometry/core/topological_dimension.hpp new file mode 100644 index 0000000000..02f1ed341e --- /dev/null +++ b/boost/geometry/core/topological_dimension.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_CORE_TOPOLOGICAL_DIMENSION_HPP +#define BOOST_GEOMETRY_CORE_TOPOLOGICAL_DIMENSION_HPP + + +#include <boost/mpl/int.hpp> + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + + +template <typename GeometryTag> +struct top_dim {}; + + +template <> +struct top_dim<point_tag> : boost::mpl::int_<0> {}; + + +template <> +struct top_dim<linestring_tag> : boost::mpl::int_<1> {}; + + +template <> +struct top_dim<segment_tag> : boost::mpl::int_<1> {}; + + +// ring: topological dimension of two, but some people say: 1 !! +template <> +struct top_dim<ring_tag> : boost::mpl::int_<2> {}; + + +template <> +struct top_dim<box_tag> : boost::mpl::int_<2> {}; + + +template <> +struct top_dim<polygon_tag> : boost::mpl::int_<2> {}; + + + +} // namespace core_dispatch +#endif + + + + + +/*! + \brief Meta-function returning the topological dimension of a geometry + \details The topological dimension defines a point as 0-dimensional, + a linestring as 1-dimensional, + and a ring or polygon as 2-dimensional. + \see http://www.math.okstate.edu/mathdept/dynamics/lecnotes/node36.html + \ingroup core +*/ +template <typename Geometry> +struct topological_dimension + : core_dispatch::top_dim<typename tag<Geometry>::type> {}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_TOPOLOGICAL_DIMENSION_HPP diff --git a/boost/geometry/geometries/adapted/boost_array.hpp b/boost/geometry/geometries/adapted/boost_array.hpp new file mode 100644 index 0000000000..275ccb5c2b --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_array.hpp @@ -0,0 +1,120 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010 Alfredo Correa +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_ARRAY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_ARRAY_HPP + + +#ifdef BOOST_GEOMETRY_ADAPTED_BOOST_ARRAY_TAG_DEFINED +#error Include either "boost_array_as_point" or \ + "boost_array_as_linestring" or "boost_array_as_ring" \ + or "boost_array_as_multi_point" to adapt a boost_array +#endif + +#define BOOST_GEOMETRY_ADAPTED_BOOST_ARRAY_TAG_DEFINED + + +#include <cstddef> + +#include <boost/type_traits/is_arithmetic.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/array.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +// Create class and specialization to indicate the tag +// for normal cases and the case that the type of the c-array is arithmetic +template <bool> +struct boost_array_tag +{ + typedef geometry_not_recognized_tag type; +}; + + +template <> +struct boost_array_tag<true> +{ + typedef point_tag type; +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +// Assign the point-tag, preventing arrays of points getting a point-tag +template <typename CoordinateType, std::size_t DimensionCount> +struct tag<boost::array<CoordinateType, DimensionCount> > + : detail::boost_array_tag<boost::is_arithmetic<CoordinateType>::value> {}; + + +template <typename CoordinateType, std::size_t DimensionCount> +struct coordinate_type<boost::array<CoordinateType, DimensionCount> > +{ + typedef CoordinateType type; +}; + + +template <typename CoordinateType, std::size_t DimensionCount> +struct dimension<boost::array<CoordinateType, DimensionCount> >: boost::mpl::int_<DimensionCount> {}; + + +template <typename CoordinateType, std::size_t DimensionCount, std::size_t Dimension> +struct access<boost::array<CoordinateType, DimensionCount>, Dimension> +{ + static inline CoordinateType get(boost::array<CoordinateType, DimensionCount> const& a) + { + return a[Dimension]; + } + + static inline void set(boost::array<CoordinateType, DimensionCount>& a, + CoordinateType const& value) + { + a[Dimension] = value; + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#define BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CS(CoordinateSystem) \ + namespace boost { namespace geometry { namespace traits { \ + template <class T, std::size_t N> \ + struct coordinate_system<boost::array<T, N> > \ + { \ + typedef CoordinateSystem type; \ + }; \ + }}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_ARRAY_HPP + diff --git a/boost/geometry/geometries/adapted/boost_fusion.hpp b/boost/geometry/geometries/adapted/boost_fusion.hpp new file mode 100644 index 0000000000..a9aba916a5 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_fusion.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 Akira Takahashi +// Copyright (c) 2011-2012 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_GEOMETRIES_ADAPTED_FUSION_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_FUSION_HPP + + +#include <cstddef> + +#include <boost/fusion/include/is_sequence.hpp> +#include <boost/fusion/include/size.hpp> +#include <boost/fusion/include/tag_of.hpp> +#include <boost/fusion/include/front.hpp> +#include <boost/fusion/include/at.hpp> +#include <boost/utility/enable_if.hpp> + +#include <boost/fusion/mpl.hpp> +#include <boost/mpl/front.hpp> +#include <boost/mpl/count_if.hpp> +#include <boost/mpl/pop_front.hpp> +#include <boost/mpl/size.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/front.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace fusion_adapt_detail +{ + +template <class Sequence> +struct all_same : + boost::mpl::bool_< + boost::mpl::count_if< + Sequence, + boost::is_same< + typename boost::mpl::front<Sequence>::type, + boost::mpl::_ + > + >::value == boost::mpl::size<Sequence>::value + > +{}; + +template <class Sequence> +struct is_coordinate_size : boost::mpl::bool_< + boost::fusion::result_of::size<Sequence>::value == 2 || + boost::fusion::result_of::size<Sequence>::value == 3> {}; + +template<typename Sequence> +struct is_fusion_sequence + : mpl::and_<boost::fusion::traits::is_sequence<Sequence>, + fusion_adapt_detail::is_coordinate_size<Sequence>, + fusion_adapt_detail::all_same<Sequence> > +{}; + + +} // namespace fusion_adapt_detail + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +// Boost Fusion Sequence, 2D or 3D +template <typename Sequence> +struct coordinate_type + < + Sequence, + typename boost::enable_if + < + fusion_adapt_detail::is_fusion_sequence<Sequence> + >::type + > +{ + typedef typename boost::mpl::front<Sequence>::type type; +}; + + +template <typename Sequence> +struct dimension + < + Sequence, + typename boost::enable_if + < + fusion_adapt_detail::is_fusion_sequence<Sequence> + >::type + > : boost::mpl::size<Sequence> +{}; + + +template <typename Sequence, std::size_t Dimension> +struct access + < + Sequence, + Dimension, + typename boost::enable_if + < + fusion_adapt_detail::is_fusion_sequence<Sequence> + >::type + > +{ + typedef typename coordinate_type<Sequence>::type ctype; + + static inline ctype get(Sequence const& point) + { + return boost::fusion::at_c<Dimension>(point); + } + + template <class CoordinateType> + static inline void set(Sequence& point, CoordinateType const& value) + { + boost::fusion::at_c<Dimension>(point) = value; + } +}; + + +template <typename Sequence> +struct tag + < + Sequence, + typename boost::enable_if + < + fusion_adapt_detail::is_fusion_sequence<Sequence> + >::type + > +{ + typedef point_tag type; +}; + + +} // namespace traits + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +// Convenience registration macro to bind a Fusion sequence to a CS +#define BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(CoordinateSystem) \ + namespace boost { namespace geometry { namespace traits { \ + template <typename Sequence> \ + struct coordinate_system \ + < \ + Sequence, \ + typename boost::enable_if \ + < \ + fusion_adapt_detail::is_fusion_sequence<Sequence> \ + >::type \ + > \ + { typedef CoordinateSystem type; }; \ + }}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_FUSION_HPP diff --git a/boost/geometry/geometries/adapted/boost_polygon.hpp b/boost/geometry/geometries/adapted/boost_polygon.hpp new file mode 100644 index 0000000000..fed2362b6e --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon.hpp @@ -0,0 +1,18 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HPP + +#include <boost/geometry/geometries/adapted/boost_polygon/point.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/box.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/ring.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/polygon.hpp> + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HPP + diff --git a/boost/geometry/geometries/adapted/boost_polygon/box.hpp b/boost/geometry/geometries/adapted/boost_polygon/box.hpp new file mode 100644 index 0000000000..87c3b60650 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/box.hpp @@ -0,0 +1,141 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_BOX_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_BOX_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::rectangle_data -> boost::geometry::box + + +#include <boost/polygon/polygon.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +template <typename CoordinateType> +struct tag<boost::polygon::rectangle_data<CoordinateType> > +{ + typedef box_tag type; +}; + + +template <typename CoordinateType> +struct point_type<boost::polygon::rectangle_data<CoordinateType> > +{ + // Not sure what to do here. Boost.Polygon's rectangle does NOT define its + // point_type (but uses it...) + typedef boost::polygon::point_data<CoordinateType> type; +}; + + +template <typename CoordinateType> +struct indexed_access +< + boost::polygon::rectangle_data<CoordinateType>, + min_corner, 0 +> +{ + typedef boost::polygon::rectangle_data<CoordinateType> box_type; + + static inline CoordinateType get(box_type const& b) + { + return boost::polygon::xl(b); + } + + static inline void set(box_type& b, CoordinateType const& value) + { + boost::polygon::xl(b, value); + } +}; + + +template <typename CoordinateType> +struct indexed_access +< + boost::polygon::rectangle_data<CoordinateType>, + min_corner, 1 +> +{ + typedef boost::polygon::rectangle_data<CoordinateType> box_type; + + static inline CoordinateType get(box_type const& b) + { + return boost::polygon::yl(b); + } + + static inline void set(box_type& b, CoordinateType const& value) + { + boost::polygon::yl(b, value); + } +}; + + +template <typename CoordinateType> +struct indexed_access +< + boost::polygon::rectangle_data<CoordinateType>, + max_corner, 0 +> +{ + typedef boost::polygon::rectangle_data<CoordinateType> box_type; + + static inline CoordinateType get(box_type const& b) + { + return boost::polygon::xh(b); + } + + static inline void set(box_type& b, CoordinateType const& value) + { + boost::polygon::xh(b, value); + } +}; + + +template <typename CoordinateType> +struct indexed_access +< + boost::polygon::rectangle_data<CoordinateType>, + max_corner, 1 +> +{ + typedef boost::polygon::rectangle_data<CoordinateType> box_type; + + static inline CoordinateType get(box_type const& b) + { + return boost::polygon::yh(b); + } + + static inline void set(box_type& b, CoordinateType const& value) + { + boost::polygon::yh(b, value); + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_BOX_HPP diff --git a/boost/geometry/geometries/adapted/boost_polygon/hole_iterator.hpp b/boost/geometry/geometries/adapted/boost_polygon/hole_iterator.hpp new file mode 100644 index 0000000000..c9c1bc7b61 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/hole_iterator.hpp @@ -0,0 +1,84 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLE_ITERATOR_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLE_ITERATOR_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::polygon_with_holes_data -> boost::geometry::polygon +// hole_iterator -> returning ring_proxy's instead of normal polygon_data + +#include <boost/polygon/polygon.hpp> + +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> + + +namespace boost { namespace geometry +{ + +namespace adapt { namespace bp +{ + + +template <typename Polygon, typename RingProxy> +class hole_iterator + : public ::boost::iterator_facade + < + hole_iterator<Polygon, RingProxy>, + RingProxy, // value type + boost::forward_traversal_tag, + RingProxy // reference type + > +{ +public : + typedef typename boost::polygon::polygon_with_holes_traits + < + Polygon + >::iterator_holes_type ith_type; + + explicit inline hole_iterator(Polygon& polygon, ith_type const it) + : m_polygon(polygon) + , m_base(it) + { + } + + typedef std::ptrdiff_t difference_type; + +private: + friend class boost::iterator_core_access; + + inline RingProxy dereference() const + { + return RingProxy(m_polygon, this->m_base); + } + + inline void increment() { ++m_base; } + inline void decrement() { --m_base; } + inline void advance(difference_type n) + { + for (int i = 0; i < n; i++) + { + ++m_base; + } + } + + inline bool equal(hole_iterator<Polygon, RingProxy> const& other) const + { + return this->m_base == other.m_base; + } + + Polygon& m_polygon; + ith_type m_base; +}; + + +}}}} + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLE_ITERATOR_HPP + diff --git a/boost/geometry/geometries/adapted/boost_polygon/holes_proxy.hpp b/boost/geometry/geometries/adapted/boost_polygon/holes_proxy.hpp new file mode 100644 index 0000000000..c2a6a44dba --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/holes_proxy.hpp @@ -0,0 +1,204 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLES_PROXY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLES_PROXY_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::polygon_with_holes_data -> boost::geometry::polygon +// pair{begin_holes, begin_holes} -> interior_proxy + +#include <boost/polygon/polygon.hpp> + +#include <boost/geometry/geometries/adapted/boost_polygon/hole_iterator.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp> + + +namespace boost { namespace geometry +{ + +namespace adapt { namespace bp +{ + + +// Polygon should implement the boost::polygon::polygon_with_holes_concept +// Specify constness in the template parameter if necessary +template<typename Polygon> +struct holes_proxy +{ + typedef ring_proxy + < + typename boost::mpl::if_ + < + typename boost::is_const<Polygon>, + Polygon const, + Polygon + >::type + > proxy_type; + typedef hole_iterator<Polygon, proxy_type> iterator_type; + + // The next line does not work probably because coordinate_type is part of the + // polygon_traits, but not of the polygon_with_holes_traits + // typedef typename boost::polygon::polygon_traits<Polygon>::coordinate_type coordinate_type; + + // So we use: + typedef typename Polygon::coordinate_type coordinate_type; + + inline holes_proxy(Polygon& p) + : polygon(p) + {} + + inline void clear() + { + Polygon empty; + // Clear the holes + polygon.set_holes + ( + boost::polygon::begin_holes(empty), + boost::polygon::end_holes(empty) + ); + } + + inline void resize(std::size_t new_size) + { + std::vector<boost::polygon::polygon_data<coordinate_type> > temporary_copy + ( + boost::polygon::begin_holes(polygon), + boost::polygon::end_holes(polygon) + ); + temporary_copy.resize(new_size); + polygon.set_holes(temporary_copy.begin(), temporary_copy.end()); + } + + template <typename Ring> + inline void push_back(Ring const& ring) + { + std::vector<boost::polygon::polygon_data<coordinate_type> > temporary_copy + ( + boost::polygon::begin_holes(polygon), + boost::polygon::end_holes(polygon) + ); + boost::polygon::polygon_data<coordinate_type> added; + boost::polygon::set_points(added, ring.begin(), ring.end()); + temporary_copy.push_back(added); + polygon.set_holes(temporary_copy.begin(), temporary_copy.end()); + } + + + Polygon& polygon; +}; + + +// Support holes_proxy for Boost.Range ADP + +// Const versions +template<typename Polygon> +inline typename boost::geometry::adapt::bp::holes_proxy<Polygon const>::iterator_type + range_begin(boost::geometry::adapt::bp::holes_proxy<Polygon const> const& proxy) +{ + typename boost::geometry::adapt::bp::holes_proxy<Polygon const>::iterator_type + begin(proxy.polygon, boost::polygon::begin_holes(proxy.polygon)); + return begin; +} + +template<typename Polygon> +inline typename boost::geometry::adapt::bp::holes_proxy<Polygon const>::iterator_type + range_end(boost::geometry::adapt::bp::holes_proxy<Polygon const> const& proxy) +{ + typename boost::geometry::adapt::bp::holes_proxy<Polygon const>::iterator_type + end(proxy.polygon, boost::polygon::end_holes(proxy.polygon)); + return end; +} + +// Mutable versions +template<typename Polygon> +inline typename boost::geometry::adapt::bp::holes_proxy<Polygon>::iterator_type + range_begin(boost::geometry::adapt::bp::holes_proxy<Polygon>& proxy) +{ + typename boost::geometry::adapt::bp::holes_proxy<Polygon>::iterator_type + begin(proxy.polygon, boost::polygon::begin_holes(proxy.polygon)); + return begin; +} + +template<typename Polygon> +inline typename boost::geometry::adapt::bp::holes_proxy<Polygon>::iterator_type + range_end(boost::geometry::adapt::bp::holes_proxy<Polygon>& proxy) +{ + typename boost::geometry::adapt::bp::holes_proxy<Polygon>::iterator_type + end(proxy.polygon, boost::polygon::end_holes(proxy.polygon)); + return end; +} + + +}} + +namespace traits +{ + +template <typename Polygon> +struct rvalue_type<adapt::bp::holes_proxy<Polygon> > +{ + typedef adapt::bp::holes_proxy<Polygon> type; +}; + + +template <typename Polygon> +struct clear<adapt::bp::holes_proxy<Polygon> > +{ + static inline void apply(adapt::bp::holes_proxy<Polygon> proxy) + { + proxy.clear(); + } +}; + +template <typename Polygon> +struct resize<adapt::bp::holes_proxy<Polygon> > +{ + static inline void apply(adapt::bp::holes_proxy<Polygon> proxy, std::size_t new_size) + { + proxy.resize(new_size); + } +}; + +template <typename Polygon> +struct push_back<adapt::bp::holes_proxy<Polygon> > +{ + template <typename Ring> + static inline void apply(adapt::bp::holes_proxy<Polygon> proxy, Ring const& ring) + { + proxy.push_back(ring); + } +}; + + + +} // namespace traits + + +}} + + +// Specialize holes_proxy for Boost.Range +namespace boost +{ + template<typename Polygon> + struct range_mutable_iterator<geometry::adapt::bp::holes_proxy<Polygon> > + { + typedef typename geometry::adapt::bp::holes_proxy<Polygon>::iterator_type type; + }; + + template<typename Polygon> + struct range_const_iterator<geometry::adapt::bp::holes_proxy<Polygon> > + { + typedef typename geometry::adapt::bp::holes_proxy<Polygon const>::iterator_type type; + }; + +} // namespace boost + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_HOLES_PROXY_HPP diff --git a/boost/geometry/geometries/adapted/boost_polygon/point.hpp b/boost/geometry/geometries/adapted/boost_polygon/point.hpp new file mode 100644 index 0000000000..2aabb5663c --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/point.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_POINT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_POINT_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::point_data -> boost::geometry::point + + +#include <boost/polygon/polygon.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +template <typename CoordinateType> +struct tag<boost::polygon::point_data<CoordinateType> > +{ + typedef point_tag type; +}; + + +template <typename CoordinateType> +struct coordinate_type<boost::polygon::point_data<CoordinateType> > +{ + typedef CoordinateType type; +}; + + +template <typename CoordinateType> +struct coordinate_system<boost::polygon::point_data<CoordinateType> > +{ + typedef cs::cartesian type; +}; + + +template <typename CoordinateType> +struct dimension<boost::polygon::point_data<CoordinateType> > + : boost::mpl::int_<2> +{}; + + +template <typename CoordinateType> +struct access<boost::polygon::point_data<CoordinateType>, 0> +{ + typedef boost::polygon::point_data<CoordinateType> point_type; + + static inline CoordinateType get(point_type const& p) + { + return p.x(); + } + + static inline void set(point_type& p, CoordinateType const& value) + { + p.x(value); + } +}; + + +template <typename CoordinateType> +struct access<boost::polygon::point_data<CoordinateType>, 1> +{ + typedef boost::polygon::point_data<CoordinateType> point_type; + + static inline CoordinateType get(point_type const& p) + { + return p.y(); + } + + static inline void set(point_type& p, CoordinateType const& value) + { + p.y(value); + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_POINT_HPP diff --git a/boost/geometry/geometries/adapted/boost_polygon/polygon.hpp b/boost/geometry/geometries/adapted/boost_polygon/polygon.hpp new file mode 100644 index 0000000000..5703601e05 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/polygon.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_POLYGON_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_POLYGON_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::polygon_with_holes_data -> boost::geometry::polygon + +#include <boost/polygon/polygon.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/adapted/boost_polygon/ring_proxy.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/hole_iterator.hpp> +#include <boost/geometry/geometries/adapted/boost_polygon/holes_proxy.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename CoordinateType> +struct tag<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef polygon_tag type; +}; + +template <typename CoordinateType> +struct ring_const_type<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef adapt::bp::ring_proxy<boost::polygon::polygon_with_holes_data<CoordinateType> const> type; +}; + +template <typename CoordinateType> +struct ring_mutable_type<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef adapt::bp::ring_proxy<boost::polygon::polygon_with_holes_data<CoordinateType> > type; +}; + +template <typename CoordinateType> +struct interior_const_type<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef adapt::bp::holes_proxy<boost::polygon::polygon_with_holes_data<CoordinateType> const> type; +}; + +template <typename CoordinateType> +struct interior_mutable_type<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef adapt::bp::holes_proxy<boost::polygon::polygon_with_holes_data<CoordinateType> > type; +}; + + +template <typename CoordinateType> +struct exterior_ring<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef boost::polygon::polygon_with_holes_data<CoordinateType> polygon_type; + typedef adapt::bp::ring_proxy<polygon_type> proxy; + typedef adapt::bp::ring_proxy<polygon_type const> const_proxy; + + static inline proxy get(polygon_type& p) + { + return proxy(p); + } + + static inline const_proxy get(polygon_type const& p) + { + return const_proxy(p); + } +}; + +template <typename CoordinateType> +struct interior_rings<boost::polygon::polygon_with_holes_data<CoordinateType> > +{ + typedef boost::polygon::polygon_with_holes_data<CoordinateType> polygon_type; + typedef adapt::bp::holes_proxy<polygon_type> proxy; + typedef adapt::bp::holes_proxy<polygon_type const> const_proxy; + + static inline proxy get(polygon_type& p) + { + return proxy(p); + } + + static inline const_proxy get(polygon_type const& p) + { + return const_proxy(p); + } +}; + + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_POLYGON_HPP + diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp new file mode 100644 index 0000000000..93b21fee94 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp @@ -0,0 +1,163 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::polygon_data -> boost::geometry::ring + +#include <cstddef> +#include <boost/polygon/polygon.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/core/tags.hpp> + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template <typename CoordinateType> +struct tag<boost::polygon::polygon_data<CoordinateType> > +{ + typedef ring_tag type; +}; + +template <typename CoordinateType> +struct clear<boost::polygon::polygon_data<CoordinateType> > +{ + static inline void apply(boost::polygon::polygon_data<CoordinateType>& data) + { + // There is no "clear" function but we can assign + // a newly (and therefore empty) constructed polygon + boost::polygon::assign(data, boost::polygon::polygon_data<CoordinateType>()); + } +}; + +template <typename CoordinateType> +struct push_back<boost::polygon::polygon_data<CoordinateType> > +{ + typedef boost::polygon::point_data<CoordinateType> point_type; + + static inline void apply(boost::polygon::polygon_data<CoordinateType>& data, + point_type const& point) + { + // Boost.Polygon's polygons are not appendable. So create a temporary vector, + // add a record and set it to the original. Of course: this is not efficient. + // But there seems no other way (without using a wrapper) + std::vector<point_type> temporary_vector + ( + boost::polygon::begin_points(data), + boost::polygon::end_points(data) + ); + temporary_vector.push_back(point); + data.set(temporary_vector.begin(), temporary_vector.end()); + } +}; + + + + +} // namespace traits + +}} // namespace boost::geometry + + +// Adapt Boost.Polygon's polygon_data to Boost.Range +// This just translates to +// polygon_data.begin() and polygon_data.end() +namespace boost +{ + template<typename CoordinateType> + struct range_mutable_iterator<boost::polygon::polygon_data<CoordinateType> > + { + typedef typename boost::polygon::polygon_traits + < + boost::polygon::polygon_data<CoordinateType> + >::iterator_type type; + }; + + template<typename CoordinateType> + struct range_const_iterator<boost::polygon::polygon_data<CoordinateType> > + { + typedef typename boost::polygon::polygon_traits + < + boost::polygon::polygon_data<CoordinateType> + >::iterator_type type; + }; + + template<typename CoordinateType> + struct range_size<boost::polygon::polygon_data<CoordinateType> > + { + typedef std::size_t type; + }; + +} // namespace boost + + +// Support Boost.Polygon's polygon_data for Boost.Range ADP +namespace boost { namespace polygon +{ + +template<typename CoordinateType> +inline typename polygon_traits + < + polygon_data<CoordinateType> + >::iterator_type range_begin(polygon_data<CoordinateType>& polygon) +{ + return polygon.begin(); +} + +template<typename CoordinateType> +inline typename polygon_traits + < + polygon_data<CoordinateType> + >::iterator_type range_begin(polygon_data<CoordinateType> const& polygon) +{ + return polygon.begin(); +} + +template<typename CoordinateType> +inline typename polygon_traits + < + polygon_data<CoordinateType> + >::iterator_type range_end(polygon_data<CoordinateType>& polygon) +{ + return polygon.end(); +} + +template<typename CoordinateType> +inline typename polygon_traits + < + polygon_data<CoordinateType> + >::iterator_type range_end(polygon_data<CoordinateType> const& polygon) +{ + return polygon.end(); +} + +template<typename CoordinateType> +inline std::size_t range_calculate_size(polygon_data<CoordinateType> const& polygon) +{ + return polygon.size(); +} + +}} + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_HPP diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp new file mode 100644 index 0000000000..825ef8061f --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp @@ -0,0 +1,301 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP + +// Adapts Geometries from Boost.Polygon for usage in Boost.Geometry +// boost::polygon::polygon_with_holes_data -> boost::geometry::polygon +// pair{begin_points, end_points} -> ring_proxy + +#include <boost/polygon/polygon.hpp> +#include <boost/range.hpp> + + + +namespace boost { namespace geometry +{ + +namespace adapt { namespace bp +{ + +namespace detail +{ + +template <bool Mutable> +struct modify +{}; + +template <> +struct modify<true> +{ + template <typename Ring, typename Point> + static inline void push_back(Ring& ring, Point const& point) + { + // Boost.Polygon's polygons are not appendable. So create a temporary vector, + // add a record and set it to the original. Of course: this is not efficient. + // But there seems no other way (without using a wrapper) + std::vector<Point> temporary_vector + ( + boost::polygon::begin_points(ring), + boost::polygon::end_points(ring) + ); + temporary_vector.push_back(point); + boost::polygon::set_points(ring, temporary_vector.begin(), temporary_vector.end()); + } + +}; + +template <> +struct modify<false> +{ + template <typename Ring, typename Point> + static inline void push_back(Ring& ring, Point const& point) + { + } + +}; + + +} + + +// Polygon should implement the boost::polygon::polygon_with_holes_concept +// Specify constness in the template parameter if necessary +template<typename Polygon> +class ring_proxy +{ +public : + typedef typename boost::polygon::polygon_traits + < + typename boost::remove_const<Polygon>::type + >::iterator_type iterator_type; + + typedef typename boost::polygon::polygon_with_holes_traits + < + typename boost::remove_const<Polygon>::type + >::iterator_holes_type hole_iterator_type; + + static const bool is_mutable = !boost::is_const<Polygon>::type::value; + + inline ring_proxy(Polygon& p) + : m_polygon_pointer(&p) + , m_do_hole(false) + {} + + // Constructor used from hole_iterator + inline ring_proxy(Polygon& p, hole_iterator_type hole_it) + : m_polygon_pointer(&p) + , m_do_hole(true) + , m_hole_it(hole_it) + {} + + // Default constructor, for mutable polygons / appending (interior) rings + inline ring_proxy() + : m_polygon_pointer(&m_polygon_for_default_constructor) + , m_do_hole(false) + {} + + + iterator_type begin() const + { + return m_do_hole + ? boost::polygon::begin_points(*m_hole_it) + : boost::polygon::begin_points(*m_polygon_pointer) + ; + } + + iterator_type begin() + { + return m_do_hole + ? boost::polygon::begin_points(*m_hole_it) + : boost::polygon::begin_points(*m_polygon_pointer) + ; + } + + iterator_type end() const + { + return m_do_hole + ? boost::polygon::end_points(*m_hole_it) + : boost::polygon::end_points(*m_polygon_pointer) + ; + } + + iterator_type end() + { + return m_do_hole + ? boost::polygon::end_points(*m_hole_it) + : boost::polygon::end_points(*m_polygon_pointer) + ; + } + + // Mutable + void clear() + { + Polygon p; + if (m_do_hole) + { + // Does NOT work see comment above + } + else + { + boost::polygon::set_points(*m_polygon_pointer, + boost::polygon::begin_points(p), + boost::polygon::end_points(p)); + } + } + + void resize(std::size_t new_size) + { + if (m_do_hole) + { + // Does NOT work see comment above + } + else + { + // TODO: implement this by resizing the container + } + } + + + + template <typename Point> + void push_back(Point const& point) + { + if (m_do_hole) + { + //detail::modify<is_mutable>::push_back(*m_hole_it, point); + //std::cout << "HOLE: " << typeid(*m_hole_it).name() << std::endl; + //std::cout << "HOLE: " << typeid(m_hole_it).name() << std::endl; + //std::cout << "HOLE: " << typeid(hole_iterator_type).name() << std::endl; + + // Note, ths does NOT work because hole_iterator_type is defined + // as a const_iterator by Boost.Polygon + + } + else + { + detail::modify<is_mutable>::push_back(*m_polygon_pointer, point); + } + } + +private : + Polygon* m_polygon_pointer; + bool m_do_hole; + hole_iterator_type m_hole_it; + + Polygon m_polygon_for_default_constructor; +}; + + + + +// Support geometry::adapt::bp::ring_proxy for Boost.Range ADP +template<typename Polygon> +inline typename boost::geometry::adapt::bp::ring_proxy<Polygon>::iterator_type + range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon>& proxy) +{ + return proxy.begin(); +} + +template<typename Polygon> +inline typename boost::geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type + range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon const> const& proxy) +{ + return proxy.begin(); +} + +template<typename Polygon> +inline typename boost::geometry::adapt::bp::ring_proxy<Polygon>::iterator_type + range_end(boost::geometry::adapt::bp::ring_proxy<Polygon>& proxy) +{ + return proxy.end(); +} + +template<typename Polygon> +inline typename boost::geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type + range_end(boost::geometry::adapt::bp::ring_proxy<Polygon const> const& proxy) +{ + return proxy.end(); +} + + + + +}} // namespace adapt::bp + + +namespace traits +{ + +template <typename Polygon> +struct tag<adapt::bp::ring_proxy<Polygon> > +{ + typedef ring_tag type; +}; + + +template <typename Polygon> +struct rvalue_type<adapt::bp::ring_proxy<Polygon> > +{ + typedef adapt::bp::ring_proxy<Polygon> type; +}; + +template <typename Polygon> +struct clear<adapt::bp::ring_proxy<Polygon> > +{ + static inline void apply(adapt::bp::ring_proxy<Polygon> proxy) + { + proxy.clear(); + } +}; + + +template <typename Polygon> +struct resize<adapt::bp::ring_proxy<Polygon> > +{ + static inline void apply(adapt::bp::ring_proxy<Polygon> proxy, std::size_t new_size) + { + proxy.resize(new_size); + } +}; + +template <typename Polygon> +struct push_back<adapt::bp::ring_proxy<Polygon> > +{ + static inline void apply(adapt::bp::ring_proxy<Polygon> proxy, + typename boost::polygon::polygon_traits<Polygon>::point_type const& point) + { + proxy.push_back(point); + } +}; + + +} // namespace traits + +}} // namespace boost::geometry + +// Specialize ring_proxy for Boost.Range +namespace boost +{ + template<typename Polygon> + struct range_mutable_iterator<geometry::adapt::bp::ring_proxy<Polygon> > + { + typedef typename geometry::adapt::bp::ring_proxy<Polygon>::iterator_type type; + }; + + template<typename Polygon> + struct range_const_iterator<geometry::adapt::bp::ring_proxy<Polygon> > + { + typedef typename geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type type; + }; + +} // namespace boost + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP diff --git a/boost/geometry/geometries/adapted/boost_range/adjacent_filtered.hpp b/boost/geometry/geometries/adapted/boost_range/adjacent_filtered.hpp new file mode 100644 index 0000000000..496dbeaec6 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/adjacent_filtered.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_ADJACENT_FILTERED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_ADJACENT_FILTERED_HPP + + +#include <boost/range/adaptor/adjacent_filtered.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Filter, typename Geometry, bool DefaultPass> +#if BOOST_VERSION > 104500 +struct tag<boost::adjacent_filtered_range<Filter, Geometry, DefaultPass> > +#else +struct tag<boost::range_detail::adjacent_filter_range<Filter, Geometry, DefaultPass> > +#endif +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_ADJACENT_FILTERED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_range/filtered.hpp b/boost/geometry/geometries/adapted/boost_range/filtered.hpp new file mode 100644 index 0000000000..990d608460 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/filtered.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_FILTERED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_FILTERED_HPP + + +#include <boost/range/adaptor/filtered.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Filter, typename Geometry> +#if BOOST_VERSION > 104500 +struct tag<boost::filtered_range<Filter, Geometry> > +#else +struct tag<boost::range_detail::filter_range<Filter, Geometry> > +#endif +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_FILTERED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_range/reversed.hpp b/boost/geometry/geometries/adapted/boost_range/reversed.hpp new file mode 100644 index 0000000000..3c8601fe19 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/reversed.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_REVERSED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_REVERSED_HPP + + +#include <boost/range/adaptor/reversed.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Geometry> +#if BOOST_VERSION > 104500 +struct tag<boost::reversed_range<Geometry> > +#else +struct tag<boost::range_detail::reverse_range<Geometry> > +#endif +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_REVERSED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_range/sliced.hpp b/boost/geometry/geometries/adapted/boost_range/sliced.hpp new file mode 100644 index 0000000000..70189819ca --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/sliced.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_SLICED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_SLICED_HPP + + +#include <boost/range/adaptor/sliced.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Geometry> +struct tag<boost::adaptors::sliced_range<Geometry> > +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_SLICED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_range/strided.hpp b/boost/geometry/geometries/adapted/boost_range/strided.hpp new file mode 100644 index 0000000000..5c9cdd6a82 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/strided.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_STRIDED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_STRIDED_HPP + + +#include <boost/range/adaptor/strided.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Geometry> +struct tag<boost::strided_range<Geometry> > +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_STRIDED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_range/uniqued.hpp b/boost/geometry/geometries/adapted/boost_range/uniqued.hpp new file mode 100644 index 0000000000..beb51fe0b8 --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_range/uniqued.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2010-2012 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_GEOMETRIES_ADAPTED_BOOST_RANGE_UNIQUED_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_UNIQUED_HPP + + +#include <boost/range/adaptor/uniqued.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +template<typename Geometry> +#if BOOST_VERSION > 104500 +struct tag<boost::uniqued_range<Geometry> > +#else +struct tag<boost::range_detail::unique_range<Geometry> > +#endif +{ + typedef typename geometry::tag<Geometry>::type type; +}; + +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_RANGE_UNIQUED_HPP + diff --git a/boost/geometry/geometries/adapted/boost_tuple.hpp b/boost/geometry/geometries/adapted/boost_tuple.hpp new file mode 100644 index 0000000000..58065fe9af --- /dev/null +++ b/boost/geometry/geometries/adapted/boost_tuple.hpp @@ -0,0 +1,109 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_ADAPTED_BOOST_TUPLE_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_TUPLE_HPP + + +#include <cstddef> + +#include <boost/tuple/tuple.hpp> + +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, typename T10> +struct tag<boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> > +{ + typedef point_tag type; +}; + + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, typename T10> +struct coordinate_type<boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> > +{ + typedef T1 type; +}; + + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, typename T10> +struct dimension<boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> > + : boost::mpl::int_ + < + boost::tuples::length + < + boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> + >::value + > +{}; + + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, typename T10, + std::size_t Dimension> +struct access + < + boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, + Dimension + > +{ + static inline T1 get( + boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> const& point) + { + return point.template get<Dimension>(); + } + + static inline void set( + boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& point, + T1 const& value) + { + point.template get<Dimension>() = value; + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +// Convenience registration macro to bind boost::tuple to a CS +#define BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(CoordinateSystem) \ + namespace boost { namespace geometry { namespace traits { \ + template <typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6, typename T7, typename T8, typename T9, typename T10> \ + struct coordinate_system<boost::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> > \ + { \ + typedef CoordinateSystem type; \ + }; \ + }}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_TUPLE_HPP diff --git a/boost/geometry/geometries/adapted/c_array.hpp b/boost/geometry/geometries/adapted/c_array.hpp new file mode 100644 index 0000000000..1b4523d969 --- /dev/null +++ b/boost/geometry/geometries/adapted/c_array.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_ADAPTED_C_ARRAY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_C_ARRAY_HPP + +#include <cstddef> + +#include <boost/type_traits/is_arithmetic.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +// Create class and specialization to indicate the tag +// for normal cases and the case that the type of the c-array is arithmetic +template <bool> +struct c_array_tag +{ + typedef geometry_not_recognized_tag type; +}; + + +template <> +struct c_array_tag<true> +{ + typedef point_tag type; +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +// Assign the point-tag, preventing arrays of points getting a point-tag +template <typename CoordinateType, std::size_t DimensionCount> +struct tag<CoordinateType[DimensionCount]> + : detail::c_array_tag<boost::is_arithmetic<CoordinateType>::value> {}; + + +template <typename CoordinateType, std::size_t DimensionCount> +struct coordinate_type<CoordinateType[DimensionCount]> +{ + typedef CoordinateType type; +}; + + +template <typename CoordinateType, std::size_t DimensionCount> +struct dimension<CoordinateType[DimensionCount]>: boost::mpl::int_<DimensionCount> {}; + + +template <typename CoordinateType, std::size_t DimensionCount, std::size_t Dimension> +struct access<CoordinateType[DimensionCount], Dimension> +{ + static inline CoordinateType get(CoordinateType const p[DimensionCount]) + { + return p[Dimension]; + } + + static inline void set(CoordinateType p[DimensionCount], + CoordinateType const& value) + { + p[Dimension] = value; + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#define BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(CoordinateSystem) \ + namespace boost { namespace geometry { namespace traits { \ + template <typename T, std::size_t N> \ + struct coordinate_system<T[N]> \ + { \ + typedef CoordinateSystem type; \ + }; \ + }}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_C_ARRAY_HPP diff --git a/boost/geometry/geometries/adapted/std_pair_as_segment.hpp b/boost/geometry/geometries/adapted/std_pair_as_segment.hpp new file mode 100644 index 0000000000..e9200e0fd0 --- /dev/null +++ b/boost/geometry/geometries/adapted/std_pair_as_segment.hpp @@ -0,0 +1,98 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_ADAPTED_STD_PAIR_AS_SEGMENT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_STD_PAIR_AS_SEGMENT_HPP + +// Only possible if the std::pair is not used for iterator/pair +// (maybe it is possible to avoid that by detecting in the other file +// if an iterator was used in the pair) + +#ifdef BOOST_GEOMETRY_ADAPTED_STD_RANGE_TAG_DEFINED +#error Include only one headerfile to register tag for adapted std:: containers or iterator pair +#endif + +#define BOOST_GEOMETRY_ADAPTED_STD_RANGE_TAG_DEFINED + + +#include <cstddef> + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +template <typename Point> +struct tag<std::pair<Point, Point> > +{ + typedef segment_tag type; +}; + +template <typename Point> +struct point_type<std::pair<Point, Point> > +{ + typedef Point type; +}; + +template <typename Point, std::size_t Dimension> +struct indexed_access<std::pair<Point, Point>, 0, Dimension> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + static inline coordinate_type get(std::pair<Point, Point> const& s) + { + return geometry::get<Dimension>(s.first); + } + + static inline void set(std::pair<Point, Point>& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.first, value); + } +}; + + +template <typename Point, std::size_t Dimension> +struct indexed_access<std::pair<Point, Point>, 1, Dimension> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + static inline coordinate_type get(std::pair<Point, Point> const& s) + { + return geometry::get<Dimension>(s.second); + } + + static inline void set(std::pair<Point, Point>& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.second, value); + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_STD_PAIR_AS_SEGMENT_HPP diff --git a/boost/geometry/geometries/box.hpp b/boost/geometry/geometries/box.hpp new file mode 100644 index 0000000000..a2e3d4fd79 --- /dev/null +++ b/boost/geometry/geometries/box.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_BOX_HPP +#define BOOST_GEOMETRY_GEOMETRIES_BOX_HPP + +#include <cstddef> + +#include <boost/concept/assert.hpp> + +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + + +namespace boost { namespace geometry +{ + +namespace model +{ + + +/*! + \brief Class box: defines a box made of two describing points + \ingroup geometries + \details Box is always described by a min_corner() and a max_corner() point. If another + rectangle is used, use linear_ring or polygon. + \note Boxes are for selections and for calculating the envelope of geometries. Not all algorithms + are implemented for box. Boxes are also used in Spatial Indexes. + \tparam Point point type. The box takes a point type as template parameter. + The point type can be any point type. + It can be 2D but can also be 3D or more dimensional. + The box can also take a latlong point type as template parameter. + */ + +template<typename Point> +class box +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + +public: + + inline box() {} + + /*! + \brief Constructor taking the minimum corner point and the maximum corner point + */ + inline box(Point const& min_corner, Point const& max_corner) + { + geometry::convert(min_corner, m_min_corner); + geometry::convert(max_corner, m_max_corner); + } + + inline Point const& min_corner() const { return m_min_corner; } + inline Point const& max_corner() const { return m_max_corner; } + + inline Point& min_corner() { return m_min_corner; } + inline Point& max_corner() { return m_max_corner; } + +private: + + Point m_min_corner; + Point m_max_corner; +}; + + +} // namespace model + + +// Traits specializations for box above +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename Point> +struct tag<model::box<Point> > +{ + typedef box_tag type; +}; + +template <typename Point> +struct point_type<model::box<Point> > +{ + typedef Point type; +}; + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::box<Point>, min_corner, Dimension> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + static inline coordinate_type get(model::box<Point> const& b) + { + return geometry::get<Dimension>(b.min_corner()); + } + + static inline void set(model::box<Point>& b, coordinate_type const& value) + { + geometry::set<Dimension>(b.min_corner(), value); + } +}; + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::box<Point>, max_corner, Dimension> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + static inline coordinate_type get(model::box<Point> const& b) + { + return geometry::get<Dimension>(b.max_corner()); + } + + static inline void set(model::box<Point>& b, coordinate_type const& value) + { + geometry::set<Dimension>(b.max_corner(), value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_BOX_HPP diff --git a/boost/geometry/geometries/concepts/box_concept.hpp b/boost/geometry/geometries/concepts/box_concept.hpp new file mode 100644 index 0000000000..ea0d84cf31 --- /dev/null +++ b/boost/geometry/geometries/concepts/box_concept.hpp @@ -0,0 +1,136 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_BOX_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_BOX_CONCEPT_HPP + + +#include <cstddef> + +#include <boost/concept_check.hpp> + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/point_type.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief Box concept +\ingroup concepts +\par Formal definition: +The box concept is defined as following: +- there must be a specialization of traits::tag defining box_tag as type +- there must be a specialization of traits::point_type to define the + underlying point type (even if it does not consist of points, it should define + this type, to indicate the points it can work with) +- there must be a specialization of traits::indexed_access, per index + (min_corner, max_corner) and per dimension, with two functions: + - get to get a coordinate value + - set to set a coordinate value (this one is not checked for ConstBox) +*/ +template <typename Geometry> +class Box +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + + template + < + std::size_t Index, + std::size_t Dimension, + std::size_t DimensionCount + > + struct dimension_checker + { + static void apply() + { + Geometry* b = 0; + geometry::set<Index, Dimension>(*b, geometry::get<Index, Dimension>(*b)); + dimension_checker<Index, Dimension + 1, DimensionCount>::apply(); + } + }; + + template <std::size_t Index, std::size_t DimensionCount> + struct dimension_checker<Index, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public : + BOOST_CONCEPT_USAGE(Box) + { + static const std::size_t n = dimension<Geometry>::type::value; + dimension_checker<min_corner, 0, n>::apply(); + dimension_checker<max_corner, 0, n>::apply(); + } +#endif +}; + + +/*! +\brief Box concept (const version) +\ingroup const_concepts +\details The ConstBox concept apply the same as the Box concept, +but does not apply write access. +*/ +template <typename Geometry> +class ConstBox +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + typedef typename coordinate_type<Geometry>::type coordinate_type; + + template + < + std::size_t Index, + std::size_t Dimension, + std::size_t DimensionCount + > + struct dimension_checker + { + static void apply() + { + const Geometry* b = 0; + coordinate_type coord(geometry::get<Index, Dimension>(*b)); + boost::ignore_unused_variable_warning(coord); + dimension_checker<Index, Dimension + 1, DimensionCount>::apply(); + } + }; + + template <std::size_t Index, std::size_t DimensionCount> + struct dimension_checker<Index, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public : + BOOST_CONCEPT_USAGE(ConstBox) + { + static const std::size_t n = dimension<Geometry>::type::value; + dimension_checker<min_corner, 0, n>::apply(); + dimension_checker<max_corner, 0, n>::apply(); + } +#endif +}; + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_BOX_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/check.hpp b/boost/geometry/geometries/concepts/check.hpp new file mode 100644 index 0000000000..f8001f0d12 --- /dev/null +++ b/boost/geometry/geometries/concepts/check.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_CHECK_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_CHECK_HPP + + +#include <boost/concept_check.hpp> +#include <boost/concept/requires.hpp> + +#include <boost/type_traits/is_const.hpp> + +#include <boost/geometry/core/tag.hpp> + +#include <boost/geometry/geometries/concepts/box_concept.hpp> +#include <boost/geometry/geometries/concepts/linestring_concept.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/concepts/polygon_concept.hpp> +#include <boost/geometry/geometries/concepts/ring_concept.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace concept_check +{ + +template <typename Concept> +class check +{ + BOOST_CONCEPT_ASSERT((Concept )); +}; + +}} // namespace detail::concept_check +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename GeometryTag, typename Geometry, bool IsConst> +struct check +{}; + + +template <typename Geometry> +struct check<point_tag, Geometry, true> + : detail::concept_check::check<concept::ConstPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<point_tag, Geometry, false> + : detail::concept_check::check<concept::Point<Geometry> > +{}; + + +template <typename Geometry> +struct check<linestring_tag, Geometry, true> + : detail::concept_check::check<concept::ConstLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<linestring_tag, Geometry, false> + : detail::concept_check::check<concept::Linestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<polygon_tag, Geometry, true> + : detail::concept_check::check<concept::ConstPolygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<polygon_tag, Geometry, false> + : detail::concept_check::check<concept::Polygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<box_tag, Geometry, true> + : detail::concept_check::check<concept::ConstBox<Geometry> > +{}; + + +template <typename Geometry> +struct check<box_tag, Geometry, false> + : detail::concept_check::check<concept::Box<Geometry> > +{}; + + + +} // namespace dispatch +#endif + + + + +namespace concept +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename Geometry, bool IsConst> +struct checker : dispatch::check + < + typename tag<Geometry>::type, + Geometry, + IsConst + > +{}; + + +} +#endif // DOXYGEN_NO_DETAIL + + +/*! + \brief Checks, in compile-time, the concept of any geometry + \ingroup concepts +*/ +template <typename Geometry> +inline void check() +{ + detail::checker<Geometry, boost::is_const<Geometry>::type::value> c; + boost::ignore_unused_variable_warning(c); +} + + +/*! + \brief Checks, in compile-time, the concept of two geometries, and if they + have equal dimensions + \ingroup concepts +*/ +template <typename Geometry1, typename Geometry2> +inline void check_concepts_and_equal_dimensions() +{ + check<Geometry1>(); + check<Geometry2>(); + assert_dimension_equal<Geometry1, Geometry2>(); +} + + +} // namespace concept + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_CHECK_HPP diff --git a/boost/geometry/geometries/concepts/linestring_concept.hpp b/boost/geometry/geometries/concepts/linestring_concept.hpp new file mode 100644 index 0000000000..091336fe30 --- /dev/null +++ b/boost/geometry/geometries/concepts/linestring_concept.hpp @@ -0,0 +1,125 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_LINESTRING_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_LINESTRING_CONCEPT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief Linestring concept +\ingroup concepts +\par Formal definition: +The linestring concept is defined as following: +- there must be a specialization of traits::tag defining linestring_tag as type +- it must behave like a Boost.Range +- it must implement a std::back_insert_iterator + - either by implementing push_back + - or by specializing std::back_insert_iterator + +\note to fulfill the concepts, no traits class has to be specialized to +define the point type. + +\par Example: + +A custom linestring, defining the necessary specializations to fulfill to the concept. + +Suppose that the following linestring is defined: +\dontinclude doxygen_5.cpp +\skip custom_linestring1 +\until }; + +It can then be adapted to the concept as following: +\dontinclude doxygen_5.cpp +\skip adapt custom_linestring1 +\until }} + +\note +- There is also the registration macro BOOST_GEOMETRY_REGISTER_LINESTRING +- For registration of std::vector<P> (and deque, and list) it is enough to +include the header-file geometries/adapted/std_as_linestring.hpp. That registers +a vector as a linestring (so it cannot be registered as a linear ring then, +in the same source code). + + +*/ + +template <typename Geometry> +class Linestring +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + +public : + + BOOST_CONCEPT_USAGE(Linestring) + { + Geometry* ls = 0; + traits::clear<Geometry>::apply(*ls); + traits::resize<Geometry>::apply(*ls, 0); + point_type* point = 0; + traits::push_back<Geometry>::apply(*ls, *point); + } +#endif +}; + + +/*! +\brief Linestring concept (const version) +\ingroup const_concepts +\details The ConstLinestring concept check the same as the Linestring concept, +but does not check write access. +*/ +template <typename Geometry> +class ConstLinestring +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) ); + //BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + // Relaxed the concept. + BOOST_CONCEPT_ASSERT( (boost::ForwardRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(ConstLinestring) + { + } +#endif +}; + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_LINESTRING_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/point_concept.hpp b/boost/geometry/geometries/concepts/point_concept.hpp new file mode 100644 index 0000000000..1e1b31e61f --- /dev/null +++ b/boost/geometry/geometries/concepts/point_concept.hpp @@ -0,0 +1,176 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_POINT_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POINT_CONCEPT_HPP + +#include <cstddef> + +#include <boost/concept_check.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_system.hpp> + + + + +namespace boost { namespace geometry { namespace concept +{ + +/*! +\brief Point concept. +\ingroup concepts + +\par Formal definition: +The point concept is defined as following: +- there must be a specialization of traits::tag defining point_tag as type +- there must be a specialization of traits::coordinate_type defining the type + of its coordinates +- there must be a specialization of traits::coordinate_system defining its + coordinate system (cartesian, spherical, etc) +- there must be a specialization of traits::dimension defining its number + of dimensions (2, 3, ...) (derive it conveniently + from boost::mpl::int_<X> for X-D) +- there must be a specialization of traits::access, per dimension, + with two functions: + - \b get to get a coordinate value + - \b set to set a coordinate value (this one is not checked for ConstPoint) + +\par Example: + +A legacy point, defining the necessary specializations to fulfil to the concept. + +Suppose that the following point is defined: +\dontinclude doxygen_5.cpp +\skip legacy_point1 +\until }; + +It can then be adapted to the concept as following: +\dontinclude doxygen_5.cpp +\skip adapt legacy_point1 +\until }} + +Note that it is done like above to show the system. Users will normally use the registration macro. + +\par Example: + +A read-only legacy point, using a macro to fulfil to the ConstPoint concept. +It cannot be modified by the library but can be used in all algorithms where +points are not modified. + +The point looks like the following: + +\dontinclude doxygen_5.cpp +\skip legacy_point2 +\until }; + +It uses the macro as following: +\dontinclude doxygen_5.cpp +\skip adapt legacy_point2 +\until end adaptation + +*/ + +template <typename Geometry> +class Point +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + typedef typename coordinate_type<Geometry>::type ctype; + typedef typename coordinate_system<Geometry>::type csystem; + + enum { ccount = dimension<Geometry>::value }; + + + template <typename P, std::size_t Dimension, std::size_t DimensionCount> + struct dimension_checker + { + static void apply() + { + P* p = 0; + geometry::set<Dimension>(*p, geometry::get<Dimension>(*p)); + dimension_checker<P, Dimension+1, DimensionCount>::apply(); + } + }; + + + template <typename P, std::size_t DimensionCount> + struct dimension_checker<P, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public: + + /// BCCL macro to apply the Point concept + BOOST_CONCEPT_USAGE(Point) + { + dimension_checker<Geometry, 0, ccount>::apply(); + } +#endif +}; + + +/*! +\brief point concept (const version). + +\ingroup const_concepts + +\details The ConstPoint concept apply the same as the Point concept, +but does not apply write access. + +*/ +template <typename Geometry> +class ConstPoint +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + typedef typename coordinate_type<Geometry>::type ctype; + typedef typename coordinate_system<Geometry>::type csystem; + + enum { ccount = dimension<Geometry>::value }; + + + template <typename P, std::size_t Dimension, std::size_t DimensionCount> + struct dimension_checker + { + static void apply() + { + const P* p = 0; + ctype coord(geometry::get<Dimension>(*p)); + boost::ignore_unused_variable_warning(coord); + dimension_checker<P, Dimension+1, DimensionCount>::apply(); + } + }; + + + template <typename P, std::size_t DimensionCount> + struct dimension_checker<P, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public: + + /// BCCL macro to apply the ConstPoint concept + BOOST_CONCEPT_USAGE(ConstPoint) + { + dimension_checker<Geometry, 0, ccount>::apply(); + } +#endif +}; + +}}} // namespace boost::geometry::concept + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POINT_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/polygon_concept.hpp b/boost/geometry/geometries/concepts/polygon_concept.hpp new file mode 100644 index 0000000000..b478a2274e --- /dev/null +++ b/boost/geometry/geometries/concepts/polygon_concept.hpp @@ -0,0 +1,135 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_POLYGON_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POLYGON_CONCEPT_HPP + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.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/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/concepts/ring_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + +/*! +\brief Checks polygon concept +\ingroup concepts +*/ +template <typename PolygonType> +class Polygon +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::remove_const<PolygonType>::type polygon_type; + + typedef typename traits::ring_const_type<polygon_type>::type ring_const_type; + typedef typename traits::ring_mutable_type<polygon_type>::type ring_mutable_type; + typedef typename traits::interior_const_type<polygon_type>::type interior_const_type; + typedef typename traits::interior_mutable_type<polygon_type>::type interior_mutable_type; + + typedef typename point_type<PolygonType>::type point_type; + typedef typename ring_type<PolygonType>::type ring_type; + + BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + BOOST_CONCEPT_ASSERT( (concept::Ring<ring_type>) ); + + //BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<interior_type>) ); + + struct checker + { + static inline void apply() + { + polygon_type* poly = 0; + polygon_type const* cpoly = poly; + + ring_mutable_type e = traits::exterior_ring<PolygonType>::get(*poly); + interior_mutable_type i = traits::interior_rings<PolygonType>::get(*poly); + ring_const_type ce = traits::exterior_ring<PolygonType>::get(*cpoly); + interior_const_type ci = traits::interior_rings<PolygonType>::get(*cpoly); + + boost::ignore_unused_variable_warning(e); + boost::ignore_unused_variable_warning(i); + boost::ignore_unused_variable_warning(ce); + boost::ignore_unused_variable_warning(ci); + boost::ignore_unused_variable_warning(poly); + boost::ignore_unused_variable_warning(cpoly); + } + }; + +public: + + BOOST_CONCEPT_USAGE(Polygon) + { + checker::apply(); + } +#endif +}; + + +/*! +\brief Checks polygon concept (const version) +\ingroup const_concepts +*/ +template <typename PolygonType> +class ConstPolygon +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + typedef typename boost::remove_const<PolygonType>::type const_polygon_type; + + typedef typename traits::ring_const_type<const_polygon_type>::type ring_const_type; + typedef typename traits::interior_const_type<const_polygon_type>::type interior_const_type; + + typedef typename point_type<const_polygon_type>::type point_type; + typedef typename ring_type<const_polygon_type>::type ring_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstRing<ring_type>) ); + + ////BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<interior_type>) ); + + struct checker + { + static inline void apply() + { + const_polygon_type const* cpoly = 0; + + ring_const_type ce = traits::exterior_ring<const_polygon_type>::get(*cpoly); + interior_const_type ci = traits::interior_rings<const_polygon_type>::get(*cpoly); + + boost::ignore_unused_variable_warning(ce); + boost::ignore_unused_variable_warning(ci); + boost::ignore_unused_variable_warning(cpoly); + } + }; + +public: + + BOOST_CONCEPT_USAGE(ConstPolygon) + { + checker::apply(); + } +#endif +}; + +}}} // namespace boost::geometry::concept + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POLYGON_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/ring_concept.hpp b/boost/geometry/geometries/concepts/ring_concept.hpp new file mode 100644 index 0000000000..02a36c96f1 --- /dev/null +++ b/boost/geometry/geometries/concepts/ring_concept.hpp @@ -0,0 +1,99 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_RING_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_RING_CONCEPT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief ring concept +\ingroup concepts +\par Formal definition: +The ring concept is defined as following: +- there must be a specialization of traits::tag defining ring_tag as type +- it must behave like a Boost.Range +- there can optionally be a specialization of traits::point_order defining the + order or orientation of its points, clockwise or counterclockwise. +- it must implement a std::back_insert_iterator + (This is the same as the for the concept Linestring, and described there) + +\note to fulfill the concepts, no traits class has to be specialized to +define the point type. +*/ +template <typename Geometry> +class Ring +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + +public : + + BOOST_CONCEPT_USAGE(Ring) + { + Geometry* ring = 0; + traits::clear<Geometry>::apply(*ring); + traits::resize<Geometry>::apply(*ring, 0); + point_type* point = 0; + traits::push_back<Geometry>::apply(*ring, *point); + } +#endif +}; + + +/*! +\brief (linear) ring concept (const version) +\ingroup const_concepts +\details The ConstLinearRing concept check the same as the Geometry concept, +but does not check write access. +*/ +template <typename Geometry> +class ConstRing +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(ConstRing) + { + } +#endif +}; + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_RING_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/segment_concept.hpp b/boost/geometry/geometries/concepts/segment_concept.hpp new file mode 100644 index 0000000000..8d2d300153 --- /dev/null +++ b/boost/geometry/geometries/concepts/segment_concept.hpp @@ -0,0 +1,135 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_GEOMETRIES_CONCEPTS_SEGMENT_CONCEPT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_SEGMENT_CONCEPT_HPP + + +#include <boost/concept_check.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/point_type.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief Segment concept. +\ingroup concepts +\details Formal definition: +The segment concept is defined as following: +- there must be a specialization of traits::tag defining segment_tag as type +- there must be a specialization of traits::point_type to define the + underlying point type (even if it does not consist of points, it should define + this type, to indicate the points it can work with) +- there must be a specialization of traits::indexed_access, per index + and per dimension, with two functions: + - get to get a coordinate value + - set to set a coordinate value (this one is not checked for ConstSegment) + +\note The segment concept is similar to the box concept, defining another tag. +However, the box concept assumes the index as min_corner, max_corner, while +for the segment concept there is no assumption. +*/ +template <typename Geometry> +class Segment +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + + + template <size_t Index, size_t Dimension, size_t DimensionCount> + struct dimension_checker + { + static void apply() + { + Geometry* s = 0; + geometry::set<Index, Dimension>(*s, geometry::get<Index, Dimension>(*s)); + dimension_checker<Index, Dimension + 1, DimensionCount>::apply(); + } + }; + + template <size_t Index, size_t DimensionCount> + struct dimension_checker<Index, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public : + + BOOST_CONCEPT_USAGE(Segment) + { + static const size_t n = dimension<point_type>::type::value; + dimension_checker<0, 0, n>::apply(); + dimension_checker<1, 0, n>::apply(); + } +#endif +}; + + +/*! +\brief Segment concept (const version). +\ingroup const_concepts +\details The ConstSegment concept verifies the same as the Segment concept, +but does not verify write access. +*/ +template <typename Geometry> +class ConstSegment +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename point_type<Geometry>::type point_type; + typedef typename coordinate_type<Geometry>::type coordinate_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) ); + + + template <size_t Index, size_t Dimension, size_t DimensionCount> + struct dimension_checker + { + static void apply() + { + const Geometry* s = 0; + coordinate_type coord(geometry::get<Index, Dimension>(*s)); + boost::ignore_unused_variable_warning(coord); + dimension_checker<Index, Dimension + 1, DimensionCount>::apply(); + } + }; + + template <size_t Index, size_t DimensionCount> + struct dimension_checker<Index, DimensionCount, DimensionCount> + { + static void apply() {} + }; + +public : + + BOOST_CONCEPT_USAGE(ConstSegment) + { + static const size_t n = dimension<point_type>::type::value; + dimension_checker<0, 0, n>::apply(); + dimension_checker<1, 0, n>::apply(); + } +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_SEGMENT_CONCEPT_HPP diff --git a/boost/geometry/geometries/geometries.hpp b/boost/geometry/geometries/geometries.hpp new file mode 100644 index 0000000000..cda55c1d28 --- /dev/null +++ b/boost/geometry/geometries/geometries.hpp @@ -0,0 +1,25 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_HPP +#define BOOST_GEOMETRY_GEOMETRIES_HPP + +#include <boost/geometry/geometries/point.hpp> +#include <boost/geometry/geometries/linestring.hpp> +#include <boost/geometry/geometries/polygon.hpp> + +#include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/geometries/ring.hpp> +#include <boost/geometry/geometries/segment.hpp> + +#endif // BOOST_GEOMETRY_GEOMETRIES_HPP diff --git a/boost/geometry/geometries/linestring.hpp b/boost/geometry/geometries/linestring.hpp new file mode 100644 index 0000000000..38bc3d4c49 --- /dev/null +++ b/boost/geometry/geometries/linestring.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_LINESTRING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_LINESTRING_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + +namespace boost { namespace geometry +{ + +namespace model +{ + +/*! +\brief A linestring (named so by OGC) is a collection (default a vector) of points. +\ingroup geometries +\tparam Point \tparam_point +\tparam Container \tparam_container +\tparam Allocator \tparam_allocator + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_linestring Linestring Concept] +} + +*/ +template +< + typename Point, + template<typename,typename> class Container = std::vector, + template<typename> class Allocator = std::allocator +> +class linestring : public Container<Point, Allocator<Point> > +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + typedef Container<Point, Allocator<Point> > base_type; + +public : + /// \constructor_default{linestring} + inline linestring() + : base_type() + {} + + /// \constructor_begin_end{linestring} + template <typename Iterator> + inline linestring(Iterator begin, Iterator end) + : base_type(begin, end) + {} +}; + +} // namespace model + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + template<typename,typename> class Container, + template<typename> class Allocator +> +struct tag<model::linestring<Point, Container, Allocator> > +{ + typedef linestring_tag type; +}; +} // namespace traits + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_LINESTRING_HPP diff --git a/boost/geometry/geometries/point.hpp b/boost/geometry/geometries/point.hpp new file mode 100644 index 0000000000..b40a47355d --- /dev/null +++ b/boost/geometry/geometries/point.hpp @@ -0,0 +1,178 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_POINT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_POINT_HPP + +#include <cstddef> + +#include <boost/mpl/int.hpp> +#include <boost/static_assert.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/util/math.hpp> + +namespace boost { namespace geometry +{ + + +namespace model +{ + +/*! +\brief Basic point class, having coordinates defined in a neutral way +\details Defines a neutral point class, fulfilling the Point Concept. + Library users can use this point class, or use their own point classes. + This point class is used in most of the samples and tests of Boost.Geometry + This point class is used occasionally within the library, where a temporary + point class is necessary. +\ingroup geometries +\tparam CoordinateType \tparam_numeric +\tparam DimensionCount number of coordinates, usually 2 or 3 +\tparam CoordinateSystem coordinate system, for example cs::cartesian + +\qbk{[include reference/geometries/point.qbk]} +\qbk{before.synopsis, [heading Model of]} +\qbk{before.synopsis, [link geometry.reference.concepts.concept_point Point Concept]} + + +*/ +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem +> +class point +{ +public: + + /// @brief Default constructor, no initialization + inline point() + {} + + /// @brief Constructor to set one, two or three values + inline point(CoordinateType const& v0, CoordinateType const& v1 = 0, CoordinateType const& v2 = 0) + { + if (DimensionCount >= 1) m_values[0] = v0; + if (DimensionCount >= 2) m_values[1] = v1; + if (DimensionCount >= 3) m_values[2] = v2; + } + + /// @brief Get a coordinate + /// @tparam K coordinate to get + /// @return the coordinate + template <std::size_t K> + inline CoordinateType const& get() const + { + BOOST_STATIC_ASSERT(K < DimensionCount); + return m_values[K]; + } + + /// @brief Set a coordinate + /// @tparam K coordinate to set + /// @param value value to set + template <std::size_t K> + inline void set(CoordinateType const& value) + { + BOOST_STATIC_ASSERT(K < DimensionCount); + m_values[K] = value; + } + +private: + + CoordinateType m_values[DimensionCount]; +}; + + +} // namespace model + +// Adapt the point to the concept +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem +> +struct tag<model::point<CoordinateType, DimensionCount, CoordinateSystem> > +{ + typedef point_tag type; +}; + +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem +> +struct coordinate_type<model::point<CoordinateType, DimensionCount, CoordinateSystem> > +{ + typedef CoordinateType type; +}; + +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem +> +struct coordinate_system<model::point<CoordinateType, DimensionCount, CoordinateSystem> > +{ + typedef CoordinateSystem type; +}; + +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem +> +struct dimension<model::point<CoordinateType, DimensionCount, CoordinateSystem> > + : boost::mpl::int_<DimensionCount> +{}; + +template +< + typename CoordinateType, + std::size_t DimensionCount, + typename CoordinateSystem, + std::size_t Dimension +> +struct access<model::point<CoordinateType, DimensionCount, CoordinateSystem>, Dimension> +{ + static inline CoordinateType get( + model::point<CoordinateType, DimensionCount, CoordinateSystem> const& p) + { + return p.template get<Dimension>(); + } + + static inline void set( + model::point<CoordinateType, DimensionCount, CoordinateSystem>& p, + CoordinateType const& value) + { + p.template set<Dimension>(value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_POINT_HPP diff --git a/boost/geometry/geometries/point_xy.hpp b/boost/geometry/geometries/point_xy.hpp new file mode 100644 index 0000000000..652930666f --- /dev/null +++ b/boost/geometry/geometries/point_xy.hpp @@ -0,0 +1,128 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_POINT_XY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_POINT_XY_HPP + +#include <cstddef> + +#include <boost/mpl/int.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/geometries/point.hpp> + +namespace boost { namespace geometry +{ + +namespace model { namespace d2 +{ + +/*! +\brief 2D point in Cartesian coordinate system +\tparam CoordinateType numeric type, for example, double, float, int +\tparam CoordinateSystem coordinate system, defaults to cs::cartesian + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_point Point Concept] +} + +\qbk{[include reference/geometries/point_assign_warning.qbk]} + +*/ +template<typename CoordinateType, typename CoordinateSystem = cs::cartesian> +class point_xy : public model::point<CoordinateType, 2, CoordinateSystem> +{ +public: + + /// Default constructor, does not initialize anything + inline point_xy() + : model::point<CoordinateType, 2, CoordinateSystem>() + {} + + /// Constructor with x/y values + inline point_xy(CoordinateType const& x, CoordinateType const& y) + : model::point<CoordinateType, 2, CoordinateSystem>(x, y) + {} + + /// Get x-value + inline CoordinateType const& x() const + { return this->template get<0>(); } + + /// Get y-value + inline CoordinateType const& y() const + { return this->template get<1>(); } + + /// Set x-value + inline void x(CoordinateType const& v) + { this->template set<0>(v); } + + /// Set y-value + inline void y(CoordinateType const& v) + { this->template set<1>(v); } +}; + + +}} // namespace model::d2 + + +// Adapt the point_xy to the concept +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename CoordinateType, typename CoordinateSystem> +struct tag<model::d2::point_xy<CoordinateType, CoordinateSystem> > +{ + typedef point_tag type; +}; + +template<typename CoordinateType, typename CoordinateSystem> +struct coordinate_type<model::d2::point_xy<CoordinateType, CoordinateSystem> > +{ + typedef CoordinateType type; +}; + +template<typename CoordinateType, typename CoordinateSystem> +struct coordinate_system<model::d2::point_xy<CoordinateType, CoordinateSystem> > +{ + typedef CoordinateSystem type; +}; + +template<typename CoordinateType, typename CoordinateSystem> +struct dimension<model::d2::point_xy<CoordinateType, CoordinateSystem> > + : boost::mpl::int_<2> +{}; + +template<typename CoordinateType, typename CoordinateSystem, std::size_t Dimension> +struct access<model::d2::point_xy<CoordinateType, CoordinateSystem>, Dimension > +{ + static inline CoordinateType get( + model::d2::point_xy<CoordinateType, CoordinateSystem> const& p) + { + return p.template get<Dimension>(); + } + + static inline void set(model::d2::point_xy<CoordinateType, CoordinateSystem>& p, + CoordinateType const& value) + { + p.template set<Dimension>(value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_POINT_XY_HPP diff --git a/boost/geometry/geometries/polygon.hpp b/boost/geometry/geometries/polygon.hpp new file mode 100644 index 0000000000..ec8d1ec38f --- /dev/null +++ b/boost/geometry/geometries/polygon.hpp @@ -0,0 +1,319 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_POLYGON_HPP +#define BOOST_GEOMETRY_GEOMETRIES_POLYGON_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/assert.hpp> + +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/ring.hpp> + +namespace boost { namespace geometry +{ + +namespace model +{ + +/*! +\brief The polygon contains an outer ring and zero or more inner rings. +\ingroup geometries +\tparam Point point type +\tparam ClockWise true for clockwise direction, + false for CounterClockWise direction +\tparam Closed true for closed polygons (last point == first point), + false open points +\tparam PointList container type for points, + for example std::vector, std::list, std::deque +\tparam RingList container type for inner rings, + for example std::vector, std::list, std::deque +\tparam PointAlloc container-allocator-type, for the points +\tparam RingAlloc container-allocator-type, for the rings +\note The container collecting the points in the rings can be different + from the container collecting the inner rings. They all default to vector. + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_polygon Polygon Concept] +} + + +*/ +template +< + typename Point, + bool ClockWise = true, + bool Closed = true, + template<typename, typename> class PointList = std::vector, + template<typename, typename> class RingList = std::vector, + template<typename> class PointAlloc = std::allocator, + template<typename> class RingAlloc = std::allocator +> +class polygon +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + +public: + + // Member types + typedef Point point_type; + typedef ring<Point, ClockWise, Closed, PointList, PointAlloc> ring_type; + typedef RingList<ring_type , RingAlloc<ring_type > > inner_container_type; + + inline ring_type const& outer() const { return m_outer; } + inline inner_container_type const& inners() const { return m_inners; } + + inline ring_type& outer() { return m_outer; } + inline inner_container_type & inners() { return m_inners; } + + /// Utility method, clears outer and inner rings + inline void clear() + { + m_outer.clear(); + m_inners.clear(); + } + +private: + + ring_type m_outer; + inner_container_type m_inners; +}; + + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct tag +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, PointAlloc, RingAlloc + > +> +{ + typedef polygon_tag type; +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct ring_const_type +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, PointAlloc, RingAlloc + > +> +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + >::ring_type const& type; +}; + + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct ring_mutable_type +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, PointAlloc, RingAlloc + > +> +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + >::ring_type& type; +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct interior_const_type +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + > +> +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + >::inner_container_type const& type; +}; + + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct interior_mutable_type +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + > +> +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + >::inner_container_type& type; +}; + + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct exterior_ring +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, PointAlloc, RingAlloc + > +> +{ + typedef model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + > polygon_type; + + static inline typename polygon_type::ring_type& get(polygon_type& p) + { + return p.outer(); + } + + static inline typename polygon_type::ring_type const& get( + polygon_type const& p) + { + return p.outer(); + } +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class PointList, + template<typename, typename> class RingList, + template<typename> class PointAlloc, + template<typename> class RingAlloc +> +struct interior_rings +< + model::polygon + < + Point, ClockWise, Closed, + PointList, RingList, + PointAlloc, RingAlloc + > +> +{ + typedef model::polygon + < + Point, ClockWise, Closed, PointList, RingList, + PointAlloc, RingAlloc + > polygon_type; + + static inline typename polygon_type::inner_container_type& get( + polygon_type& p) + { + return p.inners(); + } + + static inline typename polygon_type::inner_container_type const& get( + polygon_type const& p) + { + return p.inners(); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_POLYGON_HPP diff --git a/boost/geometry/geometries/register/box.hpp b/boost/geometry/geometries/register/box.hpp new file mode 100644 index 0000000000..838c2bb5fc --- /dev/null +++ b/boost/geometry/geometries/register/box.hpp @@ -0,0 +1,179 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_REGISTER_BOX_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_BOX_HPP + + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS(Box, Point, MinCorner, MaxCorner) \ +template <size_t D> \ +struct indexed_access<Box, min_corner, D> \ +{ \ + typedef typename coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) \ + { return geometry::get<D>(b. MinCorner); } \ + static inline void set(Box& b, ct const& value) \ + { geometry::set<D>(b. MinCorner, value); } \ +}; \ +template <size_t D> \ +struct indexed_access<Box, max_corner, D> \ +{ \ + typedef typename coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) \ + { return geometry::get<D>(b. MaxCorner); } \ + static inline void set(Box& b, ct const& value) \ + { geometry::set<D>(b. MaxCorner, value); } \ +}; + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS_TEMPLATED(Box, MinCorner, MaxCorner) \ +template <typename P, size_t D> \ +struct indexed_access<Box<P>, min_corner, D> \ +{ \ + typedef typename coordinate_type<P>::type ct; \ + static inline ct get(Box<P> const& b) \ + { return geometry::get<D>(b. MinCorner); } \ + static inline void set(Box<P>& b, ct const& value) \ + { geometry::set<D>(b. MinCorner, value); } \ +}; \ +template <typename P, size_t D> \ +struct indexed_access<Box<P>, max_corner, D> \ +{ \ + typedef typename coordinate_type<P>::type ct; \ + static inline ct get(Box<P> const& b) \ + { return geometry::get<D>(b. MaxCorner); } \ + static inline void set(Box<P>& b, ct const& value) \ + { geometry::set<D>(b. MaxCorner, value); } \ +}; + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS_4VALUES(Box, Point, Left, Bottom, Right, Top) \ +template <> struct indexed_access<Box, min_corner, 0> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) { return b. Left; } \ + static inline void set(Box& b, ct const& value) { b. Left = value; } \ +}; \ +template <> struct indexed_access<Box, min_corner, 1> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) { return b. Bottom; } \ + static inline void set(Box& b, ct const& value) { b. Bottom = value; } \ +}; \ +template <> struct indexed_access<Box, max_corner, 0> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) { return b. Right; } \ + static inline void set(Box& b, ct const& value) { b. Right = value; } \ +}; \ +template <> struct indexed_access<Box, max_corner, 1> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Box const& b) { return b. Top; } \ + static inline void set(Box& b, ct const& value) { b. Top = value; } \ +}; + + + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_TRAITS(Box, PointType) \ + template<> struct tag<Box > { typedef box_tag type; }; \ + template<> struct point_type<Box > { typedef PointType type; }; + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_TRAITS_TEMPLATED(Box) \ + template<typename P> struct tag<Box<P> > { typedef box_tag type; }; \ + template<typename P> struct point_type<Box<P> > { typedef P type; }; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + + +/*! +\brief \brief_macro{box} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX, box} The + box may contain template parameters, which must be specified then. +\param Box \param_macro_type{Box} +\param Point Point type on which box is based. Might be two or three-dimensional +\param MinCorner minimum corner (should be public member or method) +\param MaxCorner maximum corner (should be public member or method) + +\qbk{ +[heading Example] +[register_box] +[register_box_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_BOX(Box, Point, MinCorner, MaxCorner) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_TRAITS(Box, Point) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS(Box, Point, MinCorner, MaxCorner) \ +}}} + + +/*! +\brief \brief_macro{box} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED, box} + \details_macro_templated{box, point} +\param Box \param_macro_type{Box} +\param MinCorner minimum corner (should be public member or method) +\param MaxCorner maximum corner (should be public member or method) + +\qbk{ +[heading Example] +[register_box_templated] +[register_box_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED(Box, MinCorner, MaxCorner) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_TRAITS_TEMPLATED(Box) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS_TEMPLATED(Box, MinCorner, MaxCorner) \ +}}} + +/*! +\brief \brief_macro{box} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_2D_4VALUES, box} +\param Box \param_macro_type{Box} +\param Point Point type reported as point_type by box. Must be two dimensional. + Note that these box tyeps do not contain points, but they must have a + related point_type +\param Left Left side (must be public member or method) +\param Bottom Bottom side (must be public member or method) +\param Right Right side (must be public member or method) +\param Top Top side (must be public member or method) + +\qbk{ +[heading Example] +[register_box_2d_4values] +[register_box_2d_4values_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_BOX_2D_4VALUES(Box, Point, Left, Bottom, Right, Top) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_TRAITS(Box, Point) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_BOX_ACCESS_4VALUES(Box, Point, Left, Bottom, Right, Top) \ +}}} + + + +// CONST versions are for boxes probably not that common. Postponed. + + +#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_BOX_HPP diff --git a/boost/geometry/geometries/register/linestring.hpp b/boost/geometry/geometries/register/linestring.hpp new file mode 100644 index 0000000000..b064398746 --- /dev/null +++ b/boost/geometry/geometries/register/linestring.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_REGISTER_LINESTRING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_LINESTRING_HPP + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +/*! +\brief \brief_macro{linestring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING, linestring} The + linestring may contain template parameters, which must be specified then. +\param Linestring \param_macro_type{linestring} + +\qbk{ +[heading Example] +[register_linestring] +[register_linestring_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_LINESTRING(Linestring) \ +namespace boost { namespace geometry { namespace traits { \ + template<> struct tag<Linestring> { typedef linestring_tag type; }; \ +}}} + + +/*! +\brief \brief_macro{templated linestring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED, templated linestring} + \details_macro_templated{linestring, point} +\param Linestring \param_macro_type{linestring (without template parameters)} + +\qbk{ +[heading Example] +[register_linestring_templated] +[register_linestring_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(Linestring) \ +namespace boost { namespace geometry { namespace traits { \ + template<typename P> struct tag< Linestring<P> > { typedef linestring_tag type; }; \ +}}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_LINESTRING_HPP diff --git a/boost/geometry/geometries/register/point.hpp b/boost/geometry/geometries/register/point.hpp new file mode 100644 index 0000000000..676582576f --- /dev/null +++ b/boost/geometry/geometries/register/point.hpp @@ -0,0 +1,173 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_REGISTER_POINT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_POINT_HPP + + +#include <cstddef> + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + +// Starting point, specialize basic traits necessary to register a point +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, Dim, CoordinateType, CoordinateSystem) \ + template<> struct tag<Point> { typedef point_tag type; }; \ + template<> struct dimension<Point> : boost::mpl::int_<Dim> {}; \ + template<> struct coordinate_type<Point> { typedef CoordinateType type; }; \ + template<> struct coordinate_system<Point> { typedef CoordinateSystem type; }; + +// Specialize access class per dimension +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, Dim, CoordinateType, Get, Set) \ + template<> struct access<Point, Dim> \ + { \ + static inline CoordinateType get(Point const& p) { return p. Get; } \ + static inline void set(Point& p, CoordinateType const& value) { p. Set = value; } \ + }; + +// Const version +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, Dim, CoordinateType, Get) \ + template<> struct access<Point, Dim> \ + { \ + static inline CoordinateType get(Point const& p) { return p. Get; } \ + }; + + +// Getter/setter version +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, Dim, CoordinateType, Get, Set) \ + template<> struct access<Point, Dim> \ + { \ + static inline CoordinateType get(Point const& p) \ + { return p. Get (); } \ + static inline void set(Point& p, CoordinateType const& value) \ + { p. Set ( value ); } \ + }; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + +/*! +\brief \brief_macro{2D point type} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_2D, two-dimensional point type} +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Field0 \param_macro_member{\macro_x} +\param Field1 \param_macro_member{\macro_y} + +\qbk{[include reference/geometries/register/point.qbk]} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_2D(Point, CoordinateType, CoordinateSystem, Field0, Field1) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 2, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, 0, CoordinateType, Field0, Field0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, 1, CoordinateType, Field1, Field1) \ +}}} + +/*! +\brief \brief_macro{3D point type} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_3D, three-dimensional point type} +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Field0 \param_macro_member{\macro_x} +\param Field1 \param_macro_member{\macro_y} +\param Field2 \param_macro_member{\macro_z} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_3D(Point, CoordinateType, CoordinateSystem, Field0, Field1, Field2) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 3, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, 0, CoordinateType, Field0, Field0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, 1, CoordinateType, Field1, Field1) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS(Point, 2, CoordinateType, Field2, Field2) \ +}}} + +/*! +\brief \brief_macro{2D point type} \brief_macro_const +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_2D_CONST, two-dimensional point type}. \details_macro_const +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Field0 \param_macro_member{\macro_x} +\param Field1 \param_macro_member{\macro_y} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_2D_CONST(Point, CoordinateType, CoordinateSystem, Field0, Field1) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 2, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, 0, CoordinateType, Field0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, 1, CoordinateType, Field1) \ +}}} + +/*! +\brief \brief_macro{3D point type} \brief_macro_const +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_3D_CONST, three-dimensional point type}. \details_macro_const +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Field0 \param_macro_member{\macro_x} +\param Field1 \param_macro_member{\macro_y} +\param Field2 \param_macro_member{\macro_z} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_3D_CONST(Point, CoordinateType, CoordinateSystem, Field0, Field1, Field2) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 3, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, 0, CoordinateType, Field0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, 1, CoordinateType, Field1) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_CONST(Point, 2, CoordinateType, Field2) \ +}}} + +/*! +\brief \brief_macro{2D point type} \brief_macro_getset +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET, two-dimensional point type}. \details_macro_getset +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Get0 \param_macro_getset{get, \macro_x} +\param Get1 \param_macro_getset{get, \macro_y} +\param Set0 \param_macro_getset{set, \macro_x} +\param Set1 \param_macro_getset{set, \macro_y} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(Point, CoordinateType, CoordinateSystem, Get0, Get1, Set0, Set1) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 2, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, 0, CoordinateType, Get0, Set0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, 1, CoordinateType, Get1, Set1) \ +}}} + +/*! +\brief \brief_macro{3D point type} \brief_macro_getset +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_POINT_3D_GET_SET, three-dimensional point type}. \details_macro_getset +\param Point \param_macro_type{Point} +\param CoordinateType \param_macro_coortype{point} +\param CoordinateSystem \param_macro_coorsystem +\param Get0 \param_macro_getset{get, \macro_x} +\param Get1 \param_macro_getset{get, \macro_y} +\param Get2 \param_macro_getset{get, \macro_z} +\param Set0 \param_macro_getset{set, \macro_x} +\param Set1 \param_macro_getset{set, \macro_y} +\param Set2 \param_macro_getset{set, \macro_z} +*/ +#define BOOST_GEOMETRY_REGISTER_POINT_3D_GET_SET(Point, CoordinateType, CoordinateSystem, Get0, Get1, Get2, Set0, Set1, Set2) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_TRAITS(Point, 3, CoordinateType, CoordinateSystem) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, 0, CoordinateType, Get0, Set0) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, 1, CoordinateType, Get1, Set1) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_POINT_ACCESS_GET_SET(Point, 2, CoordinateType, Get2, Set2) \ +}}} + +#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_POINT_HPP diff --git a/boost/geometry/geometries/register/ring.hpp b/boost/geometry/geometries/register/ring.hpp new file mode 100644 index 0000000000..fb6cb67200 --- /dev/null +++ b/boost/geometry/geometries/register/ring.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_REGISTER_RING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_RING_HPP + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +/*! +\brief \brief_macro{ring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_RING, ring} The + ring may contain template parameters, which must be specified then. +\param Ring \param_macro_type{ring} + +\qbk{ +[heading Example] +[register_ring] +[register_ring_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_RING(Ring) \ +namespace boost { namespace geometry { namespace traits { \ + template<> struct tag<Ring> { typedef ring_tag type; }; \ +}}} + + +/*! +\brief \brief_macro{templated ring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_RING_TEMPLATED, templated ring} + \details_macro_templated{ring, point} +\param Ring \param_macro_type{ring (without template parameters)} + +\qbk{ +[heading Example] +[register_ring_templated] +[register_ring_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_RING_TEMPLATED(Ring) \ +namespace boost { namespace geometry { namespace traits { \ + template<typename P> struct tag< Ring<P> > { typedef ring_tag type; }; \ +}}} + + +#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_RING_HPP diff --git a/boost/geometry/geometries/register/segment.hpp b/boost/geometry/geometries/register/segment.hpp new file mode 100644 index 0000000000..6ea88c0918 --- /dev/null +++ b/boost/geometry/geometries/register/segment.hpp @@ -0,0 +1,129 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_REGISTER_SEGMENT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_SEGMENT_HPP + + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS(Segment, Point, Index0, Index1) \ +template <size_t D> \ +struct indexed_access<Segment, min_corner, D> \ +{ \ + typedef typename coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) \ + { return geometry::get<D>(b. Index0); } \ + static inline void set(Segment& b, ct const& value) \ + { geometry::set<D>(b. Index0, value); } \ +}; \ +template <size_t D> \ +struct indexed_access<Segment, max_corner, D> \ +{ \ + typedef typename coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) \ + { return geometry::get<D>(b. Index1); } \ + static inline void set(Segment& b, ct const& value) \ + { geometry::set<D>(b. Index1, value); } \ +}; + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS_TEMPLATIZED(Segment, Index0, Index1) \ +template <typename P, size_t D> \ +struct indexed_access<Segment<P>, min_corner, D> \ +{ \ + typedef typename coordinate_type<P>::type ct; \ + static inline ct get(Segment<P> const& b) \ + { return geometry::get<D>(b. Index0); } \ + static inline void set(Segment<P>& b, ct const& value) \ + { geometry::set<D>(b. Index0, value); } \ +}; \ +template <typename P, size_t D> \ +struct indexed_access<Segment<P>, max_corner, D> \ +{ \ + typedef typename coordinate_type<P>::type ct; \ + static inline ct get(Segment<P> const& b) \ + { return geometry::get<D>(b. Index1); } \ + static inline void set(Segment<P>& b, ct const& value) \ + { geometry::set<D>(b. Index1, value); } \ +}; + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS_4VALUES(Segment, Point, Left, Bottom, Right, Top) \ +template <> struct indexed_access<Segment, min_corner, 0> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) { return b. Left; } \ + static inline void set(Segment& b, ct const& value) { b. Left = value; } \ +}; \ +template <> struct indexed_access<Segment, min_corner, 1> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) { return b. Bottom; } \ + static inline void set(Segment& b, ct const& value) { b. Bottom = value; } \ +}; \ +template <> struct indexed_access<Segment, max_corner, 0> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) { return b. Right; } \ + static inline void set(Segment& b, ct const& value) { b. Right = value; } \ +}; \ +template <> struct indexed_access<Segment, max_corner, 1> \ +{ \ + typedef coordinate_type<Point>::type ct; \ + static inline ct get(Segment const& b) { return b. Top; } \ + static inline void set(Segment& b, ct const& value) { b. Top = value; } \ +}; + + + + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_TRAITS(Segment, PointType) \ + template<> struct tag<Segment > { typedef segment_tag type; }; \ + template<> struct point_type<Segment > { typedef PointType type; }; + +#define BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_TRAITS_TEMPLATIZED(Segment) \ + template<typename P> struct tag<Segment<P> > { typedef segment_tag type; }; \ + template<typename P> struct point_type<Segment<P> > { typedef P type; }; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + + +#define BOOST_GEOMETRY_REGISTER_SEGMENT(Segment, PointType, Index0, Index1) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_TRAITS(Segment, PointType) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS(Segment, PointType, Index0, Index1) \ +}}} + + +#define BOOST_GEOMETRY_REGISTER_SEGMENT_TEMPLATIZED(Segment, Index0, Index1) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_TRAITS_TEMPLATIZED(Segment) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS_TEMPLATIZED(Segment, Index0, Index1) \ +}}} + +#define BOOST_GEOMETRY_REGISTER_SEGMENT_2D_4VALUES(Segment, PointType, Left, Bottom, Right, Top) \ +namespace boost { namespace geometry { namespace traits { \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_TRAITS(Segment, PointType) \ + BOOST_GEOMETRY_DETAIL_SPECIALIZE_SEGMENT_ACCESS_4VALUES(Segment, PointType, Left, Bottom, Right, Top) \ +}}} + + + +// CONST versions are for segments probably not that common. Postponed. + + +#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_SEGMENT_HPP diff --git a/boost/geometry/geometries/ring.hpp b/boost/geometry/geometries/ring.hpp new file mode 100644 index 0000000000..998619785a --- /dev/null +++ b/boost/geometry/geometries/ring.hpp @@ -0,0 +1,153 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_RING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_RING_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/assert.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + +namespace boost { namespace geometry +{ + +namespace model +{ +/*! +\brief A ring (aka linear ring) is a closed line which should not be selfintersecting +\ingroup geometries +\tparam Point point type +\tparam ClockWise true for clockwise direction, + false for CounterClockWise direction +\tparam Closed true for closed polygons (last point == first point), + false open points +\tparam Container container type, for example std::vector, std::deque +\tparam Allocator container-allocator-type + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_ring Ring Concept] +} +*/ +template +< + typename Point, + bool ClockWise = true, bool Closed = true, + template<typename, typename> class Container = std::vector, + template<typename> class Allocator = std::allocator +> +class ring : public Container<Point, Allocator<Point> > +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + typedef Container<Point, Allocator<Point> > base_type; + +public : + /// \constructor_default{ring} + inline ring() + : base_type() + {} + + /// \constructor_begin_end{ring} + template <typename Iterator> + inline ring(Iterator begin, Iterator end) + : base_type(begin, end) + {} +}; + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + bool ClockWise, bool Closed, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct tag<model::ring<Point, ClockWise, Closed, Container, Allocator> > +{ + typedef ring_tag type; +}; + + +template +< + typename Point, + bool Closed, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct point_order<model::ring<Point, false, Closed, Container, Allocator> > +{ + static const order_selector value = counterclockwise; +}; + + +template +< + typename Point, + bool Closed, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct point_order<model::ring<Point, true, Closed, Container, Allocator> > +{ + static const order_selector value = clockwise; +}; + +template +< + typename Point, + bool PointOrder, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct closure<model::ring<Point, PointOrder, true, Container, Allocator> > +{ + static const closure_selector value = closed; +}; + +template +< + typename Point, + bool PointOrder, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct closure<model::ring<Point, PointOrder, false, Container, Allocator> > +{ + static const closure_selector value = open; +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_RING_HPP diff --git a/boost/geometry/geometries/segment.hpp b/boost/geometry/geometries/segment.hpp new file mode 100644 index 0000000000..3f47f79ec4 --- /dev/null +++ b/boost/geometry/geometries/segment.hpp @@ -0,0 +1,203 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRIES_SEGMENT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_SEGMENT_HPP + +#include <cstddef> + +#include <boost/concept/assert.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_const.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + +namespace boost { namespace geometry +{ + +namespace model +{ + +/*! +\brief Class segment: small class containing two points +\ingroup geometries +\details From Wikipedia: In geometry, a line segment is a part of a line that is bounded + by two distinct end points, and contains every point on the line between its end points. +\note There is also a point-referring-segment, class referring_segment, + containing point references, where points are NOT copied +*/ +template<typename Point> +class segment : public std::pair<Point, Point> +{ +public : + inline segment() + {} + + inline segment(Point const& p1, Point const& p2) + { + this->first = p1; + this->second = p2; + } +}; + + +/*! +\brief Class segment: small class containing two (templatized) point references +\ingroup geometries +\details From Wikipedia: In geometry, a line segment is a part of a line that is bounded + by two distinct end points, and contains every point on the line between its end points. +\note The structure is like std::pair, and can often be used interchangeable. +Difference is that it refers to points, does not have points. +\note Like std::pair, points are public available. +\note type is const or non const, so geometry::segment<P> or geometry::segment<P const> +\note We cannot derive from std::pair<P&, P&> because of +reference assignments. +\tparam ConstOrNonConstPoint point type of the segment, maybe a point or a const point +*/ +template<typename ConstOrNonConstPoint> +class referring_segment +{ + BOOST_CONCEPT_ASSERT( ( + typename boost::mpl::if_ + < + boost::is_const<ConstOrNonConstPoint>, + concept::Point<ConstOrNonConstPoint>, + concept::ConstPoint<ConstOrNonConstPoint> + > + ) ); + + typedef ConstOrNonConstPoint point_type; + +public: + + point_type& first; + point_type& second; + + inline referring_segment(point_type& p1, point_type& p2) + : first(p1) + , second(p2) + {} +}; + + +} // namespace model + + +// Traits specializations for segment above +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename Point> +struct tag<model::segment<Point> > +{ + typedef segment_tag type; +}; + +template <typename Point> +struct point_type<model::segment<Point> > +{ + typedef Point type; +}; + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::segment<Point>, 0, Dimension> +{ + typedef model::segment<Point> segment_type; + typedef typename geometry::coordinate_type<segment_type>::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + return geometry::get<Dimension>(s.first); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.first, value); + } +}; + + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::segment<Point>, 1, Dimension> +{ + typedef model::segment<Point> segment_type; + typedef typename geometry::coordinate_type<segment_type>::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + return geometry::get<Dimension>(s.second); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.second, value); + } +}; + + +template <typename ConstOrNonConstPoint> +struct tag<model::referring_segment<ConstOrNonConstPoint> > +{ + typedef segment_tag type; +}; + +template <typename ConstOrNonConstPoint> +struct point_type<model::referring_segment<ConstOrNonConstPoint> > +{ + typedef ConstOrNonConstPoint type; +}; + +template <typename ConstOrNonConstPoint, std::size_t Dimension> +struct indexed_access<model::referring_segment<ConstOrNonConstPoint>, 0, Dimension> +{ + typedef model::referring_segment<ConstOrNonConstPoint> segment_type; + typedef typename geometry::coordinate_type<segment_type>::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + return geometry::get<Dimension>(s.first); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.first, value); + } +}; + + +template <typename ConstOrNonConstPoint, std::size_t Dimension> +struct indexed_access<model::referring_segment<ConstOrNonConstPoint>, 1, Dimension> +{ + typedef model::referring_segment<ConstOrNonConstPoint> segment_type; + typedef typename geometry::coordinate_type<segment_type>::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + return geometry::get<Dimension>(s.second); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + geometry::set<Dimension>(s.second, value); + } +}; + + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_SEGMENT_HPP diff --git a/boost/geometry/geometry.hpp b/boost/geometry/geometry.hpp new file mode 100644 index 0000000000..22d08e2a45 --- /dev/null +++ b/boost/geometry/geometry.hpp @@ -0,0 +1,90 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_GEOMETRY_HPP +#define BOOST_GEOMETRY_GEOMETRY_HPP + +// Shortcut to include all header files + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> + +// Core algorithms +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/topological_dimension.hpp> + + +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/arithmetic/dot_product.hpp> + +#include <boost/geometry/strategies/strategies.hpp> + +#include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/area.hpp> +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/buffer.hpp> +#include <boost/geometry/algorithms/centroid.hpp> +#include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/comparable_distance.hpp> +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/convex_hull.hpp> +#include <boost/geometry/algorithms/correct.hpp> +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/difference.hpp> +#include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/algorithms/distance.hpp> +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/for_each.hpp> +#include <boost/geometry/algorithms/intersection.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/length.hpp> +#include <boost/geometry/algorithms/make.hpp> +#include <boost/geometry/algorithms/num_geometries.hpp> +#include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/algorithms/overlaps.hpp> +#include <boost/geometry/algorithms/perimeter.hpp> +#include <boost/geometry/algorithms/reverse.hpp> +#include <boost/geometry/algorithms/simplify.hpp> +#include <boost/geometry/algorithms/sym_difference.hpp> +#include <boost/geometry/algorithms/transform.hpp> +#include <boost/geometry/algorithms/union.hpp> +#include <boost/geometry/algorithms/unique.hpp> +#include <boost/geometry/algorithms/within.hpp> + +// Include multi a.o. because it can give weird effects +// if you don't (e.g. area=0 of a multipolygon) +#include <boost/geometry/multi/multi.hpp> + +// check includes all concepts +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/util/for_each_coordinate.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/io/dsv/write.hpp> + +#include <boost/geometry/views/box_view.hpp> +#include <boost/geometry/views/segment_view.hpp> + +#include <boost/geometry/io/io.hpp> + +#endif // BOOST_GEOMETRY_GEOMETRY_HPP diff --git a/boost/geometry/io/dsv/write.hpp b/boost/geometry/io/dsv/write.hpp new file mode 100644 index 0000000000..62929f8073 --- /dev/null +++ b/boost/geometry/io/dsv/write.hpp @@ -0,0 +1,375 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_DSV_WRITE_HPP +#define BOOST_GEOMETRY_IO_DSV_WRITE_HPP + +#include <cstddef> +#include <ostream> +#include <string> + +#include <boost/concept_check.hpp> +#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/ring_type.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 dsv +{ + +struct dsv_settings +{ + std::string coordinate_separator; + std::string point_open; + std::string point_close; + std::string point_separator; + std::string list_open; + std::string list_close; + std::string list_separator; + + dsv_settings(std::string const& sep + , std::string const& open + , std::string const& close + , std::string const& psep + , std::string const& lopen + , std::string const& lclose + , std::string const& lsep + ) + : coordinate_separator(sep) + , point_open(open) + , point_close(close) + , point_separator(psep) + , list_open(lopen) + , list_close(lclose) + , list_separator(lsep) + {} +}; + +/*! +\brief Stream coordinate of a point as \ref DSV +*/ +template <typename Point, std::size_t Dimension, std::size_t Count> +struct stream_coordinate +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Point const& point, + dsv_settings const& settings) + { + os << (Dimension > 0 ? settings.coordinate_separator : "") + << get<Dimension>(point); + + stream_coordinate + < + Point, Dimension + 1, Count + >::apply(os, point, settings); + } +}; + +template <typename Point, std::size_t Count> +struct stream_coordinate<Point, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, + Point const&, + dsv_settings const& ) + { + } +}; + +/*! +\brief Stream indexed coordinate of a box/segment as \ref DSV +*/ +template +< + typename Geometry, + std::size_t Index, + std::size_t Dimension, + std::size_t Count +> +struct stream_indexed +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << (Dimension > 0 ? settings.coordinate_separator : "") + << get<Index, Dimension>(geometry); + stream_indexed + < + Geometry, Index, Dimension + 1, Count + >::apply(os, geometry, settings); + } +}; + +template <typename Geometry, std::size_t Index, std::size_t Count> +struct stream_indexed<Geometry, Index, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, Geometry const&, + dsv_settings const& ) + { + } +}; + +/*! +\brief Stream points as \ref DSV +*/ +template <typename Point> +struct dsv_point +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Point const& p, + dsv_settings const& settings) + { + os << settings.point_open; + stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p, settings); + os << settings.point_close; + } +}; + +/*! +\brief Stream ranges as DSV +\note policy is used to stream prefix/postfix, enabling derived classes to override this +*/ +template <typename Range> +struct dsv_range +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range, + dsv_settings const& settings) + { + typedef typename boost::range_iterator<Range const>::type iterator_type; + + bool first = true; + + os << settings.list_open; + + for (iterator_type it = boost::begin(range); + it != boost::end(range); + ++it) + { + os << (first ? "" : settings.point_separator) + << settings.point_open; + + stream_coordinate + < + point_type, 0, dimension<point_type>::type::value + >::apply(os, *it, settings); + os << settings.point_close; + + first = false; + } + + os << settings.list_close; + } + +private: + typedef typename boost::range_value<Range>::type point_type; +}; + +/*! +\brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4) +\note Used in polygon, all multi-geometries +*/ + +template <typename Polygon> +struct dsv_poly +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Polygon const& poly, + dsv_settings const& settings) + { + typedef typename ring_type<Polygon>::type ring; + + os << settings.list_open; + + dsv_range<ring>::apply(os, exterior_ring(poly), settings); + + typename interior_return_type<Polygon const>::type rings + = interior_rings(poly); + for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + { + os << settings.list_separator; + dsv_range<ring>::apply(os, *it, settings); + } + os << settings.list_close; + } +}; + +template <typename Geometry, std::size_t Index> +struct dsv_per_index +{ + typedef typename point_type<Geometry>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << settings.point_open; + stream_indexed + < + Geometry, Index, 0, dimension<Geometry>::type::value + >::apply(os, geometry, settings); + os << settings.point_close; + } +}; + +template <typename Geometry> +struct dsv_indexed +{ + typedef typename point_type<Geometry>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << settings.list_open; + dsv_per_index<Geometry, 0>::apply(os, geometry, settings); + os << settings.point_separator; + dsv_per_index<Geometry, 1>::apply(os, geometry, settings); + os << settings.list_close; + } +}; + +}} // namespace detail::dsv +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Tag, typename Geometry> +struct dsv {}; + +template <typename Point> +struct dsv<point_tag, Point> + : detail::dsv::dsv_point<Point> +{}; + +template <typename Linestring> +struct dsv<linestring_tag, Linestring> + : detail::dsv::dsv_range<Linestring> +{}; + +template <typename Box> +struct dsv<box_tag, Box> + : detail::dsv::dsv_indexed<Box> +{}; + +template <typename Segment> +struct dsv<segment_tag, Segment> + : detail::dsv::dsv_indexed<Segment> +{}; + +template <typename Ring> +struct dsv<ring_tag, Ring> + : detail::dsv::dsv_range<Ring> +{}; + +template <typename Polygon> +struct dsv<polygon_tag, Polygon> + : detail::dsv::dsv_poly<Polygon> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace dsv +{ + +// FIXME: This class is not copyable/assignable but it is used as such --mloskot +template <typename Geometry> +class dsv_manipulator +{ +public: + + inline dsv_manipulator(Geometry const& g, + dsv_settings const& settings) + : m_geometry(g) + , m_settings(settings) + {} + + template <typename Char, typename Traits> + inline friend std::basic_ostream<Char, Traits>& operator<<( + std::basic_ostream<Char, Traits>& os, + dsv_manipulator const& m) + { + dispatch::dsv + < + typename tag_cast + < + typename tag<Geometry>::type, + multi_tag + >::type, + Geometry + >::apply(os, m.m_geometry, m.m_settings); + os.flush(); + return os; + } + +private: + Geometry const& m_geometry; + dsv_settings m_settings; +}; + +}} // namespace detail::dsv +#endif // DOXYGEN_NO_DETAIL + +/*! +\brief Main DSV-streaming function +\details DSV stands for Delimiter Separated Values. Geometries can be streamed + as DSV. There are defaults for all separators. +\note Useful for examples and testing purposes +\note With this function GeoJSON objects can be created, using the right + delimiters +\ingroup utility +*/ +template <typename Geometry> +inline detail::dsv::dsv_manipulator<Geometry> dsv(Geometry const& geometry + , std::string const& coordinate_separator = ", " + , std::string const& point_open = "(" + , std::string const& point_close = ")" + , std::string const& point_separator = ", " + , std::string const& list_open = "(" + , std::string const& list_close = ")" + , std::string const& list_separator = ", " + ) +{ + concept::check<Geometry const>(); + + return detail::dsv::dsv_manipulator<Geometry>(geometry, + detail::dsv::dsv_settings(coordinate_separator, + point_open, point_close, point_separator, + list_open, list_close, list_separator)); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP diff --git a/boost/geometry/io/io.hpp b/boost/geometry/io/io.hpp new file mode 100644 index 0000000000..9340060776 --- /dev/null +++ b/boost/geometry/io/io.hpp @@ -0,0 +1,58 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_HPP +#define BOOST_GEOMETRY_IO_HPP + +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/io/wkt/write.hpp> + +namespace boost { namespace geometry +{ + +struct format_wkt {}; +struct format_wkb {}; // TODO +struct format_dsv {}; // TODO + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ +template <typename Tag, typename Geometry> +struct read +{ +}; + +template <typename Geometry> +struct read<format_wkt, Geometry> +{ + static inline void apply(Geometry& geometry, std::string const& wkt) + { + read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +template <typename Format, typename Geometry> +inline void read(Geometry& geometry, std::string const& wkt) +{ + geometry::concept::check<Geometry>(); + dispatch::read<Format, Geometry>::apply(geometry, wkt); +} + +// TODO: wriite + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_HPP diff --git a/boost/geometry/io/wkt/detail/prefix.hpp b/boost/geometry/io/wkt/detail/prefix.hpp new file mode 100644 index 0000000000..45e43b88d4 --- /dev/null +++ b/boost/geometry/io/wkt/detail/prefix.hpp @@ -0,0 +1,45 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_WKT_DETAIL_PREFIX_HPP +#define BOOST_GEOMETRY_IO_WKT_DETAIL_PREFIX_HPP + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +struct prefix_point +{ + static inline const char* apply() { return "POINT"; } +}; + +struct prefix_polygon +{ + static inline const char* apply() { return "POLYGON"; } +}; + +struct prefix_linestring +{ + static inline const char* apply() { return "LINESTRING"; } +}; + +}} // namespace wkt::impl +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_DETAIL_PREFIX_HPP diff --git a/boost/geometry/io/wkt/detail/wkt_multi.hpp b/boost/geometry/io/wkt/detail/wkt_multi.hpp new file mode 100644 index 0000000000..0e5abbca81 --- /dev/null +++ b/boost/geometry/io/wkt/detail/wkt_multi.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP +#define BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP + + +#include <boost/geometry/domains/gis/io/wkt/write.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +struct prefix_null +{ + static inline const char* apply() { return ""; } +}; + +struct prefix_multipoint +{ + static inline const char* apply() { return "MULTIPOINT"; } +}; + +struct prefix_multilinestring +{ + static inline const char* apply() { return "MULTILINESTRING"; } +}; + +struct prefix_multipolygon +{ + static inline const char* apply() { return "MULTIPOLYGON"; } +}; + + + +}} // namespace wkt::impl +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp new file mode 100644 index 0000000000..e926939d51 --- /dev/null +++ b/boost/geometry/io/wkt/read.hpp @@ -0,0 +1,686 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_WKT_READ_HPP +#define BOOST_GEOMETRY_IO_WKT_READ_HPP + +#include <string> + +#include <boost/lexical_cast.hpp> +#include <boost/tokenizer.hpp> + +#include <boost/algorithm/string.hpp> +#include <boost/mpl/if.hpp> +#include <boost/range.hpp> + +#include <boost/type_traits.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/clear.hpp> + +#include <boost/geometry/core/access.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/geometry_id.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/util/coordinate_cast.hpp> + +#include <boost/geometry/io/wkt/detail/prefix.hpp> + +namespace boost { namespace geometry +{ + +/*! +\brief Exception showing things wrong with WKT parsing +\ingroup wkt +*/ +struct read_wkt_exception : public geometry::exception +{ + template <typename Iterator> + read_wkt_exception(std::string const& msg, + Iterator const& it, Iterator const& end, std::string const& wkt) + : message(msg) + , wkt(wkt) + { + if (it != end) + { + source = " at '"; + source += it->c_str(); + source += "'"; + } + complete = message + source + " in '" + wkt.substr(0, 100) + "'"; + } + + read_wkt_exception(std::string const& msg, std::string const& wkt) + : message(msg) + , wkt(wkt) + { + complete = message + "' in (" + wkt.substr(0, 100) + ")"; + } + + virtual ~read_wkt_exception() throw() {} + + virtual const char* what() const throw() + { + return complete.c_str(); + } +private : + std::string source; + std::string message; + std::string wkt; + std::string complete; +}; + + +#ifndef DOXYGEN_NO_DETAIL +// (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS)) +namespace detail { namespace wkt +{ + +typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + +template <typename Point, std::size_t Dimension, std::size_t DimensionCount> +struct parsing_assigner +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + Point& point, std::string const& wkt) + { + typedef typename coordinate_type<Point>::type coordinate_type; + + // Stop at end of tokens, or at "," ot ")" + bool finished = (it == end || *it == "," || *it == ")"); + + try + { + // Initialize missing coordinates to default constructor (zero) + // OR + // Use lexical_cast for conversion to double/int + // Note that it is much slower than atof. However, it is more standard + // and in parsing the change in performance falls probably away against + // the tokenizing + set<Dimension>(point, finished + ? coordinate_type() + : coordinate_cast<coordinate_type>::apply(*it)); + } + catch(boost::bad_lexical_cast const& blc) + { + throw read_wkt_exception(blc.what(), it, end, wkt); + } + catch(std::exception const& e) + { + throw read_wkt_exception(e.what(), it, end, wkt); + } + catch(...) + { + throw read_wkt_exception("", it, end, wkt); + } + + parsing_assigner<Point, Dimension + 1, DimensionCount>::apply( + (finished ? it : ++it), end, point, wkt); + } +}; + +template <typename Point, std::size_t DimensionCount> +struct parsing_assigner<Point, DimensionCount, DimensionCount> +{ + static inline void apply(tokenizer::iterator&, tokenizer::iterator, Point&, + std::string const&) + { + } +}; + + + +template <typename Iterator> +inline void handle_open_parenthesis(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it == end || *it != "(") + { + throw read_wkt_exception("Expected '('", it, end, wkt); + } + ++it; +} + + +template <typename Iterator> +inline void handle_close_parenthesis(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it != end && *it == ")") + { + ++it; + } + else + { + throw read_wkt_exception("Expected ')'", it, end, wkt); + } +} + +template <typename Iterator> +inline void check_end(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it != end) + { + throw read_wkt_exception("Too much tokens", it, end, wkt); + } +} + +/*! +\brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)" +\param it token-iterator, should be pre-positioned at "(", is post-positions after last ")" +\param end end-token-iterator +\param out Output itererator receiving coordinates +*/ +template <typename Point> +struct container_inserter +{ + // Version with output iterator + template <typename OutputIterator> + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, OutputIterator out) + { + handle_open_parenthesis(it, end, wkt); + + Point point; + + // Parse points until closing parenthesis + + while (it != end && *it != ")") + { + parsing_assigner + < + Point, + 0, + dimension<Point>::value + >::apply(it, end, point, wkt); + out = point; + ++out; + if (it != end && *it == ",") + { + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + + +// Geometry is a value-type or reference-type +template <typename Geometry> +struct container_appender +{ + typedef typename geometry::point_type + < + typename boost::remove_reference<Geometry>::type + >::type point_type; + + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Geometry out) + { + handle_open_parenthesis(it, end, wkt); + + point_type point; + + // Parse points until closing parenthesis + + while (it != end && *it != ")") + { + parsing_assigner + < + point_type, + 0, + dimension<point_type>::value + >::apply(it, end, point, wkt); + + geometry::append(out, point); + if (it != end && *it == ",") + { + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + +/*! +\brief Internal, parses a point from a string like this "(x y)" +\note used for parsing points and multi-points +*/ +template <typename P> +struct point_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, P& point) + { + handle_open_parenthesis(it, end, wkt); + parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt); + handle_close_parenthesis(it, end, wkt); + } +}; + + +template <typename Geometry> +struct linestring_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Geometry& geometry) + { + container_appender<Geometry&>::apply(it, end, wkt, geometry); + } +}; + + +template <typename Ring> +struct ring_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Ring& ring) + { + // A ring should look like polygon((x y,x y,x y...)) + // So handle the extra opening/closing parentheses + // and in between parse using the container-inserter + handle_open_parenthesis(it, end, wkt); + container_appender<Ring&>::apply(it, end, wkt, ring); + handle_close_parenthesis(it, end, wkt); + } +}; + + + + +/*! +\brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))" +\note used for parsing polygons and multi-polygons +*/ +template <typename Polygon> +struct polygon_parser +{ + typedef typename ring_return_type<Polygon>::type ring_return_type; + typedef container_appender<ring_return_type> appender; + + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Polygon& poly) + { + + handle_open_parenthesis(it, end, wkt); + + int n = -1; + + // Stop at ")" + while (it != end && *it != ")") + { + // Parse ring + if (++n == 0) + { + appender::apply(it, end, wkt, exterior_ring(poly)); + } + else + { + typename ring_type<Polygon>::type ring; + appender::apply(it, end, wkt, ring); + traits::push_back + < + typename boost::remove_reference + < + typename traits::interior_mutable_type<Polygon>::type + >::type + >::apply(interior_rings(poly), ring); + } + + if (it != end && *it == ",") + { + // Skip "," after ring is parsed + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + +inline bool one_of(tokenizer::iterator const& it, std::string const& value, + bool& is_present) +{ + if (boost::iequals(*it, value)) + { + is_present = true; + return true; + } + return false; +} + +inline bool one_of(tokenizer::iterator const& it, std::string const& value, + bool& present1, bool& present2) +{ + if (boost::iequals(*it, value)) + { + present1 = true; + present2 = true; + return true; + } + return false; +} + + +inline void handle_empty_z_m(tokenizer::iterator& it, tokenizer::iterator end, + bool& has_empty, bool& has_z, bool& has_m) +{ + has_empty = false; + has_z = false; + has_m = false; + + // WKT can optionally have Z and M (measured) values as in + // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5) + // GGL supports any of them as coordinate values, but is not aware + // of any Measured value. + while (it != end + && (one_of(it, "M", has_m) + || one_of(it, "Z", has_z) + || one_of(it, "EMPTY", has_empty) + || one_of(it, "MZ", has_m, has_z) + || one_of(it, "ZM", has_z, has_m) + ) + ) + { + ++it; + } +} + +/*! +\brief Internal, starts parsing +\param tokens boost tokens, parsed with separator " " and keeping separator "()" +\param geometry string to compare with first token +*/ +template <typename Geometry> +inline bool initialize(tokenizer const& tokens, + std::string const& geometry_name, std::string const& wkt, + tokenizer::iterator& it) +{ + it = tokens.begin(); + if (it != tokens.end() && boost::iequals(*it++, geometry_name)) + { + bool has_empty, has_z, has_m; + + handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m); + + if (has_z && dimension<Geometry>::type::value < 3) + { + throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt); + } + if (has_empty) + { + check_end(it, tokens.end(), wkt); + return false; + } + // M is ignored at all. + + return true; + } + throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt); +} + + +template <typename Geometry, template<typename> class Parser, typename PrefixPolicy> +struct geometry_parser +{ + static inline void apply(std::string const& wkt, Geometry& geometry) + { + geometry::clear(geometry); + + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it; + if (initialize<Geometry>(tokens, PrefixPolicy::apply(), wkt, it)) + { + Parser<Geometry>::apply(it, tokens.end(), wkt, geometry); + check_end(it, tokens.end(), wkt); + } + } +}; + + + + + +/*! +\brief Supports box parsing +\note OGC does not define the box geometry, and WKT does not support boxes. + However, to be generic GGL supports reading and writing from and to boxes. + Boxes are outputted as a standard POLYGON. GGL can read boxes from + a standard POLYGON, from a POLYGON with 2 points of from a BOX +\tparam Box the box +*/ +template <typename Box> +struct box_parser +{ + static inline void apply(std::string const& wkt, Box& box) + { + bool should_close = false; + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); + if (it != end && boost::iequals(*it, "POLYGON")) + { + ++it; + bool has_empty, has_z, has_m; + handle_empty_z_m(it, end, has_empty, has_z, has_m); + if (has_empty) + { + assign_zero(box); + return; + } + handle_open_parenthesis(it, end, wkt); + should_close = true; + } + else if (it != end && boost::iequals(*it, "BOX")) + { + ++it; + } + else + { + throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt); + } + + typedef typename point_type<Box>::type point_type; + std::vector<point_type> points; + container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points)); + + if (should_close) + { + handle_close_parenthesis(it, end, wkt); + } + check_end(it, end, wkt); + + int index = 0; + int n = boost::size(points); + if (n == 2) + { + index = 1; + } + else if (n == 4 || n == 5) + { + // In case of 4 or 5 points, we do not check the other ones, just + // take the opposite corner which is always 2 + index = 2; + } + else + { + throw read_wkt_exception("Box should have 2,4 or 5 points", wkt); + } + + geometry::detail::assign_point_to_index<min_corner>(points.front(), box); + geometry::detail::assign_point_to_index<max_corner>(points[index], box); + } +}; + + +/*! +\brief Supports segment parsing +\note OGC does not define the segment, and WKT does not support segmentes. + However, it is useful to implement it, also for testing purposes +\tparam Segment the segment +*/ +template <typename Segment> +struct segment_parser +{ + static inline void apply(std::string const& wkt, Segment& segment) + { + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); + if (it != end && + (boost::iequals(*it, "SEGMENT") + || boost::iequals(*it, "LINESTRING") )) + { + ++it; + } + else + { + throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt); + } + + typedef typename point_type<Segment>::type point_type; + std::vector<point_type> points; + container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points)); + + check_end(it, end, wkt); + + if (boost::size(points) == 2) + { + geometry::detail::assign_point_to_index<0>(points.front(), segment); + geometry::detail::assign_point_to_index<1>(points.back(), segment); + } + else + { + throw read_wkt_exception("Segment should have 2 points", wkt); + } + + } +}; + + + +}} // namespace detail::wkt +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Tag, typename Geometry> +struct read_wkt {}; + + +template <typename Point> +struct read_wkt<point_tag, Point> + : detail::wkt::geometry_parser + < + Point, + detail::wkt::point_parser, + detail::wkt::prefix_point + > +{}; + + +template <typename L> +struct read_wkt<linestring_tag, L> + : detail::wkt::geometry_parser + < + L, + detail::wkt::linestring_parser, + detail::wkt::prefix_linestring + > +{}; + +template <typename Ring> +struct read_wkt<ring_tag, Ring> + : detail::wkt::geometry_parser + < + Ring, + detail::wkt::ring_parser, + detail::wkt::prefix_polygon + > +{}; + +template <typename Geometry> +struct read_wkt<polygon_tag, Geometry> + : detail::wkt::geometry_parser + < + Geometry, + detail::wkt::polygon_parser, + detail::wkt::prefix_polygon + > +{}; + + +// Box (Non-OGC) +template <typename Box> +struct read_wkt<box_tag, Box> + : detail::wkt::box_parser<Box> +{}; + +// Segment (Non-OGC) +template <typename Segment> +struct read_wkt<segment_tag, Segment> + : detail::wkt::segment_parser<Segment> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +/*! +\brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry) +\ingroup wkt +\param wkt string containing \ref WKT +\param geometry output geometry +\par Example: +\note It is case insensitive and can have the WKT forms "point", "point m", "point z", "point zm", "point mz" +\note Empty sequences can have forms as "LINESTRING ()" or "POLYGON(())" +Small example showing how to use read_wkt to build a point +\dontinclude doxygen_1.cpp +\skip example_from_wkt_point +\line { +\until } +\par Example: +Small example showing how to use read_wkt to build a linestring +\dontinclude doxygen_1.cpp +\skip example_from_wkt_linestring +\line { +\until } +\par Example: +Small example showing how to use read_wkt to build a polygon +\dontinclude doxygen_1.cpp +\skip example_from_wkt_polygon +\line { +\until } +*/ +template <typename Geometry> +inline void read_wkt(std::string const& wkt, Geometry& geometry) +{ + geometry::concept::check<Geometry>(); + dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_READ_HPP diff --git a/boost/geometry/io/wkt/stream.hpp b/boost/geometry/io/wkt/stream.hpp new file mode 100644 index 0000000000..86e49fdaf1 --- /dev/null +++ b/boost/geometry/io/wkt/stream.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_WKT_STREAM_HPP +#define BOOST_GEOMETRY_IO_WKT_STREAM_HPP + +#include <boost/geometry/io/wkt/write.hpp> + +// This short file contains only one manipulator, streaming as WKT +// Don't include this in any standard-included header file. + +// Don't use namespace boost::geometry, to enable the library to stream custom +// geometries which are living outside the namespace boost::geometry + +/*! +\brief Streams a geometry as Well-Known Text +\ingroup wkt +*/ +template<typename Char, typename Traits, typename Geometry> +inline std::basic_ostream<Char, Traits>& operator<< + ( + std::basic_ostream<Char, Traits> &os, + Geometry const& geom + ) +{ + os << boost::geometry::wkt(geom); + return os; +} + +#endif // BOOST_GEOMETRY_IO_WKT_STREAM_HPP diff --git a/boost/geometry/io/wkt/wkt.hpp b/boost/geometry/io/wkt/wkt.hpp new file mode 100644 index 0000000000..28bd1e42aa --- /dev/null +++ b/boost/geometry/io/wkt/wkt.hpp @@ -0,0 +1,25 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_WKT_WKT_HPP +#define BOOST_GEOMETRY_IO_WKT_WKT_HPP + +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/io/wkt/write.hpp> + +// BSG 2011-02-03 +// We don't include stream.hpp by default. That tries to stream anything not known +// by default (such as ttmath) and reports errors. +// Users can include stream.hpp themselves (if they want to) + +#endif // BOOST_GEOMETRY_IO_WKT_WKT_HPP diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp new file mode 100644 index 0000000000..a3e3173d05 --- /dev/null +++ b/boost/geometry/io/wkt/write.hpp @@ -0,0 +1,376 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_IO_WKT_WRITE_HPP +#define BOOST_GEOMETRY_IO_WKT_WRITE_HPP + +#include <ostream> +#include <string> + +#include <boost/array.hpp> +#include <boost/concept/assert.hpp> +#include <boost/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/convert.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/geometries/ring.hpp> + +#include <boost/geometry/io/wkt/detail/prefix.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +template <typename P, int I, int Count> +struct stream_coordinate +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p) + { + os << (I > 0 ? " " : "") << get<I>(p); + stream_coordinate<P, I + 1, Count>::apply(os, p); + } +}; + +template <typename P, int Count> +struct stream_coordinate<P, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, P const&) + {} +}; + +struct prefix_linestring_par +{ + static inline const char* apply() { return "LINESTRING("; } +}; + +struct prefix_ring_par_par +{ + // Note, double parentheses are intentional, indicating WKT ring begin/end + static inline const char* apply() { return "POLYGON(("; } +}; + +struct opening_parenthesis +{ + static inline const char* apply() { return "("; } +}; + +struct closing_parenthesis +{ + static inline const char* apply() { return ")"; } +}; + +struct double_closing_parenthesis +{ + static inline const char* apply() { return "))"; } +}; + +/*! +\brief Stream points as \ref WKT +*/ +template <typename Point, typename Policy> +struct wkt_point +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p) + { + os << Policy::apply() << "("; + stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p); + os << ")"; + } +}; + +/*! +\brief Stream ranges as WKT +\note policy is used to stream prefix/postfix, enabling derived classes to override this +*/ +template <typename Range, typename PrefixPolicy, typename SuffixPolicy> +struct wkt_range +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range) + { + typedef typename boost::range_iterator<Range const>::type iterator_type; + + bool first = true; + + os << PrefixPolicy::apply(); + + // TODO: check EMPTY here + + for (iterator_type it = boost::begin(range); + it != boost::end(range); + ++it) + { + os << (first ? "" : ","); + stream_coordinate + < + point_type, 0, dimension<point_type>::type::value + >::apply(os, *it); + first = false; + } + + os << SuffixPolicy::apply(); + } + +private: + typedef typename boost::range_value<Range>::type point_type; +}; + +/*! +\brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4) +\note Used in polygon, all multi-geometries +*/ +template <typename Range> +struct wkt_sequence + : wkt_range + < + Range, + opening_parenthesis, + closing_parenthesis + > +{}; + +template <typename Polygon, typename PrefixPolicy> +struct wkt_poly +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Polygon const& poly) + { + typedef typename ring_type<Polygon const>::type ring; + + os << PrefixPolicy::apply(); + // TODO: check EMPTY here + os << "("; + wkt_sequence<ring>::apply(os, exterior_ring(poly)); + + typename interior_return_type<Polygon const>::type rings + = interior_rings(poly); + for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + { + os << ","; + wkt_sequence<ring>::apply(os, *it); + } + os << ")"; + } +}; + +template <typename Box> +struct wkt_box +{ + typedef typename point_type<Box>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Box const& box) + { + // Convert to ring, then stream + typedef model::ring<point_type> ring_type; + ring_type ring; + geometry::convert(box, ring); + os << "POLYGON("; + wkt_sequence<ring_type>::apply(os, ring); + os << ")"; + } + + private: + + inline wkt_box() + { + // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! + //assert_dimension<B, 2>(); + } +}; + + +template <typename Segment> +struct wkt_segment +{ + typedef typename point_type<Segment>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Segment const& segment) + { + // Convert to two points, then stream + typedef boost::array<point_type, 2> sequence; + + sequence points; + geometry::detail::assign_point_from_index<0>(segment, points[0]); + geometry::detail::assign_point_from_index<1>(segment, points[1]); + + // In Boost.Geometry a segment is represented + // in WKT-format like (for 2D): LINESTRING(x y,x y) + os << "LINESTRING"; + wkt_sequence<sequence>::apply(os, points); + } + + private: + + inline wkt_segment() + {} +}; + +}} // namespace detail::wkt +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Tag, typename Geometry> +struct wkt +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + +template <typename Point> +struct wkt<point_tag, Point> + : detail::wkt::wkt_point + < + Point, + detail::wkt::prefix_point + > +{}; + +template <typename Linestring> +struct wkt<linestring_tag, Linestring> + : detail::wkt::wkt_range + < + Linestring, + detail::wkt::prefix_linestring_par, + detail::wkt::closing_parenthesis + > +{}; + +/*! +\brief Specialization to stream a box as WKT +\details A "box" does not exist in WKT. +It is therefore streamed as a polygon +*/ +template <typename Box> +struct wkt<box_tag, Box> + : detail::wkt::wkt_box<Box> +{}; + +template <typename Segment> +struct wkt<segment_tag, Segment> + : detail::wkt::wkt_segment<Segment> +{}; + +/*! +\brief Specialization to stream a ring as WKT +\details A ring or "linear_ring" does not exist in WKT. +A ring is equivalent to a polygon without inner rings +It is therefore streamed as a polygon +*/ +template <typename Ring> +struct wkt<ring_tag, Ring> + : detail::wkt::wkt_range + < + Ring, + detail::wkt::prefix_ring_par_par, + detail::wkt::double_closing_parenthesis + > +{}; + +/*! +\brief Specialization to stream polygon as WKT +*/ +template <typename Polygon> +struct wkt<polygon_tag, Polygon> + : detail::wkt::wkt_poly + < + Polygon, + detail::wkt::prefix_polygon + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +/*! +\brief Generic geometry template manipulator class, takes corresponding output class from traits class +\ingroup wkt +\details Stream manipulator, streams geometry classes as \ref WKT streams +\par Example: +Small example showing how to use the wkt class +\dontinclude doxygen_1.cpp +\skip example_as_wkt_point +\line { +\until } +*/ +template <typename Geometry> +class wkt_manipulator +{ +public: + + inline wkt_manipulator(Geometry const& g) + : m_geometry(g) + {} + + template <typename Char, typename Traits> + inline friend std::basic_ostream<Char, Traits>& operator<<( + std::basic_ostream<Char, Traits>& os, + wkt_manipulator const& m) + { + dispatch::wkt + < + typename tag<Geometry>::type, + Geometry + >::apply(os, m.m_geometry); + os.flush(); + return os; + } + +private: + Geometry const& m_geometry; +}; + +/*! +\brief Main WKT-streaming function +\ingroup wkt +\par Example: +Small example showing how to use the wkt helper function +\dontinclude doxygen_1.cpp +\skip example_as_wkt_vector +\line { +\until } +*/ +template <typename Geometry> +inline wkt_manipulator<Geometry> wkt(Geometry const& geometry) +{ + concept::check<Geometry const>(); + + return wkt_manipulator<Geometry>(geometry); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP diff --git a/boost/geometry/iterators/base.hpp b/boost/geometry/iterators/base.hpp new file mode 100644 index 0000000000..1e824654e6 --- /dev/null +++ b/boost/geometry/iterators/base.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_ITERATORS_BASE_HPP +#define BOOST_GEOMETRY_ITERATORS_BASE_HPP + +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_adaptor.hpp> +#include <boost/iterator/iterator_categories.hpp> +#include <boost/mpl/if.hpp> + +#ifndef DOXYGEN_NO_DETAIL +namespace boost { namespace geometry { namespace detail { namespace iterators +{ + +template +< + typename DerivedClass, + typename Iterator, + typename TraversalFlag = boost::bidirectional_traversal_tag +> +struct iterator_base + : public boost::iterator_adaptor + < + DerivedClass, + Iterator, + boost::use_default, + typename boost::mpl::if_ + < + boost::is_convertible + < + typename boost::iterator_traversal<Iterator>::type, + boost::random_access_traversal_tag + >, + TraversalFlag, + boost::use_default + >::type + > +{ + // Define operator cast to Iterator to be able to write things like Iterator it = myit++ + inline operator Iterator() const + { + return this->base(); + } + + /*inline bool operator==(Iterator const& other) const + { + return this->base() == other; + } + inline bool operator!=(Iterator const& other) const + { + return ! operator==(other); + }*/ +}; + +}}}} // namespace boost::geometry::detail::iterators +#endif + + +#endif // BOOST_GEOMETRY_ITERATORS_BASE_HPP diff --git a/boost/geometry/iterators/closing_iterator.hpp b/boost/geometry/iterators/closing_iterator.hpp new file mode 100644 index 0000000000..7cd8fa0150 --- /dev/null +++ b/boost/geometry/iterators/closing_iterator.hpp @@ -0,0 +1,157 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_ITERATORS_CLOSING_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_CLOSING_ITERATOR_HPP + +#include <boost/range.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/iterator_categories.hpp> + + + +namespace boost { namespace geometry +{ + +/*! +\brief Iterator which iterates through a range, but adds first element at end of the range +\tparam Range range on which this class is based on +\ingroup iterators +\note Use with "closing_iterator<Range> or "closing_iterator<Range const> + to get non-const / const behaviour +\note This class is normally used from "closeable_view" if Close==true +*/ +template <typename Range> +struct closing_iterator + : public boost::iterator_facade + < + closing_iterator<Range>, + typename boost::range_value<Range>::type const, + boost::random_access_traversal_tag + > +{ + /// Constructor including the range it is based on + explicit inline closing_iterator(Range& range) + : m_range(&range) + , m_iterator(boost::begin(range)) + , m_end(boost::end(range)) + , m_size(boost::size(range)) + , m_index(0) + {} + + /// Constructor to indicate the end of a range + explicit inline closing_iterator(Range& range, bool) + : m_range(&range) + , m_iterator(boost::end(range)) + , m_end(boost::end(range)) + , m_size(boost::size(range)) + , m_index(m_size + 1) + {} + + /// Default constructor + explicit inline closing_iterator() + : m_range(NULL) + , m_size(0) + , m_index(0) + {} + + inline closing_iterator<Range>& operator=(closing_iterator<Range> const& source) + { + m_range = source.m_range; + m_iterator = source.m_iterator; + m_end = source.m_end; + m_size = source.m_size; + m_index = source.m_index; + return *this; + } + + typedef std::ptrdiff_t difference_type; + +private: + friend class boost::iterator_core_access; + + inline typename boost::range_value<Range>::type const& dereference() const + { + return *m_iterator; + } + + inline difference_type distance_to(closing_iterator<Range> const& other) const + { + return other.m_index - this->m_index; + } + + inline bool equal(closing_iterator<Range> const& other) const + { + return this->m_range == other.m_range + && this->m_index == other.m_index; + } + + inline void increment() + { + if (++m_index < m_size) + { + ++m_iterator; + } + else + { + update_iterator(); + } + } + + inline void decrement() + { + if (m_index-- < m_size) + { + --m_iterator; + } + else + { + update_iterator(); + } + } + + inline void advance(difference_type n) + { + if (m_index < m_size && m_index + n < m_size) + { + m_index += n; + m_iterator += n; + } + else + { + m_index += n; + update_iterator(); + } + } + + inline void update_iterator() + { + this->m_iterator = m_index <= m_size + ? boost::begin(*m_range) + (m_index % m_size) + : boost::end(*m_range) + ; + } + + Range* m_range; + typename boost::range_iterator<Range>::type m_iterator; + typename boost::range_iterator<Range>::type m_end; + difference_type m_size; + difference_type m_index; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_CLOSING_ITERATOR_HPP diff --git a/boost/geometry/iterators/ever_circling_iterator.hpp b/boost/geometry/iterators/ever_circling_iterator.hpp new file mode 100644 index 0000000000..03921096e7 --- /dev/null +++ b/boost/geometry/iterators/ever_circling_iterator.hpp @@ -0,0 +1,164 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_ITERATORS_EVER_CIRCLING_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP + +#include <boost/range.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_adaptor.hpp> +#include <boost/iterator/iterator_categories.hpp> + +#include <boost/geometry/iterators/base.hpp> + +namespace boost { namespace geometry +{ + +/*! + \brief Iterator which ever circles through a range + \tparam Iterator iterator on which this class is based on + \ingroup iterators + \details If the iterator arrives at range.end() it restarts from the + beginning. So it has to be stopped in another way. + Don't call for(....; it++) because it will turn in an endless loop + \note Name inspired on David Bowie's + "Chant Of The Ever Circling Skeletal Family" +*/ +template <typename Iterator> +struct ever_circling_iterator : + public detail::iterators::iterator_base + < + ever_circling_iterator<Iterator>, + Iterator + > +{ + friend class boost::iterator_core_access; + + explicit inline ever_circling_iterator(Iterator begin, Iterator end, + bool skip_first = false) + : m_begin(begin) + , m_end(end) + , m_skip_first(skip_first) + { + this->base_reference() = begin; + } + + explicit inline ever_circling_iterator(Iterator begin, Iterator end, Iterator start, + bool skip_first = false) + : m_begin(begin) + , m_end(end) + , m_skip_first(skip_first) + { + this->base_reference() = start; + } + + /// Navigate to a certain position, should be in [start .. end], if at end + /// it will circle again. + inline void moveto(Iterator it) + { + this->base_reference() = it; + check_end(); + } + +private: + + inline void increment(bool possibly_skip = true) + { + (this->base_reference())++; + check_end(possibly_skip); + } + + inline void check_end(bool possibly_skip = true) + { + if (this->base() == this->m_end) + { + this->base_reference() = this->m_begin; + if (m_skip_first && possibly_skip) + { + increment(false); + } + } + } + + Iterator m_begin; + Iterator m_end; + bool m_skip_first; +}; + + + +template <typename Range> +class ever_circling_range_iterator + : public boost::iterator_adaptor + < + ever_circling_range_iterator<Range>, + typename boost::range_iterator<Range>::type + > +{ +public : + typedef typename boost::range_iterator<Range>::type iterator_type; + + explicit inline ever_circling_range_iterator(Range& range, + bool skip_first = false) + : m_range(range) + , m_skip_first(skip_first) + { + this->base_reference() = boost::begin(m_range); + } + + explicit inline ever_circling_range_iterator(Range& range, iterator_type start, + bool skip_first = false) + : m_range(range) + , m_skip_first(skip_first) + { + this->base_reference() = start; + } + + /// Navigate to a certain position, should be in [start .. end], if at end + /// it will circle again. + inline void moveto(iterator_type it) + { + this->base_reference() = it; + check_end(); + } + +private: + + friend class boost::iterator_core_access; + + inline void increment(bool possibly_skip = true) + { + (this->base_reference())++; + check_end(possibly_skip); + } + + inline void check_end(bool possibly_skip = true) + { + if (this->base_reference() == boost::end(m_range)) + { + this->base_reference() = boost::begin(m_range); + if (m_skip_first && possibly_skip) + { + increment(false); + } + } + } + + Range& m_range; + bool m_skip_first; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP diff --git a/boost/geometry/multi/algorithms/append.hpp b/boost/geometry/multi/algorithms/append.hpp new file mode 100644 index 0000000000..e72be036ae --- /dev/null +++ b/boost/geometry/multi/algorithms/append.hpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_APPEND_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP + +#include <boost/geometry/algorithms/append.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +namespace splitted_dispatch +{ + +template <typename Geometry, typename Point> +struct append_point<multi_point_tag, Geometry, Point> + : detail::append::append_point<Geometry, Point> +{}; + +template <typename Geometry, typename Range> +struct append_range<multi_point_tag, Geometry, Range> + : detail::append::append_range<Geometry, Range> +{}; + +} + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP diff --git a/boost/geometry/multi/algorithms/area.hpp b/boost/geometry/multi/algorithms/area.hpp new file mode 100644 index 0000000000..6695686358 --- /dev/null +++ b/boost/geometry/multi/algorithms/area.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_AREA_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/area.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ +template <typename MultiGeometry, typename Strategy> +struct area<MultiGeometry, Strategy, multi_polygon_tag> + : detail::multi_sum + < + typename Strategy::return_type, + MultiGeometry, + Strategy, + area + < + typename boost::range_value<MultiGeometry>::type, + Strategy, + polygon_tag + > + > +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP diff --git a/boost/geometry/multi/algorithms/centroid.hpp b/boost/geometry/multi/algorithms/centroid.hpp new file mode 100644 index 0000000000..855ed22fda --- /dev/null +++ b/boost/geometry/multi/algorithms/centroid.hpp @@ -0,0 +1,178 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_CENTROID_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/centroid.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace centroid +{ + + +/*! + \brief Building block of a multi-point, to be used as Policy in the + more generec centroid_multi +*/ +template +< + typename Point, + typename Strategy +> +struct centroid_multi_point_state +{ + static inline void apply(Point const& point, + Strategy const& strategy, typename Strategy::state_type& state) + { + strategy.apply(point, state); + } +}; + + + +/*! + \brief Generic implementation which calls a policy to calculate the + centroid of the total of its single-geometries + \details The Policy is, in general, the single-version, with state. So + detail::centroid::centroid_polygon_state is used as a policy for this + detail::centroid::centroid_multi + +*/ +template +< + typename Multi, + typename Point, + typename Strategy, + typename Policy +> +struct centroid_multi +{ + static inline void apply(Multi const& multi, Point& centroid, + Strategy const& strategy) + { +#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) + // If there is nothing in any of the ranges, it is not possible + // to calculate the centroid + if (geometry::num_points(multi) == 0) + { + throw centroid_exception(); + } +#endif + + typename Strategy::state_type state; + + for (typename boost::range_iterator<Multi const>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it, strategy, state); + } + Strategy::result(state, centroid); + } +}; + + + +}} // namespace detail::centroid +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename MultiLinestring, + typename Point, + typename Strategy +> +struct centroid<multi_linestring_tag, MultiLinestring, Point, Strategy> + : detail::centroid::centroid_multi + < + MultiLinestring, + Point, + Strategy, + detail::centroid::centroid_range_state + < + typename boost::range_value<MultiLinestring>::type, + closed, + Strategy + > + > +{}; + +template +< + typename MultiPolygon, + typename Point, + typename Strategy +> +struct centroid<multi_polygon_tag, MultiPolygon, Point, Strategy> + : detail::centroid::centroid_multi + < + MultiPolygon, + Point, + Strategy, + detail::centroid::centroid_polygon_state + < + typename boost::range_value<MultiPolygon>::type, + Strategy + > + > +{}; + + +template +< + typename MultiPoint, + typename Point, + typename Strategy +> +struct centroid<multi_point_tag, MultiPoint, Point, Strategy> + : detail::centroid::centroid_multi + < + MultiPoint, + Point, + Strategy, + detail::centroid::centroid_multi_point_state + < + typename boost::range_value<MultiPoint>::type, + Strategy + > + > +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP + diff --git a/boost/geometry/multi/algorithms/clear.hpp b/boost/geometry/multi/algorithms/clear.hpp new file mode 100644 index 0000000000..0b14b6ce9c --- /dev/null +++ b/boost/geometry/multi/algorithms/clear.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_CLEAR_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP + + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/algorithms/clear.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Geometry> +struct clear<Geometry, multi_tag> + : detail::clear::collection_clear<Geometry> +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP diff --git a/boost/geometry/multi/algorithms/convert.hpp b/boost/geometry/multi/algorithms/convert.hpp new file mode 100644 index 0000000000..4745791135 --- /dev/null +++ b/boost/geometry/multi/algorithms/convert.hpp @@ -0,0 +1,128 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_CONVERT_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/convert.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace conversion +{ + +template <typename Single, typename Multi, typename Policy> +struct single_to_multi: private Policy +{ + static inline void apply(Single const& single, Multi& multi) + { + traits::resize<Multi>::apply(multi, 1); + Policy::apply(single, *boost::begin(multi)); + } +}; + + + +template <typename Multi1, typename Multi2, typename Policy> +struct multi_to_multi: private Policy +{ + static inline void apply(Multi1 const& multi1, Multi2& multi2) + { + traits::resize<Multi2>::apply(multi2, boost::size(multi1)); + + typename boost::range_iterator<Multi1 const>::type it1 + = boost::begin(multi1); + typename boost::range_iterator<Multi2>::type it2 + = boost::begin(multi2); + + for (; it1 != boost::end(multi1); ++it1, ++it2) + { + Policy::apply(*it1, *it2); + } + } +}; + + +}} // namespace detail::convert +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// Dispatch for multi <-> multi, specifying their single-version as policy. +// Note that, even if the multi-types are mutually different, their single +// version types might be the same and therefore we call boost::is_same again + +template <typename Multi1, typename Multi2, std::size_t DimensionCount> +struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false> + : detail::conversion::multi_to_multi + < + Multi1, + Multi2, + convert + < + typename boost::range_value<Multi1>::type, + typename boost::range_value<Multi2>::type, + typename single_tag_of + < + typename tag<Multi1>::type + >::type, + typename single_tag_of + < + typename tag<Multi2>::type + >::type, + DimensionCount + > + > +{}; + +template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount> +struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false> + : detail::conversion::single_to_multi + < + Single, + Multi, + convert + < + Single, + typename boost::range_value<Multi>::type, + typename tag<Single>::type, + typename single_tag_of + < + typename tag<Multi>::type + >::type, + DimensionCount, + false + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP diff --git a/boost/geometry/multi/algorithms/correct.hpp b/boost/geometry/multi/algorithms/correct.hpp new file mode 100644 index 0000000000..d0c3e10753 --- /dev/null +++ b/boost/geometry/multi/algorithms/correct.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_CORRECT_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/correct.hpp> +#include <boost/geometry/multi/algorithms/detail/modify.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiPoint> +struct correct<MultiPoint, multi_point_tag> + : detail::correct::correct_nop<MultiPoint> +{}; + + +template <typename MultiLineString> +struct correct<MultiLineString, multi_linestring_tag> + : detail::correct::correct_nop<MultiLineString> +{}; + + +template <typename Geometry> +struct correct<Geometry, multi_polygon_tag> + : detail::multi_modify + < + Geometry, + detail::correct::correct_polygon + < + typename boost::range_value<Geometry>::type + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP diff --git a/boost/geometry/multi/algorithms/covered_by.hpp b/boost/geometry/multi/algorithms/covered_by.hpp new file mode 100644 index 0000000000..ba398c0f42 --- /dev/null +++ b/boost/geometry/multi/algorithms/covered_by.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_COVERED_BY_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP + + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/multi/core/closure.hpp> +#include <boost/geometry/multi/core/point_order.hpp> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/algorithms/within.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Point, typename MultiPolygon> +struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag> +{ + template <typename Strategy> + static inline bool apply(Point const& point, + MultiPolygon const& multi_polygon, Strategy const& strategy) + { + return detail::within::geometry_multi_within_code + < + Point, + MultiPolygon, + Strategy, + detail::within::point_in_polygon + < + Point, + typename boost::range_value<MultiPolygon>::type, + order_as_direction + < + geometry::point_order<MultiPolygon>::value + >::value, + geometry::closure<MultiPolygon>::value, + Strategy + > + >::apply(point, multi_polygon, strategy) >= 0; + } +}; + + +} // namespace dispatch + + +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP diff --git a/boost/geometry/multi/algorithms/detail/for_each_range.hpp b/boost/geometry/multi/algorithms/detail/for_each_range.hpp new file mode 100644 index 0000000000..08ab14bd69 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/for_each_range.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP + + +#include <boost/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/detail/for_each_range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace for_each +{ + + +template <typename Multi, typename Actor, bool IsConst> +struct fe_range_multi +{ + static inline void apply( + typename add_const_if_c<IsConst, Multi>::type& multi, + Actor& actor) + { + for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it) + { + geometry::detail::for_each_range(*it, actor); + } + } +}; + + + +}} // namespace detail::for_each +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPoint, typename Actor, bool IsConst> +struct for_each_range<multi_point_tag, MultiPoint, Actor, IsConst> + : detail::for_each::fe_range_range<MultiPoint, Actor, IsConst> +{}; + +template <typename Geometry, typename Actor, bool IsConst> +struct for_each_range<multi_linestring_tag, Geometry, Actor, IsConst> + : + detail::for_each::fe_range_multi<Geometry, Actor, IsConst> +{}; + +template <typename Geometry, typename Actor, bool IsConst> +struct for_each_range<multi_polygon_tag, Geometry, Actor, IsConst> + : + detail::for_each::fe_range_multi<Geometry, Actor, IsConst> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP diff --git a/boost/geometry/multi/algorithms/detail/modify.hpp b/boost/geometry/multi/algorithms/detail/modify.hpp new file mode 100644 index 0000000000..b52efd2512 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/modify.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_MODIFY_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_HPP + + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename MultiGeometry, typename Policy> +struct multi_modify +{ + static inline void apply(MultiGeometry& multi) + { + typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; + for (iterator_type it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it); + } + } +}; + + +} // namespace detail +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_HPP diff --git a/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp b/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp new file mode 100644 index 0000000000..4ae79058da --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_MODIFY_WITH_PREDICATE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_WITH_PREDICATE_HPP + + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename MultiGeometry, typename Predicate, typename Policy> +struct multi_modify_with_predicate +{ + static inline void apply(MultiGeometry& multi, Predicate const& predicate) + { + typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; + for (iterator_type it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it, predicate); + } + } +}; + + +} // namespace detail +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_WITH_PREDICATE_HPP diff --git a/boost/geometry/multi/algorithms/detail/multi_sum.hpp b/boost/geometry/multi/algorithms/detail/multi_sum.hpp new file mode 100644 index 0000000000..a47685ceb1 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/multi_sum.hpp @@ -0,0 +1,58 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_SUM_HPP +#define BOOST_GEOMETRY_MULTI_SUM_HPP + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +< + typename ReturnType, + typename MultiGeometry, + typename Strategy, + typename Policy +> +struct multi_sum +{ + static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy) + { + ReturnType sum = ReturnType(); + for (typename boost::range_iterator + < + MultiGeometry const + >::type it = boost::begin(geometry); + it != boost::end(geometry); + ++it) + { + sum += Policy::apply(*it, strategy); + } + return sum; + } +}; + + +} // namespace detail +#endif + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_SUM_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp new file mode 100644 index 0000000000..1093a84569 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp @@ -0,0 +1,101 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace copy_segments +{ + + +template +< + typename MultiGeometry, + typename SegmentIdentifier, + typename PointOut, + typename Policy +> +struct copy_segment_point_multi +{ + static inline bool apply(MultiGeometry const& multi, + SegmentIdentifier const& seg_id, bool second, + PointOut& point) + { + + BOOST_ASSERT + ( + seg_id.multi_index >= 0 + && seg_id.multi_index < boost::size(multi) + ); + + // Call the single-version + return Policy::apply(multi[seg_id.multi_index], seg_id, second, point); + } +}; + + +}} // namespace detail::copy_segments +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename MultiGeometry, + bool Reverse, + typename SegmentIdentifier, + typename PointOut +> +struct copy_segment_point + < + multi_polygon_tag, + MultiGeometry, + Reverse, + SegmentIdentifier, + PointOut + > + : detail::copy_segments::copy_segment_point_multi + < + MultiGeometry, + SegmentIdentifier, + PointOut, + detail::copy_segments::copy_segment_point_polygon + < + typename boost::range_value<MultiGeometry>::type, + Reverse, + SegmentIdentifier, + PointOut + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp new file mode 100644 index 0000000000..a234e240da --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp @@ -0,0 +1,104 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP + + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> + +#include <boost/geometry/multi/core/ring_type.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace copy_segments +{ + + +template +< + typename MultiGeometry, + typename SegmentIdentifier, + typename RangeOut, + typename Policy +> +struct copy_segments_multi +{ + static inline void apply(MultiGeometry const& multi_geometry, + SegmentIdentifier const& seg_id, int to_index, + RangeOut& current_output) + { + + BOOST_ASSERT + ( + seg_id.multi_index >= 0 + && seg_id.multi_index < boost::size(multi_geometry) + ); + + // Call the single-version + Policy::apply(multi_geometry[seg_id.multi_index], + seg_id, to_index, current_output); + } +}; + + +}} // namespace detail::copy_segments +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename MultiPolygon, + bool Reverse, + typename SegmentIdentifier, + typename RangeOut +> +struct copy_segments + < + multi_polygon_tag, + MultiPolygon, + Reverse, + SegmentIdentifier, + RangeOut + > + : detail::copy_segments::copy_segments_multi + < + MultiPolygon, + SegmentIdentifier, + RangeOut, + detail::copy_segments::copy_segments_polygon + < + typename boost::range_value<MultiPolygon>::type, + Reverse, + SegmentIdentifier, + RangeOut + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp new file mode 100644 index 0000000000..8cdd7ed970 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp @@ -0,0 +1,54 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP + + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/multi/core/ring_type.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +template<> +struct get_ring<multi_polygon_tag> +{ + template<typename MultiPolygon> + static inline typename ring_type<MultiPolygon>::type const& apply( + ring_identifier const& id, + MultiPolygon const& multi_polygon) + { + BOOST_ASSERT + ( + id.multi_index >= 0 + && id.multi_index < boost::size(multi_polygon) + ); + return get_ring<polygon_tag>::apply(id, + multi_polygon[id.multi_index]); + } +}; + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp new file mode 100644 index 0000000000..1ee03cc4d0 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP + + +#include <boost/geometry/multi/core/ring_type.hpp> + +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> + +#include <boost/geometry/multi/algorithms/distance.hpp> +#include <boost/geometry/multi/views/detail/range_type.hpp> + +#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace get_turns +{ + +template +< + typename Multi, typename Box, + bool Reverse, bool ReverseBox, + typename Turns, + typename TurnPolicy, + typename InterruptPolicy +> +struct get_turns_multi_polygon_cs +{ + static inline void apply( + int source_id1, Multi const& multi, + int source_id2, Box const& box, + Turns& turns, InterruptPolicy& interrupt_policy) + { + typedef typename boost::range_iterator + < + Multi const + >::type iterator_type; + + int i = 0; + for (iterator_type it = boost::begin(multi); + it != boost::end(multi); + ++it, ++i) + { + // Call its single version + get_turns_polygon_cs + < + typename boost::range_value<Multi>::type, Box, + Reverse, ReverseBox, + Turns, TurnPolicy, InterruptPolicy + >::apply(source_id1, *it, source_id2, box, + turns, interrupt_policy, i); + } + } +}; + +}} // namespace detail::get_turns +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename MultiPolygon, + typename Box, + bool ReverseMultiPolygon, bool ReverseBox, + typename Turns, + typename TurnPolicy, + typename InterruptPolicy +> +struct get_turns + < + multi_polygon_tag, box_tag, + MultiPolygon, Box, + ReverseMultiPolygon, ReverseBox, + Turns, + TurnPolicy, InterruptPolicy + > + : detail::get_turns::get_turns_multi_polygon_cs + < + MultiPolygon, Box, + ReverseMultiPolygon, ReverseBox, + Turns, + TurnPolicy, InterruptPolicy + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp new file mode 100644 index 0000000000..4636187880 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +namespace dispatch +{ + + template <typename Multi> + struct select_rings<multi_polygon_tag, Multi> + { + template <typename Geometry, typename Map> + static inline void apply(Multi const& multi, Geometry const& geometry, + ring_identifier id, Map& map, bool midpoint) + { + typedef typename boost::range_iterator + < + Multi const + >::type iterator_type; + + typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon; + + id.multi_index = 0; + for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) + { + id.ring_index = -1; + per_polygon::apply(*it, geometry, id, map, midpoint); + id.multi_index++; + } + } + }; +} + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp new file mode 100644 index 0000000000..57d5ff92ca --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp @@ -0,0 +1,56 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP + + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename MultiPolygon, + typename Turns, + typename TurnPolicy, + typename InterruptPolicy +> +struct self_get_turn_points + < + multi_polygon_tag, MultiPolygon, + Turns, + TurnPolicy, InterruptPolicy + > + : detail::self_get_turn_points::get_turns + < + MultiPolygon, + Turns, + TurnPolicy, + InterruptPolicy + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP diff --git a/boost/geometry/multi/algorithms/detail/point_on_border.hpp b/boost/geometry/multi/algorithms/detail/point_on_border.hpp new file mode 100644 index 0000000000..04d76422c6 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/point_on_border.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_on_border +{ + + +template +< + typename MultiGeometry, + typename Point, + typename Policy +> +struct point_on_multi +{ + static inline bool apply(MultiGeometry const& multi, Point& point) + { + // Take a point on the first multi-geometry + // (i.e. the first that is not empty) + for (typename boost::range_iterator + < + MultiGeometry const + >::type it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + if (Policy::apply(*it, point)) + { + return true; + } + } + return false; + } +}; + + + + +}} // namespace detail::point_on_border +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template<typename Multi, typename Point> +struct point_on_border<multi_polygon_tag, Multi, Point> + : detail::point_on_border::point_on_multi + < + Multi, + Point, + detail::point_on_border::point_on_polygon + < + typename boost::range_value<Multi>::type, + Point + > + > +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP diff --git a/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp new file mode 100644 index 0000000000..cf4bf5d83b --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp @@ -0,0 +1,90 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP + + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/ring_type.hpp> +#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace section +{ + + +template +< + typename MultiGeometry, + typename Section, + typename Policy +> +struct full_section_multi +{ + static inline typename ring_return_type<MultiGeometry const>::type apply( + MultiGeometry const& multi, Section const& section) + { + BOOST_ASSERT + ( + section.ring_id.multi_index >= 0 + && section.ring_id.multi_index < boost::size(multi) + ); + + return Policy::apply(multi[section.ring_id.multi_index], section); + } +}; + + +}} // namespace detail::section +#endif + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPolygon, typename Section> +struct range_by_section<multi_polygon_tag, MultiPolygon, Section> + : detail::section::full_section_multi + < + MultiPolygon, + Section, + detail::section::full_section_polygon + < + typename boost::range_value<MultiPolygon>::type, + Section + > + > +{}; + + +} // namespace dispatch +#endif + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP diff --git a/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp new file mode 100644 index 0000000000..16f70c193d --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP + +#include <cstddef> +#include <vector> + +#include <boost/concept/requires.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace sectionalize +{ + + +template <typename MultiGeometry, typename Sections, std::size_t DimensionCount, typename Policy> +struct sectionalize_multi +{ + static inline void apply(MultiGeometry const& multi, Sections& sections, ring_identifier ring_id) + { + ring_id.multi_index = 0; + for (typename boost::range_iterator<MultiGeometry const>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it, ++ring_id.multi_index) + { + Policy::apply(*it, sections, ring_id); + } + } +}; + + +}} // namespace detail::sectionalize +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename MultiPolygon, + bool Reverse, + typename Sections, + std::size_t DimensionCount, + std::size_t MaxCount +> +struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, Sections, DimensionCount, MaxCount> + : detail::sectionalize::sectionalize_multi + < + MultiPolygon, + Sections, + DimensionCount, + detail::sectionalize::sectionalize_polygon + < + typename boost::range_value<MultiPolygon>::type, + Reverse, + Sections, + DimensionCount, + MaxCount + > + > + +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP diff --git a/boost/geometry/multi/algorithms/distance.hpp b/boost/geometry/multi/algorithms/distance.hpp new file mode 100644 index 0000000000..8acb3f9006 --- /dev/null +++ b/boost/geometry/multi/algorithms/distance.hpp @@ -0,0 +1,157 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_DISTANCE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_HPP + + +#include <boost/numeric/conversion/bounds.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/geometry_id.hpp> +#include <boost/geometry/multi/core/point_type.hpp> + +#include <boost/geometry/algorithms/distance.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template<typename Geometry, typename MultiGeometry, typename Strategy> +struct distance_single_to_multi + : private dispatch::distance + < + Geometry, + typename range_value<MultiGeometry>::type, + Strategy + > +{ + typedef typename strategy::distance::services::return_type<Strategy>::type return_type; + + static inline return_type apply(Geometry const& geometry, + MultiGeometry const& multi, + Strategy const& strategy) + { + return_type mindist = return_type(); + bool first = true; + + for(typename range_iterator<MultiGeometry const>::type it = boost::begin(multi); + it != boost::end(multi); + ++it, first = false) + { + return_type dist = dispatch::distance + < + Geometry, + typename range_value<MultiGeometry>::type, + Strategy + >::apply(geometry, *it, strategy); + + if (first || dist < mindist) + { + mindist = dist; + } + } + + return mindist; + } +}; + +template<typename Multi1, typename Multi2, typename Strategy> +struct distance_multi_to_multi + : private distance_single_to_multi + < + typename range_value<Multi1>::type, + Multi2, + Strategy + > +{ + typedef typename strategy::distance::services::return_type<Strategy>::type return_type; + + static inline return_type apply(Multi1 const& multi1, + Multi2 const& multi2, Strategy const& strategy) + { + return_type mindist = return_type(); + bool first = true; + + for(typename range_iterator<Multi1 const>::type it = boost::begin(multi1); + it != boost::end(multi1); + ++it, first = false) + { + return_type dist = distance_single_to_multi + < + typename range_value<Multi1>::type, + Multi2, + Strategy + >::apply(*it, multi2, strategy); + if (first || dist < mindist) + { + mindist = dist; + } + } + + return mindist; + } +}; + + +}} // namespace detail::distance +#endif + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename G1, + typename G2, + typename Strategy, + typename SingleGeometryTag +> +struct distance +< + G1, G2, Strategy, + SingleGeometryTag, multi_tag, strategy_tag_distance_point_point, + false +> + : detail::distance::distance_single_to_multi<G1, G2, Strategy> +{}; + +template <typename G1, typename G2, typename Strategy> +struct distance +< + G1, G2, Strategy, + multi_tag, multi_tag, strategy_tag_distance_point_point, + false +> + : detail::distance::distance_multi_to_multi<G1, G2, Strategy> +{}; + +} // namespace dispatch +#endif + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_HPP diff --git a/boost/geometry/multi/algorithms/envelope.hpp b/boost/geometry/multi/algorithms/envelope.hpp new file mode 100644 index 0000000000..1876b5f91e --- /dev/null +++ b/boost/geometry/multi/algorithms/envelope.hpp @@ -0,0 +1,117 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_ENVELOPE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP + +#include <vector> + +#include <boost/range/metafunctions.hpp> + + +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/algorithms/envelope.hpp> + +#include <boost/geometry/multi/core/point_type.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail { namespace envelope +{ + + +template<typename MultiLinestring, typename Box> +struct envelope_multi_linestring +{ + static inline void apply(MultiLinestring const& mp, Box& mbr) + { + assign_inverse(mbr); + for (typename boost::range_iterator<MultiLinestring const>::type + it = mp.begin(); + it != mp.end(); + ++it) + { + envelope_range_additional(*it, mbr); + } + } +}; + + +// version for multi_polygon: outer ring's of all polygons +template<typename MultiPolygon, typename Box> +struct envelope_multi_polygon +{ + static inline void apply(MultiPolygon const& mp, Box& mbr) + { + assign_inverse(mbr); + for (typename boost::range_const_iterator<MultiPolygon>::type + it = mp.begin(); + it != mp.end(); + ++it) + { + envelope_range_additional(exterior_ring(*it), mbr); + } + } +}; + + +}} // namespace detail::envelope + +#endif + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Multi, typename Box, + typename StrategyLess, typename StrategyGreater +> +struct envelope<multi_point_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> + : detail::envelope::envelope_range<Multi, Box> +{}; + +template +< + typename Multi, typename Box, + typename StrategyLess, typename StrategyGreater +> +struct envelope<multi_linestring_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> + : detail::envelope::envelope_multi_linestring<Multi, Box> +{}; + + +template +< + typename Multi, typename Box, + typename StrategyLess, typename StrategyGreater +> +struct envelope<multi_polygon_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> + : detail::envelope::envelope_multi_polygon<Multi, Box> +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP diff --git a/boost/geometry/multi/algorithms/equals.hpp b/boost/geometry/multi/algorithms/equals.hpp new file mode 100644 index 0000000000..a307ebae8b --- /dev/null +++ b/boost/geometry/multi/algorithms/equals.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_EQUALS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP + + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/geometry_id.hpp> + +#include <boost/geometry/algorithms/equals.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPolygon1, typename MultiPolygon2> +struct equals + < + multi_polygon_tag, multi_polygon_tag, + MultiPolygon1, MultiPolygon2, + 2 + > + : detail::equals::equals_by_collection + < + MultiPolygon1, MultiPolygon2, + detail::equals::area_check + > +{}; + + +template <typename Polygon, typename MultiPolygon> +struct equals + < + polygon_tag, multi_polygon_tag, + Polygon, MultiPolygon, + 2 + > + : detail::equals::equals_by_collection + < + Polygon, MultiPolygon, + detail::equals::area_check + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP + diff --git a/boost/geometry/multi/algorithms/for_each.hpp b/boost/geometry/multi/algorithms/for_each.hpp new file mode 100644 index 0000000000..1be38e0a7e --- /dev/null +++ b/boost/geometry/multi/algorithms/for_each.hpp @@ -0,0 +1,129 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_FOR_EACH_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP + + +#include <boost/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/point_type.hpp> + + +#include <boost/geometry/algorithms/for_each.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace for_each +{ + +// Implementation of multi, for both point and segment, +// just calling the single version. +template +< + typename MultiGeometry, + typename Functor, + bool IsConst, + typename Policy +> +struct for_each_multi +{ + static inline Functor apply( + typename add_const_if_c<IsConst, MultiGeometry>::type& multi, + Functor f) + { + for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it) + { + f = Policy::apply(*it, f); + } + return f; + } +}; + + +}} // namespace detail::for_each +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename MultiGeometry, + typename Functor, + bool IsConst +> +struct for_each_point<multi_tag, MultiGeometry, Functor, IsConst> + : detail::for_each::for_each_multi + < + MultiGeometry, + Functor, + IsConst, + // Specify the dispatch of the single-version as policy + for_each_point + < + typename single_tag_of + < + typename tag<MultiGeometry>::type + >::type, + typename boost::range_value<MultiGeometry>::type, + Functor, + IsConst + > + > +{}; + + +template +< + typename MultiGeometry, + typename Functor, + bool IsConst +> +struct for_each_segment<multi_tag, MultiGeometry, Functor, IsConst> + : detail::for_each::for_each_multi + < + MultiGeometry, + Functor, + IsConst, + // Specify the dispatch of the single-version as policy + for_each_segment + < + typename single_tag_of + < + typename tag<MultiGeometry>::type + >::type, + typename boost::range_value<MultiGeometry>::type, + Functor, + IsConst + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP diff --git a/boost/geometry/multi/algorithms/intersection.hpp b/boost/geometry/multi/algorithms/intersection.hpp new file mode 100644 index 0000000000..31e74a79ba --- /dev/null +++ b/boost/geometry/multi/algorithms/intersection.hpp @@ -0,0 +1,438 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_MULTI_ALGORITHMS_INTERSECTION_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP + + +#include <boost/geometry/multi/core/closure.hpp> +#include <boost/geometry/multi/core/geometry_id.hpp> +#include <boost/geometry/multi/core/is_areal.hpp> +#include <boost/geometry/multi/core/point_order.hpp> +#include <boost/geometry/multi/algorithms/covered_by.hpp> +#include <boost/geometry/multi/algorithms/envelope.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp> +#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> + +#include <boost/geometry/algorithms/intersection.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace intersection +{ + + +template +< + typename MultiLinestring1, typename MultiLinestring2, + typename OutputIterator, typename PointOut, + typename Strategy +> +struct intersection_multi_linestring_multi_linestring_point +{ + static inline OutputIterator apply(MultiLinestring1 const& ml1, + MultiLinestring2 const& ml2, OutputIterator out, + Strategy const& strategy) + { + // Note, this loop is quadratic w.r.t. number of linestrings per input. + // Future Enhancement: first do the sections of each, then intersect. + for (typename boost::range_iterator + < + MultiLinestring1 const + >::type it1 = boost::begin(ml1); + it1 != boost::end(ml1); + ++it1) + { + for (typename boost::range_iterator + < + MultiLinestring2 const + >::type it2 = boost::begin(ml2); + it2 != boost::end(ml2); + ++it2) + { + out = intersection_linestring_linestring_point + < + typename boost::range_value<MultiLinestring1>::type, + typename boost::range_value<MultiLinestring2>::type, + OutputIterator, PointOut, Strategy + >::apply(*it1, *it2, out, strategy); + } + } + + return out; + } +}; + + +template +< + typename Linestring, typename MultiLinestring, + typename OutputIterator, typename PointOut, + typename Strategy +> +struct intersection_linestring_multi_linestring_point +{ + static inline OutputIterator apply(Linestring const& linestring, + MultiLinestring const& ml, OutputIterator out, + Strategy const& strategy) + { + for (typename boost::range_iterator + < + MultiLinestring const + >::type it = boost::begin(ml); + it != boost::end(ml); + ++it) + { + out = intersection_linestring_linestring_point + < + Linestring, + typename boost::range_value<MultiLinestring>::type, + OutputIterator, PointOut, Strategy + >::apply(linestring, *it, out, strategy); + } + + return out; + } +}; + + +// This loop is quite similar to the loop above, but beacuse the iterator +// is second (above) or first (below) argument, it is not trivial to merge them. +template +< + typename MultiLinestring, typename Areal, + bool ReverseAreal, + typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_of_multi_linestring_with_areal +{ + static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal, + OutputIterator out, + Strategy const& strategy) + { + for (typename boost::range_iterator + < + MultiLinestring const + >::type it = boost::begin(ml); + it != boost::end(ml); + ++it) + { + out = intersection_of_linestring_with_areal + < + typename boost::range_value<MultiLinestring>::type, + Areal, ReverseAreal, + OutputIterator, LineStringOut, OverlayType, Strategy + >::apply(*it, areal, out, strategy); + } + + return out; + + } +}; + +// This one calls the one above with reversed arguments +template +< + typename Areal, typename MultiLinestring, + bool ReverseAreal, + typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_of_areal_with_multi_linestring +{ + static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, + OutputIterator out, + Strategy const& strategy) + { + return intersection_of_multi_linestring_with_areal + < + MultiLinestring, Areal, ReverseAreal, + OutputIterator, LineStringOut, + OverlayType, + Strategy + >::apply(ml, areal, out, strategy); + } +}; + + + +template +< + typename MultiLinestring, typename Box, + typename OutputIterator, typename LinestringOut, + typename Strategy +> +struct clip_multi_linestring +{ + static inline OutputIterator apply(MultiLinestring const& multi_linestring, + Box const& box, OutputIterator out, Strategy const& ) + { + typedef typename point_type<LinestringOut>::type point_type; + strategy::intersection::liang_barsky<Box, point_type> lb_strategy; + for (typename boost::range_iterator<MultiLinestring const>::type it + = boost::begin(multi_linestring); + it != boost::end(multi_linestring); ++it) + { + out = detail::intersection::clip_range_with_box + <LinestringOut>(box, *it, out, lb_strategy); + } + return out; + } +}; + + +}} // namespace detail::intersection +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// Linear +template +< + typename MultiLinestring1, typename MultiLinestring2, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + multi_linestring_tag, multi_linestring_tag, point_tag, + false, false, false, + MultiLinestring1, MultiLinestring2, + Reverse1, Reverse2, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_multi_linestring_multi_linestring_point + < + MultiLinestring1, MultiLinestring2, + OutputIterator, GeometryOut, + Strategy + > +{}; + + +template +< + typename Linestring, typename MultiLinestring, + typename OutputIterator, typename GeometryOut, + bool Reverse1, bool Reverse2, bool ReverseOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + linestring_tag, multi_linestring_tag, point_tag, + false, false, false, + Linestring, MultiLinestring, + Reverse1, Reverse2, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_linestring_multi_linestring_point + < + Linestring, MultiLinestring, + OutputIterator, GeometryOut, + Strategy + > +{}; + + +template +< + typename MultiLinestring, typename Box, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + multi_linestring_tag, box_tag, linestring_tag, + false, true, false, + MultiLinestring, Box, + Reverse1, Reverse2, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::clip_multi_linestring + < + MultiLinestring, Box, + OutputIterator, GeometryOut, + Strategy + > +{}; + + +template +< + typename Linestring, typename MultiPolygon, + bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + linestring_tag, multi_polygon_tag, linestring_tag, + false, true, false, + Linestring, MultiPolygon, + ReverseLinestring, ReverseMultiPolygon, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_linestring_with_areal + < + Linestring, MultiPolygon, + ReverseMultiPolygon, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + + +// Derives from areal/mls because runtime arguments are in that order. +// areal/mls reverses it itself to mls/areal +template +< + typename Polygon, typename MultiLinestring, + bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + polygon_tag, multi_linestring_tag, linestring_tag, + true, false, false, + Polygon, MultiLinestring, + ReversePolygon, ReverseMultiLinestring, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_areal_with_multi_linestring + < + Polygon, MultiLinestring, + ReversePolygon, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + + +template +< + typename MultiLinestring, typename Ring, + bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + multi_linestring_tag, ring_tag, linestring_tag, + false, true, false, + MultiLinestring, Ring, + ReverseMultiLinestring, ReverseRing, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + MultiLinestring, Ring, + ReverseRing, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + +template +< + typename MultiLinestring, typename Polygon, + bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + multi_linestring_tag, polygon_tag, linestring_tag, + false, true, false, + MultiLinestring, Polygon, + ReverseMultiLinestring, ReverseRing, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + MultiLinestring, Polygon, + ReverseRing, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + + + +template +< + typename MultiLinestring, typename MultiPolygon, + bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut, + typename OutputIterator, typename GeometryOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + multi_linestring_tag, multi_polygon_tag, linestring_tag, + false, true, false, + MultiLinestring, MultiPolygon, + ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + MultiLinestring, MultiPolygon, + ReverseMultiPolygon, + OutputIterator, GeometryOut, + OverlayType, + Strategy + > +{}; + + +} // namespace dispatch +#endif + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP + diff --git a/boost/geometry/multi/algorithms/length.hpp b/boost/geometry/multi/algorithms/length.hpp new file mode 100644 index 0000000000..51ff9ef3c2 --- /dev/null +++ b/boost/geometry/multi/algorithms/length.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_LENGTH_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/length.hpp> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiLinestring, typename Strategy> +struct length<multi_linestring_tag, MultiLinestring, Strategy> + : detail::multi_sum + < + typename default_length_result<MultiLinestring>::type, + MultiLinestring, + Strategy, + detail::length::range_length + < + typename boost::range_value<MultiLinestring>::type, + Strategy, + closed // no need to close it explicitly + > + > +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP diff --git a/boost/geometry/multi/algorithms/num_geometries.hpp b/boost/geometry/multi/algorithms/num_geometries.hpp new file mode 100644 index 0000000000..213339a18c --- /dev/null +++ b/boost/geometry/multi/algorithms/num_geometries.hpp @@ -0,0 +1,51 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/num_geometries.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiGeometry> +struct num_geometries<multi_tag, MultiGeometry> +{ + static inline std::size_t apply(MultiGeometry const& multi_geometry) + { + return boost::size(multi_geometry); + } +}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP diff --git a/boost/geometry/multi/algorithms/num_interior_rings.hpp b/boost/geometry/multi/algorithms/num_interior_rings.hpp new file mode 100644 index 0000000000..87b0bdea91 --- /dev/null +++ b/boost/geometry/multi/algorithms/num_interior_rings.hpp @@ -0,0 +1,61 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP +#define BOOST_GEOMETRY_MULTI_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/multi/core/tags.hpp> + +#include <boost/geometry/algorithms/num_interior_rings.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPolygon> +struct num_interior_rings<multi_polygon_tag, MultiPolygon> +{ + static inline std::size_t apply(MultiPolygon const& multi_polygon) + { + std::size_t n = 0; + for (typename boost::range_iterator<MultiPolygon const>::type + it = boost::begin(multi_polygon); + it != boost::end(multi_polygon); + ++it) + { + n += geometry::num_interior_rings(*it); + } + return n; + } + +}; + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP diff --git a/boost/geometry/multi/algorithms/num_points.hpp b/boost/geometry/multi/algorithms/num_points.hpp new file mode 100644 index 0000000000..5ea53854eb --- /dev/null +++ b/boost/geometry/multi/algorithms/num_points.hpp @@ -0,0 +1,81 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_NUM_POINTS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace num_points +{ + + +template <typename MultiGeometry> +struct multi_count +{ + static inline size_t apply(MultiGeometry const& geometry, bool add_for_open) + { + typedef typename boost::range_value<MultiGeometry>::type geometry_type; + typedef typename boost::range_iterator + < + MultiGeometry const + >::type iterator_type; + + std::size_t n = 0; + for (iterator_type it = boost::begin(geometry); + it != boost::end(geometry); + ++it) + { + n += dispatch::num_points + < + typename tag<geometry_type>::type, + geometry_type + >::apply(*it, add_for_open); + } + return n; + } +}; + + +}} // namespace detail::num_points +#endif + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry> +struct num_points<multi_tag, Geometry> + : detail::num_points::multi_count<Geometry> {}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP diff --git a/boost/geometry/multi/algorithms/perimeter.hpp b/boost/geometry/multi/algorithms/perimeter.hpp new file mode 100644 index 0000000000..147f6fcc30 --- /dev/null +++ b/boost/geometry/multi/algorithms/perimeter.hpp @@ -0,0 +1,56 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_PERIMETER_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/perimeter.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ +template <typename MultiPolygon, typename Strategy> +struct perimeter<multi_polygon_tag, MultiPolygon, Strategy> + : detail::multi_sum + < + typename default_length_result<MultiPolygon>::type, + MultiPolygon, + Strategy, + perimeter + < + polygon_tag, + typename boost::range_value<MultiPolygon>::type, + Strategy + > + > +{}; + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP diff --git a/boost/geometry/multi/algorithms/reverse.hpp b/boost/geometry/multi/algorithms/reverse.hpp new file mode 100644 index 0000000000..f8a9442ac0 --- /dev/null +++ b/boost/geometry/multi/algorithms/reverse.hpp @@ -0,0 +1,69 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_REVERSE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/algorithms/reverse.hpp> +#include <boost/geometry/multi/algorithms/detail/modify.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry> +struct reverse<multi_linestring_tag, Geometry> + : detail::multi_modify + < + Geometry, + detail::reverse::range_reverse + < + typename boost::range_value<Geometry>::type + > + > +{}; + + +template <typename Geometry> +struct reverse<multi_polygon_tag, Geometry> + : detail::multi_modify + < + Geometry, + detail::reverse::polygon_reverse + < + typename boost::range_value<Geometry>::type + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP diff --git a/boost/geometry/multi/algorithms/simplify.hpp b/boost/geometry/multi/algorithms/simplify.hpp new file mode 100644 index 0000000000..dc3c7b5937 --- /dev/null +++ b/boost/geometry/multi/algorithms/simplify.hpp @@ -0,0 +1,117 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_SIMPLIFY_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +#include <boost/geometry/multi/algorithms/clear.hpp> +#include <boost/geometry/algorithms/simplify.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace simplify +{ + +template<typename MultiGeometry, typename Strategy, typename Policy> +struct simplify_multi +{ + static inline void apply(MultiGeometry const& multi, MultiGeometry& out, + double max_distance, Strategy const& strategy) + { + traits::resize<MultiGeometry>::apply(out, boost::size(multi)); + + typename boost::range_iterator<MultiGeometry>::type it_out + = boost::begin(out); + for (typename boost::range_iterator<MultiGeometry const>::type it_in + = boost::begin(multi); + it_in != boost::end(multi); + ++it_in, ++it_out) + { + Policy::apply(*it_in, *it_out, max_distance, strategy); + } + } +}; + + + +}} // namespace detail::simplify +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiPoint, typename Strategy> +struct simplify<multi_point_tag, MultiPoint, Strategy> + : detail::simplify::simplify_copy + < + MultiPoint, + Strategy + > + +{}; + + +template <typename MultiLinestring, typename Strategy> +struct simplify<multi_linestring_tag, MultiLinestring, Strategy> + : detail::simplify::simplify_multi + < + MultiLinestring, + Strategy, + detail::simplify::simplify_range + < + typename boost::range_value<MultiLinestring>::type, + Strategy, + 2 + > + > + +{}; + + +template <typename MultiPolygon, typename Strategy> +struct simplify<multi_polygon_tag, MultiPolygon, Strategy> + : detail::simplify::simplify_multi + < + MultiPolygon, + Strategy, + detail::simplify::simplify_polygon + < + typename boost::range_value<MultiPolygon>::type, + Strategy + > + > + +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP diff --git a/boost/geometry/multi/algorithms/transform.hpp b/boost/geometry/multi/algorithms/transform.hpp new file mode 100644 index 0000000000..09926778f9 --- /dev/null +++ b/boost/geometry/multi/algorithms/transform.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_TRANSFORM_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/algorithms/transform.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace transform +{ + +/*! + \brief Is able to transform any multi-geometry, calling the single-version as policy +*/ +template <typename Multi1, typename Multi2, typename Policy> +struct transform_multi +{ + template <typename S> + static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy) + { + traits::resize<Multi2>::apply(multi2, boost::size(multi1)); + + typename boost::range_iterator<Multi1 const>::type it1 + = boost::begin(multi1); + typename boost::range_iterator<Multi2>::type it2 + = boost::begin(multi2); + + for (; it1 != boost::end(multi1); ++it1, ++it2) + { + if (! Policy::apply(*it1, *it2, strategy)) + { + return false; + } + } + + return true; + } +}; + + +}} // namespace detail::transform +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Multi1, typename Multi2, typename Strategy> +struct transform + < + multi_tag, multi_tag, + Multi1, Multi2, + Strategy + > + : detail::transform::transform_multi + < + Multi1, + Multi2, + transform + < + typename single_tag_of + < + typename tag<Multi1>::type + >::type, + typename single_tag_of + < + typename tag<Multi2>::type + >::type, + typename boost::range_value<Multi1>::type, + typename boost::range_value<Multi2>::type, + Strategy + > + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP diff --git a/boost/geometry/multi/algorithms/unique.hpp b/boost/geometry/multi/algorithms/unique.hpp new file mode 100644 index 0000000000..5067e71f3f --- /dev/null +++ b/boost/geometry/multi/algorithms/unique.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_UNIQUE_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/unique.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace unique +{ + + +template <typename MultiGeometry, typename ComparePolicy, typename Policy> +struct multi_unique +{ + static inline void apply(MultiGeometry& multi, ComparePolicy const& compare) + { + for (typename boost::range_iterator<MultiGeometry>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it, compare); + } + } +}; + + +}} // namespace detail::unique +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// For points, unique is not applicable and does nothing +// (Note that it is not "spatially unique" but that it removes duplicate coordinates, +// like std::unique does). Spatially unique is "dissolve" which can (or will be) +// possible for multi-points as well, removing points at the same location. + + +template <typename MultiLineString, typename ComparePolicy> +struct unique<multi_linestring_tag, MultiLineString, ComparePolicy> + : detail::unique::multi_unique + < + MultiLineString, + ComparePolicy, + detail::unique::range_unique + < + typename boost::range_value<MultiLineString>::type, + ComparePolicy + > + > +{}; + + +template <typename MultiPolygon, typename ComparePolicy> +struct unique<multi_polygon_tag, MultiPolygon, ComparePolicy> + : detail::unique::multi_unique + < + MultiPolygon, + ComparePolicy, + detail::unique::polygon_unique + < + typename boost::range_value<MultiPolygon>::type, + ComparePolicy + > + > +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP diff --git a/boost/geometry/multi/algorithms/within.hpp b/boost/geometry/multi/algorithms/within.hpp new file mode 100644 index 0000000000..a3ec7514b7 --- /dev/null +++ b/boost/geometry/multi/algorithms/within.hpp @@ -0,0 +1,104 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_ALGORITHMS_WITHIN_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/within.hpp> +#include <boost/geometry/multi/core/closure.hpp> +#include <boost/geometry/multi/core/point_order.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace within +{ + + +template +< + typename Geometry, + typename MultiGeometry, + typename Strategy, + typename Policy +> +struct geometry_multi_within_code +{ + static inline int apply(Geometry const& geometry, + MultiGeometry const& multi, + Strategy const& strategy) + { + for (typename boost::range_iterator<MultiGeometry const>::type it + = boost::begin(multi); + it != boost::end(multi); + ++it) + { + // Geometry coding on multi: 1 (within) if within one of them; + // 0 (touch) if on border of one of them + int const code = Policy::apply(geometry, *it, strategy); + if (code != -1) + { + return code; + } + } + return -1; + } +}; + + +}} // namespace detail::within +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Point, typename MultiPolygon> +struct within<Point, MultiPolygon, point_tag, multi_polygon_tag> +{ + template <typename Strategy> + static inline bool apply(Point const& point, + MultiPolygon const& multi_polygon, Strategy const& strategy) + { + return detail::within::geometry_multi_within_code + < + Point, + MultiPolygon, + Strategy, + detail::within::point_in_polygon + < + Point, + typename boost::range_value<MultiPolygon>::type, + order_as_direction + < + geometry::point_order<MultiPolygon>::value + >::value, + geometry::closure<MultiPolygon>::value, + Strategy + > + >::apply(point, multi_polygon, strategy) == 1; + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP diff --git a/boost/geometry/multi/core/closure.hpp b/boost/geometry/multi/core/closure.hpp new file mode 100644 index 0000000000..3964db256c --- /dev/null +++ b/boost/geometry/multi/core/closure.hpp @@ -0,0 +1,58 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_CLOSURE_HPP +#define BOOST_GEOMETRY_MULTI_CORE_CLOSURE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Multi> +struct closure<multi_point_tag, Multi> : public core_detail::closure::closed {}; + +template <typename Multi> +struct closure<multi_linestring_tag, Multi> : public core_detail::closure::closed {}; + +// Specialization for polygon: the closure is the closure of its rings +template <typename MultiPolygon> +struct closure<multi_polygon_tag, MultiPolygon> +{ + static const closure_selector value = core_dispatch::closure + < + polygon_tag, + typename boost::range_value<MultiPolygon>::type + >::value ; +}; + + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_CLOSURE_HPP diff --git a/boost/geometry/multi/core/geometry_id.hpp b/boost/geometry/multi/core/geometry_id.hpp new file mode 100644 index 0000000000..9d69cb20d9 --- /dev/null +++ b/boost/geometry/multi/core/geometry_id.hpp @@ -0,0 +1,56 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_GEOMETRY_ID_HPP +#define BOOST_GEOMETRY_MULTI_CORE_GEOMETRY_ID_HPP + + +#include <boost/mpl/int.hpp> +#include <boost/type_traits.hpp> + + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/geometry_id.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <> +struct geometry_id<multi_point_tag> : boost::mpl::int_<4> {}; + + +template <> +struct geometry_id<multi_linestring_tag> : boost::mpl::int_<5> {}; + + +template <> +struct geometry_id<multi_polygon_tag> : boost::mpl::int_<6> {}; + + +} // namespace core_dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_GEOMETRY_ID_HPP diff --git a/boost/geometry/multi/core/interior_rings.hpp b/boost/geometry/multi/core/interior_rings.hpp new file mode 100644 index 0000000000..5a200d486c --- /dev/null +++ b/boost/geometry/multi/core/interior_rings.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_INTERIOR_RINGS_HPP +#define BOOST_GEOMETRY_MULTI_CORE_INTERIOR_RINGS_HPP + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + + +template <typename MultiPolygon> +struct interior_type<multi_polygon_tag, MultiPolygon> +{ + typedef typename core_dispatch::interior_type + < + polygon_tag, + typename boost::range_value<MultiPolygon>::type + >::type type; +}; + + +} // namespace core_dispatch +#endif + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_INTERIOR_RINGS_HPP diff --git a/boost/geometry/multi/core/is_areal.hpp b/boost/geometry/multi/core/is_areal.hpp new file mode 100644 index 0000000000..ad8daeb497 --- /dev/null +++ b/boost/geometry/multi/core/is_areal.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_IS_AREAL_HPP +#define BOOST_GEOMETRY_MULTI_CORE_IS_AREAL_HPP + + +#include <boost/type_traits.hpp> + + +#include <boost/geometry/core/is_areal.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <> struct is_areal<multi_polygon_tag> : boost::true_type {}; + +} // namespace core_dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_IS_AREAL_HPP diff --git a/boost/geometry/multi/core/point_order.hpp b/boost/geometry/multi/core/point_order.hpp new file mode 100644 index 0000000000..6b08468e8c --- /dev/null +++ b/boost/geometry/multi/core/point_order.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_POINT_ORDER_HPP +#define BOOST_GEOMETRY_MULTI_CORE_POINT_ORDER_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Multi> +struct point_order<multi_point_tag, Multi> + : public detail::point_order::clockwise {}; + +template <typename Multi> +struct point_order<multi_linestring_tag, Multi> + : public detail::point_order::clockwise {}; + + +// Specialization for multi_polygon: the order is the order of its polygons +template <typename MultiPolygon> +struct point_order<multi_polygon_tag, MultiPolygon> +{ + static const order_selector value = core_dispatch::point_order + < + polygon_tag, + typename boost::range_value<MultiPolygon>::type + >::value ; +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_CORE_POINT_ORDER_HPP diff --git a/boost/geometry/multi/core/point_type.hpp b/boost/geometry/multi/core/point_type.hpp new file mode 100644 index 0000000000..3c77e973b8 --- /dev/null +++ b/boost/geometry/multi/core/point_type.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_POINT_TYPE_HPP +#define BOOST_GEOMETRY_MULTI_CORE_POINT_TYPE_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename MultiPoint> +struct point_type<multi_point_tag, MultiPoint> +{ + typedef typename boost::range_value<MultiPoint>::type type; +}; + + +template <typename MultiLinestring> +struct point_type<multi_linestring_tag, MultiLinestring> +{ + typedef typename point_type<linestring_tag, + typename boost::range_value<MultiLinestring>::type>::type type; +}; + + + +template <typename MultiPolygon> +struct point_type<multi_polygon_tag, MultiPolygon> +{ + typedef typename point_type<polygon_tag, + typename boost::range_value<MultiPolygon>::type>::type type; +}; + + +} +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_POINT_TYPE_HPP diff --git a/boost/geometry/multi/core/ring_type.hpp b/boost/geometry/multi/core/ring_type.hpp new file mode 100644 index 0000000000..faafaed021 --- /dev/null +++ b/boost/geometry/multi/core/ring_type.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_RING_TYPE_HPP +#define BOOST_GEOMETRY_MULTI_CORE_RING_TYPE_HPP + + +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename MultiPolygon> +struct ring_return_type<multi_polygon_tag, MultiPolygon> +{ + typedef typename ring_return_type + < + polygon_tag, + typename mpl::if_ + < + boost::is_const<MultiPolygon>, + typename boost::range_value<MultiPolygon>::type const, + typename boost::range_value<MultiPolygon>::type + >::type + >::type type; +}; + + +template <typename MultiPolygon> +struct ring_type<multi_polygon_tag, MultiPolygon> +{ + typedef typename boost::remove_reference + < + typename ring_return_type<multi_polygon_tag, MultiPolygon>::type + >::type type; +}; + + +} // namespace core_dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_CORE_RING_TYPE_HPP diff --git a/boost/geometry/multi/core/tags.hpp b/boost/geometry/multi/core/tags.hpp new file mode 100644 index 0000000000..dcfca65b2f --- /dev/null +++ b/boost/geometry/multi/core/tags.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_CORE_TAGS_HPP +#define BOOST_GEOMETRY_MULTI_CORE_TAGS_HPP + +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +/// OGC Multi point identifying tag +struct multi_point_tag : multi_tag, pointlike_tag {}; + +/// OGC Multi linestring identifying tag +struct multi_linestring_tag : multi_tag, linear_tag {}; + +/// OGC Multi polygon identifying tag +struct multi_polygon_tag : multi_tag, polygonal_tag {}; + +/// OGC Geometry Collection identifying tag +struct geometry_collection_tag : multi_tag {}; + + + + +/*! +\brief Meta-function to get for a tag of a multi-geometry + the tag of the corresponding single-geometry +*/ +template <typename Tag> +struct single_tag_of +{}; + +#ifndef DOXYGEN_NO_DETAIL + +template <> +struct single_tag_of<multi_point_tag> +{ + typedef point_tag type; +}; + +template <> +struct single_tag_of<multi_linestring_tag> +{ + typedef linestring_tag type; +}; + +template <> +struct single_tag_of<multi_polygon_tag> +{ + typedef polygon_tag type; +}; + +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_CORE_TAGS_HPP diff --git a/boost/geometry/multi/core/topological_dimension.hpp b/boost/geometry/multi/core/topological_dimension.hpp new file mode 100644 index 0000000000..55118f1c73 --- /dev/null +++ b/boost/geometry/multi/core/topological_dimension.hpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_TOPOLOGICAL_DIMENSION_HPP +#define BOOST_GEOMETRY_MULTI_TOPOLOGICAL_DIMENSION_HPP + + +#include <boost/mpl/int.hpp> + + +#include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <> +struct top_dim<multi_point_tag> : boost::mpl::int_<0> {}; + + +template <> +struct top_dim<multi_linestring_tag> : boost::mpl::int_<1> {}; + + +template <> +struct top_dim<multi_polygon_tag> : boost::mpl::int_<2> {}; + + +} // namespace core_dispatch +#endif + + +}} // namespace boost::geometry + + +#endif diff --git a/boost/geometry/multi/geometries/concepts/check.hpp b/boost/geometry/multi/geometries/concepts/check.hpp new file mode 100644 index 0000000000..18f4ff0c25 --- /dev/null +++ b/boost/geometry/multi/geometries/concepts/check.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP + + + +#include <boost/type_traits/is_const.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp> + + +namespace boost { namespace geometry +{ + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry> +struct check<multi_point_tag, Geometry, true> + : detail::concept_check::check<concept::ConstMultiPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<multi_point_tag, Geometry, false> + : detail::concept_check::check<concept::MultiPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<multi_linestring_tag, Geometry, true> + : detail::concept_check::check<concept::ConstMultiLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<multi_linestring_tag, Geometry, false> + : detail::concept_check::check<concept::MultiLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<multi_polygon_tag, Geometry, true> + : detail::concept_check::check<concept::ConstMultiPolygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<multi_polygon_tag, Geometry, false> + : detail::concept_check::check<concept::MultiPolygon<Geometry> > +{}; + + +} // namespace dispatch +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP diff --git a/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp new file mode 100644 index 0000000000..b0519f07ee --- /dev/null +++ b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.hpp> +#include <boost/range/metafunctions.hpp> + + +#include <boost/geometry/geometries/concepts/linestring_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief multi-linestring concept +\ingroup concepts +\par Formal definition: +The multi linestring concept is defined as following: +- there must be a specialization of traits::tag defining multi_linestring_tag as + type +- it must behave like a Boost.Range +- its range value must fulfil the Linestring concept + +*/ +template <typename Geometry> +class MultiLinestring +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type linestring_type; + + BOOST_CONCEPT_ASSERT( (concept::Linestring<linestring_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(MultiLinestring) + { + } +#endif +}; + + +/*! +\brief concept for multi-linestring (const version) +\ingroup const_concepts +*/ +template <typename Geometry> +class ConstMultiLinestring +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type linestring_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstLinestring<linestring_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(ConstMultiLinestring) + { + } +#endif +}; + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP diff --git a/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp new file mode 100644 index 0000000000..f5942df070 --- /dev/null +++ b/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp @@ -0,0 +1,85 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.hpp> +#include <boost/range/metafunctions.hpp> + + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief MultiPoint concept +\ingroup concepts +\par Formal definition: +The multi point concept is defined as following: +- there must be a specialization of traits::tag defining multi_point_tag as type +- it must behave like a Boost.Range +- its range value must fulfil the Point concept + +*/ +template <typename Geometry> +class MultiPoint +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(MultiPoint) + { + } +#endif +}; + + +/*! +\brief concept for multi-point (const version) +\ingroup const_concepts +*/ +template <typename Geometry> +class ConstMultiPoint +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type point_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(ConstMultiPoint) + { + } +#endif +}; + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP diff --git a/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp new file mode 100644 index 0000000000..ca730d4f6b --- /dev/null +++ b/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/range/concepts.hpp> +#include <boost/range/metafunctions.hpp> + +#include <boost/geometry/geometries/concepts/polygon_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief multi-polygon concept +\ingroup concepts +\par Formal definition: +The multi polygon concept is defined as following: +- there must be a specialization of traits::tag defining multi_polygon_tag + as type +- it must behave like a Boost.Range +- its range value must fulfil the Polygon concept + +*/ +template <typename Geometry> +class MultiPolygon +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type polygon_type; + + BOOST_CONCEPT_ASSERT( (concept::Polygon<polygon_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(MultiPolygon) + { + } +#endif +}; + + +/*! +\brief concept for multi-polygon (const version) +\ingroup const_concepts +*/ +template <typename Geometry> +class ConstMultiPolygon +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + typedef typename boost::range_value<Geometry>::type polygon_type; + + BOOST_CONCEPT_ASSERT( (concept::ConstPolygon<polygon_type>) ); + BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) ); + + +public : + + BOOST_CONCEPT_USAGE(ConstMultiPolygon) + { + } +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP diff --git a/boost/geometry/multi/geometries/multi_geometries.hpp b/boost/geometry/multi/geometries/multi_geometries.hpp new file mode 100644 index 0000000000..90cf85a0f6 --- /dev/null +++ b/boost/geometry/multi/geometries/multi_geometries.hpp @@ -0,0 +1,21 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP + +#include <boost/geometry/multi/geometries/multi_point.hpp> +#include <boost/geometry/multi/geometries/multi_linestring.hpp> +#include <boost/geometry/multi/geometries/multi_polygon.hpp> + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP diff --git a/boost/geometry/multi/geometries/multi_linestring.hpp b/boost/geometry/multi/geometries/multi_linestring.hpp new file mode 100644 index 0000000000..67d4da06b7 --- /dev/null +++ b/boost/geometry/multi/geometries/multi_linestring.hpp @@ -0,0 +1,80 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_LINESTRING_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_LINESTRING_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/geometries/concepts/linestring_concept.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + + +namespace model +{ + +/*! +\brief multi_line, a collection of linestring +\details Multi-linestring can be used to group lines belonging to each other, + e.g. a highway (with interruptions) +\ingroup geometries + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_multi_linestring MultiLineString Concept] +} +*/ +template +< + typename LineString, + template<typename, typename> class Container = std::vector, + template<typename> class Allocator = std::allocator +> +class multi_linestring : public Container<LineString, Allocator<LineString> > +{ + BOOST_CONCEPT_ASSERT( (concept::Linestring<LineString>) ); +}; + + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename LineString, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct tag< model::multi_linestring<LineString, Container, Allocator> > +{ + typedef multi_linestring_tag type; +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_LINESTRING_HPP diff --git a/boost/geometry/multi/geometries/multi_point.hpp b/boost/geometry/multi/geometries/multi_point.hpp new file mode 100644 index 0000000000..002d8f8a4b --- /dev/null +++ b/boost/geometry/multi/geometries/multi_point.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_MULTI_POINT_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POINT_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + +namespace model +{ + + +/*! +\brief multi_point, a collection of points +\ingroup geometries +\tparam Point \tparam_point +\tparam Container \tparam_container +\tparam Allocator \tparam_allocator +\details Multipoint can be used to group points belonging to each other, + e.g. a constellation, or the result set of an intersection +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_multi_point MultiPoint Concept] +} +*/ +template +< + typename Point, + template<typename, typename> class Container = std::vector, + template<typename> class Allocator = std::allocator +> +class multi_point : public Container<Point, Allocator<Point> > +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + typedef Container<Point, Allocator<Point> > base_type; + +public : + /// \constructor_default{multi_point} + inline multi_point() + : base_type() + {} + + /// \constructor_begin_end{multi_point} + template <typename Iterator> + inline multi_point(Iterator begin, Iterator end) + : base_type(begin, end) + {} +}; + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct tag< model::multi_point<Point, Container, Allocator> > +{ + typedef multi_point_tag type; +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POINT_HPP diff --git a/boost/geometry/multi/geometries/multi_polygon.hpp b/boost/geometry/multi/geometries/multi_polygon.hpp new file mode 100644 index 0000000000..af8d042873 --- /dev/null +++ b/boost/geometry/multi/geometries/multi_polygon.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_MULTI_POLYGON_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POLYGON_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/multi/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/polygon_concept.hpp> + +namespace boost { namespace geometry +{ + +namespace model +{ + +/*! +\brief multi_polygon, a collection of polygons +\details Multi-polygon can be used to group polygons belonging to each other, + e.g. Hawaii +\ingroup geometries + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_multi_polygon MultiPolygon Concept] +} +*/ +template +< + typename Polygon, + template<typename, typename> class Container = std::vector, + template<typename> class Allocator = std::allocator +> +class multi_polygon : public Container<Polygon, Allocator<Polygon> > +{ + BOOST_CONCEPT_ASSERT( (concept::Polygon<Polygon>) ); +}; + + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Polygon, + template<typename, typename> class Container, + template<typename> class Allocator +> +struct tag< model::multi_polygon<Polygon, Container, Allocator> > +{ + typedef multi_polygon_tag type; +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POLYGON_HPP diff --git a/boost/geometry/multi/geometries/register/multi_linestring.hpp b/boost/geometry/multi/geometries/register/multi_linestring.hpp new file mode 100644 index 0000000000..5ececdb8e8 --- /dev/null +++ b/boost/geometry/multi/geometries/register/multi_linestring.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +/*! +\brief \brief_macro{multi_linestring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING, multi_linestring} The + multi_linestring may contain template parameters, which must be specified then. +\param MultiLineString \param_macro_type{multi_linestring} + +\qbk{ +[heading Example] +[register_multi_linestring] +[register_multi_linestring_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING(MultiLineString) \ +namespace boost { namespace geometry { namespace traits { \ + template<> struct tag<MultiLineString> { typedef multi_linestring_tag type; }; \ +}}} + + +/*! +\brief \brief_macro{templated multi_linestring} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED, templated multi_linestring} + \details_macro_templated{multi_linestring, linestring} +\param MultiLineString \param_macro_type{multi_linestring (without template parameters)} + +\qbk{ +[heading Example] +[register_multi_linestring_templated] +[register_multi_linestring_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED(MultiLineString) \ +namespace boost { namespace geometry { namespace traits { \ + template<typename LineString> struct tag< MultiLineString<LineString> > { typedef multi_linestring_tag type; }; \ +}}} + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP diff --git a/boost/geometry/multi/geometries/register/multi_point.hpp b/boost/geometry/multi/geometries/register/multi_point.hpp new file mode 100644 index 0000000000..813f54733d --- /dev/null +++ b/boost/geometry/multi/geometries/register/multi_point.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +/*! +\brief \brief_macro{multi_point} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT, multi_point} The + multi_point may contain template parameters, which must be specified then. +\param MultiPoint \param_macro_type{multi_point} + +\qbk{ +[heading Example] +[register_multi_point] +[register_multi_point_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_POINT(MultiPoint) \ +namespace boost { namespace geometry { namespace traits { \ + template<> struct tag<MultiPoint> { typedef multi_point_tag type; }; \ +}}} + + +/*! +\brief \brief_macro{templated multi_point} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED, templated multi_point} + \details_macro_templated{multi_point, point} +\param MultiPoint \param_macro_type{multi_point (without template parameters)} + +\qbk{ +[heading Example] +[register_multi_point_templated] +[register_multi_point_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(MultiPoint) \ +namespace boost { namespace geometry { namespace traits { \ + template<typename Point> struct tag< MultiPoint<Point> > { typedef multi_point_tag type; }; \ +}}} + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP diff --git a/boost/geometry/multi/geometries/register/multi_polygon.hpp b/boost/geometry/multi/geometries/register/multi_polygon.hpp new file mode 100644 index 0000000000..801b98cf24 --- /dev/null +++ b/boost/geometry/multi/geometries/register/multi_polygon.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/multi/core/tags.hpp> + +/*! +\brief \brief_macro{multi_polygon} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON, multi_polygon} The + multi_polygon may contain template parameters, which must be specified then. +\param MultiPolygon \param_macro_type{multi_polygon} + +\qbk{ +[heading Example] +[register_multi_polygon] +[register_multi_polygon_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON(MultiPolygon) \ +namespace boost { namespace geometry { namespace traits { \ + template<> struct tag<MultiPolygon> { typedef multi_polygon_tag type; }; \ +}}} + + +/*! +\brief \brief_macro{templated multi_polygon} +\ingroup register +\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED, templated multi_polygon} + \details_macro_templated{multi_polygon, polygon} +\param MultiPolygon \param_macro_type{multi_polygon (without template parameters)} + +\qbk{ +[heading Example] +[register_multi_polygon_templated] +[register_multi_polygon_templated_output] +} +*/ +#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED(MultiPolygon) \ +namespace boost { namespace geometry { namespace traits { \ + template<typename Polygon> struct tag< MultiPolygon<Polygon> > { typedef multi_polygon_tag type; }; \ +}}} + + +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP diff --git a/boost/geometry/multi/io/dsv/write.hpp b/boost/geometry/multi/io/dsv/write.hpp new file mode 100644 index 0000000000..be40b5da5a --- /dev/null +++ b/boost/geometry/multi/io/dsv/write.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_IO_DSV_WRITE_HPP +#define BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/io/dsv/write.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace dsv +{ + +template <typename MultiGeometry> +struct dsv_multi +{ + typedef dispatch::dsv + < + typename single_tag_of + < + typename tag<MultiGeometry>::type + >::type, + typename boost::range_value<MultiGeometry>::type + > dispatch_one; + + typedef typename boost::range_iterator + < + MultiGeometry const + >::type iterator; + + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + MultiGeometry const& multi, + dsv_settings const& settings) + { + os << settings.list_open; + + bool first = true; + for(iterator it = boost::begin(multi); + it != boost::end(multi); + ++it, first = false) + { + os << (first ? "" : settings.list_separator); + dispatch_one::apply(os, *it, settings); + } + os << settings.list_close; + } +}; + +}} // namespace detail::dsv +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Geometry> +struct dsv<multi_tag, Geometry> + : detail::dsv::dsv_multi<Geometry> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP diff --git a/boost/geometry/multi/io/wkt/detail/prefix.hpp b/boost/geometry/multi/io/wkt/detail/prefix.hpp new file mode 100644 index 0000000000..37b07979ba --- /dev/null +++ b/boost/geometry/multi/io/wkt/detail/prefix.hpp @@ -0,0 +1,51 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_IO_WKT_DETAIL_PREFIX_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP + +#include <boost/geometry/multi/core/tags.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +struct prefix_null +{ + static inline const char* apply() { return ""; } +}; + +struct prefix_multipoint +{ + static inline const char* apply() { return "MULTIPOINT"; } +}; + +struct prefix_multilinestring +{ + static inline const char* apply() { return "MULTILINESTRING"; } +}; + +struct prefix_multipolygon +{ + static inline const char* apply() { return "MULTIPOLYGON"; } +}; + +}} // namespace wkt::impl +#endif + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP diff --git a/boost/geometry/multi/io/wkt/read.hpp b/boost/geometry/multi/io/wkt/read.hpp new file mode 100644 index 0000000000..3c75fd8040 --- /dev/null +++ b/boost/geometry/multi/io/wkt/read.hpp @@ -0,0 +1,105 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_IO_WKT_READ_MULTI_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP + +#include <string> + +#include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/io/wkt/detail/prefix.hpp> +#include <boost/geometry/io/wkt/read.hpp> + +namespace boost { namespace geometry +{ + +namespace detail { namespace wkt +{ + +template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy> +struct multi_parser +{ + static inline void apply(std::string const& wkt, MultiGeometry& geometry) + { + traits::clear<MultiGeometry>::apply(geometry); + + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it; + if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it)) + { + handle_open_parenthesis(it, tokens.end(), wkt); + + // Parse sub-geometries + while(it != tokens.end() && *it != ")") + { + traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1); + Parser + < + typename boost::range_value<MultiGeometry>::type + >::apply(it, tokens.end(), wkt, geometry.back()); + if (it != tokens.end() && *it == ",") + { + // Skip "," after multi-element is parsed + ++it; + } + } + + handle_close_parenthesis(it, tokens.end(), wkt); + } + } +}; + +}} // namespace detail::wkt + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiGeometry> +struct read_wkt<multi_point_tag, MultiGeometry> + : detail::wkt::multi_parser + < + MultiGeometry, + detail::wkt::point_parser, + detail::wkt::prefix_multipoint + > +{}; + +template <typename MultiGeometry> +struct read_wkt<multi_linestring_tag, MultiGeometry> + : detail::wkt::multi_parser + < + MultiGeometry, + detail::wkt::linestring_parser, + detail::wkt::prefix_multilinestring + > +{}; + +template <typename MultiGeometry> +struct read_wkt<multi_polygon_tag, MultiGeometry> + : detail::wkt::multi_parser + < + MultiGeometry, + detail::wkt::polygon_parser, + detail::wkt::prefix_multipolygon + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP diff --git a/boost/geometry/multi/io/wkt/wkt.hpp b/boost/geometry/multi/io/wkt/wkt.hpp new file mode 100644 index 0000000000..55f1713d4d --- /dev/null +++ b/boost/geometry/multi/io/wkt/wkt.hpp @@ -0,0 +1,20 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_IO_WKT_WKT_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKT_WKT_HPP + +#include <boost/geometry/multi/io/wkt/read.hpp> +#include <boost/geometry/multi/io/wkt/write.hpp> + +#endif // BOOST_GEOMETRY_MULTI_IO_WKT_WKT_HPP diff --git a/boost/geometry/multi/io/wkt/write.hpp b/boost/geometry/multi/io/wkt/write.hpp new file mode 100644 index 0000000000..374da28b53 --- /dev/null +++ b/boost/geometry/multi/io/wkt/write.hpp @@ -0,0 +1,108 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_IO_WKT_WRITE_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/io/wkt/detail/prefix.hpp> +#include <boost/geometry/io/wkt/write.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +template <typename Multi, typename StreamPolicy, typename PrefixPolicy> +struct wkt_multi +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Multi const& geometry) + { + os << PrefixPolicy::apply(); + // TODO: check EMPTY here + os << "("; + + for (typename boost::range_iterator<Multi const>::type + it = boost::begin(geometry); + it != boost::end(geometry); + ++it) + { + if (it != boost::begin(geometry)) + { + os << ","; + } + StreamPolicy::apply(os, *it); + } + + os << ")"; + } +}; + +}} // namespace wkt::impl +#endif + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Multi> +struct wkt<multi_point_tag, Multi> + : detail::wkt::wkt_multi + < + Multi, + detail::wkt::wkt_point + < + typename boost::range_value<Multi>::type, + detail::wkt::prefix_null + >, + detail::wkt::prefix_multipoint + > +{}; + +template <typename Multi> +struct wkt<multi_linestring_tag, Multi> + : detail::wkt::wkt_multi + < + Multi, + detail::wkt::wkt_sequence + < + typename boost::range_value<Multi>::type + >, + detail::wkt::prefix_multilinestring + > +{}; + +template <typename Multi> +struct wkt<multi_polygon_tag, Multi> + : detail::wkt::wkt_multi + < + Multi, + detail::wkt::wkt_poly + < + typename boost::range_value<Multi>::type, + detail::wkt::prefix_null + >, + detail::wkt::prefix_multipolygon + > +{}; + +} // namespace dispatch +#endif + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP diff --git a/boost/geometry/multi/multi.hpp b/boost/geometry/multi/multi.hpp new file mode 100644 index 0000000000..db33a9dd03 --- /dev/null +++ b/boost/geometry/multi/multi.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_HPP +#define BOOST_GEOMETRY_MULTI_HPP + + +#include <boost/geometry/multi/core/closure.hpp> +#include <boost/geometry/multi/core/geometry_id.hpp> +#include <boost/geometry/multi/core/interior_rings.hpp> +#include <boost/geometry/multi/core/is_areal.hpp> +#include <boost/geometry/multi/core/point_order.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/core/ring_type.hpp> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/core/topological_dimension.hpp> + +#include <boost/geometry/multi/algorithms/append.hpp> +#include <boost/geometry/multi/algorithms/area.hpp> +#include <boost/geometry/multi/algorithms/centroid.hpp> +#include <boost/geometry/multi/algorithms/clear.hpp> +#include <boost/geometry/multi/algorithms/convert.hpp> +#include <boost/geometry/multi/algorithms/correct.hpp> +#include <boost/geometry/multi/algorithms/covered_by.hpp> +#include <boost/geometry/multi/algorithms/distance.hpp> +#include <boost/geometry/multi/algorithms/envelope.hpp> +#include <boost/geometry/multi/algorithms/equals.hpp> +#include <boost/geometry/multi/algorithms/for_each.hpp> +#include <boost/geometry/multi/algorithms/intersection.hpp> +#include <boost/geometry/multi/algorithms/length.hpp> +#include <boost/geometry/multi/algorithms/num_geometries.hpp> +#include <boost/geometry/multi/algorithms/num_interior_rings.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> +#include <boost/geometry/multi/algorithms/perimeter.hpp> +#include <boost/geometry/multi/algorithms/reverse.hpp> +#include <boost/geometry/multi/algorithms/simplify.hpp> +#include <boost/geometry/multi/algorithms/transform.hpp> +#include <boost/geometry/multi/algorithms/unique.hpp> +#include <boost/geometry/multi/algorithms/within.hpp> + +#include <boost/geometry/multi/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp> +#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> + +#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> + +#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp> +#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp> + +#include <boost/geometry/multi/geometries/concepts/check.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp> +#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp> + +#include <boost/geometry/multi/views/detail/range_type.hpp> +#include <boost/geometry/multi/strategies/cartesian/centroid_average.hpp> + +#include <boost/geometry/multi/io/dsv/write.hpp> +#include <boost/geometry/multi/io/wkt/wkt.hpp> + + +#endif // BOOST_GEOMETRY_MULTI_HPP diff --git a/boost/geometry/multi/strategies/cartesian/centroid_average.hpp b/boost/geometry/multi/strategies/cartesian/centroid_average.hpp new file mode 100644 index 0000000000..f28daf20bb --- /dev/null +++ b/boost/geometry/multi/strategies/cartesian/centroid_average.hpp @@ -0,0 +1,116 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP +#define BOOST_GEOMETRY_MULTI_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP + + +#include <boost/numeric/conversion/cast.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/strategies/centroid.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace centroid +{ + + +/*! +\brief Centroid calculation taking average of points +\ingroup strategies +*/ +template +< + typename PointCentroid, + typename Point = PointCentroid +> +class average +{ +private : + + /*! subclass to keep state */ + class sum + { + friend class average; + int count; + PointCentroid centroid; + + public : + inline sum() + : count(0) + { + assign_zero(centroid); + } + }; + +public : + typedef sum state_type; + typedef PointCentroid centroid_point_type; + typedef Point point_type; + + static inline void apply(Point const& p, sum& state) + { + add_point(state.centroid, p); + state.count++; + } + + static inline void result(sum const& state, PointCentroid& centroid) + { + centroid = state.centroid; + divide_value(centroid, state.count); + } + +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace services +{ + +template <typename Point, std::size_t DimensionCount, typename Geometry> +struct default_strategy +< + cartesian_tag, + pointlike_tag, + DimensionCount, + Point, + Geometry +> +{ + typedef average + < + Point, + typename point_type<Geometry>::type + > type; +}; + +} // namespace services + +#endif + + +}} // namespace strategy::centroid + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP diff --git a/boost/geometry/multi/views/detail/range_type.hpp b/boost/geometry/multi/views/detail/range_type.hpp new file mode 100644 index 0000000000..172feb251f --- /dev/null +++ b/boost/geometry/multi/views/detail/range_type.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_MULTI_VIEWS_DETAIL_RANGE_TYPE_HPP +#define BOOST_GEOMETRY_MULTI_VIEWS_DETAIL_RANGE_TYPE_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/views/detail/range_type.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// multi-point acts itself as a range +template <typename Geometry> +struct range_type<multi_point_tag, Geometry> +{ + typedef Geometry type; +}; + + +template <typename Geometry> +struct range_type<multi_linestring_tag, Geometry> +{ + typedef typename boost::range_value<Geometry>::type type; +}; + + +template <typename Geometry> +struct range_type<multi_polygon_tag, Geometry> +{ + // Call its single-version + typedef typename geometry::detail::range_type + < + typename boost::range_value<Geometry>::type + >::type type; +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_VIEWS_DETAIL_RANGE_TYPE_HPP diff --git a/boost/geometry/policies/compare.hpp b/boost/geometry/policies/compare.hpp new file mode 100644 index 0000000000..2e952d3e15 --- /dev/null +++ b/boost/geometry/policies/compare.hpp @@ -0,0 +1,242 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_POLICIES_COMPARE_HPP +#define BOOST_GEOMETRY_POLICIES_COMPARE_HPP + + +#include <cstddef> + +#include <boost/geometry/strategies/compare.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace compare +{ + + +template +< + int Direction, + typename Point, + typename Strategy, + std::size_t Dimension, + std::size_t DimensionCount +> +struct compare_loop +{ + typedef typename strategy::compare::detail::select_strategy + < + Strategy, Direction, Point, Dimension + >::type compare_type; + + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + static inline bool apply(Point const& left, Point const& right) + { + coordinate_type const& cleft = geometry::get<Dimension>(left); + coordinate_type const& cright = geometry::get<Dimension>(right); + + if (geometry::math::equals(cleft, cright)) + { + return compare_loop + < + Direction, Point, Strategy, + Dimension + 1, DimensionCount + >::apply(left, right); + } + else + { + compare_type compare; + return compare(cleft, cright); + } + } +}; + +template +< + int Direction, + typename Point, + typename Strategy, + std::size_t DimensionCount +> +struct compare_loop<Direction, Point, Strategy, DimensionCount, DimensionCount> +{ + static inline bool apply(Point const&, Point const&) + { + // On coming here, points are equal. Return true if + // direction = 0 (equal), false if -1/1 (greater/less) + return Direction == 0; + } +}; + + +template <int Direction, typename Point, typename Strategy> +struct compare_in_all_dimensions +{ + inline bool operator()(Point const& left, Point const& right) const + { + return detail::compare::compare_loop + < + Direction, Point, Strategy, + 0, geometry::dimension<Point>::type::value + >::apply(left, right); + } +}; + + +template <typename Point, typename Strategy, std::size_t Dimension> +class compare_in_one_dimension +{ + Strategy compare; + +public : + inline bool operator()(Point const& left, Point const& right) const + { + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + coordinate_type const& cleft = get<Dimension>(left); + coordinate_type const& cright = get<Dimension>(right); + return compare(cleft, cright); + } +}; + +}} // namespace detail::compare + +#endif + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + int Direction, + typename Point, + typename Strategy, + int Dimension +> +struct compare_geometries + : detail::compare::compare_in_one_dimension + < + Point, + typename strategy::compare::detail::select_strategy + < + Strategy, Direction, Point, Dimension + >::type, + Dimension + > +{}; + + +// Specialization with -1: compare in all dimensions +template <int Direction, typename Point, typename Strategy> +struct compare_geometries<Direction, Point, Strategy, -1> + : detail::compare::compare_in_all_dimensions<Direction, Point, Strategy> +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief Less functor, to sort points in ascending order. +\ingroup compare +\details This functor compares points and orders them on x, + then on y, then on z coordinate. +\tparam Geometry the geometry +\tparam Dimension the dimension to sort on, defaults to -1, + indicating ALL dimensions. That's to say, first on x, + on equal x-es then on y, etc. + If a dimension is specified, only that dimension is considered +\tparam Strategy underlying coordinate comparing functor, + defaults to the default comparison strategies + related to the point coordinate system. If specified, the specified + strategy is used. This can e.g. be std::less<double>. +*/ +template +< + typename Point, + int Dimension = -1, + typename Strategy = strategy::compare::default_strategy +> +struct less + : dispatch::compare_geometries + < + 1, // indicates ascending + Point, + Strategy, + Dimension + > +{ + typedef Point first_argument_type; + typedef Point second_argument_type; + typedef bool result_type; +}; + + +/*! +\brief Greater functor +\ingroup compare +\details Can be used to sort points in reverse order +\see Less functor +*/ +template +< + typename Point, + int Dimension = -1, + typename Strategy = strategy::compare::default_strategy +> +struct greater + : dispatch::compare_geometries + < + -1, // indicates descending + Point, + Strategy, + Dimension + > +{}; + + +/*! +\brief Equal To functor, to compare if points are equal +\ingroup compare +\tparam Geometry the geometry +\tparam Dimension the dimension to compare on, defaults to -1, + indicating ALL dimensions. + If a dimension is specified, only that dimension is considered +\tparam Strategy underlying coordinate comparing functor +*/ +template +< + typename Point, + int Dimension = -1, + typename Strategy = strategy::compare::default_strategy +> +struct equal_to + : dispatch::compare_geometries + < + 0, + Point, + Strategy, + Dimension + > +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_COMPARE_HPP diff --git a/boost/geometry/policies/relate/de9im.hpp b/boost/geometry/policies/relate/de9im.hpp new file mode 100644 index 0000000000..766d80b220 --- /dev/null +++ b/boost/geometry/policies/relate/de9im.hpp @@ -0,0 +1,177 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_GEOMETRY_POLICIES_RELATE_DE9IM_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DE9IM_HPP + + +#include <boost/geometry/strategies/intersection_result.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +template <typename S1, typename S2> +struct segments_de9im +{ + typedef de9im_segment return_type; + typedef S1 segment_type1; + typedef S2 segment_type2; + typedef typename select_coordinate_type<S1, S2>::type coordinate_type; + + static inline return_type rays_intersect(bool on_segment, + double ra, double rb, + coordinate_type const& dx1, coordinate_type const& dy1, + coordinate_type const& dx2, coordinate_type const& dy2, + coordinate_type const& wx, coordinate_type const& wy, + S1 const& s1, S2 const& s2) + { + if(on_segment) + { + // 0 <= ra <= 1 and 0 <= rb <= 1 + // Now check if one of them is 0 or 1, these are "touch" cases + bool a = math::equals(ra, 0.0) || math::equals(ra, 1.0); + bool b = math::equals(rb, 0.0) || math::equals(rb, 1.0); + if (a && b) + { + // Touch boundary/boundary: i-i == -1, i-b == -1, b-b == 0 + // Opposite: if both are equal they touch in opposite direction + return de9im_segment(ra,rb, + -1, -1, 1, + -1, 0, 0, + 1, 0, 2, false, math::equals(ra,rb)); + } + else if (a || b) + { + // Touch boundary/interior: i-i == -1, i-b == -1 or 0, b-b == -1 + int A = a ? 0 : -1; + int B = b ? 0 : -1; + return de9im_segment(ra,rb, + -1, B, 1, + A, -1, 0, + 1, 0, 2); + } + + // Intersects: i-i == 0, i-b == -1, i-e == 1 + return de9im_segment(ra,rb, + 0, -1, 1, + -1, -1, 0, + 1, 0, 2); + } + + // Not on segment, disjoint + return de9im_segment(ra,rb, + -1, -1, 1, + -1, -1, 0, + 1, 0, 2); + } + + static inline return_type collinear_touch(coordinate_type const& x, + coordinate_type const& y, bool opposite, char) + { + return de9im_segment(0,0, + -1, -1, 1, + -1, 0, 0, + 1, 0, 2, + true, opposite); + } + + template <typename S> + static inline return_type collinear_interior_boundary_intersect(S const& s, + bool a_within_b, bool opposite) + { + return a_within_b + ? de9im_segment(0,0, + 1, -1, -1, + 0, 0, -1, + 1, 0, 2, + true, opposite) + : de9im_segment(0,0, + 1, 0, 1, + -1, 0, 0, + -1, -1, 2, + true, opposite); + } + + + + static inline return_type collinear_a_in_b(S1 const& s, bool opposite) + { + return de9im_segment(0,0, + 1, -1, -1, + 0, -1, -1, + 1, 0, 2, + true, opposite); + } + static inline return_type collinear_b_in_a(S2 const& s, bool opposite) + { + return de9im_segment(0,0, + 1, 0, 1, + -1, -1, 0, + -1, -1, 2, + true, opposite); + } + + static inline return_type collinear_overlaps( + coordinate_type const& x1, coordinate_type const& y1, + coordinate_type const& x2, coordinate_type const& y2, bool opposite) + { + return de9im_segment(0,0, + 1, 0, 1, + 0, -1, 0, + 1, 0, 2, + true, opposite); + } + + static inline return_type segment_equal(S1 const& s, bool opposite) + { + return de9im_segment(0,0, + 1, -1, -1, + -1, 0, -1, + -1, -1, 2, + true, opposite); + } + + static inline return_type degenerate(S1 const& segment, bool a_degenerate) + { + return a_degenerate + ? de9im_segment(0,0, + 0, -1, -1, + -1, -1, -1, + 1, 0, 2, + false, false, false, true) + : de9im_segment(0,0, + 0, -1, 1, + -1, -1, 0, + -1, -1, 2, + false, false, false, true); + } + + static inline return_type collinear_disjoint() + { + return de9im_segment(0,0, + -1, -1, 1, + -1, -1, 0, + 1, 0, 2, + true); + } + +}; + + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DE9IM_HPP diff --git a/boost/geometry/policies/relate/direction.hpp b/boost/geometry/policies/relate/direction.hpp new file mode 100644 index 0000000000..9090d8b51e --- /dev/null +++ b/boost/geometry/policies/relate/direction.hpp @@ -0,0 +1,360 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP + + +#include <cstddef> +#include <string> + +#include <boost/concept_check.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/strategies/side_info.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + + +namespace policies { namespace relate +{ + +struct direction_type +{ + // NOTE: "char" will be replaced by enum in future version + + inline direction_type(side_info const& s, char h, + int ha, int hb, + int da = 0, int db = 0, + bool op = false) + : how(h) + , opposite(op) + , how_a(ha) + , how_b(hb) + , dir_a(da) + , dir_b(db) + , sides(s) + { + arrival[0] = ha; + arrival[1] = hb; + } + + inline direction_type(char h, bool op, int ha = 0, int hb = 0) + : how(h) + , opposite(op) + , how_a(ha) + , how_b(hb) + , dir_a(0) + , dir_b(0) + { + arrival[0] = ha; + arrival[1] = hb; + } + + + // TODO: replace this + // NOTE: "char" will be replaced by enum in future version + // "How" is the intersection formed? + char how; + + // Is it opposite (for collinear/equal cases) + bool opposite; + + // Information on how A arrives at intersection, how B arrives at intersection + // 1: arrives at intersection + // -1: starts from intersection + int how_a; + int how_b; + + // Direction: how is A positioned from B + // 1: points left, seen from IP + // -1: points right, seen from IP + // In case of intersection: B's TO direction + // In case that B's TO direction is at A: B's from direction + // In collinear cases: it is 0 + int dir_a; // Direction of A-s TO from IP + int dir_b; // Direction of B-s TO from IP + + // New information + side_info sides; + int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b + + + // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases + // Arrival 1: a1--------->a2 (a arrives within b) + // b1----->b2 + + // Arrival 1: (a in b) + // + + + // Arrival -1: a1--------->a2 (a does not arrive within b) + // b1----->b2 + + // Arrival -1: (b in a) a_1-------------a_2 + // b_1---b_2 + + // Arrival 0: a1------->a2 (a arrives at TO-border of b) + // b1--->b2 + +}; + + +template <typename S1, typename S2, typename CalculationType = void> +struct segments_direction +{ + typedef direction_type return_type; + typedef S1 segment_type1; + typedef S2 segment_type2; + typedef typename select_calculation_type + < + S1, S2, CalculationType + >::type coordinate_type; + + // Get the same type, but at least a double + typedef typename select_most_precise<coordinate_type, double>::type rtype; + + + static inline return_type segments_intersect(side_info const& sides, + coordinate_type const& dx1, coordinate_type const& dy1, + coordinate_type const& dx2, coordinate_type const& dy2, + S1 const& s1, S2 const& s2) + { + bool const ra0 = sides.get<0,0>() == 0; + bool const ra1 = sides.get<0,1>() == 0; + bool const rb0 = sides.get<1,0>() == 0; + bool const rb1 = sides.get<1,1>() == 0; + + return + // opposite and same starting point (FROM) + ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1) + + // opposite and point to each other (TO) + : ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1) + + // not opposite, forming an angle, first a then b, + // directed either both left, or both right + // Check side of B2 from A. This is not calculated before + : ra1 && rb0 ? angle<1>(sides, dx1, dy1, s1, s2, 'a', 1, -1) + + // not opposite, forming a angle, first b then a, + // directed either both left, or both right + : ra0 && rb1 ? angle<0>(sides, dx1, dy1, s1, s2, 'a', -1, 1) + + // b starts from interior of a + : rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1) + + // a starts from interior of b (#39) + : ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0) + + // b ends at interior of a, calculate direction of A from IP + : rb1 ? b_ends_at_middle(sides, dx2, dy2, s1, s2) + + // a ends at interior of b + : ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2) + + // normal intersection + : calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1) + ; + } + + static inline return_type collinear_touch( + coordinate_type const& , + coordinate_type const& , int arrival_a, int arrival_b) + { + // Though this is 'collinear', we handle it as To/From/Angle because it is the same. + // It only does NOT have a direction. + side_info sides; + //int const arrive = how == 'T' ? 1 : -1; + bool opposite = arrival_a == arrival_b; + return + ! opposite + ? return_type(sides, 'a', arrival_a, arrival_b) + : return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true); + } + + template <typename S> + static inline return_type collinear_interior_boundary_intersect(S const& , bool, + int arrival_a, int arrival_b, bool opposite) + { + return_type r('c', opposite); + r.arrival[0] = arrival_a; + r.arrival[1] = arrival_b; + return r; + } + + static inline return_type collinear_a_in_b(S1 const& , bool opposite) + { + return_type r('c', opposite); + r.arrival[0] = 1; + r.arrival[1] = -1; + return r; + } + static inline return_type collinear_b_in_a(S2 const& , bool opposite) + { + return_type r('c', opposite); + r.arrival[0] = -1; + r.arrival[1] = 1; + return r; + } + + static inline return_type collinear_overlaps( + coordinate_type const& , coordinate_type const& , + coordinate_type const& , coordinate_type const& , + int arrival_a, int arrival_b, bool opposite) + { + return_type r('c', opposite); + r.arrival[0] = arrival_a; + r.arrival[1] = arrival_b; + return r; + } + + static inline return_type segment_equal(S1 const& , bool opposite) + { + return return_type('e', opposite); + } + + static inline return_type degenerate(S1 const& , bool) + { + return return_type('0', false); + } + + static inline return_type disjoint() + { + return return_type('d', false); + } + + static inline return_type collinear_disjoint() + { + return return_type('d', false); + } + + static inline return_type error(std::string const&) + { + // Return "E" to denote error + // This will throw an error in get_turn_info + // TODO: change to enum or similar + return return_type('E', false); + } + +private : + + static inline bool is_left + ( + coordinate_type const& ux, + coordinate_type const& uy, + coordinate_type const& vx, + coordinate_type const& vy + ) + { + // This is a "side calculation" as in the strategies, but here terms are precalculated + // We might merge this with side, offering a pre-calculated term (in fact already done using cross-product) + // Waiting for implementing spherical... + + rtype const zero = rtype(); + return geometry::detail::determinant<rtype>(ux, uy, vx, vy) > zero; + } + + template <std::size_t I> + static inline return_type calculate_side(side_info const& sides, + coordinate_type const& dx1, coordinate_type const& dy1, + S1 const& s1, S2 const& s2, + char how, int how_a, int how_b) + { + coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); + coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); + + return is_left(dx1, dy1, dpx, dpy) + ? return_type(sides, how, how_a, how_b, -1, 1) + : return_type(sides, how, how_a, how_b, 1, -1); + } + + template <std::size_t I> + static inline return_type angle(side_info const& sides, + coordinate_type const& dx1, coordinate_type const& dy1, + S1 const& s1, S2 const& s2, + char how, int how_a, int how_b) + { + coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); + coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); + + return is_left(dx1, dy1, dpx, dpy) + ? return_type(sides, how, how_a, how_b, 1, 1) + : return_type(sides, how, how_a, how_b, -1, -1); + } + + + static inline return_type starts_from_middle(side_info const& sides, + coordinate_type const& dx1, coordinate_type const& dy1, + S1 const& s1, S2 const& s2, + char which, + int how_a, int how_b) + { + // Calculate ARROW of b segment w.r.t. s1 + coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); + coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); + + int dir = is_left(dx1, dy1, dpx, dpy) ? 1 : -1; + + // From other perspective, then reverse + bool const is_a = which == 'A'; + if (is_a) + { + dir = -dir; + } + + return return_type(sides, 's', + how_a, + how_b, + is_a ? dir : -dir, + ! is_a ? dir : -dir); + } + + + + // To be harmonized + static inline return_type a_ends_at_middle(side_info const& sides, + coordinate_type const& dx, coordinate_type const& dy, + S1 const& s1, S2 const& s2) + { + coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); + coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); + + // Ending at the middle, one ARRIVES, the other one is NEUTRAL + // (because it both "arrives" and "departs" there + return is_left(dx, dy, dpx, dpy) + ? return_type(sides, 'm', 1, 0, 1, 1) + : return_type(sides, 'm', 1, 0, -1, -1); + } + + + static inline return_type b_ends_at_middle(side_info const& sides, + coordinate_type const& dx, coordinate_type const& dy, + S1 const& s1, S2 const& s2) + { + coordinate_type dpx = get<1, 0>(s1) - get<0, 0>(s2); + coordinate_type dpy = get<1, 1>(s1) - get<0, 1>(s2); + + return is_left(dx, dy, dpx, dpy) + ? return_type(sides, 'm', 0, 1, 1, 1) + : return_type(sides, 'm', 0, 1, -1, -1); + } + +}; + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP diff --git a/boost/geometry/policies/relate/intersection_points.hpp b/boost/geometry/policies/relate/intersection_points.hpp new file mode 100644 index 0000000000..afd1dde501 --- /dev/null +++ b/boost/geometry/policies/relate/intersection_points.hpp @@ -0,0 +1,188 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP + + +#include <algorithm> +#include <string> + +#include <boost/concept_check.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +template <typename S1, typename S2, typename ReturnType, typename CalculationType = void> +struct segments_intersection_points +{ + typedef ReturnType return_type; + typedef S1 segment_type1; + typedef S2 segment_type2; + typedef typename select_calculation_type + < + S1, S2, CalculationType + >::type coordinate_type; + + static inline return_type segments_intersect(side_info const&, + coordinate_type const& dx1, coordinate_type const& dy1, + coordinate_type const& dx2, coordinate_type const& dy2, + S1 const& s1, S2 const& s2) + { + return_type result; + typedef typename geometry::coordinate_type + < + typename return_type::point_type + >::type coordinate_type; + + // Get the same type, but at least a double (also used for divisions) + typedef typename select_most_precise + < + coordinate_type, double + >::type promoted_type; + + promoted_type const s1x = get<0, 0>(s1); + promoted_type const s1y = get<0, 1>(s1); + + // Calculate other determinants - Cramers rule + promoted_type const wx = get<0, 0>(s1) - get<0, 0>(s2); + promoted_type const wy = get<0, 1>(s1) - get<0, 1>(s2); + promoted_type const d = detail::determinant<promoted_type>(dx1, dy1, dx2, dy2); + promoted_type const da = detail::determinant<promoted_type>(dx2, dy2, wx, wy); + + // r: ratio 0-1 where intersection divides A/B + promoted_type r = da / d; + promoted_type const zero = promoted_type(); + promoted_type const one = 1; + // Handle robustness issues + if (r < zero) + { + r = zero; + } + else if (r > one) + { + r = one; + } + + result.count = 1; + set<0>(result.intersections[0], + boost::numeric_cast<coordinate_type>(s1x + r * promoted_type(dx1))); + set<1>(result.intersections[0], + boost::numeric_cast<coordinate_type>(s1y + r * promoted_type(dy1))); + + return result; + } + + static inline return_type collinear_touch(coordinate_type const& x, + coordinate_type const& y, int, int) + { + return_type result; + result.count = 1; + set<0>(result.intersections[0], x); + set<1>(result.intersections[0], y); + return result; + } + + template <typename S> + static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1) + { + return_type result; + result.count = 2; + set<0>(result.intersections[index1], get<0, 0>(s)); + set<1>(result.intersections[index1], get<0, 1>(s)); + set<0>(result.intersections[index2], get<1, 0>(s)); + set<1>(result.intersections[index2], get<1, 1>(s)); + return result; + } + + template <typename S> + static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b, + int, int, bool opposite) + { + int index1 = opposite && ! a_in_b ? 1 : 0; + return collinear_inside(s, index1, 1 - index1); + } + + static inline return_type collinear_a_in_b(S1 const& s, bool) + { + return collinear_inside(s); + } + static inline return_type collinear_b_in_a(S2 const& s, bool opposite) + { + int index1 = opposite ? 1 : 0; + return collinear_inside(s, index1, 1 - index1); + } + + static inline return_type collinear_overlaps( + coordinate_type const& x1, coordinate_type const& y1, + coordinate_type const& x2, coordinate_type const& y2, + int, int, bool) + { + return_type result; + result.count = 2; + set<0>(result.intersections[0], x1); + set<1>(result.intersections[0], y1); + set<0>(result.intersections[1], x2); + set<1>(result.intersections[1], y2); + return result; + } + + static inline return_type segment_equal(S1 const& s, bool) + { + return_type result; + result.count = 2; + // TODO: order of IP's + set<0>(result.intersections[0], get<0, 0>(s)); + set<1>(result.intersections[0], get<0, 1>(s)); + set<0>(result.intersections[1], get<1, 0>(s)); + set<1>(result.intersections[1], get<1, 1>(s)); + return result; + } + + static inline return_type disjoint() + { + return return_type(); + } + static inline return_type error(std::string const&) + { + return return_type(); + } + + static inline return_type collinear_disjoint() + { + return return_type(); + } + + static inline return_type degenerate(S1 const& s, bool) + { + return_type result; + result.count = 1; + set<0>(result.intersections[0], get<0, 0>(s)); + set<1>(result.intersections[0], get<0, 1>(s)); + return result; + } +}; + + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP diff --git a/boost/geometry/policies/relate/tupled.hpp b/boost/geometry/policies/relate/tupled.hpp new file mode 100644 index 0000000000..853a8a26a8 --- /dev/null +++ b/boost/geometry/policies/relate/tupled.hpp @@ -0,0 +1,173 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_GEOMETRY_POLICIES_RELATE_TUPLED_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_TUPLED_HPP + + +#include <string> + +#include <boost/tuple/tuple.hpp> +#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +// "tupled" to return intersection results together. +// Now with two, with some meta-programming and derivations it can also be three (or more) +template <typename Policy1, typename Policy2, typename CalculationType = void> +struct segments_tupled +{ + typedef boost::tuple + < + typename Policy1::return_type, + typename Policy2::return_type + > return_type; + + // Take segments of first policy, they should be equal + typedef typename Policy1::segment_type1 segment_type1; + typedef typename Policy1::segment_type2 segment_type2; + + typedef typename select_calculation_type + < + segment_type1, + segment_type2, + CalculationType + >::type coordinate_type; + + // Get the same type, but at least a double + typedef typename select_most_precise<coordinate_type, double>::type rtype; + + static inline return_type segments_intersect(side_info const& sides, + coordinate_type const& dx1, coordinate_type const& dy1, + coordinate_type const& dx2, coordinate_type const& dy2, + segment_type1 const& s1, segment_type2 const& s2) + { + return boost::make_tuple + ( + Policy1::segments_intersect(sides, + dx1, dy1, dx2, dy2, s1, s2), + Policy2::segments_intersect(sides, + dx1, dy1, dx2, dy2, s1, s2) + ); + } + + static inline return_type collinear_touch(coordinate_type const& x, + coordinate_type const& y, int arrival_a, int arrival_b) + { + return boost::make_tuple + ( + Policy1::collinear_touch(x, y, arrival_a, arrival_b), + Policy2::collinear_touch(x, y, arrival_a, arrival_b) + ); + } + + template <typename S> + static inline return_type collinear_interior_boundary_intersect(S const& segment, + bool a_within_b, + int arrival_a, int arrival_b, bool opposite) + { + return boost::make_tuple + ( + Policy1::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite), + Policy2::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite) + ); + } + + static inline return_type collinear_a_in_b(segment_type1 const& segment, + bool opposite) + { + return boost::make_tuple + ( + Policy1::collinear_a_in_b(segment, opposite), + Policy2::collinear_a_in_b(segment, opposite) + ); + } + static inline return_type collinear_b_in_a(segment_type2 const& segment, + bool opposite) + { + return boost::make_tuple + ( + Policy1::collinear_b_in_a(segment, opposite), + Policy2::collinear_b_in_a(segment, opposite) + ); + } + + + static inline return_type collinear_overlaps( + coordinate_type const& x1, coordinate_type const& y1, + coordinate_type const& x2, coordinate_type const& y2, + int arrival_a, int arrival_b, bool opposite) + { + return boost::make_tuple + ( + Policy1::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite), + Policy2::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite) + ); + } + + static inline return_type segment_equal(segment_type1 const& s, + bool opposite) + { + return boost::make_tuple + ( + Policy1::segment_equal(s, opposite), + Policy2::segment_equal(s, opposite) + ); + } + + static inline return_type degenerate(segment_type1 const& segment, + bool a_degenerate) + { + return boost::make_tuple + ( + Policy1::degenerate(segment, a_degenerate), + Policy2::degenerate(segment, a_degenerate) + ); + } + + static inline return_type disjoint() + { + return boost::make_tuple + ( + Policy1::disjoint(), + Policy2::disjoint() + ); + } + + static inline return_type error(std::string const& msg) + { + return boost::make_tuple + ( + Policy1::error(msg), + Policy2::error(msg) + ); + } + + static inline return_type collinear_disjoint() + { + return boost::make_tuple + ( + Policy1::collinear_disjoint(), + Policy2::collinear_disjoint() + ); + } + +}; + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_TUPLED_HPP diff --git a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp new file mode 100644 index 0000000000..747c140754 --- /dev/null +++ b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp @@ -0,0 +1,384 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP + + +#include <cstddef> +#include <algorithm> +#include <vector> + +#include <boost/range.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/strategies/convex_hull.hpp> + +#include <boost/geometry/views/detail/range_type.hpp> + +#include <boost/geometry/policies/compare.hpp> + +#include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/views/reversible_view.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace convex_hull +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template +< + typename InputRange, + typename RangeIterator, + typename StrategyLess, + typename StrategyGreater +> +struct get_extremes +{ + typedef typename point_type<InputRange>::type point_type; + + point_type left, right; + + bool first; + + StrategyLess less; + StrategyGreater greater; + + inline get_extremes() + : first(true) + {} + + inline void apply(InputRange const& range) + { + if (boost::size(range) == 0) + { + return; + } + + // First iterate through this range + // (this two-stage approach avoids many point copies, + // because iterators are kept in memory. Because iterators are + // not persistent (in MSVC) this approach is not applicable + // for more ranges together) + + RangeIterator left_it = boost::begin(range); + RangeIterator right_it = boost::begin(range); + + for (RangeIterator it = boost::begin(range) + 1; + it != boost::end(range); + ++it) + { + if (less(*it, *left_it)) + { + left_it = it; + } + + if (greater(*it, *right_it)) + { + right_it = it; + } + } + + // Then compare with earlier + if (first) + { + // First time, assign left/right + left = *left_it; + right = *right_it; + first = false; + } + else + { + // Next time, check if this range was left/right from + // the extremes already collected + if (less(*left_it, left)) + { + left = *left_it; + } + + if (greater(*right_it, right)) + { + right = *right_it; + } + } + } +}; + + +template +< + typename InputRange, + typename RangeIterator, + typename Container, + typename SideStrategy +> +struct assign_range +{ + Container lower_points, upper_points; + + typedef typename point_type<InputRange>::type point_type; + + point_type const& most_left; + point_type const& most_right; + + inline assign_range(point_type const& left, point_type const& right) + : most_left(left) + , most_right(right) + {} + + inline void apply(InputRange const& range) + { + typedef SideStrategy side; + + // Put points in one of the two output sequences + for (RangeIterator it = boost::begin(range); + it != boost::end(range); + ++it) + { + // check if it is lying most_left or most_right from the line + + int dir = side::apply(most_left, most_right, *it); + switch(dir) + { + case 1 : // left side + upper_points.push_back(*it); + break; + case -1 : // right side + lower_points.push_back(*it); + break; + + // 0: on line most_left-most_right, + // or most_left, or most_right, + // -> all never part of hull + } + } + } +}; + +template <typename Range> +static inline void sort(Range& range) +{ + typedef typename boost::range_value<Range>::type point_type; + typedef geometry::less<point_type> comparator; + + std::sort(boost::begin(range), boost::end(range), comparator()); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Graham scan strategy to calculate convex hull +\ingroup strategies +\note Completely reworked version inspired on the sources listed below +\see http://www.ddj.com/architect/201806315 +\see http://marknelson.us/2007/08/22/convex + */ +template <typename InputGeometry, typename OutputPoint> +class graham_andrew +{ +public : + typedef OutputPoint point_type; + typedef InputGeometry geometry_type; + +private: + + typedef typename cs_tag<point_type>::type cs_tag; + + typedef typename std::vector<point_type> container_type; + typedef typename std::vector<point_type>::const_iterator iterator; + typedef typename std::vector<point_type>::const_reverse_iterator rev_iterator; + + + class partitions + { + friend class graham_andrew; + + container_type m_lower_hull; + container_type m_upper_hull; + container_type m_copied_input; + }; + + +public: + typedef partitions state_type; + + + inline void apply(InputGeometry const& geometry, partitions& state) const + { + // First pass. + // Get min/max (in most cases left / right) points + // This makes use of the geometry::less/greater predicates + + // For the left boundary it is important that multiple points + // are sorted from bottom to top. Therefore the less predicate + // does not take the x-only template parameter (this fixes ticket #6019. + // For the right boundary it is not necessary (though also not harmful), + // because points are sorted from bottom to top in a later stage. + // For symmetry and to get often more balanced lower/upper halves + // we keep it. + + typedef typename geometry::detail::range_type<InputGeometry>::type range_type; + + typedef typename boost::range_iterator + < + range_type const + >::type range_iterator; + + detail::get_extremes + < + range_type, + range_iterator, + geometry::less<point_type>, + geometry::greater<point_type> + > extremes; + geometry::detail::for_each_range(geometry, extremes); + + // Bounding left/right points + // Second pass, now that extremes are found, assign all points + // in either lower, either upper + detail::assign_range + < + range_type, + range_iterator, + container_type, + typename strategy::side::services::default_strategy<cs_tag>::type + > assigner(extremes.left, extremes.right); + + geometry::detail::for_each_range(geometry, assigner); + + + // Sort both collections, first on x(, then on y) + detail::sort(assigner.lower_points); + detail::sort(assigner.upper_points); + + //std::cout << boost::size(assigner.lower_points) << std::endl; + //std::cout << boost::size(assigner.upper_points) << std::endl; + + // And decide which point should be in the final hull + build_half_hull<-1>(assigner.lower_points, state.m_lower_hull, + extremes.left, extremes.right); + build_half_hull<1>(assigner.upper_points, state.m_upper_hull, + extremes.left, extremes.right); + } + + + template <typename OutputIterator> + inline void result(partitions const& state, + OutputIterator out, bool clockwise) const + { + if (clockwise) + { + output_range<iterate_forward>(state.m_upper_hull, out, false); + output_range<iterate_reverse>(state.m_lower_hull, out, true); + } + else + { + output_range<iterate_forward>(state.m_lower_hull, out, false); + output_range<iterate_reverse>(state.m_upper_hull, out, true); + } + } + + +private: + + template <int Factor> + static inline void build_half_hull(container_type const& input, + container_type& output, + point_type const& left, point_type const& right) + { + output.push_back(left); + for(iterator it = input.begin(); it != input.end(); ++it) + { + add_to_hull<Factor>(*it, output); + } + add_to_hull<Factor>(right, output); + } + + + template <int Factor> + static inline void add_to_hull(point_type const& p, container_type& output) + { + typedef typename strategy::side::services::default_strategy<cs_tag>::type side; + + output.push_back(p); + register std::size_t output_size = output.size(); + while (output_size >= 3) + { + rev_iterator rit = output.rbegin(); + point_type const& last = *rit++; + point_type const& last2 = *rit++; + + if (Factor * side::apply(*rit, last, last2) <= 0) + { + // Remove last two points from stack, and add last again + // This is much faster then erasing the one but last. + output.pop_back(); + output.pop_back(); + output.push_back(last); + output_size--; + } + else + { + return; + } + } + } + + + template <iterate_direction Direction, typename OutputIterator> + static inline void output_range(container_type const& range, + OutputIterator out, bool skip_first) + { + typedef typename reversible_view<container_type const, Direction>::type view_type; + view_type view(range); + bool first = true; + for (typename boost::range_iterator<view_type const>::type it = boost::begin(view); + it != boost::end(view); ++it) + { + if (first && skip_first) + { + first = false; + } + else + { + *out = *it; + ++out; + } + } + } + +}; + +}} // namespace strategy::convex_hull + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +template <typename InputGeometry, typename OutputPoint> +struct strategy_convex_hull<InputGeometry, OutputPoint, cartesian_tag> +{ + typedef strategy::convex_hull::graham_andrew<InputGeometry, OutputPoint> type; +}; +#endif + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP diff --git a/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp new file mode 100644 index 0000000000..1398ddb687 --- /dev/null +++ b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp @@ -0,0 +1,151 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP + +#include <boost/array.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry { namespace strategy +{ + +namespace within +{ + +struct decide_within +{ + static inline bool apply(int side, bool& result) + { + if (side != 1) + { + result = false; + return false; + } + return true; // continue + } +}; + +struct decide_covered_by +{ + static inline bool apply(int side, bool& result) + { + if (side != 1) + { + result = side >= 0; + return false; + } + return true; // continue + } +}; + + +template <typename Point, typename Box, typename Decide = decide_within> +struct point_in_box_by_side +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Box>::type + >::type side_strategy_type; + + static inline bool apply(Point const& point, Box const& box) + { + // Create (counterclockwise) array of points, the fifth one closes it + // Every point should be on the LEFT side (=1), or ON the border (=0), + // So >= 1 or >= 0 + boost::array<typename point_type<Box>::type, 5> bp; + geometry::detail::assign_box_corners_oriented<true>(box, bp); + bp[4] = bp[0]; + + bool result = true; + side_strategy_type strategy; + boost::ignore_unused_variable_warning(strategy); + + for (int i = 1; i < 5; i++) + { + int const side = strategy.apply(point, bp[i - 1], bp[i]); + if (! Decide::apply(side, result)) + { + return result; + } + } + + return result; + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template <typename Point, typename Box> +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, + Point, Box + > +{ + typedef within::point_in_box_by_side + < + Point, Box, within::decide_within + > type; +}; + + + +}} // namespace within::services + + +namespace covered_by { namespace services +{ + + +template <typename Point, typename Box> +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, + Point, Box + > +{ + typedef within::point_in_box_by_side + < + Point, Box, within::decide_covered_by + > type; +}; + + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP diff --git a/boost/geometry/strategies/agnostic/point_in_poly_oriented_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_oriented_winding.hpp new file mode 100644 index 0000000000..423948fff3 --- /dev/null +++ b/boost/geometry/strategies/agnostic/point_in_poly_oriented_winding.hpp @@ -0,0 +1,208 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP + + +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +/*! +\brief Within detection using winding rule, but checking if enclosing ring is + counter clockwise and, if so, reverses the result +\ingroup strategies +\tparam Point \tparam_point +\tparam Reverse True if parameter should be reversed +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\author Barend Gehrels +\note The implementation is inspired by terralib http://www.terralib.org (LGPL) +\note but totally revised afterwards, especially for cases on segments +\note Only dependant on "side", -> agnostic, suitable for spherical/latlong + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)] +} + */ +template +< + bool Reverse, + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void +> +class oriented_winding +{ + typedef typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type calculation_type; + + + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type strategy_side_type; + + + /*! subclass to keep state */ + class counter + { + int m_count; + bool m_touches; + calculation_type m_sum_area; + + inline int code() const + { + return m_touches ? 0 : m_count == 0 ? -1 : 1; + } + inline int clockwise_oriented_code() const + { + return (m_sum_area > 0) ? code() : -code(); + } + inline int oriented_code() const + { + return Reverse + ? -clockwise_oriented_code() + : clockwise_oriented_code(); + } + + public : + friend class oriented_winding; + + inline counter() + : m_count(0) + , m_touches(false) + , m_sum_area(0) + {} + + inline void add_to_area(calculation_type triangle) + { + m_sum_area += triangle; + } + + }; + + + template <size_t D> + static inline int check_touch(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + counter& state) + { + calculation_type const p = get<D>(point); + calculation_type const s1 = get<D>(seg1); + calculation_type const s2 = get<D>(seg2); + if ((s1 <= p && s2 >= p) || (s2 <= p && s1 >= p)) + { + state.m_touches = true; + } + return 0; + } + + + template <size_t D> + static inline int check_segment(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + counter& state) + { + calculation_type const p = get<D>(point); + calculation_type const s1 = get<D>(seg1); + calculation_type const s2 = get<D>(seg2); + + + // Check if one of segment endpoints is at same level of point + bool eq1 = math::equals(s1, p); + bool eq2 = math::equals(s2, p); + + if (eq1 && eq2) + { + // Both equal p -> segment is horizontal (or vertical for D=0) + // The only thing which has to be done is check if point is ON segment + return check_touch<1 - D>(point, seg1, seg2, state); + } + + return + eq1 ? (s2 > p ? 1 : -1) // Point on level s1, UP/DOWN depending on s2 + : eq2 ? (s1 > p ? -1 : 1) // idem + : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> UP + : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> DOWN + : 0; + } + + + + +public : + + // Typedefs and static methods to fulfill the concept + typedef Point point_type; + typedef PointOfSegment segment_point_type; + typedef counter state_type; + + static inline bool apply(Point const& point, + PointOfSegment const& s1, PointOfSegment const& s2, + counter& state) + { + state.add_to_area(get<0>(s2) * get<1>(s1) - get<0>(s1) * get<1>(s2)); + + int count = check_segment<1>(point, s1, s2, state); + if (count != 0) + { + int side = strategy_side_type::apply(s1, s2, point); + if (side == 0) + { + // Point is lying on segment + state.m_touches = true; + state.m_count = 0; + return false; + } + + // Side is NEG for right, POS for left. + // The count is -2 for down, 2 for up (or -1/1) + // Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE + // See accompagnying figure (TODO) + if (side * count > 0) + { + state.m_count += count; + } + } + return ! state.m_touches; + } + + static inline int result(counter const& state) + { + return state.oriented_code(); + } +}; + + +}} // namespace strategy::within + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp new file mode 100644 index 0000000000..69188650d8 --- /dev/null +++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -0,0 +1,232 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP + + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +/*! +\brief Within detection using winding rule +\ingroup strategies +\tparam Point \tparam_point +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\author Barend Gehrels +\note The implementation is inspired by terralib http://www.terralib.org (LGPL) +\note but totally revised afterwards, especially for cases on segments +\note Only dependant on "side", -> agnostic, suitable for spherical/latlong + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)] +} + */ +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void +> +class winding +{ + typedef typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type calculation_type; + + + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type strategy_side_type; + + + /*! subclass to keep state */ + class counter + { + int m_count; + bool m_touches; + + inline int code() const + { + return m_touches ? 0 : m_count == 0 ? -1 : 1; + } + + public : + friend class winding; + + inline counter() + : m_count(0) + , m_touches(false) + {} + + }; + + + template <size_t D> + static inline int check_touch(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + counter& state) + { + calculation_type const p = get<D>(point); + calculation_type const s1 = get<D>(seg1); + calculation_type const s2 = get<D>(seg2); + if ((s1 <= p && s2 >= p) || (s2 <= p && s1 >= p)) + { + state.m_touches = true; + } + return 0; + } + + + template <size_t D> + static inline int check_segment(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + counter& state) + { + calculation_type const p = get<D>(point); + calculation_type const s1 = get<D>(seg1); + calculation_type const s2 = get<D>(seg2); + + // Check if one of segment endpoints is at same level of point + bool eq1 = math::equals(s1, p); + bool eq2 = math::equals(s2, p); + + if (eq1 && eq2) + { + // Both equal p -> segment is horizontal (or vertical for D=0) + // The only thing which has to be done is check if point is ON segment + return check_touch<1 - D>(point, seg1, seg2,state); + } + + return + eq1 ? (s2 > p ? 1 : -1) // Point on level s1, UP/DOWN depending on s2 + : eq2 ? (s1 > p ? -1 : 1) // idem + : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> UP + : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> DOWN + : 0; + } + + + + +public : + + // Typedefs and static methods to fulfill the concept + typedef Point point_type; + typedef PointOfSegment segment_point_type; + typedef counter state_type; + + static inline bool apply(Point const& point, + PointOfSegment const& s1, PointOfSegment const& s2, + counter& state) + { + int count = check_segment<1>(point, s1, s2, state); + if (count != 0) + { + int side = strategy_side_type::apply(s1, s2, point); + if (side == 0) + { + // Point is lying on segment + state.m_touches = true; + state.m_count = 0; + return false; + } + + // Side is NEG for right, POS for left. + // The count is -2 for down, 2 for up (or -1/1) + // Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE + // See accompagnying figure (TODO) + if (side * count > 0) + { + state.m_count += count; + } + } + return ! state.m_touches; + } + + static inline int result(counter const& state) + { + return state.code(); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +// Register using "areal_tag" for ring, polygon, multi-polygon +template <typename AnyTag, typename Point, typename Geometry> +struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, cartesian_tag, cartesian_tag, Point, Geometry> +{ + typedef winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + +template <typename AnyTag, typename Point, typename Geometry> +struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, spherical_tag, Point, Geometry> +{ + typedef winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + + +} // namespace services + +#endif + + +}} // namespace strategy::within + + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace strategy { namespace covered_by { namespace services +{ + +// Register using "areal_tag" for ring, polygon, multi-polygon +template <typename AnyTag, typename Point, typename Geometry> +struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, cartesian_tag, cartesian_tag, Point, Geometry> +{ + typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + +template <typename AnyTag, typename Point, typename Geometry> +struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, spherical_tag, Point, Geometry> +{ + typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + + +}}} // namespace strategy::covered_by::services +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP diff --git a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp new file mode 100644 index 0000000000..4a1a22d1cf --- /dev/null +++ b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp @@ -0,0 +1,229 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 1995, 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 1995 Maarten Hilferink, Amsterdam, the Netherlands + +// 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_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP + + +#include <cstddef> +#include <vector> + +#include <boost/range.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/strategies/distance.hpp> + + + +//#define GL_DEBUG_DOUGLAS_PEUCKER + +#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#include <boost/geometry/io/dsv/write.hpp> +#endif + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace simplify +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + /*! + \brief Small wrapper around a point, with an extra member "included" + \details + It has a const-reference to the original point (so no copy here) + \tparam the enclosed point type + */ + template<typename Point> + struct douglas_peucker_point + { + Point const& p; + bool included; + + inline douglas_peucker_point(Point const& ap) + : p(ap) + , included(false) + {} + + // Necessary for proper compilation + inline douglas_peucker_point<Point> operator=(douglas_peucker_point<Point> const& ) + { + return douglas_peucker_point<Point>(*this); + } + }; +} +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Implements the simplify algorithm. +\ingroup strategies +\details The douglas_peucker strategy simplifies a linestring, ring or + vector of points using the well-known Douglas-Peucker algorithm. + For the algorithm, see for example: +\see http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm +\see http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html +\tparam Point the point type +\tparam PointDistanceStrategy point-segment distance strategy to be used +\note This strategy uses itself a point-segment-distance strategy which + can be specified +\author Barend and Maarten, 1995/1996 +\author Barend, revised for Generic Geometry Library, 2008 +*/ +template +< + typename Point, + typename PointDistanceStrategy +> +class douglas_peucker +{ +public : + + // See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954 + // Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more. + // For now we have to take the real distance. + typedef PointDistanceStrategy distance_strategy_type; + // typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type; + + typedef typename strategy::distance::services::return_type<distance_strategy_type>::type return_type; + +private : + typedef detail::douglas_peucker_point<Point> dp_point_type; + typedef typename std::vector<dp_point_type>::iterator iterator_type; + + + static inline void consider(iterator_type begin, + iterator_type end, + return_type const& max_dist, int& n, + distance_strategy_type const& ps_distance_strategy) + { + std::size_t size = end - begin; + + // size must be at least 3 + // because we want to consider a candidate point in between + if (size <= 2) + { +#ifdef GL_DEBUG_DOUGLAS_PEUCKER + if (begin != end) + { + std::cout << "ignore between " << dsv(begin->p) + << " and " << dsv((end - 1)->p) + << " size=" << size << std::endl; + } + std::cout << "return because size=" << size << std::endl; +#endif + return; + } + + iterator_type last = end - 1; + +#ifdef GL_DEBUG_DOUGLAS_PEUCKER + std::cout << "find between " << dsv(begin->p) + << " and " << dsv(last->p) + << " size=" << size << std::endl; +#endif + + + // Find most far point, compare to the current segment + //geometry::segment<Point const> s(begin->p, last->p); + return_type md(-1.0); // any value < 0 + iterator_type candidate; + for(iterator_type it = begin + 1; it != last; ++it) + { + return_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p); + +#ifdef GL_DEBUG_DOUGLAS_PEUCKER + std::cout << "consider " << dsv(it->p) + << " at " << double(dist) + << ((dist > max_dist) ? " maybe" : " no") + << std::endl; + +#endif + if (dist > md) + { + md = dist; + candidate = it; + } + } + + // If a point is found, set the include flag + // and handle segments in between recursively + if (md > max_dist) + { +#ifdef GL_DEBUG_DOUGLAS_PEUCKER + std::cout << "use " << dsv(candidate->p) << std::endl; +#endif + + candidate->included = true; + n++; + + consider(begin, candidate + 1, max_dist, n, ps_distance_strategy); + consider(candidate, end, max_dist, n, ps_distance_strategy); + } + } + + +public : + + template <typename Range, typename OutputIterator> + static inline OutputIterator apply(Range const& range, + OutputIterator out, double max_distance) + { + distance_strategy_type strategy; + + // Copy coordinates, a vector of references to all points + std::vector<dp_point_type> ref_candidates(boost::begin(range), + boost::end(range)); + + // Include first and last point of line, + // they are always part of the line + int n = 2; + ref_candidates.front().included = true; + ref_candidates.back().included = true; + + // Get points, recursively, including them if they are further away + // than the specified distance + typedef typename strategy::distance::services::return_type<distance_strategy_type>::type return_type; + + consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy); + + // Copy included elements to the output + for(typename std::vector<dp_point_type>::const_iterator it + = boost::begin(ref_candidates); + it != boost::end(ref_candidates); + ++it) + { + if (it->included) + { + // copy-coordinates does not work because OutputIterator + // does not model Point (??) + //geometry::convert(it->p, *out); + *out = it->p; + out++; + } + } + return out; + } + +}; + +}} // namespace strategy::simplify + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP diff --git a/boost/geometry/strategies/area.hpp b/boost/geometry/strategies/area.hpp new file mode 100644 index 0000000000..e192d9b28b --- /dev/null +++ b/boost/geometry/strategies/area.hpp @@ -0,0 +1,50 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_AREA_HPP +#define BOOST_GEOMETRY_STRATEGIES_AREA_HPP + +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/strategies/tags.hpp> + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace area { namespace services +{ + +/*! + \brief Traits class binding a default area strategy to a coordinate system + \ingroup area + \tparam Tag tag of coordinate system + \tparam PointOfSegment point-type +*/ +template <typename Tag, typename PointOfSegment> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE + , (types<PointOfSegment>) + ); +}; + + +}}} // namespace strategy::area::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_AREA_HPP diff --git a/boost/geometry/strategies/cartesian/area_surveyor.hpp b/boost/geometry/strategies/cartesian/area_surveyor.hpp new file mode 100644 index 0000000000..74b63532c0 --- /dev/null +++ b/boost/geometry/strategies/cartesian/area_surveyor.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP + + +#include <boost/mpl/if.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + +/*! +\brief Area calculation for cartesian points +\ingroup strategies +\details Calculates area using the Surveyor's formula, a well-known + triangulation algorithm +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] +} + +*/ +template +< + typename PointOfSegment, + typename CalculationType = void +> +class surveyor +{ +public : + // If user specified a calculation type, use that type, + // whatever it is and whatever the point-type is. + // Else, use the pointtype, but at least double + typedef typename + boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename coordinate_type<PointOfSegment>::type, + double + >::type, + CalculationType + >::type return_type; + + +private : + + class summation + { + friend class surveyor; + + return_type sum; + public : + + inline summation() : sum(return_type()) + { + // Strategy supports only 2D areas + assert_dimension<PointOfSegment, 2>(); + } + inline return_type area() const + { + return_type result = sum; + return_type const two = 2; + result /= two; + return result; + } + }; + +public : + typedef summation state_type; + typedef PointOfSegment segment_point_type; + + static inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + summation& state) + { + // SUM += x2 * y1 - x1 * y2; + state.sum += detail::determinant<return_type>(p2, p1); + } + + static inline return_type result(summation const& state) + { + return state.area(); + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + template <typename Point> + struct default_strategy<cartesian_tag, Point> + { + typedef strategy::area::surveyor<Point> type; + }; + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::area + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP diff --git a/boost/geometry/strategies/cartesian/box_in_box.hpp b/boost/geometry/strategies/cartesian/box_in_box.hpp new file mode 100644 index 0000000000..7680b8362c --- /dev/null +++ b/boost/geometry/strategies/cartesian/box_in_box.hpp @@ -0,0 +1,176 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry { namespace strategy +{ + + +namespace within +{ + +struct box_within_range +{ + template <typename BoxContainedValue, typename BoxContainingValue> + static inline bool apply(BoxContainedValue const& bed_min + , BoxContainedValue const& bed_max + , BoxContainingValue const& bing_min + , BoxContainingValue const& bing_max) + { + return bed_min > bing_min && bed_max < bing_max; + } +}; + + +struct box_covered_by_range +{ + template <typename BoxContainedValue, typename BoxContainingValue> + static inline bool apply(BoxContainedValue const& bed_min + , BoxContainedValue const& bed_max + , BoxContainingValue const& bing_min + , BoxContainingValue const& bing_max) + { + return bed_min >= bing_min && bed_max <= bing_max; + } +}; + + +template +< + typename SubStrategy, + typename Box1, + typename Box2, + std::size_t Dimension, + std::size_t DimensionCount +> +struct relate_box_box_loop +{ + static inline bool apply(Box1 const& b_contained, Box2 const& b_containing) + { + assert_dimension_equal<Box1, Box2>(); + + if (! SubStrategy::apply( + get<min_corner, Dimension>(b_contained), + get<max_corner, Dimension>(b_contained), + get<min_corner, Dimension>(b_containing), + get<max_corner, Dimension>(b_containing) + ) + ) + { + return false; + } + + return relate_box_box_loop + < + SubStrategy, + Box1, Box2, + Dimension + 1, DimensionCount + >::apply(b_contained, b_containing); + } +}; + +template +< + typename SubStrategy, + typename Box1, + typename Box2, + std::size_t DimensionCount +> +struct relate_box_box_loop<SubStrategy, Box1, Box2, DimensionCount, DimensionCount> +{ + static inline bool apply(Box1 const& , Box2 const& ) + { + return true; + } +}; + +template +< + typename Box1, + typename Box2, + typename SubStrategy = box_within_range +> +struct box_in_box +{ + static inline bool apply(Box1 const& box1, Box2 const& box2) + { + return relate_box_box_loop + < + SubStrategy, + Box1, Box2, 0, dimension<Box1>::type::value + >::apply(box1, box2); + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template <typename BoxContained, typename BoxContaining> +struct default_strategy + < + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, + BoxContained, BoxContaining + > +{ + typedef within::box_in_box<BoxContained, BoxContaining> type; +}; + + +}} // namespace within::services + +namespace covered_by { namespace services +{ + +template <typename BoxContained, typename BoxContaining> +struct default_strategy + < + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, + BoxContained, BoxContaining + > +{ + typedef within::box_in_box + < + BoxContained, BoxContaining, + within::box_covered_by_range + > type; +}; + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP diff --git a/boost/geometry/strategies/cartesian/cart_intersect.hpp b/boost/geometry/strategies/cartesian/cart_intersect.hpp new file mode 100644 index 0000000000..2bf7b77676 --- /dev/null +++ b/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -0,0 +1,502 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_CARTESIAN_INTERSECTION_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_INTERSECTION_HPP + +#include <algorithm> + +#include <boost/geometry/core/exception.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/concepts/segment_concept.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/algorithms/detail/assign_values.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +// Temporary / will be Strategy as template parameter +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> + +#include <boost/geometry/strategies/side_info.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace intersection +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Segment, size_t Dimension> +struct segment_arrange +{ + template <typename T> + static inline void apply(Segment const& s, T& s_1, T& s_2, bool& swapped) + { + s_1 = get<0, Dimension>(s); + s_2 = get<1, Dimension>(s); + if (s_1 > s_2) + { + std::swap(s_1, s_2); + swapped = true; + } + } +}; + +template <std::size_t Index, typename Segment> +inline typename geometry::point_type<Segment>::type get_from_index( + Segment const& segment) +{ + typedef typename geometry::point_type<Segment>::type point_type; + point_type point; + geometry::detail::assign::assign_point_from_index + < + Segment, point_type, Index, 0, dimension<Segment>::type::value + >::apply(segment, point); + return point; +} + +} +#endif + +/*** +template <typename T> +inline std::string rdebug(T const& value) +{ + if (math::equals(value, 0)) return "'0'"; + if (math::equals(value, 1)) return "'1'"; + if (value < 0) return "<0"; + if (value > 1) return ">1"; + return "<0..1>"; +} +***/ + +/*! + \see http://mathworld.wolfram.com/Line-LineIntersection.html + */ +template <typename Policy, typename CalculationType = void> +struct relate_cartesian_segments +{ + typedef typename Policy::return_type return_type; + typedef typename Policy::segment_type1 segment_type1; + typedef typename Policy::segment_type2 segment_type2; + + //typedef typename point_type<segment_type1>::type point_type; + //BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) ); + + BOOST_CONCEPT_ASSERT( (concept::ConstSegment<segment_type1>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstSegment<segment_type2>) ); + + typedef typename select_calculation_type + <segment_type1, segment_type2, CalculationType>::type coordinate_type; + + /// Relate segments a and b + static inline return_type apply(segment_type1 const& a, segment_type2 const& b) + { + coordinate_type const dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir + coordinate_type const dx_b = get<1, 0>(b) - get<0, 0>(b); + coordinate_type const dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir + coordinate_type const dy_b = get<1, 1>(b) - get<0, 1>(b); + return apply(a, b, dx_a, dy_a, dx_b, dy_b); + } + + + // Relate segments a and b using precalculated differences. + // This can save two or four subtractions in many cases + static inline return_type apply(segment_type1 const& a, segment_type2 const& b, + coordinate_type const& dx_a, coordinate_type const& dy_a, + coordinate_type const& dx_b, coordinate_type const& dy_b) + { + // 1) Handle "disjoint", common case. + // per dimension, 2 cases: a_1----------a_2 b_1-------b_2 or B left of A + coordinate_type ax_1, ax_2, bx_1, bx_2; + bool ax_swapped = false, bx_swapped = false; + detail::segment_arrange<segment_type1, 0>::apply(a, ax_1, ax_2, ax_swapped); + detail::segment_arrange<segment_type2, 0>::apply(b, bx_1, bx_2, bx_swapped); + if (ax_2 < bx_1 || ax_1 > bx_2) + { + return Policy::disjoint(); + } + + // 1b) In Y-dimension + coordinate_type ay_1, ay_2, by_1, by_2; + bool ay_swapped = false, by_swapped = false; + detail::segment_arrange<segment_type1, 1>::apply(a, ay_1, ay_2, ay_swapped); + detail::segment_arrange<segment_type2, 1>::apply(b, by_1, by_2, by_swapped); + if (ay_2 < by_1 || ay_1 > by_2) + { + return Policy::disjoint(); + } + + typedef side::side_by_triangle<coordinate_type> side; + side_info sides; + + // 2) Calculate sides + // Note: Do NOT yet calculate the determinant here, but use the SIDE strategy. + // Determinant calculation is not robust; side (orient) can be made robust + // (and is much robuster even without measures) + sides.set<1> + ( + side::apply(detail::get_from_index<0>(a) + , detail::get_from_index<1>(a) + , detail::get_from_index<0>(b)), + side::apply(detail::get_from_index<0>(a) + , detail::get_from_index<1>(a) + , detail::get_from_index<1>(b)) + ); + + if (sides.same<1>()) + { + // Both points are at same side of other segment, we can leave + return Policy::disjoint(); + } + + // 2b) For other segment + sides.set<0> + ( + side::apply(detail::get_from_index<0>(b) + , detail::get_from_index<1>(b) + , detail::get_from_index<0>(a)), + side::apply(detail::get_from_index<0>(b) + , detail::get_from_index<1>(b) + , detail::get_from_index<1>(a)) + ); + + if (sides.same<0>()) + { + return Policy::disjoint(); + } + + // Degenerate cases: segments of single point, lying on other segment, non disjoint + coordinate_type const zero = 0; + if (math::equals(dx_a, zero) && math::equals(dy_a, zero)) + { + return Policy::degenerate(a, true); + } + if (math::equals(dx_b, zero) && math::equals(dy_b, zero)) + { + return Policy::degenerate(b, false); + } + + bool collinear = sides.collinear(); + + // Get the same type, but at least a double (also used for divisions) + typedef typename select_most_precise + < + coordinate_type, double + >::type promoted_type; + + // Calculate the determinant/2D cross product + // (Note, because we only check on zero, + // the order a/b does not care) + promoted_type const d = geometry::detail::determinant + < + promoted_type + >(dx_a, dy_a, dx_b, dy_b); + + // Determinant d should be nonzero. + // If it is zero, we have an robustness issue here, + // (and besides that we cannot divide by it) + promoted_type const pt_zero = promoted_type(); + if(math::equals(d, pt_zero) && ! collinear) + { +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION + std::cout << "Determinant zero? Type : " + << typeid(coordinate_type).name() + << std::endl; + + std::cout << " dx_a : " << dx_a << std::endl; + std::cout << " dy_a : " << dy_a << std::endl; + std::cout << " dx_b : " << dx_b << std::endl; + std::cout << " dy_b : " << dy_b << std::endl; + + std::cout << " side a <-> b.first : " << sides.get<0,0>() << std::endl; + std::cout << " side a <-> b.second: " << sides.get<0,1>() << std::endl; + std::cout << " side b <-> a.first : " << sides.get<1,0>() << std::endl; + std::cout << " side b <-> a.second: " << sides.get<1,1>() << std::endl; +#endif + + if (sides.as_collinear()) + { + sides.set<0>(0,0); + sides.set<1>(0,0); + collinear = true; + } + else + { + return Policy::error("Determinant zero!"); + } + } + + if(collinear) + { + // Segments are collinear. We'll find out how. + if (math::equals(dx_b, zero)) + { + // Vertical -> Check y-direction + return relate_collinear(a, b, + ay_1, ay_2, by_1, by_2, + ay_swapped, by_swapped); + } + else + { + // Check x-direction + return relate_collinear(a, b, + ax_1, ax_2, bx_1, bx_2, + ax_swapped, bx_swapped); + } + } + + return Policy::segments_intersect(sides, + dx_a, dy_a, dx_b, dy_b, + a, b); + } + +private : + + /// Relate segments known collinear + static inline return_type relate_collinear(segment_type1 const& a + , segment_type2 const& b + , coordinate_type a_1, coordinate_type a_2 + , coordinate_type b_1, coordinate_type b_2 + , bool a_swapped, bool b_swapped) + { + // All ca. 150 lines are about collinear rays + // The intersections, if any, are always boundary points of the segments. No need to calculate anything. + // However we want to find out HOW they intersect, there are many cases. + // Most sources only provide the intersection (above) or that there is a collinearity (but not the points) + // or some spare sources give the intersection points (calculated) but not how they align. + // This source tries to give everything and still be efficient. + // It is therefore (and because of the extensive clarification comments) rather long... + + // \see http://mpa.itc.it/radim/g50history/CMP/4.2.1-CERL-beta-libes/file475.txt + // \see http://docs.codehaus.org/display/GEOTDOC/Point+Set+Theory+and+the+DE-9IM+Matrix + // \see http://mathworld.wolfram.com/Line-LineIntersection.html + + // Because of collinearity the case is now one-dimensional and can be checked using intervals + // This function is called either horizontally or vertically + // We get then two intervals: + // a_1-------------a_2 where a_1 < a_2 + // b_1-------------b_2 where b_1 < b_2 + // In all figures below a_1/a_2 denotes arranged intervals, a1-a2 or a2-a1 are still unarranged + + // Handle "equal", in polygon neighbourhood comparisons a common case + + // Check if segments are equal... + bool const a1_eq_b1 = math::equals(get<0, 0>(a), get<0, 0>(b)) + && math::equals(get<0, 1>(a), get<0, 1>(b)); + bool const a2_eq_b2 = math::equals(get<1, 0>(a), get<1, 0>(b)) + && math::equals(get<1, 1>(a), get<1, 1>(b)); + if (a1_eq_b1 && a2_eq_b2) + { + return Policy::segment_equal(a, false); + } + + // ... or opposite equal + bool const a1_eq_b2 = math::equals(get<0, 0>(a), get<1, 0>(b)) + && math::equals(get<0, 1>(a), get<1, 1>(b)); + bool const a2_eq_b1 = math::equals(get<1, 0>(a), get<0, 0>(b)) + && math::equals(get<1, 1>(a), get<0, 1>(b)); + if (a1_eq_b2 && a2_eq_b1) + { + return Policy::segment_equal(a, true); + } + + + // The rest below will return one or two intersections. + // The delegated class can decide which is the intersection point, or two, build the Intersection Matrix (IM) + // For IM it is important to know which relates to which. So this information is given, + // without performance penalties to intersection calculation + + bool const has_common_points = a1_eq_b1 || a1_eq_b2 || a2_eq_b1 || a2_eq_b2; + + + // "Touch" -> one intersection point -> one but not two common points + // --------> A (or B) + // <---------- B (or A) + // a_2==b_1 (b_2==a_1 or a_2==b1) + + // The check a_2/b_1 is necessary because it excludes cases like + // -------> + // ---> + // ... which are handled lateron + + // Corresponds to 4 cases, of which the equal points are determined above + // #1: a1---->a2 b1--->b2 (a arrives at b's border) + // #2: a2<----a1 b2<---b1 (b arrives at a's border) + // #3: a1---->a2 b2<---b1 (both arrive at each others border) + // #4: a2<----a1 b1--->b2 (no arrival at all) + // Where the arranged forms have two forms: + // a_1-----a_2/b_1-------b_2 or reverse (B left of A) + if (has_common_points && (math::equals(a_2, b_1) || math::equals(b_2, a_1))) + { + if (a2_eq_b1) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, -1); + if (a1_eq_b2) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, 0); + if (a2_eq_b2) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, 0); + if (a1_eq_b1) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, -1); + } + + + // "Touch/within" -> there are common points and also an intersection of interiors: + // Corresponds to many cases: + // #1a: a1------->a2 #1b: a1-->a2 + // b1--->b2 b1------->b2 + // #2a: a2<-------a1 #2b: a2<--a1 + // b1--->b2 b1------->b2 + // #3a: a1------->a2 #3b: a1-->a2 + // b2<---b1 b2<-------b1 + // #4a: a2<-------a1 #4b: a2<--a1 + // b2<---b1 b2<-------b1 + + // Note: next cases are similar and handled by the code + // #4c: a1--->a2 + // b1-------->b2 + // #4d: a1-------->a2 + // b1-->b2 + + // For case 1-4: a_1 < (b_1 or b_2) < a_2, two intersections are equal to segment B + // For case 5-8: b_1 < (a_1 or a_2) < b_2, two intersections are equal to segment A + if (has_common_points) + { + // Either A is in B, or B is in A, or (in case of robustness/equals) + // both are true, see below + bool a_in_b = (b_1 < a_1 && a_1 < b_2) || (b_1 < a_2 && a_2 < b_2); + bool b_in_a = (a_1 < b_1 && b_1 < a_2) || (a_1 < b_2 && b_2 < a_2); + + if (a_in_b && b_in_a) + { + // testcase "ggl_list_20110306_javier" + // In robustness it can occur that a point of A is inside B AND a point of B is inside A, + // still while has_common_points is true (so one point equals the other). + // If that is the case we select on length. + coordinate_type const length_a = geometry::math::abs(a_1 - a_2); + coordinate_type const length_b = geometry::math::abs(b_1 - b_2); + if (length_a > length_b) + { + a_in_b = false; + } + else + { + b_in_a = false; + } + } + + int const arrival_a = a_in_b ? 1 : -1; + if (a2_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, 0, false); + if (a1_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, 0, true); + if (a2_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, -arrival_a, true); + if (a1_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, -arrival_a, false); + } + + bool const opposite = a_swapped ^ b_swapped; + + + // "Inside", a completely within b or b completely within a + // 2 cases: + // case 1: + // a_1---a_2 -> take A's points as intersection points + // b_1------------b_2 + // case 2: + // a_1------------a_2 + // b_1---b_2 -> take B's points + if (a_1 > b_1 && a_2 < b_2) + { + // A within B + return Policy::collinear_a_in_b(a, opposite); + } + if (b_1 > a_1 && b_2 < a_2) + { + // B within A + return Policy::collinear_b_in_a(b, opposite); + } + + + /* + + Now that all cases with equal,touch,inside,disjoint, + degenerate are handled the only thing left is an overlap + + Either a1 is between b1,b2 + or a2 is between b1,b2 (a2 arrives) + + Next table gives an overview. + The IP's are ordered following the line A1->A2 + + | | + | a_2 in between | a_1 in between + | | + -----+---------------------------------+-------------------------- + | a1--------->a2 | a1--------->a2 + | b1----->b2 | b1----->b2 + | (b1,a2), a arrives | (a1,b2), b arrives + | | + -----+---------------------------------+-------------------------- + a sw.| a2<---------a1* | a2<---------a1* + | b1----->b2 | b1----->b2 + | (a1,b1), no arrival | (b2,a2), a and b arrive + | | + -----+---------------------------------+-------------------------- + | a1--------->a2 | a1--------->a2 + b sw.| b2<-----b1 | b2<-----b1 + | (b2,a2), a and b arrive | (a1,b1), no arrival + | | + -----+---------------------------------+-------------------------- + a sw.| a2<---------a1* | a2<---------a1* + b sw.| b2<-----b1 | b2<-----b1 + | (a1,b2), b arrives | (b1,a2), a arrives + | | + -----+---------------------------------+-------------------------- + * Note that a_1 < a_2, and a1 <> a_1; if a is swapped, + the picture might seem wrong but it (supposed to be) is right. + */ + + bool const both_swapped = a_swapped && b_swapped; + if (b_1 < a_2 && a_2 < b_2) + { + // Left column, from bottom to top + return + both_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite) + : b_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite) + : a_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite) + : Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite) + ; + } + if (b_1 < a_1 && a_1 < b_2) + { + // Right column, from bottom to top + return + both_swapped ? Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite) + : b_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite) + : a_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite) + : Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite) + ; + } + // Nothing should goes through. If any we have made an error + // Robustness: it can occur here... + return Policy::error("Robustness issue, non-logical behaviour"); + } +}; + + +}} // namespace strategy::intersection + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_INTERSECTION_HPP diff --git a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp new file mode 100644 index 0000000000..8b42715e0b --- /dev/null +++ b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp @@ -0,0 +1,242 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP + + +#include <boost/mpl/if.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/strategies/centroid.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + + +namespace boost { namespace geometry +{ + +// Note: when calling the namespace "centroid", it sometimes, +// somehow, in gcc, gives compilation problems (confusion with function centroid). + +namespace strategy { namespace centroid +{ + + + +/*! +\brief Centroid calculation using algorith Bashein / Detmer +\ingroup strategies +\details Calculates centroid using triangulation method published by + Bashein / Detmer +\tparam Point point type of centroid to calculate +\tparam PointOfSegment point type of segments, defaults to Point +\par Concepts for Point and PointOfSegment: +- specialized point_traits class +\author Adapted from "Centroid of a Polygon" by + Gerard Bashein and Paul R. Detmer<em>, +in "Graphics Gems IV", Academic Press, 1994</em> +\par Research notes +The algorithm gives the same results as Oracle and PostGIS but + differs from MySQL +(tried 5.0.21 / 5.0.45 / 5.0.51a / 5.1.23). + +Without holes: +- this: POINT(4.06923363095238 1.65055803571429) +- geolib: POINT(4.07254 1.66819) +- MySQL: POINT(3.6636363636364 1.6272727272727)' +- PostGIS: POINT(4.06923363095238 1.65055803571429) +- Oracle: 4.06923363095238 1.65055803571429 +- SQL Server: POINT(4.06923362245959 1.65055804168294) + +Statements: +- \b MySQL/PostGIS: select AsText(Centroid(GeomFromText( + 'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6 + ,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))'))) +- \b Oracle: select sdo_geom.sdo_centroid(sdo_geometry(2003, null, null, + sdo_elem_info_array(1, 1003, 1), sdo_ordinate_array( + 2,1.3,2.4,1.7,2.8,1.8,3.4,1.2,3.7,1.6,3.4,2,4.1,3,5.3,2.6 + ,5.4,1.2,4.9,0.8,2.9,0.7,2,1.3)) + , mdsys.sdo_dim_array(mdsys.sdo_dim_element('x',0,10,.00000005) + ,mdsys.sdo_dim_element('y',0,10,.00000005))) + from dual +- \b SQL Server 2008: select geometry::STGeomFromText( + 'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6 + ,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))',0) + .STCentroid() + .STAsText() + +With holes: +- this: POINT(4.04663 1.6349) +- geolib: POINT(4.04675 1.65735) +- MySQL: POINT(3.6090580503834 1.607573932092) +- PostGIS: POINT(4.0466265060241 1.63489959839357) +- Oracle: 4.0466265060241 1.63489959839357 +- SQL Server: POINT(4.0466264962959677 1.6348996057331333) + +Statements: +- \b MySQL/PostGIS: select AsText(Centroid(GeomFromText( + 'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2 + ,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3) + ,(4 2,4.2 1.4,4.8 1.9,4.4 2.2,4 2))'))); +- \b Oracle: select sdo_geom.sdo_centroid(sdo_geometry(2003, null, null + , sdo_elem_info_array(1, 1003, 1, 25, 2003, 1) + , sdo_ordinate_array(2,1.3,2.4,1.7,2.8,1.8,3.4,1.2,3.7,1.6,3.4, + 2,4.1,3,5.3,2.6,5.4,1.2,4.9,0.8,2.9,0.7,2,1.3,4,2, 4.2,1.4, + 4.8,1.9, 4.4,2.2, 4,2)) + , mdsys.sdo_dim_array(mdsys.sdo_dim_element('x',0,10,.00000005) + ,mdsys.sdo_dim_element('y',0,10,.00000005))) + from dual + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.centroid.centroid_3_with_strategy centroid (with strategy)] +} + + */ +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void +> +class bashein_detmer +{ +private : + // If user specified a calculation type, use that type, + // whatever it is and whatever the point-type(s) are. + // Else, use the most appropriate coordinate type + // of the two points, but at least double + typedef typename + boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename select_coordinate_type + < + Point, + PointOfSegment + >::type, + double + >::type, + CalculationType + >::type calculation_type; + + /*! subclass to keep state */ + class sums + { + friend class bashein_detmer; + int count; + calculation_type sum_a2; + calculation_type sum_x; + calculation_type sum_y; + + public : + inline sums() + : count(0) + , sum_a2(calculation_type()) + , sum_x(calculation_type()) + , sum_y(calculation_type()) + { + typedef calculation_type ct; + } + }; + +public : + typedef sums state_type; + + static inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, sums& state) + { + /* Algorithm: + For each segment: + begin + ai = x1 * y2 - x2 * y1; + sum_a2 += ai; + sum_x += ai * (x1 + x2); + sum_y += ai * (y1 + y2); + end + return POINT(sum_x / (3 * sum_a2), sum_y / (3 * sum_a2) ) + */ + + // Get coordinates and promote them to calculation_type + calculation_type const x1 = boost::numeric_cast<calculation_type>(get<0>(p1)); + calculation_type const y1 = boost::numeric_cast<calculation_type>(get<1>(p1)); + calculation_type const x2 = boost::numeric_cast<calculation_type>(get<0>(p2)); + calculation_type const y2 = boost::numeric_cast<calculation_type>(get<1>(p2)); + calculation_type const ai = geometry::detail::determinant<calculation_type>(p1, p2); + state.count++; + state.sum_a2 += ai; + state.sum_x += ai * (x1 + x2); + state.sum_y += ai * (y1 + y2); + } + + static inline bool result(sums const& state, Point& centroid) + { + calculation_type const zero = calculation_type(); + if (state.count > 0 && ! math::equals(state.sum_a2, zero)) + { + calculation_type const v3 = 3; + calculation_type const a3 = v3 * state.sum_a2; + + typedef typename geometry::coordinate_type + < + Point + >::type coordinate_type; + + set<0>(centroid, + boost::numeric_cast<coordinate_type>(state.sum_x / a3)); + set<1>(centroid, + boost::numeric_cast<coordinate_type>(state.sum_y / a3)); + return true; + } + + return false; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +// Register this strategy for rings and (multi)polygons, in two dimensions +template <typename Point, typename Geometry> +struct default_strategy<cartesian_tag, areal_tag, 2, Point, Geometry> +{ + typedef bashein_detmer + < + Point, + typename point_type<Geometry>::type + > type; +}; + + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::centroid + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP diff --git a/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp new file mode 100644 index 0000000000..48feae51df --- /dev/null +++ b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP + +#include <boost/geometry/algorithms/distance.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/util/select_most_precise.hpp> +#include <boost/geometry/strategies/centroid.hpp> +#include <boost/geometry/strategies/default_distance_result.hpp> + +// Helper geometry +#include <boost/geometry/geometries/point.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace centroid +{ + +namespace detail +{ + +template <typename Type, std::size_t DimensionCount> +struct weighted_length_sums +{ + typedef typename geometry::model::point + < + Type, DimensionCount, + cs::cartesian + > work_point; + + Type length; + work_point average_sum; + + inline weighted_length_sums() + : length(Type()) + { + geometry::assign_zero(average_sum); + } +}; +} + +template +< + typename Point, + typename PointOfSegment = Point +> +class weighted_length +{ +private : + typedef typename select_most_precise + < + typename default_distance_result<Point>::type, + typename default_distance_result<PointOfSegment>::type + >::type distance_type; + +public : + typedef detail::weighted_length_sums + < + distance_type, + geometry::dimension<Point>::type::value + > state_type; + + static inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, state_type& state) + { + distance_type const d = geometry::distance(p1, p2); + state.length += d; + + typename state_type::work_point weighted_median; + geometry::assign_zero(weighted_median); + geometry::add_point(weighted_median, p1); + geometry::add_point(weighted_median, p2); + geometry::multiply_value(weighted_median, d/2); + geometry::add_point(state.average_sum, weighted_median); + } + + static inline bool result(state_type const& state, Point& centroid) + { + distance_type const zero = distance_type(); + if (! geometry::math::equals(state.length, zero)) + { + assign_zero(centroid); + add_point(centroid, state.average_sum); + divide_value(centroid, state.length); + return true; + } + + return false; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +// Register this strategy for linear geometries, in all dimensions + +template <std::size_t N, typename Point, typename Geometry> +struct default_strategy +< + cartesian_tag, + linear_tag, + N, + Point, + Geometry +> +{ + typedef weighted_length + < + Point, + typename point_type<Geometry>::type + > type; +}; + + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::centroid + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP diff --git a/boost/geometry/strategies/cartesian/distance_projected_point.hpp b/boost/geometry/strategies/cartesian/distance_projected_point.hpp new file mode 100644 index 0000000000..e704a33105 --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_projected_point.hpp @@ -0,0 +1,315 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP + + +#include <boost/concept_check.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/arithmetic/dot_product.hpp> + +#include <boost/geometry/strategies/tags.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/default_distance_result.hpp> +#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp> + +#include <boost/geometry/util/select_coordinate_type.hpp> + +// Helper geometry (projected point on line) +#include <boost/geometry/geometries/point.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace distance +{ + + +/*! +\brief Strategy for distance point to segment +\ingroup strategies +\details Calculates distance using projected-point method, and (optionally) Pythagoras +\author Adapted from: http://geometryalgorithms.com/Archive/algorithm_0102/algorithm_0102.htm +\tparam Point \tparam_point +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\tparam Strategy underlying point-point distance strategy +\par Concepts for Strategy: +- cartesian_distance operator(Point,Point) +\note If the Strategy is a "comparable::pythagoras", this strategy + automatically is a comparable projected_point strategy (so without sqrt) + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void, + typename Strategy = pythagoras<Point, PointOfSegment, CalculationType> +> +class projected_point +{ +public : + typedef typename strategy::distance::services::return_type<Strategy>::type calculation_type; + +private : + + // The three typedefs below are necessary to calculate distances + // from segments defined in integer coordinates. + + // Integer coordinates can still result in FP distances. + // There is a division, which must be represented in FP. + // So promote. + typedef typename promote_floating_point<calculation_type>::type fp_type; + + // A projected point of points in Integer coordinates must be able to be + // represented in FP. + typedef model::point + < + fp_type, + dimension<PointOfSegment>::value, + typename coordinate_system<PointOfSegment>::type + > fp_point_type; + + // For convenience + typedef fp_point_type fp_vector_type; + + // We have to use a strategy using FP coordinates (fp-type) which is + // not always the same as Strategy (defined as point_strategy_type) + // So we create a "similar" one + typedef typename strategy::distance::services::similar_type + < + Strategy, + Point, + fp_point_type + >::type fp_strategy_type; + +public : + + inline calculation_type apply(Point const& p, + PointOfSegment const& p1, PointOfSegment const& p2) const + { + assert_dimension_equal<Point, PointOfSegment>(); + + /* + Algorithm [p1: (x1,y1), p2: (x2,y2), p: (px,py)] + VECTOR v(x2 - x1, y2 - y1) + VECTOR w(px - x1, py - y1) + c1 = w . v + c2 = v . v + b = c1 / c2 + RETURN POINT(x1 + b * vx, y1 + b * vy) + */ + + // v is multiplied below with a (possibly) FP-value, so should be in FP + // For consistency we define w also in FP + fp_vector_type v, w; + + geometry::convert(p2, v); + geometry::convert(p, w); + subtract_point(v, p1); + subtract_point(w, p1); + + Strategy strategy; + boost::ignore_unused_variable_warning(strategy); + + calculation_type const zero = calculation_type(); + fp_type const c1 = dot_product(w, v); + if (c1 <= zero) + { + return strategy.apply(p, p1); + } + fp_type const c2 = dot_product(v, v); + if (c2 <= c1) + { + return strategy.apply(p, p2); + } + + // See above, c1 > 0 AND c2 > c1 so: c2 != 0 + fp_type const b = c1 / c2; + + fp_strategy_type fp_strategy + = strategy::distance::services::get_similar + < + Strategy, Point, fp_point_type + >::apply(strategy); + + fp_point_type projected; + geometry::convert(p1, projected); + multiply_value(v, b); + add_point(projected, v); + + //std::cout << "distance " << dsv(p) << " .. " << dsv(projected) << std::endl; + + return fp_strategy.apply(p, projected); + } +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct tag<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef strategy_tag_distance_point_segment type; +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct return_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef typename projected_point<Point, PointOfSegment, CalculationType, Strategy>::calculation_type type; +}; + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct strategy_point_point<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef Strategy type; +}; + + +template +< + typename Point, + typename PointOfSegment, + typename CalculationType, + typename Strategy, + typename P1, + typename P2 +> +struct similar_type<projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2> +{ + typedef projected_point<P1, P2, CalculationType, Strategy> type; +}; + + +template +< + typename Point, + typename PointOfSegment, + typename CalculationType, + typename Strategy, + typename P1, + typename P2 +> +struct get_similar<projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2> +{ + static inline typename similar_type + < + projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2 + >::type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& ) + { + return projected_point<P1, P2, CalculationType, Strategy>(); + } +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct comparable_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ + // Define a projected_point strategy with its underlying point-point-strategy + // being comparable + typedef projected_point + < + Point, + PointOfSegment, + CalculationType, + typename comparable_type<Strategy>::type + > type; +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct get_comparable<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef typename comparable_type + < + projected_point<Point, PointOfSegment, CalculationType, Strategy> + >::type comparable_type; +public : + static inline comparable_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& ) + { + return comparable_type(); + } +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct result_from_distance<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +{ +private : + typedef typename return_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> >::type return_type; +public : + template <typename T> + static inline return_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& , T const& value) + { + Strategy s; + return result_from_distance<Strategy>::apply(s, value); + } +}; + + +// Get default-strategy for point-segment distance calculation +// while still have the possibility to specify point-point distance strategy (PPS) +// It is used in algorithms/distance.hpp where users specify PPS for distance +// of point-to-segment or point-to-linestring. +// Convenient for geographic coordinate systems especially. +template <typename Point, typename PointOfSegment, typename Strategy> +struct default_strategy<segment_tag, Point, PointOfSegment, cartesian_tag, cartesian_tag, Strategy> +{ + typedef strategy::distance::projected_point + < + Point, + PointOfSegment, + void, + typename boost::mpl::if_ + < + boost::is_void<Strategy>, + typename default_strategy + < + point_tag, Point, PointOfSegment, + cartesian_tag, cartesian_tag + >::type, + Strategy + >::type + > type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp new file mode 100644 index 0000000000..51d2722663 --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp @@ -0,0 +1,349 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP + + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/access.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/calculation_type.hpp> + + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Point1, typename Point2, size_t I, typename T> +struct compute_pythagoras +{ + static inline T apply(Point1 const& p1, Point2 const& p2) + { + T const c1 = boost::numeric_cast<T>(get<I-1>(p2)); + T const c2 = boost::numeric_cast<T>(get<I-1>(p1)); + T const d = c1 - c2; + return d * d + compute_pythagoras<Point1, Point2, I-1, T>::apply(p1, p2); + } +}; + +template <typename Point1, typename Point2, typename T> +struct compute_pythagoras<Point1, Point2, 0, T> +{ + static inline T apply(Point1 const&, Point2 const&) + { + return boost::numeric_cast<T>(0); + } +}; + +} +#endif // DOXYGEN_NO_DETAIL + + +namespace comparable +{ + +/*! +\brief Strategy to calculate comparable distance between two points +\ingroup strategies +\tparam Point1 \tparam_first_point +\tparam Point2 \tparam_second_point +\tparam CalculationType \tparam_calculation +*/ +template +< + typename Point1, + typename Point2 = Point1, + typename CalculationType = void +> +class pythagoras +{ +public : + + typedef typename util::calculation_type::geometric::binary + < + Point1, + Point2, + CalculationType + >::type calculation_type; + + static inline calculation_type apply(Point1 const& p1, Point2 const& p2) + { + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point1>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); + + // Calculate distance using Pythagoras + // (Leave comment above for Doxygen) + + assert_dimension_equal<Point1, Point2>(); + + return detail::compute_pythagoras + < + Point1, Point2, + dimension<Point1>::value, + calculation_type + >::apply(p1, p2); + } +}; + +} // namespace comparable + + +/*! +\brief Strategy to calculate the distance between two points +\ingroup strategies +\tparam Point1 \tparam_first_point +\tparam Point2 \tparam_second_point +\tparam CalculationType \tparam_calculation + +\qbk{ +[heading Notes] +[note Can be used for points with two\, three or more dimensions] +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename Point1, + typename Point2 = Point1, + typename CalculationType = void +> +class pythagoras +{ + typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type; +public : + typedef typename util::calculation_type::geometric::binary + < + Point1, + Point2, + CalculationType, + double, + double // promote integer to double + >::type calculation_type; + + /*! + \brief applies the distance calculation using pythagoras + \return the calculated distance (including taking the square root) + \param p1 first point + \param p2 second point + */ + static inline calculation_type apply(Point1 const& p1, Point2 const& p2) + { + calculation_type const t = comparable_type::apply(p1, p2); + return sqrt(t); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Point1, typename Point2, typename CalculationType> +struct tag<pythagoras<Point1, Point2, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct return_type<pythagoras<Point1, Point2, CalculationType> > +{ + typedef typename pythagoras<Point1, Point2, CalculationType>::calculation_type type; +}; + + +template +< + typename Point1, + typename Point2, + typename CalculationType, + typename P1, + typename P2 +> +struct similar_type<pythagoras<Point1, Point2, CalculationType>, P1, P2> +{ + typedef pythagoras<P1, P2, CalculationType> type; +}; + + +template +< + typename Point1, + typename Point2, + typename CalculationType, + typename P1, + typename P2 +> +struct get_similar<pythagoras<Point1, Point2, CalculationType>, P1, P2> +{ + static inline typename similar_type + < + pythagoras<Point1, Point2, CalculationType>, P1, P2 + >::type apply(pythagoras<Point1, Point2, CalculationType> const& ) + { + return pythagoras<P1, P2, CalculationType>(); + } +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct comparable_type<pythagoras<Point1, Point2, CalculationType> > +{ + typedef comparable::pythagoras<Point1, Point2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct get_comparable<pythagoras<Point1, Point2, CalculationType> > +{ + typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type; +public : + static inline comparable_type apply(pythagoras<Point1, Point2, CalculationType> const& ) + { + return comparable_type(); + } +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct result_from_distance<pythagoras<Point1, Point2, CalculationType> > +{ +private : + typedef typename return_type<pythagoras<Point1, Point2, CalculationType> >::type return_type; +public : + template <typename T> + static inline return_type apply(pythagoras<Point1, Point2, CalculationType> const& , T const& value) + { + return return_type(value); + } +}; + + +// Specializations for comparable::pythagoras +template <typename Point1, typename Point2, typename CalculationType> +struct tag<comparable::pythagoras<Point1, Point2, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct return_type<comparable::pythagoras<Point1, Point2, CalculationType> > +{ + typedef typename comparable::pythagoras<Point1, Point2, CalculationType>::calculation_type type; +}; + + + + +template +< + typename Point1, + typename Point2, + typename CalculationType, + typename P1, + typename P2 +> +struct similar_type<comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2> +{ + typedef comparable::pythagoras<P1, P2, CalculationType> type; +}; + + +template +< + typename Point1, + typename Point2, + typename CalculationType, + typename P1, + typename P2 +> +struct get_similar<comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2> +{ + static inline typename similar_type + < + comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2 + >::type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& ) + { + return comparable::pythagoras<P1, P2, CalculationType>(); + } +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct comparable_type<comparable::pythagoras<Point1, Point2, CalculationType> > +{ + typedef comparable::pythagoras<Point1, Point2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct get_comparable<comparable::pythagoras<Point1, Point2, CalculationType> > +{ + typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type; +public : + static inline comparable_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& ) + { + return comparable_type(); + } +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct result_from_distance<comparable::pythagoras<Point1, Point2, CalculationType> > +{ +private : + typedef typename return_type<comparable::pythagoras<Point1, Point2, CalculationType> >::type return_type; +public : + template <typename T> + static inline return_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& , T const& value) + { + return_type const v = value; + return v * v; + } +}; + + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, Point1, Point2, cartesian_tag, cartesian_tag, void> +{ + typedef pythagoras<Point1, Point2> type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP diff --git a/boost/geometry/strategies/cartesian/point_in_box.hpp b/boost/geometry/strategies/cartesian/point_in_box.hpp new file mode 100644 index 0000000000..275f7550e4 --- /dev/null +++ b/boost/geometry/strategies/cartesian/point_in_box.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry { namespace strategy +{ + +namespace within +{ + + +struct within_range +{ + template <typename Value1, typename Value2> + static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value) + { + return value > min_value && value < max_value; + } +}; + + +struct covered_by_range +{ + template <typename Value1, typename Value2> + static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value) + { + return value >= min_value && value <= max_value; + } +}; + + +template +< + typename SubStrategy, + typename Point, + typename Box, + std::size_t Dimension, + std::size_t DimensionCount +> +struct relate_point_box_loop +{ + static inline bool apply(Point const& point, Box const& box) + { + if (! SubStrategy::apply(get<Dimension>(point), + get<min_corner, Dimension>(box), + get<max_corner, Dimension>(box)) + ) + { + return false; + } + + return relate_point_box_loop + < + SubStrategy, + Point, Box, + Dimension + 1, DimensionCount + >::apply(point, box); + } +}; + + +template +< + typename SubStrategy, + typename Point, + typename Box, + std::size_t DimensionCount +> +struct relate_point_box_loop<SubStrategy, Point, Box, DimensionCount, DimensionCount> +{ + static inline bool apply(Point const& , Box const& ) + { + return true; + } +}; + + +template +< + typename Point, + typename Box, + typename SubStrategy = within_range +> +struct point_in_box +{ + static inline bool apply(Point const& point, Box const& box) + { + return relate_point_box_loop + < + SubStrategy, + Point, Box, + 0, dimension<Point>::type::value + >::apply(point, box); + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template <typename Point, typename Box> +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, + Point, Box + > +{ + typedef within::point_in_box<Point, Box> type; +}; + + +}} // namespace within::services + + +namespace covered_by { namespace services +{ + + +template <typename Point, typename Box> +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, + Point, Box + > +{ + typedef within::point_in_box + < + Point, Box, + within::covered_by_range + > type; +}; + + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP diff --git a/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp b/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp new file mode 100644 index 0000000000..94da5cc677 --- /dev/null +++ b/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp @@ -0,0 +1,124 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +/*! +\brief Within detection using cross counting, +\ingroup strategies +\tparam Point \tparam_point +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\see http://tog.acm.org/resources/GraphicsGems/gemsiv/ptpoly_haines/ptinpoly.c +\note Does NOT work correctly for point ON border +\qbk{ +[heading See also] +[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)] +} + */ + +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void +> +class crossings_multiply +{ + typedef typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type calculation_type; + + class flags + { + bool inside_flag; + bool first; + bool yflag0; + + public : + + friend class crossings_multiply; + + inline flags() + : inside_flag(false) + , first(true) + , yflag0(false) + {} + }; + +public : + + typedef Point point_type; + typedef PointOfSegment segment_point_type; + typedef flags state_type; + + static inline bool apply(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + flags& state) + { + calculation_type const tx = get<0>(point); + calculation_type const ty = get<1>(point); + calculation_type const x0 = get<0>(seg1); + calculation_type const y0 = get<1>(seg1); + calculation_type const x1 = get<0>(seg2); + calculation_type const y1 = get<1>(seg2); + + if (state.first) + { + state.first = false; + state.yflag0 = y0 >= ty; + } + + + bool yflag1 = y1 >= ty; + if (state.yflag0 != yflag1) + { + if ( ((y1-ty) * (x0-x1) >= (x1-tx) * (y0-y1)) == yflag1 ) + { + state.inside_flag = ! state.inside_flag; + } + } + state.yflag0 = yflag1; + return true; + } + + static inline int result(flags const& state) + { + return state.inside_flag ? 1 : -1; + } +}; + + + +}} // namespace strategy::within + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP diff --git a/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp b/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp new file mode 100644 index 0000000000..a774d3c52d --- /dev/null +++ b/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp @@ -0,0 +1,118 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +/*! +\brief Within detection using cross counting +\ingroup strategies +\tparam Point \tparam_point +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\author adapted from Randolph Franklin algorithm +\author Barend and Maarten, 1995 +\author Revised for templatized library, Barend Gehrels, 2007 +\return true if point is in ring, works for closed rings in both directions +\note Does NOT work correctly for point ON border + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)] +} + */ + +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void +> +class franklin +{ + typedef typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type calculation_type; + + /*! subclass to keep state */ + class crossings + { + bool crosses; + + public : + + friend class franklin; + inline crossings() + : crosses(false) + {} + }; + +public : + + typedef Point point_type; + typedef PointOfSegment segment_point_type; + typedef crossings state_type; + + static inline bool apply(Point const& point, + PointOfSegment const& seg1, PointOfSegment const& seg2, + crossings& state) + { + calculation_type const& px = get<0>(point); + calculation_type const& py = get<1>(point); + calculation_type const& x1 = get<0>(seg1); + calculation_type const& y1 = get<1>(seg1); + calculation_type const& x2 = get<0>(seg2); + calculation_type const& y2 = get<1>(seg2); + + if ( + ( (y2 <= py && py < y1) || (y1 <= py && py < y2) ) + && (px < (x1 - x2) * (py - y2) / (y1 - y2) + x2) + ) + { + state.crosses = ! state.crosses; + } + return true; + } + + static inline int result(crossings const& state) + { + return state.crosses ? 1 : -1; + } +}; + + + +}} // namespace strategy::within + + + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP diff --git a/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/boost/geometry/strategies/cartesian/side_by_triangle.hpp new file mode 100644 index 0000000000..967090c50a --- /dev/null +++ b/boost/geometry/strategies/cartesian/side_by_triangle.hpp @@ -0,0 +1,121 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/strategies/side.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace side +{ + +/*! +\brief Check at which side of a segment a point lies: + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam CalculationType \tparam_calculation + */ +template <typename CalculationType = void> +class side_by_triangle +{ +public : + + // Template member function, because it is not always trivial + // or convenient to explicitly mention the typenames in the + // strategy-struct itself. + + // Types can be all three different. Therefore it is + // not implemented (anymore) as "segment" + + template <typename P1, typename P2, typename P> + static inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename select_most_precise + < + typename coordinate_type<P1>::type, + typename coordinate_type<P2>::type + >::type, + typename coordinate_type<P>::type + >::type, + CalculationType + >::type coordinate_type; + + coordinate_type const x = get<0>(p); + coordinate_type const y = get<1>(p); + + coordinate_type const sx1 = get<0>(p1); + coordinate_type const sy1 = get<1>(p1); + coordinate_type const sx2 = get<0>(p2); + coordinate_type const sy2 = get<1>(p2); + + // Promote float->double, small int->int + typedef typename select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + promoted_type const dx = sx2 - sx1; + promoted_type const dy = sy2 - sy1; + promoted_type const dpx = x - sx1; + promoted_type const dpy = y - sy1; + + promoted_type const s + = geometry::detail::determinant<promoted_type> + ( + dx, dy, + dpx, dpy + ); + + promoted_type const zero = promoted_type(); + return math::equals(s, zero) ? 0 + : s > zero ? 1 + : -1; + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename CalculationType> +struct default_strategy<cartesian_tag, CalculationType> +{ + typedef side_by_triangle<CalculationType> type; +}; + +} +#endif + +}} // namespace strategy::side + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP diff --git a/boost/geometry/strategies/centroid.hpp b/boost/geometry/strategies/centroid.hpp new file mode 100644 index 0000000000..4963e6b40b --- /dev/null +++ b/boost/geometry/strategies/centroid.hpp @@ -0,0 +1,72 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CENTROID_HPP +#define BOOST_GEOMETRY_STRATEGIES_CENTROID_HPP + + +#include <cstddef> + +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/strategies/tags.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace centroid +{ + +struct not_applicable_strategy +{ +}; + + +namespace services +{ + +/*! + \brief Traits class binding a centroid calculation strategy to a coordinate system + \ingroup centroid + \tparam CsTag tag of coordinate system, for specialization + \tparam GeometryTag tag of geometry, for specialization + \tparam Dimension dimension of geometry, for specialization + \tparam Point point-type + \tparam Geometry +*/ +template +< + typename CsTag, + typename GeometryTag, + std::size_t Dimension, + typename Point, + typename Geometry +> +struct default_strategy +{ + typedef not_applicable_strategy type; +}; + + +} // namespace services + + +}} // namespace strategy::centroid + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CENTROID_HPP diff --git a/boost/geometry/strategies/compare.hpp b/boost/geometry/strategies/compare.hpp new file mode 100644 index 0000000000..2958319229 --- /dev/null +++ b/boost/geometry/strategies/compare.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_COMPARE_HPP +#define BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP + +#include <cstddef> +#include <functional> + +#include <boost/mpl/if.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_type.hpp> + +#include <boost/geometry/strategies/tags.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Traits class binding a comparing strategy to a coordinate system + \ingroup util + \tparam Tag tag of coordinate system of point-type + \tparam Direction direction to compare on: 1 for less (-> ascending order) + and -1 for greater (-> descending order) + \tparam Point point-type + \tparam CoordinateSystem coordinate sytem of point + \tparam Dimension: the dimension to compare on +*/ +template +< + typename Tag, + int Direction, + typename Point, + typename CoordinateSystem, + std::size_t Dimension +> +struct strategy_compare +{ + typedef strategy::not_implemented type; +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +// For compare we add defaults specializations, +// because they defaultly redirect to std::less / greater / equal_to +template +< + typename Tag, + typename Point, + typename CoordinateSystem, + std::size_t Dimension +> +struct strategy_compare<Tag, 1, Point, CoordinateSystem, Dimension> +{ + typedef std::less<typename coordinate_type<Point>::type> type; +}; + + +template +< + typename Tag, + typename Point, + typename CoordinateSystem, + std::size_t Dimension +> +struct strategy_compare<Tag, -1, Point, CoordinateSystem, Dimension> +{ + typedef std::greater<typename coordinate_type<Point>::type> type; +}; + + +template +< + typename Tag, + typename Point, + typename CoordinateSystem, + std::size_t Dimension +> +struct strategy_compare<Tag, 0, Point, CoordinateSystem, Dimension> +{ + typedef std::equal_to<typename coordinate_type<Point>::type> type; +}; + + +#endif + + +namespace strategy { namespace compare +{ + + +/*! + \brief Default strategy, indicates the default strategy for comparisons + \details The default strategy for comparisons defer in most cases + to std::less (for ascending) and std::greater (for descending). + However, if a spherical coordinate system is used, and comparison + is done on longitude, it will take another strategy handling circular +*/ +struct default_strategy {}; + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Type> +struct is_default : boost::false_type +{}; + + +template <> +struct is_default<default_strategy> : boost::true_type +{}; + + +/*! + \brief Meta-function to select strategy + \details If "default_strategy" is specified, it will take the + traits-registered class for the specified coordinate system. + If another strategy is explicitly specified, it takes that one. +*/ +template +< + typename Strategy, + int Direction, + typename Point, + std::size_t Dimension +> +struct select_strategy +{ + typedef typename + boost::mpl::if_ + < + is_default<Strategy>, + typename strategy_compare + < + typename cs_tag<Point>::type, + Direction, + Point, + typename coordinate_system<Point>::type, + Dimension + >::type, + Strategy + >::type type; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace strategy::compare + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP diff --git a/boost/geometry/strategies/concepts/area_concept.hpp b/boost/geometry/strategies/concepts/area_concept.hpp new file mode 100644 index 0000000000..75821b52a1 --- /dev/null +++ b/boost/geometry/strategies/concepts/area_concept.hpp @@ -0,0 +1,75 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP + + +#include <boost/concept_check.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for area + \ingroup area +*/ +template <typename Strategy> +class AreaStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // 1) must define state_type, + typedef typename Strategy::state_type state_type; + + // 2) must define return_type, + typedef typename Strategy::return_type return_type; + + // 3) must define point_type, of polygon (segments) + typedef typename Strategy::segment_point_type spoint_type; + + struct check_methods + { + static void apply() + { + Strategy const* str = 0; + state_type *st = 0; + + // 4) must implement a method apply with the following signature + spoint_type const* sp = 0; + str->apply(*sp, *sp, *st); + + // 5) must implement a static method result with the following signature + return_type r = str->result(*st); + + boost::ignore_unused_variable_warning(r); + boost::ignore_unused_variable_warning(str); + } + }; + +public : + BOOST_CONCEPT_USAGE(AreaStrategy) + { + check_methods::apply(); + } + +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/centroid_concept.hpp b/boost/geometry/strategies/concepts/centroid_concept.hpp new file mode 100644 index 0000000000..f493ef6810 --- /dev/null +++ b/boost/geometry/strategies/concepts/centroid_concept.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP + + + +#include <boost/concept_check.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for centroid + \ingroup centroid +*/ +template <typename Strategy> +class CentroidStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // 1) must define state_type, + typedef typename Strategy::state_type state_type; + + // 2) must define point_type, + typedef typename Strategy::point_type point_type; + + // 3) must define point_type, of polygon (segments) + typedef typename Strategy::segment_point_type spoint_type; + + struct check_methods + { + static void apply() + { + Strategy *str = 0; + state_type *st = 0; + + // 4) must implement a static method apply, + // getting two segment-points + spoint_type const* sp = 0; + str->apply(*sp, *sp, *st); + + // 5) must implement a static method result + // getting the centroid + point_type *c = 0; + bool r = str->result(*st, *c); + + boost::ignore_unused_variable_warning(str); + boost::ignore_unused_variable_warning(r); + } + }; + +public : + BOOST_CONCEPT_USAGE(CentroidStrategy) + { + check_methods::apply(); + } +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/convex_hull_concept.hpp b/boost/geometry/strategies/concepts/convex_hull_concept.hpp new file mode 100644 index 0000000000..b31f0caa4e --- /dev/null +++ b/boost/geometry/strategies/concepts/convex_hull_concept.hpp @@ -0,0 +1,75 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP + + +#include <vector> + +#include <boost/concept_check.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for convex_hull + \ingroup convex_hull +*/ +template <typename Strategy> +class ConvexHullStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // 1) must define state_type + typedef typename Strategy::state_type state_type; + + // 2) must define point_type + typedef typename Strategy::point_type point_type; + + // 3) must define geometry_type + typedef typename Strategy::geometry_type geometry_type; + + struct check_methods + { + static void apply() + { + Strategy const* str; + + state_type* st; + geometry_type* sp; + std::vector<point_type> *v; + + // 4) must implement a method apply, iterating over a range + str->apply(*sp, *st); + + // 5) must implement a method result, with an output iterator + str->result(*st, std::back_inserter(*v), true); + } + }; + +public : + BOOST_CONCEPT_USAGE(ConvexHullStrategy) + { + check_methods::apply(); + } +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/distance_concept.hpp b/boost/geometry/strategies/concepts/distance_concept.hpp new file mode 100644 index 0000000000..ba347d015a --- /dev/null +++ b/boost/geometry/strategies/concepts/distance_concept.hpp @@ -0,0 +1,206 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP + +#include <vector> +#include <iterator> + +#include <boost/concept_check.hpp> + +#include <boost/geometry/util/parameter_type_of.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/segment.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for point-segment-distance + \ingroup distance +*/ +template <typename Strategy> +struct PointDistanceStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS +private : + + struct checker + { + template <typename ApplyMethod> + static void apply(ApplyMethod const&) + { + // 1: inspect and define both arguments of apply + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type ptype1; + + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type ptype2; + + // 2) check if apply-arguments fulfill point concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<ptype1>) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<ptype2>) + ); + + + // 3) must define meta-function return_type + typedef typename strategy::distance::services::return_type<Strategy>::type rtype; + + // 4) must define meta-function "similar_type" + typedef typename strategy::distance::services::similar_type + < + Strategy, ptype2, ptype1 + >::type stype; + + // 5) must define meta-function "comparable_type" + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type ctype; + + // 6) must define meta-function "tag" + typedef typename strategy::distance::services::tag + < + Strategy + >::type tag; + + // 7) must implement apply with arguments + Strategy* str = 0; + ptype1 *p1 = 0; + ptype2 *p2 = 0; + rtype r = str->apply(*p1, *p2); + + // 8) must define (meta)struct "get_similar" with apply + stype s = strategy::distance::services::get_similar + < + Strategy, + ptype2, ptype1 + >::apply(*str); + + // 9) must define (meta)struct "get_comparable" with apply + ctype c = strategy::distance::services::get_comparable + < + Strategy + >::apply(*str); + + // 10) must define (meta)struct "result_from_distance" with apply + r = strategy::distance::services::result_from_distance + < + Strategy + >::apply(*str, 1.0); + + boost::ignore_unused_variable_warning(str); + boost::ignore_unused_variable_warning(s); + boost::ignore_unused_variable_warning(c); + boost::ignore_unused_variable_warning(r); + } + }; + + + +public : + BOOST_CONCEPT_USAGE(PointDistanceStrategy) + { + checker::apply(&Strategy::apply); + } +#endif +}; + + +/*! + \brief Checks strategy for point-segment-distance + \ingroup strategy_concepts +*/ +template <typename Strategy> +struct PointSegmentDistanceStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS +private : + + struct checker + { + template <typename ApplyMethod> + static void apply(ApplyMethod const&) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type ptype; + + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type sptype; + + // 2) check if apply-arguments fulfill point concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<ptype>) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<sptype>) + ); + + + // 3) must define meta-function return_type + typedef typename strategy::distance::services::return_type<Strategy>::type rtype; + + // 4) must define underlying point-distance-strategy + typedef typename strategy::distance::services::strategy_point_point<Strategy>::type stype; + BOOST_CONCEPT_ASSERT + ( + (concept::PointDistanceStrategy<stype>) + ); + + + Strategy *str = 0; + ptype *p = 0; + sptype *sp1 = 0; + sptype *sp2 = 0; + + rtype r = str->apply(*p, *sp1, *sp2); + + boost::ignore_unused_variable_warning(str); + boost::ignore_unused_variable_warning(r); + } + }; + +public : + BOOST_CONCEPT_USAGE(PointSegmentDistanceStrategy) + { + checker::apply(&Strategy::apply); + } +#endif +}; + + +}}} // namespace boost::geometry::concept + + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/segment_intersect_concept.hpp b/boost/geometry/strategies/concepts/segment_intersect_concept.hpp new file mode 100644 index 0000000000..43bcccf374 --- /dev/null +++ b/boost/geometry/strategies/concepts/segment_intersect_concept.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP + + +//NOT FINISHED! + +#include <boost/concept_check.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for segment intersection + \ingroup segment_intersection +*/ +template <typename Strategy> +class SegmentIntersectStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // 1) must define return_type + typedef typename Strategy::return_type return_type; + + // 2) must define point_type (of segment points) + //typedef typename Strategy::point_type point_type; + + // 3) must define segment_type 1 and 2 (of segment points) + typedef typename Strategy::segment_type1 segment_type1; + typedef typename Strategy::segment_type2 segment_type2; + + + struct check_methods + { + static void apply() + { + Strategy const* str; + + return_type* rt; + //point_type const* p; + segment_type1 const* s1; + segment_type2 const* s2; + + // 4) must implement a method apply + // having two segments + *rt = str->apply(*s1, *s2); + + } + }; + + +public : + BOOST_CONCEPT_USAGE(SegmentIntersectStrategy) + { + check_methods::apply(); + } +#endif +}; + + + +}}} // namespace boost::geometry::concept + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/simplify_concept.hpp b/boost/geometry/strategies/concepts/simplify_concept.hpp new file mode 100644 index 0000000000..92e5156b5a --- /dev/null +++ b/boost/geometry/strategies/concepts/simplify_concept.hpp @@ -0,0 +1,109 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP + +#include <vector> +#include <iterator> + +#include <boost/concept_check.hpp> + +#include <boost/geometry/strategies/concepts/distance_concept.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! + \brief Checks strategy for simplify + \ingroup simplify +*/ +template <typename Strategy> +struct SimplifyStrategy +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS +private : + + // 1) must define distance_strategy_type, + // defining point-segment distance strategy (to be checked) + typedef typename Strategy::distance_strategy_type ds_type; + + + struct checker + { + template <typename ApplyMethod> + static void apply(ApplyMethod const&) + { + namespace ft = boost::function_types; + typedef typename ft::parameter_types + < + ApplyMethod + >::type parameter_types; + + typedef typename boost::mpl::if_ + < + ft::is_member_function_pointer<ApplyMethod>, + boost::mpl::int_<1>, + boost::mpl::int_<0> + >::type base_index; + + // 1: inspect and define both arguments of apply + typedef typename boost::remove_const + < + typename boost::remove_reference + < + typename boost::mpl::at + < + parameter_types, + base_index + >::type + >::type + >::type point_type; + + + + BOOST_CONCEPT_ASSERT + ( + (concept::PointSegmentDistanceStrategy<ds_type>) + ); + + Strategy *str = 0; + std::vector<point_type> const* v1 = 0; + std::vector<point_type> * v2 = 0; + + // 2) must implement method apply with arguments + // - Range + // - OutputIterator + // - floating point value + str->apply(*v1, std::back_inserter(*v2), 1.0); + + boost::ignore_unused_variable_warning(str); + } + }; + +public : + BOOST_CONCEPT_USAGE(SimplifyStrategy) + { + checker::apply(&ds_type::apply); + + } +#endif +}; + + + +}}} // namespace boost::geometry::concept + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP diff --git a/boost/geometry/strategies/concepts/within_concept.hpp b/boost/geometry/strategies/concepts/within_concept.hpp new file mode 100644 index 0000000000..a9684b98e1 --- /dev/null +++ b/boost/geometry/strategies/concepts/within_concept.hpp @@ -0,0 +1,291 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP + + + +#include <boost/concept_check.hpp> +#include <boost/function_types/result_type.hpp> + +#include <boost/geometry/util/parameter_type_of.hpp> + + +namespace boost { namespace geometry { namespace concept +{ + + +/*! +\brief Checks strategy for within (point-in-polygon) +\ingroup within +*/ +template <typename Strategy> +class WithinStrategyPolygonal +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // 1) must define state_type + typedef typename Strategy::state_type state_type; + + struct checker + { + template <typename ApplyMethod, typename ResultMethod> + static void apply(ApplyMethod const&, ResultMethod const& ) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type point_type; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type segment_point_type; + + // CHECK: apply-arguments should both fulfill point concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<point_type>) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<segment_point_type>) + ); + + // CHECK: return types (result: int, apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, typename boost::function_types::result_type<ApplyMethod>::type + >::type::value), + WRONG_RETURN_TYPE_OF_APPLY + , (bool) + ); + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + int, typename boost::function_types::result_type<ResultMethod>::type + >::type::value), + WRONG_RETURN_TYPE_OF_RESULT + , (int) + ); + + + // CHECK: calling method apply and result + Strategy const* str = 0; + state_type* st = 0; + point_type const* p = 0; + segment_point_type const* sp = 0; + + bool b = str->apply(*p, *sp, *sp, *st); + int r = str->result(*st); + + boost::ignore_unused_variable_warning(r); + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(str); + } + }; + + +public : + BOOST_CONCEPT_USAGE(WithinStrategyPolygonal) + { + checker::apply(&Strategy::apply, &Strategy::result); + } +#endif +}; + +template <typename Strategy> +class WithinStrategyPointBox +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + struct checker + { + template <typename ApplyMethod> + static void apply(ApplyMethod const&) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type point_type; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type box_type; + + // CHECK: apply-arguments should fulfill point/box concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint<point_type>) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox<box_type>) + ); + + // CHECK: return types (apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, + typename boost::function_types::result_type<ApplyMethod>::type + >::type::value), + WRONG_RETURN_TYPE + , (bool) + ); + + + // CHECK: calling method apply + Strategy const* str = 0; + point_type const* p = 0; + box_type const* bx = 0; + + bool b = str->apply(*p, *bx); + + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(str); + } + }; + + +public : + BOOST_CONCEPT_USAGE(WithinStrategyPointBox) + { + checker::apply(&Strategy::apply); + } +#endif +}; + +template <typename Strategy> +class WithinStrategyBoxBox +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + struct checker + { + template <typename ApplyMethod> + static void apply(ApplyMethod const&) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type box_type1; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type box_type2; + + // CHECK: apply-arguments should both fulfill box concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox<box_type1>) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox<box_type2>) + ); + + // CHECK: return types (apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, + typename boost::function_types::result_type<ApplyMethod>::type + >::type::value), + WRONG_RETURN_TYPE + , (bool) + ); + + + // CHECK: calling method apply + Strategy const* str = 0; + box_type1 const* b1 = 0; + box_type2 const* b2 = 0; + + bool b = str->apply(*b1, *b2); + + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(str); + } + }; + + +public : + BOOST_CONCEPT_USAGE(WithinStrategyBoxBox) + { + checker::apply(&Strategy::apply); + } +#endif +}; + +// So now: boost::geometry::concept::within +namespace within +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename FirstTag, typename SecondTag, typename CastedTag, typename Strategy> +struct check_within +{}; + + +template <typename AnyTag, typename Strategy> +struct check_within<point_tag, AnyTag, areal_tag, Strategy> +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyPolygonal<Strategy>) ); +}; + + +template <typename Strategy> +struct check_within<point_tag, box_tag, areal_tag, Strategy> +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyPointBox<Strategy>) ); +}; + +template <typename Strategy> +struct check_within<box_tag, box_tag, areal_tag, Strategy> +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyBoxBox<Strategy>) ); +}; + + +} // namespace dispatch +#endif + + +/*! +\brief Checks, in compile-time, the concept of any within-strategy +\ingroup concepts +*/ +template <typename FirstTag, typename SecondTag, typename CastedTag, typename Strategy> +inline void check() +{ + dispatch::check_within<FirstTag, SecondTag, CastedTag, Strategy> c; + boost::ignore_unused_variable_warning(c); +} + + +}}}} // namespace boost::geometry::concept::within + + +#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP diff --git a/boost/geometry/strategies/convex_hull.hpp b/boost/geometry/strategies/convex_hull.hpp new file mode 100644 index 0000000000..f4edc5ba3f --- /dev/null +++ b/boost/geometry/strategies/convex_hull.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_CONVEX_HULL_HPP +#define BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_HPP + +#include <boost/geometry/strategies/tags.hpp> + + +namespace boost { namespace geometry +{ + + + + +/*! + \brief Traits class binding a convex hull calculation strategy to a coordinate system + \ingroup convex_hull + \tparam Tag tag of coordinate system + \tparam Geometry the geometry type (hull operates internally per hull over geometry) + \tparam Point point-type of output points +*/ +template +< + typename Geometry1, + typename Point, + typename CsTag = typename cs_tag<Point>::type +> +struct strategy_convex_hull +{ + typedef strategy::not_implemented type; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_HPP diff --git a/boost/geometry/strategies/covered_by.hpp b/boost/geometry/strategies/covered_by.hpp new file mode 100644 index 0000000000..a878b26c86 --- /dev/null +++ b/boost/geometry/strategies/covered_by.hpp @@ -0,0 +1,72 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_COVERED_BY_HPP +#define BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP + +#include <boost/mpl/assert.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace covered_by +{ + + +namespace services +{ + +/*! +\brief Traits class binding a covered_by determination strategy to a coordinate system +\ingroup covered_by +\tparam TagContained tag (possibly casted) of point-type +\tparam TagContained tag (possibly casted) of (possibly) containing type +\tparam CsTagContained tag of coordinate system of point-type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type +\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContaining geometry-type of input (possibly) containing type +*/ +template +< + typename TagContained, + typename TagContaining, + typename CastedTagContained, + typename CastedTagContaining, + typename CsTagContained, + typename CsTagContaining, + typename GeometryContained, + typename GeometryContaining +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPES + , (types<GeometryContained, GeometryContaining>) + ); +}; + + +} // namespace services + + +}} // namespace strategy::covered_by + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP + diff --git a/boost/geometry/strategies/default_area_result.hpp b/boost/geometry/strategies/default_area_result.hpp new file mode 100644 index 0000000000..8adfa5d6ea --- /dev/null +++ b/boost/geometry/strategies/default_area_result.hpp @@ -0,0 +1,51 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_DEFAULT_AREA_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_AREA_RESULT_HPP + + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/strategies/area.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +/*! +\brief Meta-function defining return type of area function, using the default strategy +\ingroup area +\note The strategy defines the return-type (so this situation is different + from length, where distance is sqr/sqrt, but length always squared) + */ + +template <typename Geometry> +struct default_area_result +{ + 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; + + typedef typename strategy_type::return_type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_AREA_RESULT_HPP diff --git a/boost/geometry/strategies/default_distance_result.hpp b/boost/geometry/strategies/default_distance_result.hpp new file mode 100644 index 0000000000..ea5f3ff764 --- /dev/null +++ b/boost/geometry/strategies/default_distance_result.hpp @@ -0,0 +1,50 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP + + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/strategies/distance.hpp> + + +namespace boost { namespace geometry +{ + +/*! +\brief Meta-function defining return type of distance function +\ingroup distance +\note The strategy defines the return-type (so this situation is different + from length, where distance is sqr/sqrt, but length always squared) + */ +template <typename Geometry1, typename Geometry2 = Geometry1> +struct default_distance_result +{ + typedef typename strategy::distance::services::return_type + < + typename strategy::distance::services::default_strategy + < + point_tag, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + >::type + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP diff --git a/boost/geometry/strategies/default_length_result.hpp b/boost/geometry/strategies/default_length_result.hpp new file mode 100644 index 0000000000..706941b9e4 --- /dev/null +++ b/boost/geometry/strategies/default_length_result.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +/*! + \brief Meta-function defining return type of length function + \ingroup length + \note Length of a line of integer coordinates can be double. + So we take at least a double. If Big Number types are used, + we take that type. + + */ +template <typename Geometry> +struct default_length_result +{ + typedef typename select_most_precise + < + typename coordinate_type<Geometry>::type, + long double + >::type type; +}; + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP diff --git a/boost/geometry/strategies/distance.hpp b/boost/geometry/strategies/distance.hpp new file mode 100644 index 0000000000..ef9a7ee10d --- /dev/null +++ b/boost/geometry/strategies/distance.hpp @@ -0,0 +1,135 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_DISTANCE_HPP +#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_HPP + + +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/strategies/tags.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace distance { namespace services +{ + + +template <typename Strategy> struct tag {}; +template <typename Strategy> struct return_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>) + ); +}; + + +/*! + \brief Metafunction delivering a similar strategy with other input point types +*/ +template +< + typename Strategy, + typename Point1, + typename Point2 +> +struct similar_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY + , (types<Strategy, Point1, Point2>) + ); +}; + +template +< + typename Strategy, + typename Point1, + typename Point2 +> +struct get_similar +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY + , (types<Strategy, Point1, Point2>) + ); +}; + +template <typename Strategy> struct comparable_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>) + ); +}; + +template <typename Strategy> struct get_comparable +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>) + ); +}; + +template <typename Strategy> struct result_from_distance {}; + + +// For point-segment only: +template <typename Strategy> struct strategy_point_point {}; + + +// Default strategy + + +/*! + \brief Traits class binding a default strategy for distance + to one (or possibly two) coordinate system(s) + \ingroup distance + \tparam GeometryTag tag (point/segment) for which this strategy is the default + \tparam Point1 first point-type + \tparam Point2 second point-type + \tparam CsTag1 tag of coordinate system of first point type + \tparam CsTag2 tag of coordinate system of second point type +*/ +template +< + typename GeometryTag, + typename Point1, + typename Point2 = Point1, + typename CsTag1 = typename cs_tag<Point1>::type, + typename CsTag2 = typename cs_tag<Point2>::type, + typename UnderlyingStrategy = void +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE_COMBINATION + , (types<Point1, Point2, CsTag1, CsTag2>) + ); +}; + + +}}} // namespace strategy::distance::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_HPP diff --git a/boost/geometry/strategies/intersection.hpp b/boost/geometry/strategies/intersection.hpp new file mode 100644 index 0000000000..fc628c0635 --- /dev/null +++ b/boost/geometry/strategies/intersection.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_INTERSECTION_HPP +#define BOOST_GEOMETRY_STRATEGIES_INTERSECTION_HPP + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/geometries/segment.hpp> + +#include <boost/geometry/policies/relate/intersection_points.hpp> +#include <boost/geometry/policies/relate/direction.hpp> +#include <boost/geometry/policies/relate/tupled.hpp> + +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/intersection.hpp> +#include <boost/geometry/strategies/intersection_result.hpp> + +#include <boost/geometry/strategies/cartesian/cart_intersect.hpp> + + +namespace boost { namespace geometry +{ + + +// The intersection strategy is a "compound strategy", +// it contains a segment-intersection-strategy +// and a side-strategy +/*! +\tparam CalculationType \tparam_calculation +*/ +template +< + typename Tag, + typename Geometry1, + typename Geometry2, + typename IntersectionPoint, + typename CalculationType = void +> +struct strategy_intersection +{ +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; + + typedef segment_intersection_points + < + IntersectionPoint + > ip_type; + +public: + typedef strategy::intersection::relate_cartesian_segments + < + policies::relate::segments_tupled + < + policies::relate::segments_intersection_points + < + segment1_type, + segment2_type, + ip_type, + CalculationType + > , + policies::relate::segments_direction + < + segment1_type, + segment2_type, + CalculationType + >, + CalculationType + >, + CalculationType + > segment_intersection_strategy_type; + + typedef typename strategy::side::services::default_strategy + < + Tag, + CalculationType + >::type side_strategy_type; +}; + + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_INTERSECTION_HPP diff --git a/boost/geometry/strategies/intersection_result.hpp b/boost/geometry/strategies/intersection_result.hpp new file mode 100644 index 0000000000..15917a9eb5 --- /dev/null +++ b/boost/geometry/strategies/intersection_result.hpp @@ -0,0 +1,174 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_INTERSECTION_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_INTERSECTION_RESULT_HPP + +#if defined(HAVE_MATRIX_AS_STRING) +#include <string> +#endif + +#include <cstddef> + + +namespace boost { namespace geometry +{ + +/*! + \brief Dimensionally Extended 9 Intersection Matrix + \details + \ingroup overlay + \see http://gis.hsr.ch/wiki/images/3/3d/9dem_springer.pdf +*/ +struct de9im +{ + int ii, ib, ie, + bi, bb, be, + ei, eb, ee; + + inline de9im() + : ii(-1), ib(-1), ie(-1) + , bi(-1), bb(-1), be(-1) + , ei(-1), eb(-1), ee(-1) + { + } + + inline de9im(int ii0, int ib0, int ie0, + int bi0, int bb0, int be0, + int ei0, int eb0, int ee0) + : ii(ii0), ib(ib0), ie(ie0) + , bi(bi0), bb(bb0), be(be0) + , ei(ei0), eb(eb0), ee(ee0) + {} + + inline bool equals() const + { + return ii >= 0 && ie < 0 && be < 0 && ei < 0 && eb < 0; + } + + inline bool disjoint() const + { + return ii < 0 && ib < 0 && bi < 0 && bb < 0; + } + + inline bool intersects() const + { + return ii >= 0 || bb >= 0 || bi >= 0 || ib >= 0; + } + + inline bool touches() const + { + return ii < 0 && (bb >= 0 || bi >= 0 || ib >= 0); + } + + inline bool crosses() const + { + return (ii >= 0 && ie >= 0) || (ii == 0); + } + + inline bool overlaps() const + { + return ii >= 0 && ie >= 0 && ei >= 0; + } + + inline bool within() const + { + return ii >= 0 && ie < 0 && be < 0; + } + + inline bool contains() const + { + return ii >= 0 && ei < 0 && eb < 0; + } + + + static inline char as_char(int v) + { + return v >= 0 && v < 10 ? ('0' + char(v)) : '-'; + } + +#if defined(HAVE_MATRIX_AS_STRING) + inline std::string matrix_as_string(std::string const& tab, std::string const& nl) const + { + std::string ret; + ret.reserve(9 + tab.length() * 3 + nl.length() * 3); + ret += tab; ret += as_char(ii); ret += as_char(ib); ret += as_char(ie); ret += nl; + ret += tab; ret += as_char(bi); ret += as_char(bb); ret += as_char(be); ret += nl; + ret += tab; ret += as_char(ei); ret += as_char(eb); ret += as_char(ee); + return ret; + } + + inline std::string matrix_as_string() const + { + return matrix_as_string("", ""); + } +#endif + +}; + +struct de9im_segment : public de9im +{ + bool collinear; // true if segments are aligned (for equal,overlap,touch) + bool opposite; // true if direction is reversed (for equal,overlap,touch) + bool parallel; // true if disjoint but parallel + bool degenerate; // true for segment(s) of zero length + + double ra, rb; // temp + + inline de9im_segment() + : de9im() + , collinear(false) + , opposite(false) + , parallel(false) + , degenerate(false) + {} + + inline de9im_segment(double a, double b, + int ii0, int ib0, int ie0, + int bi0, int bb0, int be0, + int ei0, int eb0, int ee0, + bool c = false, bool o = false, bool p = false, bool d = false) + : de9im(ii0, ib0, ie0, bi0, bb0, be0, ei0, eb0, ee0) + , collinear(c) + , opposite(o) + , parallel(p) + , degenerate(d) + , ra(a), rb(b) + {} + + +#if defined(HAVE_MATRIX_AS_STRING) + inline std::string as_string() const + { + std::string ret = matrix_as_string(); + ret += collinear ? "c" : "-"; + ret += opposite ? "o" : "-"; + return ret; + } +#endif +}; + + + +template <typename Point> +struct segment_intersection_points +{ + std::size_t count; + Point intersections[2]; + typedef Point point_type; + + segment_intersection_points() + : count(0) + {} +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_INTERSECTION_RESULT_HPP diff --git a/boost/geometry/strategies/side.hpp b/boost/geometry/strategies/side.hpp new file mode 100644 index 0000000000..376f2fdf1b --- /dev/null +++ b/boost/geometry/strategies/side.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_SIDE_HPP +#define BOOST_GEOMETRY_STRATEGIES_SIDE_HPP + + +#include <boost/geometry/strategies/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace side +{ + +namespace services +{ + +/*! +\brief Traits class binding a side determination strategy to a coordinate system +\ingroup util +\tparam Tag tag of coordinate system of point-type +\tparam CalculationType \tparam_calculation +*/ +template <typename Tag, typename CalculationType = void> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types<Tag>) + ); +}; + + +} // namespace services + + +}} // namespace strategy::side + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SIDE_HPP diff --git a/boost/geometry/strategies/side_info.hpp b/boost/geometry/strategies/side_info.hpp new file mode 100644 index 0000000000..3fc43b8d99 --- /dev/null +++ b/boost/geometry/strategies/side_info.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_SIDE_INFO_HPP +#define BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP + + +#include <utility> + + +namespace boost { namespace geometry +{ + + +/*! +\brief Class side_info: small class wrapping for sides (-1,0,1) +*/ +class side_info +{ +public : + inline side_info(int side_a1 = 0, int side_a2 = 0, + int side_b1 = 0, int side_b2 = 0) + { + sides[0].first = side_a1; + sides[0].second = side_a2; + sides[1].first = side_b1; + sides[1].second = side_b2; + } + + template <int Which> + inline void set(int first, int second) + { + sides[Which].first = first; + sides[Which].second = second; + } + + template <int Which, int Index> + inline int get() const + { + return Index == 0 ? sides[Which].first : sides[Which].second; + } + + + // Returns true if both lying on the same side WRT the other + // (so either 1,1 or -1-1) + template <int Which> + inline bool same() const + { + return sides[Which].first * sides[Which].second == 1; + } + + inline bool collinear() const + { + return sides[0].first == 0 + && sides[0].second == 0 + && sides[1].first == 0 + && sides[1].second == 0; + } + + // If one of the segments is collinear, the other must be as well. + // So handle it as collinear. + // (In floating point margins it can occur that one of them is 1!) + inline bool as_collinear() const + { + return sides[0].first * sides[0].second == 0 + || sides[1].first * sides[1].second == 0; + } + + inline void reverse() + { + std::swap(sides[0], sides[1]); + } + +private : + std::pair<int, int> sides[2]; + +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP diff --git a/boost/geometry/strategies/spherical/area_huiller.hpp b/boost/geometry/strategies/spherical/area_huiller.hpp new file mode 100644 index 0000000000..1bef9b5f2f --- /dev/null +++ b/boost/geometry/strategies/spherical/area_huiller.hpp @@ -0,0 +1,202 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP + + + +#include <boost/geometry/strategies/spherical/distance_haversine.hpp> + +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + + + +/*! +\brief Area calculation by spherical excess / Huiller's formula +\ingroup strategies +\tparam PointOfSegment point type of segments of rings/polygons +\tparam CalculationType \tparam_calculation +\author Barend Gehrels. Adapted from: +- http://www.soe.ucsc.edu/~pang/160/f98/Gems/GemsIV/sph_poly.c +- http://williams.best.vwh.net/avform.htm +\note The version in Gems didn't account for polygons crossing the 180 meridian. +\note This version works for convex and non-convex polygons, for 180 meridian +crossing polygons and for polygons with holes. However, some cases (especially +180 meridian cases) must still be checked. +\note The version which sums angles, which is often seen, doesn't handle non-convex +polygons correctly. +\note The version which sums longitudes, see +http://trs-new.jpl.nasa.gov/dspace/bitstream/2014/40409/1/07-03.pdf, is simple +and works well in most cases but not in 180 meridian crossing cases. This probably +could be solved. + +\note This version is made for spherical equatorial coordinate systems + +\qbk{ + +[heading Example] +[area_with_strategy] +[area_with_strategy_output] + + +[heading See also] +[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] +} + +*/ +template +< + typename PointOfSegment, + typename CalculationType = void +> +class huiller +{ +typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename coordinate_type<PointOfSegment>::type, + double + >::type, + CalculationType + >::type calculation_type; + +protected : + struct excess_sum + { + calculation_type sum; + + // Distances are calculated on unit sphere here + strategy::distance::haversine<PointOfSegment, PointOfSegment> + distance_over_unit_sphere; + + + inline excess_sum() + : sum(0) + , distance_over_unit_sphere(1) + {} + inline calculation_type area(calculation_type radius) const + { + return - sum * radius * radius; + } + }; + +public : + typedef calculation_type return_type; + typedef PointOfSegment segment_point_type; + typedef excess_sum state_type; + + inline huiller(calculation_type radius = 1.0) + : m_radius(radius) + {} + + inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + excess_sum& state) const + { + if (! geometry::math::equals(get<0>(p1), get<0>(p2))) + { + calculation_type const half = 0.5; + calculation_type const two = 2.0; + calculation_type const four = 4.0; + calculation_type const two_pi = two * geometry::math::pi<calculation_type>(); + calculation_type const half_pi = half * geometry::math::pi<calculation_type>(); + + // Distance p1 p2 + calculation_type a = state.distance_over_unit_sphere.apply(p1, p2); + + // Sides on unit sphere to south pole + calculation_type b = half_pi - geometry::get_as_radian<1>(p2); + calculation_type c = half_pi - geometry::get_as_radian<1>(p1); + + // Semi parameter + calculation_type s = half * (a + b + c); + + // E: spherical excess, using l'Huiller's formula + // [tg(e / 4)]2 = tg[s / 2] tg[(s-a) / 2] tg[(s-b) / 2] tg[(s-c) / 2] + calculation_type E = four * atan(sqrt(geometry::math::abs(tan(s / two) + * tan((s - a) / two) + * tan((s - b) / two) + * tan((s - c) / two)))); + + E = geometry::math::abs(E); + + // In right direction: positive, add area. In left direction: negative, subtract area. + // Longitude comparisons are not so obvious. If one is negative, other is positive, + // we have to take the dateline into account. + // TODO: check this / enhance this, should be more robust. See also the "grow" for ll + // TODO: use minmax or "smaller"/"compare" strategy for this + calculation_type lon1 = geometry::get_as_radian<0>(p1) < 0 + ? geometry::get_as_radian<0>(p1) + two_pi + : geometry::get_as_radian<0>(p1); + + calculation_type lon2 = geometry::get_as_radian<0>(p2) < 0 + ? geometry::get_as_radian<0>(p2) + two_pi + : geometry::get_as_radian<0>(p2); + + if (lon2 < lon1) + { + E = -E; + } + + state.sum += E; + } + } + + inline return_type result(excess_sum const& state) const + { + return state.area(m_radius); + } + +private : + /// Radius of the sphere + calculation_type m_radius; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template <typename Point> +struct default_strategy<spherical_equatorial_tag, Point> +{ + typedef strategy::area::huiller<Point> type; +}; + +// Note: spherical polar coordinate system requires "get_as_radian_equatorial" +/***template <typename Point> +struct default_strategy<spherical_polar_tag, Point> +{ + typedef strategy::area::huiller<Point> type; +};***/ + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::area + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP diff --git a/boost/geometry/strategies/spherical/compare_circular.hpp b/boost/geometry/strategies/spherical/compare_circular.hpp new file mode 100644 index 0000000000..2f890dfd87 --- /dev/null +++ b/boost/geometry/strategies/spherical/compare_circular.hpp @@ -0,0 +1,152 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP + +#include <boost/math/constants/constants.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/strategies/compare.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace compare +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Units> +struct shift +{ +}; + +template <> +struct shift<degree> +{ + static inline double full() { return 360.0; } + static inline double half() { return 180.0; } +}; + +template <> +struct shift<radian> +{ + static inline double full() { return 2.0 * boost::math::constants::pi<double>(); } + static inline double half() { return boost::math::constants::pi<double>(); } +}; + +} // namespace detail +#endif + +/*! +\brief Compare (in one direction) strategy for spherical coordinates +\ingroup strategies +\tparam Point point-type +\tparam Dimension dimension +*/ +template <typename CoordinateType, typename Units, typename Compare> +struct circular_comparator +{ + static inline CoordinateType put_in_range(CoordinateType const& c, + double min_border, double max_border) + { + CoordinateType value = c; + while (value < min_border) + { + value += detail::shift<Units>::full(); + } + while (value > max_border) + { + value -= detail::shift<Units>::full(); + } + return value; + } + + inline bool operator()(CoordinateType const& c1, CoordinateType const& c2) const + { + Compare compare; + + // Check situation that one of them is e.g. std::numeric_limits. + static const double full = detail::shift<Units>::full(); + double mx = 10.0 * full; + if (c1 < -mx || c1 > mx || c2 < -mx || c2 > mx) + { + // do normal comparison, using circular is not useful + return compare(c1, c2); + } + + static const double half = full / 2.0; + CoordinateType v1 = put_in_range(c1, -half, half); + CoordinateType v2 = put_in_range(c2, -half, half); + + // Two coordinates on a circle are + // at max <= half a circle away from each other. + // So if it is more, shift origin. + CoordinateType diff = geometry::math::abs(v1 - v2); + if (diff > half) + { + v1 = put_in_range(v1, 0, full); + v2 = put_in_range(v2, 0, full); + } + + return compare(v1, v2); + } +}; + +}} // namespace strategy::compare + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +// Specialize for the longitude (dim 0) +template +< + typename Point, + template<typename> class CoordinateSystem, + typename Units +> +struct strategy_compare<spherical_polar_tag, 1, Point, CoordinateSystem<Units>, 0> +{ + typedef typename coordinate_type<Point>::type coordinate_type; + typedef strategy::compare::circular_comparator + < + coordinate_type, + Units, + std::less<coordinate_type> + > type; +}; + +template +< + typename Point, + template<typename> class CoordinateSystem, + typename Units +> +struct strategy_compare<spherical_polar_tag, -1, Point, CoordinateSystem<Units>, 0> +{ + typedef typename coordinate_type<Point>::type coordinate_type; + typedef strategy::compare::circular_comparator + < + coordinate_type, + Units, + std::greater<coordinate_type> + > type; +}; + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP diff --git a/boost/geometry/strategies/spherical/distance_cross_track.hpp b/boost/geometry/strategies/spherical/distance_cross_track.hpp new file mode 100644 index 0000000000..ba589223ec --- /dev/null +++ b/boost/geometry/strategies/spherical/distance_cross_track.hpp @@ -0,0 +1,349 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP + + +#include <boost/concept_check.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> + + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/concepts/distance_concept.hpp> + +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/math.hpp> + +#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK +# include <boost/geometry/io/dsv/write.hpp> +#endif + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +/*! +\brief Strategy functor for distance point to segment calculation +\ingroup strategies +\details Class which calculates the distance of a point to a segment, using latlong points +\see http://williams.best.vwh.net/avform.htm +\tparam Point point type +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation +\tparam Strategy underlying point-point distance strategy, defaults to haversine + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename Point, + typename PointOfSegment = Point, + typename CalculationType = void, + typename Strategy = typename services::default_strategy<point_tag, Point>::type +> +class cross_track +{ +public : + typedef typename promote_floating_point + < + typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type + >::type return_type; + + inline cross_track() + { + m_strategy = Strategy(); + m_radius = m_strategy.radius(); + } + + inline cross_track(return_type const& r) + : m_radius(r) + , m_strategy(r) + {} + + inline cross_track(Strategy const& s) + : m_strategy(s) + { + m_radius = m_strategy.radius(); + } + + + // It might be useful in the future + // to overload constructor with strategy info. + // crosstrack(...) {} + + + inline return_type apply(Point const& p, + PointOfSegment const& sp1, PointOfSegment const& sp2) const + { + // http://williams.best.vwh.net/avform.htm#XTE + return_type d1 = m_strategy.apply(sp1, p); + + // Actually, calculation of d2 not necessary if we know that the projected point is on the great circle... + return_type d2 = m_strategy.apply(sp2, p); + + return_type crs_AD = course(sp1, p); + return_type crs_AB = course(sp1, sp2); + return_type XTD = m_radius * geometry::math::abs(asin(sin(d1 / m_radius) * sin(crs_AD - crs_AB))); + +#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK +std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; +std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; +std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; +#endif + + + // Return shortest distance, either to projected point on segment sp1-sp2, or to sp1, or to sp2 + return return_type((std::min)((std::min)(d1, d2), XTD)); + } + + inline return_type radius() const { return m_radius; } + +private : + BOOST_CONCEPT_ASSERT + ( + (geometry::concept::PointDistanceStrategy<Strategy >) + ); + + + return_type m_radius; + + // Point-point distances are calculated in radians, on the unit sphere + Strategy m_strategy; + + /// Calculate course (bearing) between two points. Might be moved to a "course formula" ... + inline return_type course(Point const& p1, Point const& p2) const + { + // http://williams.best.vwh.net/avform.htm#Crs + return_type dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1); + return_type cos_p2lat = cos(get_as_radian<1>(p2)); + + // "An alternative formula, not requiring the pre-computation of d" + return atan2(sin(dlon) * cos_p2lat, + cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2)) + - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon)); + } + +}; + + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct tag<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef strategy_tag_distance_point_segment type; +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct return_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type type; +}; + + +template +< + typename Point, + typename PointOfSegment, + typename CalculationType, + typename Strategy, + typename P, + typename PS +> +struct similar_type<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS> +{ + typedef cross_track<Point, PointOfSegment, CalculationType, Strategy> type; +}; + + +template +< + typename Point, + typename PointOfSegment, + typename CalculationType, + typename Strategy, + typename P, + typename PS +> +struct get_similar<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS> +{ + static inline typename similar_type + < + cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS + >::type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy) + { + return cross_track<P, PS, CalculationType, Strategy>(strategy.radius()); + } +}; + + +template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> +struct comparable_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ + // Comparable type is here just the strategy + typedef typename similar_type + < + cross_track + < + Point, PointOfSegment, CalculationType, Strategy + >, Point, PointOfSegment + >::type type; +}; + + +template +< + typename Point, typename PointOfSegment, + typename CalculationType, + typename Strategy +> +struct get_comparable<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef typename comparable_type + < + cross_track<Point, PointOfSegment, CalculationType, Strategy> + >::type comparable_type; +public : + static inline comparable_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy) + { + return comparable_type(strategy.radius()); + } +}; + + +template +< + typename Point, typename PointOfSegment, + typename CalculationType, + typename Strategy +> +struct result_from_distance<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ +private : + typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type return_type; +public : + template <typename T> + static inline return_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& , T const& distance) + { + return distance; + } +}; + + +template +< + typename Point, typename PointOfSegment, + typename CalculationType, + typename Strategy +> +struct strategy_point_point<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +{ + typedef Strategy type; +}; + + + +/* + +TODO: spherical polar coordinate system requires "get_as_radian_equatorial<>" + +template <typename Point, typename PointOfSegment, typename Strategy> +struct default_strategy + < + segment_tag, Point, PointOfSegment, + spherical_polar_tag, spherical_polar_tag, + Strategy + > +{ + typedef cross_track + < + Point, + PointOfSegment, + void, + typename boost::mpl::if_ + < + boost::is_void<Strategy>, + typename default_strategy + < + point_tag, Point, PointOfSegment, + spherical_polar_tag, spherical_polar_tag + >::type, + Strategy + >::type + > type; +}; +*/ + +template <typename Point, typename PointOfSegment, typename Strategy> +struct default_strategy + < + segment_tag, Point, PointOfSegment, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + > +{ + typedef cross_track + < + Point, + PointOfSegment, + void, + typename boost::mpl::if_ + < + boost::is_void<Strategy>, + typename default_strategy + < + point_tag, Point, PointOfSegment, + spherical_equatorial_tag, spherical_equatorial_tag + >::type, + Strategy + >::type + > type; +}; + + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP diff --git a/boost/geometry/strategies/spherical/distance_haversine.hpp b/boost/geometry/strategies/spherical/distance_haversine.hpp new file mode 100644 index 0000000000..59ec1c33ff --- /dev/null +++ b/boost/geometry/strategies/spherical/distance_haversine.hpp @@ -0,0 +1,330 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP + + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> + +#include <boost/geometry/util/select_calculation_type.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> + +#include <boost/geometry/strategies/distance.hpp> + + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace distance +{ + + +namespace comparable +{ + +// Comparable haversine. +// To compare distances, we can avoid: +// - multiplication with radius and 2.0 +// - applying sqrt +// - applying asin (which is strictly (monotone) increasing) +template +< + typename Point1, + typename Point2 = Point1, + typename CalculationType = void +> +class haversine +{ +public : + typedef typename promote_floating_point + < + typename select_calculation_type + < + Point1, + Point2, + CalculationType + >::type + >::type calculation_type; + + inline haversine(calculation_type const& r = 1.0) + : m_radius(r) + {} + + + static inline calculation_type apply(Point1 const& p1, Point2 const& p2) + { + return calculate(get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2)); + } + + inline calculation_type radius() const + { + return m_radius; + } + + +private : + + static inline calculation_type calculate(calculation_type const& lon1, + calculation_type const& lat1, + calculation_type const& lon2, + calculation_type const& lat2) + { + return math::hav(lat2 - lat1) + + cos(lat1) * cos(lat2) * math::hav(lon2 - lon1); + } + + calculation_type m_radius; +}; + + + +} // namespace comparable + +/*! +\brief Distance calculation for spherical coordinates +on a perfect sphere using haversine +\ingroup strategies +\tparam Point1 \tparam_first_point +\tparam Point2 \tparam_second_point +\tparam CalculationType \tparam_calculation +\author Adapted from: http://williams.best.vwh.net/avform.htm +\see http://en.wikipedia.org/wiki/Great-circle_distance +\note It says: <em>The great circle distance d between two +points with coordinates {lat1,lon1} and {lat2,lon2} is given by: + d=acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2)) +A mathematically equivalent formula, which is less subject + to rounding error for short distances is: + d=2*asin(sqrt((sin((lat1-lat2)/2))^2 + + cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2)) + </em> + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename Point1, + typename Point2 = Point1, + typename CalculationType = void +> +class haversine +{ + typedef comparable::haversine<Point1, Point2, CalculationType> comparable_type; + +public : + + typedef typename services::return_type<comparable_type>::type calculation_type; + + /*! + \brief Constructor + \param radius radius of the sphere, defaults to 1.0 for the unit sphere + */ + inline haversine(calculation_type const& radius = 1.0) + : m_radius(radius) + {} + + /*! + \brief applies the distance calculation + \return the calculated distance (including multiplying with radius) + \param p1 first point + \param p2 second point + */ + inline calculation_type apply(Point1 const& p1, Point2 const& p2) const + { + calculation_type const a = comparable_type::apply(p1, p2); + calculation_type const c = calculation_type(2.0) * asin(sqrt(a)); + return m_radius * c; + } + + /*! + \brief access to radius value + \return the radius + */ + inline calculation_type radius() const + { + return m_radius; + } + +private : + calculation_type m_radius; +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Point1, typename Point2, typename CalculationType> +struct tag<haversine<Point1, Point2, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct return_type<haversine<Point1, Point2, CalculationType> > +{ + typedef typename haversine<Point1, Point2, CalculationType>::calculation_type type; +}; + + +template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> +struct similar_type<haversine<Point1, Point2, CalculationType>, P1, P2> +{ + typedef haversine<P1, P2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> +struct get_similar<haversine<Point1, Point2, CalculationType>, P1, P2> +{ +private : + typedef haversine<Point1, Point2, CalculationType> this_type; +public : + static inline typename similar_type<this_type, P1, P2>::type apply(this_type const& input) + { + return haversine<P1, P2, CalculationType>(input.radius()); + } +}; + +template <typename Point1, typename Point2, typename CalculationType> +struct comparable_type<haversine<Point1, Point2, CalculationType> > +{ + typedef comparable::haversine<Point1, Point2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct get_comparable<haversine<Point1, Point2, CalculationType> > +{ +private : + typedef haversine<Point1, Point2, CalculationType> this_type; + typedef comparable::haversine<Point1, Point2, CalculationType> comparable_type; +public : + static inline comparable_type apply(this_type const& input) + { + return comparable_type(input.radius()); + } +}; + +template <typename Point1, typename Point2, typename CalculationType> +struct result_from_distance<haversine<Point1, Point2, CalculationType> > +{ +private : + typedef haversine<Point1, Point2, CalculationType> this_type; + typedef typename return_type<this_type>::type return_type; +public : + template <typename T> + static inline return_type apply(this_type const& , T const& value) + { + return return_type(value); + } +}; + + +// Specializations for comparable::haversine +template <typename Point1, typename Point2, typename CalculationType> +struct tag<comparable::haversine<Point1, Point2, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct return_type<comparable::haversine<Point1, Point2, CalculationType> > +{ + typedef typename comparable::haversine<Point1, Point2, CalculationType>::calculation_type type; +}; + + +template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> +struct similar_type<comparable::haversine<Point1, Point2, CalculationType>, P1, P2> +{ + typedef comparable::haversine<P1, P2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> +struct get_similar<comparable::haversine<Point1, Point2, CalculationType>, P1, P2> +{ +private : + typedef comparable::haversine<Point1, Point2, CalculationType> this_type; +public : + static inline typename similar_type<this_type, P1, P2>::type apply(this_type const& input) + { + return comparable::haversine<P1, P2, CalculationType>(input.radius()); + } +}; + +template <typename Point1, typename Point2, typename CalculationType> +struct comparable_type<comparable::haversine<Point1, Point2, CalculationType> > +{ + typedef comparable::haversine<Point1, Point2, CalculationType> type; +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct get_comparable<comparable::haversine<Point1, Point2, CalculationType> > +{ +private : + typedef comparable::haversine<Point1, Point2, CalculationType> this_type; +public : + static inline this_type apply(this_type const& input) + { + return input; + } +}; + + +template <typename Point1, typename Point2, typename CalculationType> +struct result_from_distance<comparable::haversine<Point1, Point2, CalculationType> > +{ +private : + typedef comparable::haversine<Point1, Point2, CalculationType> strategy_type; + typedef typename return_type<strategy_type>::type return_type; +public : + template <typename T> + static inline return_type apply(strategy_type const& strategy, T const& distance) + { + return_type const s = sin((distance / strategy.radius()) / return_type(2)); + return s * s; + } +}; + + +// Register it as the default for point-types +// in a spherical equatorial coordinate system +template <typename Point1, typename Point2> +struct default_strategy<point_tag, Point1, Point2, spherical_equatorial_tag, spherical_equatorial_tag> +{ + typedef strategy::distance::haversine<Point1, Point2> type; +}; + +// Note: spherical polar coordinate system requires "get_as_radian_equatorial" + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP diff --git a/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/boost/geometry/strategies/spherical/side_by_cross_track.hpp new file mode 100644 index 0000000000..b7cf279d5b --- /dev/null +++ b/boost/geometry/strategies/spherical/side_by_cross_track.hpp @@ -0,0 +1,100 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 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_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> + +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/side.hpp> +//#include <boost/geometry/strategies/concepts/side_concept.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace side +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/// Calculate course (bearing) between two points. Might be moved to a "course formula" ... +template <typename Point> +static inline double course(Point const& p1, Point const& p2) +{ + // http://williams.best.vwh.net/avform.htm#Crs + double dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1); + double cos_p2lat = cos(get_as_radian<1>(p2)); + + // "An alternative formula, not requiring the pre-computation of d" + return atan2(sin(dlon) * cos_p2lat, + cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2)) + - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon)); +} + +} +#endif // DOXYGEN_NO_DETAIL + + + +/*! +\brief Check at which side of a Great Circle segment a point lies + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam CalculationType \tparam_calculation + */ +template <typename CalculationType = void> +class side_by_cross_track +{ + +public : + template <typename P1, typename P2, typename P> + static inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename select_most_precise + < + typename coordinate_type<P1>::type, + typename coordinate_type<P2>::type + >::type, + typename coordinate_type<P>::type + >::type, + CalculationType + >::type coordinate_type; + + double d1 = 0.001; // m_strategy.apply(sp1, p); + double crs_AD = detail::course(p1, p); + double crs_AB = detail::course(p1, p2); + double XTD = asin(sin(d1) * sin(crs_AD - crs_AB)); + + return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1; + } +}; + +}} // namespace strategy::side + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP diff --git a/boost/geometry/strategies/spherical/ssf.hpp b/boost/geometry/strategies/spherical/ssf.hpp new file mode 100644 index 0000000000..ab7c67559a --- /dev/null +++ b/boost/geometry/strategies/spherical/ssf.hpp @@ -0,0 +1,136 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 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_STRATEGIES_SPHERICAL_SSF_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SSF_HPP + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> + +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/side.hpp> +//#include <boost/geometry/strategies/concepts/side_concept.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace side +{ + + +/*! +\brief Check at which side of a Great Circle segment a point lies + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam CalculationType \tparam_calculation + */ +template <typename CalculationType = void> +class spherical_side_formula +{ + +public : + template <typename P1, typename P2, typename P> + static inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + + // Select at least a double... + typename select_most_precise + < + typename select_most_precise + < + typename select_most_precise + < + typename coordinate_type<P1>::type, + typename coordinate_type<P2>::type + >::type, + typename coordinate_type<P>::type + >::type, + double + >::type, + CalculationType + >::type coordinate_type; + + // Convenient shortcuts + typedef coordinate_type ct; + ct const lambda1 = get_as_radian<0>(p1); + ct const delta1 = get_as_radian<1>(p1); + ct const lambda2 = get_as_radian<0>(p2); + ct const delta2 = get_as_radian<1>(p2); + ct const lambda = get_as_radian<0>(p); + ct const delta = get_as_radian<1>(p); + + // Create temporary points (vectors) on unit a sphere + ct const cos_delta1 = cos(delta1); + ct const c1x = cos_delta1 * cos(lambda1); + ct const c1y = cos_delta1 * sin(lambda1); + ct const c1z = sin(delta1); + + ct const cos_delta2 = cos(delta2); + ct const c2x = cos_delta2 * cos(lambda2); + ct const c2y = cos_delta2 * sin(lambda2); + ct const c2z = sin(delta2); + + // (Third point is converted directly) + ct const cos_delta = cos(delta); + + // Apply the "Spherical Side Formula" as presented on my blog + ct const dist + = (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda) + + (c1z * c2x - c1x * c2z) * cos_delta * sin(lambda) + + (c1x * c2y - c1y * c2x) * sin(delta); + + ct zero = ct(); + return dist > zero ? 1 + : dist < zero ? -1 + : 0; + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +/*template <typename CalculationType> +struct default_strategy<spherical_polar_tag, CalculationType> +{ + typedef spherical_side_formula<CalculationType> type; +};*/ + +template <typename CalculationType> +struct default_strategy<spherical_equatorial_tag, CalculationType> +{ + typedef spherical_side_formula<CalculationType> type; +}; + +template <typename CalculationType> +struct default_strategy<geographic_tag, CalculationType> +{ + typedef spherical_side_formula<CalculationType> type; +}; + +} +#endif + +}} // namespace strategy::side + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SSF_HPP diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp new file mode 100644 index 0000000000..3aa9ab00f5 --- /dev/null +++ b/boost/geometry/strategies/strategies.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_STRATEGIES_HPP +#define BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP + + +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/strategies/area.hpp> +#include <boost/geometry/strategies/centroid.hpp> +#include <boost/geometry/strategies/compare.hpp> +#include <boost/geometry/strategies/convex_hull.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/intersection.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/transform.hpp> +#include <boost/geometry/strategies/within.hpp> + +#include <boost/geometry/strategies/cartesian/area_surveyor.hpp> +#include <boost/geometry/strategies/cartesian/box_in_box.hpp> +#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp> +#include <boost/geometry/strategies/cartesian/centroid_weighted_length.hpp> +#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp> +#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp> +#include <boost/geometry/strategies/cartesian/point_in_box.hpp> +#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp> +#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp> +#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> + +#include <boost/geometry/strategies/spherical/area_huiller.hpp> +#include <boost/geometry/strategies/spherical/distance_haversine.hpp> +#include <boost/geometry/strategies/spherical/distance_cross_track.hpp> +#include <boost/geometry/strategies/spherical/compare_circular.hpp> +#include <boost/geometry/strategies/spherical/ssf.hpp> + +#include <boost/geometry/strategies/agnostic/hull_graham_andrew.hpp> +#include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp> +#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> +#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp> + +#include <boost/geometry/strategies/strategy_transform.hpp> + +#include <boost/geometry/strategies/transform/matrix_transformers.hpp> +#include <boost/geometry/strategies/transform/map_transformer.hpp> +#include <boost/geometry/strategies/transform/inverse_transformer.hpp> + + +#endif // BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP diff --git a/boost/geometry/strategies/strategy_transform.hpp b/boost/geometry/strategies/strategy_transform.hpp new file mode 100644 index 0000000000..7a1f060169 --- /dev/null +++ b/boost/geometry/strategies/strategy_transform.hpp @@ -0,0 +1,470 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_STRATEGY_TRANSFORM_HPP +#define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP + +#include <cstddef> +#include <cmath> +#include <functional> + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + +namespace boost { namespace geometry +{ + +namespace strategy { namespace transform +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +< + typename Src, typename Dst, + std::size_t D, std::size_t N, + template <typename> class F +> +struct transform_coordinates +{ + template <typename T> + static inline void transform(Src const& source, Dst& dest, T value) + { + typedef typename select_coordinate_type<Src, Dst>::type coordinate_type; + + F<coordinate_type> function; + set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value))); + transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value); + } +}; + +template +< + typename Src, typename Dst, + std::size_t N, + template <typename> class F +> +struct transform_coordinates<Src, Dst, N, N, F> +{ + template <typename T> + static inline void transform(Src const& , Dst& , T ) + { + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! + \brief Transformation strategy to copy one point to another using assignment operator + \ingroup transform + \tparam P point type + */ +template <typename P> +struct copy_direct +{ + inline bool apply(P const& p1, P& p2) const + { + p2 = p1; + return true; + } +}; + +/*! + \brief Transformation strategy to do copy a point, copying per coordinate. + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + */ +template <typename P1, typename P2> +struct copy_per_coordinate +{ + inline bool apply(P1 const& p1, P2& p2) const + { + // Defensive check, dimensions are equal, selected by specialization + assert_dimension_equal<P1, P2>(); + + geometry::convert(p1, p2); + return true; + } +}; + + +/*! + \brief Transformation strategy to go from degree to radian and back + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + \tparam F additional functor to divide or multiply with d2r + */ +template <typename P1, typename P2, template <typename> class F> +struct degree_radian_vv +{ + inline bool apply(P1 const& p1, P2& p2) const + { + // Spherical coordinates always have 2 coordinates measured in angles + // The optional third one is distance/height, provided in another strategy + // Polar coordinates having one angle, will be also in another strategy + assert_dimension<P1, 2>(); + assert_dimension<P2, 2>(); + + detail::transform_coordinates<P1, P2, 0, 2, F>::transform(p1, p2, math::d2r); + return true; + } +}; + +template <typename P1, typename P2, template <typename> class F> +struct degree_radian_vv_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + assert_dimension<P2, 3>(); + + detail::transform_coordinates<P1, P2, 0, 2, F>::transform(p1, p2, math::d2r); + // Copy height or other third dimension + set<2>(p2, get<2>(p1)); + return true; + } +}; + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + /// Helper function for conversion, phi/theta are in radians + template <typename P, typename T, typename R> + inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p) + { + assert_dimension<P, 3>(); + + // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates + // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm + // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf + // http://en.citizendium.org/wiki/Spherical_polar_coordinates + + // Phi = first, theta is second, r is third, see documentation on cs::spherical + + // (calculations are splitted to implement ttmath) + + T r_sin_theta = r; + T r_cos_theta = r; + r_sin_theta *= sin(theta); + r_cos_theta *= cos(theta); + + set<0>(p, r_sin_theta * cos(phi)); + set<1>(p, r_sin_theta * sin(phi)); + set<2>(p, r_cos_theta); + } + + /// Helper function for conversion, lambda/delta (lon lat) are in radians + template <typename P, typename T, typename R> + inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p) + { + assert_dimension<P, 3>(); + + // http://mathworld.wolfram.com/GreatCircle.html + // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG + + T r_cos_delta = r; + T r_sin_delta = r; + r_cos_delta *= cos(delta); + r_sin_delta *= sin(delta); + + set<0>(p, r_cos_delta * cos(lambda)); + set<1>(p, r_cos_delta * sin(lambda)); + set<2>(p, r_sin_delta); + } + + + /// Helper function for conversion + template <typename P, typename T> + inline bool cartesian_to_spherical2(T x, T y, T z, P& p) + { + assert_dimension<P, 2>(); + + // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates + +#if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE) + // TODO: MAYBE ONLY IF TO BE CHECKED? + T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z); + + // Unit sphere, so r should be 1 + if (geometry::math::abs(r - 1.0) > T(1e-6)) + { + return false; + } + // end todo +#endif + + set_from_radian<0>(p, atan2(y, x)); + set_from_radian<1>(p, acos(z)); + return true; + } + + template <typename P, typename T> + inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p) + { + assert_dimension<P, 2>(); + + set_from_radian<0>(p, atan2(y, x)); + set_from_radian<1>(p, asin(z)); + return true; + } + + + template <typename P, typename T> + inline bool cartesian_to_spherical3(T x, T y, T z, P& p) + { + assert_dimension<P, 3>(); + + // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates + T const r = sqrt(x * x + y * y + z * z); + set<2>(p, r); + set_from_radian<0>(p, atan2(y, x)); + if (r > 0.0) + { + set_from_radian<1>(p, acos(z / r)); + return true; + } + return false; + } + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! + \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z) + \details on Unit sphere + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + */ +template <typename P1, typename P2> +struct from_spherical_polar_2_to_cartesian_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 2>(); + detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2); + return true; + } +}; + +template <typename P1, typename P2> +struct from_spherical_equatorial_2_to_cartesian_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 2>(); + detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2); + return true; + } +}; + + +/*! + \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z) + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + */ +template <typename P1, typename P2> +struct from_spherical_polar_3_to_cartesian_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + detail::spherical_polar_to_cartesian( + get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2); + return true; + } +}; + +template <typename P1, typename P2> +struct from_spherical_equatorial_3_to_cartesian_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + detail::spherical_equatorial_to_cartesian( + get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2); + return true; + } +}; + + +/*! + \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta) + \details on Unit sphere + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + \note If x,y,z point is not lying on unit sphere, transformation will return false + */ +template <typename P1, typename P2> +struct from_cartesian_3_to_spherical_polar_2 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2); + } +}; + +template <typename P1, typename P2> +struct from_cartesian_3_to_spherical_equatorial_2 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2); + } +}; + + +/*! + \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r) + \ingroup transform + \tparam P1 first point type + \tparam P2 second point type + */ +template <typename P1, typename P2> +struct from_cartesian_3_to_spherical_polar_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2); + } +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +/// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied +template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P> +{ + typedef copy_direct<P> type; +}; + +/// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate +template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2> +{ + typedef copy_per_coordinate<P1, P2> type; +}; + +/// Specialization to transform from degree to radian for any coordinate system / point type combination +template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2> +{ + typedef degree_radian_vv<P1, P2, std::multiplies> type; +}; + +/// Specialization to transform from radian to degree for any coordinate system / point type combination +template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2> +{ + typedef degree_radian_vv<P1, P2, std::divides> type; +}; + + +/// Specialization degree->radian in 3D +template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2> +{ + typedef degree_radian_vv_3<P1, P2, std::multiplies> type; +}; + +/// Specialization radian->degree in 3D +template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2> +struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2> +{ + typedef degree_radian_vv_3<P1, P2, std::divides> type; +}; + +/// Specialization to transform from unit sphere(phi,theta) to XYZ +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2> +{ + typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type; +}; + +/// Specialization to transform from sphere(phi,theta,r) to XYZ +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2> +{ + typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type; +}; + +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2> +{ + typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type; +}; + +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2> +{ + typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type; +}; + +/// Specialization to transform from XYZ to unit sphere(phi,theta) +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2> +{ + typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type; +}; + +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2> +{ + typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type; +}; + +/// Specialization to transform from XYZ to sphere(phi,theta,r) +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2> +{ + typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type; +}; + + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::transform + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP diff --git a/boost/geometry/strategies/tags.hpp b/boost/geometry/strategies/tags.hpp new file mode 100644 index 0000000000..39f2f23036 --- /dev/null +++ b/boost/geometry/strategies/tags.hpp @@ -0,0 +1,41 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_TAGS_HPP +#define BOOST_GEOMETRY_STRATEGIES_TAGS_HPP + + +namespace boost { namespace geometry +{ + +namespace strategy +{ + /*! + \brief Indicate compiler/library user that strategy is not implemented. + \details Strategies are defined for point types or for point type + combinations. If there is no implementation for that specific point type, or point type + combination, the calculation cannot be done. To indicate this, this not_implemented + class is used as a typedef stub. + + */ + struct not_implemented {}; +} + + +struct strategy_tag_distance_point_point {}; +struct strategy_tag_distance_point_segment {}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_TAGS_HPP diff --git a/boost/geometry/strategies/transform.hpp b/boost/geometry/strategies/transform.hpp new file mode 100644 index 0000000000..3c806acac6 --- /dev/null +++ b/boost/geometry/strategies/transform.hpp @@ -0,0 +1,63 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_TRANSFORM_HPP +#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP + +#include <cstddef> + +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/strategies/tags.hpp> + +namespace boost { namespace geometry +{ + +namespace strategy { namespace transform { namespace services +{ + +/*! + \brief Traits class binding a transformation strategy to a coordinate system + \ingroup transform + \details Can be specialized + - per coordinate system family (tag) + - per coordinate system (or groups of them) + - per dimension + - per point type + \tparam CoordinateSystemTag 1,2 coordinate system tags + \tparam CoordinateSystem 1,2 coordinate system + \tparam D 1, 2 dimension + \tparam Point 1, 2 point type + */ +template +< + typename CoordinateSystemTag1, typename CoordinateSystemTag2, + typename CoordinateSystem1, typename CoordinateSystem2, + std::size_t Dimension1, std::size_t Dimension2, + typename Point1, typename Point2 +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPES + , (types<Point1, Point2>) + ); +}; + +}}} // namespace strategy::transform::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP diff --git a/boost/geometry/strategies/transform/inverse_transformer.hpp b/boost/geometry/strategies/transform/inverse_transformer.hpp new file mode 100644 index 0000000000..845a71ded3 --- /dev/null +++ b/boost/geometry/strategies/transform/inverse_transformer.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP +#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP + +// Remove the ublas checking, otherwise the inverse might fail +// (while nothing seems to be wrong) +#define BOOST_UBLAS_TYPE_CHECK 0 + +#include <boost/numeric/ublas/lu.hpp> +#include <boost/numeric/ublas/io.hpp> + +#include <boost/geometry/strategies/transform/matrix_transformers.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace transform +{ + +/*! +\brief Transformation strategy to do an inverse ransformation in Cartesian system +\ingroup strategies +\tparam P1 first point type +\tparam P2 second point type + */ +template <typename P1, typename P2> +class inverse_transformer + : public ublas_transformer<P1, P2, dimension<P1>::type::value, dimension<P2>::type::value> +{ + typedef typename select_coordinate_type<P1, P2>::type T; + +public : + template <typename Transformer> + inline inverse_transformer(Transformer const& input) + { + typedef boost::numeric::ublas::matrix<T> matrix_type; + + // create a working copy of the input + matrix_type copy(input.matrix()); + + // create a permutation matrix for the LU-factorization + typedef boost::numeric::ublas::permutation_matrix<> permutation_matrix; + permutation_matrix pm(copy.size1()); + + // perform LU-factorization + int res = boost::numeric::ublas::lu_factorize<matrix_type>(copy, pm); + if( res == 0 ) + { + // create identity matrix + this->m_matrix.assign(boost::numeric::ublas::identity_matrix<T>(copy.size1())); + + // backsubstitute to get the inverse + boost::numeric::ublas::lu_substitute(copy, pm, this->m_matrix); + } + } + +}; + + +}} // namespace strategy::transform + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP diff --git a/boost/geometry/strategies/transform/map_transformer.hpp b/boost/geometry/strategies/transform/map_transformer.hpp new file mode 100644 index 0000000000..150ff1de9b --- /dev/null +++ b/boost/geometry/strategies/transform/map_transformer.hpp @@ -0,0 +1,165 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP +#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP + + +#include <cstddef> + +#include <boost/geometry/strategies/transform/matrix_transformers.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace transform +{ + +/*! +\brief Transformation strategy to do map from one to another Cartesian system +\ingroup strategies +\tparam P1 first point type +\tparam P2 second point type +\tparam Mirror if true map is mirrored upside-down (in most cases pixels + are from top to bottom, while map is from bottom to top) + */ +template +< + typename P1, typename P2, + bool Mirror = false, bool SameScale = true, + std::size_t Dimension1 = dimension<P1>::type::value, + std::size_t Dimension2 = dimension<P2>::type::value +> +class map_transformer + : public ublas_transformer<P1, P2, Dimension1, Dimension2> +{ + typedef typename select_coordinate_type<P1, P2>::type T; + typedef boost::numeric::ublas::matrix<T> M; + +public : + template <typename B, typename D> + explicit inline map_transformer(B const& box, D const& width, D const& height) + { + set_transformation( + get<min_corner, 0>(box), get<min_corner, 1>(box), + get<max_corner, 0>(box), get<max_corner, 1>(box), + width, height); + } + + template <typename W, typename D> + explicit inline map_transformer(W const& wx1, W const& wy1, W const& wx2, W const& wy2, + D const& width, D const& height) + { + set_transformation(wx1, wy1, wx2, wy2, width, height); + } + + +private : + template <typename W, typename P, typename S> + inline void set_transformation_point(W const& wx, W const& wy, + P const& px, P const& py, + S const& scalex, S const& scaley) + { + + // Translate to a coordinate system centered on world coordinates (-wx, -wy) + M t1(3,3); + t1(0,0) = 1; t1(0,1) = 0; t1(0,2) = -wx; + t1(1,0) = 0; t1(1,1) = 1; t1(1,2) = -wy; + t1(2,0) = 0; t1(2,1) = 0; t1(2,2) = 1; + + // Scale the map + M s(3,3); + s(0,0) = scalex; s(0,1) = 0; s(0,2) = 0; + s(1,0) = 0; s(1,1) = scaley; s(1,2) = 0; + s(2,0) = 0; s(2,1) = 0; s(2,2) = 1; + + // Translate to a coordinate system centered on the specified pixels (+px, +py) + M t2(3, 3); + t2(0,0) = 1; t2(0,1) = 0; t2(0,2) = px; + t2(1,0) = 0; t2(1,1) = 1; t2(1,2) = py; + t2(2,0) = 0; t2(2,1) = 0; t2(2,2) = 1; + + // Calculate combination matrix in two steps + this->m_matrix = boost::numeric::ublas::prod(s, t1); + this->m_matrix = boost::numeric::ublas::prod(t2, this->m_matrix); + } + + + template <typename W, typename D> + void set_transformation(W const& wx1, W const& wy1, W const& wx2, W const& wy2, + D const& width, D const& height) + { + D px1 = 0; + D py1 = 0; + D px2 = width; + D py2 = height; + + // Get the same type, but at least a double + typedef typename select_most_precise<D, double>::type type; + + + // Calculate appropriate scale, take min because whole box must fit + // Scale is in PIXELS/MAPUNITS (meters) + W wdx = wx2 - wx1; + W wdy = wy2 - wy1; + type sx = (px2 - px1) / boost::numeric_cast<type>(wdx); + type sy = (py2 - py1) / boost::numeric_cast<type>(wdy); + + if (SameScale) + { + type scale = (std::min)(sx, sy); + sx = scale; + sy = scale; + } + + // Calculate centerpoints + W wtx = wx1 + wx2; + W wty = wy1 + wy2; + W two = 2; + W wmx = wtx / two; + W wmy = wty / two; + type pmx = (px1 + px2) / 2.0; + type pmy = (py1 + py2) / 2.0; + + set_transformation_point(wmx, wmy, pmx, pmy, sx, sy); + + if (Mirror) + { + // Mirror in y-direction + M m(3,3); + m(0,0) = 1; m(0,1) = 0; m(0,2) = 0; + m(1,0) = 0; m(1,1) = -1; m(1,2) = 0; + m(2,0) = 0; m(2,1) = 0; m(2,2) = 1; + + // Translate in y-direction such that it fits again + M y(3, 3); + y(0,0) = 1; y(0,1) = 0; y(0,2) = 0; + y(1,0) = 0; y(1,1) = 1; y(1,2) = height; + y(2,0) = 0; y(2,1) = 0; y(2,2) = 1; + + // Calculate combination matrix in two steps + this->m_matrix = boost::numeric::ublas::prod(m, this->m_matrix); + this->m_matrix = boost::numeric::ublas::prod(y, this->m_matrix); + } + } +}; + + +}} // namespace strategy::transform + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP diff --git a/boost/geometry/strategies/transform/matrix_transformers.hpp b/boost/geometry/strategies/transform/matrix_transformers.hpp new file mode 100644 index 0000000000..68da240934 --- /dev/null +++ b/boost/geometry/strategies/transform/matrix_transformers.hpp @@ -0,0 +1,422 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP +#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP + + +#include <cstddef> + +// Remove the ublas checking, otherwise the inverse might fail +// (while nothing seems to be wrong) +#define BOOST_UBLAS_TYPE_CHECK 0 + +#include <boost/numeric/conversion/cast.hpp> +#include <boost/numeric/ublas/vector.hpp> +#include <boost/numeric/ublas/matrix.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace transform +{ + +/*! +\brief Affine transformation strategy in Cartesian system. +\details The strategy serves as a generic definition of affine transformation matrix + and procedure of application it to given point. +\see http://en.wikipedia.org/wiki/Affine_transformation + and http://www.devmaster.net/wiki/Transformation_matrices +\ingroup strategies +\tparam P1 first point type (source) +\tparam P2 second point type (target) +\tparam Dimension1 number of dimensions to transform from first point +\tparam Dimension1 number of dimensions to transform to second point + */ +template +< + typename P1, typename P2, + std::size_t Dimension1, + std::size_t Dimension2 +> +class ublas_transformer +{ +}; + + +template <typename P1, typename P2> +class ublas_transformer<P1, P2, 2, 2> +{ +protected : + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + typedef coordinate_type ct; // Abbreviation + typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type; + matrix_type m_matrix; + +public : + + inline ublas_transformer( + ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, + ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, + ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) + : m_matrix(3, 3) + { + m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; + m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; + m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; + } + + inline ublas_transformer(matrix_type const& matrix) + : m_matrix(matrix) + {} + + + inline ublas_transformer() : m_matrix(3, 3) {} + + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension_greater_equal<P1, 2>(); + assert_dimension_greater_equal<P2, 2>(); + + coordinate_type const& c1 = get<0>(p1); + coordinate_type const& c2 = get<1>(p1); + + + coordinate_type p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2); + coordinate_type p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2); + + typedef typename geometry::coordinate_type<P2>::type ct2; + set<0>(p2, boost::numeric_cast<ct2>(p2x)); + set<1>(p2, boost::numeric_cast<ct2>(p2y)); + + return true; + } + + matrix_type const& matrix() const { return m_matrix; } +}; + + +// It IS possible to go from 3 to 2 coordinates +template <typename P1, typename P2> +class ublas_transformer<P1, P2, 3, 2> : public ublas_transformer<P1, P2, 2, 2> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + typedef coordinate_type ct; // Abbreviation + +public : + inline ublas_transformer( + ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, + ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, + ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) + : ublas_transformer<P1, P2, 2, 2>( + m_0_0, m_0_1, m_0_2, + m_1_0, m_1_1, m_1_2, + m_2_0, m_2_1, m_2_2) + {} + + inline ublas_transformer() + : ublas_transformer<P1, P2, 2, 2>() + {} +}; + + +template <typename P1, typename P2> +class ublas_transformer<P1, P2, 3, 3> +{ +protected : + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + typedef coordinate_type ct; // Abbreviation + typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type; + matrix_type m_matrix; + + inline ublas_transformer( + ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3, + ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3, + ct const& m_2_0, ct const& m_2_1, ct const& m_2_2, ct const& m_2_3, + ct const& m_3_0, ct const& m_3_1, ct const& m_3_2, ct const& m_3_3 + ) + : m_matrix(4, 4) + { + m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; m_matrix(0,3) = m_0_3; + m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; m_matrix(1,3) = m_1_3; + m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; m_matrix(2,3) = m_2_3; + m_matrix(3,0) = m_3_0; m_matrix(3,1) = m_3_1; m_matrix(3,2) = m_3_2; m_matrix(3,3) = m_3_3; + } + + inline ublas_transformer() : m_matrix(4, 4) {} + +public : + + inline bool apply(P1 const& p1, P2& p2) const + { + coordinate_type const& c1 = get<0>(p1); + coordinate_type const& c2 = get<1>(p1); + coordinate_type const& c3 = get<2>(p1); + + typedef typename geometry::coordinate_type<P2>::type ct2; + + set<0>(p2, boost::numeric_cast<ct2>( + c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + c3 * m_matrix(0,2) + m_matrix(0,3))); + set<1>(p2, boost::numeric_cast<ct2>( + c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + c3 * m_matrix(1,2) + m_matrix(1,3))); + set<2>(p2, boost::numeric_cast<ct2>( + c1 * m_matrix(2,0) + c2 * m_matrix(2,1) + c3 * m_matrix(2,2) + m_matrix(2,3))); + + return true; + } + + matrix_type const& matrix() const { return m_matrix; } +}; + + +/*! +\brief Strategy of translate transformation in Cartesian system. +\details Translate moves a geometry a fixed distance in 2 or 3 dimensions. +\see http://en.wikipedia.org/wiki/Translation_%28geometry%29 +\ingroup strategies +\tparam P1 first point type +\tparam P2 second point type +\tparam Dimension1 number of dimensions to transform from first point +\tparam Dimension1 number of dimensions to transform to second point + */ +template +< + typename P1, typename P2, + std::size_t Dimension1 = geometry::dimension<P1>::type::value, + std::size_t Dimension2 = geometry::dimension<P2>::type::value +> +class translate_transformer +{ +}; + + +template <typename P1, typename P2> +class translate_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + +public : + // To have translate transformers compatible for 2/3 dimensions, the + // constructor takes an optional third argument doing nothing. + inline translate_transformer(coordinate_type const& translate_x, + coordinate_type const& translate_y, + coordinate_type const& = 0) + : ublas_transformer<P1, P2, 2, 2>( + 1, 0, translate_x, + 0, 1, translate_y, + 0, 0, 1) + {} +}; + + +template <typename P1, typename P2> +class translate_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + +public : + inline translate_transformer(coordinate_type const& translate_x, + coordinate_type const& translate_y, + coordinate_type const& translate_z) + : ublas_transformer<P1, P2, 3, 3>( + 1, 0, 0, translate_x, + 0, 1, 0, translate_y, + 0, 0, 1, translate_z, + 0, 0, 0, 1) + {} + +}; + + +/*! +\brief Strategy of scale transformation in Cartesian system. +\details Scale scales a geometry up or down in all its dimensions. +\see http://en.wikipedia.org/wiki/Scaling_%28geometry%29 +\ingroup strategies +\tparam P1 first point type +\tparam P2 second point type +\tparam Dimension1 number of dimensions to transform from first point +\tparam Dimension1 number of dimensions to transform to second point +*/ +template +< + typename P1, typename P2 = P1, + std::size_t Dimension1 = geometry::dimension<P1>::type::value, + std::size_t Dimension2 = geometry::dimension<P2>::type::value +> +class scale_transformer +{ +}; + + +template <typename P1, typename P2> +class scale_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + +public : + inline scale_transformer(coordinate_type const& scale_x, + coordinate_type const& scale_y, + coordinate_type const& = 0) + : ublas_transformer<P1, P2, 2, 2>( + scale_x, 0, 0, + 0, scale_y, 0, + 0, 0, 1) + {} + + + inline scale_transformer(coordinate_type const& scale) + : ublas_transformer<P1, P2, 2, 2>( + scale, 0, 0, + 0, scale, 0, + 0, 0, 1) + {} +}; + + +template <typename P1, typename P2> +class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3> +{ + typedef typename select_coordinate_type<P1, P2>::type coordinate_type; + + inline scale_transformer(coordinate_type const& scale_x, + coordinate_type const& scale_y, + coordinate_type const& scale_z) + : ublas_transformer<P1, P2, 3, 3>( + scale_x, 0, 0, 0, + 0, scale_y, 0, 0, + 0, 0, scale_z, 0, + 0, 0, 0, 1) + {} + + + inline scale_transformer(coordinate_type const& scale) + : ublas_transformer<P1, P2, 3, 3>( + scale, 0, 0, 0, + 0, scale, 0, 0, + 0, 0, scale, 0, + 0, 0, 0, 1) + {} +}; + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename DegreeOrRadian> +struct as_radian +{}; + + +template <> +struct as_radian<radian> +{ + template <typename T> + static inline T get(T const& value) + { + return value; + } +}; + +template <> +struct as_radian<degree> +{ + template <typename T> + static inline T get(T const& value) + { + return value * math::d2r; + } + +}; + + +template +< + typename P1, typename P2, + std::size_t Dimension1 = geometry::dimension<P1>::type::value, + std::size_t Dimension2 = geometry::dimension<P2>::type::value +> +class rad_rotate_transformer + : public ublas_transformer<P1, P2, Dimension1, Dimension2> +{ + // Angle has type of coordinate type, but at least a double + typedef typename select_most_precise + < + typename select_coordinate_type<P1, P2>::type, + double + >::type angle_type; + +public : + inline rad_rotate_transformer(angle_type const& angle) + : ublas_transformer<P1, P2, Dimension1, Dimension2>( + cos(angle), sin(angle), 0, + -sin(angle), cos(angle), 0, + 0, 0, 1) + {} +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Strategy of rotate transformation in Cartesian system. +\details Rotate rotates a geometry of specified angle about a fixed point (e.g. origin). +\see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29 +\ingroup strategies +\tparam P1 first point type +\tparam P2 second point type +\tparam DegreeOrRadian degree/or/radian, type of rotation angle specification +\note A single angle is needed to specify a rotation in 2D. + Not yet in 3D, the 3D version requires special things to allow + for rotation around X, Y, Z or arbitrary axis. +\todo The 3D version will not compile. + */ +template <typename P1, typename P2, typename DegreeOrRadian> +class rotate_transformer : public detail::rad_rotate_transformer<P1, P2> +{ + // Angle has type of coordinate type, but at least a double + typedef typename select_most_precise + < + typename select_coordinate_type<P1, P2>::type, + double + >::type angle_type; + +public : + inline rotate_transformer(angle_type const& angle) + : detail::rad_rotate_transformer + < + P1, P2 + >(detail::as_radian<DegreeOrRadian>::get(angle)) + {} +}; + + +}} // namespace strategy::transform + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP diff --git a/boost/geometry/strategies/within.hpp b/boost/geometry/strategies/within.hpp new file mode 100644 index 0000000000..0852a22d2d --- /dev/null +++ b/boost/geometry/strategies/within.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_STRATEGIES_WITHIN_HPP +#define BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP + +#include <boost/mpl/assert.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + + +namespace services +{ + +/*! +\brief Traits class binding a within determination strategy to a coordinate system +\ingroup within +\tparam TagContained tag (possibly casted) of point-type +\tparam TagContained tag (possibly casted) of (possibly) containing type +\tparam CsTagContained tag of coordinate system of point-type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type +\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContaining geometry-type of input (possibly) containing type +*/ +template +< + typename TagContained, + typename TagContaining, + typename CastedTagContained, + typename CastedTagContaining, + typename CsTagContained, + typename CsTagContaining, + typename GeometryContained, + typename GeometryContaining +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPES + , (types<GeometryContained, GeometryContaining>) + ); +}; + + +} // namespace services + + +}} // namespace strategy::within + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP + diff --git a/boost/geometry/util/add_const_if_c.hpp b/boost/geometry/util/add_const_if_c.hpp new file mode 100644 index 0000000000..9e0c01299c --- /dev/null +++ b/boost/geometry/util/add_const_if_c.hpp @@ -0,0 +1,56 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_ADD_CONST_IF_C_HPP +#define BOOST_GEOMETRY_UTIL_ADD_CONST_IF_C_HPP + + +#include <boost/mpl/if.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Meta-function to define a const or non const type + \ingroup utility + \details If the boolean template parameter is true, the type parameter + will be defined as const, otherwise it will be defined as it was. + This meta-function is used to have one implementation for both + const and non const references + \note This traits class is completely independant from Boost.Geometry + and might be a separate addition to Boost + \note Used in a.o. for_each, interior_rings, exterior_ring + \par Example + \code + void foo(typename add_const_if_c<IsConst, Point>::type& point) + \endcode +*/ +template <bool IsConst, typename Type> +struct add_const_if_c +{ + typedef typename boost::mpl::if_c + < + IsConst, + Type const, + Type + >::type type; +}; + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_ADD_CONST_IF_C_HPP diff --git a/boost/geometry/util/calculation_type.hpp b/boost/geometry/util/calculation_type.hpp new file mode 100644 index 0000000000..aef58909e7 --- /dev/null +++ b/boost/geometry/util/calculation_type.hpp @@ -0,0 +1,176 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012 Bruno Lalande, Paris, France. +// Copyright (c) 2012 Mateusz Loskot, London, UK. + +// 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_UTIL_CALCULATION_TYPE_HPP +#define BOOST_GEOMETRY_UTIL_CALCULATION_TYPE_HPP + +#include <boost/config.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + +namespace util +{ + +namespace detail +{ + +struct default_integral +{ +#ifdef BOOST_HAS_LONG_LONG + typedef boost::long_long_type type; +#else + typedef int type; +#endif +}; + +/*! +\details Selects the most appropriate: + - if calculation type is specified (not void), that one is used + - else if type is non-fundamental (user defined e.g. ttmath), that one + - else if type is floating point, the specified default FP is used + - else it is integral and the specified default integral is used + */ +template +< + typename Type, + typename CalculationType, + typename DefaultFloatingPointCalculationType, + typename DefaultIntegralCalculationType +> +struct calculation_type +{ + BOOST_STATIC_ASSERT(( + boost::is_fundamental + < + DefaultFloatingPointCalculationType + >::type::value + )); + BOOST_STATIC_ASSERT(( + boost::is_fundamental + < + DefaultIntegralCalculationType + >::type::value + )); + + + typedef typename boost::mpl::if_ + < + boost::is_void<CalculationType>, + typename boost::mpl::if_ + < + boost::is_floating_point<Type>, + typename select_most_precise + < + DefaultFloatingPointCalculationType, + Type + >::type, + typename select_most_precise + < + DefaultIntegralCalculationType, + Type + >::type + >::type, + CalculationType + >::type type; +}; + +} // namespace detail + + +namespace calculation_type +{ + +namespace geometric +{ + +template +< + typename Geometry, + typename CalculationType, + typename DefaultFloatingPointCalculationType = double, + typename DefaultIntegralCalculationType = detail::default_integral::type +> +struct unary +{ + typedef typename detail::calculation_type + < + typename geometry::coordinate_type<Geometry>::type, + CalculationType, + DefaultFloatingPointCalculationType, + DefaultIntegralCalculationType + >::type type; +}; + +template +< + typename Geometry1, + typename Geometry2, + typename CalculationType, + typename DefaultFloatingPointCalculationType = double, + typename DefaultIntegralCalculationType = detail::default_integral::type +> +struct binary +{ + typedef typename detail::calculation_type + < + typename select_coordinate_type<Geometry1, Geometry2>::type, + CalculationType, + DefaultFloatingPointCalculationType, + DefaultIntegralCalculationType + >::type type; +}; + + +/*! +\brief calculation type (ternary, for three geometry types) + */ +template +< + typename Geometry1, + typename Geometry2, + typename Geometry3, + typename CalculationType, + typename DefaultFloatingPointCalculationType = double, + typename DefaultIntegralCalculationType = detail::default_integral::type +> +struct ternary +{ + typedef typename detail::calculation_type + < + typename select_most_precise + < + typename coordinate_type<Geometry1>::type, + typename select_coordinate_type + < + Geometry2, + Geometry3 + >::type + >::type, + CalculationType, + DefaultFloatingPointCalculationType, + DefaultIntegralCalculationType + >::type type; +}; + +}} // namespace calculation_type::geometric + +} // namespace util + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_CALCULATION_TYPE_HPP diff --git a/boost/geometry/util/closure_as_bool.hpp b/boost/geometry/util/closure_as_bool.hpp new file mode 100644 index 0000000000..57fcd52800 --- /dev/null +++ b/boost/geometry/util/closure_as_bool.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_CLOSURE_AS_BOOL_HPP +#define BOOST_GEOMETRY_UTIL_CLOSURE_AS_BOOL_HPP + +#include <boost/geometry/core/closure.hpp> + + +namespace boost { namespace geometry +{ + + +template<closure_selector Closure> +struct closure_as_bool +{}; + + +template<> +struct closure_as_bool<closed> +{ + static const bool value = true; +}; + + +template<> +struct closure_as_bool<open> +{ + static const bool value = false; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_CLOSURE_AS_BOOL_HPP diff --git a/boost/geometry/util/coordinate_cast.hpp b/boost/geometry/util/coordinate_cast.hpp new file mode 100644 index 0000000000..16a15cca5b --- /dev/null +++ b/boost/geometry/util/coordinate_cast.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_COORDINATE_CAST_HPP +#define BOOST_GEOMETRY_UTIL_COORDINATE_CAST_HPP + +#include <cstdlib> +#include <string> +#include <boost/lexical_cast.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/*! +\brief cast coordinates from a string to a coordinate type +\detail By default it uses lexical_cast. However, lexical_cast seems not to support + ttmath / partial specializations. Therefore this small utility is added. + See also "define_pi" where the same issue is solved +*/ +template <typename CoordinateType> +struct coordinate_cast +{ + static inline CoordinateType apply(std::string const& source) + { +#if defined(BOOST_GEOMETRY_NO_LEXICAL_CAST) + return atof(source.c_str()); +#else + return boost::lexical_cast<CoordinateType>(source); +#endif + } +}; + + +} // namespace detail +#endif + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_COORDINATE_CAST_HPP diff --git a/boost/geometry/util/for_each_coordinate.hpp b/boost/geometry/util/for_each_coordinate.hpp new file mode 100644 index 0000000000..7a1f55b00b --- /dev/null +++ b/boost/geometry/util/for_each_coordinate.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_FOR_EACH_COORDINATE_HPP +#define BOOST_GEOMETRY_UTIL_FOR_EACH_COORDINATE_HPP + +#include <boost/concept/requires.hpp> +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/util/add_const_if_c.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Point, int Dimension, int DimensionCount, bool IsConst> +struct coordinates_scanner +{ + template <typename Op> + static inline Op apply(typename add_const_if_c + < + IsConst, + Point + >::type& point, Op operation) + { + operation.template apply<Point, Dimension>(point); + return coordinates_scanner + < + Point, + Dimension+1, + DimensionCount, + IsConst + >::apply(point, operation); + } +}; + +template <typename Point, int DimensionCount, bool IsConst> +struct coordinates_scanner<Point, DimensionCount, DimensionCount, IsConst> +{ + template <typename Op> + static inline Op apply(typename add_const_if_c + < + IsConst, + Point + >::type& , Op operation) + { + return operation; + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +template <typename Point, typename Op> +inline void for_each_coordinate(Point& point, Op operation) +{ + BOOST_CONCEPT_ASSERT( (concept::Point<Point>) ); + + typedef typename detail::coordinates_scanner + < + Point, 0, dimension<Point>::type::value, false + > scanner; + + scanner::apply(point, operation); +} + +template <typename Point, typename Op> +inline Op for_each_coordinate(Point const& point, Op operation) +{ + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point>) ); + + typedef typename detail::coordinates_scanner + < + Point, 0, dimension<Point>::type::value, true + > scanner; + + return scanner::apply(point, operation); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_FOR_EACH_COORDINATE_HPP diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp new file mode 100644 index 0000000000..edfa961b15 --- /dev/null +++ b/boost/geometry/util/math.hpp @@ -0,0 +1,168 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_MATH_HPP +#define BOOST_GEOMETRY_UTIL_MATH_HPP + +#include <cmath> +#include <limits> + +#include <boost/math/constants/constants.hpp> + +#include <boost/geometry/util/select_most_precise.hpp> + +namespace boost { namespace geometry +{ + +namespace math +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename Type, bool IsFloatingPoint> +struct equals +{ + static inline bool apply(Type const& a, Type const& b) + { + return a == b; + } +}; + +template <typename Type> +struct equals<Type, true> +{ + static inline bool apply(Type const& a, Type const& b) + { + // See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17, + // FUTURE: replace by some boost tool or boost::test::close_at_tolerance + return std::abs(a - b) <= std::numeric_limits<Type>::epsilon() * std::abs(a); + } +}; + + +template <typename Type, bool IsFloatingPoint> +struct equals_with_epsilon : public equals<Type, IsFloatingPoint> {}; + + +/*! +\brief Short construct to enable partial specialization for PI, currently not possible in Math. +*/ +template <typename T> +struct define_pi +{ + static inline T apply() + { + // Default calls Boost.Math + return boost::math::constants::pi<T>(); + } +}; + + +} // namespace detail +#endif + + +template <typename T> +inline T pi() { return detail::define_pi<T>::apply(); } + + +// Maybe replace this by boost equals or boost ublas numeric equals or so + +/*! + \brief returns true if both arguments are equal. + \ingroup utility + \param a first argument + \param b second argument + \return true if a == b + \note If both a and b are of an integral type, comparison is done by ==. + If one of the types is floating point, comparison is done by abs and + comparing with epsilon. If one of the types is non-fundamental, it might + be a high-precision number and comparison is done using the == operator + of that class. +*/ + +template <typename T1, typename T2> +inline bool equals(T1 const& a, T2 const& b) +{ + typedef typename select_most_precise<T1, T2>::type select_type; + return detail::equals + < + select_type, + boost::is_floating_point<select_type>::type::value + >::apply(a, b); +} + +template <typename T1, typename T2> +inline bool equals_with_epsilon(T1 const& a, T2 const& b) +{ + typedef typename select_most_precise<T1, T2>::type select_type; + return detail::equals_with_epsilon + < + select_type, + boost::is_floating_point<select_type>::type::value + >::apply(a, b); +} + + + +double const d2r = geometry::math::pi<double>() / 180.0; +double const r2d = 1.0 / d2r; + +/*! + \brief Calculates the haversine of an angle + \ingroup utility + \note See http://en.wikipedia.org/wiki/Haversine_formula + haversin(alpha) = sin2(alpha/2) +*/ +template <typename T> +inline T hav(T const& theta) +{ + T const half = T(0.5); + T const sn = sin(half * theta); + return sn * sn; +} + +/*! +\brief Short utility to return the square +\ingroup utility +\param value Value to calculate the square from +\return The squared value +*/ +template <typename T> +inline T sqr(T const& value) +{ + return value * value; +} + + +/*! +\brief Short utility to workaround gcc/clang problem that abs is converting to integer +\ingroup utility +*/ +template<typename T> +inline T abs(const T& t) +{ + using std::abs; + return abs(t); +} + + +} // namespace math + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_MATH_HPP diff --git a/boost/geometry/util/order_as_direction.hpp b/boost/geometry/util/order_as_direction.hpp new file mode 100644 index 0000000000..6895ebf3f1 --- /dev/null +++ b/boost/geometry/util/order_as_direction.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_ORDER_AS_DIRECTION_HPP +#define BOOST_GEOMETRY_UTIL_ORDER_AS_DIRECTION_HPP + +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/views/reversible_view.hpp> + +namespace boost { namespace geometry +{ + + +template<order_selector Order> +struct order_as_direction +{}; + + +template<> +struct order_as_direction<clockwise> +{ + static const iterate_direction value = iterate_forward; +}; + + +template<> +struct order_as_direction<counterclockwise> +{ + static const iterate_direction value = iterate_reverse; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_ORDER_AS_DIRECTION_HPP diff --git a/boost/geometry/util/parameter_type_of.hpp b/boost/geometry/util/parameter_type_of.hpp new file mode 100644 index 0000000000..b8872d52bf --- /dev/null +++ b/boost/geometry/util/parameter_type_of.hpp @@ -0,0 +1,75 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_PARAMETER_TYPE_OF_HPP +#define BOOST_GEOMETRY_UTIL_PARAMETER_TYPE_OF_HPP + + +#include <boost/function_types/function_arity.hpp> +#include <boost/function_types/is_member_function_pointer.hpp> +#include <boost/function_types/parameter_types.hpp> +#include <boost/mpl/at.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/plus.hpp> +#include <boost/type_traits.hpp> + + +namespace boost { namespace geometry +{ + + +/*! +\brief Meta-function selecting a parameter type of a (member) function, by index +\ingroup utility + */ +template <typename Method, std::size_t Index> +struct parameter_type_of +{ + typedef typename boost::function_types::parameter_types + < + Method + >::type parameter_types; + + typedef typename boost::mpl::if_ + < + boost::function_types::is_member_function_pointer<Method>, + boost::mpl::int_<1>, + boost::mpl::int_<0> + >::type base_index_type; + + typedef typename boost::mpl::if_c + < + Index == 0, + base_index_type, + typename boost::mpl::plus + < + base_index_type, + boost::mpl::int_<Index> + >::type + >::type indexed_type; + + typedef typename boost::remove_reference + < + typename boost::mpl::at + < + parameter_types, + indexed_type + >::type + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_PARAMETER_TYPE_OF_HPP diff --git a/boost/geometry/util/promote_floating_point.hpp b/boost/geometry/util/promote_floating_point.hpp new file mode 100644 index 0000000000..0c74cb8d6c --- /dev/null +++ b/boost/geometry/util/promote_floating_point.hpp @@ -0,0 +1,50 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_PROMOTE_FLOATING_POINT_HPP +#define BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP + + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Meta-function converting, if necessary, to "a floating point" type + \details + - if input type is integer, type is double + - else type is input type + \ingroup utility + */ + +template <typename T, typename PromoteIntegerTo = double> +struct promote_floating_point +{ + typedef typename + boost::mpl::if_ + < + boost::is_integral<T>, + PromoteIntegerTo, + T + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP diff --git a/boost/geometry/util/rational.hpp b/boost/geometry/util/rational.hpp new file mode 100644 index 0000000000..45bee20460 --- /dev/null +++ b/boost/geometry/util/rational.hpp @@ -0,0 +1,179 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2011-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2011-2012 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_UTIL_RATIONAL_HPP +#define BOOST_GEOMETRY_UTIL_RATIONAL_HPP + +#include <boost/rational.hpp> +#include <boost/numeric/conversion/bounds.hpp> + +#include <boost/geometry/util/coordinate_cast.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost{ namespace geometry +{ + + +// Specialize for Boost.Geometry's coordinate cast +// (from string to coordinate type) +namespace detail +{ + +template <typename T> +struct coordinate_cast<rational<T> > +{ + static inline void split_parts(std::string const& source, std::string::size_type p, + T& before, T& after, bool& negate, std::string::size_type& len) + { + std::string before_part = source.substr(0, p); + std::string const after_part = source.substr(p + 1); + + negate = false; + + if (before_part.size() > 0 && before_part[0] == '-') + { + negate = true; + before_part.erase(0, 1); + } + before = atol(before_part.c_str()); + after = atol(after_part.c_str()); + len = after_part.length(); + } + + + static inline rational<T> apply(std::string const& source) + { + T before, after; + bool negate; + std::string::size_type len; + + // Note: decimal comma is not (yet) supported, it does (and should) not + // occur in a WKT, where points are comma separated. + std::string::size_type p = source.find("."); + if (p == std::string::npos) + { + p = source.find("/"); + if (p == std::string::npos) + { + return rational<T>(atol(source.c_str())); + } + split_parts(source, p, before, after, negate, len); + + return negate + ? -rational<T>(before, after) + : rational<T>(before, after) + ; + + } + + split_parts(source, p, before, after, negate, len); + + T den = 1; + for (std::string::size_type i = 0; i < len; i++) + { + den *= 10; + } + + return negate + ? -rational<T>(before) - rational<T>(after, den) + : rational<T>(before) + rational<T>(after, den) + ; + } +}; + +} // namespace detail + +// Specialize for Boost.Geometry's select_most_precise +template <typename T1, typename T2> +struct select_most_precise<boost::rational<T1>, boost::rational<T2> > +{ + typedef typename boost::rational + < + typename select_most_precise<T1, T2>::type + > type; +}; + +template <typename T> +struct select_most_precise<boost::rational<T>, double> +{ + typedef typename boost::rational<T> type; +}; + + +}} // namespace boost::geometry + + +// Specializes boost::rational to boost::numeric::bounds +namespace boost { namespace numeric +{ + +template<class T> +struct bounds<rational<T> > +{ + static inline rational<T> lowest() + { + return rational<T>(bounds<T>::lowest(), 1); + } + static inline rational<T> highest() + { + return rational<T>(bounds<T>::highest(), 1); + } +}; + +}} // namespace boost::numeric + + +// Support for boost::numeric_cast to int and to double (necessary for SVG-mapper) +namespace boost { namespace numeric +{ + +template +< + typename T, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter<int, rational<T>, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline int convert(rational<T> const& arg) + { + return int(rational_cast<double>(arg)); + } +}; + +template +< + typename T, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter<double, rational<T>, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline double convert(rational<T> const& arg) + { + return rational_cast<double>(arg); + } +}; + + +}} + + +#endif // BOOST_GEOMETRY_UTIL_RATIONAL_HPP diff --git a/boost/geometry/util/readme.txt b/boost/geometry/util/readme.txt new file mode 100644 index 0000000000..7a1bf88beb --- /dev/null +++ b/boost/geometry/util/readme.txt @@ -0,0 +1,17 @@ +// 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) + +This folder contains several headerfiles not fitting in one of the other folders, +or meta-functions which would fit into boost as a separate trait or utility, +such as add_const_if_c + diff --git a/boost/geometry/util/select_calculation_type.hpp b/boost/geometry/util/select_calculation_type.hpp new file mode 100644 index 0000000000..4946c45e84 --- /dev/null +++ b/boost/geometry/util/select_calculation_type.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_SELECT_CALCULATION_TYPE_HPP +#define BOOST_GEOMETRY_UTIL_SELECT_CALCULATION_TYPE_HPP + + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/util/select_coordinate_type.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Meta-function selecting the "calculation" type + \details Based on two input geometry types, and an input calculation type, + (which defaults to void in the calling function), this meta-function + selects the most appropriate: + - if calculation type is specified, that one is used, + - if it is void, the most precise of the two points is used + \ingroup utility + */ +template <typename Geometry1, typename Geometry2, typename CalculationType> +struct select_calculation_type +{ + typedef typename + boost::mpl::if_ + < + boost::is_void<CalculationType>, + typename select_coordinate_type + < + Geometry1, + Geometry2 + >::type, + CalculationType + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_SELECT_CALCULATION_TYPE_HPP diff --git a/boost/geometry/util/select_coordinate_type.hpp b/boost/geometry/util/select_coordinate_type.hpp new file mode 100644 index 0000000000..8309da42b7 --- /dev/null +++ b/boost/geometry/util/select_coordinate_type.hpp @@ -0,0 +1,45 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_SELECT_COORDINATE_TYPE_HPP +#define BOOST_GEOMETRY_UTIL_SELECT_COORDINATE_TYPE_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Meta-function selecting the most precise coordinate type + of two geometries + \ingroup utility + */ +template <typename T1, typename T2> +struct select_coordinate_type +{ + typedef typename select_most_precise + < + typename coordinate_type<T1>::type, + typename coordinate_type<T2>::type + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_SELECT_COORDINATE_TYPE_HPP diff --git a/boost/geometry/util/select_most_precise.hpp b/boost/geometry/util/select_most_precise.hpp new file mode 100644 index 0000000000..d55fdbfd98 --- /dev/null +++ b/boost/geometry/util/select_most_precise.hpp @@ -0,0 +1,162 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_UTIL_SELECT_MOST_PRECISE_HPP +#define BOOST_GEOMETRY_UTIL_SELECT_MOST_PRECISE_HPP + +#include <boost/mpl/if.hpp> +#include <boost/type_traits.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail { namespace select_most_precise +{ + + +// At least one of the types is non-fundamental. Take that one. +// if both are non-fundamental, the type-to-be-selected +// is unknown, it should be defined by explicit specialization. +template <bool Fundamental1, bool Fundamental2, typename T1, typename T2> +struct select_non_fundamental +{ + typedef T1 type; +}; + +template <typename T1, typename T2> +struct select_non_fundamental<true, false, T1, T2> +{ + typedef T2 type; +}; + +template <typename T1, typename T2> +struct select_non_fundamental<false, true, T1, T2> +{ + typedef T1 type; +}; + + +// Selection of largest type (e.g. int of <short int,int> +// It defaults takes the first one, if second is larger, take the second one +template <bool SecondLarger, typename T1, typename T2> +struct select_largest +{ + typedef T1 type; +}; + +template <typename T1, typename T2> +struct select_largest<true, T1, T2> +{ + typedef T2 type; +}; + + + +// Selection of floating point and specializations: +// both FP or both !FP does never occur... +template <bool FP1, bool FP2, typename T1, typename T2> +struct select_floating_point +{ + typedef char type; +}; + + +// ... so if ONE but not both of these types is floating point, take that one +template <typename T1, typename T2> +struct select_floating_point<true, false, T1, T2> +{ + typedef T1 type; +}; + + +template <typename T1, typename T2> +struct select_floating_point<false, true, T1, T2> +{ + typedef T2 type; +}; + + +}} // namespace detail::select_most_precise +#endif // DOXYGEN_NO_DETAIL + + +/*! + \brief Meta-function to select, of two types, the most accurate type for + calculations + \ingroup utility + \details select_most_precise classes, compares two types on compile time. + For example, if an addition must be done with a double and an integer, the + result must be a double. + If both types are integer, the result can be an integer. + \note It is different from the "promote" class, already in boost. That + class promotes e.g. a (one) float to a double. This class selects a + type from two types. It takes the most accurate, but does not promote + afterwards. + \note This traits class is completely independant from GGL and might be a + separate addition to Boost + \note If the input is a non-fundamental type, it might be a calculation + type such as a GMP-value or another high precision value. Therefore, + if one is non-fundamental, that one is chosen. + \note If both types are non-fundamental, the result is indeterminate and + currently the first one is chosen. +*/ +template <typename T1, typename T2> +struct select_most_precise +{ + static const bool second_larger = sizeof(T2) > sizeof(T1); + static const bool one_not_fundamental = ! + (boost::is_fundamental<T1>::type::value + && boost::is_fundamental<T2>::type::value); + + static const bool both_same = + boost::is_floating_point<T1>::type::value + == boost::is_floating_point<T2>::type::value; + + typedef typename boost::mpl::if_c + < + one_not_fundamental, + typename detail::select_most_precise::select_non_fundamental + < + boost::is_fundamental<T1>::type::value, + boost::is_fundamental<T2>::type::value, + T1, + T2 + >::type, + typename boost::mpl::if_c + < + both_same, + typename detail::select_most_precise::select_largest + < + second_larger, + T1, + T2 + >::type, + typename detail::select_most_precise::select_floating_point + < + boost::is_floating_point<T1>::type::value, + boost::is_floating_point<T2>::type::value, + T1, + T2 + >::type + >::type + >::type type; +}; + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_SELECT_MOST_PRECISE_HPP diff --git a/boost/geometry/views/box_view.hpp b/boost/geometry/views/box_view.hpp new file mode 100644 index 0000000000..26608b0860 --- /dev/null +++ b/boost/geometry/views/box_view.hpp @@ -0,0 +1,114 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_BOX_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_BOX_VIEW_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/views/detail/points_view.hpp> +#include <boost/geometry/algorithms/assign.hpp> + + +namespace boost { namespace geometry +{ + + +/*! +\brief Makes a box behave like a ring or a range +\details Adapts a box to the Boost.Range concept, enabling the user to iterating + box corners. The box_view is registered as a Ring Concept +\tparam Box \tparam_geometry{Box} +\tparam Clockwise If true, walks in clockwise direction, otherwise + it walks in counterclockwise direction +\ingroup views + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_ring Ring Concept] +} + +\qbk{[include reference/views/box_view.qbk]} +*/ +template <typename Box, bool Clockwise = true> +struct box_view + : public detail::points_view + < + typename geometry::point_type<Box>::type, + 5 + > +{ + typedef typename geometry::point_type<Box>::type point_type; + + /// Constructor accepting the box to adapt + explicit box_view(Box const& box) + : detail::points_view<point_type, 5>(copy_policy(box)) + {} + +private : + + class copy_policy + { + public : + inline copy_policy(Box const& box) + : m_box(box) + {} + + inline void apply(point_type* points) const + { + detail::assign_box_corners_oriented<!Clockwise>(m_box, points); + points[4] = points[0]; + } + private : + Box const& m_box; + }; + +}; + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +// All views on boxes are handled as rings +namespace traits +{ + +template<typename Box, bool Clockwise> +struct tag<box_view<Box, Clockwise> > +{ + typedef ring_tag type; +}; + +template<typename Box> +struct point_order<box_view<Box, false> > +{ + static order_selector const value = counterclockwise; +}; + + +template<typename Box> +struct point_order<box_view<Box, true> > +{ + static order_selector const value = clockwise; +}; + +} + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_BOX_VIEW_HPP diff --git a/boost/geometry/views/closeable_view.hpp b/boost/geometry/views/closeable_view.hpp new file mode 100644 index 0000000000..376246d2dc --- /dev/null +++ b/boost/geometry/views/closeable_view.hpp @@ -0,0 +1,100 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_CLOSEABLE_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_CLOSEABLE_VIEW_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/iterators/closing_iterator.hpp> + +#include <boost/geometry/views/identity_view.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail +{ + +template <typename Range> +struct closing_view +{ + // Keep this explicit, important for nested views/ranges + explicit inline closing_view(Range& r) + : m_range(r) + {} + + typedef closing_iterator<Range> iterator; + typedef closing_iterator<Range const> const_iterator; + + inline const_iterator begin() const { return const_iterator(m_range); } + inline const_iterator end() const { return const_iterator(m_range, true); } + + inline iterator begin() { return iterator(m_range); } + inline iterator end() { return iterator(m_range, true); } +private : + Range& m_range; +}; + +} + +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief View on a range, either closing it or leaving it as it is +\details The closeable_view is used internally by the library to handle all rings, + either closed or open, the same way. The default method is closed, all + algorithms process rings as if they are closed. Therefore, if they are opened, + a view is created which closes them. + The closeable_view might be used by library users, but its main purpose is + internally. +\tparam Range Original range +\tparam Close Specifies if it the range is closed, if so, nothing will happen. + If it is open, it will iterate the first point after the last point. +\ingroup views +*/ +template <typename Range, closure_selector Close> +struct closeable_view {}; + + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + +template <typename Range> +struct closeable_view<Range, closed> +{ + typedef identity_view<Range> type; +}; + + +template <typename Range> +struct closeable_view<Range, open> +{ + typedef detail::closing_view<Range> type; +}; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_CLOSEABLE_VIEW_HPP diff --git a/boost/geometry/views/detail/points_view.hpp b/boost/geometry/views/detail/points_view.hpp new file mode 100644 index 0000000000..91fbc41c19 --- /dev/null +++ b/boost/geometry/views/detail/points_view.hpp @@ -0,0 +1,141 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_DETAIL_POINTS_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_DETAIL_POINTS_VIEW_HPP + + +#include <boost/range.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/iterator_categories.hpp> + +#include <boost/geometry/core/exception.hpp> + +namespace boost { namespace geometry +{ + +namespace detail +{ + +// Adapts pointer, on points, to a Boost.Range +template <typename Point, int MaxSize> +class points_view +{ + // Iterates over a series of points (indicated by pointer + // to have it lightweight). Probably there is already an + // equivalent of this within Boost. If so, TODO: use that one. + // This used to be "box_iterator" and "segment_iterator". + struct points_iterator + : public boost::iterator_facade + < + points_iterator, + Point const, + boost::random_access_traversal_tag + > + { + // Constructor: Begin iterator + inline points_iterator(Point const* p) + : m_points(p) + , m_index(0) + {} + + // Constructor: End iterator + inline points_iterator(Point const* p, bool) + : m_points(p) + , m_index(MaxSize) + {} + + // Constructor: default (for Range Concept checking). + inline points_iterator() + : m_points(NULL) + , m_index(MaxSize) + {} + + typedef std::ptrdiff_t difference_type; + + private: + friend class boost::iterator_core_access; + + inline Point const& dereference() const + { + if (m_index >= 0 && m_index < MaxSize) + { + return m_points[m_index]; + } + + // If it index larger (or smaller) return first point + // (assuming initialized) + return m_points[0]; + } + + inline bool equal(points_iterator const& other) const + { + return other.m_index == this->m_index; + } + + inline void increment() + { + m_index++; + } + + inline void decrement() + { + m_index--; + } + + inline difference_type distance_to(points_iterator const& other) const + { + return other.m_index - this->m_index; + } + + inline void advance(difference_type n) + { + m_index += n; + } + + Point const* m_points; + int m_index; + }; + +public : + + typedef points_iterator const_iterator; + typedef points_iterator iterator; // must be defined + + const_iterator begin() const { return const_iterator(m_points); } + const_iterator end() const { return const_iterator(m_points, true); } + + // It may NOT be used non-const, so commented: + //iterator begin() { return m_begin; } + //iterator end() { return m_end; } + +protected : + + template <typename CopyPolicy> + explicit points_view(CopyPolicy const& copy) + { + copy.apply(m_points); + } + +private : + // Copy points here - box might define them otherwise + Point m_points[MaxSize]; +}; + +} + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_DETAIL_POINTS_VIEW_HPP diff --git a/boost/geometry/views/detail/range_type.hpp b/boost/geometry/views/detail/range_type.hpp new file mode 100644 index 0000000000..a40670cf99 --- /dev/null +++ b/boost/geometry/views/detail/range_type.hpp @@ -0,0 +1,106 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_DETAIL_RANGE_TYPE_HPP +#define BOOST_GEOMETRY_VIEWS_DETAIL_RANGE_TYPE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/views/box_view.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename GeometryTag, typename Geometry> +struct range_type +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types<Geometry>) + ); +}; + + +template <typename Geometry> +struct range_type<ring_tag, Geometry> +{ + typedef Geometry type; +}; + +template <typename Geometry> +struct range_type<linestring_tag, Geometry> +{ + typedef Geometry type; +}; + + +template <typename Geometry> +struct range_type<polygon_tag, Geometry> +{ + typedef typename ring_type<Geometry>::type type; +}; + +template <typename Geometry> +struct range_type<box_tag, Geometry> +{ + typedef box_view<Geometry> type; +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +// Will probably be replaced by the more generic "view_as", therefore in detail +namespace detail +{ + + +/*! +\brief Meta-function defining a type which is a boost-range. +\details +- For linestrings and rings, it defines the type itself. +- For polygons it defines the ring type. +- For multi-points, it defines the type itself +- For multi-polygons and multi-linestrings, it defines the single-version + (so in the end the linestring and ring-type-of-multi-polygon) +\ingroup iterators +*/ +template <typename Geometry> +struct range_type +{ + typedef typename dispatch::range_type + < + typename tag<Geometry>::type, + Geometry + >::type type; +}; + +} + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_DETAIL_RANGE_TYPE_HPP diff --git a/boost/geometry/views/identity_view.hpp b/boost/geometry/views/identity_view.hpp new file mode 100644 index 0000000000..5ce6e8e6d6 --- /dev/null +++ b/boost/geometry/views/identity_view.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_IDENTITY_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_IDENTITY_VIEW_HPP + + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + + +/*! +\brief View on a range, not modifying anything +\tparam Range original range +\ingroup views +*/ +template <typename Range> +struct identity_view +{ + typedef typename boost::range_iterator<Range const>::type const_iterator; + typedef typename boost::range_iterator<Range>::type iterator; + + explicit inline identity_view(Range& r) + : m_range(r) + {} + + inline const_iterator begin() const { return boost::begin(m_range); } + inline const_iterator end() const { return boost::end(m_range); } + + inline iterator begin() { return boost::begin(m_range); } + inline iterator end() { return boost::end(m_range); } +private : + Range& m_range; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_IDENTITY_VIEW_HPP diff --git a/boost/geometry/views/reversible_view.hpp b/boost/geometry/views/reversible_view.hpp new file mode 100644 index 0000000000..ad22136c81 --- /dev/null +++ b/boost/geometry/views/reversible_view.hpp @@ -0,0 +1,74 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_REVERSIBLE_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_REVERSIBLE_VIEW_HPP + + +#include <boost/version.hpp> +#include <boost/range.hpp> +#include <boost/range/adaptor/reversed.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/views/identity_view.hpp> + +namespace boost { namespace geometry +{ + +/*! +\brief Flag for iterating a reversible_view in forward or reverse direction +\ingroup views +*/ +enum iterate_direction { iterate_forward, iterate_reverse }; + +/*! +\brief View on a range, reversing direction if necessary +\tparam Range original range +\tparam Direction direction of iteration +\ingroup views +*/ +template <typename Range, iterate_direction Direction> +struct reversible_view {}; + + + +#ifndef DOXYGEN_NO_SPECIALIZATIONS + +template <typename Range> +struct reversible_view<Range, iterate_forward> +{ + typedef identity_view<Range> type; +}; + + +template <typename Range> +struct reversible_view<Range, iterate_reverse> +{ +#if BOOST_VERSION > 104500 + typedef boost::reversed_range<Range> type; +#else + // For older versions of Boost + typedef boost::range_detail::reverse_range<Range> type; +#endif +}; + +#endif // DOXYGEN_NO_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_REVERSIBLE_VIEW_HPP diff --git a/boost/geometry/views/segment_view.hpp b/boost/geometry/views/segment_view.hpp new file mode 100644 index 0000000000..50ff617a8d --- /dev/null +++ b/boost/geometry/views/segment_view.hpp @@ -0,0 +1,100 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 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_VIEWS_SEGMENT_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_SEGMENT_VIEW_HPP + + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/views/detail/points_view.hpp> +#include <boost/geometry/algorithms/assign.hpp> + + +namespace boost { namespace geometry +{ + + +/*! +\brief Makes a segment behave like a linestring or a range +\details Adapts a segment to the Boost.Range concept, enabling the user to + iterate the two segment points. The segment_view is registered as a LineString Concept +\tparam Segment \tparam_geometry{Segment} +\ingroup views + +\qbk{before.synopsis, +[heading Model of] +[link geometry.reference.concepts.concept_linestring LineString Concept] +} + +\qbk{[include reference/views/segment_view.qbk]} + +*/ +template <typename Segment> +struct segment_view + : public detail::points_view + < + typename geometry::point_type<Segment>::type, + 2 + > +{ + typedef typename geometry::point_type<Segment>::type point_type; + + /// Constructor accepting the segment to adapt + explicit segment_view(Segment const& segment) + : detail::points_view<point_type, 2>(copy_policy(segment)) + {} + +private : + + class copy_policy + { + public : + inline copy_policy(Segment const& segment) + : m_segment(segment) + {} + + inline void apply(point_type* points) const + { + geometry::detail::assign_point_from_index<0>(m_segment, points[0]); + geometry::detail::assign_point_from_index<1>(m_segment, points[1]); + } + private : + Segment const& m_segment; + }; + +}; + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +// All segment ranges can be handled as linestrings +namespace traits +{ + +template<typename Segment> +struct tag<segment_view<Segment> > +{ + typedef linestring_tag type; +}; + +} + +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_SEGMENT_VIEW_HPP |