diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-06-25 22:59:01 +0000 |
---|---|---|
committer | <> | 2013-09-27 11:49:28 +0000 |
commit | 8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch) | |
tree | c09e2ce80f47b90c85cc720f5139089ad9c8cfff /boost/geometry | |
download | boost-tarball-8c4528713d907ee2cfd3bfcbbad272c749867f84.tar.gz |
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'boost/geometry')
388 files changed, 65998 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp new file mode 100644 index 000000000..f2d0d366d --- /dev/null +++ b/boost/geometry/algorithms/append.hpp @@ -0,0 +1,292 @@ +// 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/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/detail/convert_point_to_point.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/geometries/concepts/check.hpp> +#include <boost/geometry/geometries/variant.hpp> +#include <boost/range.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.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> +{}; + +} // namespace splitted_dispatch + + +// 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> +{}; + +template <typename Geometry> +struct devarianted_append +{ + template <typename RangeOrPoint> + static inline void apply(Geometry& geometry, + RangeOrPoint const& range_or_point, + int ring_index, + int multi_index) + { + concept::check<Geometry>(); + append<Geometry, RangeOrPoint>::apply(geometry, + range_or_point, + ring_index, + multi_index); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename RangeOrPoint> + struct visitor: boost::static_visitor<void> + { + RangeOrPoint const& m_range_or_point; + int m_ring_index; + int m_multi_index; + + visitor(RangeOrPoint const& range_or_point, + int ring_index, + int multi_index): + m_range_or_point(range_or_point), + m_ring_index(ring_index), + m_multi_index(multi_index) + {} + + template <typename Geometry> + void operator()(Geometry& geometry) const + { + concept::check<Geometry>(); + append<Geometry, RangeOrPoint>::apply(geometry, + m_range_or_point, + m_ring_index, + m_multi_index); + } + }; + + template <typename RangeOrPoint> + static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant_geometry, + RangeOrPoint const& range_or_point, + int ring_index, + int multi_index) + { + apply_visitor( + visitor<RangeOrPoint>( + range_or_point, + ring_index, + multi_index + ), + variant_geometry + ); + } +}; + + +} // 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) +{ + dispatch::devarianted_append<Geometry> + ::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 000000000..537a36763 --- /dev/null +++ b/boost/geometry/algorithms/area.hpp @@ -0,0 +1,299 @@ +// 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/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.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 +{ + +struct box_area +{ + template <typename Box, typename Strategy> + static inline typename coordinate_type<Box>::type + apply(Box const& box, Strategy const&) + { + // Currently only works for 2D Cartesian boxes + assert_dimension<Box, 2>(); + + return (get<max_corner, 0>(box) - get<min_corner, 0>(box)) + * (get<max_corner, 1>(box) - get<min_corner, 1>(box)); + } +}; + + +template +< + iterate_direction Direction, + closure_selector Closure +> +struct ring_area +{ + template <typename Ring, typename Strategy> + static inline typename Strategy::return_type + apply(Ring const& ring, Strategy const& strategy) + { + BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<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 (int(boost::size(ring)) + < core_detail::closure::minimum_ring_size<Closure>::value) + { + return typename Strategy::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 Tag = typename tag<Geometry>::type +> +struct area : detail::calculate_null +{ + template <typename Strategy> + static inline typename Strategy::return_type apply(Geometry const& geometry, Strategy const& strategy) + { + return calculate_null::apply<typename Strategy::return_type>(geometry, strategy); + } +}; + + +template <typename Geometry> +struct area<Geometry, box_tag> : detail::area::box_area +{}; + + +template <typename Ring> +struct area<Ring, ring_tag> + : detail::area::ring_area + < + order_as_direction<geometry::point_order<Ring>::value>::value, + geometry::closure<Ring>::value + > +{}; + + +template <typename Polygon> +struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum +{ + template <typename Strategy> + static inline typename Strategy::return_type apply(Polygon const& polygon, Strategy const& strategy) + { + return calculate_polygon_sum::apply< + typename Strategy::return_type, + detail::area::ring_area + < + order_as_direction<geometry::point_order<Polygon>::value>::value, + geometry::closure<Polygon>::value + > + >(polygon, strategy); + } +}; + + +template <typename Geometry> +struct devarianted_area +{ + template <typename Strategy> + static inline typename Strategy::return_type apply(Geometry const& geometry, + Strategy const& strategy) + { + return area<Geometry>::apply(geometry, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Strategy> + struct visitor: boost::static_visitor<typename Strategy::return_type> + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy): m_strategy(strategy) {} + + template <typename Geometry> + typename Strategy::return_type operator()(Geometry const& geometry) const + { + return devarianted_area<Geometry>::apply(geometry, m_strategy); + } + }; + + template <typename Strategy> + static inline typename Strategy::return_type + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<Strategy>(strategy), geometry); + } +}; + + +} // 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::devarianted_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::devarianted_area<Geometry>::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 000000000..97a033d1d --- /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 works 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 000000000..29966d8cc --- /dev/null +++ b/boost/geometry/algorithms/buffer.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_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/not_implemented.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 Input, + typename Output, + typename TagIn = typename tag<Input>::type, + typename TagOut = typename tag<Output>::type +> +struct buffer: not_implemented<TagIn, TagOut> +{}; + + +template <typename BoxIn, typename BoxOut> +struct buffer<BoxIn, BoxOut, box_tag, box_tag> +{ + template <typename Distance> + static inline void apply(BoxIn const& box_in, Distance const& distance, + Distance 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 + < + Input, + 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 Distance> +Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1) +{ + concept::check<Input const>(); + concept::check<Output>(); + + Output geometry_out; + + dispatch::buffer + < + Input, + 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 000000000..9be51f409 --- /dev/null +++ b/boost/geometry/algorithms/centroid.hpp @@ -0,0 +1,429 @@ +// 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/algorithms/not_implemented.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 +{ + +struct centroid_point +{ + template<typename Point, typename PointCentroid, typename Strategy> + 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& ) + { + } +}; + + +struct centroid_box +{ + template<typename Box, typename Point, typename Strategy> + 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 <closure_selector Closure> +struct centroid_range_state +{ + template<typename Ring, typename Strategy> + 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 <closure_selector Closure> +struct centroid_range +{ + template<typename Range, typename Point, typename Strategy> + 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<Closure>::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. +*/ +struct centroid_polygon_state +{ + template<typename Polygon, typename Strategy> + static inline void apply(Polygon const& poly, + Strategy const& strategy, typename Strategy::state_type& state) + { + typedef typename ring_type<Polygon>::type ring_type; + typedef centroid_range_state<geometry::closure<ring_type>::value> 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); + } + } +}; + +struct centroid_polygon +{ + template<typename Polygon, typename Point, typename Strategy> + 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::apply(poly, strategy, state); + strategy.result(state, centroid); + } + } +}; + + +}} // namespace detail::centroid +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct centroid: not_implemented<Tag> +{}; + +template <typename Geometry> +struct centroid<Geometry, point_tag> + : detail::centroid::centroid_point +{}; + +template <typename Box> +struct centroid<Box, box_tag> + : detail::centroid::centroid_box +{}; + +template <typename Ring> +struct centroid<Ring, ring_tag> + : detail::centroid::centroid_range<geometry::closure<Ring>::value> +{}; + +template <typename Linestring> +struct centroid<Linestring, linestring_tag> + : detail::centroid::centroid_range<closed> + {}; + +template <typename Polygon> +struct centroid<Polygon, polygon_tag> + : detail::centroid::centroid_polygon + {}; + +} // 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<Geometry>::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 000000000..b8cd0dca7 --- /dev/null +++ b/boost/geometry/algorithms/clear.hpp @@ -0,0 +1,184 @@ +// 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/geometry/algorithms/not_implemented.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> +#include <boost/type_traits/remove_const.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.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: not_implemented<Tag> +{}; + +// 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> +{}; + + +template <typename Geometry> +struct devarianted_clear +{ + static inline void apply(Geometry& geometry) + { + clear<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_clear<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: static_visitor<void> + { + template <typename Geometry> + inline void operator()(Geometry& geometry) const + { + clear<Geometry>::apply(geometry); + } + }; + + static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) + { + apply_visitor(visitor(), geometry); + } +}; + + +} // 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::devarianted_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 000000000..3467045ca --- /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 000000000..6b48ca604 --- /dev/null +++ b/boost/geometry/algorithms/convert.hpp @@ -0,0 +1,461 @@ +// 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> + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry +{ + +// Silence warning C4127: conditional expression is constant +// Silence warning C4512: assignment operator could not be generated +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127 4512) +#endif + + +#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); + } +}; + + +template <typename Geometry1, typename Geometry2> +struct devarianted_convert +{ + static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2) + { + concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>(); + convert<Geometry1, Geometry2>::apply(geometry1, geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct devarianted_convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + struct visitor: static_visitor<void> + { + Geometry2& m_geometry2; + + visitor(Geometry2& geometry2) + : m_geometry2(geometry2) + {} + + template <typename Geometry1> + inline void operator()(Geometry1 const& geometry1) const + { + devarianted_convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2); + } + }; + + static inline void apply( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2& geometry2 + ) + { + apply_visitor(visitor(geometry2), geometry1); + } +}; + + +} // 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 works 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) +{ + dispatch::devarianted_convert<Geometry1, Geometry2>::apply(geometry1, geometry2); +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..a623064bf --- /dev/null +++ b/boost/geometry/algorithms/convex_hull.hpp @@ -0,0 +1,249 @@ +// 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 <order_selector Order> +struct hull_insert +{ + + // Member template function (to avoid inconvenient declaration + // of output-iterator-type, from hull_to_geometry) + template <typename Geometry, typename OutputIterator, typename Strategy> + 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; + } +}; + +struct hull_to_geometry +{ + template <typename Geometry, typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, OutputGeometry& out, + Strategy const& strategy) + { + hull_insert + < + geometry::point_order<OutputGeometry>::value + >::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 Tag = typename tag<Geometry>::type +> +struct convex_hull + : detail::convex_hull::hull_to_geometry +{}; + +template <typename Box> +struct convex_hull<Box, box_tag> +{ + template <typename OutputGeometry, typename Strategy> + 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> +struct convex_hull_insert + : detail::convex_hull::hull_insert<Order> +{}; + + +} // 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>::apply(geometry, out, strategy); +} + + +/*! +\brief \brief_calc{convex hull} +\ingroup convex_hull +\details \details_calc{convex_hull,convex hull}. +\tparam Geometry the input geometry type +\tparam OutputGeometry the output geometry type +\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 + >::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 000000000..79c76a567 --- /dev/null +++ b/boost/geometry/algorithms/correct.hpp @@ -0,0 +1,272 @@ +// 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 +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + +#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 + < + order_as_direction<geometry::point_order<Ring>::value>::value, + geometry::closure<Ring>::value + > 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 && s != 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); +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..f0f572421 --- /dev/null +++ b/boost/geometry/algorithms/covered_by.hpp @@ -0,0 +1,197 @@ +// 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) + { + ::boost::ignore_unused_variable_warning(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>(); + ::boost::ignore_unused_variable_warning(strategy); + 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 000000000..d0dfb07e4 --- /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 000000000..1637c30cc --- /dev/null +++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp @@ -0,0 +1,103 @@ +// 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); +} + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + +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]); + } +} +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + +} // 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 000000000..a1cffb80a --- /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 000000000..ed4713493 --- /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 000000000..3ebca8350 --- /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 +{ + +struct calculate_null +{ + template<typename ReturnType, typename Geometry, typename Strategy> + 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 000000000..dd0399bb1 --- /dev/null +++ b/boost/geometry/algorithms/detail/calculate_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_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 +{ + + +class calculate_polygon_sum +{ + template <typename ReturnType, typename Policy, typename Rings, typename Strategy> + 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 : + template <typename ReturnType, typename Policy, typename Polygon, typename Strategy> + static inline ReturnType apply(Polygon const& poly, Strategy const& strategy) + { + return Policy::apply(exterior_ring(poly), strategy) + + sum_interior_rings<ReturnType, Policy>(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 000000000..d39824a61 --- /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 000000000..c7d37b6ca --- /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 000000000..e944e5169 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint.hpp @@ -0,0 +1,239 @@ +// 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/algorithms/covered_by.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; + } +}; + + +template +< + typename Geometry1, typename Geometry2 +> +struct reverse_covered_by +{ + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + return ! geometry::covered_by(geometry1, geometry2); + } +}; + + + +/*! + \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 000000000..9c2fe2805 --- /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 000000000..7cb01fa9b --- /dev/null +++ b/boost/geometry/algorithms/detail/for_each_range.hpp @@ -0,0 +1,149 @@ +// 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> +#include <boost/geometry/views/box_view.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/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp new file mode 100644 index 000000000..d23f1e4c2 --- /dev/null +++ b/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -0,0 +1,371 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 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_GET_LEFT_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP + +#include <boost/geometry/iterators/ever_circling_iterator.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// TODO: move this to /util/ +template <typename T> +static inline std::pair<T, T> ordered_pair(T const& first, T const& second) +{ + return first < second ? std::make_pair(first, second) : std::make_pair(second, first); +} + +template <typename AngleInfo> +inline void debug_left_turn(AngleInfo const& ai, AngleInfo const& previous) +{ +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << "Angle: " << (ai.incoming ? "i" : "o") + << " " << si(ai.seg_id) + << " " << (math::r2d * (ai.angle) ) + << " turn: " << ai.turn_index << "[" << ai.operation_index << "]" + ; + + if (ai.turn_index != previous.turn_index + || ai.operation_index != previous.operation_index) + { + std::cout << " diff: " << math::r2d * math::abs(previous.angle - ai.angle); + } + std::cout << std::endl; +#endif +} + +template <typename AngleInfo> +inline void debug_left_turn(std::string const& caption, AngleInfo const& ai, AngleInfo const& previous, + int code = -99, int code2 = -99, int code3 = -99, int code4 = -99) +{ +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << " " << caption + << " turn: " << ai.turn_index << "[" << ai.operation_index << "]" + << " " << si(ai.seg_id) + << " " << (ai.incoming ? "i" : "o") + << " " << (math::r2d * (ai.angle) ) + << " turn: " << previous.turn_index << "[" << previous.operation_index << "]" + << " " << si(previous.seg_id) + << " " << (previous.incoming ? "i" : "o") + << " " << (math::r2d * (previous.angle) ) + ; + + if (code != -99) + { + std::cout << " code: " << code << " , " << code2 << " , " << code3 << " , " << code4; + } + std::cout << std::endl; +#endif +} + + +template <typename Operation> +inline bool include_operation(Operation const& op, + segment_identifier const& outgoing_seg_id, + segment_identifier const& incoming_seg_id) +{ + return op.seg_id == outgoing_seg_id + && op.other_id == incoming_seg_id + && (op.operation == detail::overlay::operation_union + ||op.operation == detail::overlay::operation_continue) + ; +} + +template <typename Turn> +inline bool process_include(segment_identifier const& outgoing_seg_id, segment_identifier const& incoming_seg_id, + int turn_index, Turn& turn, + std::set<int>& keep_indices, int priority) +{ + bool result = false; + for (int i = 0; i < 2; i++) + { + if (include_operation(turn.operations[i], outgoing_seg_id, incoming_seg_id)) + { + turn.operations[i].include_in_occupation_map = true; + if (priority > turn.priority) + { + turn.priority = priority; + } + keep_indices.insert(turn_index); + result = true; + } + } + return result; +} + +template <typename AngleInfo, typename Turns, typename TurnSegmentIndices> +inline bool include_left_turn_of_all( + AngleInfo const& outgoing, AngleInfo const& incoming, + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set<int>& keep_indices, int priority) +{ + segment_identifier const& outgoing_seg_id = turns[outgoing.turn_index].operations[outgoing.operation_index].seg_id; + segment_identifier const& incoming_seg_id = turns[incoming.turn_index].operations[incoming.operation_index].seg_id; + + if (outgoing.turn_index == incoming.turn_index) + { + return process_include(outgoing_seg_id, incoming_seg_id, outgoing.turn_index, turns[outgoing.turn_index], keep_indices, priority); + } + + bool result = false; + std::pair<segment_identifier, segment_identifier> pair = ordered_pair(outgoing_seg_id, incoming_seg_id); + typename boost::range_iterator<TurnSegmentIndices const>::type it = turn_segment_indices.find(pair); + if (it != turn_segment_indices.end()) + { + for (std::set<int>::const_iterator sit = it->second.begin(); sit != it->second.end(); ++sit) + { + if (process_include(outgoing_seg_id, incoming_seg_id, *sit, turns[*sit], keep_indices, priority)) + { + result = true; + } + } + } + return result; +} + +template <std::size_t Index, typename Turn> +inline bool corresponds(Turn const& turn, segment_identifier const& seg_id) +{ + return turn.operations[Index].operation == detail::overlay::operation_union + && turn.operations[Index].seg_id == seg_id; +} + + +template <typename Turns, typename TurnSegmentIndices> +inline bool prefer_by_other(Turns const& turns, + TurnSegmentIndices const& turn_segment_indices, + std::set<int>& indices) +{ + std::map<segment_identifier, int> map; + for (std::set<int>::const_iterator sit = indices.begin(); + sit != indices.end(); + ++sit) + { + map[turns[*sit].operations[0].seg_id]++; + map[turns[*sit].operations[1].seg_id]++; + } + + std::set<segment_identifier> segment_occuring_once; + for (std::map<segment_identifier, int>::const_iterator mit = map.begin(); + mit != map.end();++mit) + { + if (mit->second == 1) + { + segment_occuring_once.insert(mit->first); + } +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER + std::cout << si(mit->first) << " " << mit->second << std::endl; +#endif + } + + if (segment_occuring_once.size() == 2) + { + // Try to find within all turns a turn with these two segments + + std::set<segment_identifier>::const_iterator soo_it = segment_occuring_once.begin(); + segment_identifier front = *soo_it; + soo_it++; + segment_identifier back = *soo_it; + + std::pair<segment_identifier, segment_identifier> pair = ordered_pair(front, back); + + typename boost::range_iterator<TurnSegmentIndices const>::type it = turn_segment_indices.find(pair); + if (it != turn_segment_indices.end()) + { + // debug_turns_by_indices("Found", it->second); + // Check which is the union/continue + segment_identifier good; + for (std::set<int>::const_iterator sit = it->second.begin(); sit != it->second.end(); ++sit) + { + if (turns[*sit].operations[0].operation == detail::overlay::operation_union) + { + good = turns[*sit].operations[0].seg_id; + } + else if (turns[*sit].operations[1].operation == detail::overlay::operation_union) + { + good = turns[*sit].operations[1].seg_id; + } + } + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER + std::cout << "Good: " << si(good) << std::endl; +#endif + + // Find in indexes-to-keep this segment with the union. Discard the other one + std::set<int> ok_indices; + for (std::set<int>::const_iterator sit = indices.begin(); sit != indices.end(); ++sit) + { + if (corresponds<0>(turns[*sit], good) || corresponds<1>(turns[*sit], good)) + { + ok_indices.insert(*sit); + } + } + if (ok_indices.size() > 0 && ok_indices.size() < indices.size()) + { + indices = ok_indices; + std::cout << "^"; + return true; + } + } + } + return false; +} + +template <typename Turns> +inline void prefer_by_priority(Turns const& turns, std::set<int>& indices) +{ + // Find max prio + int min_prio = 1024, max_prio = 0; + for (std::set<int>::const_iterator sit = indices.begin(); sit != indices.end(); ++sit) + { + if (turns[*sit].priority > max_prio) + { + max_prio = turns[*sit].priority; + } + if (turns[*sit].priority < min_prio) + { + min_prio = turns[*sit].priority; + } + } + + if (min_prio == max_prio) + { + return; + } + + // Only keep indices with high prio + std::set<int> ok_indices; + for (std::set<int>::const_iterator sit = indices.begin(); sit != indices.end(); ++sit) + { + if (turns[*sit].priority >= max_prio) + { + ok_indices.insert(*sit); + } + } + if (ok_indices.size() > 0 && ok_indices.size() < indices.size()) + { + indices = ok_indices; + std::cout << "%"; + } +} + +template <typename AngleInfo, typename Angles, typename Turns, typename TurnSegmentIndices> +inline void calculate_left_turns(Angles const& angles, + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set<int>& keep_indices) +{ + bool debug_indicate_size = false; + + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<typename AngleInfo::point_type>::type + >::type side_strategy; + + std::size_t i = 0; + std::size_t n = boost::size(angles); + + typedef geometry::ever_circling_range_iterator<Angles const> circling_iterator; + circling_iterator cit(angles); + + debug_left_turn(*cit, *cit); + for(circling_iterator prev = cit++; i < n; prev = cit++, i++) + { + debug_left_turn(*cit, *prev); + + bool const include = ! geometry::math::equals(prev->angle, cit->angle) + && ! prev->incoming + && cit->incoming; + + if (include) + { + // Go back to possibly include more same left outgoing angles: + // Because we check on side too we can take a large "epsilon" + circling_iterator back = prev - 1; + + typename AngleInfo::angle_type eps = 0.00001; + int b = 1; + for(std::size_t d = 0; + math::abs(prev->angle - back->angle) < eps + && ! back->incoming + && d < n; + d++) + { + --back; + ++b; + } + + // Same but forward to possibly include more incoming angles + int f = 1; + circling_iterator forward = cit + 1; + for(std::size_t d = 0; + math::abs(cit->angle - forward->angle) < eps + && forward->incoming + && d < n; + d++) + { + ++forward; + ++f; + } + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << "HANDLE " << b << "/" << f << " ANGLES" << std::endl; +#endif + for(circling_iterator bit = prev; bit != back; --bit) + { + int code = side_strategy::apply(bit->direction_point, prev->intersection_point, prev->direction_point); + int code2 = side_strategy::apply(prev->direction_point, bit->intersection_point, bit->direction_point); + for(circling_iterator fit = cit; fit != forward; ++fit) + { + int code3 = side_strategy::apply(fit->direction_point, cit->intersection_point, cit->direction_point); + int code4 = side_strategy::apply(cit->direction_point, fit->intersection_point, fit->direction_point); + + int priority = 2; + if (code == -1 && code2 == 1) + { + // This segment is lying right of the other one. + // Cannot ignore it (because of robustness, see a.o. #rt_p21 from unit test). + // But if we find more we can prefer later by priority + // (a.o. necessary for #rt_o2 from unit test) + priority = 1; + } + + bool included = include_left_turn_of_all(*bit, *fit, turns, turn_segment_indices, keep_indices, priority); + debug_left_turn(included ? "KEEP" : "SKIP", *fit, *bit, code, code2, code3, code4); + } + } + } + } + + if (debug_indicate_size) + { + std::cout << " size=" << keep_indices.size(); + } + + if (keep_indices.size() >= 2) + { + prefer_by_other(turns, turn_segment_indices, keep_indices); + } + if (keep_indices.size() >= 2) + { + prefer_by_priority(turns, keep_indices); + } +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_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 000000000..1e6215ed9 --- /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 000000000..abc3a4e16 --- /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/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp new file mode 100644 index 000000000..f4d5adac8 --- /dev/null +++ b/boost/geometry/algorithms/detail/occupation_info.hpp @@ -0,0 +1,329 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 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_OCCUPATION_INFO_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP + +#if ! defined(NDEBUG) +// #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION +#endif + +#include <algorithm> +#include <boost/range.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/iterators/closing_iterator.hpp> + +#include <boost/geometry/algorithms/detail/get_left_turns.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename P> +class relaxed_less +{ + typedef typename geometry::coordinate_type<P>::type coordinate_type; + + coordinate_type epsilon; + +public : + + inline relaxed_less() + { + // TODO: adapt for ttmath, and maybe build the map in another way + // (e.g. exact constellations of segment-id's), maybe adaptive. + epsilon = std::numeric_limits<double>::epsilon() * 100.0; + } + + inline bool operator()(P const& a, P const& b) const + { + coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b)); + coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b)); + + + if (dx < epsilon && dy < epsilon) + { + return false; + } + if (dx < epsilon) + { + return geometry::get<1>(a) < geometry::get<1>(b); + } + + return geometry::get<0>(a) < geometry::get<0>(b); + } + + inline bool equals(P const& a, P const& b) const + { + typedef typename geometry::coordinate_type<P>::type coordinate_type; + + coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b)); + coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b)); + + return dx < epsilon && dy < epsilon; + }; +}; + + +template <typename T, typename P1, typename P2> +inline T calculate_angle(P1 const& from_point, P2 const& to_point) +{ + typedef P1 vector_type; + vector_type v = from_point; + geometry::subtract_point(v, to_point); + return atan2(geometry::get<1>(v), geometry::get<0>(v)); +} + +template <typename Iterator, typename Vector> +inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true) +{ + int const increment = forward ? 1 : -1; + if (it == boost::begin(vector) && increment < 0) + { + it = boost::end(vector); + seg_id.segment_index = boost::size(vector); + } + it += increment; + seg_id.segment_index += increment; + if (it == boost::end(vector)) + { + seg_id.segment_index = 0; + it = boost::begin(vector); + } + return it; +} + +template <typename Point, typename T> +struct angle_info +{ + typedef T angle_type; + typedef Point point_type; + + segment_identifier seg_id; + int turn_index; + int operation_index; + Point intersection_point; + Point direction_point; + T angle; + bool incoming; +}; + +template <typename AngleInfo> +class occupation_info +{ + typedef std::vector<AngleInfo> collection_type; + + struct angle_sort + { + inline bool operator()(AngleInfo const& left, AngleInfo const& right) const + { + // In this case we can compare even double using equals + // return geometry::math::equals(left.angle, right.angle) + return left.angle == right.angle + ? int(left.incoming) < int(right.incoming) + : left.angle < right.angle + ; + } + }; + +public : + collection_type angles; +private : + bool m_occupied; + bool m_calculated; + + inline bool is_occupied() + { + if (boost::size(angles) <= 1) + { + return false; + } + + std::sort(angles.begin(), angles.end(), angle_sort()); + + typedef geometry::closing_iterator<collection_type const> closing_iterator; + closing_iterator vit(angles); + closing_iterator end(angles, true); + + closing_iterator prev = vit++; + for( ; vit != end; prev = vit++) + { + if (! geometry::math::equals(prev->angle, vit->angle) + && ! prev->incoming + && vit->incoming) + { + return false; + } + } + return true; + } + +public : + inline occupation_info() + : m_occupied(false) + , m_calculated(false) + {} + + template <typename PointC, typename Point1, typename Point2> + inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point, + int turn_index, int operation_index, + segment_identifier const& seg_id, bool incoming) + { + //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl; + if (geometry::equals(direction_point, intersection_point)) + { + //std::cout << "EQUAL! Skipping" << std::endl; + return; + } + + AngleInfo info; + info.incoming = incoming; + info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point); + info.seg_id = seg_id; + info.turn_index = turn_index; + info.operation_index = operation_index; + info.intersection_point = intersection_point; + info.direction_point = direction_point; + angles.push_back(info); + + m_calculated = false; + } + + inline bool occupied() + { + if (! m_calculated) + { + m_occupied = is_occupied(); + m_calculated = true; + } + return m_occupied; + } + + template <typename Turns, typename TurnSegmentIndices> + inline void get_left_turns( + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set<int>& keep_indices) + { + std::sort(angles.begin(), angles.end(), angle_sort()); + calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices); + } +}; + + +template <typename Point, typename Ring, typename Info> +inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point, + Ring const& ring, + int turn_index, + int operation_index, + segment_identifier seg_id, + Info& info) +{ + typedef typename boost::range_iterator + < + Ring const + >::type iterator_type; + + int const n = boost::size(ring); + if (seg_id.segment_index >= n || seg_id.segment_index < 0) + { + return; + } + + segment_identifier real_seg_id = seg_id; + iterator_type it = boost::begin(ring) + seg_id.segment_index; + + // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals + relaxed_less<Point> comparator; + + if (comparator.equals(intersection_point, *it)) + { + // It should be equal only once. But otherwise we skip it (in "add") + it = advance_circular(it, ring, seg_id, false); + } + + info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true); + + if (comparator.equals(intersection_point, *it)) + { + it = advance_circular(it, ring, real_seg_id); + } + else + { + // Don't upgrade the ID + it = advance_circular(it, ring, seg_id); + } + for (int defensive_check = 0; + comparator.equals(intersection_point, *it) && defensive_check < n; + defensive_check++) + { + it = advance_circular(it, ring, real_seg_id); + } + + info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false); +} + + +// Map in two senses of the word: it is a std::map where the key is a point. +// Per point an "occupation_info" record is kept +// Used for the buffer (but will also be used for intersections/unions having complex self-tangencies) +template <typename Point, typename OccupationInfo> +class occupation_map +{ +public : + typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type; + + map_type map; + std::set<int> turn_indices; + + inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point) + { + typename map_type::iterator it = map.find(point); + if (it == boost::end(map)) + { + std::pair<typename map_type::iterator, bool> pair + = map.insert(std::make_pair(point, OccupationInfo())); + it = pair.first; + } + mapped_point = it->first; + return it->second; + } + + inline bool contains(Point const& point) const + { + typename map_type::const_iterator it = map.find(point); + return it != boost::end(map); + } + + inline bool contains_turn_index(int index) const + { + return turn_indices.count(index) > 0; + } + + inline void insert_turn_index(int index) + { + turn_indices.insert(index); + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_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 000000000..5ff0b57d6 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp @@ -0,0 +1,159 @@ +// 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/core/closure.hpp> +#include <boost/geometry/algorithms/area.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; + typedef typename SelectionMap::mapped_type property_type; + typedef typename property_type::area_type area_type; + + area_type const zero = 0; + std::size_t const min_num_points = core_detail::closure::minimum_ring_size + < + geometry::closure + < + typename boost::range_value + < + RingCollection const + >::type + >::value + >::value; + + + 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); + } + } + + // Only add rings if they satisfy minimal requirements. + // This cannot be done earlier (during traversal), not + // everything is figured out yet (sum of positive/negative rings) + if (geometry::num_points(result) >= min_num_points + && math::larger(geometry::area(result), zero)) + { + *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 000000000..2c0f88e2a --- /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 000000000..5063f49eb --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -0,0 +1,338 @@ +// 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 (math::larger(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, + bool check_for_orientation) +{ + // Call it with an empty geometry + // (ring_map should be empty for source_id==1) + + Geometry empty; + assign_parents(geometry, empty, collection, ring_map, check_for_orientation); +} + + +}} // 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 000000000..012b3aca3 --- /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 000000000..a365ccf90 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.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_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; + static bool const include_opposite = false; + + template + < + typename Info, + typename Point1, + typename Point2, + typename IntersectionInfo, + typename DirInfo + > + static inline void apply(Info& info, Point1 const& p1, Point2 const& p2, + IntersectionInfo const&, DirInfo const&) + { + 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 000000000..b210fd04b --- /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 000000000..fc4f65732 --- /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 000000000..51955b515 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp @@ -0,0 +1,110 @@ +// 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 + { + // Avoid adding interior rings which are invalid + // because of its number of points: + std::size_t const min_num_points + = core_detail::closure::minimum_ring_size + < + geometry::closure<Destination>::value + >::value; + + if (geometry::num_points(source) >= min_num_points) + { + 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 000000000..5e18d0453 --- /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 >= int(boost::size(range))) + { + index = 0; + } + } + + // Exception? + if (index >= int(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 000000000..805f3923e --- /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 < int(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 + : int(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 >= int(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 000000000..0cc34255c --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp @@ -0,0 +1,66 @@ +// 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'; + case method_error : return '!'; + 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'; + case operation_opposite : return 'o'; + 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 000000000..00b7a5c3a --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -0,0 +1,525 @@ +// 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) + { + // Both left and right are located on the SAME segment. + typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type; + coordinate_type diff = geometry::math::abs(left.subject.enriched.distance - right.subject.enriched.distance); + if (diff < geometry::math::relaxed_epsilon<coordinate_type>(10)) + { + // 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.subject.enriched.distance < right.subject.enriched.distance; + } + } + 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 000000000..8c8ed9618 --- /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 000000000..b110cc960 --- /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). + inline int operation_order(Turn const& turn) const + { + operation_type const& operation = turn.operations[0].operation; + switch(operation) + { + case operation_opposite : return 0; + 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 000000000..019c3ba3f --- /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 000000000..522ef6838 --- /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 000000000..c2c698057 --- /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 < int(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 000000000..68aa62bb4 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -0,0 +1,1122 @@ +// 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> + + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + +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 both_continue = side_pk_p == 0 && side_qk_q == 0; + bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0; + + bool const q_turns_left = side_qk_q == 1; + bool const block_q = side_qk_p1 == 0 + && ! same(side_qi_p1, side_qk_q) + && ! robustness_issue_in_continue + ; + + // 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 independent), + // 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 AssignPolicy +> +struct equal_opposite : public base_turn_handler +{ + template + < + typename Point1, + typename Point2, + typename OutputIterator, + typename IntersectionInfo, + typename DirInfo + > + static inline void apply(Point1 const& pi, Point2 const& qi, + /* by value: */ TurnInfo tp, + OutputIterator& out, + IntersectionInfo const& intersection_info, + DirInfo const& dir_info) + { + // For equal-opposite segments, normally don't do anything. + if (AssignPolicy::include_opposite) + { + tp.method = method_equal; + for (int i = 0; i < 2; i++) + { + tp.operations[i].operation = operation_opposite; + } + for (unsigned int i = 0; i < intersection_info.count; i++) + { + geometry::convert(intersection_info.intersections[i], tp.point); + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *out++ = tp; + } + } + } +}; + +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) + + ROBUSTNESS: p and q are collinear, so you would expect + that side qk//p1 == pk//q1. But that is not always the case + in near-epsilon ranges. Then decision logic is different. + If p arrives, q is further, so the angle qk//p1 is (normally) + more precise than pk//p1 + + */ + 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); + + int const side_p = SideStrategy::apply(pi, pj, pk); + int const side_q = SideStrategy::apply(qi, qj, qk); + + // If p arrives, use p, else use q + int const side_p_or_q = arrival == 1 + ? side_p + : side_q + ; + + int const side_pk = SideStrategy::apply(qi, qj, pk); + int const side_qk = SideStrategy::apply(pi, pj, 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; + + // Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear) + // and side_q to side_qk + bool const robustness_issue = side_pk != side_p || side_qk != side_q; + + if (robustness_issue) + { + handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk); + } + else if(product == 0) + { + both(ti, operation_continue); + } + else + { + ui_else_iu(product == 1, ti); + } + } + + static inline void handle_robustness(TurnInfo& ti, int arrival, + int side_p, int side_q, int side_pk, int side_qk) + { + // We take the longer one, i.e. if q arrives in p (arrival == -1), + // then p exceeds q and we should take p for a union... + + bool use_p_for_union = arrival == -1; + + // ... unless one of the sides consistently directs to the other side + int const consistent_side_p = side_p == side_pk ? side_p : 0; + int const consistent_side_q = side_q == side_qk ? side_q : 0; + if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1)) + { + use_p_for_union = false; + } + if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1)) + { + use_p_for_union = true; + } + + //std::cout << "ROBUSTNESS -> Collinear " + // << " arr: " << arrival + // << " dir: " << side_p << " " << side_q + // << " rev: " << side_pk << " " << side_qk + // << " cst: " << cside_p << " " << cside_q + // << std::boolalpha << " " << use_p_for_union + // << std::endl; + + ui_else_iu(use_p_for_union, 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, + bool const handle_robustness, Point const& si, Point const& sj, + TurnInfo& tp, IntersectionInfo const& intersection_info) + { + int side_rk_r = SideStrategy::apply(ri, rj, rk); + + if (handle_robustness) + { + int const side_rk_s = SideStrategy::apply(si, sj, rk); + + // For Robustness: also calculate rk w.r.t. the other line. Because they are collinear opposite, that direction should be the reverse of the first direction. + // If this is not the case, we make it all-collinear, so zero + if (side_rk_r != 0 && side_rk_r != -side_rk_s) + { +#ifdef BOOST_GEOMETRY_DEBUG_ROBUSTNESS + std::cout << "Robustness correction: " << side_rk_r << " / " << side_rk_s << std::endl; +#endif + side_rk_r = 0; + } + } + + operation_type blocked = operation_blocked; + 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 usually ignored, it is useless to include + // two operations blocked, so the whole point does not need + // to be generated. + // So return false to indicate nothing is to be done. + if (AssignPolicy::include_opposite) + { + tp.operations[Index].operation = operation_opposite; + blocked = operation_opposite; + } + else + { + return false; + } + break; + } + + // The other direction is always blocked when collinear opposite + tp.operations[1 - Index].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) + { + TurnInfo tp = tp_model; + + tp.method = method_collinear; + + // If P arrives within Q, there is a turn dependent on P + if (dir_info.arrival[0] == 1 + && set_tp<0>(pi, pj, pk, true, qi, qj, tp, intersection_info)) + { + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *out++ = tp; + } + + // If Q arrives within P, there is a turn dependent on Q + if (dir_info.arrival[1] == 1 + && set_tp<1>(qi, qj, qk, false, pi, pj, tp, intersection_info)) + { + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *out++ = tp; + } + + if (AssignPolicy::include_opposite) + { + // Handle cases not yet handled above + if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0) + || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0)) + { + for (int i = 0; i < 2; i++) + { + tp.operations[i].operation = operation_opposite; + } + for (unsigned int i = 0; i < intersection_info.count; i++) + { + geometry::convert(intersection_info.intersections[i], tp.point); + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *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; + static bool const include_opposite = false; + + template + < + typename Info, + typename Point1, + typename Point2, + typename IntersectionInfo, + typename DirInfo + > + static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo 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; + + // Intersect pi-pj with qi-qj + // The points pk and qk are only used do determine more information + // about the turn. + 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, result.template get<0>(), result.template get<1>()); + *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, result.template get<0>(), result.template get<1>()); + *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, result.template get<0>(), result.template get<1>()); + *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, result.template get<0>(), result.template get<1>()); + *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, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + else + { + equal_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, qi, + tp, out, result.template get<0>(), result.template get<1>()); + } + } + 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, result.template get<0>(), result.template get<1>()); + *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, result.template get<0>(), result.template get<1>()); + *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 + + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#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 000000000..782ea7fd2 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -0,0 +1,890 @@ +// 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/concept_check.hpp> +#include <boost/mpl/if.hpp> +#include <boost/range.hpp> +#include <boost/typeof/typeof.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 +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + +#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); + + boost::ignore_unused_variable_warning(n); + boost::ignore_unused_variable_warning(index1); + boost::ignore_unused_variable_warning(index2); + + 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) + { + boost::ignore_unused_variable_warning(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& interrupt_policy, + 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, interrupt_policy); + // 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, + InterruptPolicy& interrupt_policy) + { + boost::ignore_unused_variable_warning(interrupt_policy); + + // 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)); + + if (InterruptPolicy::enabled) + { + interrupt_policy.apply(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); +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..84ec16f23 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -0,0 +1,703 @@ +// 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_ix_ix(Indexed const& left, Indexed const& right + , std::string const& // header + ) const + { + // Take first intersection, then blocked. + if (left.subject.operation == operation_intersection + && right.subject.operation == operation_blocked) + { + return true; + } + else if (left.subject.operation == operation_blocked + && right.subject.operation == operation_intersection) + { + return false; + } + + // Default case, should not occur + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "ix/ix unhandled" << std::endl; +#endif + //debug_consider(0, left, right, header, false, "-> return", ret); + + return left.index < right.index; + } + + + 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].combination(operation_intersection, operation_blocked) + && m_turn_points[right.index].combination(operation_intersection, operation_blocked)) + { + return consider_ix_ix(left, right, "ix/ix"); + } + 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::endl; +#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 000000000..f0307eaf8 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -0,0 +1,646 @@ +// 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 PointOut> +struct intersection_segment_segment_point +{ + template + < + typename Segment1, typename Segment2, + typename OutputIterator, typename Strategy + > + 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 PointOut> +struct intersection_linestring_linestring_point +{ + template + < + typename Linestring1, typename Linestring2, + typename OutputIterator, typename Strategy + > + 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 +< + bool ReverseAreal, + typename LineStringOut, + overlay_type OverlayType +> +struct intersection_of_linestring_with_areal +{ +#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 + + template + < + typename LineString, typename Areal, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(LineString const& linestring, Areal const& areal, + OutputIterator out, + Strategy const& ) + { + if (boost::size(linestring) == 0) + { + return out; + } + + typedef detail::overlay::follow + < + LineStringOut, + LineString, + Areal, + OverlayType + > follower; + + 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 +< + // real types + typename Geometry1, typename Geometry2, + typename GeometryOut, + overlay_type OverlayType, + // orientation + bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, + bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, + // tag dispatching: + typename TagIn1 = typename geometry::tag<Geometry1>::type, + typename TagIn2 = typename geometry::tag<Geometry2>::type, + typename TagOut = typename geometry::tag<GeometryOut>::type, + // metafunction finetuning helpers: + bool Areal1 = geometry::is_areal<Geometry1>::value, + bool Areal2 = geometry::is_areal<Geometry2>::value, + bool ArealOut = geometry::is_areal<GeometryOut>::value +> +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 Geometry1, typename Geometry2, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename TagIn1, typename TagIn2, typename TagOut +> +struct intersection_insert + < + Geometry1, Geometry2, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + TagIn1, TagIn2, TagOut, + true, true, true + > : detail::overlay::overlay + <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType> +{}; + + +// Any areal type with box: +template +< + typename Geometry, typename Box, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename TagIn, typename TagOut +> +struct intersection_insert + < + Geometry, Box, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + TagIn, box_tag, TagOut, + true, true, true + > : detail::overlay::overlay + <Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType> +{}; + + +template +< + typename Segment1, typename Segment2, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Segment1, Segment2, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + segment_tag, segment_tag, point_tag, + false, false, false + > : detail::intersection::intersection_segment_segment_point<GeometryOut> +{}; + + +template +< + typename Linestring1, typename Linestring2, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Linestring1, Linestring2, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + linestring_tag, linestring_tag, point_tag, + false, false, false + > : detail::intersection::intersection_linestring_linestring_point<GeometryOut> +{}; + + +template +< + typename Linestring, typename Box, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Linestring, Box, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + linestring_tag, box_tag, linestring_tag, + false, true, false + > +{ + template <typename OutputIterator, typename 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, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseLinestring, bool ReversePolygon, bool ReverseOut +> +struct intersection_insert + < + Linestring, Polygon, + GeometryOut, + OverlayType, + ReverseLinestring, ReversePolygon, ReverseOut, + linestring_tag, polygon_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_linestring_with_areal + < + ReversePolygon, + GeometryOut, + OverlayType + > +{}; + + +template +< + typename Linestring, typename Ring, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseLinestring, bool ReverseRing, bool ReverseOut +> +struct intersection_insert + < + Linestring, Ring, + GeometryOut, + OverlayType, + ReverseLinestring, ReverseRing, ReverseOut, + linestring_tag, ring_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_linestring_with_areal + < + ReverseRing, + GeometryOut, + OverlayType + > +{}; + +template +< + typename Segment, typename Box, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Segment, Box, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + segment_tag, box_tag, linestring_tag, + false, true, false + > +{ + template <typename OutputIterator, typename 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 Geometry1, typename Geometry2, + typename PointOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename Tag1, typename Tag2, + bool Areal1, bool Areal2 +> +struct intersection_insert + < + Geometry1, Geometry2, + PointOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + Tag1, Tag2, point_tag, + Areal1, Areal2, false + > +{ + template <typename OutputIterator, typename 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 Geometry1, typename Geometry2, typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert_reversed +{ + template <typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Geometry1 const& g1, + Geometry2 const& g2, OutputIterator out, + Strategy const& strategy) + { + return intersection_insert + < + Geometry2, Geometry1, GeometryOut, + OverlayType, + Reverse2, Reverse1, ReverseOut + >::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 + < + Geometry1, Geometry2, + GeometryOut, + OverlayType, + 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 + >, + geometry::dispatch::intersection_insert + < + Geometry1, Geometry2, + GeometryOut, + OverlayType, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value + > + >::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 000000000..af9a8d991 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -0,0 +1,312 @@ +// 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; + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + // 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; + } + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + + 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 GeometryOut, + overlay_type Direction +> +struct overlay +{ + template <typename OutputIterator, typename Strategy> + 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<GeometryOut>::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 000000000..af62131f0 --- /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 000000000..a6088694d --- /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 000000000..007113ffb --- /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 000000000..f664b1951 --- /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 000000000..9c4c99394 --- /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 000000000..eebe38194 --- /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 000000000..810a27af0 --- /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 000000000..72665922b --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -0,0 +1,410 @@ +// 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/algorithms/num_points.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/closure.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, const char*) +{ +} +#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_value<Rings>::type ring_type; + 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 const min_num_points + = core_detail::closure::minimum_ring_size + < + geometry::closure<ring_type>::value + >::value; + + 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); + + ring_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); + } + else + { + 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"); + if (geometry::num_points(current_output) >= min_num_points) + { + 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 000000000..89a60b21a --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/turn_info.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_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, + operation_opposite +}; + + +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 has(operation_type type) const + { + return this->operations[0].operation == type + || this->operations[1].operation == 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 opposite() const + { + return both(operation_opposite); + } + inline bool any_blocked() const + { + return has(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 000000000..6be63f42b --- /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 000000000..45ff52ccb --- /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, std::size_t min_elements, + Policy& policy, VisitBoxPolicy& box_policy) + { + if (boost::size(input) > 0) + { + if (std::size_t(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, + std::size_t 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, std::size_t min_elements, + Policy& policy, VisitBoxPolicy& box_policy) + { + if (boost::size(input1) > 0 && boost::size(input2) > 0) + { + if (std::size_t(boost::size(input1)) > min_elements + && std::size_t(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, + std::size_t 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, + std::size_t min_elements = 16, + VisitBoxPolicy box_visitor = visit_no_policy() + ) + { + if (std::size_t(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, + std::size_t min_elements = 16, + VisitBoxPolicy box_visitor = visit_no_policy() + ) + { + if (std::size_t(boost::size(collection1)) > min_elements + && std::size_t(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 000000000..b7e15ba3f --- /dev/null +++ b/boost/geometry/algorithms/detail/point_on_border.hpp @@ -0,0 +1,246 @@ +// 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/convert_point_to_point.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 +{ + template <typename InputPoint> + static inline bool apply(Point& p, InputPoint const& p1, InputPoint 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> +{ + template <typename InputPoint> + static inline bool apply(Point& , InputPoint const& , InputPoint 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) + { + geometry::detail::conversion::convert_point_to_point(*boost::begin(range), point); + 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 000000000..9209ee030 --- /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 000000000..ad62f232b --- /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 000000000..2ec63aa42 --- /dev/null +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -0,0 +1,672 @@ +// 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 (int(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++; + } +} + +template <typename Sections> +inline void enlargeSections(Sections& sections) +{ + // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border) + // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1") + // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large, + // which might cause (a small number) of more comparisons + // TODO: make dimension-agnostic + for (typename boost::range_iterator<Sections>::type it = boost::begin(sections); + it != boost::end(sections); + ++it) + { + typedef typename boost::range_value<Sections>::type section_type; + typedef typename section_type::box_type box_type; + typedef typename geometry::coordinate_type<box_type>::type coordinate_type; + coordinate_type const reps = math::relaxed_epsilon(10.0); + geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps); + geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps); + geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps); + geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps); + } +} + + +}} // 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); + detail::sectionalize::enlargeSections(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 000000000..62328a0d8 --- /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 000000000..2f32b344c --- /dev/null +++ b/boost/geometry/algorithms/difference.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_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 + < + Geometry1, Geometry2, + GeometryOut, + overlay_difference, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value + >::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 000000000..ade4e57d5 --- /dev/null +++ b/boost/geometry/algorithms/disjoint.hpp @@ -0,0 +1,296 @@ +// 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/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + +template<typename Geometry> +struct check_each_ring_for_within +{ + bool has_within; + Geometry const& m_geometry; + + inline check_each_ring_for_within(Geometry const& g) + : has_within(false) + , m_geometry(g) + {} + + template <typename Range> + inline void apply(Range const& range) + { + typename geometry::point_type<Range>::type p; + geometry::point_on_border(p, range); + if (geometry::within(p, m_geometry)) + { + has_within = true; + } + } +}; + +template <typename FirstGeometry, typename SecondGeometry> +inline bool rings_containing(FirstGeometry const& geometry1, + SecondGeometry const& geometry2) +{ + check_each_ring_for_within<FirstGeometry> checker(geometry1); + geometry::detail::for_each_range(geometry2, checker); + return checker.has_within; +} + + +struct assign_disjoint_policy +{ + // We want to include all points: + static bool const include_no_turn = true; + static bool const include_degenerate = true; + static bool const include_opposite = true; + + // We don't assign extra info: + template + < + typename Info, + typename Point1, + typename Point2, + typename IntersectionInfo, + typename DirInfo + > + static inline void apply(Info& , Point1 const& , Point2 const&, + IntersectionInfo const&, DirInfo 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; + } + + // If there is no intersection of segments, they might located + // inside each other + if (rings_containing(geometry1, geometry2) + || rings_containing(geometry2, geometry1)) + { + return false; + } + + return true; + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry1, typename Geometry2, + std::size_t DimensionCount = dimension<Geometry1>::type::value, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct disjoint + : detail::disjoint::general_areal<Geometry1, Geometry2> +{}; + + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, + std::size_t DimensionCount, + typename Tag1, typename Tag2 +> +struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true> + : disjoint<Geometry2, Geometry1, DimensionCount, Tag2, Tag1, false> +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + return disjoint + < + Geometry2, Geometry1, + DimensionCount, + Tag2, Tag1 + >::apply(g2, g1); + } +}; + + +template <typename Point1, typename Point2, std::size_t DimensionCount, bool Reverse> +struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, Reverse> + : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount> +{}; + + +template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse> +struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, Reverse> + : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount> +{}; + + +template <typename Point, typename Box, std::size_t DimensionCount, bool Reverse> +struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, Reverse> + : detail::disjoint::point_box<Point, Box, 0, DimensionCount> +{}; + +template <typename Point, typename Ring, std::size_t DimensionCount, bool Reverse> +struct disjoint<Point, Ring, DimensionCount, point_tag, ring_tag, Reverse> + : detail::disjoint::reverse_covered_by<Point, Ring> +{}; + +template <typename Point, typename Polygon, std::size_t DimensionCount, bool Reverse> +struct disjoint<Point, Polygon, DimensionCount, point_tag, polygon_tag, Reverse> + : detail::disjoint::reverse_covered_by<Point, Polygon> +{}; + +template <typename Linestring1, typename Linestring2, bool Reverse> +struct disjoint<Linestring1, Linestring2, 2, linestring_tag, linestring_tag, Reverse> + : detail::disjoint::disjoint_linear<Linestring1, Linestring2> +{}; + +template <typename Linestring1, typename Linestring2, bool Reverse> +struct disjoint<Linestring1, Linestring2, 2, segment_tag, segment_tag, Reverse> + : detail::disjoint::disjoint_segment<Linestring1, Linestring2> +{}; + +template <typename Linestring, typename Segment, bool Reverse> +struct disjoint<Linestring, Segment, 2, linestring_tag, segment_tag, Reverse> + : detail::disjoint::disjoint_linear<Linestring, Segment> +{}; + + +} // 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 dispatch::disjoint<Geometry1, Geometry2>::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 000000000..0fd5c43f4 --- /dev/null +++ b/boost/geometry/algorithms/distance.hpp @@ -0,0 +1,596 @@ +// 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/concept_check.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) + { + boost::ignore_unused_variable_warning(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 = eps_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, + typename cs_tag<Point>::type, + typename cs_tag<typename point_type<Linestring>::type>::type, + Strategy + >::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 000000000..ee88fe888 --- /dev/null +++ b/boost/geometry/algorithms/envelope.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_ENVELOPE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_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/algorithms/not_implemented.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 +struct envelope_expand_one +{ + template<typename Geometry, typename Box> + 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 +struct envelope_range +{ + /// Calculate envelope of range using a strategy + template <typename Range, typename Box> + 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 +{ + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct envelope: not_implemented<Tag> +{}; + + +template <typename Point> +struct envelope<Point, point_tag> + : detail::envelope::envelope_expand_one +{}; + + +template <typename Box> +struct envelope<Box, box_tag> + : detail::envelope::envelope_expand_one +{}; + + +template <typename Segment> +struct envelope<Segment, segment_tag> + : detail::envelope::envelope_expand_one +{}; + + +template <typename Linestring> +struct envelope<Linestring, linestring_tag> + : detail::envelope::envelope_range +{}; + + +template <typename Ring> +struct envelope<Ring, ring_tag> + : detail::envelope::envelope_range +{}; + + +template <typename Polygon> +struct envelope<Polygon, polygon_tag> + : detail::envelope::envelope_range +{ + template <typename Box> + static inline void apply(Polygon const& poly, Box& mbr) + { + // For polygon, inspecting outer ring is sufficient + detail::envelope::envelope_range::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<Geometry>::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<Geometry>::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 000000000..60175d456 --- /dev/null +++ b/boost/geometry/algorithms/equals.hpp @@ -0,0 +1,382 @@ +// 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/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> +#include <boost/geometry/algorithms/not_implemented.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> + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace equals +{ + + +template +< + std::size_t Dimension, + std::size_t DimensionCount +> +struct box_box +{ + template <typename Box1, typename Box2> + 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<Dimension + 1, DimensionCount>::apply(box1, box2); + } +}; + +template <std::size_t DimensionCount> +struct box_box<DimensionCount, DimensionCount> +{ + template <typename Box1, typename Box2> + 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 TrivialCheck> +struct equals_by_collection +{ + template <typename Geometry1, typename Geometry2> + 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 Geometry1, + typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type, + std::size_t DimensionCount = dimension<Geometry1>::type::value, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct equals: not_implemented<Tag1, Tag2> +{}; + + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, + typename Tag1, typename Tag2, + std::size_t DimensionCount +> +struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true> + : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false> +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + return equals + < + Geometry2, Geometry1, + Tag2, Tag1, + DimensionCount, + false + >::apply(g2, g1); + } +}; + + +template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse> +struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse> + : geometry::detail::not_ + < + P1, + P2, + detail::disjoint::point_point<P1, P2, 0, DimensionCount> + > +{}; + + +template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse> +struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse> + : detail::equals::box_box<0, DimensionCount> +{}; + + +template <typename Ring1, typename Ring2, bool Reverse> +struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename Polygon1, typename Polygon2, bool Reverse> +struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename LineString1, typename LineString2, bool Reverse> +struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::length_check> +{}; + + +template <typename Polygon, typename Ring, bool Reverse> +struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename Ring, typename Box, bool Reverse> +struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename Polygon, typename Box, bool Reverse> +struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename Geometry1, typename Geometry2> +struct devarianted_equals +{ + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2) + { + concept::check_concepts_and_equal_dimensions + < + Geometry1 const, + Geometry2 const + >(); + return equals<Geometry1, Geometry2>::apply(geometry1, geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct devarianted_equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + struct visitor: static_visitor<bool> + { + Geometry2 const& m_geometry2; + + visitor(Geometry2 const& geometry2) + : m_geometry2(geometry2) + {} + + template <typename Geometry1> + inline bool operator()(Geometry1 const& geometry1) const + { + return devarianted_equals<Geometry1, Geometry2> + ::apply(geometry1, m_geometry2); + } + + }; + + static inline bool apply( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2 + ) + { + return apply_visitor(visitor(geometry2), geometry1); + } +}; + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: static_visitor<bool> + { + Geometry1 const& m_geometry1; + + visitor(Geometry1 const& geometry1) + : m_geometry1(geometry1) + {} + + template <typename Geometry2> + inline bool operator()(Geometry2 const& geometry2) const + { + return devarianted_equals<Geometry1, Geometry2> + ::apply(m_geometry1, geometry2); + } + + }; + + static inline bool apply( + Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2 + ) + { + return apply_visitor(visitor(geometry1), geometry2); + } +}; + +template < + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) +> +struct devarianted_equals< + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> +> +{ + struct visitor: static_visitor<bool> + { + template <typename Geometry1, typename Geometry2> + inline bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return devarianted_equals<Geometry1, Geometry2> + ::apply(geometry1, geometry2); + } + + }; + + static inline bool apply( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2 + ) + { + return apply_visitor(visitor(), geometry1, geometry2); + } +}; + + +} // 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 works 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) +{ + return dispatch::devarianted_equals<Geometry1, Geometry2> + ::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 000000000..2e1531bf0 --- /dev/null +++ b/boost/geometry/algorithms/expand.hpp @@ -0,0 +1,300 @@ +// 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/algorithms/not_implemented.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 StrategyLess, typename StrategyGreater, + std::size_t Dimension, std::size_t DimensionCount +> +struct point_loop +{ + template <typename Box, typename Point> + static inline void apply(Box& box, Point const& source) + { + 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; + + 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 + < + StrategyLess, StrategyGreater, + Dimension + 1, DimensionCount + >::apply(box, source); + } +}; + + +template +< + typename StrategyLess, typename StrategyGreater, + std::size_t DimensionCount +> +struct point_loop + < + StrategyLess, StrategyGreater, + DimensionCount, DimensionCount + > +{ + template <typename Box, typename Point> + static inline void apply(Box&, Point const&) {} +}; + + +template +< + typename StrategyLess, typename StrategyGreater, + std::size_t Index, + std::size_t Dimension, std::size_t DimensionCount +> +struct indexed_loop +{ + template <typename Box, typename Geometry> + static inline void apply(Box& box, Geometry const& source) + { + 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; + + 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 + < + StrategyLess, StrategyGreater, + Index, Dimension + 1, DimensionCount + >::apply(box, source); + } +}; + + +template +< + typename StrategyLess, typename StrategyGreater, + std::size_t Index, std::size_t DimensionCount +> +struct indexed_loop + < + StrategyLess, StrategyGreater, + Index, DimensionCount, DimensionCount + > +{ + template <typename Box, typename Geometry> + static inline void apply(Box&, Geometry const&) {} +}; + + + +// Changes a box such that the other box is also contained by the box +template +< + typename StrategyLess, typename StrategyGreater +> +struct expand_indexed +{ + template <typename Box, typename Geometry> + static inline void apply(Box& box, Geometry const& geometry) + { + indexed_loop + < + StrategyLess, StrategyGreater, + 0, 0, dimension<Geometry>::type::value + >::apply(box, geometry); + + indexed_loop + < + 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 GeometryOut, typename Geometry, + typename StrategyLess = strategy::compare::default_strategy, + typename StrategyGreater = strategy::compare::default_strategy, + typename TagOut = typename tag<GeometryOut>::type, + typename Tag = typename tag<Geometry>::type +> +struct expand: not_implemented<TagOut, Tag> +{}; + + +// Box + point -> new box containing also point +template +< + typename BoxOut, typename Point, + typename StrategyLess, typename StrategyGreater +> +struct expand<BoxOut, Point, StrategyLess, StrategyGreater, box_tag, point_tag> + : detail::expand::point_loop + < + 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<BoxOut, BoxIn, StrategyLess, StrategyGreater, box_tag, box_tag> + : detail::expand::expand_indexed<StrategyLess, StrategyGreater> +{}; + +template +< + typename Box, typename Segment, + typename StrategyLess, typename StrategyGreater +> +struct expand<Box, Segment, StrategyLess, StrategyGreater, box_tag, segment_tag> + : detail::expand::expand_indexed<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<Box, Geometry>::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<Box, Geometry>::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 000000000..24d38d3d8 --- /dev/null +++ b/boost/geometry/algorithms/for_each.hpp @@ -0,0 +1,271 @@ +// 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/type_traits/is_const.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/not_implemented.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 +{ + + +struct fe_point_per_point +{ + template <typename Point, typename Functor> + static inline void apply(Point& point, Functor& f) + { + f(point); + } +}; + + +struct fe_point_per_segment +{ + template <typename Point, typename Functor> + static inline void apply(Point& , Functor& f) + { + // TODO: if non-const, we should extract the points from the segment + // and call the functor on those two points + } +}; + + +struct fe_range_per_point +{ + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) + { + // The previous implementation called the std library: + // return (std::for_each(boost::begin(range), boost::end(range), f)); + // But that is not accepted for capturing lambda's. + // It needs to do it like that to return the state of Functor f (f is passed by value in std::for_each). + + // So we now loop manually. + + for (typename boost::range_iterator<Range>::type it = boost::begin(range); it != boost::end(range); ++it) + { + f(*it); + } + } +}; + + +struct fe_range_per_segment +{ + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) + { + typedef typename add_const_if_c + < + is_const<Range>::value, + 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++; + } + } +}; + + +struct fe_polygon_per_point +{ + template <typename Polygon, typename Functor> + static inline void apply(Polygon& poly, Functor& f) + { + fe_range_per_point::apply(exterior_ring(poly), f); + + typename interior_return_type<Polygon>::type rings + = interior_rings(poly); + for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + { + fe_range_per_point::apply(*it, f); + } + } + +}; + + +struct fe_polygon_per_segment +{ + template <typename Polygon, typename Functor> + static inline void apply(Polygon& poly, Functor& f) + { + fe_range_per_segment::apply(exterior_ring(poly), f); + + typename interior_return_type<Polygon>::type rings + = interior_rings(poly); + for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + { + fe_range_per_segment::apply(*it, f); + } + } + +}; + + +}} // namespace detail::for_each +#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 for_each_point: not_implemented<Tag> +{}; + + +template <typename Point> +struct for_each_point<Point, point_tag> + : detail::for_each::fe_point_per_point +{}; + + +template <typename Linestring> +struct for_each_point<Linestring, linestring_tag> + : detail::for_each::fe_range_per_point +{}; + + +template <typename Ring> +struct for_each_point<Ring, ring_tag> + : detail::for_each::fe_range_per_point +{}; + + +template <typename Polygon> +struct for_each_point<Polygon, polygon_tag> + : detail::for_each::fe_polygon_per_point +{}; + + +template +< + typename Geometry, + typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type +> +struct for_each_segment: not_implemented<Tag> +{}; + +template <typename Point> +struct for_each_segment<Point, point_tag> + : detail::for_each::fe_point_per_segment +{}; + + +template <typename Linestring> +struct for_each_segment<Linestring, linestring_tag> + : detail::for_each::fe_range_per_segment +{}; + + +template <typename Ring> +struct for_each_segment<Ring, ring_tag> + : detail::for_each::fe_range_per_segment +{}; + + +template <typename Polygon> +struct for_each_segment<Polygon, polygon_tag> + : detail::for_each::fe_polygon_per_segment +{}; + + +} // 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{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]} +\qbk{[for_each_point_const] [for_each_point_const_output]} +*/ +template<typename Geometry, typename Functor> +inline Functor for_each_point(Geometry& geometry, Functor f) +{ + concept::check<Geometry>(); + + dispatch::for_each_point<Geometry>::apply(geometry, f); + return 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]} +\qbk{[heading Example]} +\qbk{[for_each_segment_const] [for_each_segment_const_output]} +*/ +template<typename Geometry, typename Functor> +inline Functor for_each_segment(Geometry& geometry, Functor f) +{ + concept::check<Geometry>(); + + dispatch::for_each_segment<Geometry>::apply(geometry, f); + return 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 000000000..3125752db --- /dev/null +++ b/boost/geometry/algorithms/intersection.hpp @@ -0,0 +1,208 @@ +// 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 <std::size_t Dimension, std::size_t DimensionCount> +struct intersection_box_box +{ + template + < + typename Box1, typename Box2, typename BoxOut, + typename Strategy + > + 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<Dimension + 1, DimensionCount> + ::apply(box1, box2, box_out, strategy); + } +}; + +template <std::size_t DimensionCount> +struct intersection_box_box<DimensionCount, DimensionCount> +{ + template + < + typename Box1, typename Box2, typename BoxOut, + typename Strategy + > + 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 Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct intersection +{ + template <typename GeometryOut, typename Strategy> + 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 + < + Geometry1, Geometry2, OneOut, + overlay_intersection + >::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy); + + return true; + } + +}; + + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, + typename Tag1, typename Tag2 +> +struct intersection +< + Geometry1, Geometry2, + Tag1, Tag2, + true +> + : intersection<Geometry2, Geometry1, Tag2, Tag1, false> +{ + template <typename GeometryOut, typename Strategy> + static inline bool apply( + Geometry1 const& g1, + Geometry2 const& g2, + GeometryOut& out, + Strategy const& strategy) + { + return intersection< + Geometry2, Geometry1, + Tag2, Tag1, + false + >::apply(g2, g1, out, strategy); + } +}; + + +template +< + typename Box1, typename Box2, bool Reverse +> +struct intersection + < + Box1, Box2, + box_tag, box_tag, + Reverse + > : public detail::intersection::intersection_box_box + < + 0, geometry::dimension<Box1>::value + > +{}; + + +} // 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 dispatch::intersection< + Geometry1, + Geometry2 + >::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 000000000..f367f2e25 --- /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 000000000..2051e41a9 --- /dev/null +++ b/boost/geometry/algorithms/length.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_LENGTH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP + +#include <iterator> + +#include <boost/concept_check.hpp> +#include <boost/range.hpp> + +#include <boost/mpl/fold.hpp> +#include <boost/mpl/greater.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/insert.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/set.hpp> +#include <boost/mpl/size.hpp> +#include <boost/mpl/transform.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> + +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace length +{ + + +template<typename Segment> +struct segment_length +{ + template <typename Strategy> + 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, closure_selector Closure> +struct range_length +{ + typedef typename default_length_result<Range>::type return_type; + + template <typename Strategy> + static inline return_type apply( + Range const& range, Strategy const& strategy) + { + boost::ignore_unused_variable_warning(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 Geometry, typename Tag = typename tag<Geometry>::type> +struct length : detail::calculate_null +{ + typedef typename default_length_result<Geometry>::type return_type; + + template <typename Strategy> + static inline return_type apply(Geometry const& geometry, Strategy const& strategy) + { + return calculate_null::apply<return_type>(geometry, strategy); + } +}; + + +template <typename Geometry> +struct length<Geometry, linestring_tag> + : detail::length::range_length<Geometry, closed> +{}; + + +// RING: length is currently 0; it might be argued that it is the "perimeter" + + +template <typename Geometry> +struct length<Geometry, segment_tag> + : detail::length::segment_length<Geometry> +{}; + + +template <typename Geometry> +struct devarianted_length +{ + typedef typename default_length_result<Geometry>::type result_type; + + template <typename Strategy> + static inline result_type apply(Geometry const& geometry, + Strategy const& strategy) + { + return length<Geometry>::apply(geometry, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_length<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + typedef typename mpl::fold< + typename mpl::transform< + typename variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + default_length_result<mpl::_> + >::type, + mpl::set0<>, + mpl::insert<mpl::_1, mpl::_2> + >::type possible_result_types; + + typedef typename mpl::if_< + mpl::greater< + mpl::size<possible_result_types>, + mpl::int_<1> + >, + typename make_variant_over<possible_result_types>::type, + typename mpl::front<possible_result_types>::type + >::type result_type; + + template <typename Strategy> + struct visitor + : static_visitor<result_type> + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + + template <typename Geometry> + inline typename devarianted_length<Geometry>::result_type + operator()(Geometry const& geometry) const + { + return devarianted_length<Geometry>::apply(geometry, m_strategy); + } + }; + + template <typename Strategy> + static inline result_type apply( + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Strategy const& strategy + ) + { + return apply_visitor(visitor<Strategy>(strategy), geometry); + } +}; + + +} // 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 dispatch::devarianted_length<Geometry>::result_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::devarianted_length<Geometry>::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 dispatch::devarianted_length<Geometry>::result_type +length(Geometry const& geometry, Strategy const& strategy) +{ + concept::check<Geometry const>(); + + // detail::throw_on_empty_input(geometry); + + return dispatch::devarianted_length<Geometry>::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 000000000..d0e309249 --- /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 000000000..008f111cc --- /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 000000000..58afe4b97 --- /dev/null +++ b/boost/geometry/algorithms/num_geometries.hpp @@ -0,0 +1,89 @@ +// 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/geometry/algorithms/not_implemented.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 Geometry, + typename Tag = typename tag_cast + < + typename tag<Geometry>::type, + single_tag, + multi_tag + >::type +> +struct num_geometries: not_implemented<Tag> +{}; + + +template <typename Geometry> +struct num_geometries<Geometry, single_tag> +{ + 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<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 000000000..e815f5981 --- /dev/null +++ b/boost/geometry/algorithms/num_interior_rings.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_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 Geometry, typename Tag = typename tag<Geometry>::type> +struct num_interior_rings +{ + static inline std::size_t apply(Geometry const& ) + { + return 0; + } +}; + + + +template <typename Polygon> +struct num_interior_rings<Polygon, polygon_tag> +{ + 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<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 000000000..923ae8297 --- /dev/null +++ b/boost/geometry/algorithms/num_points.hpp @@ -0,0 +1,212 @@ +// 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/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/algorithms/not_implemented.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace num_points +{ + + +struct range_count +{ + template <typename Range> + 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) + { + if (geometry::closure<Range>::value == open) + { + if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1))) + { + return n + 1; + } + } + } + return n; + } +}; + +template <std::size_t D> +struct other_count +{ + template <typename Geometry> + static inline std::size_t apply(Geometry const&, bool) + { + return D; + } +}; + +struct polygon_count: private range_count +{ + template <typename Polygon> + 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::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::apply(*it, add_for_open); + } + + return n; + } +}; + +}} // namespace detail::num_points +#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 num_points: not_implemented<Tag> +{}; + +template <typename Geometry> +struct num_points<Geometry, point_tag> + : detail::num_points::other_count<1> +{}; + +template <typename Geometry> +struct num_points<Geometry, box_tag> + : detail::num_points::other_count<4> +{}; + +template <typename Geometry> +struct num_points<Geometry, segment_tag> + : detail::num_points::other_count<2> +{}; + +template <typename Geometry> +struct num_points<Geometry, linestring_tag> + : detail::num_points::range_count +{}; + +template <typename Geometry> +struct num_points<Geometry, ring_tag> + : detail::num_points::range_count +{}; + +template <typename Geometry> +struct num_points<Geometry, polygon_tag> + : detail::num_points::polygon_count +{}; + +template <typename Geometry> +struct devarianted_num_points +{ + static inline std::size_t apply(Geometry const& geometry, + bool add_for_open) + { + return num_points<Geometry>::apply(geometry, add_for_open); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<std::size_t> + { + bool m_add_for_open; + + visitor(bool add_for_open): m_add_for_open(add_for_open) {} + + template <typename Geometry> + typename std::size_t operator()(Geometry const& geometry) const + { + return dispatch::num_points<Geometry>::apply(geometry, m_add_for_open); + } + }; + + static inline std::size_t + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + bool add_for_open) + { + return boost::apply_visitor(visitor(add_for_open), 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::devarianted_num_points<Geometry>::apply(geometry, add_for_open); +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..d417a4b1f --- /dev/null +++ b/boost/geometry/algorithms/overlaps.hpp @@ -0,0 +1,184 @@ +// 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/geometry/core/access.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlaps +{ + +template +< + std::size_t Dimension, + std::size_t DimensionCount +> +struct box_box_loop +{ + template <typename Box1, typename Box2> + 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 + < + Dimension + 1, + DimensionCount + >::apply(b1, b2, overlaps, one_in_two, two_in_one); + } +}; + +template +< + std::size_t DimensionCount +> +struct box_box_loop<DimensionCount, DimensionCount> +{ + template <typename Box1, typename Box2> + static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&) + { + } +}; + +struct box_box +{ + template <typename Box1, typename Box2> + static inline bool apply(Box1 const& b1, Box2 const& b2) + { + bool overlaps = true; + bool within1 = true; + bool within2 = true; + box_box_loop + < + 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 Geometry1, + typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type +> +struct overlaps: not_implemented<Tag1, Tag2> +{}; + + +template <typename Box1, typename Box2> +struct overlaps<Box1, Box2, box_tag, box_tag> + : detail::overlaps::box_box +{}; + + + + +} // 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 + < + 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 000000000..b70517e3e --- /dev/null +++ b/boost/geometry/algorithms/perimeter.hpp @@ -0,0 +1,137 @@ +// 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 Geometry, typename Tag = typename tag<Geometry>::type> +struct perimeter : detail::calculate_null +{ + typedef typename default_length_result<Geometry>::type return_type; + + template <typename Strategy> + static inline return_type apply(Geometry const& geometry, Strategy const& strategy) + { + return calculate_null::apply<return_type>(geometry, strategy); + } +}; + +template <typename Geometry> +struct perimeter<Geometry, ring_tag> + : detail::length::range_length + < + Geometry, + closure<Geometry>::value + > +{}; + +template <typename Polygon> +struct perimeter<Polygon, polygon_tag> : detail::calculate_polygon_sum +{ + typedef typename default_length_result<Polygon>::type return_type; + typedef detail::length::range_length + < + typename ring_type<Polygon>::type, + closure<Polygon>::value + > policy; + + template <typename Strategy> + static inline return_type apply(Polygon const& polygon, Strategy const& strategy) + { + return calculate_polygon_sum::apply<return_type, policy>(polygon, strategy); + } +}; + + +// 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<Geometry>::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<Geometry>::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 000000000..1e1168a5a --- /dev/null +++ b/boost/geometry/algorithms/reverse.hpp @@ -0,0 +1,125 @@ +// 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 +{ + + +struct range_reverse +{ + template <typename Range> + static inline void apply(Range& range) + { + std::reverse(boost::begin(range), boost::end(range)); + } +}; + + +struct polygon_reverse: private range_reverse +{ + template <typename Polygon> + static inline void apply(Polygon& polygon) + { + typedef typename geometry::ring_type<Polygon>::type ring_type; + + range_reverse::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) + { + range_reverse::apply(*it); + } + } +}; + + +}} // namespace detail::reverse +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct reverse +{ + static inline void apply(Geometry&) + {} +}; + + +template <typename Ring> +struct reverse<Ring, ring_tag> + : detail::reverse::range_reverse +{}; + + +template <typename LineString> +struct reverse<LineString, linestring_tag> + : detail::reverse::range_reverse +{}; + + +template <typename Polygon> +struct reverse<Polygon, polygon_tag> + : detail::reverse::polygon_reverse +{}; + + +} // 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<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 000000000..7e3aca401 --- /dev/null +++ b/boost/geometry/algorithms/simplify.hpp @@ -0,0 +1,371 @@ +// 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/not_implemented.hpp> +#include <boost/geometry/algorithms/num_interior_rings.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace simplify +{ + +struct simplify_range_insert +{ + template<typename Range, typename Strategy, 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); + } + } +}; + + +struct simplify_copy +{ + template <typename Range, typename Strategy, 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<std::size_t Minimum> +struct simplify_range +{ + template <typename Range, typename Strategy, 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::apply(range, out, max_distance, strategy); + } + else + { + simplify_range_insert::apply + ( + range, std::back_inserter(out), max_distance, strategy + ); + } + } +}; + +struct simplify_polygon +{ + template <typename Polygon, typename Strategy, 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<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<Minimum>::apply(*it_in, *it_out, max_distance, strategy); + } + } +}; + + +}} // namespace detail::simplify +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct simplify: not_implemented<Tag> +{}; + +template <typename Point> +struct simplify<Point, point_tag> +{ + template <typename Distance, typename Strategy> + static inline void apply(Point const& point, Point& out, + Distance const& , Strategy const& ) + { + geometry::convert(point, out); + } +}; + + +template <typename Linestring> +struct simplify<Linestring, linestring_tag> + : detail::simplify::simplify_range<2> +{}; + +template <typename Ring> +struct simplify<Ring, ring_tag> + : detail::simplify::simplify_range + < + core_detail::closure::minimum_ring_size + < + geometry::closure<Ring>::value + >::value + > +{}; + +template <typename Polygon> +struct simplify<Polygon, polygon_tag> + : detail::simplify::simplify_polygon +{}; + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct simplify_insert: not_implemented<Tag> +{}; + + +template <typename Linestring> +struct simplify_insert<Linestring, linestring_tag> + : detail::simplify::simplify_range_insert +{}; + +template <typename Ring> +struct simplify_insert<Ring, ring_tag> + : detail::simplify::simplify_range_insert +{}; + + +} // 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<Geometry>::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<Geometry>::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<Geometry>::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 000000000..28affc43c --- /dev/null +++ b/boost/geometry/algorithms/sym_difference.hpp @@ -0,0 +1,162 @@ +// 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 + < + Geometry1, Geometry2, + GeometryOut, + overlay_difference, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value + >::apply(geometry1, geometry2, out, strategy); + out = geometry::dispatch::intersection_insert + < + Geometry2, Geometry1, + GeometryOut, + overlay_difference, + 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 + >::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/touches.hpp b/boost/geometry/algorithms/touches.hpp new file mode 100644 index 000000000..7d424af42 --- /dev/null +++ b/boost/geometry/algorithms/touches.hpp @@ -0,0 +1,181 @@ +// 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_TOUCHES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP + + +#include <deque> + +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/num_geometries.hpp> + + +namespace boost { namespace geometry +{ + +namespace detail { namespace touches +{ + +template <typename Turn> +inline bool ok_for_touch(Turn const& turn) +{ + return turn.both(detail::overlay::operation_union) + || turn.both(detail::overlay::operation_blocked) + || turn.combination(detail::overlay::operation_union, detail::overlay::operation_blocked) + ; +} + +template <typename Turns> +inline bool has_only_turns(Turns const& turns) +{ + bool has_touch = false; + typedef typename boost::range_iterator<Turns const>::type iterator_type; + for (iterator_type it = boost::begin(turns); it != boost::end(turns); ++it) + { + if (it->has(detail::overlay::operation_intersection)) + { + return false; + } + + switch(it->method) + { + case detail::overlay::method_crosses: + return false; + case detail::overlay::method_equal: + // Segment spatially equal means: at the right side + // the polygon internally overlaps. So return false. + return false; + case detail::overlay::method_touch: + case detail::overlay::method_touch_interior: + case detail::overlay::method_collinear: + if (ok_for_touch(*it)) + { + has_touch = true; + } + else + { + return false; + } + break; + case detail::overlay::method_none : + case detail::overlay::method_disjoint : + case detail::overlay::method_error : + break; + } + } + return has_touch; +} + +}} + +/*! +\brief \brief_check{has at least one touching point (self-tangency)} +\note This function can be called for one geometry (self-tangency) and + also for two geometries (touch) +\ingroup touches +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\return \return_check{is self-touching} + +\qbk{distinguish,one geometry} +\qbk{[def __one_parameter__]} +\qbk{[include reference/algorithms/touches.qbk]} +*/ +template <typename Geometry> +inline bool touches(Geometry const& geometry) +{ + concept::check<Geometry const>(); + + typedef detail::overlay::turn_info + < + typename geometry::point_type<Geometry>::type + > turn_info; + + typedef detail::overlay::get_turn_info + < + typename point_type<Geometry>::type, + typename point_type<Geometry>::type, + turn_info, + detail::overlay::assign_null_policy + > policy_type; + + std::deque<turn_info> turns; + detail::self_get_turn_points::no_interrupt_policy policy; + detail::self_get_turn_points::get_turns + < + Geometry, + std::deque<turn_info>, + policy_type, + detail::self_get_turn_points::no_interrupt_policy + >::apply(geometry, turns, policy); + + return detail::touches::has_only_turns(turns); +} + + +/*! +\brief \brief_check2{have at least one touching point (tangent - non overlapping)} +\ingroup touches +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\return \return_check2{touch each other} + +\qbk{distinguish,two geometries} +\qbk{[include reference/algorithms/touches.qbk]} + */ +template <typename Geometry1, typename Geometry2> +inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + + typedef detail::overlay::turn_info + < + typename geometry::point_type<Geometry1>::type + > turn_info; + + typedef detail::overlay::get_turn_info + < + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type, + turn_info, + detail::overlay::assign_null_policy + > policy_type; + + std::deque<turn_info> turns; + detail::get_turns::no_interrupt_policy policy; + boost::geometry::get_turns + < + false, false, + detail::overlay::assign_null_policy + >(geometry1, geometry2, turns, policy); + + return detail::touches::has_only_turns(turns) + && ! geometry::detail::disjoint::rings_containing(geometry1, geometry2) + && ! geometry::detail::disjoint::rings_containing(geometry2, geometry1) + ; +} + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp new file mode 100644 index 000000000..52d195fe8 --- /dev/null +++ b/boost/geometry/algorithms/transform.hpp @@ -0,0 +1,339 @@ +// 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 +{ + +struct transform_point +{ + template <typename Point1, typename Point2, typename Strategy> + static inline bool apply(Point1 const& p1, Point2& p2, + Strategy const& strategy) + { + return strategy.apply(p1, p2); + } +}; + + +struct transform_box +{ + template <typename Box1, typename Box2, typename Strategy> + 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; + } +}; + +struct transform_box_or_segment +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + 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::apply(*it, point_out, strategy)) + { + return false; + } + *out++ = point_out; + } + return true; +} + + +struct transform_polygon +{ + template <typename Polygon1, typename Polygon2, typename Strategy> + 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; +}; + +struct transform_range +{ + template <typename Range1, typename Range2, typename Strategy> + 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 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 +> +struct transform {}; + +template <typename Point1, typename Point2> +struct transform<Point1, Point2, point_tag, point_tag> + : detail::transform::transform_point +{ +}; + + +template <typename Linestring1, typename Linestring2> +struct transform + < + Linestring1, Linestring2, + linestring_tag, linestring_tag + > + : detail::transform::transform_range +{ +}; + +template <typename Range1, typename Range2> +struct transform<Range1, Range2, ring_tag, ring_tag> + : detail::transform::transform_range +{ +}; + +template <typename Polygon1, typename Polygon2> +struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag> + : detail::transform::transform_polygon +{ +}; + +template <typename Box1, typename Box2> +struct transform<Box1, Box2, box_tag, box_tag> + : detail::transform::transform_box +{ +}; + +template <typename Segment1, typename Segment2> +struct transform<Segment1, Segment2, segment_tag, segment_tag> + : detail::transform::transform_box_or_segment +{ +}; + + +} // 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<Geometry1, Geometry2> 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 000000000..479f556a1 --- /dev/null +++ b/boost/geometry/algorithms/union.hpp @@ -0,0 +1,245 @@ +// 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/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/not_implemented.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, + typename TagIn1 = typename tag<Geometry1>::type, + typename TagIn2 = typename tag<Geometry2>::type, + typename TagOut = typename tag<GeometryOut>::type, + bool Areal1 = geometry::is_areal<Geometry1>::value, + bool Areal2 = geometry::is_areal<Geometry2>::value, + bool ArealOut = geometry::is_areal<GeometryOut>::value, + bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, + bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, + bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct union_insert: not_implemented<TagIn1, TagIn2, TagOut> +{}; + + +// If reversal is needed, perform it first + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, + typename TagIn1, typename TagIn2, typename TagOut, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct union_insert + < + Geometry1, Geometry2, GeometryOut, + TagIn1, TagIn2, TagOut, + true, true, true, + Reverse1, Reverse2, ReverseOut, + true + >: union_insert<Geometry2, Geometry1, GeometryOut> +{ + template <typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Geometry1 const& g1, + Geometry2 const& g2, OutputIterator out, + Strategy const& strategy) + { + return union_insert + < + Geometry2, Geometry1, GeometryOut + >::apply(g2, g1, out, strategy); + } +}; + + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, + typename TagIn1, typename TagIn2, typename TagOut, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct union_insert + < + Geometry1, Geometry2, GeometryOut, + TagIn1, TagIn2, TagOut, + true, true, true, + Reverse1, Reverse2, ReverseOut, + false + > : detail::overlay::overlay + <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, overlay_union> +{}; + + +} // 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 dispatch::union_insert + < + Geometry1, Geometry2, GeometryOut + >::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 000000000..e11dc13c4 --- /dev/null +++ b/boost/geometry/algorithms/unique.hpp @@ -0,0 +1,147 @@ +// 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 +{ + + +struct range_unique +{ + template <typename Range, typename ComparePolicy> + 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)); + } +}; + + +struct polygon_unique +{ + template <typename Polygon, typename ComparePolicy> + static inline void apply(Polygon& polygon, ComparePolicy const& policy) + { + typedef typename geometry::ring_type<Polygon>::type ring_type; + + range_unique::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) + { + range_unique::apply(*it, policy); + } + } +}; + + + +}} // namespace detail::unique +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct unique +{ + template <typename ComparePolicy> + static inline void apply(Geometry&, ComparePolicy const& ) + {} +}; + + +template <typename Ring> +struct unique<Ring, ring_tag> + : detail::unique::range_unique +{}; + + +template <typename LineString> +struct unique<LineString, linestring_tag> + : detail::unique::range_unique +{}; + + +template <typename Polygon> +struct unique<Polygon, polygon_tag> + : detail::unique::polygon_unique +{}; + + +} // 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<Geometry>::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 000000000..b024bd9fa --- /dev/null +++ b/boost/geometry/algorithms/within.hpp @@ -0,0 +1,348 @@ +// 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/concept_check.hpp> +#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) + { + boost::ignore_unused_variable_warning(strategy); + if (int(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) + { + boost::ignore_unused_variable_warning(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>(); + boost::ignore_unused_variable_warning(strategy); + 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 000000000..6479ecc4a --- /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 000000000..db3b86709 --- /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 000000000..13fe96877 --- /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 000000000..9ee33cd64 --- /dev/null +++ b/boost/geometry/core/access.hpp @@ -0,0 +1,398 @@ +// 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/concept_check.hpp> +#include <boost/type_traits/is_pointer.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/util/bare_type.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_DETAIL +namespace detail +{ + +template +< + typename Geometry, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access_non_pointer +{ + static inline CoordinateType get(Geometry const& geometry) + { + return traits::indexed_access<Geometry, Index, Dimension>::get(geometry); + } + static inline void set(Geometry& b, CoordinateType const& value) + { + traits::indexed_access<Geometry, Index, Dimension>::set(b, value); + } +}; + +template +< + typename Geometry, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access_pointer +{ + static inline CoordinateType get(Geometry const* geometry) + { + return traits::indexed_access<typename boost::remove_pointer<Geometry>::type, Index, Dimension>::get(*geometry); + } + static inline void set(Geometry* geometry, CoordinateType const& value) + { + traits::indexed_access<typename boost::remove_pointer<Geometry>::type, Index, Dimension>::set(*geometry, value); + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template +< + typename Tag, + typename Geometry, + typename + CoordinateType, + std::size_t Dimension, + typename IsPointer +> +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, + typename IsPointer +> +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, boost::false_type> +{ + 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 Point, typename CoordinateType, std::size_t Dimension> +struct access<point_tag, Point, CoordinateType, Dimension, boost::true_type> +{ + static inline CoordinateType get(Point const* point) + { + return traits::access<typename boost::remove_pointer<Point>::type, Dimension>::get(*point); + } + static inline void set(Point* p, CoordinateType const& value) + { + traits::access<typename boost::remove_pointer<Point>::type, 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, boost::false_type> + : detail::indexed_access_non_pointer<Box, CoordinateType, Index, Dimension> +{}; + +template +< + typename Box, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access<box_tag, Box, CoordinateType, Index, Dimension, boost::true_type> + : detail::indexed_access_pointer<Box, CoordinateType, Index, Dimension> +{}; + + +template +< + typename Segment, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access<segment_tag, Segment, CoordinateType, Index, Dimension, boost::false_type> + : detail::indexed_access_non_pointer<Segment, CoordinateType, Index, Dimension> +{}; + + +template +< + typename Segment, + typename CoordinateType, + std::size_t Index, + std::size_t Dimension +> +struct indexed_access<segment_tag, Segment, CoordinateType, Index, Dimension, boost::true_type> + : detail::indexed_access_pointer<Segment, CoordinateType, Index, Dimension> +{}; + +} // 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) +\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 +#ifndef DOXYGEN_SHOULD_SKIP_THIS + , detail::signature_getset_dimension* dummy = 0 +#endif + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef core_dispatch::access + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type, + typename coordinate_type<Geometry>::type, + Dimension, + typename boost::is_pointer<Geometry>::type + > 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 +\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 +#ifndef DOXYGEN_SHOULD_SKIP_THIS + , detail::signature_getset_dimension* dummy = 0 +#endif + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef core_dispatch::access + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type, + typename coordinate_type<Geometry>::type, + Dimension, + typename boost::is_pointer<Geometry>::type + > 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 +\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 +#ifndef DOXYGEN_SHOULD_SKIP_THIS + , detail::signature_getset_index_dimension* dummy = 0 +#endif + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef core_dispatch::indexed_access + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type, + typename coordinate_type<Geometry>::type, + Index, + Dimension, + typename boost::is_pointer<Geometry>::type + > 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 +\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 +#ifndef DOXYGEN_SHOULD_SKIP_THIS + , detail::signature_getset_index_dimension* dummy = 0 +#endif + ) +{ + boost::ignore_unused_variable_warning(dummy); + + typedef core_dispatch::indexed_access + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type, + typename coordinate_type<Geometry>::type, + Index, + Dimension, + typename boost::is_pointer<Geometry>::type + > 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 000000000..aab02e787 --- /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 000000000..15df129de --- /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/geometry/core/point_type.hpp> +#include <boost/geometry/util/bare_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<typename geometry::util::bare_type<P>::type> {}; + +} // 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 geometry::util::bare_type<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 000000000..d33353f4b --- /dev/null +++ b/boost/geometry/core/coordinate_system.hpp @@ -0,0 +1,100 @@ +// 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/geometry/core/point_type.hpp> +#include <boost/geometry/util/bare_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 Point> + struct coordinate_system<point_tag, Point> + { + typedef typename traits::coordinate_system + < + typename geometry::util::bare_type<Point>::type + >::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 core_dispatch::coordinate_system + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type + >::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 000000000..f138d59c8 --- /dev/null +++ b/boost/geometry/core/coordinate_type.hpp @@ -0,0 +1,108 @@ +// 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/geometry/core/tag.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/util/bare_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 + < + typename geometry::util::bare_type<Point>::type + >::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 geometry::util::bare_type<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 000000000..3588ed1a8 --- /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 000000000..97d249e93 --- /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 000000000..e5c97dd30 --- /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 Polygon 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 000000000..369c5cfa1 --- /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 000000000..10af2ae4e --- /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 000000000..02328372f --- /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 000000000..5ddfa753b --- /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 000000000..9b53e4057 --- /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 000000000..f09086a9d --- /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 000000000..e148c84a5 --- /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> +#include <boost/geometry/util/bare_type.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 core_dispatch::point_type + < + typename tag<Geometry>::type, + typename boost::geometry::util::bare_type<Geometry>::type + >::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 000000000..bac77d7bc --- /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 000000000..2e4fb8005 --- /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 000000000..9b984faf3 --- /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 000000000..1687085a7 --- /dev/null +++ b/boost/geometry/core/tag.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_CORE_TAG_HPP +#define BOOST_GEOMETRY_CORE_TAG_HPP + + +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/bare_type.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 geometry::util::bare_type<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 000000000..47a2e834f --- /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 000000000..9272858ed --- /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 000000000..02f1ed341 --- /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 000000000..275ccb5c2 --- /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 000000000..a9aba916a --- /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 000000000..fed2362b6 --- /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 000000000..87c3b6065 --- /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 000000000..c9c1bc7b6 --- /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 000000000..c2a6a44db --- /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 000000000..2aabb5663 --- /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 000000000..5703601e0 --- /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 000000000..93b21fee9 --- /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 000000000..825ef8061 --- /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 000000000..496dbeaec --- /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 000000000..990d60846 --- /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 000000000..3c8601fe1 --- /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 000000000..70189819c --- /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 000000000..5c9cdd6a8 --- /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 000000000..beb51fe0b --- /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 000000000..58065fe9a --- /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 000000000..1b4523d96 --- /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 000000000..e9200e0fd --- /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 000000000..a2e3d4fd7 --- /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 000000000..ea0d84cf3 --- /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 000000000..68cca9e98 --- /dev/null +++ b/boost/geometry/geometries/concepts/check.hpp @@ -0,0 +1,205 @@ +// 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> +#include <boost/geometry/geometries/concepts/segment_concept.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/variant/variant_fwd.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 Geometry, + typename GeometryTag = typename geometry::tag<Geometry>::type, + bool IsConst = boost::is_const<Geometry>::type::value +> +struct check : not_implemented<GeometryTag> +{}; + + +template <typename Geometry> +struct check<Geometry, point_tag, true> + : detail::concept_check::check<concept::ConstPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, point_tag, false> + : detail::concept_check::check<concept::Point<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, linestring_tag, true> + : detail::concept_check::check<concept::ConstLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, linestring_tag, false> + : detail::concept_check::check<concept::Linestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, ring_tag, true> + : detail::concept_check::check<concept::ConstRing<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, ring_tag, false> + : detail::concept_check::check<concept::Ring<Geometry> > +{}; + +template <typename Geometry> +struct check<Geometry, polygon_tag, true> + : detail::concept_check::check<concept::ConstPolygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, polygon_tag, false> + : detail::concept_check::check<concept::Polygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, box_tag, true> + : detail::concept_check::check<concept::ConstBox<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, box_tag, false> + : detail::concept_check::check<concept::Box<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, segment_tag, true> + : detail::concept_check::check<concept::ConstSegment<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, segment_tag, false> + : detail::concept_check::check<concept::Segment<Geometry> > +{}; + + +} // namespace dispatch +#endif + + + + +namespace concept +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename Geometry> +struct checker : dispatch::check<Geometry> +{}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct checker<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct checker<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const> +{}; + + +} +#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> 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 000000000..091336fe3 --- /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 000000000..1e1b31e61 --- /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 000000000..b478a2274 --- /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 000000000..02a36c96f --- /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 000000000..8d2d30015 --- /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 000000000..cda55c1d2 --- /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 000000000..38bc3d4c4 --- /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 000000000..b53114731 --- /dev/null +++ b/boost/geometry/geometries/point.hpp @@ -0,0 +1,188 @@ +// 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 +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + +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 + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..652930666 --- /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 000000000..ec8d1ec38 --- /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 000000000..838c2bb5f --- /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 000000000..b06439874 --- /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 000000000..676582576 --- /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 000000000..fb6cb6720 --- /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 000000000..6ea88c091 --- /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 000000000..998619785 --- /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 000000000..3f47f79ec --- /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/geometries/variant.hpp b/boost/geometry/geometries/variant.hpp new file mode 100644 index 000000000..9db11d5a8 --- /dev/null +++ b/boost/geometry/geometries/variant.hpp @@ -0,0 +1,34 @@ +// 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_VARIANT_GEOMETRY_HPP +#define BOOST_GEOMETRY_GEOMETRIES_VARIANT_GEOMETRY_HPP + + +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry { + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct point_type<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > + : point_type<T0> +{}; + + +} // namespace geometry +} // namespace boost + + +#endif // BOOST_GEOMETRY_GEOMETRIES_VARIANT_GEOMETRY_HPP diff --git a/boost/geometry/geometry.hpp b/boost/geometry/geometry.hpp new file mode 100644 index 000000000..dce17e260 --- /dev/null +++ b/boost/geometry/geometry.hpp @@ -0,0 +1,92 @@ +// 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/touches.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> +#include <boost/geometry/io/svg/svg_mapper.hpp> + +#endif // BOOST_GEOMETRY_GEOMETRY_HPP diff --git a/boost/geometry/index/adaptors/query.hpp b/boost/geometry/index/adaptors/query.hpp new file mode 100644 index 000000000..472b3693b --- /dev/null +++ b/boost/geometry/index/adaptors/query.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry Index +// +// Query range adaptor +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP +#define BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP + +/*! +\defgroup adaptors Adaptors (boost::geometry::index::adaptors::) +*/ + +namespace boost { namespace geometry { namespace index { + +namespace adaptors { + +namespace detail { + +template <typename Index> +class query_range +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEX, + (query_range)); + + typedef int* iterator; + typedef const int* const_iterator; + + template <typename Predicates> + inline query_range( + Index const&, + Predicates const&) + {} + + inline iterator begin() { return 0; } + inline iterator end() { return 0; } + inline const_iterator begin() const { return 0; } + inline const_iterator end() const { return 0; } +}; + +// TODO: awulkiew - consider removing reference from predicates + +template<typename Predicates> +struct query +{ + inline explicit query(Predicates const& pred) + : predicates(pred) + {} + + Predicates const& predicates; +}; + +template<typename Index, typename Predicates> +index::adaptors::detail::query_range<Index> +operator|( + Index const& si, + index::adaptors::detail::query<Predicates> const& f) +{ + return index::adaptors::detail::query_range<Index>(si, f.predicates); +} + +} // namespace detail + +/*! +\brief The query index adaptor generator. + +\ingroup adaptors + +\param pred Predicates. +*/ +template <typename Predicates> +detail::query<Predicates> +queried(Predicates const& pred) +{ + return detail::query<Predicates>(pred); +} + +} // namespace adaptors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP diff --git a/boost/geometry/index/detail/algorithms/bounds.hpp b/boost/geometry/index/detail/algorithms/bounds.hpp new file mode 100644 index 000000000..58c575d26 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/bounds.hpp @@ -0,0 +1,41 @@ +// Boost.Geometry Index +// +// n-dimensional bounds +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template <typename Geometry, + typename Bounds, + typename TagGeometry = typename geometry::tag<Geometry>::type, + typename TagBounds = typename geometry::tag<Bounds>::type> +struct bounds +{ + static inline void apply(Geometry const& g, Bounds & b) + { + geometry::convert(g, b); + } +}; + +} // namespace dispatch + +template <typename Geometry, typename Bounds> +inline void bounds(Geometry const& g, Bounds & b) +{ + concept::check_concepts_and_equal_dimensions<Geometry const, Bounds>(); + dispatch::bounds<Geometry, Bounds>::apply(g, b); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp new file mode 100644 index 000000000..841876eb3 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry Index +// +// squared distance between point and centroid of the box or point +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP + +#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp> +#include <boost/geometry/index/detail/algorithms/diff_abs.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +struct comparable_distance_centroid_tag {}; + +template < + typename Point, + typename PointIndexable, + size_t N> +struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_centroid_tag, N> +{ + typedef typename geometry::default_distance_result<Point, PointIndexable>::type result_type; + + inline static result_type apply(Point const& pt, PointIndexable const& i) + { + return geometry::comparable_distance(pt, i); + } +}; + +template < + typename Point, + typename BoxIndexable, + size_t DimensionIndex> +struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_centroid_tag, DimensionIndex> +{ + typedef typename geometry::default_distance_result<Point, BoxIndexable>::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename coordinate_type<Point>::type point_coord_t; + typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t; + + point_coord_t pt_c = geometry::get<DimensionIndex>(pt); + indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i); + indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i); + + indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2; + // TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe? + + result_type diff = detail::diff_abs(ind_c_avg, pt_c); + + return diff * diff; + } +}; + +template <typename Point, typename Indexable> +typename geometry::default_distance_result<Point, Indexable>::type +comparable_distance_centroid(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename tag<Indexable>::type, + detail::comparable_distance_centroid_tag, + dimension<Indexable>::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP + diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp new file mode 100644 index 000000000..07dfcfc0f --- /dev/null +++ b/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry Index +// +// squared distance between point and furthest point of the box or point +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP + +#include <boost/geometry/index/detail/algorithms/diff_abs.hpp> +#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +// minmaxdist component + +struct comparable_distance_far_tag {}; + +template < + typename Point, + typename BoxIndexable, + size_t DimensionIndex> +struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_far_tag, DimensionIndex> +{ + typedef typename geometry::default_distance_result<Point, BoxIndexable>::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename coordinate_type<Point>::type point_coord_t; + typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t; + + point_coord_t pt_c = geometry::get<DimensionIndex>(pt); + indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i); + indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i); + + result_type further_diff = 0; + + if ( (ind_c_min + ind_c_max) / 2 <= pt_c ) + further_diff = pt_c - ind_c_min; + else + further_diff = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection + + return further_diff * further_diff; + } +}; + +template <typename Point, typename Indexable> +typename geometry::default_distance_result<Point, Indexable>::type +comparable_distance_far(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename tag<Indexable>::type, + detail::comparable_distance_far_tag, + dimension<Indexable>::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp new file mode 100644 index 000000000..5584bf85e --- /dev/null +++ b/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry Index +// +// squared distance between point and nearest point of the box or point +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP + +#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +struct comparable_distance_near_tag {}; + +template < + typename Point, + typename PointIndexable, + size_t N> +struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_near_tag, N> +{ + typedef typename geometry::default_distance_result<Point, PointIndexable>::type result_type; + + inline static result_type apply(Point const& pt, PointIndexable const& i) + { + return geometry::comparable_distance(pt, i); + } +}; + +template < + typename Point, + typename BoxIndexable, + size_t DimensionIndex> +struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_near_tag, DimensionIndex> +{ + typedef typename geometry::default_distance_result<Point, BoxIndexable>::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename coordinate_type<Point>::type point_coord_t; + typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t; + + point_coord_t pt_c = geometry::get<DimensionIndex>(pt); + indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i); + indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i); + + result_type diff = 0; + + if ( pt_c < ind_c_min ) + diff = ind_c_min - pt_c; + else if ( ind_c_max < pt_c ) + diff = pt_c - ind_c_max; + + return diff * diff; + } +}; + +template <typename Point, typename Indexable> +typename geometry::default_distance_result<Point, Indexable>::type +comparable_distance_near(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename tag<Indexable>::type, + detail::comparable_distance_near_tag, + dimension<Indexable>::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP diff --git a/boost/geometry/index/detail/algorithms/content.hpp b/boost/geometry/index/detail/algorithms/content.hpp new file mode 100644 index 000000000..1c4739d8e --- /dev/null +++ b/boost/geometry/index/detail/algorithms/content.hpp @@ -0,0 +1,85 @@ +// Boost.Geometry Index +// +// n-dimensional content (hypervolume) - 2d area, 3d volume, ... +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename Indexable> +struct default_content_result +{ + typedef typename select_most_precise< + typename coordinate_type<Indexable>::type, + long double + >::type type; +}; + +namespace dispatch { + +template <typename Box, size_t CurrentDimension> +struct content_box +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + //BOOST_STATIC_ASSERT(CurrentDimension <= traits::dimension<Box>::value); + + static inline typename detail::default_content_result<Box>::type apply(Box const& b) + { + return content_box<Box, CurrentDimension - 1>::apply(b) * + ( get<max_corner, CurrentDimension - 1>(b) - get<min_corner, CurrentDimension - 1>(b) ); + } +}; + +template <typename Box> +struct content_box<Box, 1> +{ + static inline typename detail::default_content_result<Box>::type apply(Box const& b) + { + return get<max_corner, 0>(b) - get<min_corner, 0>(b); + } +}; + +template <typename Indexable, typename Tag> +struct content +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_AND_TAG, (Indexable, Tag)); +}; + +template <typename Indexable> +struct content<Indexable, point_tag> +{ + static typename detail::default_content_result<Indexable>::type apply(Indexable const&) + { + return 0; + } +}; + +template <typename Indexable> +struct content<Indexable, box_tag> +{ + static typename default_content_result<Indexable>::type apply(Indexable const& b) + { + return dispatch::content_box<Indexable, dimension<Indexable>::value>::apply(b); + } +}; + +} // namespace dispatch + +template <typename Indexable> +typename default_content_result<Indexable>::type content(Indexable const& b) +{ + return dispatch::content<Indexable, + typename tag<Indexable>::type + >::apply(b); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP diff --git a/boost/geometry/index/detail/algorithms/diff_abs.hpp b/boost/geometry/index/detail/algorithms/diff_abs.hpp new file mode 100644 index 000000000..ec63bd9a5 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/diff_abs.hpp @@ -0,0 +1,39 @@ +// Boost.Geometry Index +// +// Abs of difference +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename T> +inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<true> const& /*is_integral*/) +{ + return v1 < v2 ? v2 - v1 : v1 - v2; +} + +template <typename T> +inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<false> const& /*is_integral*/) +{ + return ::fabs(v1 - v2); +} + +template <typename T> +inline T diff_abs(T const& v1, T const& v2) +{ + typedef boost::mpl::bool_< + boost::is_integral<T>::value + > is_integral; + return diff_abs_dispatch(v1, v2, is_integral()); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP diff --git a/boost/geometry/index/detail/algorithms/intersection_content.hpp b/boost/geometry/index/detail/algorithms/intersection_content.hpp new file mode 100644 index 000000000..955d6eb65 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/intersection_content.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry Index +// +// boxes union/intersection area/volume +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP + +#include <boost/geometry/algorithms/intersection.hpp> +#include <boost/geometry/index/detail/algorithms/content.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +/** + * \brief Compute the area of the intersection of b1 and b2 + */ +template <typename Box> +inline typename default_content_result<Box>::type intersection_content(Box const& box1, Box const& box2) +{ + if ( geometry::intersects(box1, box2) ) + { + Box box_intersection; + geometry::intersection(box1, box2, box_intersection); + return detail::content(box_intersection); + } + return 0; +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP diff --git a/boost/geometry/index/detail/algorithms/is_valid.hpp b/boost/geometry/index/detail/algorithms/is_valid.hpp new file mode 100644 index 000000000..56c164dae --- /dev/null +++ b/boost/geometry/index/detail/algorithms/is_valid.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry Index +// +// n-dimensional box's / point validity check +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template <typename Box, size_t Dimension> +struct is_valid_box +{ + BOOST_MPL_ASSERT_MSG( + (0 < Dimension && Dimension <= dimension<Box>::value), + INVALID_DIMENSION_PARAMETER, + (is_valid_box)); + + static inline bool apply(Box const& b) + { + return is_valid_box<Box, Dimension - 1>::apply(b) && + ( get<min_corner, Dimension - 1>(b) <= get<max_corner, Dimension - 1>(b) ); + } +}; + +template <typename Box> +struct is_valid_box<Box, 1> +{ + static inline bool apply(Box const& b) + { + return get<min_corner, 0>(b) <= get<max_corner, 0>(b); + } +}; + +template <typename Indexable, typename Tag> +struct is_valid +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE, + (is_valid)); +}; + +template <typename Indexable> +struct is_valid<Indexable, point_tag> +{ + static inline bool apply(Indexable const&) + { + return true; + } +}; + +template <typename Indexable> +struct is_valid<Indexable, box_tag> +{ + static inline bool apply(Indexable const& b) + { + return dispatch::is_valid_box<Indexable, dimension<Indexable>::value>::apply(b); + } +}; + +} // namespace dispatch + +template <typename Indexable> +inline bool is_valid(Indexable const& b) +{ + return dispatch::is_valid<Indexable, typename tag<Indexable>::type>::apply(b); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_DETAIL_INDEX_ALGORITHMS_IS_VALID_HPP diff --git a/boost/geometry/index/detail/algorithms/margin.hpp b/boost/geometry/index/detail/algorithms/margin.hpp new file mode 100644 index 000000000..8e2685ab3 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/margin.hpp @@ -0,0 +1,167 @@ +// Boost.Geometry Index +// +// n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc... +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP + +// WARNING! comparable_margin() will work only if the same Geometries are compared +// so it shouldn't be used in the case of Variants! + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename Box> +struct default_margin_result +{ + typedef typename select_most_precise< + typename coordinate_type<Box>::type, + long double + >::type type; +}; + +//template <typename Box, size_t CurrentDimension, size_t EdgeDimension> +//struct margin_for_each_edge +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// BOOST_STATIC_ASSERT(0 < EdgeDimension); +// +// static inline typename default_margin_result<Box>::type apply(Box const& b) +// { +// return margin_for_each_edge<Box, CurrentDimension, EdgeDimension - 1>::apply(b) * +// ( geometry::get<max_corner, EdgeDimension - 1>(b) - geometry::get<min_corner, EdgeDimension - 1>(b) ); +// } +//}; +// +//template <typename Box, size_t CurrentDimension> +//struct margin_for_each_edge<Box, CurrentDimension, CurrentDimension> +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// +// static inline typename default_margin_result<Box>::type apply(Box const& b) +// { +// return margin_for_each_edge<Box, CurrentDimension, CurrentDimension - 1>::apply(b); +// } +//}; +// +//template <typename Box, size_t CurrentDimension> +//struct margin_for_each_edge<Box, CurrentDimension, 1> +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// +// static inline typename default_margin_result<Box>::type apply(Box const& b) +// { +// return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b); +// } +//}; +// +//template <typename Box> +//struct margin_for_each_edge<Box, 1, 1> +//{ +// static inline typename default_margin_result<Box>::type apply(Box const& /*b*/) +// { +// return 1; +// } +//}; +// +//template <typename Box, size_t CurrentDimension> +//struct margin_for_each_dimension +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// BOOST_STATIC_ASSERT(CurrentDimension <= detail::traits::dimension<Box>::value); +// +// static inline typename default_margin_result<Box>::type apply(Box const& b) +// { +// return margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) + +// margin_for_each_edge<Box, CurrentDimension, detail::traits::dimension<Box>::value>::apply(b); +// } +//}; +// +//template <typename Box> +//struct margin_for_each_dimension<Box, 1> +//{ +// static inline typename default_margin_result<Box>::type apply(Box const& b) +// { +// return margin_for_each_edge<Box, 1, detail::traits::dimension<Box>::value>::apply(b); +// } +//}; + +// TODO - test if this definition of margin is ok for Dimension > 2 +// Now it's sum of edges lengths +// maybe margin_for_each_dimension should be used to get more or less hypersurface? + +template <typename Box, size_t CurrentDimension> +struct simple_margin_for_each_dimension +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + //BOOST_STATIC_ASSERT(CurrentDimension <= dimension<Box>::value); + + static inline typename default_margin_result<Box>::type apply(Box const& b) + { + return simple_margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) + + geometry::get<max_corner, CurrentDimension - 1>(b) - geometry::get<min_corner, CurrentDimension - 1>(b); + } +}; + +template <typename Box> +struct simple_margin_for_each_dimension<Box, 1> +{ + static inline typename default_margin_result<Box>::type apply(Box const& b) + { + return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b); + } +}; + +namespace dispatch { + +template <typename Geometry, typename Tag> +struct comparable_margin +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (Geometry, Tag)); +}; + +template <typename Geometry> +struct comparable_margin<Geometry, point_tag> +{ + typedef typename default_margin_result<Geometry>::type result_type; + + static inline result_type apply(Geometry const& ) { return 0; } +}; + +template <typename Box> +struct comparable_margin<Box, box_tag> +{ + typedef typename default_margin_result<Box>::type result_type; + + static inline result_type apply(Box const& g) + { + //return detail::margin_for_each_dimension<Box, dimension<Box>::value>::apply(g); + return detail::simple_margin_for_each_dimension<Box, dimension<Box>::value>::apply(g); + } +}; + +} // namespace dispatch + +template <typename Geometry> +typename default_margin_result<Geometry>::type comparable_margin(Geometry const& g) +{ + return dispatch::comparable_margin< + Geometry, + typename tag<Geometry>::type + >::apply(g); +} + +//template <typename Box> +//typename default_margin_result<Box>::type margin(Box const& b) +//{ +// return 2 * detail::margin_for_each_dimension<Box, dimension<Box>::value>::apply(b); +//} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP diff --git a/boost/geometry/index/detail/algorithms/minmaxdist.hpp b/boost/geometry/index/detail/algorithms/minmaxdist.hpp new file mode 100644 index 000000000..680fb202b --- /dev/null +++ b/boost/geometry/index/detail/algorithms/minmaxdist.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry Index +// +// minmaxdist used in R-tree k nearest neighbors query +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP + +#include <boost/geometry/algorithms/distance.hpp> +#include <boost/geometry/algorithms/comparable_distance.hpp> + +#include <boost/geometry/index/detail/algorithms/diff_abs.hpp> +#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp> +#include <boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +struct minmaxdist_tag {}; + +template < + typename Point, + typename BoxIndexable, + size_t DimensionIndex> +struct smallest_for_indexable_dimension<Point, BoxIndexable, box_tag, minmaxdist_tag, DimensionIndex> +{ + typedef typename geometry::default_distance_result<Point, BoxIndexable>::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i, result_type const& maxd) + { + typedef typename coordinate_type<Point>::type point_coord_t; + typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t; + + point_coord_t pt_c = geometry::get<DimensionIndex>(pt); + indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i); + indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i); + + indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2; + // TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe? + + // TODO: awulkiew - optimize! don't calculate 2x pt_c <= ind_c_avg + // take particular case pt_c == ind_c_avg into account + + result_type closer_comp = 0; + if ( pt_c <= ind_c_avg ) + closer_comp = detail::diff_abs(pt_c, ind_c_min); // unsigned values protection + else + closer_comp = ind_c_max - pt_c; + + result_type further_comp = 0; + if ( ind_c_avg <= pt_c ) + further_comp = pt_c - ind_c_min; + else + further_comp = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection + + return (maxd + closer_comp * closer_comp) - further_comp * further_comp; + } +}; + +template <typename Point, typename Indexable, typename IndexableTag> +struct minmaxdist_impl +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE, + (minmaxdist_impl)); +}; + +template <typename Point, typename Indexable> +struct minmaxdist_impl<Point, Indexable, point_tag> +{ + typedef typename geometry::default_distance_result<Point, Indexable>::type result_type; + + inline static result_type apply(Point const& pt, Indexable const& i) + { + return geometry::comparable_distance(pt, i); + } +}; + +template <typename Point, typename Indexable> +struct minmaxdist_impl<Point, Indexable, box_tag> +{ + typedef typename geometry::default_distance_result<Point, Indexable>::type result_type; + + inline static result_type apply(Point const& pt, Indexable const& i) + { + result_type maxd = geometry::comparable_distance(pt, i); + + return smallest_for_indexable< + Point, + Indexable, + box_tag, + minmaxdist_tag, + dimension<Indexable>::value + >::apply(pt, i, maxd); + } +}; + +/** + * This is comparable distace. + */ +template <typename Point, typename Indexable> +typename geometry::default_distance_result<Point, Indexable>::type +minmaxdist(Point const& pt, Indexable const& i) +{ + return detail::minmaxdist_impl< + Point, + Indexable, + typename tag<Indexable>::type + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP diff --git a/boost/geometry/index/detail/algorithms/path_intersection.hpp b/boost/geometry/index/detail/algorithms/path_intersection.hpp new file mode 100644 index 000000000..a9e0f3dcb --- /dev/null +++ b/boost/geometry/index/detail/algorithms/path_intersection.hpp @@ -0,0 +1,114 @@ +// Boost.Geometry Index +// +// n-dimensional box-linestring intersection +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP + +#include <boost/geometry/index/detail/algorithms/segment_intersection.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template <typename Indexable, typename Geometry, typename IndexableTag, typename GeometryTag> +struct path_intersection +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_OR_INDEXABLE, (path_intersection)); +}; + +template <typename Indexable, typename Segment> +struct path_intersection<Indexable, Segment, box_tag, segment_tag> +{ + typedef typename default_distance_result<typename point_type<Segment>::type>::type comparable_distance_type; + + static inline bool apply(Indexable const& b, Segment const& segment, comparable_distance_type & comparable_distance) + { + 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 index::detail::segment_intersection(b, p1, p2, comparable_distance); + } +}; + +template <typename Indexable, typename Linestring> +struct path_intersection<Indexable, Linestring, box_tag, linestring_tag> +{ + typedef typename default_length_result<Linestring>::type comparable_distance_type; + + static inline bool apply(Indexable const& b, Linestring const& path, comparable_distance_type & comparable_distance) + { + typedef typename ::boost::range_value<Linestring>::type point_type; + typedef typename ::boost::range_const_iterator<Linestring>::type const_iterator; + typedef typename ::boost::range_size<Linestring>::type size_type; + + const size_type count = ::boost::size(path); + + if ( count == 2 ) + { + return index::detail::segment_intersection(b, *::boost::begin(path), *(::boost::begin(path)+1), comparable_distance); + } + else if ( 2 < count ) + { + const_iterator it0 = ::boost::begin(path); + const_iterator it1 = ::boost::begin(path) + 1; + const_iterator last = ::boost::end(path); + + comparable_distance = 0; + + for ( ; it1 != last ; ++it0, ++it1 ) + { + typename default_distance_result<point_type, point_type>::type + dist = geometry::distance(*it0, *it1); + + comparable_distance_type rel_dist; + if ( index::detail::segment_intersection(b, *it0, *it1, rel_dist) ) + { + comparable_distance += dist * rel_dist; + return true; + } + else + comparable_distance += dist; + } + } + + return false; + } +}; + +} // namespace dispatch + +template <typename Indexable, typename SegmentOrLinestring> +struct default_path_intersection_distance_type +{ + typedef typename dispatch::path_intersection< + Indexable, SegmentOrLinestring, + typename tag<Indexable>::type, + typename tag<SegmentOrLinestring>::type + >::comparable_distance_type type; +}; + +template <typename Indexable, typename SegmentOrLinestring> inline +bool path_intersection(Indexable const& b, + SegmentOrLinestring const& path, + typename default_path_intersection_distance_type<Indexable, SegmentOrLinestring>::type & comparable_distance) +{ + // TODO check Indexable and Linestring concepts + + return dispatch::path_intersection< + Indexable, SegmentOrLinestring, + typename tag<Indexable>::type, + typename tag<SegmentOrLinestring>::type + >::apply(b, path, comparable_distance); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP diff --git a/boost/geometry/index/detail/algorithms/segment_intersection.hpp b/boost/geometry/index/detail/algorithms/segment_intersection.hpp new file mode 100644 index 000000000..4ae82c6ba --- /dev/null +++ b/boost/geometry/index/detail/algorithms/segment_intersection.hpp @@ -0,0 +1,141 @@ +// Boost.Geometry Index +// +// n-dimensional box-segment intersection +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +//template <typename Indexable, typename Point> +//struct default_relative_distance_type +//{ +// typedef typename select_most_precise< +// typename select_most_precise< +// typename coordinate_type<Indexable>::type, +// typename coordinate_type<Point>::type +// >::type, +// float // TODO - use bigger type, calculated from the size of coordinate types +// >::type type; +// +// +// BOOST_MPL_ASSERT_MSG((!::boost::is_unsigned<type>::value), +// THIS_TYPE_SHOULDNT_BE_UNSIGNED, (type)); +//}; + +namespace dispatch { + +template <typename Box, typename Point, size_t I> +struct box_segment_intersection_dim +{ + BOOST_STATIC_ASSERT(I < dimension<Box>::value); + BOOST_STATIC_ASSERT(I < dimension<Point>::value); + BOOST_STATIC_ASSERT(dimension<Point>::value == dimension<Box>::value); + + // WARNING! - RelativeDistance must be IEEE float for this to work + + template <typename RelativeDistance> + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + RelativeDistance & t_near, RelativeDistance & t_far) + { + RelativeDistance ray_d = geometry::get<I>(p1) - geometry::get<I>(p0); + RelativeDistance tn = ( geometry::get<min_corner, I>(b) - geometry::get<I>(p0) ) / ray_d; + RelativeDistance tf = ( geometry::get<max_corner, I>(b) - geometry::get<I>(p0) ) / ray_d; + if ( tf < tn ) + ::std::swap(tn, tf); + + if ( t_near < tn ) + t_near = tn; + if ( tf < t_far ) + t_far = tf; + + return 0 <= t_far && t_near <= t_far; + } +}; + +template <typename Box, typename Point, size_t CurrentDimension> +struct box_segment_intersection +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + + typedef box_segment_intersection_dim<Box, Point, CurrentDimension - 1> for_dim; + + template <typename RelativeDistance> + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + RelativeDistance & t_near, RelativeDistance & t_far) + { + return box_segment_intersection<Box, Point, CurrentDimension - 1>::apply(b, p0, p1, t_near, t_far) + && for_dim::apply(b, p0, p1, t_near, t_far); + } +}; + +template <typename Box, typename Point> +struct box_segment_intersection<Box, Point, 1> +{ + typedef box_segment_intersection_dim<Box, Point, 0> for_dim; + + template <typename RelativeDistance> + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + RelativeDistance & t_near, RelativeDistance & t_far) + { + return for_dim::apply(b, p0, p1, t_near, t_far); + } +}; + +template <typename Indexable, typename Point, typename Tag> +struct segment_intersection +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (segment_intersection)); +}; + +template <typename Indexable, typename Point> +struct segment_intersection<Indexable, Point, point_tag> +{ + BOOST_MPL_ASSERT_MSG((false), SEGMENT_POINT_INTERSECTION_UNAVAILABLE, (segment_intersection)); +}; + +template <typename Indexable, typename Point> +struct segment_intersection<Indexable, Point, box_tag> +{ + typedef dispatch::box_segment_intersection<Indexable, Point, dimension<Indexable>::value> impl; + + template <typename RelativeDistance> + static inline bool apply(Indexable const& b, Point const& p0, Point const& p1, RelativeDistance & relative_distance) + { + static const bool check = !::boost::is_integral<RelativeDistance>::value; + BOOST_MPL_ASSERT_MSG(check, RELATIVE_DISTANCE_MUST_BE_FLOATING_POINT_TYPE, (RelativeDistance)); + + RelativeDistance t_near = -(::std::numeric_limits<RelativeDistance>::max)(); + RelativeDistance t_far = (::std::numeric_limits<RelativeDistance>::max)(); + + return impl::apply(b, p0, p1, t_near, t_far) && + (t_near <= 1) && + ( relative_distance = 0 < t_near ? t_near : 0, true ); + } +}; + +} // namespace dispatch + +template <typename Indexable, typename Point, typename RelativeDistance> inline +bool segment_intersection(Indexable const& b, + Point const& p0, + Point const& p1, + RelativeDistance & relative_distance) +{ + // TODO check Indexable and Point concepts + + return dispatch::segment_intersection< + Indexable, Point, + typename tag<Indexable>::type + >::apply(b, p0, p1, relative_distance); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP diff --git a/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp b/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp new file mode 100644 index 000000000..3ca335d5a --- /dev/null +++ b/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp @@ -0,0 +1,80 @@ +// Boost.Geometry Index +// +// Get smallest value calculated for indexable's dimensions, used in R-tree k nearest neighbors query +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag, + size_t DimensionIndex> +struct smallest_for_indexable_dimension +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE, + (smallest_for_indexable_dimension)); +}; + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag, + size_t N> +struct smallest_for_indexable +{ + typedef typename smallest_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::result_type result_type; + + template <typename Data> + inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data) + { + result_type r1 = smallest_for_indexable< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::apply(g, i, data); + + result_type r2 = smallest_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::apply(g, i, data); + + return r1 < r2 ? r1 : r2; + } +}; + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag> +struct smallest_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1> +{ + typedef typename smallest_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, 0 + >::result_type result_type; + + template <typename Data> + inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data) + { + return + smallest_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, 0 + >::apply(g, i, data); + } +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP diff --git a/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp b/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp new file mode 100644 index 000000000..4aef36352 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp @@ -0,0 +1,76 @@ +// Boost.Geometry Index +// +// Sum values calculated for indexable's dimensions, used e.g. in R-tree k nearest neighbors query +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag, + size_t DimensionIndex> +struct sum_for_indexable_dimension +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE, + (sum_for_indexable_dimension)); +}; + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag, + size_t N> +struct sum_for_indexable +{ + typedef typename sum_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::result_type result_type; + + inline static result_type apply(Geometry const& g, Indexable const& i) + { + return + sum_for_indexable< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::apply(g, i) + + sum_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, N - 1 + >::apply(g, i); + } +}; + +template < + typename Geometry, + typename Indexable, + typename IndexableTag, + typename AlgoTag> +struct sum_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1> +{ + typedef typename sum_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, 0 + >::result_type result_type; + + inline static result_type apply(Geometry const& g, Indexable const& i) + { + return + sum_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, 0 + >::apply(g, i); + } +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP diff --git a/boost/geometry/index/detail/algorithms/union_content.hpp b/boost/geometry/index/detail/algorithms/union_content.hpp new file mode 100644 index 000000000..3acdc3d19 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/union_content.hpp @@ -0,0 +1,33 @@ +// Boost.Geometry Index +// +// boxes union/sum area/volume +// +// Copyright (c) 2008 Federico J. Fernandez. +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP + +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/index/detail/algorithms/content.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +/** + * \brief Compute the area of the union of b1 and b2 + */ +template <typename Box, typename Geometry> +inline typename default_content_result<Box>::type union_content(Box const& b, Geometry const& g) +{ + Box expanded_box(b); + geometry::expand(expanded_box, g); + return detail::content(expanded_box); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP diff --git a/boost/geometry/index/detail/assert.hpp b/boost/geometry/index/detail/assert.hpp new file mode 100644 index 000000000..22af315bc --- /dev/null +++ b/boost/geometry/index/detail/assert.hpp @@ -0,0 +1,30 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP + +#include <boost/assert.hpp> + +#define BOOST_GEOMETRY_INDEX_ASSERT(CONDITION, TEXT_MSG) \ + BOOST_ASSERT_MSG(CONDITION, TEXT_MSG) + +// TODO - change it to something like: +// BOOST_ASSERT((CONDITION) && (TEXT_MSG)) + +#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) + +#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM) + +#else + +#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM) PARAM + +#endif + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP diff --git a/boost/geometry/index/detail/config_begin.hpp b/boost/geometry/index/detail/config_begin.hpp new file mode 100644 index 000000000..21c346012 --- /dev/null +++ b/boost/geometry/index/detail/config_begin.hpp @@ -0,0 +1,21 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +#ifdef BOOST_MSVC + + #pragma warning (push) + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4127) // conditional expression is constant + + // temporary? + #pragma warning (disable : 4180) // qualifier applied to function type has no meaning + +#endif //BOOST_MSVC + diff --git a/boost/geometry/index/detail/config_end.hpp b/boost/geometry/index/detail/config_end.hpp new file mode 100644 index 000000000..d144c3369 --- /dev/null +++ b/boost/geometry/index/detail/config_end.hpp @@ -0,0 +1,12 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if defined BOOST_MSVC + #pragma warning (pop) +#endif + diff --git a/boost/geometry/index/detail/distance_predicates.hpp b/boost/geometry/index/detail/distance_predicates.hpp new file mode 100644 index 000000000..c5c2c4c51 --- /dev/null +++ b/boost/geometry/index/detail/distance_predicates.hpp @@ -0,0 +1,161 @@ +// Boost.Geometry Index +// +// Spatial index distance predicates, calculators and checkers +// used in nearest query - specialized for envelopes +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP + +#include <boost/geometry/index/detail/algorithms/comparable_distance_near.hpp> +#include <boost/geometry/index/detail/algorithms/comparable_distance_far.hpp> +#include <boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp> +#include <boost/geometry/index/detail/algorithms/path_intersection.hpp> + +#include <boost/geometry/index/detail/tags.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +// ------------------------------------------------------------------ // +// relations +// ------------------------------------------------------------------ // + +template <typename T> +struct to_nearest +{ + to_nearest(T const& v) : value(v) {} + T value; +}; + +template <typename T> +struct to_centroid +{ + to_centroid(T const& v) : value(v) {} + T value; +}; + +template <typename T> +struct to_furthest +{ + to_furthest(T const& v) : value(v) {} + T value; +}; + +// tags + +struct to_nearest_tag {}; +struct to_centroid_tag {}; +struct to_furthest_tag {}; + +// ------------------------------------------------------------------ // +// relation traits and access +// ------------------------------------------------------------------ // + +template <typename T> +struct relation +{ + typedef T value_type; + typedef to_nearest_tag tag; + static inline T const& value(T const& v) { return v; } + static inline T & value(T & v) { return v; } +}; + +template <typename T> +struct relation< to_nearest<T> > +{ + typedef T value_type; + typedef to_nearest_tag tag; + static inline T const& value(to_nearest<T> const& r) { return r.value; } + static inline T & value(to_nearest<T> & r) { return r.value; } +}; + +template <typename T> +struct relation< to_centroid<T> > +{ + typedef T value_type; + typedef to_centroid_tag tag; + static inline T const& value(to_centroid<T> const& r) { return r.value; } + static inline T & value(to_centroid<T> & r) { return r.value; } +}; + +template <typename T> +struct relation< to_furthest<T> > +{ + typedef T value_type; + typedef to_furthest_tag tag; + static inline T const& value(to_furthest<T> const& r) { return r.value; } + static inline T & value(to_furthest<T> & r) { return r.value; } +}; + +// ------------------------------------------------------------------ // +// calculate_distance +// ------------------------------------------------------------------ // + +template <typename Predicate, typename Indexable, typename Tag> +struct calculate_distance +{ + BOOST_MPL_ASSERT_MSG((false), INVALID_PREDICATE_OR_TAG, (calculate_distance)); +}; + +// this handles nearest() with default Point parameter, to_nearest() and bounds +template <typename PointRelation, typename Indexable, typename Tag> +struct calculate_distance< nearest<PointRelation>, Indexable, Tag > +{ + typedef detail::relation<PointRelation> relation; + typedef typename relation::value_type point_type; + typedef typename geometry::default_distance_result<point_type, Indexable>::type result_type; + + static inline bool apply(nearest<PointRelation> const& p, Indexable const& i, result_type & result) + { + result = index::detail::comparable_distance_near(relation::value(p.point_or_relation), i); + return true; + } +}; + +template <typename Point, typename Indexable> +struct calculate_distance< nearest< to_centroid<Point> >, Indexable, value_tag> +{ + typedef Point point_type; + typedef typename geometry::default_distance_result<point_type, Indexable>::type result_type; + + static inline bool apply(nearest< to_centroid<Point> > const& p, Indexable const& i, result_type & result) + { + result = index::detail::comparable_distance_centroid(p.point_or_relation.value, i); + return true; + } +}; + +template <typename Point, typename Indexable> +struct calculate_distance< nearest< to_furthest<Point> >, Indexable, value_tag> +{ + typedef Point point_type; + typedef typename geometry::default_distance_result<point_type, Indexable>::type result_type; + + static inline bool apply(nearest< to_furthest<Point> > const& p, Indexable const& i, result_type & result) + { + result = index::detail::comparable_distance_far(p.point_or_relation.value, i); + return true; + } +}; + +template <typename SegmentOrLinestring, typename Indexable, typename Tag> +struct calculate_distance< path<SegmentOrLinestring>, Indexable, Tag> +{ + typedef typename index::detail::default_path_intersection_distance_type< + Indexable, SegmentOrLinestring + >::type result_type; + + static inline bool apply(path<SegmentOrLinestring> const& p, Indexable const& i, result_type & result) + { + return index::detail::path_intersection(i, p.geometry, result); + } +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_RTREE_DISTANCE_PREDICATES_HPP diff --git a/boost/geometry/index/detail/exception.hpp b/boost/geometry/index/detail/exception.hpp new file mode 100644 index 000000000..c3ea0e192 --- /dev/null +++ b/boost/geometry/index/detail/exception.hpp @@ -0,0 +1,72 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP + +#ifndef BOOST_NO_EXCEPTIONS +#include <stdexcept> +#else +#include <cstdlib> +#endif + +namespace boost { namespace geometry { namespace index { namespace detail { + +#ifndef BOOST_NO_EXCEPTIONS + +inline void throw_runtime_error(const char * str) +{ + throw std::runtime_error(str); +} + +inline void throw_logic_error(const char * str) +{ + throw std::logic_error(str); +} + +inline void throw_invalid_argument(const char * str) +{ + throw std::invalid_argument(str); +} + +inline void throw_length_error(const char * str) +{ + throw std::length_error(str); +} + +#else + +inline void throw_runtime_error(const char * str) +{ + BOOST_ASSERT_MSG(!"runtime_error thrown", str); + std::abort(); +} + +inline void throw_logic_error(const char * str) +{ + BOOST_ASSERT_MSG(!"logic_error thrown", str); + std::abort(); +} + +inline void throw_invalid_argument(const char * str) +{ + BOOST_ASSERT_MSG(!"invalid_argument thrown", str); + std::abort(); +} + +inline void throw_length_error(const char * str) +{ + BOOST_ASSERT_MSG(!"length_error thrown", str); + std::abort(); +} + +#endif + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP diff --git a/boost/geometry/index/detail/meta.hpp b/boost/geometry/index/detail/meta.hpp new file mode 100644 index 000000000..bec1380b0 --- /dev/null +++ b/boost/geometry/index/detail/meta.hpp @@ -0,0 +1,42 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/range.hpp> +#include <boost/mpl/aux_/has_type.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/and.hpp> +//#include <boost/type_traits/is_convertible.hpp> + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_META_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_META_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename T> +struct is_range + : ::boost::mpl::aux::has_type< ::boost::range_iterator<T> > +{}; + +//template <typename T, typename V, bool IsRange> +//struct is_range_of_convertible_values_impl +// : ::boost::is_convertible<typename ::boost::range_value<T>::type, V> +//{}; +// +//template <typename T, typename V> +//struct is_range_of_convertible_values_impl<T, V, false> +// : ::boost::mpl::bool_<false> +//{}; +// +//template <typename T, typename V> +//struct is_range_of_convertible_values +// : is_range_of_convertible_values_impl<T, V, is_range<T>::value> +//{}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_META_HPP diff --git a/boost/geometry/index/detail/predicates.hpp b/boost/geometry/index/detail/predicates.hpp new file mode 100644 index 000000000..fd5a92796 --- /dev/null +++ b/boost/geometry/index/detail/predicates.hpp @@ -0,0 +1,814 @@ +// Boost.Geometry Index +// +// Spatial query predicates definition and checks. +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP + +#include <boost/geometry/index/predicates.hpp> +#include <boost/geometry/index/detail/tags.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +// ------------------------------------------------------------------ // +// predicates +// ------------------------------------------------------------------ // + +template <typename Fun, bool IsFunction> +struct satisfies_impl +{ + satisfies_impl(Fun f) : fun(f) {} + Fun * fun; +}; + +template <typename Fun> +struct satisfies_impl<Fun, false> +{ + satisfies_impl(Fun const& f) : fun(f) {} + Fun fun; +}; + +template <typename Fun, bool Negated> +struct satisfies + : satisfies_impl<Fun, ::boost::is_function<Fun>::value> +{ + typedef satisfies_impl<Fun, ::boost::is_function<Fun>::value> base; + + satisfies(Fun const& f) : base(f) {} + satisfies(base const& b) : base(b) {} +}; + +// ------------------------------------------------------------------ // + +struct contains_tag {}; +struct covered_by_tag {}; +struct covers_tag {}; +struct disjoint_tag {}; +struct intersects_tag {}; +struct overlaps_tag {}; +struct touches_tag {}; +struct within_tag {}; + +template <typename Geometry, typename Tag, bool Negated> +struct spatial_predicate +{ + spatial_predicate(Geometry const& g) : geometry(g) {} + Geometry geometry; +}; + +// ------------------------------------------------------------------ // + +// TODO +// may be replaced by +// nearest_predicate<Geometry> +// Geometry geometry +// unsigned count +// + point_tag, path_tag + +template <typename PointOrRelation> +struct nearest +{ + nearest(PointOrRelation const& por, unsigned k) + : point_or_relation(por) + , count(k) + {} + PointOrRelation point_or_relation; + unsigned count; +}; + +template <typename SegmentOrLinestring> +struct path +{ + path(SegmentOrLinestring const& g, unsigned k) + : geometry(g) + , count(k) + {} + SegmentOrLinestring geometry; + unsigned count; +}; + +// ------------------------------------------------------------------ // +// predicate_check +// ------------------------------------------------------------------ // + +template <typename Predicate, typename Tag> +struct predicate_check +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_PREDICATE_OR_TAG, + (predicate_check)); +}; + +// ------------------------------------------------------------------ // + +template <typename Fun> +struct predicate_check<satisfies<Fun, false>, value_tag> +{ + template <typename Value, typename Indexable> + static inline bool apply(satisfies<Fun, false> const& p, Value const& v, Indexable const&) + { + return p.fun(v); + } +}; + +template <typename Fun> +struct predicate_check<satisfies<Fun, true>, value_tag> +{ + template <typename Value, typename Indexable> + static inline bool apply(satisfies<Fun, true> const& p, Value const& v, Indexable const&) + { + return !p.fun(v); + } +}; + +// ------------------------------------------------------------------ // + +template <typename Tag> +struct spatial_predicate_call +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag)); +}; + +template <> +struct spatial_predicate_call<contains_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::within(g2, g1); + } +}; + +template <> +struct spatial_predicate_call<covered_by_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::covered_by(g1, g2); + } +}; + +template <> +struct spatial_predicate_call<covers_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::covered_by(g2, g1); + } +}; + +template <> +struct spatial_predicate_call<disjoint_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::disjoint(g1, g2); + } +}; + +template <> +struct spatial_predicate_call<intersects_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::intersects(g1, g2); + } +}; + +template <> +struct spatial_predicate_call<overlaps_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::overlaps(g1, g2); + } +}; + +template <> +struct spatial_predicate_call<touches_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::touches(g1, g2); + } +}; + +template <> +struct spatial_predicate_call<within_tag> +{ + template <typename G1, typename G2> + static inline bool apply(G1 const& g1, G2 const& g2) + { + return geometry::within(g1, g2); + } +}; + +// ------------------------------------------------------------------ // + +// spatial predicate +template <typename Geometry, typename Tag> +struct predicate_check<spatial_predicate<Geometry, Tag, false>, value_tag> +{ + typedef spatial_predicate<Geometry, Tag, false> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return spatial_predicate_call<Tag>::apply(i, p.geometry); + } +}; + +// negated spatial predicate +template <typename Geometry, typename Tag> +struct predicate_check<spatial_predicate<Geometry, Tag, true>, value_tag> +{ + typedef spatial_predicate<Geometry, Tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return !spatial_predicate_call<Tag>::apply(i, p.geometry); + } +}; + +// ------------------------------------------------------------------ // + +template <typename DistancePredicates> +struct predicate_check<nearest<DistancePredicates>, value_tag> +{ + template <typename Value, typename Box> + static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&) + { + return true; + } +}; + +template <typename Linestring> +struct predicate_check<path<Linestring>, value_tag> +{ + template <typename Value, typename Box> + static inline bool apply(path<Linestring> const&, Value const&, Box const&) + { + return true; + } +}; + +// ------------------------------------------------------------------ // +// predicates_check for bounds +// ------------------------------------------------------------------ // + +template <typename Fun, bool Negated> +struct predicate_check<satisfies<Fun, Negated>, bounds_tag> +{ + template <typename Value, typename Box> + static bool apply(satisfies<Fun, Negated> const&, Value const&, Box const&) + { + return true; + } +}; + +// ------------------------------------------------------------------ // + +// NOT NEGATED +// value_tag bounds_tag +// --------------------------- +// contains(I,G) contains(I,G) +// covered_by(I,G) intersects(I,G) +// covers(I,G) covers(I,G) +// disjoint(I,G) !covered_by(I,G) +// intersects(I,G) intersects(I,G) +// overlaps(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false +// touches(I,G) intersects(I,G) +// within(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false + +// spatial predicate - default +template <typename Geometry, typename Tag> +struct predicate_check<spatial_predicate<Geometry, Tag, false>, bounds_tag> +{ + typedef spatial_predicate<Geometry, Tag, false> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return spatial_predicate_call<intersects_tag>::apply(i, p.geometry); + } +}; + +// spatial predicate - contains +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, contains_tag, false>, bounds_tag> +{ + typedef spatial_predicate<Geometry, contains_tag, false> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return spatial_predicate_call<contains_tag>::apply(i, p.geometry); + } +}; + +// spatial predicate - covers +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, covers_tag, false>, bounds_tag> +{ + typedef spatial_predicate<Geometry, covers_tag, false> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return spatial_predicate_call<covers_tag>::apply(i, p.geometry); + } +}; + +// spatial predicate - disjoint +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, disjoint_tag, false>, bounds_tag> +{ + typedef spatial_predicate<Geometry, disjoint_tag, false> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return !spatial_predicate_call<covered_by_tag>::apply(i, p.geometry); + } +}; + +// NEGATED +// value_tag bounds_tag +// --------------------------- +// !contains(I,G) TRUE +// !covered_by(I,G) !covered_by(I,G) +// !covers(I,G) TRUE +// !disjoint(I,G) !disjoint(I,G) +// !intersects(I,G) !covered_by(I,G) +// !overlaps(I,G) TRUE +// !touches(I,G) !intersects(I,G) +// !within(I,G) !within(I,G) + +// negated spatial predicate - default +template <typename Geometry, typename Tag> +struct predicate_check<spatial_predicate<Geometry, Tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, Tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return !spatial_predicate_call<Tag>::apply(i, p.geometry); + } +}; + +// negated spatial predicate - contains +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, contains_tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, contains_tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& , Value const&, Indexable const& ) + { + return true; + } +}; + +// negated spatial predicate - covers +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, covers_tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, covers_tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& , Value const&, Indexable const& ) + { + return true; + } +}; + +// negated spatial predicate - intersects +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, intersects_tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, intersects_tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return !spatial_predicate_call<covered_by_tag>::apply(i, p.geometry); + } +}; + +// negated spatial predicate - overlaps +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, overlaps_tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, overlaps_tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& , Value const&, Indexable const& ) + { + return true; + } +}; + +// negated spatial predicate - touches +template <typename Geometry> +struct predicate_check<spatial_predicate<Geometry, touches_tag, true>, bounds_tag> +{ + typedef spatial_predicate<Geometry, touches_tag, true> Pred; + + template <typename Value, typename Indexable> + static inline bool apply(Pred const& p, Value const&, Indexable const& i) + { + return !spatial_predicate_call<intersects_tag>::apply(i, p.geometry); + } +}; + +// ------------------------------------------------------------------ // + +template <typename DistancePredicates> +struct predicate_check<nearest<DistancePredicates>, bounds_tag> +{ + template <typename Value, typename Box> + static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&) + { + return true; + } +}; + +template <typename Linestring> +struct predicate_check<path<Linestring>, bounds_tag> +{ + template <typename Value, typename Box> + static inline bool apply(path<Linestring> const&, Value const&, Box const&) + { + return true; + } +}; + +// ------------------------------------------------------------------ // +// predicates_length +// ------------------------------------------------------------------ // + +template <typename T> +struct predicates_length +{ + static const unsigned value = 1; +}; + +//template <typename F, typename S> +//struct predicates_length< std::pair<F, S> > +//{ +// static const unsigned value = 2; +//}; + +//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> +//struct predicates_length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +//{ +// static const unsigned value = boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value; +//}; + +template <typename Head, typename Tail> +struct predicates_length< boost::tuples::cons<Head, Tail> > +{ + static const unsigned value = boost::tuples::length< boost::tuples::cons<Head, Tail> >::value; +}; + +// ------------------------------------------------------------------ // +// predicates_element +// ------------------------------------------------------------------ // + +template <unsigned I, typename T> +struct predicates_element +{ + BOOST_MPL_ASSERT_MSG((I < 1), INVALID_INDEX, (predicates_element)); + typedef T type; + static type const& get(T const& p) { return p; } +}; + +//template <unsigned I, typename F, typename S> +//struct predicates_element< I, std::pair<F, S> > +//{ +// BOOST_MPL_ASSERT_MSG((I < 2), INVALID_INDEX, (predicates_element)); +// +// typedef F type; +// static type const& get(std::pair<F, S> const& p) { return p.first; } +//}; +// +//template <typename F, typename S> +//struct predicates_element< 1, std::pair<F, S> > +//{ +// typedef S type; +// static type const& get(std::pair<F, S> const& p) { return p.second; } +//}; +// +//template <unsigned I, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> +//struct predicates_element< I, boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +//{ +// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicate_type; +// +// typedef typename boost::tuples::element<I, predicate_type>::type type; +// static type const& get(predicate_type const& p) { return boost::get<I>(p); } +//}; + +template <unsigned I, typename Head, typename Tail> +struct predicates_element< I, boost::tuples::cons<Head, Tail> > +{ + typedef boost::tuples::cons<Head, Tail> predicate_type; + + typedef typename boost::tuples::element<I, predicate_type>::type type; + static type const& get(predicate_type const& p) { return boost::get<I>(p); } +}; + +// ------------------------------------------------------------------ // +// predicates_check +// ------------------------------------------------------------------ // + +//template <typename PairPredicates, typename Tag, unsigned First, unsigned Last> +//struct predicates_check_pair {}; +// +//template <typename PairPredicates, typename Tag, unsigned I> +//struct predicates_check_pair<PairPredicates, Tag, I, I> +//{ +// template <typename Value, typename Indexable> +// static inline bool apply(PairPredicates const& , Value const& , Indexable const& ) +// { +// return true; +// } +//}; +// +//template <typename PairPredicates, typename Tag> +//struct predicates_check_pair<PairPredicates, Tag, 0, 1> +//{ +// template <typename Value, typename Indexable> +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i); +// } +//}; +// +//template <typename PairPredicates, typename Tag> +//struct predicates_check_pair<PairPredicates, Tag, 1, 2> +//{ +// template <typename Value, typename Indexable> +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i); +// } +//}; +// +//template <typename PairPredicates, typename Tag> +//struct predicates_check_pair<PairPredicates, Tag, 0, 2> +//{ +// template <typename Value, typename Indexable> +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i) +// && predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i); +// } +//}; + +template <typename TuplePredicates, typename Tag, unsigned First, unsigned Last> +struct predicates_check_tuple +{ + template <typename Value, typename Indexable> + static inline bool apply(TuplePredicates const& p, Value const& v, Indexable const& i) + { + return + predicate_check< + typename boost::tuples::element<First, TuplePredicates>::type, + Tag + >::apply(boost::get<First>(p), v, i) && + predicates_check_tuple<TuplePredicates, Tag, First+1, Last>::apply(p, v, i); + } +}; + +template <typename TuplePredicates, typename Tag, unsigned First> +struct predicates_check_tuple<TuplePredicates, Tag, First, First> +{ + template <typename Value, typename Indexable> + static inline bool apply(TuplePredicates const& , Value const& , Indexable const& ) + { + return true; + } +}; + +template <typename Predicate, typename Tag, unsigned First, unsigned Last> +struct predicates_check_impl +{ + static const bool check = First < 1 && Last <= 1 && First <= Last; + BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl)); + + template <typename Value, typename Indexable> + static inline bool apply(Predicate const& p, Value const& v, Indexable const& i) + { + return predicate_check<Predicate, Tag>::apply(p, v, i); + } +}; + +//template <typename Predicate1, typename Predicate2, typename Tag, size_t First, size_t Last> +//struct predicates_check_impl<std::pair<Predicate1, Predicate2>, Tag, First, Last> +//{ +// BOOST_MPL_ASSERT_MSG((First < 2 && Last <= 2 && First <= Last), INVALID_INDEXES, (predicates_check_impl)); +// +// template <typename Value, typename Indexable> +// static inline bool apply(std::pair<Predicate1, Predicate2> const& p, Value const& v, Indexable const& i) +// { +// return predicate_check<Predicate1, Tag>::apply(p.first, v, i) +// && predicate_check<Predicate2, Tag>::apply(p.second, v, i); +// } +//}; +// +//template < +// typename T0, typename T1, typename T2, typename T3, typename T4, +// typename T5, typename T6, typename T7, typename T8, typename T9, +// typename Tag, unsigned First, unsigned Last +//> +//struct predicates_check_impl< +// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, +// Tag, First, Last +//> +//{ +// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicates_type; +// +// static const unsigned pred_len = boost::tuples::length<predicates_type>::value; +// BOOST_MPL_ASSERT_MSG((First < pred_len && Last <= pred_len && First <= Last), INVALID_INDEXES, (predicates_check_impl)); +// +// template <typename Value, typename Indexable> +// static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i) +// { +// return predicates_check_tuple< +// predicates_type, +// Tag, First, Last +// >::apply(p, v, i); +// } +//}; + +template <typename Head, typename Tail, typename Tag, unsigned First, unsigned Last> +struct predicates_check_impl< + boost::tuples::cons<Head, Tail>, + Tag, First, Last +> +{ + typedef boost::tuples::cons<Head, Tail> predicates_type; + + static const unsigned pred_len = boost::tuples::length<predicates_type>::value; + static const bool check = First < pred_len && Last <= pred_len && First <= Last; + BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl)); + + template <typename Value, typename Indexable> + static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i) + { + return predicates_check_tuple< + predicates_type, + Tag, First, Last + >::apply(p, v, i); + } +}; + +template <typename Tag, unsigned First, unsigned Last, typename Predicates, typename Value, typename Indexable> +inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i) +{ + return detail::predicates_check_impl<Predicates, Tag, First, Last> + ::apply(p, v, i); +} + +// ------------------------------------------------------------------ // +// nearest predicate helpers +// ------------------------------------------------------------------ // + +// predicates_is_nearest + +template <typename P> +struct predicates_is_distance +{ + static const unsigned value = 0; +}; + +template <typename DistancePredicates> +struct predicates_is_distance< nearest<DistancePredicates> > +{ + static const unsigned value = 1; +}; + +template <typename Linestring> +struct predicates_is_distance< path<Linestring> > +{ + static const unsigned value = 1; +}; + +// predicates_count_nearest + +template <typename T> +struct predicates_count_distance +{ + static const unsigned value = predicates_is_distance<T>::value; +}; + +//template <typename F, typename S> +//struct predicates_count_distance< std::pair<F, S> > +//{ +// static const unsigned value = predicates_is_distance<F>::value +// + predicates_is_distance<S>::value; +//}; + +template <typename Tuple, unsigned N> +struct predicates_count_distance_tuple +{ + static const unsigned value = + predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value + + predicates_count_distance_tuple<Tuple, N-1>::value; +}; + +template <typename Tuple> +struct predicates_count_distance_tuple<Tuple, 1> +{ + static const unsigned value = + predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value; +}; + +//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> +//struct predicates_count_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +//{ +// static const unsigned value = predicates_count_distance_tuple< +// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, +// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value +// >::value; +//}; + +template <typename Head, typename Tail> +struct predicates_count_distance< boost::tuples::cons<Head, Tail> > +{ + static const unsigned value = predicates_count_distance_tuple< + boost::tuples::cons<Head, Tail>, + boost::tuples::length< boost::tuples::cons<Head, Tail> >::value + >::value; +}; + +// predicates_find_nearest + +template <typename T> +struct predicates_find_distance +{ + static const unsigned value = predicates_is_distance<T>::value ? 0 : 1; +}; + +//template <typename F, typename S> +//struct predicates_find_distance< std::pair<F, S> > +//{ +// static const unsigned value = predicates_is_distance<F>::value ? 0 : +// (predicates_is_distance<S>::value ? 1 : 2); +//}; + +template <typename Tuple, unsigned N> +struct predicates_find_distance_tuple +{ + static const bool is_found = predicates_find_distance_tuple<Tuple, N-1>::is_found + || predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value; + + static const unsigned value = predicates_find_distance_tuple<Tuple, N-1>::is_found ? + predicates_find_distance_tuple<Tuple, N-1>::value : + (predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value ? + N-1 : boost::tuples::length<Tuple>::value); +}; + +template <typename Tuple> +struct predicates_find_distance_tuple<Tuple, 1> +{ + static const bool is_found = predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value; + static const unsigned value = is_found ? 0 : boost::tuples::length<Tuple>::value; +}; + +//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> +//struct predicates_find_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +//{ +// static const unsigned value = predicates_find_distance_tuple< +// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, +// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value +// >::value; +//}; + +template <typename Head, typename Tail> +struct predicates_find_distance< boost::tuples::cons<Head, Tail> > +{ + static const unsigned value = predicates_find_distance_tuple< + boost::tuples::cons<Head, Tail>, + boost::tuples::length< boost::tuples::cons<Head, Tail> >::value + >::value; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP diff --git a/boost/geometry/index/detail/pushable_array.hpp b/boost/geometry/index/detail/pushable_array.hpp new file mode 100644 index 000000000..180d46580 --- /dev/null +++ b/boost/geometry/index/detail/pushable_array.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_PUSHABLE_ARRAY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_PUSHABLE_ARRAY_HPP + +#include <boost/array.hpp> + +#include <boost/geometry/index/detail/assert.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename Element, size_t Capacity> +class pushable_array +{ + typedef typename boost::array<Element, Capacity> array_type; + +public: + typedef typename array_type::value_type value_type; + typedef typename array_type::size_type size_type; + typedef typename array_type::iterator iterator; + typedef typename array_type::const_iterator const_iterator; + typedef typename array_type::reverse_iterator reverse_iterator; + typedef typename array_type::const_reverse_iterator const_reverse_iterator; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + inline pushable_array() + : m_size(0) + {} + + inline explicit pushable_array(size_type s) + : m_size(s) + { + BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + } + + inline void resize(size_type s) + { + BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + m_size = s; + } + + inline void reserve(size_type /*s*/) + { + //BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + // do nothing + } + + inline Element & operator[](size_type i) + { + BOOST_GEOMETRY_INDEX_ASSERT(i < m_size, "index of the element outside the container"); + return m_array[i]; + } + + inline Element const& operator[](size_type i) const + { + BOOST_GEOMETRY_INDEX_ASSERT(i < m_size, "index of the element outside the container"); + return m_array[i]; + } + + inline Element const& front() const + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return m_array.front(); + } + + inline Element & front() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return m_array.front(); + } + + inline Element const& back() const + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return *(begin() + (m_size - 1)); + } + + inline Element & back() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return *(begin() + (m_size - 1)); + } + + inline iterator begin() + { + return m_array.begin(); + } + + inline iterator end() + { + return m_array.begin() + m_size; + } + + inline const_iterator begin() const + { + return m_array.begin(); + } + + inline const_iterator end() const + { + return m_array.begin() + m_size; + } + + inline reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + inline reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + inline const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + inline const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + inline void clear() + { + m_size = 0; + } + + inline void push_back(Element const& v) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_size < Capacity, "can't further increase the size of the container"); + m_array[m_size] = v; + ++m_size; + } + + inline void pop_back() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + --m_size; + } + + inline bool empty() const + { + return m_size == 0; + } + + inline size_t size() const + { + return m_size; + } + + inline size_t capacity() const + { + return Capacity; + } + +private: + boost::array<Element, Capacity> m_array; + size_type m_size; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_PUSHABLE_ARRAY_HPP diff --git a/boost/geometry/index/detail/rtree/adaptors.hpp b/boost/geometry/index/detail/rtree/adaptors.hpp new file mode 100644 index 000000000..4e0eb9ba0 --- /dev/null +++ b/boost/geometry/index/detail/rtree/adaptors.hpp @@ -0,0 +1,54 @@ +// Boost.Geometry Index +// +// R-tree queries range adaptors +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP + +#include <deque> +#include <boost/static_assert.hpp> + +#include <boost/geometry/index/adaptors/query.hpp> + +namespace boost { namespace geometry { namespace index { + +template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator> +class rtree; + +namespace adaptors { namespace detail { + +template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator> +class query_range< index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> > +{ +public: + typedef std::vector<Value> result_type; + typedef typename result_type::iterator iterator; + typedef typename result_type::const_iterator const_iterator; + + template <typename Predicates> inline + query_range(index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> const& rtree, + Predicates const& pred) + { + rtree.query(pred, std::back_inserter(m_result)); + } + + inline iterator begin() { return m_result.begin(); } + inline iterator end() { return m_result.end(); } + inline const_iterator begin() const { return m_result.begin(); } + inline const_iterator end() const { return m_result.end(); } + +private: + result_type m_result; +}; + +}} // namespace adaptors::detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP diff --git a/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp b/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp new file mode 100644 index 000000000..3f61482b2 --- /dev/null +++ b/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp @@ -0,0 +1,16 @@ +// Boost.Geometry Index +// +// R-tree kmeans algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP + +#include <boost/geometry/index/rtree/kmeans/split.hpp> + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP diff --git a/boost/geometry/index/detail/rtree/kmeans/split.hpp b/boost/geometry/index/detail/rtree/kmeans/split.hpp new file mode 100644 index 000000000..f19654972 --- /dev/null +++ b/boost/geometry/index/detail/rtree/kmeans/split.hpp @@ -0,0 +1,87 @@ +// Boost.Geometry Index +// +// R-tree kmeans split algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP + +#include <boost/geometry/index/rtree/node/node.hpp> +#include <boost/geometry/index/rtree/visitors/insert.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace kmeans { + +// some details + +} // namespace kmeans + +// split_kmeans_tag +// OR +// split_clusters_tag and redistribute_kmeans_tag - then redistribute will probably slightly different interface +// or some other than "redistribute" + +// 1. for this algorithm one probably MUST USE NON-STATIC NODES with node_default_tag +// or the algorithm must be changed somehow - to not store additional nodes in the current node +// but return excessive element/elements container instead (possibly pushable_array<1> or std::vector) +// this would also cause building of smaller trees since +1 element in nodes wouldn't be needed in different redistributing algorithms +// 2. it is probably possible to add e.g. 2 levels of tree in one insert + +// Edge case is that every node split generates M + 1 children, in parent containing M nodes +// result is 2M + 1 nodes in parent on this level +// On next level the same, next the same and so on. +// We have Depth*M+1 nodes in the root +// The tree may then gain some > 1 levels in one insert +// split::apply() manages this but special attention is required + +// which algorithm should be used to choose current node in traversing while inserting? +// some of the currently used ones or some using mean values as well? + +// TODO +// 1. Zmienic troche algorytm zeby przekazywal nadmiarowe elementy do split +// i pobieral ze split nadmiarowe elementy rodzica +// W zaleznosci od algorytmu w rozny sposob - l/q/r* powinny zwracac np pushable_array<1> +// wtedy tez is_overerflow (z R* insert?) bedzie nieportrzebne +// Dla kmeans zapewne std::vector, jednak w wezlach nadal moglaby byc pushable_array +// 2. Fajnie byloby tez uproscic te wszystkie parametry root,parent,index itd. Mozliwe ze okazalyby sie zbedne +// 3. Sprawdzyc czasy wykonywania i zajetosc pamieci +// 4. Pamietac o parametryzacji kontenera z nadmiarowymi elementami +// PS. Z R* reinsertami moze byc masakra + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class split<Value, Options, Translator, Box, Allocators, split_kmeans_tag> +{ +protected: + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Options::parameters_type parameters_type; + +public: + template <typename Node> + static inline void apply(node* & root_node, + size_t & leafs_level, + Node & n, + internal_node *parent_node, + size_t current_child_index, + Translator const& tr, + Allocators & allocators) + { + + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP diff --git a/boost/geometry/index/detail/rtree/linear/linear.hpp b/boost/geometry/index/detail/rtree/linear/linear.hpp new file mode 100644 index 000000000..1461692a1 --- /dev/null +++ b/boost/geometry/index/detail/rtree/linear/linear.hpp @@ -0,0 +1,16 @@ +// Boost.Geometry Index +// +// R-tree linear algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP + +#include <boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp> + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP diff --git a/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp new file mode 100644 index 000000000..45bd18a79 --- /dev/null +++ b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp @@ -0,0 +1,447 @@ +// Boost.Geometry Index +// +// R-tree linear split algorithm implementation +// +// Copyright (c) 2008 Federico J. Fernandez. +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP + +#include <boost/type_traits/is_unsigned.hpp> + +#include <boost/geometry/index/detail/algorithms/content.hpp> + +#include <boost/geometry/index/detail/rtree/node/node.hpp> +#include <boost/geometry/index/detail/rtree/visitors/insert.hpp> +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace linear { + +template <typename R, typename T> +inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<false> const& /*is_unsigned*/) +{ + return to - from; +} + +template <typename R, typename T> +inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<true> const& /*is_unsigned*/) +{ + return from <= to ? R(to - from) : -R(from - to); +} + +template <typename R, typename T> +inline R difference(T const& from, T const& to) +{ + BOOST_MPL_ASSERT_MSG(!boost::is_unsigned<R>::value, RESULT_CANT_BE_UNSIGNED, (R)); + + typedef ::boost::mpl::bool_< + boost::is_unsigned<T>::value + > is_unsigned; + + return difference_dispatch<R>(from, to, is_unsigned()); +} + +// TODO: awulkiew +// In general, all aerial Indexables in the tree with box-like nodes will be analyzed as boxes +// because they must fit into larger box. Therefore the algorithm could be the same for Bounds type. +// E.g. if Bounds type is sphere, Indexables probably should be analyzed as spheres. +// 1. View could be provided to 'see' all Indexables as Bounds type. +// Not ok in the case of big types like Ring, however it's possible that Rings won't be supported, +// only simple types. Even then if we consider storing Box inside the Sphere we must calculate +// the bounding sphere 2x for each box because there are 2 loops. For each calculation this means +// 4-2d or 8-3d expansions or -, / and sqrt(). +// 2. Additional container could be used and reused if the Indexable type is other than the Bounds type. + +// IMPORTANT! +// Still probably the best way would be providing specialized algorithms for each Indexable-Bounds pair! +// Probably on pick_seeds algorithm level - For Bounds=Sphere seeds would be choosen differently + +// TODO: awulkiew +// there are loops inside find_greatest_normalized_separation::apply() +// iteration is done for each DimensionIndex. +// Separations and seeds for all DimensionIndex(es) could be calculated at once, stored, then the greatest would be choosen. + +// The following struct/method was adapted for the preliminary version of the R-tree. Then it was called: +// void find_normalized_separations(std::vector<Box> const& boxes, T& separation, unsigned int& first, unsigned int& second) const + +template <typename Elements, typename Parameters, typename Translator, typename Tag, size_t DimensionIndex> +struct find_greatest_normalized_separation +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag)); +}; + +template <typename Elements, typename Parameters, typename Translator, size_t DimensionIndex> +struct find_greatest_normalized_separation<Elements, Parameters, Translator, box_tag, DimensionIndex> +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + typedef typename boost::mpl::if_c< + boost::is_integral<coordinate_type>::value, + double, + coordinate_type + >::type separation_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& translator, + separation_type & separation, + size_t & seed1, + size_t & seed2) + { + const size_t elements_count = parameters.get_max_elements() + 1; + BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements"); + BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements"); + + // find the lowest low, highest high + coordinate_type lowest_low = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[0], translator)); + coordinate_type highest_high = geometry::get<max_corner, DimensionIndex>(rtree::element_indexable(elements[0], translator)); + // and the lowest high + coordinate_type lowest_high = highest_high; + size_t lowest_high_index = 0; + for ( size_t i = 1 ; i < elements_count ; ++i ) + { + coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); + coordinate_type max_coord = geometry::get<max_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); + + if ( max_coord < lowest_high ) + { + lowest_high = max_coord; + lowest_high_index = i; + } + + if ( min_coord < lowest_low ) + lowest_low = min_coord; + + if ( highest_high < max_coord ) + highest_high = max_coord; + } + + // find the highest low + size_t highest_low_index = lowest_high_index == 0 ? 1 : 0; + coordinate_type highest_low = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[highest_low_index], translator)); + for ( size_t i = highest_low_index ; i < elements_count ; ++i ) + { + coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); + if ( highest_low < min_coord && + i != lowest_high_index ) + { + highest_low = min_coord; + highest_low_index = i; + } + } + + coordinate_type const width = highest_high - lowest_low; + + // highest_low - lowest_high + separation = difference<separation_type>(lowest_high, highest_low); + // BOOST_ASSERT(0 <= width); + if ( std::numeric_limits<coordinate_type>::epsilon() < width ) + separation /= width; + + seed1 = highest_low_index; + seed2 = lowest_high_index; + + ::boost::ignore_unused_variable_warning(parameters); + } +}; + +// Version for points doesn't calculate normalized separation since it would always be equal to 1 +// It returns two seeds most distant to each other, separation is equal to distance +template <typename Elements, typename Parameters, typename Translator, size_t DimensionIndex> +struct find_greatest_normalized_separation<Elements, Parameters, Translator, point_tag, DimensionIndex> +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + typedef coordinate_type separation_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& translator, + separation_type & separation, + size_t & seed1, + size_t & seed2) + { + const size_t elements_count = parameters.get_max_elements() + 1; + BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements"); + BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements"); + + // find the lowest low, highest high + coordinate_type lowest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator)); + coordinate_type highest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator)); + size_t lowest_index = 0; + size_t highest_index = 0; + for ( size_t i = 1 ; i < elements_count ; ++i ) + { + coordinate_type coord = geometry::get<DimensionIndex>(rtree::element_indexable(elements[i], translator)); + + if ( coord < lowest ) + { + lowest = coord; + lowest_index = i; + } + + if ( highest < coord ) + { + highest = coord; + highest_index = i; + } + } + + separation = highest - lowest; + seed1 = lowest_index; + seed2 = highest_index; + + if ( lowest_index == highest_index ) + seed2 = (lowest_index + 1) % elements_count; // % is just in case since if this is true lowest_index is 0 + + ::boost::ignore_unused_variable_warning(parameters); + } +}; + +template <typename Elements, typename Parameters, typename Translator, size_t Dimension> +struct pick_seeds_impl +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + typedef find_greatest_normalized_separation< + Elements, Parameters, Translator, + typename tag<indexable_type>::type, Dimension - 1 + > find_norm_sep; + + typedef typename find_norm_sep::separation_type separation_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + separation_type & separation, + size_t & seed1, + size_t & seed2) + { + pick_seeds_impl<Elements, Parameters, Translator, Dimension - 1>::apply(elements, parameters, tr, separation, seed1, seed2); + + separation_type current_separation; + size_t s1, s2; + find_norm_sep::apply(elements, parameters, tr, current_separation, s1, s2); + + // in the old implementation different operator was used: <= (y axis prefered) + if ( separation < current_separation ) + { + separation = current_separation; + seed1 = s1; + seed2 = s2; + } + } +}; + +template <typename Elements, typename Parameters, typename Translator> +struct pick_seeds_impl<Elements, Parameters, Translator, 1> +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + typedef find_greatest_normalized_separation< + Elements, Parameters, Translator, + typename tag<indexable_type>::type, 0 + > find_norm_sep; + + typedef typename find_norm_sep::separation_type separation_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + separation_type & separation, + size_t & seed1, + size_t & seed2) + { + find_norm_sep::apply(elements, parameters, tr, separation, seed1, seed2); + } +}; + +// from void linear_pick_seeds(node_pointer const& n, unsigned int &seed1, unsigned int &seed2) const + +template <typename Elements, typename Parameters, typename Translator> +struct pick_seeds +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + static const size_t dimension = geometry::dimension<indexable_type>::value; + + typedef pick_seeds_impl<Elements, Parameters, Translator, dimension> impl; + typedef typename impl::separation_type separation_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) + { + separation_type separation = 0; + pick_seeds_impl<Elements, Parameters, Translator, dimension>::apply(elements, parameters, tr, separation, seed1, seed2); + } +}; + +} // namespace linear + +// from void split_node(node_pointer const& n, node_pointer& n1, node_pointer& n2) const + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear_tag> +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + template <typename Node> + static inline void apply(Node & n, + Node & second_node, + Box & box1, + Box & box2, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + { + typedef typename rtree::elements_type<Node>::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + elements_type & elements1 = rtree::elements(n); + elements_type & elements2 = rtree::elements(second_node); + const size_t elements1_count = parameters.get_max_elements() + 1; + + BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements"); + + // copy original elements + elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + linear::pick_seeds< + elements_type, + parameters_type, + Translator + >::apply(elements_copy, parameters, translator, seed1, seed2); + + // prepare nodes' elements containers + elements1.clear(); + BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "unexpected container state"); + + BOOST_TRY + { + // add seeds + elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy) + elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy) + + // calculate boxes + detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1); + detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2); + + // initialize areas + content_type content1 = index::detail::content(box1); + content_type content2 = index::detail::content(box2); + + BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements1_count, "unexpected elements number"); + size_t remaining = elements1_count - 2; + + // redistribute the rest of the elements + for ( size_t i = 0 ; i < elements1_count ; ++i ) + { + if (i != seed1 && i != seed2) + { + element_type const& elem = elements_copy[i]; + indexable_type const& indexable = rtree::element_indexable(elem, translator); + + // if there is small number of elements left and the number of elements in node is lesser than min_elems + // just insert them to this node + if ( elements1.size() + remaining <= parameters.get_min_elements() ) + { + elements1.push_back(elem); // MAY THROW, STRONG (copy) + geometry::expand(box1, indexable); + content1 = index::detail::content(box1); + } + else if ( elements2.size() + remaining <= parameters.get_min_elements() ) + { + elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy) + geometry::expand(box2, indexable); + content2 = index::detail::content(box2); + } + // choose better node and insert element + else + { + // calculate enlarged boxes and areas + Box enlarged_box1(box1); + Box enlarged_box2(box2); + geometry::expand(enlarged_box1, indexable); + geometry::expand(enlarged_box2, indexable); + content_type enlarged_content1 = index::detail::content(enlarged_box1); + content_type enlarged_content2 = index::detail::content(enlarged_box2); + + content_type content_increase1 = enlarged_content1 - content1; + content_type content_increase2 = enlarged_content2 - content2; + + // choose group which box content have to be enlarged least or has smaller content or has fewer elements + if ( content_increase1 < content_increase2 || + ( content_increase1 == content_increase2 && + ( content1 < content2 || + ( content1 == content2 && elements1.size() <= elements2.size() ) ) ) ) + { + elements1.push_back(elem); // MAY THROW, STRONG (copy) + box1 = enlarged_box1; + content1 = enlarged_content1; + } + else + { + elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy) + box2 = enlarged_box2; + content2 = enlarged_content2; + } + } + + BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "unexpected value"); + --remaining; + } + } + } + BOOST_CATCH(...) + { + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators); + //elements_copy.clear(); + + BOOST_RETHROW // RETHROW, BASIC + } + BOOST_CATCH_END + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP diff --git a/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp b/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp new file mode 100644 index 000000000..dd55c6d76 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp @@ -0,0 +1,38 @@ +// Boost.Geometry Index +// +// R-tree auto deallocator +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Alloc> +class auto_deallocator +{ + auto_deallocator(auto_deallocator const&); + auto_deallocator & operator=(auto_deallocator const&); +public: + typedef typename Alloc::pointer pointer; + inline auto_deallocator(Alloc & a, pointer p) : m_alloc(a), m_ptr(p) {} + inline ~auto_deallocator() { if ( m_ptr ) boost::container::allocator_traits<Alloc>::deallocate(m_alloc, m_ptr, 1); } + inline void release() { m_ptr = 0; } + inline pointer ptr() { return m_ptr; } +private: + Alloc & m_alloc; + pointer m_ptr; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP diff --git a/boost/geometry/index/detail/rtree/node/concept.hpp b/boost/geometry/index/detail/rtree/node/concept.hpp new file mode 100644 index 000000000..30fa44d26 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/concept.hpp @@ -0,0 +1,85 @@ +// Boost.Geometry Index +// +// R-tree node concept +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (node)); +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct internal_node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (internal_node)); +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct leaf +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (leaf)); +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst> +struct visitor +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (visitor)); +}; + +template <typename Allocator, typename Value, typename Parameters, typename Box, typename Tag> +class allocators +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (allocators)); +}; + +template <typename Allocators, typename Node> +struct create_node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE, + (create_node)); +}; + +template <typename Allocators, typename Node> +struct destroy_node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE, + (destroy_node)); +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP diff --git a/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp new file mode 100644 index 000000000..477d937db --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry Index +// +// R-tree nodes dynamic visitor and nodes base type +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// visitor forward declaration +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst> +struct dynamic_visitor; + +// node + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct dynamic_node +{ + virtual ~dynamic_node() {} + virtual void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, Tag, false> &) = 0; + virtual void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, Tag, true> &) const = 0; +}; + +// nodes variants forward declarations + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct dynamic_internal_node; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct dynamic_leaf; + +// visitor + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct dynamic_visitor<Value, Parameters, Box, Allocators, Tag, true> +{ + typedef dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node; + typedef dynamic_leaf<Value, Parameters, Box, Allocators, Tag> leaf; + + virtual ~dynamic_visitor() {} + + virtual void operator()(internal_node const&) = 0; + virtual void operator()(leaf const&) = 0; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct dynamic_visitor<Value, Parameters, Box, Allocators, Tag, false> +{ + typedef dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node; + typedef dynamic_leaf<Value, Parameters, Box, Allocators, Tag> leaf; + + virtual ~dynamic_visitor() {} + + virtual void operator()(internal_node &) = 0; + virtual void operator()(leaf &) = 0; +}; + +// nodes conversion + +template <typename Derived, typename Parameters, typename Value, typename Box, typename Allocators, typename Tag> +inline Derived & get(dynamic_node<Value, Parameters, Box, Allocators, Tag> & n) +{ + BOOST_GEOMETRY_INDEX_ASSERT(dynamic_cast<Derived*>(&n), "can't cast to a Derived type"); + return static_cast<Derived&>(n); +} + +// apply visitor + +template <typename Visitor, typename Visitable> +inline void apply_visitor(Visitor & v, Visitable & n) +{ + BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); + n.apply_visitor(v); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP diff --git a/boost/geometry/index/detail/rtree/node/node.hpp b/boost/geometry/index/detail/rtree/node/node.hpp new file mode 100644 index 000000000..d788cdc0d --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node.hpp @@ -0,0 +1,175 @@ +// Boost.Geometry Index +// +// R-tree nodes +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP + +#include <boost/container/vector.hpp> +#include <boost/geometry/index/detail/varray.hpp> + +#include <boost/geometry/index/detail/rtree/node/concept.hpp> +#include <boost/geometry/index/detail/rtree/node/pairs.hpp> +#include <boost/geometry/index/detail/rtree/node/auto_deallocator.hpp> + +#include <boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp> +#include <boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp> +#include <boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp> + +#include <boost/geometry/index/detail/rtree/node/static_visitor.hpp> +#include <boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp> +#include <boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp> + +#include <boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp> + +#include <boost/geometry/algorithms/expand.hpp> + +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +#include <boost/geometry/index/detail/algorithms/bounds.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// elements box + +template <typename Box, typename FwdIter, typename Translator> +inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr) +{ + Box result; + + if ( first == last ) + { + geometry::assign_inverse(result); + return result; + } + + detail::bounds(element_indexable(*first, tr), result); + ++first; + + for ( ; first != last ; ++first ) + geometry::expand(result, element_indexable(*first, tr)); + + return result; +} + +// destroys subtree if the element is internal node's element +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct destroy_element +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + + inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators) + { + node_auto_ptr dummy(element.second, allocators); + element.second = 0; + } + + inline static void apply(typename leaf::elements_type::value_type &, Allocators &) {} +}; + +// destroys stored subtrees if internal node's elements are passed +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct destroy_elements +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + + inline static void apply(typename internal_node::elements_type & elements, Allocators & allocators) + { + for ( size_t i = 0 ; i < elements.size() ; ++i ) + { + node_auto_ptr dummy(elements[i].second, allocators); + elements[i].second = 0; + } + } + + inline static void apply(typename leaf::elements_type &, Allocators &) + {} + + inline static void apply(typename internal_node::elements_type::iterator first, + typename internal_node::elements_type::iterator last, + Allocators & allocators) + { + for ( ; first != last ; ++first ) + { + node_auto_ptr dummy(first->second, allocators); + first->second = 0; + } + } + + inline static void apply(typename leaf::elements_type::iterator /*first*/, + typename leaf::elements_type::iterator /*last*/, + Allocators & /*allocators*/) + {} +}; + +// clears node, deletes all subtrees stored in node +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct clear_node +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline static void apply(node & node, Allocators & allocators) + { + rtree::visitors::is_leaf<Value, Options, Box, Allocators> ilv; + rtree::apply_visitor(ilv, node); + if ( ilv.result ) + { + apply(rtree::get<leaf>(node), allocators); + } + else + { + apply(rtree::get<internal_node>(node), allocators); + } + } + + inline static void apply(internal_node & internal_node, Allocators & allocators) + { + destroy_elements<Value, Options, Translator, Box, Allocators>::apply(rtree::elements(internal_node), allocators); + rtree::elements(internal_node).clear(); + } + + inline static void apply(leaf & leaf, Allocators &) + { + rtree::elements(leaf).clear(); + } +}; + +template <typename Container, typename Iterator> +void move_from_back(Container & container, Iterator it) +{ + BOOST_GEOMETRY_INDEX_ASSERT(!container.empty(), "cannot copy from empty container"); + Iterator back_it = container.end(); + --back_it; + if ( it != back_it ) + { + *it = boost::move(*back_it); // MAY THROW (copy) + } +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp b/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp new file mode 100644 index 000000000..359d4380d --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry Index +// +// R-tree node auto ptr +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP + +#include <boost/geometry/index/detail/rtree/visitors/destroy.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class node_auto_ptr +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename Allocators::node_pointer pointer; + + node_auto_ptr(node_auto_ptr const&); + node_auto_ptr & operator=(node_auto_ptr const&); + +public: + node_auto_ptr(pointer ptr, Allocators & allocators) + : m_ptr(ptr) + , m_allocators(allocators) + {} + + ~node_auto_ptr() + { + reset(); + } + + void reset(pointer ptr = 0) + { + if ( m_ptr ) + { + detail::rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(m_ptr, m_allocators); + detail::rtree::apply_visitor(del_v, *m_ptr); + } + m_ptr = ptr; + } + + void release() + { + m_ptr = 0; + } + + pointer get() const + { + return m_ptr; + } + + node & operator*() const + { + return *m_ptr; + } + + pointer operator->() const + { + return m_ptr; + } + +private: + pointer m_ptr; + Allocators & m_allocators; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp b/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp new file mode 100644 index 000000000..832335f24 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp @@ -0,0 +1,358 @@ +// Boost.Geometry Index +// +// R-tree nodes based on run-time polymorphism, storing std::vectors +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct dynamic_internal_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> + : public dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other elements_allocator_type; + + typedef boost::container::vector< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + elements_allocator_type + > elements_type; + + template <typename Al> + inline dynamic_internal_node(Al const& al) + : elements(al) + {} + + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, false> & v) { v(*this); } + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, true> & v) const { v(*this); } + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct dynamic_leaf<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> + : public dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef boost::container::vector< + Value, + elements_allocator_type + > elements_type; + + template <typename Al> + inline dynamic_leaf(Al const& al) + : elements(al) + {} + + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, false> & v) { v(*this); } + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, true> & v) const { v(*this); } + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> +{ + typedef dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> +{ + typedef dynamic_internal_node<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> +{ + typedef dynamic_leaf<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, IsVisitableConst> +{ + typedef dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_dynamic_tag, IsVisitableConst> type; +}; + +// element's indexable type + +template <typename Element, typename Translator> +struct element_indexable_type +{ + typedef typename indexable_type<Translator>::type type; +}; + +template <typename First, typename Pointer, typename Translator> +struct element_indexable_type< + rtree::ptr_pair<First, Pointer>, + Translator +> +{ + typedef First type; +}; + +// element's indexable getter + +template <typename Element, typename Translator> +typename result_type<Translator>::type +element_indexable(Element const& el, Translator const& tr) +{ + return tr(el); +} + +template <typename First, typename Pointer, typename Translator> +First const& +element_indexable(rtree::ptr_pair<First, Pointer> const& el, Translator const& /*tr*/) +{ + return el.first; +} + +// nodes elements + +template <typename Node> +struct elements_type +{ + typedef typename Node::elements_type type; +}; + +template <typename Node> +inline typename elements_type<Node>::type & +elements(Node & n) +{ + return n.elements; +} + +template <typename Node> +inline typename elements_type<Node>::type const& +elements(Node const& n) +{ + return n.elements; +} + +// elements derived type +template <typename Elements, typename NewValue> +struct container_from_elements_type +{ + typedef boost::container::vector<NewValue> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_d_mem_dynamic_tag> + : public Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators<Allocator, Value, Parameters, Box, node_d_mem_dynamic_tag>, node_d_mem_dynamic_tag>::type + >::other + , public Allocator::template rebind< + typename leaf<Value, Parameters, Box, allocators<Allocator, Value, Parameters, Box, node_d_mem_dynamic_tag>, node_d_mem_dynamic_tag>::type + >::other +{ + typedef typename Allocator::template rebind< + Value + >::other value_allocator_type; + +public: + typedef Allocator allocator_type; + + typedef Value value_type; + typedef typename value_allocator_type::reference reference; + typedef typename value_allocator_type::const_reference const_reference; + typedef typename value_allocator_type::size_type size_type; + typedef typename value_allocator_type::difference_type difference_type; + typedef typename value_allocator_type::pointer pointer; + typedef typename value_allocator_type::const_pointer const_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_d_mem_dynamic_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_d_mem_dynamic_tag>::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_d_mem_dynamic_tag>::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf<Value, Parameters, Box, allocators, node_d_mem_dynamic_tag>::type + >::other leaf_allocator_type; + + inline allocators() + : internal_node_allocator_type() + , leaf_allocator_type() + {} + + template <typename Alloc> + inline explicit allocators(Alloc const& alloc) + : internal_node_allocator_type(alloc) + , leaf_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : internal_node_allocator_type(boost::move(a.internal_node_allocator())) + , leaf_allocator_type(boost::move(a.leaf_allocator())) + {} + + inline allocators & operator=(BOOST_FWD_REF(allocators) a) + { + internal_node_allocator() = ::boost::move(a.internal_node_allocator()); + leaf_allocator() = ::boost::move(a.leaf_allocator()); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + inline allocators & operator=(allocators const& a) + { + internal_node_allocator() = a.internal_node_allocator(); + leaf_allocator() = a.leaf_allocator(); + return *this; + } +#endif + + void swap(allocators & a) + { + boost::swap(internal_node_allocator(), a.internal_node_allocator()); + boost::swap(leaf_allocator(), a.leaf_allocator()); + } + + bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); } + template <typename Alloc> + bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); } + + Allocator allocator() const { return Allocator(leaf_allocator()); } + + internal_node_allocator_type & internal_node_allocator() { return *this; } + internal_node_allocator_type const& internal_node_allocator() const { return *this; } + leaf_allocator_type & leaf_allocator() { return *this; } + leaf_allocator_type const& leaf_allocator() const { return *this; } +}; + +// create_node_impl + +template <typename BaseNodePtr, typename Node> +struct create_dynamic_node +{ + template <typename AllocNode> + static inline BaseNodePtr apply(AllocNode & alloc_node) + { + typedef boost::container::allocator_traits<AllocNode> Al; + typedef typename Al::pointer P; + + P p = Al::allocate(alloc_node, 1); + + if ( 0 == p ) + throw_runtime_error("boost::geometry::index::rtree node creation failed"); + + auto_deallocator<AllocNode> deallocator(alloc_node, p); + + Al::construct(alloc_node, boost::addressof(*p), alloc_node); + + deallocator.release(); + return p; + } +}; + +// destroy_node_impl + +template <typename Node> +struct destroy_dynamic_node +{ + template <typename AllocNode, typename BaseNodePtr> + static inline void apply(AllocNode & alloc_node, BaseNodePtr n) + { + typedef boost::container::allocator_traits<AllocNode> Al; + typedef typename Al::pointer P; + + P p(&static_cast<Node&>(rtree::get<Node>(*n))); + Al::destroy(alloc_node, boost::addressof(*p)); + Al::deallocate(alloc_node, p, 1); + } +}; + +// create_node + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct create_node< + Allocators, + dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_dynamic_node< + typename Allocators::node_pointer, + dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.internal_node_allocator()); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct create_node< + Allocators, + dynamic_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_dynamic_node< + typename Allocators::node_pointer, + dynamic_leaf<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.leaf_allocator()); + } +}; + +// destroy_node + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct destroy_node< + Allocators, + dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_dynamic_node< + dynamic_internal_node<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.internal_node_allocator(), n); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct destroy_node< + Allocators, + dynamic_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_dynamic_node< + dynamic_leaf<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.leaf_allocator(), n); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp b/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp new file mode 100644 index 000000000..bfbe0ae93 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp @@ -0,0 +1,199 @@ +// Boost.Geometry Index +// +// R-tree nodes based on runtime-polymorphism, storing static-size containers +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct dynamic_internal_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> + : public dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other elements_allocator_type; + + typedef detail::varray< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline dynamic_internal_node(Alloc const&) {} + + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, false> & v) { v(*this); } + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, true> & v) const { v(*this); } + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct dynamic_leaf<Value, Parameters, Box, Allocators, node_d_mem_static_tag> + : public dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef detail::varray< + Value, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline dynamic_leaf(Alloc const&) {} + + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, false> & v) { v(*this); } + void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, true> & v) const { v(*this); } + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> +{ + typedef dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> +{ + typedef dynamic_internal_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_d_mem_static_tag> +{ + typedef dynamic_leaf<Value, Parameters, Box, Allocators, node_d_mem_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, IsVisitableConst> +{ + typedef dynamic_visitor<Value, Parameters, Box, Allocators, node_d_mem_static_tag, IsVisitableConst> type; +}; + +// elements derived type +template <typename OldValue, size_t N, typename NewValue> +struct container_from_elements_type<detail::varray<OldValue, N>, NewValue> +{ + typedef detail::varray<NewValue, N> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_d_mem_static_tag> + : public Allocator::template rebind< + typename internal_node< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_d_mem_static_tag>, + node_d_mem_static_tag + >::type + >::other + , public Allocator::template rebind< + typename leaf< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_d_mem_static_tag>, + node_d_mem_static_tag + >::type + >::other +{ + typedef typename Allocator::template rebind< + Value + >::other value_allocator_type; + +public: + typedef Allocator allocator_type; + + typedef Value value_type; + typedef value_type & reference; + typedef const value_type & const_reference; + typedef typename value_allocator_type::size_type size_type; + typedef typename value_allocator_type::difference_type difference_type; + typedef typename value_allocator_type::pointer pointer; + typedef typename value_allocator_type::const_pointer const_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_d_mem_static_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_d_mem_static_tag>::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_d_mem_static_tag>::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf<Value, Parameters, Box, allocators, node_d_mem_static_tag>::type + >::other leaf_allocator_type; + + inline allocators() + : internal_node_allocator_type() + , leaf_allocator_type() + {} + + template <typename Alloc> + inline explicit allocators(Alloc const& alloc) + : internal_node_allocator_type(alloc) + , leaf_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : internal_node_allocator_type(boost::move(a.internal_node_allocator())) + , leaf_allocator_type(boost::move(a.leaf_allocator())) + {} + + inline allocators & operator=(BOOST_FWD_REF(allocators) a) + { + internal_node_allocator() = ::boost::move(a.internal_node_allocator()); + leaf_allocator() = ::boost::move(a.leaf_allocator()); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + inline allocators & operator=(allocators const& a) + { + internal_node_allocator() = a.internal_node_allocator(); + leaf_allocator() = a.leaf_allocator(); + return *this; + } +#endif + + void swap(allocators & a) + { + boost::swap(internal_node_allocator(), a.internal_node_allocator()); + boost::swap(leaf_allocator(), a.leaf_allocator()); + } + + bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); } + template <typename Alloc> + bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); } + + Allocator allocator() const { return Allocator(leaf_allocator()); } + + internal_node_allocator_type & internal_node_allocator() { return *this; } + internal_node_allocator_type const& internal_node_allocator() const { return *this; } + leaf_allocator_type & leaf_allocator() { return *this; } + leaf_allocator_type const& leaf_allocator() const{ return *this; } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp b/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp new file mode 100644 index 000000000..a37856c55 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp @@ -0,0 +1,276 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing std::vectors +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_VARIANT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_VARIANT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes default types + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct static_internal_node +{ + typedef typename Allocators::node_allocator_type::template rebind< + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other elements_allocator_type; + + typedef boost::container::vector< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + elements_allocator_type + > elements_type; + + template <typename Al> + inline static_internal_node(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct static_leaf +{ + typedef typename Allocators::node_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef boost::container::vector< + Value, + elements_allocator_type + > elements_type; + + template <typename Al> + inline static_leaf(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> +{ + typedef boost::variant< + static_leaf<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag>, + static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> + > type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> +{ + typedef static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> +{ + typedef static_leaf<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_s_mem_dynamic_tag, IsVisitableConst> +{ + typedef static_visitor<> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_s_mem_dynamic_tag> + : public Allocator::template rebind< + typename node<Value, Parameters, Box, allocators<Allocator, Value, Parameters, Box, node_s_mem_dynamic_tag>, node_s_mem_dynamic_tag>::type + >::other +{ + typedef typename Allocator::template rebind< + Value + >::other value_allocator_type; + +public: + typedef Allocator allocator_type; + + typedef Value value_type; + typedef typename value_allocator_type::reference reference; + typedef typename value_allocator_type::const_reference const_reference; + typedef typename value_allocator_type::size_type size_type; + typedef typename value_allocator_type::difference_type difference_type; + typedef typename value_allocator_type::pointer pointer; + typedef typename value_allocator_type::const_pointer const_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_s_mem_dynamic_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_s_mem_dynamic_tag>::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_s_mem_dynamic_tag>::type + >::other node_allocator_type; + + inline allocators() + : node_allocator_type() + {} + + template <typename Alloc> + inline explicit allocators(Alloc const& alloc) + : node_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : node_allocator_type(boost::move(a.node_allocator())) + {} + + inline allocators & operator=(BOOST_FWD_REF(allocators) a) + { + node_allocator() = boost::move(a.node_allocator()); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + inline allocators & operator=(allocators const& a) + { + node_allocator() = a.node_allocator(); + return *this; + } +#endif + + void swap(allocators & a) + { + boost::swap(node_allocator(), a.node_allocator()); + } + + bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); } + template <typename Alloc> + bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); } + + Allocator allocator() const { return Allocator(node_allocator()); } + + node_allocator_type & node_allocator() { return *this; } + node_allocator_type const& node_allocator() const { return *this; } +}; + +// create_node_variant + +template <typename VariantPtr, typename Node> +struct create_static_node +{ + template <typename AllocNode> + static inline VariantPtr apply(AllocNode & alloc_node) + { + typedef boost::container::allocator_traits<AllocNode> Al; + typedef typename Al::pointer P; + + P p = Al::allocate(alloc_node, 1); + + if ( 0 == p ) + throw_runtime_error("boost::geometry::index::rtree node creation failed"); + + auto_deallocator<AllocNode> deallocator(alloc_node, p); + + Al::construct(alloc_node, boost::addressof(*p), Node(alloc_node)); // implicit cast to Variant + + deallocator.release(); + return p; + } +}; + +// destroy_node_variant + +template <typename Node> +struct destroy_static_node +{ + template <typename AllocNode, typename VariantPtr> + static inline void apply(AllocNode & alloc_node, VariantPtr n) + { + typedef boost::container::allocator_traits<AllocNode> Al; + + Al::destroy(alloc_node, boost::addressof(*n)); + Al::deallocate(alloc_node, n, 1); + } +}; + +// create_node + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct create_node< + Allocators, + static_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_internal_node<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.node_allocator()); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct create_node< + Allocators, + static_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_leaf<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.node_allocator()); + } +}; + +// destroy_node + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct destroy_node< + Allocators, + static_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_static_node< + static_internal_node<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.node_allocator(), n); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag> +struct destroy_node< + Allocators, + static_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_static_node< + static_leaf<Value, Parameters, Box, Allocators, Tag> + >::apply(allocators.node_allocator(), n); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_VARIANT_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp b/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp new file mode 100644 index 000000000..fa9fb456f --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp @@ -0,0 +1,202 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing static-size containers +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_VARIANT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_VARIANT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes default types + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +{ + typedef typename Allocators::node_allocator_type::template rebind< + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other elements_allocator_type; + + typedef detail::varray< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline static_internal_node(Alloc const&) {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct static_leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +{ + typedef typename Allocators::node_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef detail::varray< + Value, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline static_leaf(Alloc const&) {} + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +{ + typedef boost::variant< + static_leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag>, + static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> + > type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +{ + typedef static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +{ + typedef static_leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_s_mem_static_tag, IsVisitableConst> +{ + typedef static_visitor<> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +struct allocators<Allocator, Value, Parameters, Box, node_s_mem_static_tag> + : public Allocator::template rebind< + typename node<Value, Parameters, Box, allocators<Allocator, Value, Parameters, Box, node_s_mem_static_tag>, node_s_mem_static_tag>::type + >::other +{ + typedef typename Allocator::template rebind< + Value + >::other value_allocator_type; + +public: + typedef Allocator allocator_type; + + typedef Value value_type; + typedef value_type & reference; + typedef const value_type & const_reference; + typedef typename value_allocator_type::size_type size_type; + typedef typename value_allocator_type::difference_type difference_type; + typedef typename value_allocator_type::pointer pointer; + typedef typename value_allocator_type::const_pointer const_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_s_mem_static_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_s_mem_static_tag>::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_s_mem_static_tag>::type + >::other node_allocator_type; + + inline allocators() + : node_allocator_type() + {} + + template <typename Alloc> + inline explicit allocators(Alloc const& alloc) + : node_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : node_allocator_type(boost::move(a.node_allocator())) + {} + + inline allocators & operator=(BOOST_FWD_REF(allocators) a) + { + node_allocator() = boost::move(a.node_allocator()); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + inline allocators & operator=(allocators const& a) + { + node_allocator() = a.node_allocator(); + return *this; + } +#endif + + void swap(allocators & a) + { + boost::swap(node_allocator(), a.node_allocator()); + } + + bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); } + template <typename Alloc> + bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); } + + Allocator allocator() const { return Allocator(node_allocator()); } + + node_allocator_type & node_allocator() { return *this; } + node_allocator_type const& node_allocator() const { return *this; } +}; + +// create_node + +template <typename Allocators, typename Value, typename Parameters, typename Box> +struct create_node< + Allocators, + static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_internal_node<Value, Parameters, Box, Allocators, node_s_mem_static_tag> + >::template apply(allocators.node_allocator()); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box> +struct create_node< + Allocators, + static_leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_leaf<Value, Parameters, Box, Allocators, node_s_mem_static_tag> + >::template apply(allocators.node_allocator()); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_VARIANT_HPP diff --git a/boost/geometry/index/detail/rtree/node/pairs.hpp b/boost/geometry/index/detail/rtree/node/pairs.hpp new file mode 100644 index 000000000..dc088ec29 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/pairs.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry Index +// +// Pairs intended to be used internally in nodes. +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP + +#include <boost/move/move.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename First, typename Pointer> +class ptr_pair +{ +public: + typedef First first_type; + typedef Pointer second_type; + ptr_pair(First const& f, Pointer s) : first(f), second(s) {} + //ptr_pair(ptr_pair const& p) : first(p.first), second(p.second) {} + //ptr_pair & operator=(ptr_pair const& p) { first = p.first; second = p.second; return *this; } + + first_type first; + second_type second; +}; + +template <typename First, typename Pointer> inline +ptr_pair<First, Pointer> +make_ptr_pair(First const& f, Pointer s) +{ + return ptr_pair<First, Pointer>(f, s); +} + +// TODO: It this will be used, rename it to unique_ptr_pair and possibly use unique_ptr. + +template <typename First, typename Pointer> +class exclusive_ptr_pair +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(exclusive_ptr_pair) +public: + typedef First first_type; + typedef Pointer second_type; + exclusive_ptr_pair(First const& f, Pointer s) : first(f), second(s) {} + + // INFO - members aren't really moved! + exclusive_ptr_pair(BOOST_RV_REF(exclusive_ptr_pair) p) : first(p.first), second(p.second) { p.second = 0; } + exclusive_ptr_pair & operator=(BOOST_RV_REF(exclusive_ptr_pair) p) { first = p.first; second = p.second; p.second = 0; return *this; } + + first_type first; + second_type second; +}; + +template <typename First, typename Pointer> inline +exclusive_ptr_pair<First, Pointer> +make_exclusive_ptr_pair(First const& f, Pointer s) +{ + return exclusive_ptr_pair<First, Pointer>(f, s); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP diff --git a/boost/geometry/index/detail/rtree/node/static_visitor.hpp b/boost/geometry/index/detail/rtree/node/static_visitor.hpp new file mode 100644 index 000000000..9b74b1e41 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/static_visitor.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry Index +// +// R-tree nodes static visitor related code +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_STATIC_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_STATIC_VISITOR_HPP + +#include <boost/variant.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes variants forward declarations + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct static_internal_node; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct static_leaf; + +// nodes conversion + +template <typename V, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline V & get( + boost::variant< + static_leaf<Value, Parameters, Box, Allocators, Tag>, + static_internal_node<Value, Parameters, Box, Allocators, Tag> + > & v) +{ + return boost::get<V>(v); +} + +// apply visitor + +template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline void apply_visitor(Visitor & v, + boost::variant< + static_leaf<Value, Parameters, Box, Allocators, Tag>, + static_internal_node<Value, Parameters, Box, Allocators, Tag> + > & n) +{ + boost::apply_visitor(v, n); +} + +template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline void apply_visitor(Visitor & v, + boost::variant< + static_leaf<Value, Parameters, Box, Allocators, Tag>, + static_internal_node<Value, Parameters, Box, Allocators, Tag> + > const& n) +{ + boost::apply_visitor(v, n); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_STATIC_VISITOR_HPP diff --git a/boost/geometry/index/detail/rtree/options.hpp b/boost/geometry/index/detail/rtree/options.hpp new file mode 100644 index 000000000..b1bb60df1 --- /dev/null +++ b/boost/geometry/index/detail/rtree/options.hpp @@ -0,0 +1,155 @@ +// Boost.Geometry Index +// +// R-tree options, algorithms, parameters +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP + +#include <boost/geometry/index/parameters.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// InsertTag +struct insert_default_tag {}; +struct insert_reinsert_tag {}; + +// ChooseNextNodeTag +struct choose_by_content_diff_tag {}; +struct choose_by_overlap_diff_tag {}; + +// SplitTag +struct split_default_tag {}; +//struct split_kmeans_tag {}; + +// RedistributeTag +struct linear_tag {}; +struct quadratic_tag {}; +struct rstar_tag {}; + +// NodeTag +struct node_d_mem_dynamic_tag {}; +struct node_d_mem_static_tag {}; +struct node_s_mem_dynamic_tag {}; +struct node_s_mem_static_tag {}; + +template <typename Parameters, typename InsertTag, typename ChooseNextNodeTag, typename SplitTag, typename RedistributeTag, typename NodeTag> +struct options +{ + typedef Parameters parameters_type; + typedef InsertTag insert_tag; + typedef ChooseNextNodeTag choose_next_node_tag; + typedef SplitTag split_tag; + typedef RedistributeTag redistribute_tag; + typedef NodeTag node_tag; +}; + +template <typename Parameters> +struct options_type +{ + // TODO: awulkiew - use static assert +}; + +template <size_t MaxElements, size_t MinElements> +struct options_type< index::linear<MaxElements, MinElements> > +{ + typedef options< + index::linear<MaxElements, MinElements>, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + linear_tag, + node_d_mem_static_tag + > type; +}; + +template <size_t MaxElements, size_t MinElements> +struct options_type< index::quadratic<MaxElements, MinElements> > +{ + typedef options< + index::quadratic<MaxElements, MinElements>, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + quadratic_tag, + node_d_mem_static_tag + > type; +}; + +template <size_t MaxElements, size_t MinElements, size_t OverlapCostThreshold, size_t ReinsertedElements> +struct options_type< index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements> > +{ + typedef options< + index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements>, + insert_reinsert_tag, + choose_by_overlap_diff_tag, + split_default_tag, + rstar_tag, + node_d_mem_static_tag + > type; +}; + +//template <size_t MaxElements, size_t MinElements> +//struct options_type< kmeans<MaxElements, MinElements> > +//{ +// typedef options< +// kmeans<MaxElements, MinElements>, +// insert_default_tag, +// choose_by_content_diff_tag, // change it? +// split_kmeans_tag, +// int, // dummy tag - not used for now +// node_d_mem_static_tag +// > type; +//}; + +template <> +struct options_type< index::dynamic_linear > +{ + typedef options< + index::dynamic_linear, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + linear_tag, + node_d_mem_dynamic_tag + > type; +}; + +template <> +struct options_type< index::dynamic_quadratic > +{ + typedef options< + index::dynamic_quadratic, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + quadratic_tag, + node_d_mem_dynamic_tag + > type; +}; + +template <> +struct options_type< index::dynamic_rstar > +{ + typedef options< + index::dynamic_rstar, + insert_reinsert_tag, + choose_by_overlap_diff_tag, + split_default_tag, + rstar_tag, + node_d_mem_dynamic_tag + > type; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP diff --git a/boost/geometry/index/detail/rtree/pack_create.hpp b/boost/geometry/index/detail/rtree/pack_create.hpp new file mode 100644 index 000000000..44292f18c --- /dev/null +++ b/boost/geometry/index/detail/rtree/pack_create.hpp @@ -0,0 +1,376 @@ +// Boost.Geometry Index +// +// R-tree initial packing +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +namespace pack_utils { + +template <std::size_t Dimension> +struct biggest_edge +{ + BOOST_STATIC_ASSERT(0 < Dimension); + template <typename Box> + static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index) + { + biggest_edge<Dimension-1>::apply(box, length, dim_index); + typename coordinate_type<Box>::type curr + = geometry::get<max_corner, Dimension-1>(box) - geometry::get<min_corner, Dimension-1>(box); + if ( length < curr ) + { + dim_index = Dimension - 1; + length = curr; + } + } +}; + +template <> +struct biggest_edge<1> +{ + template <typename Box> + static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index) + { + dim_index = 0; + length = geometry::get<max_corner, 0>(box) - geometry::get<min_corner, 0>(box); + } +}; + +template <std::size_t I> +struct point_entries_comparer +{ + template <typename PointEntry> + bool operator()(PointEntry const& e1, PointEntry const& e2) const + { + return geometry::get<I>(e1.first) < geometry::get<I>(e2.first); + } +}; + +template <std::size_t I, std::size_t Dimension> +struct partial_sort_and_half_boxes +{ + template <typename EIt, typename Box> + static inline void apply(EIt first, EIt median, EIt last, Box const& box, Box & left, Box & right, std::size_t dim_index) + { + if ( I == dim_index ) + { + std::partial_sort(first, median, last, point_entries_comparer<I>()); + + geometry::convert(box, left); + geometry::convert(box, right); + typename coordinate_type<Box>::type edge_len + = geometry::get<max_corner, I>(box) - geometry::get<min_corner, I>(box); + typename coordinate_type<Box>::type median + = geometry::get<min_corner, I>(box) + edge_len / 2; + geometry::set<max_corner, I>(left, median); + geometry::set<min_corner, I>(right, median); + } + else + partial_sort_and_half_boxes<I+1, Dimension>::apply(first, median, last, box, left, right, dim_index); + } +}; + +template <std::size_t Dimension> +struct partial_sort_and_half_boxes<Dimension, Dimension> +{ + template <typename EIt, typename Box> + static inline void apply(EIt , EIt , EIt , Box const& , Box & , Box & , std::size_t ) {} +}; + +} // namespace pack_utils + +// STR leafs number are calculated as rcount/max +// and the number of splitting planes for each dimension as (count/max)^(1/dimension) +// <-> for dimension==2 -> sqrt(count/max) +// +// The main flaw of this algorithm is that the resulting tree will have bad structure for: +// 1. non-uniformly distributed elements +// Statistic check could be performed, e.g. based on variance of lengths of elements edges for each dimension +// 2. elements distributed mainly along one axis +// Calculate bounding box of all elements and then number of dividing planes for a dimension +// from the length of BB edge for this dimension (more or less assuming that elements are uniformly-distributed squares) +// +// Another thing is that the last node may have less elements than Max or even Min. +// The number of splitting planes must be chosen more carefully than count/max +// +// This algorithm is something between STR and TGS +// it is more similar to the top-down recursive kd-tree creation algorithm +// using object median split and split axis of greatest BB edge +// BB is only used as a hint (assuming objects are distributed uniformly) +// +// Implemented algorithm guarantees that the number of elements in nodes will be between Min and Max +// and that nodes are packed as tightly as possible +// e.g. for 177 values Max = 5 and Min = 2 it will construct the following tree: +// ROOT 177 +// L1 125 52 +// L2 25 25 25 25 25 25 17 10 +// L3 5x5 5x5 5x5 5x5 5x5 5x5 3x5+2 2x5 + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class pack +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Allocators::node_pointer node_pointer; + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + typedef typename Allocators::size_type size_type; + + typedef typename traits::point_type<Box>::type point_type; + typedef typename traits::coordinate_type<point_type>::type coordinate_type; + typedef typename detail::default_content_result<Box>::type content_type; + typedef typename Options::parameters_type parameters_type; + static const std::size_t dimension = traits::dimension<point_type>::value; + + typedef typename rtree::container_from_elements_type< + typename rtree::elements_type<leaf>::type, + std::size_t + >::type values_counts_container; + + typedef typename rtree::elements_type<internal_node>::type internal_elements; + typedef typename internal_elements::value_type internal_element; + +public: + // Arbitrary iterators + template <typename InIt> inline static + node_pointer apply(InIt first, InIt last, size_type & values_count, size_type & leafs_level, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) + { + typedef typename std::iterator_traits<InIt>::difference_type diff_type; + + diff_type diff = std::distance(first, last); + if ( diff <= 0 ) + return node_pointer(0); + + typedef std::pair<point_type, InIt> entry_type; + std::vector<entry_type> entries; + + values_count = static_cast<size_type>(diff); + entries.reserve(values_count); + + Box hint_box; + geometry::assign_inverse(hint_box); + for ( ; first != last ; ++first ) + { + geometry::expand(hint_box, translator(*first)); + + point_type pt; + geometry::centroid(translator(*first), pt); + entries.push_back(std::make_pair(pt, first)); + } + + subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(values_count, parameters, leafs_level); + internal_element el = per_level(entries.begin(), entries.end(), hint_box, values_count, subtree_counts, + parameters, translator, allocators); + + return el.second; + } + +private: + struct subtree_elements_counts + { + subtree_elements_counts(std::size_t ma, std::size_t mi) : maxc(ma), minc(mi) {} + std::size_t maxc; + std::size_t minc; + }; + + template <typename EIt> inline static + internal_element per_level(EIt first, EIt last, Box const& hint_box, std::size_t values_count, subtree_elements_counts const& subtree_counts, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) + { + BOOST_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count); + + if ( subtree_counts.maxc <= 1 ) + { + // ROOT or LEAF + BOOST_ASSERT(values_count <= parameters.get_max_elements()); + // if !root check m_parameters.get_min_elements() <= count + + // create new leaf node + node_pointer n = rtree::create_node<Allocators, leaf>::apply(allocators); // MAY THROW (A) + node_auto_ptr auto_remover(n, allocators); + leaf & l = rtree::get<leaf>(*n); + + // reserve space for values + rtree::elements(l).reserve(values_count); // MAY THROW (A) + // calculate values box and copy values + Box elements_box; + geometry::assign_inverse(elements_box); + for ( ; first != last ; ++first ) + { + rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C) + geometry::expand(elements_box, translator(*(first->second))); + } + + auto_remover.release(); + return internal_element(elements_box, n); + } + + // calculate next max and min subtree counts + subtree_elements_counts next_subtree_counts = subtree_counts; + next_subtree_counts.maxc /= parameters.get_max_elements(); + next_subtree_counts.minc /= parameters.get_max_elements(); + + // create new internal node + node_pointer n = rtree::create_node<Allocators, internal_node>::apply(allocators); // MAY THROW (A) + node_auto_ptr auto_remover(n, allocators); + internal_node & in = rtree::get<internal_node>(*n); + + // reserve space for values + std::size_t nodes_count = calculate_nodes_count(values_count, subtree_counts); + rtree::elements(in).reserve(nodes_count); // MAY THROW (A) + // calculate values box and copy values + Box elements_box; + geometry::assign_inverse(elements_box); + + per_level_packets(first, last, hint_box, values_count, subtree_counts, next_subtree_counts, + rtree::elements(in), elements_box, + parameters, translator, allocators); + + auto_remover.release(); + return internal_element(elements_box, n); + } + + template <typename EIt> inline static + void per_level_packets(EIt first, EIt last, Box const& hint_box, + std::size_t values_count, + subtree_elements_counts const& subtree_counts, + subtree_elements_counts const& next_subtree_counts, + internal_elements & elements, Box & elements_box, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) + { + BOOST_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count); + + BOOST_ASSERT_MSG( subtree_counts.minc <= values_count, "too small number of elements"); + + // only one packet + if ( values_count <= subtree_counts.maxc ) + { + // the end, move to the next level + internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts, + parameters, translator, allocators); + + // in case if push_back() do throw here + // and even if this is not probable (previously reserved memory, nonthrowing pairs copy) + // this case is also tested by exceptions test. + node_auto_ptr auto_remover(el.second, allocators); + // this container should have memory allocated, reserve() called outside + elements.push_back(el); // MAY THROW (A?,C) - however in normal conditions shouldn't + auto_remover.release(); + + geometry::expand(elements_box, el.first); + return; + } + + std::size_t median_count = calculate_median_count(values_count, subtree_counts); + EIt median = first + median_count; + + coordinate_type greatest_length; + std::size_t greatest_dim_index = 0; + pack_utils::biggest_edge<dimension>::apply(hint_box, greatest_length, greatest_dim_index); + Box left, right; + pack_utils::partial_sort_and_half_boxes<0, dimension> + ::apply(first, median, last, hint_box, left, right, greatest_dim_index); + + per_level_packets(first, median, left, + median_count, subtree_counts, next_subtree_counts, + elements, elements_box, + parameters, translator, allocators); + per_level_packets(median, last, right, + values_count - median_count, subtree_counts, next_subtree_counts, + elements, elements_box, + parameters, translator, allocators); + } + + inline static + subtree_elements_counts calculate_subtree_elements_counts(std::size_t elements_count, parameters_type const& parameters, size_type & leafs_level) + { + (void)parameters; + + subtree_elements_counts res(1, 1); + leafs_level = 0; + + std::size_t smax = parameters.get_max_elements(); + for ( ; smax < elements_count ; smax *= parameters.get_max_elements(), ++leafs_level ) + res.maxc = smax; + + res.minc = parameters.get_min_elements() * (res.maxc / parameters.get_max_elements()); + + return res; + } + + inline static + std::size_t calculate_nodes_count(std::size_t count, + subtree_elements_counts const& subtree_counts) + { + std::size_t n = count / subtree_counts.maxc; + std::size_t r = count % subtree_counts.maxc; + + if ( 0 < r && r < subtree_counts.minc ) + { + std::size_t count_minus_min = count - subtree_counts.minc; + n = count_minus_min / subtree_counts.maxc; + r = count_minus_min % subtree_counts.maxc; + ++n; + } + + if ( 0 < r ) + ++n; + + return n; + } + + inline static + std::size_t calculate_median_count(std::size_t count, + subtree_elements_counts const& subtree_counts) + { + // e.g. for max = 5, min = 2, count = 52, subtree_max = 25, subtree_min = 10 + + std::size_t n = count / subtree_counts.maxc; // e.g. 52 / 25 = 2 + std::size_t r = count % subtree_counts.maxc; // e.g. 52 % 25 = 2 + std::size_t median_count = (n / 2) * subtree_counts.maxc; // e.g. 2 / 2 * 25 = 25 + + if ( 0 != r ) // e.g. 0 != 2 + { + if ( subtree_counts.minc <= r ) // e.g. 10 <= 2 == false + { + //BOOST_ASSERT_MSG(0 < n, "unexpected value"); + median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((2+1)/2) * 25 which would be ok, but not in all cases + } + else // r < subtree_counts.second // e.g. 2 < 10 == true + { + std::size_t count_minus_min = count - subtree_counts.minc; // e.g. 52 - 10 = 42 + n = count_minus_min / subtree_counts.maxc; // e.g. 42 / 25 = 1 + r = count_minus_min % subtree_counts.maxc; // e.g. 42 % 25 = 17 + if ( r == 0 ) // e.g. false + { + // n can't be equal to 0 because then there wouldn't be any element in the other node + //BOOST_ASSERT_MSG(0 < n, "unexpected value"); + median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((1+1)/2) * 25 which would be ok, but not in all cases + } + else + { + if ( n == 0 ) // e.g. false + median_count = r; // if calculated -> 17 which is wrong! + else + median_count = ((n+2)/2) * subtree_counts.maxc; // e.g. ((1+2)/2) * 25 = 25 + } + } + } + + return median_count; + } +}; + +}}}}} // namespace boost::geometry::index::detail::rtree + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP diff --git a/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp b/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp new file mode 100644 index 000000000..837ddbeec --- /dev/null +++ b/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp @@ -0,0 +1,16 @@ +// Boost.Geometry Index +// +// R-tree quadratic algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP + +#include <boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp> + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP diff --git a/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp new file mode 100644 index 000000000..d18998970 --- /dev/null +++ b/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp @@ -0,0 +1,298 @@ +// Boost.Geometry Index +// +// R-tree quadratic split algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP + +#include <algorithm> + +#include <boost/geometry/index/detail/algorithms/content.hpp> +#include <boost/geometry/index/detail/algorithms/union_content.hpp> + +#include <boost/geometry/index/detail/rtree/node/node.hpp> +#include <boost/geometry/index/detail/rtree/visitors/insert.hpp> +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace quadratic { + +template <typename Elements, typename Parameters, typename Translator, typename Box> +struct pick_seeds +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + typedef Box box_type; + typedef typename index::detail::default_content_result<box_type>::type content_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) + { + const size_t elements_count = parameters.get_max_elements() + 1; + BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "wrong number of elements"); + BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements"); + + content_type greatest_free_content = 0; + seed1 = 0; + seed2 = 1; + + for ( size_t i = 0 ; i < elements_count - 1 ; ++i ) + { + for ( size_t j = i + 1 ; j < elements_count ; ++j ) + { + indexable_type const& ind1 = rtree::element_indexable(elements[i], tr); + indexable_type const& ind2 = rtree::element_indexable(elements[j], tr); + + box_type enlarged_box; + //geometry::convert(ind1, enlarged_box); + detail::bounds(ind1, enlarged_box); + geometry::expand(enlarged_box, ind2); + + content_type free_content = (index::detail::content(enlarged_box) - index::detail::content(ind1)) - index::detail::content(ind2); + + if ( greatest_free_content < free_content ) + { + greatest_free_content = free_content; + seed1 = i; + seed2 = j; + } + } + } + + ::boost::ignore_unused_variable_warning(parameters); + } +}; + +} // namespace quadratic + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadratic_tag> +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Node> + static inline void apply(Node & n, + Node & second_node, + Box & box1, + Box & box2, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + { + typedef typename rtree::elements_type<Node>::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename coordinate_type<indexable_type>::type coordinate_type; + + elements_type & elements1 = rtree::elements(n); + elements_type & elements2 = rtree::elements(second_node); + + BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number"); + + // copy original elements + elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy) + elements_type elements_backup(elements1); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + quadratic::pick_seeds< + elements_type, + parameters_type, + Translator, + Box + >::apply(elements_copy, parameters, translator, seed1, seed2); + + // prepare nodes' elements containers + elements1.clear(); + BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty"); + + BOOST_TRY + { + // add seeds + elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy) + elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy) + + // calculate boxes + //geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1); + detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1); + //geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2); + detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2); + + // remove seeds + if (seed1 < seed2) + { + rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy) + elements_copy.pop_back(); + rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy) + elements_copy.pop_back(); + } + else + { + rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy) + elements_copy.pop_back(); + rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy) + elements_copy.pop_back(); + } + + // initialize areas + content_type content1 = index::detail::content(box1); + content_type content2 = index::detail::content(box2); + + size_t remaining = elements_copy.size(); + + // redistribute the rest of the elements + while ( !elements_copy.empty() ) + { + typename elements_type::reverse_iterator el_it = elements_copy.rbegin(); + bool insert_into_group1 = false; + + size_t elements1_count = elements1.size(); + size_t elements2_count = elements2.size(); + + // if there is small number of elements left and the number of elements in node is lesser than min_elems + // just insert them to this node + if ( elements1_count + remaining <= parameters.get_min_elements() ) + { + insert_into_group1 = true; + } + else if ( elements2_count + remaining <= parameters.get_min_elements() ) + { + insert_into_group1 = false; + } + // insert the best element + else + { + // find element with minimum groups areas increses differences + content_type content_increase1 = 0; + content_type content_increase2 = 0; + el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(), + box1, box2, content1, content2, translator, + content_increase1, content_increase2); + + if ( content_increase1 < content_increase2 || + ( content_increase1 == content_increase2 && ( content1 < content2 || + ( content1 == content2 && elements1_count <= elements2_count ) ) + ) ) + { + insert_into_group1 = true; + } + else + { + insert_into_group1 = false; + } + } + + // move element to the choosen group + element_type const& elem = *el_it; + indexable_type const& indexable = rtree::element_indexable(elem, translator); + + if ( insert_into_group1 ) + { + elements1.push_back(elem); // MAY THROW, STRONG (copy) + geometry::expand(box1, indexable); + content1 = index::detail::content(box1); + } + else + { + elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy) + geometry::expand(box2, indexable); + content2 = index::detail::content(box2); + } + + BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements"); + typename elements_type::iterator el_it_base = el_it.base(); + rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy) + elements_copy.pop_back(); + + BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements"); + --remaining; + } + } + BOOST_CATCH(...) + { + //elements_copy.clear(); + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators); + //elements_backup.clear(); + + BOOST_RETHROW // RETHROW, BASIC + } + BOOST_CATCH_END + } + + // TODO: awulkiew - change following function to static member of the pick_next class? + + template <typename It> + static inline It pick_next(It first, It last, + Box const& box1, Box const& box2, + content_type const& content1, content_type const& content2, + Translator const& translator, + content_type & out_content_increase1, content_type & out_content_increase2) + { + typedef typename boost::iterator_value<It>::type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + + content_type greatest_content_incrase_diff = 0; + It out_it = first; + out_content_increase1 = 0; + out_content_increase2 = 0; + + // find element with greatest difference between increased group's boxes areas + for ( It el_it = first ; el_it != last ; ++el_it ) + { + indexable_type const& indexable = rtree::element_indexable(*el_it, translator); + + // calculate enlarged boxes and areas + Box enlarged_box1(box1); + Box enlarged_box2(box2); + geometry::expand(enlarged_box1, indexable); + geometry::expand(enlarged_box2, indexable); + content_type enlarged_content1 = index::detail::content(enlarged_box1); + content_type enlarged_content2 = index::detail::content(enlarged_box2); + + content_type content_incrase1 = (enlarged_content1 - content1); + content_type content_incrase2 = (enlarged_content2 - content2); + + content_type content_incrase_diff = content_incrase1 < content_incrase2 ? + content_incrase2 - content_incrase1 : content_incrase1 - content_incrase2; + + if ( greatest_content_incrase_diff < content_incrase_diff ) + { + greatest_content_incrase_diff = content_incrase_diff; + out_it = el_it; + out_content_increase1 = content_incrase1; + out_content_increase2 = content_incrase2; + } + } + + return out_it; + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP diff --git a/boost/geometry/index/detail/rtree/query_iterators.hpp b/boost/geometry/index/detail/rtree/query_iterators.hpp new file mode 100644 index 000000000..8d0dbdd9d --- /dev/null +++ b/boost/geometry/index/detail/rtree/query_iterators.hpp @@ -0,0 +1,230 @@ +// Boost.Geometry Index +// +// R-tree query iterators +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Allocators> +struct end_query_iterator +{ + typedef std::input_iterator_tag iterator_category; + typedef Value value_type; + typedef typename Allocators::const_reference reference; + typedef typename Allocators::difference_type difference_type; + typedef typename Allocators::const_pointer pointer; + + reference operator*() const + { + BOOST_ASSERT_MSG(false, "iterator not dereferencable"); + pointer p(0); + return *p; + } + + const value_type * operator->() const + { + BOOST_ASSERT_MSG(false, "iterator not dereferencable"); + const value_type * p = 0; + return p; + } + + end_query_iterator & operator++() + { + BOOST_ASSERT_MSG(false, "iterator not incrementable"); + return *this; + } + + end_query_iterator operator++(int) + { + BOOST_ASSERT_MSG(false, "iterator not incrementable"); + return *this; + } + + friend bool operator==(end_query_iterator l, end_query_iterator r) + { + return true; + } + + friend bool operator!=(end_query_iterator l, end_query_iterator r) + { + return false; + } +}; + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates> +class spatial_query_iterator +{ + typedef visitors::spatial_query_incremental<Value, Options, Translator, Box, Allocators, Predicates> visitor_type; + typedef typename visitor_type::node_pointer node_pointer; + +public: + typedef std::input_iterator_tag iterator_category; + typedef Value value_type; + typedef typename Allocators::const_reference reference; + typedef typename Allocators::difference_type difference_type; + typedef typename Allocators::const_pointer pointer; + + inline spatial_query_iterator(Translator const& t, Predicates const& p) + : m_visitor(t, p) + {} + + inline spatial_query_iterator(node_pointer root, Translator const& t, Predicates const& p) + : m_visitor(t, p) + { + detail::rtree::apply_visitor(m_visitor, *root); + m_visitor.increment(); + } + + reference operator*() const + { + return m_visitor.dereference(); + } + + const value_type * operator->() const + { + return boost::addressof(m_visitor.dereference()); + } + + spatial_query_iterator & operator++() + { + m_visitor.increment(); + return *this; + } + + spatial_query_iterator operator++(int) + { + spatial_query_iterator temp = *this; + this->operator++(); + return temp; + } + + friend bool operator==(spatial_query_iterator const& l, spatial_query_iterator const& r) + { + return l.m_visitor == r.m_visitor; + } + + friend bool operator==(spatial_query_iterator const& l, end_query_iterator<Value, Allocators>) + { + return l.m_visitor.is_end(); + } + + friend bool operator==(end_query_iterator<Value, Allocators>, spatial_query_iterator const& r) + { + return r.m_visitor.is_end(); + } + + friend bool operator!=(spatial_query_iterator const& l, spatial_query_iterator const& r) + { + return !(l.m_visitor == r.m_visitor); + } + + friend bool operator!=(spatial_query_iterator const& l, end_query_iterator<Value, Allocators>) + { + return !l.m_visitor.is_end(); + } + + friend bool operator!=(end_query_iterator<Value, Allocators>, spatial_query_iterator const& r) + { + return !r.m_visitor.is_end(); + } + +private: + visitor_type m_visitor; +}; + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, unsigned NearestPredicateIndex> +class distance_query_iterator +{ + typedef visitors::distance_query_incremental<Value, Options, Translator, Box, Allocators, Predicates, NearestPredicateIndex> visitor_type; + typedef typename visitor_type::node_pointer node_pointer; + +public: + typedef std::input_iterator_tag iterator_category; + typedef Value value_type; + typedef typename Allocators::const_reference reference; + typedef typename Allocators::difference_type difference_type; + typedef typename Allocators::const_pointer pointer; + + inline distance_query_iterator(Translator const& t, Predicates const& p) + : m_visitor(t, p) + {} + + inline distance_query_iterator(node_pointer root, Translator const& t, Predicates const& p) + : m_visitor(t, p) + { + detail::rtree::apply_visitor(m_visitor, *root); + m_visitor.increment(); + } + + reference operator*() const + { + return m_visitor.dereference(); + } + + const value_type * operator->() const + { + return boost::addressof(m_visitor.dereference()); + } + + distance_query_iterator & operator++() + { + m_visitor.increment(); + return *this; + } + + distance_query_iterator operator++(int) + { + distance_query_iterator temp = *this; + this->operator++(); + return temp; + } + + friend bool operator==(distance_query_iterator const& l, distance_query_iterator const& r) + { + return l.m_visitor == r.m_visitor; + } + + friend bool operator==(distance_query_iterator const& l, end_query_iterator<Value, Allocators>) + { + return l.m_visitor.is_end(); + } + + friend bool operator==(end_query_iterator<Value, Allocators>, distance_query_iterator const& r) + { + return r.m_visitor.is_end(); + } + + friend bool operator!=(distance_query_iterator const& l, distance_query_iterator const& r) + { + return !(l.m_visitor == r.m_visitor); + } + + friend bool operator!=(distance_query_iterator const& l, end_query_iterator<Value, Allocators>) + { + return !l.m_visitor.is_end(); + } + + friend bool operator!=(end_query_iterator<Value, Allocators>, distance_query_iterator const& r) + { + return !r.m_visitor.is_end(); + } + +private: + visitor_type m_visitor; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP diff --git a/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp new file mode 100644 index 000000000..89dd5e5ff --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp @@ -0,0 +1,426 @@ +// Boost.Geometry Index +// +// R-tree R*-tree next node choosing algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP + +#include <algorithm> + +#include <boost/geometry/algorithms/expand.hpp> + +#include <boost/geometry/index/detail/algorithms/content.hpp> +#include <boost/geometry/index/detail/algorithms/intersection_content.hpp> +#include <boost/geometry/index/detail/algorithms/union_content.hpp> + +#include <boost/geometry/index/detail/rtree/node/node.hpp> +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Options, typename Box, typename Allocators> +class choose_next_node<Value, Options, Box, Allocators, choose_by_overlap_diff_tag> +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename rtree::elements_type<internal_node>::type children_type; + typedef typename children_type::value_type child_type; + + typedef typename Options::parameters_type parameters_type; + + typedef typename index::detail::default_content_result<Box>::type content_type; + +public: + template <typename Indexable> + static inline size_t apply(internal_node & n, + Indexable const& indexable, + parameters_type const& parameters, + size_t node_relative_level) + { + ::boost::ignore_unused_variable_warning(parameters); + + children_type & children = rtree::elements(n); + + // children are leafs + if ( node_relative_level <= 1 ) + { + /*if ( 0 < parameters.get_overlap_cost_threshold() && + parameters.get_overlap_cost_threshold() < children.size() ) + return choose_by_nearly_minimum_overlap_cost(children, indexable, parameters.get_overlap_cost_threshold()); + else + return choose_by_minimum_overlap_cost(children, indexable);*/ + + return choose_by_minimum_overlap_cost(children, indexable, parameters.get_overlap_cost_threshold()); + } + // children are internal nodes + else + return choose_by_minimum_content_cost(children, indexable); + } + +private: + template <typename Indexable> + static inline size_t choose_by_minimum_overlap_cost(children_type const& children, + Indexable const& indexable, + size_t overlap_cost_threshold) + { + const size_t children_count = children.size(); + + content_type min_content_diff = (std::numeric_limits<content_type>::max)(); + content_type min_content = (std::numeric_limits<content_type>::max)(); + size_t choosen_index = 0; + + // create container of children sorted by content enlargement needed to include the new value + typedef boost::tuple<size_t, content_type, content_type> child_contents; + + typename rtree::container_from_elements_type<children_type, child_contents>::type children_contents; + children_contents.resize(children_count); + + for ( size_t i = 0 ; i < children_count ; ++i ) + { + child_type const& ch_i = children[i]; + + // expanded child node's box + Box box_exp(ch_i.first); + geometry::expand(box_exp, indexable); + + // areas difference + content_type content = index::detail::content(box_exp); + content_type content_diff = content - index::detail::content(ch_i.first); + + children_contents[i] = boost::make_tuple(i, content_diff, content); + + if ( content_diff < min_content_diff || + (content_diff == min_content_diff && content < min_content) ) + { + min_content_diff = content_diff; + min_content = content; + choosen_index = i; + } + } + + // is this assumption ok? if min_content_diff == 0 there is no overlap increase? + + if ( min_content_diff < -std::numeric_limits<double>::epsilon() || std::numeric_limits<double>::epsilon() < min_content_diff ) + { + if ( 0 < overlap_cost_threshold && overlap_cost_threshold < children.size() ) + { + // calculate nearly minimum overlap cost + + // sort by content_diff + std::partial_sort(children_contents.begin(), children_contents.begin() + overlap_cost_threshold, children_contents.end(), content_diff_less); + choosen_index = choose_by_minimum_overlap_cost_sorted_by_content(children, indexable, children_count, overlap_cost_threshold, children_contents); + } + else + { + // calculate minimum overlap cost + + choosen_index = choose_by_minimum_overlap_cost_unsorted_by_content(children, indexable, children_count, children_contents); + } + } + + return choosen_index; + } + + template <typename Indexable, typename ChildrenContents> + static inline size_t choose_by_minimum_overlap_cost_unsorted_by_content(children_type const& children, + Indexable const& indexable, + size_t children_count, + ChildrenContents const& children_contents) + { + BOOST_GEOMETRY_INDEX_ASSERT(children_contents.size() == children_count, "unexpected number of elements"); + + // choose index with smallest overlap change value, or content change or smallest content + size_t choosen_index = 0; + content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)(); + content_type smallest_content_diff = (std::numeric_limits<content_type>::max)(); + content_type smallest_content = (std::numeric_limits<content_type>::max)(); + + // for each child node + for (size_t i = 0 ; i < children_count ; ++i ) + { + child_type const& ch_i = children[i]; + + Box box_exp(ch_i.first); + // calculate expanded box of child node ch_i + geometry::expand(box_exp, indexable); + + content_type overlap_diff = 0; + + // calculate overlap + for ( size_t j = 0 ; j < children_count ; ++j ) + { + if ( i != j ) + { + child_type const& ch_j = children[j]; + + content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first); + if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp ) + { + overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first); + } + } + } + + content_type content = boost::get<2>(children_contents[i]); + content_type content_diff = boost::get<1>(children_contents[i]); + + // update result + if ( overlap_diff < smallest_overlap_diff || + ( overlap_diff == smallest_overlap_diff && ( content_diff < smallest_content_diff || + ( content_diff == smallest_content_diff && content < smallest_content ) ) + ) ) + { + smallest_overlap_diff = overlap_diff; + smallest_content_diff = content_diff; + smallest_content = content; + choosen_index = i; + } + } + + return choosen_index; + } + + template <typename Indexable, typename ChildrenContents> + static inline size_t choose_by_minimum_overlap_cost_sorted_by_content(children_type const& children, + Indexable const& indexable, + size_t children_count, + size_t overlap_cost_threshold, + ChildrenContents const& children_contents) + { + BOOST_GEOMETRY_INDEX_ASSERT(overlap_cost_threshold < children_count, "unexpected value"); + BOOST_GEOMETRY_INDEX_ASSERT(children_count == children_contents.size(), "unexpected number of elements"); + + // for overlap_cost_threshold child nodes find the one with smallest overlap value + size_t choosen_index = 0; + content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)(); + + // for each node + for (size_t i = 0 ; i < overlap_cost_threshold ; ++i ) + { + size_t child_index = boost::get<0>(children_contents[i]); + + typedef typename children_type::value_type child_type; + child_type const& ch_i = children[child_index]; + + Box box_exp(ch_i.first); + // calculate expanded box of child node ch_i + geometry::expand(box_exp, indexable); + + content_type overlap_diff = 0; + + // calculate overlap + for ( size_t j = 0 ; j < children_count ; ++j ) + { + if ( child_index != j ) + { + child_type const& ch_j = children[j]; + + content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first); + if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp ) + { + overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first); + } + } + } + + // update result + if ( overlap_diff < smallest_overlap_diff ) + { + smallest_overlap_diff = overlap_diff; + choosen_index = child_index; + } + } + + return choosen_index; + } + + //template <typename Indexable> + //static inline size_t choose_by_minimum_overlap_cost(children_type const& children, + // Indexable const& indexable) + //{ + // size_t children_count = children.size(); + + // // choose index with smallest overlap change value, or content change or smallest content + // size_t choosen_index = 0; + // content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)(); + // content_type smallest_content_diff = (std::numeric_limits<content_type>::max)(); + // content_type smallest_content = (std::numeric_limits<content_type>::max)(); + + // // for each child node + // for (size_t i = 0 ; i < children_count ; ++i ) + // { + // child_type const& ch_i = children[i]; + + // Box box_exp(ch_i.first); + // // calculate expanded box of child node ch_i + // geometry::expand(box_exp, indexable); + + // // calculate content and content diff + // content_type content = index::detail::content(box_exp); + // content_type content_diff = content - index::detail::content(ch_i.first); + + // content_type overlap_diff = 0; + // + // // calculate overlap + // for ( size_t j = 0 ; j < children_count ; ++j ) + // { + // if ( i != j ) + // { + // child_type const& ch_j = children[j]; + + // content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first); + // if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp ) + // { + // overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first); + // } + // } + // } + + // // update result + // if ( overlap_diff < smallest_overlap_diff || + // ( overlap_diff == smallest_overlap_diff && ( content_diff < smallest_content_diff || + // ( content_diff == smallest_content_diff && content < smallest_content ) ) + // ) ) + // { + // smallest_overlap_diff = overlap_diff; + // smallest_content_diff = content_diff; + // smallest_content = content; + // choosen_index = i; + // } + // } + + // return choosen_index; + //} + + //template <typename Indexable> + //static inline size_t choose_by_nearly_minimum_overlap_cost(children_type const& children, + // Indexable const& indexable, + // size_t overlap_cost_threshold) + //{ + // const size_t children_count = children.size(); + + // // create container of children sorted by content enlargement needed to include the new value + // std::vector< boost::tuple<size_t, content_type, content_type> > sorted_children(children_count); + // for ( size_t i = 0 ; i < children_count ; ++i ) + // { + // child_type const& ch_i = children[i]; + + // // expanded child node's box + // Box box_exp(ch_i.first); + // geometry::expand(box_exp, indexable); + + // // areas difference + // content_type content = index::detail::content(box_exp); + // content_type content_diff = content - index::detail::content(ch_i.first); + + // sorted_children[i] = boost::make_tuple(i, content_diff, content); + // } + + // BOOST_GEOMETRY_INDEX_ASSERT(overlap_cost_threshold <= children_count, "there is not enough children"); + + // // sort by content_diff + // //std::sort(sorted_children.begin(), sorted_children.end(), content_diff_less); + // std::partial_sort(sorted_children.begin(), sorted_children.begin() + overlap_cost_threshold, sorted_children.end(), content_diff_less); + + // // for overlap_cost_threshold child nodes find the one with smallest overlap value + // size_t choosen_index = 0; + // content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)(); + + // // for each node + // for (size_t i = 0 ; i < overlap_cost_threshold ; ++i ) + // { + // size_t child_index = boost::get<0>(sorted_children[i]); + + // typedef typename children_type::value_type child_type; + // child_type const& ch_i = children[child_index]; + + // Box box_exp(ch_i.first); + // // calculate expanded box of child node ch_i + // geometry::expand(box_exp, indexable); + + // content_type overlap_diff = 0; + + // // calculate overlap + // for ( size_t j = 0 ; j < children_count ; ++j ) + // { + // if ( child_index != j ) + // { + // child_type const& ch_j = children[j]; + + // content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first); + // if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp ) + // { + // overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first); + // } + // } + // } + + // // update result + // if ( overlap_diff < smallest_overlap_diff ) + // { + // smallest_overlap_diff = overlap_diff; + // choosen_index = child_index; + // } + // } + + // return choosen_index; + //} + + static inline bool content_diff_less(boost::tuple<size_t, content_type, content_type> const& p1, boost::tuple<size_t, content_type, content_type> const& p2) + { + return boost::get<1>(p1) < boost::get<1>(p2) || + (boost::get<1>(p1) == boost::get<1>(p2) && boost::get<2>(p1) < boost::get<2>(p2)); + } + + template <typename Indexable> + static inline size_t choose_by_minimum_content_cost(children_type const& children, Indexable const& indexable) + { + size_t children_count = children.size(); + + // choose index with smallest content change or smallest content + size_t choosen_index = 0; + content_type smallest_content_diff = (std::numeric_limits<content_type>::max)(); + content_type smallest_content = (std::numeric_limits<content_type>::max)(); + + // choose the child which requires smallest box expansion to store the indexable + for ( size_t i = 0 ; i < children_count ; ++i ) + { + child_type const& ch_i = children[i]; + + // expanded child node's box + Box box_exp(ch_i.first); + geometry::expand(box_exp, indexable); + + // areas difference + content_type content = index::detail::content(box_exp); + content_type content_diff = content - index::detail::content(ch_i.first); + + // update the result + if ( content_diff < smallest_content_diff || + ( content_diff == smallest_content_diff && content < smallest_content ) ) + { + smallest_content_diff = content_diff; + smallest_content = content; + choosen_index = i; + } + } + + return choosen_index; + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP diff --git a/boost/geometry/index/detail/rtree/rstar/insert.hpp b/boost/geometry/index/detail/rtree/rstar/insert.hpp new file mode 100644 index 000000000..e681bbb6b --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/insert.hpp @@ -0,0 +1,567 @@ +// Boost.Geometry Index +// +// R-tree R*-tree insert algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP + +#include <boost/geometry/index/detail/algorithms/content.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +namespace rstar { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class remove_elements_to_reinsert +{ +public: + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Options::parameters_type parameters_type; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + + template <typename ResultElements, typename Node> + static inline void apply(ResultElements & result_elements, + Node & n, + internal_node_pointer parent, + size_t current_child_index, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + { + typedef typename rtree::elements_type<Node>::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename geometry::point_type<Box>::type point_type; + // TODO: awulkiew - change second point_type to the point type of the Indexable? + typedef typename geometry::default_distance_result<point_type>::type distance_type; + + elements_type & elements = rtree::elements(n); + + const size_t elements_count = parameters.get_max_elements() + 1; + const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements()); + + BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node"); + BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number"); + BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert"); + + // calculate current node's center + point_type node_center; + geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center); + + // fill the container of centers' distances of children from current node's center + typedef typename index::detail::rtree::container_from_elements_type< + elements_type, + std::pair<distance_type, element_type> + >::type sorted_elements_type; + sorted_elements_type sorted_elements; + // If constructor is used instead of resize() MS implementation leaks here + sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy) + + for ( typename elements_type::const_iterator it = elements.begin() ; + it != elements.end() ; ++it ) + { + point_type element_center; + geometry::centroid( rtree::element_indexable(*it, translator), element_center); + sorted_elements.push_back(std::make_pair( + geometry::comparable_distance(node_center, element_center), + *it)); // MAY THROW (V, E: copy) + } + + // sort elements by distances from center + std::partial_sort( + sorted_elements.begin(), + sorted_elements.begin() + reinserted_elements_count, + sorted_elements.end(), + distances_dsc<distance_type, element_type>); // MAY THROW, BASIC (V, E: copy) + + // copy elements which will be reinserted + result_elements.clear(); + result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy) + for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ; + it != sorted_elements.begin() + reinserted_elements_count ; ++it ) + { + result_elements.push_back(it->second); // MAY THROW (V, E: copy) + } + + BOOST_TRY + { + // copy remaining elements to the current node + elements.clear(); + elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size) + for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count; + it != sorted_elements.end() ; ++it ) + { + elements.push_back(it->second); // MAY THROW (V, E: copy) + } + } + BOOST_CATCH(...) + { + elements.clear(); + + for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ; + it != sorted_elements.end() ; ++it ) + { + destroy_element<Value, Options, Translator, Box, Allocators>::apply(it->second, allocators); + } + + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + + ::boost::ignore_unused_variable_warning(parameters); + } + +private: + template <typename Distance, typename El> + static inline bool distances_asc( + std::pair<Distance, El> const& d1, + std::pair<Distance, El> const& d2) + { + return d1.first < d2.first; + } + + template <typename Distance, typename El> + static inline bool distances_dsc( + std::pair<Distance, El> const& d1, + std::pair<Distance, El> const& d2) + { + return d1.first > d2.first; + } +}; + +template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Box, typename Allocators> +struct level_insert_elements_type +{ + typedef typename rtree::elements_type< + typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type + >::type type; +}; + +template <typename Value, typename Options, typename Box, typename Allocators> +struct level_insert_elements_type<0, Value, Value, Options, Box, Allocators> +{ + typedef typename rtree::elements_type< + typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type + >::type type; +}; + +template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct level_insert_base + : public detail::insert<Element, Value, Options, Translator, Box, Allocators> +{ + typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename level_insert_elements_type<InsertIndex, Element, Value, Options, Box, Allocators>::type elements_type; + typedef typename index::detail::rtree::container_from_elements_type< + elements_type, + typename elements_type::value_type + >::type result_elements_type; + + typedef typename Options::parameters_type parameters_type; + + typedef typename Allocators::node_pointer node_pointer; + + inline level_insert_base(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level) + : base(root, leafs_level, element, parameters, translator, allocators, relative_level) + , result_relative_level(0) + {} + + template <typename Node> + inline void handle_possible_reinsert_or_split_of_root(Node &n) + { + BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level"); + + result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level; + + // overflow + if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() ) + { + // node isn't root node + if ( !base::m_traverse_data.current_is_root() ) + { + // NOTE: exception-safety + // After an exception result_elements may contain garbage, don't use it + rstar::remove_elements_to_reinsert<Value, Options, Translator, Box, Allocators>::apply( + result_elements, n, + base::m_traverse_data.parent, base::m_traverse_data.current_child_index, + base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy) + } + // node is root node + else + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node"); + base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + } + + template <typename Node> + inline void handle_possible_split(Node &n) const + { + // overflow + if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() ) + { + base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + + template <typename Node> + inline void recalculate_aabb_if_necessary(Node &n) const + { + if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() ) + { + // calulate node's new box + base::m_traverse_data.current_element().first = + elements_box<Box>(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator); + } + } + + size_t result_relative_level; + result_elements_type result_elements; +}; + +template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct level_insert + : public level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators> +{ + typedef level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename Options::parameters_type parameters_type; + + typedef typename Allocators::node_pointer node_pointer; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level) + : base(root, leafs_level, element, parameters, translator, allocators, relative_level) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level"); + + if ( base::m_traverse_data.current_level < base::m_level ) + { + // next traversing step + base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc) + + // further insert + if ( 0 < InsertIndex ) + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex"); + + if ( base::m_traverse_data.current_level == base::m_level - 1 ) + { + base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc) + } + } + } + else + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level"); + + BOOST_TRY + { + // push new child node + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy) + } + BOOST_CATCH(...) + { + // NOTE: exception-safety + // if the insert fails above, the element won't be stored in the tree, so delete it + + rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators); + rtree::apply_visitor(del_v, *base::m_element.second); + + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + + // first insert + if ( 0 == InsertIndex ) + { + base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc) + } + // not the first insert + else + { + base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc) + } + } + + base::recalculate_aabb_if_necessary(n); + } + + inline void operator()(leaf &) + { + BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf"); + } +}; + +template <size_t InsertIndex, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocators> + : public level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators> +{ + typedef level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename Options::parameters_type parameters_type; + + typedef typename Allocators::node_pointer node_pointer; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level) + : base(root, leafs_level, v, parameters, translator, allocators, relative_level) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level"); + + // next traversing step + base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc) + + BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex"); + + if ( base::m_traverse_data.current_level == base::m_level - 1 ) + { + base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc) + } + + base::recalculate_aabb_if_necessary(n); + } + + inline void operator()(leaf & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level, + "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level || + base::m_level == (std::numeric_limits<size_t>::max)(), + "unexpected level"); + + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy) + + base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc) + } +}; + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct level_insert<0, Value, Value, Options, Translator, Box, Allocators> + : public level_insert_base<0, Value, Value, Options, Translator, Box, Allocators> +{ + typedef level_insert_base<0, Value, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename Options::parameters_type parameters_type; + + typedef typename Allocators::node_pointer node_pointer; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level) + : base(root, leafs_level, v, parameters, translator, allocators, relative_level) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, + "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, + "unexpected level"); + + // next traversing step + base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc) + + base::recalculate_aabb_if_necessary(n); + } + + inline void operator()(leaf & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level, + "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level || + base::m_level == (std::numeric_limits<size_t>::max)(), + "unexpected level"); + + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy) + + base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc) + + base::recalculate_aabb_if_necessary(n); + } +}; + +} // namespace rstar + +// R*-tree insert visitor +// After passing the Element to insert visitor the Element is managed by the tree +// I.e. one should not delete the node passed to the insert visitor after exception is thrown +// because this visitor may delete it +template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class insert<Element, Value, Options, Translator, Box, Allocators, insert_reinsert_tag> + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Allocators::node_pointer node_pointer; + +public: + inline insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level = 0) + : m_root(root), m_leafs_level(leafs_level), m_element(element) + , m_parameters(parameters), m_translator(translator) + , m_relative_level(relative_level), m_allocators(allocators) + {} + + inline void operator()(internal_node & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root"); + + // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one + if ( m_parameters.get_reinserted_elements() > 0 ) + { + rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v( + m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level); + + rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc) + + if ( !lins_v.result_elements.empty() ) + { + recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + else + { + visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v( + m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level); + + rtree::apply_visitor(ins_v, *m_root); + } + } + + inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root"); + + // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one + if ( m_parameters.get_reinserted_elements() > 0 ) + { + rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v( + m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level); + + rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc) + + // we're in the root, so root should be split and there should be no elements to reinsert + BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state"); + } + else + { + visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v( + m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level); + + rtree::apply_visitor(ins_v, *m_root); + } + } + +private: + template <typename Elements> + inline void recursive_reinsert(Elements & elements, size_t relative_level) + { + typedef typename Elements::value_type element_type; + + // reinsert children starting from the minimum distance + typename Elements::reverse_iterator it = elements.rbegin(); + for ( ; it != elements.rend() ; ++it) + { + rstar::level_insert<1, element_type, Value, Options, Translator, Box, Allocators> lins_v( + m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level); + + BOOST_TRY + { + rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc) + } + BOOST_CATCH(...) + { + ++it; + for ( ; it != elements.rend() ; ++it) + rtree::destroy_element<Value, Options, Translator, Box, Allocators>::apply(*it, m_allocators); + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + + BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level"); + + // non-root relative level + if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty()) + { + recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + } + + node_pointer & m_root; + size_t & m_leafs_level; + Element const& m_element; + + parameters_type const& m_parameters; + Translator const& m_translator; + + size_t m_relative_level; + + Allocators & m_allocators; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP diff --git a/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp new file mode 100644 index 000000000..aedc2d1a4 --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp @@ -0,0 +1,441 @@ +// Boost.Geometry Index +// +// R-tree R*-tree split algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP + +#include <boost/geometry/index/detail/algorithms/intersection_content.hpp> +#include <boost/geometry/index/detail/algorithms/union_content.hpp> +#include <boost/geometry/index/detail/algorithms/margin.hpp> + +#include <boost/geometry/index/detail/rtree/node/node.hpp> +#include <boost/geometry/index/detail/rtree/visitors/insert.hpp> +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace rstar { + +template <typename Element, typename Translator, typename Tag, size_t Corner, size_t AxisIndex> +class element_axis_corner_less +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag)); +}; + +template <typename Element, typename Translator, size_t Corner, size_t AxisIndex> +class element_axis_corner_less<Element, Translator, box_tag, Corner, AxisIndex> +{ +public: + element_axis_corner_less(Translator const& tr) + : m_tr(tr) + {} + + bool operator()(Element const& e1, Element const& e2) const + { + return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr)) + < geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr)); + } + +private: + Translator const& m_tr; +}; + +template <typename Element, typename Translator, size_t Corner, size_t AxisIndex> +class element_axis_corner_less<Element, Translator, point_tag, Corner, AxisIndex> +{ +public: + element_axis_corner_less(Translator const& tr) + : m_tr(tr) + {} + + bool operator()(Element const& e1, Element const& e2) const + { + return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr)) + < geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr)); + } + +private: + Translator const& m_tr; +}; + +template <typename Parameters, typename Box, size_t Corner, size_t AxisIndex> +struct choose_split_axis_and_index_for_corner +{ + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Elements, typename Translator> + static inline void apply(Elements const& elements, + size_t & choosen_index, + margin_type & sum_of_margins, + content_type & smallest_overlap, + content_type & smallest_content, + Parameters const& parameters, + Translator const& translator) + { + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename tag<indexable_type>::type indexable_tag; + + BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements"); + + // copy elements + Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy) + + // sort elements + element_axis_corner_less<element_type, Translator, indexable_tag, Corner, AxisIndex> elements_less(translator); + std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) + + // init outputs + choosen_index = parameters.get_min_elements(); + sum_of_margins = 0; + smallest_overlap = (std::numeric_limits<content_type>::max)(); + smallest_content = (std::numeric_limits<content_type>::max)(); + + // calculate sum of margins for all distributions + size_t index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2; + for ( size_t i = parameters.get_min_elements() ; i < index_last ; ++i ) + { + // TODO - awulkiew: may be optimized - box of group 1 may be initialized with + // box of min_elems number of elements and expanded for each iteration by another element + + Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i, translator); + Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(), translator); + + sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2); + + content_type ovl = index::detail::intersection_content(box1, box2); + content_type con = index::detail::content(box1) + index::detail::content(box2); + + // TODO - shouldn't here be < instead of <= ? + if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) ) + { + choosen_index = i; + smallest_overlap = ovl; + smallest_content = con; + } + } + + ::boost::ignore_unused_variable_warning(parameters); + } +}; + +template <typename Parameters, typename Box, size_t AxisIndex, typename ElementIndexableTag> +struct choose_split_axis_and_index_for_axis +{ + BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (ElementIndexableTag)); +}; + +template <typename Parameters, typename Box, size_t AxisIndex> +struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, box_tag> +{ + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Elements, typename Translator> + static inline void apply(Elements const& elements, + size_t & choosen_corner, + size_t & choosen_index, + margin_type & sum_of_margins, + content_type & smallest_overlap, + content_type & smallest_content, + Parameters const& parameters, + Translator const& translator) + { + size_t index1 = 0; + margin_type som1 = 0; + content_type ovl1 = (std::numeric_limits<content_type>::max)(); + content_type con1 = (std::numeric_limits<content_type>::max)(); + + choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>:: + apply(elements, index1, + som1, ovl1, con1, + parameters, translator); // MAY THROW, STRONG + + size_t index2 = 0; + margin_type som2 = 0; + content_type ovl2 = (std::numeric_limits<content_type>::max)(); + content_type con2 = (std::numeric_limits<content_type>::max)(); + + choose_split_axis_and_index_for_corner<Parameters, Box, max_corner, AxisIndex>:: + apply(elements, index2, + som2, ovl2, con2, + parameters, translator); // MAY THROW, STRONG + + sum_of_margins = som1 + som2; + + if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) ) + { + choosen_corner = min_corner; + choosen_index = index1; + smallest_overlap = ovl1; + smallest_content = con1; + } + else + { + choosen_corner = max_corner; + choosen_index = index2; + smallest_overlap = ovl2; + smallest_content = con2; + } + } +}; + +template <typename Parameters, typename Box, size_t AxisIndex> +struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, point_tag> +{ + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Elements, typename Translator> + static inline void apply(Elements const& elements, + size_t & choosen_corner, + size_t & choosen_index, + margin_type & sum_of_margins, + content_type & smallest_overlap, + content_type & smallest_content, + Parameters const& parameters, + Translator const& translator) + { + choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>:: + apply(elements, choosen_index, + sum_of_margins, smallest_overlap, smallest_content, + parameters, translator); // MAY THROW, STRONG + + choosen_corner = min_corner; + } +}; + +template <typename Parameters, typename Box, size_t Dimension> +struct choose_split_axis_and_index +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Elements, typename Translator> + static inline void apply(Elements const& elements, + size_t & choosen_axis, + size_t & choosen_corner, + size_t & choosen_index, + margin_type & smallest_sum_of_margins, + content_type & smallest_overlap, + content_type & smallest_content, + Parameters const& parameters, + Translator const& translator) + { + typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type; + + choose_split_axis_and_index<Parameters, Box, Dimension - 1>:: + apply(elements, choosen_axis, choosen_corner, choosen_index, + smallest_sum_of_margins, smallest_overlap, smallest_content, + parameters, translator); // MAY THROW, STRONG + + margin_type sum_of_margins = 0; + + size_t corner = min_corner; + size_t index = 0; + + content_type overlap_val = (std::numeric_limits<content_type>::max)(); + content_type content_val = (std::numeric_limits<content_type>::max)(); + + choose_split_axis_and_index_for_axis< + Parameters, + Box, + Dimension - 1, + typename tag<element_indexable_type>::type + >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG + + if ( sum_of_margins < smallest_sum_of_margins ) + { + choosen_axis = Dimension - 1; + choosen_corner = corner; + choosen_index = index; + smallest_sum_of_margins = sum_of_margins; + smallest_overlap = overlap_val; + smallest_content = content_val; + } + } +}; + +template <typename Parameters, typename Box> +struct choose_split_axis_and_index<Parameters, Box, 1> +{ + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Elements, typename Translator> + static inline void apply(Elements const& elements, + size_t & choosen_axis, + size_t & choosen_corner, + size_t & choosen_index, + margin_type & smallest_sum_of_margins, + content_type & smallest_overlap, + content_type & smallest_content, + Parameters const& parameters, + Translator const& translator) + { + typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type; + + choosen_axis = 0; + + choose_split_axis_and_index_for_axis< + Parameters, + Box, + 0, + typename tag<element_indexable_type>::type + >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW + } +}; + +template <size_t Corner, size_t Dimension> +struct partial_sort +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + template <typename Elements, typename Translator> + static inline void apply(Elements & elements, const size_t axis, const size_t index, Translator const& tr) + { + if ( axis < Dimension - 1 ) + { + partial_sort<Corner, Dimension - 1>::apply(elements, axis, index, tr); // MAY THROW, BASIC (copy) + } + else + { + BOOST_GEOMETRY_INDEX_ASSERT(axis == Dimension - 1, "unexpected axis value"); + + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename tag<indexable_type>::type indexable_tag; + + element_axis_corner_less<element_type, Translator, indexable_tag, Corner, Dimension - 1> less(tr); + std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + } + } +}; + +template <size_t Corner> +struct partial_sort<Corner, 1> +{ + template <typename Elements, typename Translator> + static inline void apply(Elements & elements, + const size_t BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(axis), + const size_t index, + Translator const& tr) + { + BOOST_GEOMETRY_INDEX_ASSERT(axis == 0, "unexpected axis value"); + + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef typename tag<indexable_type>::type indexable_tag; + + element_axis_corner_less<element_type, Translator, indexable_tag, Corner, 0> less(tr); + std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + } +}; + +} // namespace rstar + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_tag> +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Options::parameters_type parameters_type; + + static const size_t dimension = geometry::dimension<Box>::value; + + typedef typename index::detail::default_margin_result<Box>::type margin_type; + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Node> + static inline void apply( + Node & n, + Node & second_node, + Box & box1, + Box & box2, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + { + typedef typename rtree::elements_type<Node>::type elements_type; + + elements_type & elements1 = rtree::elements(n); + elements_type & elements2 = rtree::elements(second_node); + + size_t split_axis = 0; + size_t split_corner = 0; + size_t split_index = parameters.get_min_elements(); + margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)(); + content_type smallest_overlap = (std::numeric_limits<content_type>::max)(); + content_type smallest_content = (std::numeric_limits<content_type>::max)(); + + rstar::choose_split_axis_and_index< + typename Options::parameters_type, + Box, + dimension + >::apply(elements1, + split_axis, split_corner, split_index, + smallest_sum_of_margins, smallest_overlap, smallest_content, + parameters, translator); // MAY THROW, STRONG + + // TODO: awulkiew - get rid of following static_casts? + + BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value"); + BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value"); + BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value"); + + // copy original elements + elements_type elements_copy(elements1); // MAY THROW, STRONG + elements_type elements_backup(elements1); // MAY THROW, STRONG + + // TODO: awulkiew - check if std::partial_sort produces the same result as std::sort + if ( split_corner == static_cast<size_t>(min_corner) ) + rstar::partial_sort<min_corner, dimension> + ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy) + else + rstar::partial_sort<max_corner, dimension> + ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy) + + BOOST_TRY + { + // copy elements to nodes + elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC + elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC + + // calculate boxes + box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(), translator); + box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(), translator); + } + BOOST_CATCH(...) + { + //elements_copy.clear(); + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators); + //elements_backup.clear(); + + BOOST_RETHROW // RETHROW, BASIC + } + BOOST_CATCH_END + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP diff --git a/boost/geometry/index/detail/rtree/rstar/rstar.hpp b/boost/geometry/index/detail/rtree/rstar/rstar.hpp new file mode 100644 index 000000000..ed3959c89 --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/rstar.hpp @@ -0,0 +1,18 @@ +// Boost.Geometry Index +// +// R-tree R*-tree algorithm implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP + +#include <boost/geometry/index/detail/rtree/rstar/insert.hpp> +#include <boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp> +#include <boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp> + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp b/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp new file mode 100644 index 000000000..f283c3e5b --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp @@ -0,0 +1,140 @@ +// Boost.Geometry Index +// +// R-tree boxes validating visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/index/detail/rtree/node/node.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities { + +namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class are_boxes_ok + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + +public: + are_boxes_ok(Translator const& tr, bool exact_match) + : result(false), m_tr(tr), m_is_root(true), m_exact_match(exact_match) + {} + + void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + if (elements.empty()) + { + result = false; + return; + } + + Box box_bckup = m_box; + bool is_root_bckup = m_is_root; + + m_is_root = false; + + for ( typename elements_type::const_iterator it = elements.begin(); + it != elements.end() ; ++it) + { + m_box = it->first; + + rtree::apply_visitor(*this, *it->second); + + if ( result == false ) + return; + } + + m_box = box_bckup; + m_is_root = is_root_bckup; + + Box box_exp; + geometry::convert(elements.front().first, box_exp); + for( typename elements_type::const_iterator it = elements.begin() + 1; + it != elements.end() ; ++it) + { + geometry::expand(box_exp, it->first); + } + + if ( m_exact_match ) + result = m_is_root || geometry::equals(box_exp, m_box); + else + result = m_is_root || geometry::covered_by(box_exp, m_box); + } + + void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // non-root node + if (!m_is_root) + { + if ( elements.empty() ) + { + result = false; + return; + } + + Box box_exp; + geometry::convert(m_tr(elements.front()), box_exp); + for(typename elements_type::const_iterator it = elements.begin() + 1; + it != elements.end() ; ++it) + { + geometry::expand(box_exp, m_tr(*it)); + } + + if ( m_exact_match ) + result = geometry::equals(box_exp, m_box); + else + result = geometry::covered_by(box_exp, m_box); + } + else + result = true; + } + + bool result; + +private: + Translator const& m_tr; + Box m_box; + bool m_is_root; + bool m_exact_match; +}; + +} // namespace visitors + +template <typename Rtree> inline +bool are_boxes_ok(Rtree const& tree, bool exact_match = true) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + visitors::are_boxes_ok< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::translator_type, + typename RTV::box_type, + typename RTV::allocators_type + > v(rtv.translator(), exact_match); + + rtv.apply_visitor(v); + + return v.result; +} + +}}}}}} // namespace boost::geometry::index::detail::rtree::utilities + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp b/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp new file mode 100644 index 000000000..4860dbcb9 --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp @@ -0,0 +1,109 @@ +// Boost.Geometry Index +// +// R-tree levels validating visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP + +#include <boost/geometry/index/detail/rtree/node/node.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities { + +namespace visitors { + +template <typename Value, typename Options, typename Box, typename Allocators> +class are_levels_ok + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + +public: + inline are_levels_ok() + : result(true), m_leafs_level((std::numeric_limits<size_t>::max)()), m_current_level(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + if (elements.empty()) + { + result = false; + return; + } + + size_t current_level_backup = m_current_level; + ++m_current_level; + + for ( typename elements_type::const_iterator it = elements.begin(); + it != elements.end() ; ++it) + { + rtree::apply_visitor(*this, *it->second); + + if ( result == false ) + return; + } + + m_current_level = current_level_backup; + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // empty leaf in non-root node + if (0 < m_current_level && elements.empty()) + { + result = false; + return; + } + + if ( m_leafs_level == (std::numeric_limits<size_t>::max)() ) + { + m_leafs_level = m_current_level; + } + else if ( m_leafs_level != m_current_level ) + { + result = false; + } + } + + bool result; + +private: + size_t m_leafs_level; + size_t m_current_level; +}; + +} // namespace visitors + +template <typename Rtree> inline +bool are_levels_ok(Rtree const& tree) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + visitors::are_levels_ok< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::box_type, + typename RTV::allocators_type + > v; + + rtv.apply_visitor(v); + + return v.result; +} + +}}}}}} // namespace boost::geometry::index::detail::rtree::utilities + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp b/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp new file mode 100644 index 000000000..7072a1879 --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp @@ -0,0 +1,223 @@ +// Boost.Geometry Index +// +// R-tree OpenGL drawing visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace utilities { + +namespace dispatch { + +template <typename Point, size_t Dimension> +struct gl_draw_point +{}; + +template <typename Point> +struct gl_draw_point<Point, 2> +{ + static inline void apply(Point const& p, typename coordinate_type<Point>::type z) + { + glBegin(GL_POINT); + glVertex3f(geometry::get<0>(p), geometry::get<1>(p), z); + glEnd(); + } +}; + +template <typename Box, size_t Dimension> +struct gl_draw_box +{}; + +template <typename Box> +struct gl_draw_box<Box, 2> +{ + static inline void apply(Box const& b, typename coordinate_type<Box>::type z) + { + glBegin(GL_LINE_LOOP); + glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<min_corner, 1>(b), z); + glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<min_corner, 1>(b), z); + glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<max_corner, 1>(b), z); + glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<max_corner, 1>(b), z); + glEnd(); + } +}; + +template <typename Indexable, typename Tag> +struct gl_draw_indexable +{ +}; + +template <typename Indexable> +struct gl_draw_indexable<Indexable, box_tag> +{ + static const size_t dimension = dimension<Indexable>::value; + + static inline void apply(Indexable const& i, typename coordinate_type<Indexable>::type z) + { + gl_draw_box<Indexable, dimension>::apply(i, z); + } +}; + +template <typename Indexable> +struct gl_draw_indexable<Indexable, point_tag> +{ + static const size_t dimension = dimension<Indexable>::value; + + static inline void apply(Indexable const& i, typename coordinate_type<Indexable>::type z) + { + gl_draw_point<Indexable, dimension>::apply(i, z); + } +}; + +} // namespace dispatch + +template <typename Indexable> inline +void gl_draw_indexable(Indexable const& i, typename coordinate_type<Indexable>::type z) +{ + dispatch::gl_draw_indexable< + Indexable, + typename tag<Indexable>::type + >::apply(i, z); +} + +} // namespace utilities + +namespace rtree { namespace utilities { + +namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct gl_draw : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline gl_draw(Translator const& t, + size_t level_first = 0, + size_t level_last = (std::numeric_limits<size_t>::max)(), + typename coordinate_type<Box>::type z_coord_level_multiplier = 1 + ) + : tr(t) + , level_f(level_first) + , level_l(level_last) + , z_mul(z_coord_level_multiplier) + , level(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + if ( level_f <= level ) + { + size_t level_rel = level - level_f; + + if ( level_rel == 0 ) + glColor3f(0.75f, 0.0f, 0.0f); + else if ( level_rel == 1 ) + glColor3f(0.0f, 0.75f, 0.0f); + else if ( level_rel == 2 ) + glColor3f(0.0f, 0.0f, 0.75f); + else if ( level_rel == 3 ) + glColor3f(0.75f, 0.75f, 0.0f); + else if ( level_rel == 4 ) + glColor3f(0.75f, 0.0f, 0.75f); + else if ( level_rel == 5 ) + glColor3f(0.0f, 0.75f, 0.75f); + else + glColor3f(0.5f, 0.5f, 0.5f); + + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + detail::utilities::gl_draw_indexable(it->first, level_rel * z_mul); + } + } + + size_t level_backup = level; + ++level; + + if ( level < level_l ) + { + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + rtree::apply_visitor(*this, *it->second); + } + } + + level = level_backup; + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + if ( level_f <= level ) + { + size_t level_rel = level - level_f; + + glColor3f(0.25f, 0.25f, 0.25f); + + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + detail::utilities::gl_draw_indexable(tr(*it), level_rel * z_mul); + } + } + } + + Translator const& tr; + size_t level_f; + size_t level_l; + typename coordinate_type<Box>::type z_mul; + + size_t level; +}; + +} // namespace visitors + +template <typename Rtree> inline +void gl_draw(Rtree const& tree, + size_t level_first = 0, + size_t level_last = (std::numeric_limits<size_t>::max)(), + typename coordinate_type< + typename Rtree::bounds_type + >::type z_coord_level_multiplier = 1 + ) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + if ( !tree.empty() ) + { + glColor3f(0.75f, 0.75f, 0.75f); + detail::utilities::gl_draw_indexable(tree.bounds(), 0); + } + + visitors::gl_draw< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::translator_type, + typename RTV::box_type, + typename RTV::allocators_type + > gl_draw_v(rtv.translator(), level_first, level_last, z_coord_level_multiplier); + + rtv.apply_visitor(gl_draw_v); +} + +}} // namespace rtree::utilities + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/print.hpp b/boost/geometry/index/detail/rtree/utilities/print.hpp new file mode 100644 index 000000000..f7d503a7d --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/print.hpp @@ -0,0 +1,203 @@ +// Boost.Geometry Index +// +// R-tree ostreaming visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP + +#include <iostream> + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace utilities { + +namespace dispatch { + +template <typename Point, size_t Dimension> +struct print_point +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + static inline void apply(std::ostream & os, Point const& p) + { + print_point<Point, Dimension - 1>::apply(os, p); + + os << ", " << geometry::get<Dimension - 1>(p); + } +}; + +template <typename Point> +struct print_point<Point, 1> +{ + static inline void apply(std::ostream & os, Point const& p) + { + os << geometry::get<0>(p); + } +}; + +template <typename Box, size_t Corner, size_t Dimension> +struct print_corner +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + static inline void apply(std::ostream & os, Box const& b) + { + print_corner<Box, Corner, Dimension - 1>::apply(os, b); + + os << ", " << geometry::get<Corner, Dimension - 1>(b); + } +}; + +template <typename Box, size_t Corner> +struct print_corner<Box, Corner, 1> +{ + static inline void apply(std::ostream & os, Box const& b) + { + os << geometry::get<Corner, 0>(b); + } +}; + +template <typename Indexable, typename Tag> +struct print_indexable +{ +}; + +template <typename Indexable> +struct print_indexable<Indexable, box_tag> +{ + static const size_t dimension = dimension<Indexable>::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_corner<Indexable, min_corner, dimension>::apply(os, i); + os << ")x("; + print_corner<Indexable, max_corner, dimension>::apply(os, i); + os << ')'; + } +}; + +template <typename Indexable> +struct print_indexable<Indexable, point_tag> +{ + static const size_t dimension = dimension<Indexable>::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_point<Indexable, dimension>::apply(os, i); + os << ')'; + } +}; + +} // namespace dispatch + +template <typename Indexable> inline +void print_indexable(std::ostream & os, Indexable const& i) +{ + dispatch::print_indexable< + Indexable, + typename tag<Indexable>::type + >::apply(os, i); +} + +} // namespace utilities + +namespace rtree { namespace utilities { + +namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct print : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline print(std::ostream & o, Translator const& t) + : os(o), tr(t), level(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + spaces(level) << "INTERNAL NODE - L:" << level << " Ch:" << elements.size() << " @:" << &n << '\n'; + + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + spaces(level); + detail::utilities::print_indexable(os, it->first); + os << " ->" << it->second << '\n'; + } + + size_t level_backup = level; + ++level; + + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + rtree::apply_visitor(*this, *it->second); + } + + level = level_backup; + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + spaces(level) << "LEAF - L:" << level << " V:" << elements.size() << " @:" << &n << '\n'; + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + spaces(level); + detail::utilities::print_indexable(os, tr(*it)); + os << '\n'; + } + } + + inline std::ostream & spaces(size_t level) + { + for ( size_t i = 0 ; i < 2 * level ; ++i ) + os << ' '; + return os; + } + + std::ostream & os; + Translator const& tr; + + size_t level; +}; + +} // namespace visitors + +template <typename Rtree> inline +void print(std::ostream & os, Rtree const& tree) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + visitors::print< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::translator_type, + typename RTV::box_type, + typename RTV::allocators_type + > print_v(os, rtv.translator()); + rtv.apply_visitor(print_v); +} + +}} // namespace rtree::utilities + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/statistics.hpp b/boost/geometry/index/detail/rtree/utilities/statistics.hpp new file mode 100644 index 000000000..c8e420d91 --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/statistics.hpp @@ -0,0 +1,105 @@ +// Boost.Geometry Index +// +// R-tree visitor collecting basic statistics +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2013 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_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP + +#include <algorithm> +#include <tuple> + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities { + +namespace visitors { + +template <typename Value, typename Options, typename Box, typename Allocators> +struct statistics : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline statistics() + : level(0) + , levels(1) // count root + , nodes(0) + , leaves(0) + , values(0) + , values_min(0) + , values_max(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + ++nodes; // count node + + size_t const level_backup = level; + ++level; + + levels += level++ > levels ? 1 : 0; // count level (root already counted) + + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + rtree::apply_visitor(*this, *it->second); + } + + level = level_backup; + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + ++leaves; // count leaves + + std::size_t const v = elements.size(); + // count values spread per node and total + values_min = (std::min)(values_min == 0 ? v : values_min, v); + values_max = (std::max)(values_max, v); + values += v; + } + + std::size_t level; + std::size_t levels; + std::size_t nodes; + std::size_t leaves; + std::size_t values; + std::size_t values_min; + std::size_t values_max; +}; + +} // namespace visitors + +template <typename Rtree> inline +boost::tuple<std::size_t, std::size_t, std::size_t, std::size_t, std::size_t, std::size_t> +statistics(Rtree const& tree) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + visitors::statistics< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::box_type, + typename RTV::allocators_type + > stats_v; + + rtv.apply_visitor(stats_v); + + return boost::make_tuple(stats_v.levels, stats_v.nodes, stats_v.leaves, stats_v.values, stats_v.values_min, stats_v.values_max); +} + +}}}}}} // namespace boost::geometry::index::detail::rtree::utilities + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP diff --git a/boost/geometry/index/detail/rtree/utilities/view.hpp b/boost/geometry/index/detail/rtree/utilities/view.hpp new file mode 100644 index 000000000..6dbbd07bf --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/view.hpp @@ -0,0 +1,61 @@ +// Boost.Geometry Index +// +// Rtree utilities view +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace utilities { + +template <typename Rtree> +class view +{ +public: + typedef typename Rtree::size_type size_type; + + typedef typename Rtree::translator_type translator_type; + typedef typename Rtree::value_type value_type; + typedef typename Rtree::options_type options_type; + typedef typename Rtree::box_type box_type; + typedef typename Rtree::allocators_type allocators_type; + + view(Rtree const& rt) : m_rtree(rt) {} + + template <typename Visitor> + void apply_visitor(Visitor & vis) const + { + m_rtree.apply_visitor(vis); + } + + // This will most certainly be removed in the future + translator_type translator() const + { + return m_rtree.translator(); + } + + // This will probably be removed in the future + size_type depth() const + { + return m_rtree.depth(); + } + +private: + view(view const&); + view & operator=(view const&); + + Rtree const& m_rtree; +}; + +}}} // namespace detail::rtree::utilities + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/children_box.hpp b/boost/geometry/index/detail/rtree/visitors/children_box.hpp new file mode 100644 index 000000000..93726063b --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/children_box.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry Index +// +// R-tree node children box calculating visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class children_box + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + +public: + inline children_box(Box & result, Translator const& tr) + : m_result(result), m_tr(tr) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + m_result = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr); + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + m_result = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr); + } + +private: + Box & m_result; + Translator const& m_tr; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/copy.hpp b/boost/geometry/index/detail/rtree/visitors/copy.hpp new file mode 100644 index 000000000..8fc25ac80 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/copy.hpp @@ -0,0 +1,92 @@ +// Boost.Geometry Index +// +// R-tree deep copying visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class copy + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type +{ +public: + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + typedef typename Allocators::node_pointer node_pointer; + + explicit inline copy(Allocators & allocators) + : result(0) + , m_allocators(allocators) + {} + + inline void operator()(internal_node & n) + { + node_pointer raw_new_node = rtree::create_node<Allocators, internal_node>::apply(m_allocators); // MAY THROW, STRONG (N: alloc) + node_auto_ptr new_node(raw_new_node, m_allocators); + + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type & elements = rtree::elements(n); + + elements_type & elements_dst = rtree::elements(rtree::get<internal_node>(*new_node)); + + for (typename elements_type::iterator it = elements.begin(); + it != elements.end(); ++it) + { + rtree::apply_visitor(*this, *it->second); // MAY THROW (V, E: alloc, copy, N: alloc) + + // for exception safety + node_auto_ptr auto_result(result, m_allocators); + + elements_dst.push_back( rtree::make_ptr_pair(it->first, result) ); // MAY THROW, STRONG (E: alloc, copy) + + auto_result.release(); + } + + result = new_node.get(); + new_node.release(); + } + + inline void operator()(leaf & l) + { + node_pointer raw_new_node = rtree::create_node<Allocators, leaf>::apply(m_allocators); // MAY THROW, STRONG (N: alloc) + node_auto_ptr new_node(raw_new_node, m_allocators); + + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type & elements = rtree::elements(l); + + elements_type & elements_dst = rtree::elements(rtree::get<leaf>(*new_node)); + + for (typename elements_type::iterator it = elements.begin(); + it != elements.end(); ++it) + { + elements_dst.push_back(*it); // MAY THROW, STRONG (V: alloc, copy) + } + + result = new_node.get(); + new_node.release(); + } + + node_pointer result; + +private: + Allocators & m_allocators; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/count.hpp b/boost/geometry/index/detail/rtree/visitors/count.hpp new file mode 100644 index 000000000..203422f33 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/count.hpp @@ -0,0 +1,118 @@ +// Boost.Geometry Index +// +// R-tree count visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Indexable, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct count + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline count(Indexable const& i, Translator const& t) + : indexable(i), tr(t), found_count(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // traverse nodes meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + if ( geometry::covered_by(indexable, it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // get all values meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if value meets predicates + if ( geometry::equals(indexable, tr(*it)) ) + { + ++found_count; + } + } + } + + Indexable const& indexable; + Translator const& tr; + typename Allocators::size_type found_count; +}; + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +struct count<Value, Value, Options, Translator, Box, Allocators> + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline count(Value const& v, Translator const& t) + : value(v), tr(t), found_count(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // traverse nodes meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + if ( geometry::covered_by(tr(value), it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // get all values meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if value meets predicates + if ( tr.equals(value, *it) ) + { + ++found_count; + } + } + } + + Value const& value; + Translator const& tr; + typename Allocators::size_type found_count; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/destroy.hpp b/boost/geometry/index/detail/rtree/visitors/destroy.hpp new file mode 100644 index 000000000..62722b97a --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/destroy.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry Index +// +// R-tree destroying visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class destroy + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type +{ +public: + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Allocators::node_pointer node_pointer; + + inline destroy(node_pointer root_node, Allocators & allocators) + : m_current_node(root_node) + , m_allocators(allocators) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_current_node), "invalid pointers"); + + node_pointer node_to_destroy = m_current_node; + + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type & elements = rtree::elements(n); + + for (typename elements_type::iterator it = elements.begin(); + it != elements.end(); ++it) + { + m_current_node = it->second; + rtree::apply_visitor(*this, *m_current_node); + it->second = 0; + } + + rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, node_to_destroy); + } + + inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(l)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&l == &rtree::get<leaf>(*m_current_node), "invalid pointers"); + + rtree::destroy_node<Allocators, leaf>::apply(m_allocators, m_current_node); + } + +private: + node_pointer m_current_node; + Allocators & m_allocators; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/distance_query.hpp b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp new file mode 100644 index 000000000..616150222 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -0,0 +1,540 @@ +// Boost.Geometry Index +// +// R-tree distance (knn, path, etc. ) query visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Translator, typename DistanceType, typename OutIt> +class distance_query_result +{ +public: + typedef DistanceType distance_type; + + inline explicit distance_query_result(size_t k, OutIt out_it) + : m_count(k), m_out_it(out_it) + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0"); + + m_neighbors.reserve(m_count); + } + + inline void store(Value const& val, distance_type const& curr_comp_dist) + { + if ( m_neighbors.size() < m_count ) + { + m_neighbors.push_back(std::make_pair(curr_comp_dist, val)); + + if ( m_neighbors.size() == m_count ) + std::make_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + } + else + { + if ( curr_comp_dist < m_neighbors.front().first ) + { + std::pop_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + m_neighbors.back().first = curr_comp_dist; + m_neighbors.back().second = val; + std::push_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less); + } + } + } + + inline bool has_enough_neighbors() const + { + return m_count <= m_neighbors.size(); + } + + inline distance_type greatest_comparable_distance() const + { + // greatest distance is in the first neighbor only + // if there is at least m_count values found + // this is just for safety reasons since is_comparable_distance_valid() is checked earlier + // TODO - may be replaced by ASSERT + return m_neighbors.size() < m_count + ? (std::numeric_limits<distance_type>::max)() + : m_neighbors.front().first; + } + + inline size_t finish() + { + typedef typename std::vector< std::pair<distance_type, Value> >::const_iterator neighbors_iterator; + for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it ) + *m_out_it = it->second; + + return m_neighbors.size(); + } + +private: + inline static bool neighbors_less( + std::pair<distance_type, Value> const& p1, + std::pair<distance_type, Value> const& p2) + { + return p1.first < p2.first; + } + + size_t m_count; + OutIt m_out_it; + + std::vector< std::pair<distance_type, Value> > m_neighbors; +}; + +template < + typename Value, + typename Options, + typename Translator, + typename Box, + typename Allocators, + typename Predicates, + unsigned DistancePredicateIndex, + typename OutIter +> +class distance_query + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ +public: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access; + typedef typename nearest_predicate_access::type nearest_predicate_type; + typedef typename indexable_type<Translator>::type indexable_type; + + typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance; + typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance; + typedef typename calculate_value_distance::result_type value_distance_type; + typedef typename calculate_node_distance::result_type node_distance_type; + + static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value; + + inline distance_query(parameters_type const& parameters, Translator const& translator, Predicates const& pred, OutIter out_it) + : m_parameters(parameters), m_translator(translator) + , m_pred(pred) + , m_result(nearest_predicate_access::get(m_pred).count, out_it) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + + // array of active nodes + typedef typename index::detail::rtree::container_from_elements_type< + elements_type, + std::pair<node_distance_type, typename Allocators::node_pointer> + >::type active_branch_list_type; + + active_branch_list_type active_branch_list; + active_branch_list.reserve(m_parameters.get_max_elements()); + + elements_type const& elements = rtree::elements(n); + + // fill array of nodes meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if current node meets predicates + // 0 - dummy value + if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) ) + { + // calculate node's distance(s) for distance predicate + node_distance_type node_distance; + // if distance isn't ok - move to the next node + if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) ) + { + continue; + } + + // if current node is further than found neighbors - don't analyze it + if ( m_result.has_enough_neighbors() && + is_node_prunable(m_result.greatest_comparable_distance(), node_distance) ) + { + continue; + } + + // add current node's data into the list + active_branch_list.push_back( std::make_pair(node_distance, it->second) ); + } + } + + // if there aren't any nodes in ABL - return + if ( active_branch_list.empty() ) + return; + + // sort array + std::sort(active_branch_list.begin(), active_branch_list.end(), abl_less); + + // recursively visit nodes + for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin(); + it != active_branch_list.end() ; ++it ) + { + // if current node is further than furthest neighbor, the rest of nodes also will be further + if ( m_result.has_enough_neighbors() && + is_node_prunable(m_result.greatest_comparable_distance(), it->first) ) + break; + + rtree::apply_visitor(*this, *(it->second)); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // search leaf for closest value meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if value meets predicates + if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, m_translator(*it)) ) + { + // calculate values distance for distance predicate + value_distance_type value_distance; + // if distance is ok + if ( calculate_value_distance::apply(predicate(), m_translator(*it), value_distance) ) + { + // store value + m_result.store(*it, value_distance); + } + } + } + } + + inline size_t finish() + { + return m_result.finish(); + } + +private: + static inline bool abl_less( + std::pair<node_distance_type, typename Allocators::node_pointer> const& p1, + std::pair<node_distance_type, typename Allocators::node_pointer> const& p2) + { + return p1.first < p2.first; + } + + template <typename Distance> + static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d) + { + return greatest_dist <= d; + } + + nearest_predicate_type const& predicate() const + { + return nearest_predicate_access::get(m_pred); + } + + parameters_type const& m_parameters; + Translator const& m_translator; + + Predicates m_pred; + distance_query_result<Value, Translator, value_distance_type, OutIter> m_result; +}; + +template < + typename Value, + typename Options, + typename Translator, + typename Box, + typename Allocators, + typename Predicates, + unsigned DistancePredicateIndex +> +class distance_query_incremental + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ +public: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access; + typedef typename nearest_predicate_access::type nearest_predicate_type; + typedef typename indexable_type<Translator>::type indexable_type; + + typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance; + typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance; + typedef typename calculate_value_distance::result_type value_distance_type; + typedef typename calculate_node_distance::result_type node_distance_type; + + typedef typename Allocators::size_type size_type; + typedef typename Allocators::const_reference const_reference; + typedef typename Allocators::node_pointer node_pointer; + + static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value; + + typedef typename rtree::elements_type<internal_node>::type internal_elements; + typedef typename internal_elements::const_iterator internal_iterator; + typedef typename rtree::elements_type<leaf>::type leaf_elements; + + typedef std::pair<node_distance_type, node_pointer> branch_data; + typedef typename index::detail::rtree::container_from_elements_type< + internal_elements, branch_data + >::type active_branch_list_type; + struct internal_stack_element + { + internal_stack_element() : current_branch(0) {} +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + // Required in c++03 for containers using Boost.Move + internal_stack_element & operator=(internal_stack_element const& o) + { + branches = o.branches; + current_branch = o.current_branch; + return *this; + } +#endif + active_branch_list_type branches; + typename active_branch_list_type::size_type current_branch; + }; + typedef std::vector<internal_stack_element> internal_stack_type; + + inline distance_query_incremental(Translator const& translator, Predicates const& pred) + : m_translator(::boost::addressof(translator)) + , m_pred(pred) + , current_neighbor((std::numeric_limits<size_type>::max)()) + + , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)()) + { + BOOST_ASSERT_MSG(0 < max_count(), "k must be greather than 0"); + } + + const_reference dereference() const + { + return *(neighbors[current_neighbor].second); + } + + void increment() + { + for (;;) + { + size_type new_neighbor = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1; + + if ( internal_stack.empty() ) + { + if ( new_neighbor < neighbors.size() ) + current_neighbor = new_neighbor; + else + { + current_neighbor = (std::numeric_limits<size_type>::max)(); + // clear() is used to disable the condition above + neighbors.clear(); + } + + return; + } + else + { + active_branch_list_type & branches = internal_stack.back().branches; + typename active_branch_list_type::size_type & current_branch = internal_stack.back().current_branch; + + if ( branches.size() <= current_branch ) + { + internal_stack.pop_back(); + continue; + } + + // if there are no nodes which can have closer values, set new value + if ( new_neighbor < neighbors.size() && + // here must be < because otherwise neighbours may be sorted in different order + // if there is another value with equal distance + neighbors[new_neighbor].first < next_closest_node_distance ) + { + current_neighbor = new_neighbor; + return; + } + + // if node is further than the furthest neighbour, following nodes also will be further + BOOST_ASSERT_MSG(neighbors.size() <= max_count(), "unexpected neighbours count"); + if ( max_count() <= neighbors.size() && + is_node_prunable(neighbors.back().first, branches[current_branch].first) ) + { + // stop traversing current level + internal_stack.pop_back(); + continue; + } + else + { + // new level - must increment current_branch before traversing of another level (mem reallocation) + ++current_branch; + rtree::apply_visitor(*this, *(branches[current_branch - 1].second)); + + next_closest_node_distance = calc_closest_node_distance(internal_stack.begin(), internal_stack.end()); + } + } + } + } + + bool is_end() const + { + return (std::numeric_limits<size_type>::max)() == current_neighbor; + } + + friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r) + { + BOOST_ASSERT_MSG(l.current_neighbor != r.current_neighbor || + (std::numeric_limits<size_type>::max)() == l.current_neighbor || + l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second, + "not corresponding iterators"); + return l.current_neighbor == r.current_neighbor; + } + + // Put node's elements into the list of active branches if those elements meets predicates + // and distance predicates(currently not used) + // and aren't further than found neighbours (if there is enough neighbours) + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // add new element + internal_stack.resize(internal_stack.size()+1); + + // fill active branch list array of nodes meeting predicates + for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it ) + { + // if current node meets predicates + // 0 - dummy value + if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) ) + { + // calculate node's distance(s) for distance predicate + node_distance_type node_distance; + // if distance isn't ok - move to the next node + if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) ) + { + continue; + } + + // if current node is further than found neighbors - don't analyze it + if ( max_count() <= neighbors.size() && + is_node_prunable(neighbors.back().first, node_distance) ) + { + continue; + } + + // add current node's data into the list + internal_stack.back().branches.push_back( std::make_pair(node_distance, it->second) ); + } + } + + if ( internal_stack.back().branches.empty() ) + internal_stack.pop_back(); + else + // sort array + std::sort(internal_stack.back().branches.begin(), internal_stack.back().branches.end(), abl_less); + } + + // Put values into the list of neighbours if those values meets predicates + // and distance predicates(currently not used) + // and aren't further than already found neighbours (if there is enough neighbours) + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // store distance to the furthest neighbour + bool not_enough_neighbors = neighbors.size() < max_count(); + value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits<value_distance_type>::max)(); + + // search leaf for closest value meeting predicates + for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + { + // if value meets predicates + if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, (*m_translator)(*it)) ) + { + // calculate values distance for distance predicate + value_distance_type value_distance; + // if distance is ok + if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it), value_distance) ) + { + // if there is not enough values or current value is closer than furthest neighbour + if ( not_enough_neighbors || value_distance < greatest_distance ) + { + neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it))); + } + } + } + } + + // sort array + std::sort(neighbors.begin(), neighbors.end(), neighbors_less); + // remove furthest values + if ( max_count() < neighbors.size() ) + neighbors.resize(max_count()); + } + +private: + static inline bool abl_less(std::pair<node_distance_type, typename Allocators::node_pointer> const& p1, + std::pair<node_distance_type, typename Allocators::node_pointer> const& p2) + { + return p1.first < p2.first; + } + + static inline bool neighbors_less(std::pair<value_distance_type, const Value *> const& p1, + std::pair<value_distance_type, const Value *> const& p2) + { + return p1.first < p2.first; + } + + node_distance_type + calc_closest_node_distance(typename internal_stack_type::const_iterator first, + typename internal_stack_type::const_iterator last) + { + node_distance_type result = (std::numeric_limits<node_distance_type>::max)(); + for ( ; first != last ; ++first ) + { + if ( first->branches.size() <= first->current_branch ) + continue; + + node_distance_type curr_dist = first->branches[first->current_branch].first; + if ( curr_dist < result ) + result = curr_dist; + } + return result; + } + + template <typename Distance> + static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d) + { + return greatest_dist <= d; + } + + inline unsigned max_count() const + { + return nearest_predicate_access::get(m_pred).count; + } + + nearest_predicate_type const& predicate() const + { + return nearest_predicate_access::get(m_pred); + } + + const Translator * m_translator; + + Predicates m_pred; + + internal_stack_type internal_stack; + std::vector< std::pair<value_distance_type, const Value *> > neighbors; + size_type current_neighbor; + node_distance_type next_closest_node_distance; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/insert.hpp b/boost/geometry/index/detail/rtree/visitors/insert.hpp new file mode 100644 index 000000000..9ff5f0749 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/insert.hpp @@ -0,0 +1,516 @@ +// Boost.Geometry Index +// +// R-tree inserting visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP + +#include <boost/geometry/index/detail/algorithms/content.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// Default choose_next_node +template <typename Value, typename Options, typename Box, typename Allocators, typename ChooseNextNodeTag> +class choose_next_node; + +template <typename Value, typename Options, typename Box, typename Allocators> +class choose_next_node<Value, Options, Box, Allocators, choose_by_content_diff_tag> +{ +public: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename rtree::elements_type<internal_node>::type children_type; + + typedef typename index::detail::default_content_result<Box>::type content_type; + + template <typename Indexable> + static inline size_t apply(internal_node & n, + Indexable const& indexable, + parameters_type const& /*parameters*/, + size_t /*node_relative_level*/) + { + children_type & children = rtree::elements(n); + + BOOST_GEOMETRY_INDEX_ASSERT(!children.empty(), "can't choose the next node if children are empty"); + + size_t children_count = children.size(); + + // choose index with smallest content change or smallest content + size_t choosen_index = 0; + content_type smallest_content_diff = (std::numeric_limits<content_type>::max)(); + content_type smallest_content = (std::numeric_limits<content_type>::max)(); + + // caculate areas and areas of all nodes' boxes + for ( size_t i = 0 ; i < children_count ; ++i ) + { + typedef typename children_type::value_type child_type; + child_type const& ch_i = children[i]; + + // expanded child node's box + Box box_exp(ch_i.first); + geometry::expand(box_exp, indexable); + + // areas difference + content_type content = index::detail::content(box_exp); + content_type content_diff = content - index::detail::content(ch_i.first); + + // update the result + if ( content_diff < smallest_content_diff || + ( content_diff == smallest_content_diff && content < smallest_content ) ) + { + smallest_content_diff = content_diff; + smallest_content = content; + choosen_index = i; + } + } + + return choosen_index; + } +}; + +// ----------------------------------------------------------------------- // + +// Not implemented here +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename RedistributeTag> +struct redistribute_elements +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_REDISTRIBUTE_TAG_TYPE, + (redistribute_elements)); +}; + +// ----------------------------------------------------------------------- // + +// Split algorithm +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename SplitTag> +class split +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_SPLIT_TAG_TYPE, + (split)); +}; + +// Default split algorithm +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class split<Value, Options, Translator, Box, Allocators, split_default_tag> +{ +protected: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + +public: + typedef index::detail::varray< + typename rtree::elements_type<internal_node>::type::value_type, + 1 + > nodes_container_type; + + template <typename Node> + static inline void apply(nodes_container_type & additional_nodes, + Node & n, + Box & n_box, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + { + // TODO - consider creating nodes always with sufficient memory allocated + + // create additional node, use auto ptr for automatic destruction on exception + node_auto_ptr second_node(rtree::create_node<Allocators, Node>::apply(allocators), allocators); // MAY THROW, STRONG (N: alloc) + // create reference to the newly created node + Node & n2 = rtree::get<Node>(*second_node); + + // NOTE: thread-safety + // After throwing an exception by redistribute_elements the original node may be not changed or + // both nodes may be empty. In both cases the tree won't be valid r-tree. + // The alternative is to create 2 (or more) additional nodes here and store backup info + // in the original node, then, if exception was thrown, the node would always have more than max + // elements. + // The alternative is to use moving semantics in the implementations of redistribute_elements, + // it will be possible to throw from boost::move() in the case of e.g. static size nodes. + + // redistribute elements + Box box2; + redistribute_elements< + Value, + Options, + Translator, + Box, + Allocators, + typename Options::redistribute_tag + >::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V, E: alloc, copy, copy) + + // check numbers of elements + BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() && + rtree::elements(n).size() <= parameters.get_max_elements(), + "unexpected number of elements"); + BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n2).size() && + rtree::elements(n2).size() <= parameters.get_max_elements(), + "unexpected number of elements"); + + // return the list of newly created nodes (this algorithm returns one) + additional_nodes.push_back(rtree::make_ptr_pair(box2, second_node.get())); // MAY THROW, STRONG (alloc, copy) + + // release the ptr + second_node.release(); + } +}; + +// ----------------------------------------------------------------------- // + +namespace visitors { namespace detail { + +template <typename InternalNode, typename InternalNodePtr> +struct insert_traverse_data +{ + typedef typename rtree::elements_type<InternalNode>::type elements_type; + typedef typename elements_type::value_type element_type; + + insert_traverse_data() + : parent(0), current_child_index(0), current_level(0) + {} + + void move_to_next_level(InternalNodePtr new_parent, size_t new_child_index) + { + parent = new_parent; + current_child_index = new_child_index; + ++current_level; + } + + bool current_is_root() const + { + return 0 == parent; + } + + elements_type & parent_elements() const + { + BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer"); + return rtree::elements(*parent); + } + + element_type & current_element() const + { + BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer"); + return rtree::elements(*parent)[current_child_index]; + } + + InternalNodePtr parent; + size_t current_child_index; + size_t current_level; +}; + +// Default insert visitor +template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class insert + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type +{ +protected: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + typedef typename Allocators::node_pointer node_pointer; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + + inline insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level = 0 + ) + : m_element(element) + , m_parameters(parameters) + , m_translator(translator) + , m_relative_level(relative_level) + , m_level(leafs_level - relative_level) + , m_root_node(root) + , m_leafs_level(leafs_level) + , m_traverse_data() + , m_allocators(allocators) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_relative_level <= leafs_level, "unexpected level value"); + BOOST_GEOMETRY_INDEX_ASSERT(m_level <= m_leafs_level, "unexpected level value"); + BOOST_GEOMETRY_INDEX_ASSERT(0 != m_root_node, "there is no root node"); + // TODO + // assert - check if Box is correct + } + + template <typename Visitor> + inline void traverse(Visitor & visitor, internal_node & n) + { + // choose next node + size_t choosen_node_index = rtree::choose_next_node<Value, Options, Box, Allocators, typename Options::choose_next_node_tag>:: + apply(n, rtree::element_indexable(m_element, m_translator), m_parameters, m_leafs_level - m_traverse_data.current_level); + + // expand the node to contain value + geometry::expand( + rtree::elements(n)[choosen_node_index].first, + rtree::element_indexable(m_element, m_translator)); + + // next traversing step + traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW (V, E: alloc, copy, N:alloc) + } + + // TODO: awulkiew - change post_traverse name to handle_overflow or overflow_treatment? + + template <typename Node> + inline void post_traverse(Node &n) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_traverse_data.current_is_root() || + &n == &rtree::get<Node>(*m_traverse_data.current_element().second), + "if node isn't the root current_child_index should be valid"); + + // handle overflow + if ( m_parameters.get_max_elements() < rtree::elements(n).size() ) + { + split(n); // MAY THROW (V, E: alloc, copy, N:alloc) + } + } + + template <typename Visitor> + inline void traverse_apply_visitor(Visitor & visitor, internal_node &n, size_t choosen_node_index) + { + // save previous traverse inputs and set new ones + insert_traverse_data<internal_node, internal_node_pointer> backup_traverse_data = m_traverse_data; + + // calculate new traverse inputs + m_traverse_data.move_to_next_level(&n, choosen_node_index); + + // next traversing step + rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N:alloc) + + // restore previous traverse inputs + m_traverse_data = backup_traverse_data; + } + + // TODO: consider - split result returned as OutIter is faster than reference to the container. Why? + + template <typename Node> + inline void split(Node & n) const + { + typedef rtree::split<Value, Options, Translator, Box, Allocators, typename Options::split_tag> split_algo; + + typename split_algo::nodes_container_type additional_nodes; + Box n_box; + + split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW (V, E: alloc, copy, N:alloc) + + BOOST_GEOMETRY_INDEX_ASSERT(additional_nodes.size() == 1, "unexpected number of additional nodes"); + + // TODO add all additional nodes + // For kmeans algorithm: + // elements number may be greater than node max elements count + // split and reinsert must take node with some elements count + // and container of additional elements (std::pair<Box, node*>s or Values) + // and translator + allocators + // where node_elements_count + additional_elements > node_max_elements_count + // What with elements other than std::pair<Box, node*> ? + // Implement template <node_tag> struct node_element_type or something like that + + // for exception safety + node_auto_ptr additional_node_ptr(additional_nodes[0].second, m_allocators); + + // node is not the root - just add the new node + if ( !m_traverse_data.current_is_root() ) + { + // update old node's box + m_traverse_data.current_element().first = n_box; + // add new node to parent's children + m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW, STRONG (V, E: alloc, copy) + } + // node is the root - add level + else + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*m_root_node), "node should be the root"); + + // create new root and add nodes + node_auto_ptr new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc) + + BOOST_TRY + { + rtree::elements(rtree::get<internal_node>(*new_root)).push_back(rtree::make_ptr_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy) + rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy) + } + BOOST_CATCH(...) + { + // clear new root to not delete in the ~node_auto_ptr() potentially stored old root node + rtree::elements(rtree::get<internal_node>(*new_root)).clear(); + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + + m_root_node = new_root.get(); + ++m_leafs_level; + + new_root.release(); + } + + additional_node_ptr.release(); + } + + // TODO: awulkiew - implement dispatchable split::apply to enable additional nodes creation + + Element const& m_element; + parameters_type const& m_parameters; + Translator const& m_translator; + const size_t m_relative_level; + const size_t m_level; + + node_pointer & m_root_node; + size_t & m_leafs_level; + + // traversing input parameters + insert_traverse_data<internal_node, internal_node_pointer> m_traverse_data; + + Allocators & m_allocators; +}; + +} // namespace detail + +// Insert visitor forward declaration +template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename InsertTag> +class insert; + +// Default insert visitor used for nodes elements +// After passing the Element to insert visitor the Element is managed by the tree +// I.e. one should not delete the node passed to the insert visitor after exception is thrown +// because this visitor may delete it +template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> + : public detail::insert<Element, Value, Options, Translator, Box, Allocators> +{ +public: + typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename Options::parameters_type parameters_type; + typedef typename base::node_pointer node_pointer; + + inline insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level = 0 + ) + : base(root, leafs_level, element, parameters, translator, allocators, relative_level) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level"); + + if ( base::m_traverse_data.current_level < base::m_level ) + { + // next traversing step + base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc) + } + else + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level"); + + BOOST_TRY + { + // push new child node + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy) + } + BOOST_CATCH(...) + { + // if the insert fails above, the element won't be stored in the tree + + rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators); + rtree::apply_visitor(del_v, *base::m_element.second); + + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + } + + base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc) + } + + inline void operator()(leaf &) + { + BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf"); + } +}; + +// Default insert visitor specialized for Values elements +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class insert<Value, Value, Options, Translator, Box, Allocators, insert_default_tag> + : public detail::insert<Value, Value, Options, Translator, Box, Allocators> +{ +public: + typedef detail::insert<Value, Value, Options, Translator, Box, Allocators> base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename Options::parameters_type parameters_type; + typedef typename base::node_pointer node_pointer; + + inline insert(node_pointer & root, + size_t & leafs_level, + Value const& value, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level = 0 + ) + : base(root, leafs_level, value, parameters, translator, allocators, relative_level) + {} + + inline void operator()(internal_node & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level"); + + // next traversing step + base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc) + + base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc) + } + + inline void operator()(leaf & n) + { + BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level, "unexpected level"); + BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level || + base::m_level == (std::numeric_limits<size_t>::max)(), "unexpected level"); + + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy) + + base::post_traverse(n); // MAY THROW (V: alloc, copy, N: alloc) + } +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp new file mode 100644 index 000000000..6d21afd99 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp @@ -0,0 +1,41 @@ +// Boost.Geometry Index +// +// R-tree leaf node checking visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Options, typename Box, typename Allocators> +struct is_leaf : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + inline void operator()(internal_node const&) + { + result = false; + } + + inline void operator()(leaf const&) + { + result = true; + } + + bool result; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/remove.hpp b/boost/geometry/index/detail/rtree/visitors/remove.hpp new file mode 100644 index 000000000..5b77b5acb --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/remove.hpp @@ -0,0 +1,316 @@ +// Boost.Geometry Index +// +// R-tree removing visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP + +#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +// Default remove algorithm +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class remove + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + typedef typename Allocators::node_pointer node_pointer; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + +public: + inline remove(node_pointer & root, + size_t & leafs_level, + Value const& value, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators) + : m_value(value) + , m_parameters(parameters) + , m_translator(translator) + , m_allocators(allocators) + , m_root_node(root) + , m_leafs_level(leafs_level) + , m_is_value_removed(false) + , m_parent(0) + , m_current_child_index(0) + , m_current_level(0) + , m_is_underflow(false) + { + // TODO + // assert - check if Value/Box is correct + } + + inline void operator()(internal_node & n) + { + typedef typename rtree::elements_type<internal_node>::type children_type; + children_type & children = rtree::elements(n); + + // traverse children which boxes intersects value's box + size_t child_node_index = 0; + for ( ; child_node_index < children.size() ; ++child_node_index ) + { + if ( geometry::covered_by(m_translator(m_value), children[child_node_index].first) ) + { + // next traversing step + traverse_apply_visitor(n, child_node_index); // MAY THROW + + if ( m_is_value_removed ) + break; + } + } + + // value was found and removed + if ( m_is_value_removed ) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + typedef typename elements_type::iterator element_iterator; + elements_type & elements = rtree::elements(n); + + // underflow occured - child node should be removed + if ( m_is_underflow ) + { + element_iterator underfl_el_it = elements.begin() + child_node_index; + size_t relative_level = m_leafs_level - m_current_level; + + // move node to the container - store node's relative level as well and return new underflow state + m_is_underflow = store_underflowed_node(elements, underfl_el_it, relative_level); // MAY THROW (E: alloc, copy) + } + + // n is not root - adjust aabb + if ( 0 != m_parent ) + { + // underflow state should be ok here + // note that there may be less than min_elems elements in root + // so this condition should be checked only here + BOOST_GEOMETRY_INDEX_ASSERT((elements.size() < m_parameters.get_min_elements()) == m_is_underflow, "unexpected state"); + + rtree::elements(*m_parent)[m_current_child_index].first + = rtree::elements_box<Box>(elements.begin(), elements.end(), m_translator); + } + // n is root node + else + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root_node), "node must be the root"); + + // reinsert elements from removed nodes (underflows) + reinsert_removed_nodes_elements(); // MAY THROW (V, E: alloc, copy, N: alloc) + + // shorten the tree + if ( rtree::elements(n).size() == 1 ) + { + node_pointer root_to_destroy = m_root_node; + m_root_node = rtree::elements(n)[0].second; + --m_leafs_level; + + rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, root_to_destroy); + } + } + } + } + + inline void operator()(leaf & n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type & elements = rtree::elements(n); + + // find value and remove it + for ( typename elements_type::iterator it = elements.begin() ; it != elements.end() ; ++it ) + { + if ( m_translator.equals(*it, m_value) ) + { + rtree::move_from_back(elements, it); // MAY THROW (V: copy) + elements.pop_back(); + m_is_value_removed = true; + break; + } + } + + // if value was removed + if ( m_is_value_removed ) + { + BOOST_ASSERT_MSG(0 < m_parameters.get_min_elements(), "min number of elements is too small"); + + // calc underflow + m_is_underflow = elements.size() < m_parameters.get_min_elements(); + + // n is not root - adjust aabb + if ( 0 != m_parent ) + { + rtree::elements(*m_parent)[m_current_child_index].first + = rtree::elements_box<Box>(elements.begin(), elements.end(), m_translator); + } + } + } + + bool is_value_removed() const + { + return m_is_value_removed; + } + +private: + + typedef std::vector< std::pair<size_t, node_pointer> > UnderflowNodes; + + void traverse_apply_visitor(internal_node &n, size_t choosen_node_index) + { + // save previous traverse inputs and set new ones + internal_node_pointer parent_bckup = m_parent; + size_t current_child_index_bckup = m_current_child_index; + size_t current_level_bckup = m_current_level; + + m_parent = &n; + m_current_child_index = choosen_node_index; + ++m_current_level; + + // next traversing step + rtree::apply_visitor(*this, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N: alloc) + + // restore previous traverse inputs + m_parent = parent_bckup; + m_current_child_index = current_child_index_bckup; + m_current_level = current_level_bckup; + } + + bool store_underflowed_node( + typename rtree::elements_type<internal_node>::type & elements, + typename rtree::elements_type<internal_node>::type::iterator underfl_el_it, + size_t relative_level) + { + // move node to the container - store node's relative level as well + m_underflowed_nodes.push_back(std::make_pair(relative_level, underfl_el_it->second)); // MAY THROW (E: alloc, copy) + + BOOST_TRY + { + rtree::move_from_back(elements, underfl_el_it); // MAY THROW (E: copy) + elements.pop_back(); + } + BOOST_CATCH(...) + { + m_underflowed_nodes.pop_back(); + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + + // calc underflow + return elements.size() < m_parameters.get_min_elements(); + } + + void reinsert_removed_nodes_elements() + { + typename UnderflowNodes::reverse_iterator it = m_underflowed_nodes.rbegin(); + + BOOST_TRY + { + // reinsert elements from removed nodes + // begin with levels closer to the root + for ( ; it != m_underflowed_nodes.rend() ; ++it ) + { + is_leaf<Value, Options, Box, Allocators> ilv; + rtree::apply_visitor(ilv, *it->second); + if ( ilv.result ) + { + reinsert_node_elements(rtree::get<leaf>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc) + + rtree::destroy_node<Allocators, leaf>::apply(m_allocators, it->second); + } + else + { + reinsert_node_elements(rtree::get<internal_node>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc) + + rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, it->second); + } + } + + //m_underflowed_nodes.clear(); + } + BOOST_CATCH(...) + { + // destroy current and remaining nodes + for ( ; it != m_underflowed_nodes.rend() ; ++it ) + { + node_auto_ptr dummy(it->second, m_allocators); + } + + //m_underflowed_nodes.clear(); + + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + } + + template <typename Node> + void reinsert_node_elements(Node &n, size_t node_relative_level) + { + typedef typename rtree::elements_type<Node>::type elements_type; + elements_type & elements = rtree::elements(n); + + typename elements_type::iterator it = elements.begin(); + BOOST_TRY + { + for ( ; it != elements.end() ; ++it ) + { + visitors::insert< + typename elements_type::value_type, + Value, Options, Translator, Box, Allocators, + typename Options::insert_tag + > insert_v( + m_root_node, m_leafs_level, *it, + m_parameters, m_translator, m_allocators, + node_relative_level - 1); + + rtree::apply_visitor(insert_v, *m_root_node); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + BOOST_CATCH(...) + { + ++it; + rtree::destroy_elements<Value, Options, Translator, Box, Allocators> + ::apply(it, elements.end(), m_allocators); + elements.clear(); + BOOST_RETHROW // RETHROW + } + BOOST_CATCH_END + } + + Value const& m_value; + parameters_type const& m_parameters; + Translator const& m_translator; + Allocators & m_allocators; + + node_pointer & m_root_node; + size_t & m_leafs_level; + + bool m_is_value_removed; + UnderflowNodes m_underflowed_nodes; + + // traversing input parameters + internal_node_pointer m_parent; + size_t m_current_child_index; + size_t m_current_level; + + // traversing output parameters + bool m_is_underflow; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp new file mode 100644 index 000000000..48d9c3d3c --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -0,0 +1,198 @@ +// Boost.Geometry Index +// +// R-tree spatial query visitor implementation +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, typename OutIter> +struct spatial_query + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Allocators::size_type size_type; + + static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value; + + inline spatial_query(Translator const& t, Predicates const& p, OutIter out_it) + : tr(t), pred(p), out_iter(out_it), found_count(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // traverse nodes meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if node meets predicates + // 0 - dummy value + if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(pred, 0, it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // get all values meeting predicates + for (typename elements_type::const_iterator it = elements.begin(); + it != elements.end(); ++it) + { + // if value meets predicates + if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(pred, *it, tr(*it)) ) + { + *out_iter = *it; + ++out_iter; + + ++found_count; + } + } + } + + Translator const& tr; + + Predicates pred; + + OutIter out_iter; + size_type found_count; +}; + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates> +class spatial_query_incremental + : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type +{ +public: + typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node; + typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node; + typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf; + + typedef typename Allocators::size_type size_type; + typedef typename Allocators::const_reference const_reference; + typedef typename Allocators::node_pointer node_pointer; + + typedef typename rtree::elements_type<internal_node>::type::const_iterator internal_iterator; + typedef typename rtree::elements_type<leaf>::type leaf_elements; + typedef typename rtree::elements_type<leaf>::type::const_iterator leaf_iterator; + + static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value; + + inline spatial_query_incremental(Translator const& t, Predicates const& p) + : m_translator(::boost::addressof(t)) + , m_pred(p) + , m_values(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end())); + } + + inline void operator()(leaf const& n) + { + m_values = ::boost::addressof(rtree::elements(n)); + m_current = rtree::elements(n).begin(); + m_last = rtree::elements(n).end(); + } + + const_reference dereference() const + { + BOOST_ASSERT_MSG(m_values, "not dereferencable"); + return *m_current; + } + + void increment() + { + if ( m_values ) + ++m_current; + + for (;;) + { + // if leaf is choosen, move to the next value in leaf + if ( m_values ) + { + if ( m_current != m_last ) + { + // return if next value is found + Value const& v = *m_current; + if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, v, (*m_translator)(v)) ) + return; + + ++m_current; + } + // no more values, clear current leaf + else + { + m_values = 0; + } + } + // if leaf isn't choosen, move to the next leaf + else + { + // return if there is no more nodes to traverse + if ( m_internal_stack.empty() ) + return; + + // no more children in current node, remove it from stack + if ( m_internal_stack.back().first == m_internal_stack.back().second ) + { + m_internal_stack.pop_back(); + continue; + } + + internal_iterator it = m_internal_stack.back().first; + ++m_internal_stack.back().first; + + // next node is found, push it to the stack + if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) ) + rtree::apply_visitor(*this, *(it->second)); + } + } + } + + bool is_end() const + { + return 0 == m_values; + } + + friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r) + { + return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current ); + } + +private: + + const Translator * m_translator; + + Predicates m_pred; + + std::vector< std::pair<internal_iterator, internal_iterator> > m_internal_stack; + const leaf_elements * m_values; + leaf_iterator m_current, m_last; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP diff --git a/boost/geometry/index/detail/tags.hpp b/boost/geometry/index/detail/tags.hpp new file mode 100644 index 000000000..e1a1716be --- /dev/null +++ b/boost/geometry/index/detail/tags.hpp @@ -0,0 +1,25 @@ +// Boost.Geometry Index +// +// Tags used by the predicates checks implementation. +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TAGS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_TAGS_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +struct value_tag {}; +struct bounds_tag {}; + +} // namespace detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_RTREE_TAGS_HPP diff --git a/boost/geometry/index/detail/translator.hpp b/boost/geometry/index/detail/translator.hpp new file mode 100644 index 000000000..f377c720a --- /dev/null +++ b/boost/geometry/index/detail/translator.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template <typename IndexableGetter, typename EqualTo> +struct translator + : public IndexableGetter + , public EqualTo +{ + typedef typename IndexableGetter::result_type result_type; + + translator(IndexableGetter const& i, EqualTo const& e) + : IndexableGetter(i), EqualTo(e) + {} + + template <typename Value> + result_type operator()(Value const& value) const + { + return IndexableGetter::operator()(value); + } + + template <typename Value> + bool equals(Value const& v1, Value const& v2) const + { + return EqualTo::operator()(v1, v2); + } +}; + +template <typename IndexableGetter> +struct result_type +{ + typedef typename IndexableGetter::result_type type; +}; + +template <typename IndexableGetter> +struct indexable_type +{ + typedef typename boost::remove_const< + typename boost::remove_reference< + typename result_type<IndexableGetter>::type + >::type + >::type type; +}; + +} // namespace detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP diff --git a/boost/geometry/index/detail/tuples.hpp b/boost/geometry/index/detail/tuples.hpp new file mode 100644 index 000000000..28e347bed --- /dev/null +++ b/boost/geometry/index/detail/tuples.hpp @@ -0,0 +1,201 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TUPLES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_TUPLES_HPP + +#include <boost/tuple/tuple.hpp> +#include <boost/type_traits/is_same.hpp> + +// TODO move this to index/tuples and separate algorithms + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace tuples { + +// find_index + +namespace detail { + +template <typename Tuple, typename El, size_t N> +struct find_index; + +template <typename Tuple, typename El, size_t N, typename CurrentEl> +struct find_index_impl +{ + static const size_t value = find_index<Tuple, El, N - 1>::value; +}; + +template <typename Tuple, typename El, size_t N> +struct find_index_impl<Tuple, El, N, El> +{ + static const size_t value = N - 1; +}; + +template <typename Tuple, typename El, typename CurrentEl> +struct find_index_impl<Tuple, El, 1, CurrentEl> +{ + BOOST_MPL_ASSERT_MSG( + (false), + ELEMENT_NOT_FOUND, + (find_index_impl)); +}; + +template <typename Tuple, typename El> +struct find_index_impl<Tuple, El, 1, El> +{ + static const size_t value = 0; +}; + +template <typename Tuple, typename El, size_t N> +struct find_index +{ + static const size_t value = + find_index_impl< + Tuple, + El, + N, + typename boost::tuples::element<N - 1, Tuple>::type + >::value; +}; + +} // namespace detail + +template <typename Tuple, typename El> +struct find_index +{ + static const size_t value = + detail::find_index< + Tuple, + El, + boost::tuples::length<Tuple>::value + >::value; +}; + +// has + +namespace detail { + +template <typename Tuple, typename El, size_t N> +struct has +{ + static const bool value + = boost::is_same< + typename boost::tuples::element<N - 1, Tuple>::type, + El + >::value + || has<Tuple, El, N - 1>::value; +}; + +template <typename Tuple, typename El> +struct has<Tuple, El, 1> +{ + static const bool value + = boost::is_same< + typename boost::tuples::element<0, Tuple>::type, + El + >::value; +}; + +} // namespace detail + +template <typename Tuple, typename El> +struct has +{ + static const bool value + = detail::has< + Tuple, + El, + boost::tuples::length<Tuple>::value + >::value; +}; + +// add + +template <typename Tuple, typename El> +struct add +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TUPLE_TYPE, + (add)); +}; + +template <typename T1, typename T> +struct add<boost::tuple<T1>, T> +{ + typedef boost::tuple<T1, T> type; +}; + +template <typename T1, typename T2, typename T> +struct add<boost::tuple<T1, T2>, T> +{ + typedef boost::tuple<T1, T2, T> type; +}; + +// add_if + +template <typename Tuple, typename El, bool Cond> +struct add_if +{ + typedef Tuple type; +}; + +template <typename Tuple, typename El> +struct add_if<Tuple, El, true> +{ + typedef typename add<Tuple, El>::type type; +}; + +// add_unique + +template <typename Tuple, typename El> +struct add_unique +{ + typedef typename add_if< + Tuple, + El, + !has<Tuple, El>::value + >::type type; +}; + +template <typename Tuple, typename T, size_t I, size_t N> +struct push_back_impl +{ + typedef + boost::tuples::cons< + typename boost::tuples::element<I, Tuple>::type, + typename push_back_impl<Tuple, T, I+1, N>::type + > type; + + static type apply(Tuple const& tup, T const& t) + { + return + type( + boost::get<I>(tup), + push_back_impl<Tuple, T, I+1, N>::apply(tup, t) + ); + } +}; + +template <typename Tuple, typename T, size_t N> +struct push_back_impl<Tuple, T, N, N> +{ + typedef boost::tuples::cons<T, boost::tuples::null_type> type; + + static type apply(Tuple const&, T const& t) + { + return type(t, boost::tuples::null_type()); + } +}; + +} // namespace tuples + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_TAGS_HPP diff --git a/boost/geometry/index/detail/type_erased_iterators.hpp b/boost/geometry/index/detail/type_erased_iterators.hpp new file mode 100644 index 000000000..92867a4ce --- /dev/null +++ b/boost/geometry/index/detail/type_erased_iterators.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry Index +// +// Type-erased iterators +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TYPE_ERASED_ITERATORS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_TYPE_ERASED_ITERATORS_HPP + +#include <boost/type_erasure/any.hpp> +#include <boost/type_erasure/operators.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +template<typename T, typename ValueType, typename Reference, typename Pointer, typename DifferenceType> +struct single_pass_iterator_concept : + ::boost::mpl::vector< + ::boost::type_erasure::copy_constructible<T>, + ::boost::type_erasure::equality_comparable<T>, + ::boost::type_erasure::dereferenceable<Reference, T>, + ::boost::type_erasure::assignable<T>, + ::boost::type_erasure::incrementable<T> + > +{}; + +template <typename ValueType, typename Reference, typename Pointer, typename DifferenceType> +struct single_pass_iterator_type +{ + typedef ::boost::type_erasure::any< + single_pass_iterator_concept< + ::boost::type_erasure::_self, ValueType, Reference, Pointer, DifferenceType + > + > type; +}; + +}}}} // namespace boost::geometry::index::detail + +namespace boost { namespace type_erasure { + +template<typename T, typename ValueType, typename Reference, typename Pointer, typename DifferenceType, typename Base> +struct concept_interface< + ::boost::geometry::index::detail::single_pass_iterator_concept< + T, ValueType, Reference, Pointer, DifferenceType + >, Base, T> + : Base +{ + typedef ValueType value_type; + typedef Reference reference; + typedef Pointer pointer; + typedef DifferenceType difference_type; + typedef ::std::input_iterator_tag iterator_category; +}; + +}} // namespace boost::type_erasure + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_TYPE_ERASED_ITERATORS_HPP diff --git a/boost/geometry/index/detail/utilities.hpp b/boost/geometry/index/detail/utilities.hpp new file mode 100644 index 000000000..26f078001 --- /dev/null +++ b/boost/geometry/index/detail/utilities.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/swap.hpp> +//#include <boost/type_traits/is_empty.hpp> + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template<class T> +static inline void assign_cond(T & l, T const& r, boost::mpl::bool_<true> const&) +{ + l = r; +} + +template<class T> +static inline void assign_cond(T &, T const&, boost::mpl::bool_<false> const&) {} + +template<class T> +static inline void move_cond(T & l, T & r, boost::mpl::bool_<true> const&) +{ + l = ::boost::move(r); +} + +template<class T> +static inline void move_cond(T &, T &, boost::mpl::bool_<false> const&) {} + +template <typename T> inline +void swap_cond(T & l, T & r, boost::mpl::bool_<true> const&) +{ + ::boost::swap(l, r); +} + +template <typename T> inline +void swap_cond(T &, T &, boost::mpl::bool_<false> const&) {} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP diff --git a/boost/geometry/index/detail/varray.hpp b/boost/geometry/index/detail/varray.hpp new file mode 100644 index 000000000..9570c21ce --- /dev/null +++ b/boost/geometry/index/detail/varray.hpp @@ -0,0 +1,2209 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP + +// TODO - REMOVE/CHANGE +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> +#include <boost/container/detail/preprocessor.hpp> + +#include <boost/config.hpp> +#include <boost/swap.hpp> +#include <boost/integer.hpp> + +#include <boost/mpl/assert.hpp> + +#include <boost/type_traits/is_unsigned.hpp> +#include <boost/type_traits/alignment_of.hpp> +#include <boost/type_traits/aligned_storage.hpp> + +// TODO - use std::reverse_iterator and std::iterator_traits +// instead Boost.Iterator to remove dependency? +// or boost/detail/iterator.hpp ? +#include <boost/iterator/reverse_iterator.hpp> +#include <boost/iterator/iterator_concepts.hpp> + +#include <boost/geometry/index/detail/assert.hpp> + +#include <boost/geometry/index/detail/assert.hpp> +#include <boost/geometry/index/detail/varray_detail.hpp> + +#include <boost/concept_check.hpp> + +/*! +\defgroup varray_non_member varray non-member functions +*/ + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace varray_detail { + +template <typename Value, std::size_t Capacity> +struct varray_traits +{ + typedef Value value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef Value * pointer; + typedef const Value * const_pointer; + typedef Value & reference; + typedef const Value & const_reference; + + typedef boost::false_type use_memop_in_swap_and_move; + typedef boost::false_type use_optimized_swap; + typedef boost::false_type disable_trivial_init; +}; + +template <typename Varray> +struct checker +{ + typedef typename Varray::size_type size_type; + typedef typename Varray::const_iterator const_iterator; + + static inline void check_capacity(Varray const& v, size_type s) + { + BOOST_GEOMETRY_INDEX_ASSERT(s <= v.capacity(), "size too big"); + + ::boost::ignore_unused_variable_warning(v); + ::boost::ignore_unused_variable_warning(s); + } + + static inline void throw_out_of_bounds(Varray const& v, size_type i) + { +//#ifndef BOOST_NO_EXCEPTIONS + if ( v.size() <= i ) + BOOST_THROW_EXCEPTION(std::out_of_range("index out of bounds")); +//#else // BOOST_NO_EXCEPTIONS +// BOOST_GEOMETRY_INDEX_ASSERT(i < v.size(), "index out of bounds"); +//#endif // BOOST_NO_EXCEPTIONS + + ::boost::ignore_unused_variable_warning(v); + ::boost::ignore_unused_variable_warning(i); + } + + static inline void check_index(Varray const& v, size_type i) + { + BOOST_GEOMETRY_INDEX_ASSERT(i < v.size(), "index out of bounds"); + + ::boost::ignore_unused_variable_warning(v); + ::boost::ignore_unused_variable_warning(i); + } + + static inline void check_not_empty(Varray const& v) + { + BOOST_GEOMETRY_INDEX_ASSERT(!v.empty(), "the container is empty"); + + ::boost::ignore_unused_variable_warning(v); + } + + static inline void check_iterator_end_neq(Varray const& v, const_iterator position) + { + BOOST_GEOMETRY_INDEX_ASSERT(v.begin() <= position && position < v.end(), "iterator out of bounds"); + + ::boost::ignore_unused_variable_warning(v); + ::boost::ignore_unused_variable_warning(position); + } + + static inline void check_iterator_end_eq(Varray const& v, const_iterator position) + { + BOOST_GEOMETRY_INDEX_ASSERT(v.begin() <= position && position <= v.end(), "iterator out of bounds"); + + ::boost::ignore_unused_variable_warning(v); + ::boost::ignore_unused_variable_warning(position); + } +}; + +} // namespace varray_detail + +/*! +\brief A variable-size array container with fixed capacity. + +varray is a sequence container like boost::container::vector with contiguous storage that can +change in size, along with the static allocation, low overhead, and fixed capacity of boost::array. + +A varray is a sequence that supports random access to elements, constant time insertion and +removal of elements at the end, and linear time insertion and removal of elements at the beginning or +in the middle. The number of elements in a varray may vary dynamically up to a fixed capacity +because elements are stored within the object itself similarly to an array. However, objects are +initialized as they are inserted into varray unlike C arrays or std::array which must construct +all elements on instantiation. The behavior of varray enables the use of statically allocated +elements in cases with complex object lifetime requirements that would otherwise not be trivially +possible. + +\par Error Handling + Insertion beyond the capacity and out of bounds errors result in undefined behavior unless + otherwise specified. In this respect if size() == capacity(), then varray::push_back() + behaves like std::vector pop_front() if size() == empty(). The reason for this difference + is because unlike vectors, varray does not perform allocation. + +\par Advanced Usage + Error handling behavior can be modified to more closely match std::vector exception behavior + when exceeding bounds by providing an alternate Strategy and varray_traits instantiation. + +\tparam Value The type of element that will be stored. +\tparam Capacity The maximum number of elements varray can store, fixed at compile time. +\tparam Strategy Defines the public typedefs and error handlers, + implements StaticVectorStrategy and has some similarities + to an Allocator. +*/ +template <typename Value, std::size_t Capacity> +class varray +{ + typedef varray_detail::varray_traits<Value, Capacity> vt; + typedef varray_detail::checker<varray> errh; + + BOOST_MPL_ASSERT_MSG( + ( boost::is_unsigned<typename vt::size_type>::value && + sizeof(typename boost::uint_value_t<Capacity>::least) <= sizeof(typename vt::size_type) ), + SIZE_TYPE_IS_TOO_SMALL_FOR_SPECIFIED_CAPACITY, + (varray) + ); + + typedef boost::aligned_storage< + sizeof(Value[Capacity]), + boost::alignment_of<Value[Capacity]>::value + > aligned_storage_type; + + template <typename V, std::size_t C> + friend class varray; + + BOOST_COPYABLE_AND_MOVABLE(varray) + +#ifdef BOOST_NO_RVALUE_REFERENCES +public: + template <std::size_t C> + varray & operator=(varray<Value, C> & sv) + { + typedef varray<Value, C> other; + this->operator=(static_cast<const ::boost::rv<other> &>(const_cast<const other &>(sv))); + return *this; + } +#endif + +public: + //! @brief The type of elements stored in the container. + typedef typename vt::value_type value_type; + //! @brief The unsigned integral type used by the container. + typedef typename vt::size_type size_type; + //! @brief The pointers difference type. + typedef typename vt::difference_type difference_type; + //! @brief The pointer type. + typedef typename vt::pointer pointer; + //! @brief The const pointer type. + typedef typename vt::const_pointer const_pointer; + //! @brief The value reference type. + typedef typename vt::reference reference; + //! @brief The value const reference type. + typedef typename vt::const_reference const_reference; + + //! @brief The iterator type. + typedef pointer iterator; + //! @brief The const iterator type. + typedef const_pointer const_iterator; + //! @brief The reverse iterator type. + typedef boost::reverse_iterator<iterator> reverse_iterator; + //! @brief The const reverse iterator. + typedef boost::reverse_iterator<const_iterator> const_reverse_iterator; + + //! @brief Constructs an empty varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + varray() + : m_size(0) + {} + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief Constructs a varray containing count default constructed Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + explicit varray(size_type count) + : m_size(0) + { + this->resize(count); // may throw + } + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief Constructs a varray containing count copies of value. + //! + //! @param count The number of copies of a values that will be contained in the container. + //! @param value The value which will be used to copy construct values. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray(size_type count, value_type const& value) + : m_size(0) + { + this->resize(count, value); // may throw + } + + //! @pre + //! @li <tt>distance(first, last) <= capacity()</tt> + //! @li Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Constructs a varray containing copy of a range <tt>[first, last)</tt>. + //! + //! @param first The iterator to the first element in range. + //! @param last The iterator to the one after the last element in range. + //! + //! @par Throws + //! If Value's constructor taking a dereferenced Iterator throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <typename Iterator> + varray(Iterator first, Iterator last) + : m_size(0) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator + + this->assign(first, last); // may throw + } + + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + varray(varray const& other) + : m_size(other.size()) + { + namespace sv = varray_detail; + sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + //! @pre <tt>other.size() <= capacity()</tt>. + //! + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <std::size_t C> + varray(varray<value_type, C> const& other) + : m_size(other.size()) + { + errh::check_capacity(*this, other.size()); // may throw + + namespace sv = varray_detail; + sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other) + { + this->assign(other.begin(), other.end()); // may throw + + return *this; + } + + //! @pre <tt>other.size() <= capacity()</tt> + //! + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <std::size_t C> +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_RVALUE_REFERENCES) + varray & operator=(::boost::rv< varray<value_type, C> > const& other) +#else + varray & operator=(varray<value_type, C> const& other) +#endif + { + this->assign(other.begin(), other.end()); // may throw + + return *this; + } + + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray(BOOST_RV_REF(varray) other) + { + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); + } + + //! @pre <tt>other.size() <= capacity()</tt> + //! + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <std::size_t C> + varray(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + : m_size(other.m_size) + { + errh::check_capacity(*this, other.size()); // may throw + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); + } + + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_RV_REF(varray) other) + { + if ( &other == this ) + return *this; + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_assign_dispatch(other, use_memop_in_swap_and_move()); + + return *this; + } + + //! @pre <tt>other.size() <= capacity()</tt> + //! + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <std::size_t C> + varray & operator=(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + { + errh::check_capacity(*this, other.size()); // may throw + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_assign_dispatch(other, use_memop_in_swap_and_move()); + + return *this; + } + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~varray() + { + namespace sv = varray_detail; + sv::destroy(this->begin(), this->end()); + } + + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws, + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void swap(varray & other) + { + typedef typename + vt::use_optimized_swap use_optimized_swap; + + this->swap_dispatch(other, use_optimized_swap()); + } + + //! @pre <tt>other.size() <= capacity() && size() <= other.capacity()</tt> + //! + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws, + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <std::size_t C> + void swap(varray<value_type, C> & other) + { + errh::check_capacity(*this, other.size()); + errh::check_capacity(other, this->size()); + + typedef typename + vt::use_optimized_swap use_optimized_swap; + + this->swap_dispatch(other, use_optimized_swap()); + } + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are default constructed. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count) + { + namespace sv = varray_detail; + typedef typename vt::disable_trivial_init dti; + + if ( count < m_size ) + { + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + sv::uninitialized_fill(this->end(), this->begin() + count, dti()); // may throw + } + m_size = count; // update end + } + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are copy constructed from value. + //! + //! @param count The number of elements which will be stored in the container. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count, value_type const& value) + { + if ( count < m_size ) + { + namespace sv = varray_detail; + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief This call has no effect because the Capacity of this container is constant. + //! + //! @param count The number of elements which the container should be able to contain. + //! + //! @par Throws + //! Nothing. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void reserve(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + //! @pre <tt>size() < capacity()</tt> + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + void push_back(value_type const& value) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), value); // may throw + ++m_size; // update end + } + + //! @pre <tt>size() < capacity()</tt> + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + void push_back(BOOST_RV_REF(value_type) value) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), ::boost::move(value)); // may throw + ++m_size; // update end + } + + //! @pre <tt>!empty()</tt> + //! + //! @brief Destroys last value and decreases the size. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + void pop_back() + { + errh::check_not_empty(*this); + + namespace sv = varray_detail; + sv::destroy(this->end() - 1); + --m_size; // update end + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>. + //! @li <tt>size() < capacity()</tt> + //! + //! @brief Inserts a copy of element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, value_type const& value) + { + typedef typename vt::disable_trivial_init dti; + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + 1); // may throw + + if ( position == this->end() ) + { + sv::construct(dti(), position, value); // may throw + ++m_size; // update end + } + else + { + // TODO - should move be used only if it's nonthrowing? + value_type & r = *(this->end() - 1); + sv::construct(dti(), this->end(), boost::move(r)); // may throw + ++m_size; // update end + sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw + sv::assign(position, value); // may throw + } + + return position; + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>. + //! @li <tt>size() < capacity()</tt> + //! + //! @brief Inserts a move-constructed element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, BOOST_RV_REF(value_type) value) + { + typedef typename vt::disable_trivial_init dti; + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + 1); // may throw + + if ( position == this->end() ) + { + sv::construct(dti(), position, boost::move(value)); // may throw + ++m_size; // update end + } + else + { + // TODO - should move be used only if it's nonthrowing? + value_type & r = *(this->end() - 1); + sv::construct(dti(), this->end(), boost::move(r)); // may throw + ++m_size; // update end + sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw + sv::assign(position, boost::move(value)); // may throw + } + + return position; + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>. + //! @li <tt>size() + count <= capacity()</tt> + //! + //! @brief Inserts a count copies of value at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param count The number of new elements which will be inserted. + //! @param value The value used to copy construct new elements. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws. + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + iterator insert(iterator position, size_type count, value_type const& value) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + count); // may throw + + if ( position == this->end() ) + { + std::uninitialized_fill(position, position + count, value); // may throw + m_size += count; // update end + } + else + { + namespace sv = varray_detail; + + difference_type to_move = std::distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < static_cast<size_type>(to_move) ) + { + sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + sv::move_backward(position, position + to_move - count, this->end() - count); // may throw + std::fill_n(position, count, value); // may throw + } + else + { + std::uninitialized_fill(this->end(), position + count, value); // may throw + m_size += count - to_move; // update end + sv::uninitialized_move(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + std::fill_n(position, to_move, value); // may throw + } + } + + return position; + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>. + //! @li <tt>distance(first, last) <= capacity()</tt> + //! @li \c Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Inserts a copy of a range <tt>[first, last)</tt> at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param first The iterator to the first element of a range used to construct new elements. + //! @param last The iterator to the one after the last element of a range used to construct new elements. + //! + //! @par Throws + //! @li If Value's constructor and assignment taking a dereferenced \c Iterator. + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template <typename Iterator> + iterator insert(iterator position, Iterator first, Iterator last) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator + + typedef typename boost::iterator_traversal<Iterator>::type traversal; + this->insert_dispatch(position, first, last, traversal()); + + return position; + } + + //! @pre \c position must be a valid iterator of \c *this in range <tt>[begin(), end())</tt> + //! + //! @brief Erases Value from position. + //! + //! @param position The position of the element which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator position) + { + namespace sv = varray_detail; + + errh::check_iterator_end_neq(*this, position); + + //TODO - add empty check? + //errh::check_empty(*this); + + sv::move(position + 1, this->end(), position); // may throw + sv::destroy(this->end() - 1); + --m_size; + + return position; + } + + //! @pre + //! @li \c first and \c last must define a valid range + //! @li iterators must be in range <tt>[begin(), end()]</tt> + //! + //! @brief Erases Values from a range <tt>[first, last)</tt>. + //! + //! @param first The position of the first element of a range which will be erased from the container. + //! @param last The position of the one after the last element of a range which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator first, iterator last) + { + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, first); + errh::check_iterator_end_eq(*this, last); + + difference_type n = std::distance(first, last); + + //TODO - add invalid range check? + //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + //TODO - add this->size() check? + //BOOST_ASSERT_MSG(n <= this->size(), "invalid range"); + + sv::move(last, this->end(), first); // may throw + sv::destroy(this->end() - n, this->end()); + m_size -= n; + + return first; + } + + //! @pre <tt>distance(first, last) <= capacity()</tt> + //! + //! @brief Assigns a range <tt>[first, last)</tt> of Values to this container. + //! + //! @param first The iterator to the first element of a range used to construct new content of this container. + //! @param last The iterator to the one after the last element of a range used to construct new content of this container. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template <typename Iterator> + void assign(Iterator first, Iterator last) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator + + typedef typename boost::iterator_traversal<Iterator>::type traversal; + this->assign_dispatch(first, last, traversal()); // may throw + } + + //! @pre <tt>count <= capacity()</tt> + //! + //! @brief Assigns a count copies of value to this container. + //! + //! @param count The new number of elements which will be container in the container. + //! @param value The value which will be used to copy construct the new content. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + void assign(size_type count, value_type const& value) + { + if ( count < m_size ) + { + namespace sv = varray_detail; + + std::fill_n(this->begin(), count, value); // may throw + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + std::fill_n(this->begin(), m_size, value); // may throw + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! @pre <tt>size() < capacity()</tt> + //! + //! @brief Inserts a Value constructed with + //! \c std::forward<Args>(args)... in the end of the container. + //! + //! @param args The arguments of the constructor of the new element which will be created at the end of the container. + //! + //! @par Throws + //! If in-place constructor throws or Value's move constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + template<class ...Args> + void emplace_back(BOOST_FWD_REF(Args) ...args) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), ::boost::forward<Args>(args)...); // may throw + ++m_size; // update end + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt> + //! @li <tt>size() < capacity()</tt> + //! + //! @brief Inserts a Value constructed with + //! \c std::forward<Args>(args)... before position + //! + //! @param position The position at which new elements will be inserted. + //! @param args The arguments of the constructor of the new element. + //! + //! @par Throws + //! If in-place constructor throws or if Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + template<class ...Args> + iterator emplace(iterator position, BOOST_FWD_REF(Args) ...args) + { + typedef typename vt::disable_trivial_init dti; + + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + 1); // may throw + + if ( position == this->end() ) + { + sv::construct(dti(), position, ::boost::forward<Args>(args)...); // may throw + ++m_size; // update end + } + else + { + // TODO - should following lines check for exception and revert to the old size? + + // TODO - should move be used only if it's nonthrowing? + value_type & r = *(this->end() - 1); + sv::construct(dti(), this->end(), boost::move(r)); // may throw + ++m_size; // update end + sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw + + aligned_storage<sizeof(value_type), alignment_of<value_type>::value> temp_storage; + value_type * val_p = static_cast<value_type *>(temp_storage.address()); + sv::construct(dti(), val_p, ::boost::forward<Args>(args)...); // may throw + sv::scoped_destructor<value_type> d(val_p); + sv::assign(position, ::boost::move(*val_p)); // may throw + } + + return position; + } + +#else // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + typedef typename vt::disable_trivial_init dti; \ + \ + errh::check_capacity(*this, m_size + 1); /*may throw*/\ + \ + namespace sv = varray_detail; \ + sv::construct(dti(), this->end() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + ++m_size; /*update end*/ \ + } \ + // + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace(iterator position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + typedef typename vt::disable_trivial_init dti; \ + namespace sv = varray_detail; \ + \ + errh::check_iterator_end_eq(*this, position); \ + errh::check_capacity(*this, m_size + 1); /*may throw*/\ + \ + if ( position == this->end() ) \ + { \ + sv::construct(dti(), position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + ++m_size; /*update end*/ \ + } \ + else \ + { \ + /* TODO - should following lines check for exception and revert to the old size? */ \ + /* TODO - should move be used only if it's nonthrowing? */ \ + \ + value_type & r = *(this->end() - 1); \ + sv::construct(dti(), this->end(), boost::move(r)); /*may throw*/\ + ++m_size; /*update end*/ \ + sv::move_backward(position, this->end() - 2, this->end() - 1); /*may throw*/\ + \ + aligned_storage<sizeof(value_type), alignment_of<value_type>::value> temp_storage; \ + value_type * val_p = static_cast<value_type *>(temp_storage.address()); \ + sv::construct(dti(), val_p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + sv::scoped_destructor<value_type> d(val_p); \ + sv::assign(position, ::boost::move(*val_p)); /*may throw*/\ + } \ + \ + return position; \ + } \ + // + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + +#endif // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + + //! @brief Removes all elements from the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + void clear() + { + namespace sv = varray_detail; + sv::destroy(this->begin(), this->end()); + m_size = 0; // update end + } + + //! @pre <tt>i < size()</tt> + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + reference at(size_type i) + { + errh::throw_out_of_bounds(*this, i); // may throw + return *(this->begin() + i); + } + + //! @pre <tt>i < size()</tt> + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference at(size_type i) const + { + errh::throw_out_of_bounds(*this, i); // may throw + return *(this->begin() + i); + } + + //! @pre <tt>i < size()</tt> + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference operator[](size_type i) + { + // TODO: Remove bounds check? std::vector and std::array operator[] don't check. + errh::check_index(*this, i); + return *(this->begin() + i); + } + + //! @pre <tt>i < size()</tt> + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference operator[](size_type i) const + { + errh::check_index(*this, i); + return *(this->begin() + i); + } + + //! @pre \c !empty() + //! + //! @brief Returns reference to the first element. + //! + //! @return reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference front() + { + errh::check_not_empty(*this); + return *(this->begin()); + } + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference front() const + { + errh::check_not_empty(*this); + return *(this->begin()); + } + + //! @pre \c !empty() + //! + //! @brief Returns reference to the last element. + //! + //! @return reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference back() + { + errh::check_not_empty(*this); + return *(this->end() - 1); + } + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference back() const + { + errh::check_not_empty(*this); + return *(this->end() - 1); + } + + //! @brief Pointer such that <tt>[data(), data() + size())</tt> is a valid range. + //! For a non-empty vector <tt>data() == &front()</tt>. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + Value * data() + { + return boost::addressof(*(this->ptr())); + } + + //! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range. + //! For a non-empty vector <tt>data() == &front()</tt>. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const Value * data() const + { + return boost::addressof(*(this->ptr())); + } + + + //! @brief Returns iterator to the first element. + //! + //! @return iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator begin() { return this->ptr(); } + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator begin() const { return this->ptr(); } + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cbegin() const { return this->ptr(); } + + //! @brief Returns iterator to the one after the last element. + //! + //! @return iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator end() { return this->begin() + m_size; } + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator end() const { return this->begin() + m_size; } + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cend() const { return this->cbegin() + m_size; } + + //! @brief Returns reverse iterator to the first element of the reversed container. + //! + //! @return reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rbegin() { return reverse_iterator(this->end()); } + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } + + //! @brief Returns reverse iterator to the one after the last element of the reversed container. + //! + //! @return reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rend() { return reverse_iterator(this->begin()); } + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type capacity() { return Capacity; } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type max_size() { return Capacity; } + + //! @brief Returns the number of stored elements. + //! + //! @return Number of elements contained in the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + size_type size() const { return m_size; } + + //! @brief Queries if the container contains elements. + //! + //! @return true if the number of elements contained in the + //! container is equal to 0. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + bool empty() const { return 0 == m_size; } + +private: + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void move_ctor_dispatch(varray<value_type, C> & other, boost::true_type /*use_memop*/) + { + ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); + m_size = other.m_size; + } + + // @par Throws + // @li If boost::has_nothrow_move<Value>::value is true and Value's move constructor throws + // @li If boost::has_nothrow_move<Value>::value is false and Value's copy constructor throws. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void move_ctor_dispatch(varray<value_type, C> & other, boost::false_type /*use_memop*/) + { + namespace sv = varray_detail; + sv::uninitialized_move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw + m_size = other.m_size; + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void move_assign_dispatch(varray<value_type, C> & other, boost::true_type /*use_memop*/) + { + this->clear(); + + ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); + std::swap(m_size, other.m_size); + } + + // @par Throws + // @li If boost::has_nothrow_move<Value>::value is true and Value's move constructor or move assignment throws + // @li If boost::has_nothrow_move<Value>::value is false and Value's copy constructor or move assignment throws. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void move_assign_dispatch(varray<value_type, C> & other, boost::false_type /*use_memop*/) + { + namespace sv = varray_detail; + if ( m_size <= static_cast<size_type>(other.size()) ) + { + sv::move_if_noexcept(other.begin(), other.begin() + m_size, this->begin()); // may throw + // TODO - perform uninitialized_copy first? + sv::uninitialized_move_if_noexcept(other.begin() + m_size, other.end(), this->end()); // may throw + } + else + { + sv::move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw + sv::destroy(this->begin() + other.size(), this->end()); + } + m_size = other.size(); // update end + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void swap_dispatch(varray<value_type, C> & other, boost::true_type const& /*use_optimized_swap*/) + { + typedef typename + boost::mpl::if_c< + Capacity < C, + aligned_storage_type, + typename varray<value_type, C>::aligned_storage_type + >::type + storage_type; + + storage_type temp; + Value * temp_ptr = reinterpret_cast<Value*>(temp.address()); + + ::memcpy(temp_ptr, this->data(), sizeof(Value) * this->size()); + ::memcpy(this->data(), other.data(), sizeof(Value) * other.size()); + ::memcpy(other.data(), temp_ptr, sizeof(Value) * this->size()); + + std::swap(m_size, other.m_size); + } + + // @par Throws + // If Value's move constructor or move assignment throws + // but only if use_memop_in_swap_and_move is false_type - default. + // @par Complexity + // Linear O(N). + template <std::size_t C> + void swap_dispatch(varray<value_type, C> & other, boost::false_type const& /*use_optimized_swap*/) + { + namespace sv = varray_detail; + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + if ( this->size() < other.size() ) + swap_dispatch_impl(this->begin(), this->end(), other.begin(), other.end(), use_memop_in_swap_and_move()); // may throw + else + swap_dispatch_impl(other.begin(), other.end(), this->begin(), this->end(), use_memop_in_swap_and_move()); // may throw + std::swap(m_size, other.m_size); + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, boost::true_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + boost::aligned_storage< + sizeof(value_type), + boost::alignment_of<value_type>::value + > temp_storage; + value_type * temp_ptr = reinterpret_cast<value_type*>(temp_storage.address()); + + ::memcpy(temp_ptr, boost::addressof(*first_sm), sizeof(value_type)); + ::memcpy(boost::addressof(*first_sm), boost::addressof(*first_la), sizeof(value_type)); + ::memcpy(boost::addressof(*first_la), temp_ptr, sizeof(value_type)); + } + + ::memcpy(first_sm, first_la, sizeof(value_type) * std::distance(first_la, last_la)); + } + + // @par Throws + // If Value's move constructor or move assignment throws. + // @par Complexity + // Linear O(N). + void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, boost::false_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + //boost::swap(*first_sm, *first_la); // may throw + value_type temp(boost::move(*first_sm)); // may throw + *first_sm = boost::move(*first_la); // may throw + *first_la = boost::move(temp); // may throw + } + sv::uninitialized_move(first_la, last_la, first_sm); // may throw + sv::destroy(first_la, last_la); + } + + // insert + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template <typename Iterator> + void insert_dispatch(iterator position, Iterator first, Iterator last, boost::random_access_traversal_tag const&) + { + BOOST_CONCEPT_ASSERT((boost_concepts::RandomAccessTraversal<Iterator>)); // Make sure you passed a RandomAccessIterator + + errh::check_iterator_end_eq(*this, position); + + typename boost::iterator_difference<Iterator>::type + count = std::distance(first, last); + + errh::check_capacity(*this, m_size + count); // may throw + + if ( position == this->end() ) + { + namespace sv = varray_detail; + + sv::uninitialized_copy(first, last, position); // may throw + m_size += count; // update end + } + else + { + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template <typename Iterator, typename Traversal> + void insert_dispatch(iterator position, Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + errh::check_iterator_end_eq(*this, position); + + if ( position == this->end() ) + { + namespace sv = varray_detail; + + std::ptrdiff_t d = std::distance(position, this->begin() + Capacity); + std::size_t count = sv::uninitialized_copy_s(first, last, position, d); // may throw + + errh::check_capacity(*this, count <= static_cast<std::size_t>(d) ? m_size + count : Capacity + 1); // may throw + + m_size += count; + } + else + { + typename boost::iterator_difference<Iterator>::type + count = std::distance(first, last); + + errh::check_capacity(*this, m_size + count); // may throw + + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template <typename Iterator> + void insert_in_the_middle(iterator position, Iterator first, Iterator last, difference_type count) + { + namespace sv = varray_detail; + + difference_type to_move = std::distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < to_move ) + { + sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + sv::move_backward(position, position + to_move - count, this->end() - count); // may throw + sv::copy(first, last, position); // may throw + } + else + { + Iterator middle_iter = first; + std::advance(middle_iter, to_move); + + sv::uninitialized_copy(middle_iter, last, this->end()); // may throw + m_size += count - to_move; // update end + sv::uninitialized_move(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + sv::copy(first, middle_iter, position); // may throw + } + } + + // assign + + // @par Throws + // If Value's constructor or assignment taking dereferenced Iterator throws. + // @par Complexity + // Linear O(N). + template <typename Iterator> + void assign_dispatch(Iterator first, Iterator last, boost::random_access_traversal_tag const& /*not_random_access*/) + { + namespace sv = varray_detail; + + typename boost::iterator_difference<Iterator>::type + s = std::distance(first, last); + + errh::check_capacity(*this, s); // may throw + + if ( m_size <= static_cast<size_type>(s) ) + { + sv::copy(first, first + m_size, this->begin()); // may throw + // TODO - perform uninitialized_copy first? + sv::uninitialized_copy(first + m_size, last, this->end()); // may throw + } + else + { + sv::copy(first, last, this->begin()); // may throw + sv::destroy(this->begin() + s, this->end()); + } + m_size = s; // update end + } + + // @par Throws + // If Value's constructor or assignment taking dereferenced Iterator throws. + // @par Complexity + // Linear O(N). + template <typename Iterator, typename Traversal> + void assign_dispatch(Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + namespace sv = varray_detail; + + size_type s = 0; + iterator it = this->begin(); + + for ( ; it != this->end() && first != last ; ++it, ++first, ++s ) + *it = *first; // may throw + + sv::destroy(it, this->end()); + + std::ptrdiff_t d = std::distance(it, this->begin() + Capacity); + std::size_t count = sv::uninitialized_copy_s(first, last, it, d); // may throw + s += count; + + errh::check_capacity(*this, count <= static_cast<std::size_t>(d) ? s : Capacity + 1); // may throw + + m_size = s; // update end + } + + pointer ptr() + { + return pointer(static_cast<Value*>(m_storage.address())); + } + + const_pointer ptr() const + { + return const_pointer(static_cast<const Value*>(m_storage.address())); + } + + size_type m_size; + aligned_storage_type m_storage; +}; + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template<typename Value> +class varray<Value, 0> +{ + typedef varray_detail::varray_traits<Value, 0> vt; + typedef varray_detail::checker<varray> errh; + +public: + typedef typename vt::value_type value_type; + typedef typename vt::size_type size_type; + typedef typename vt::difference_type difference_type; + typedef typename vt::pointer pointer; + typedef typename vt::const_pointer const_pointer; + typedef typename vt::reference reference; + typedef typename vt::const_reference const_reference; + + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef boost::reverse_iterator<iterator> reverse_iterator; + typedef boost::reverse_iterator<const_iterator> const_reverse_iterator; + + // nothrow + varray() {} + + // strong + explicit varray(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + varray(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + varray(varray const& /*other*/) + { + //errh::check_capacity(*this, count); + } + + // strong + template <std::size_t C> + varray(varray<value_type, C> const& other) + { + errh::check_capacity(*this, other.size()); // may throw + } + + // strong + template <typename Iterator> + varray(Iterator first, Iterator last) + { + errh::check_capacity(*this, std::distance(first, last)); // may throw + } + + // basic + varray & operator=(varray const& /*other*/) + { + //errh::check_capacity(*this, other.size()); + return *this; + } + + // basic + template <size_t C> + varray & operator=(varray<value_type, C> const& other) + { + errh::check_capacity(*this, other.size()); // may throw + return *this; + } + + // nothrow + ~varray() {} + + // strong + void resize(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + void resize(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + + // nothrow + void reserve(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + void push_back(value_type const&) + { + errh::check_capacity(*this, 1); // may throw + } + + // nothrow + void pop_back() + { + errh::check_not_empty(*this); + } + + // basic + void insert(iterator position, value_type const&) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, 1); // may throw + } + + // basic + void insert(iterator position, size_type count, value_type const&) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, count); // may throw + } + + // basic + template <typename Iterator> + void insert(iterator, Iterator first, Iterator last) + { + // TODO - add MPL_ASSERT, check if Iterator is really an iterator + typedef typename boost::iterator_traversal<Iterator>::type traversal; + errh::check_capacity(*this, std::distance(first, last)); // may throw + } + + // basic + void erase(iterator position) + { + errh::check_iterator_end_neq(*this, position); + } + + // basic + void erase(iterator first, iterator last) + { + errh::check_iterator_end_eq(*this, first); + errh::check_iterator_end_eq(*this, last); + + //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + } + + // basic + template <typename Iterator> + void assign(Iterator first, Iterator last) + { + // TODO - add MPL_ASSERT, check if Iterator is really an iterator + typedef typename boost::iterator_traversal<Iterator>::type traversal; + errh::check_capacity(*this, std::distance(first, last)); // may throw + } + + // basic + void assign(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + // nothrow + void clear() {} + + // strong + reference at(size_type i) + { + errh::throw_out_of_bounds(*this, i); // may throw + return *(this->begin() + i); + } + + // strong + const_reference at(size_type i) const + { + errh::throw_out_of_bounds(*this, i); // may throw + return *(this->begin() + i); + } + + // nothrow + reference operator[](size_type i) + { + errh::check_index(*this, i); + return *(this->begin() + i); + } + + // nothrow + const_reference operator[](size_type i) const + { + errh::check_index(*this, i); + return *(this->begin() + i); + } + + // nothrow + reference front() + { + errh::check_not_empty(*this); + return *(this->begin()); + } + + // nothrow + const_reference front() const + { + errh::check_not_empty(*this); + return *(this->begin()); + } + + // nothrow + reference back() + { + errh::check_not_empty(*this); + return *(this->end() - 1); + } + + // nothrow + const_reference back() const + { + errh::check_not_empty(*this); + return *(this->end() - 1); + } + + // nothrow + Value * data() { return boost::addressof(*(this->ptr())); } + const Value * data() const { return boost::addressof(*(this->ptr())); } + + // nothrow + iterator begin() { return this->ptr(); } + const_iterator begin() const { return this->ptr(); } + const_iterator cbegin() const { return this->ptr(); } + iterator end() { return this->begin(); } + const_iterator end() const { return this->begin(); } + const_iterator cend() const { return this->cbegin(); } + // nothrow + reverse_iterator rbegin() { return reverse_iterator(this->end()); } + const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } + reverse_iterator rend() { return reverse_iterator(this->begin()); } + const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } + const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } + + // nothrow + size_type capacity() const { return 0; } + size_type max_size() const { return 0; } + size_type size() const { return 0; } + bool empty() const { return true; } + +private: + pointer ptr() + { + return pointer(reinterpret_cast<Value*>(this)); + } + + const_pointer ptr() const + { + return const_pointer(reinterpret_cast<const Value*>(this)); + } +}; + +#endif // !BOOST_CONTAINER_DOXYGEN_INVOKED + +//! @brief Checks if contents of two varrays are equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have the same size and elements in both containers are equal. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator== (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); +} + +//! @brief Checks if contents of two varrays are not equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have different size or elements in both containers are not equal. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator!= (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return !(x==y); +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x compares lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator< (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y compares lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator> (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return y<x; +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y don't compare lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator<= (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return !(y<x); +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x don't compare lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +bool operator>= (varray<V, C1> const& x, varray<V, C2> const& y) +{ + return !(x<y); +} + +//! @brief Swaps contents of two varrays. +//! +//! This function calls varray::swap(). +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @par Complexity +//! Linear O(N). +template<typename V, std::size_t C1, std::size_t C2> +inline void swap(varray<V, C1> & x, varray<V, C2> & y) +{ + x.swap(y); +} + +}}}} // namespace boost::geometry::index::detail + +// TODO - REMOVE/CHANGE +#include <boost/container/detail/config_end.hpp> + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP diff --git a/boost/geometry/index/detail/varray_detail.hpp b/boost/geometry/index/detail/varray_detail.hpp new file mode 100644 index 000000000..4e16cc97d --- /dev/null +++ b/boost/geometry/index/detail/varray_detail.hpp @@ -0,0 +1,714 @@ +// Boost.Geometry +// +// varray details +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP + +#include <cstddef> +#include <cstring> +#include <memory> +#include <limits> + +#include <boost/mpl/if.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/int.hpp> + +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/type_traits/has_trivial_assign.hpp> +#include <boost/type_traits/has_trivial_copy.hpp> +#include <boost/type_traits/has_trivial_constructor.hpp> +#include <boost/type_traits/has_trivial_destructor.hpp> +//#include <boost/type_traits/has_nothrow_constructor.hpp> +//#include <boost/type_traits/has_nothrow_copy.hpp> +//#include <boost/type_traits/has_nothrow_assign.hpp> +//#include <boost/type_traits/has_nothrow_destructor.hpp> + +#include <boost/detail/no_exceptions_support.hpp> +#include <boost/config.hpp> +#include <boost/move/move.hpp> +#include <boost/utility/addressof.hpp> +#include <boost/iterator/iterator_traits.hpp> + +// TODO - move vectors iterators optimization to the other, optional file instead of checking defines? + +#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) +#include <vector> +#include <boost/container/vector.hpp> +#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +namespace boost { namespace geometry { namespace index { namespace detail { namespace varray_detail { + +template <typename I> +struct are_elements_contiguous : boost::is_pointer<I> +{}; + +// EXPERIMENTAL - not finished +// Conditional setup - mark vector iterators defined in known implementations +// as iterators pointing to contiguous ranges + +#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) + +template <typename Pointer> +struct are_elements_contiguous< + boost::container::container_detail::vector_const_iterator<Pointer> +> : boost::true_type +{}; + +template <typename Pointer> +struct are_elements_contiguous< + boost::container::container_detail::vector_iterator<Pointer> +> : boost::true_type +{}; + +#if defined(BOOST_DINKUMWARE_STDLIB) + +template <typename T> +struct are_elements_contiguous< + std::_Vector_const_iterator<T> +> : boost::true_type +{}; + +template <typename T> +struct are_elements_contiguous< + std::_Vector_iterator<T> +> : boost::true_type +{}; + +#elif defined(BOOST_GNU_STDLIB) + +template <typename P, typename T, typename A> +struct are_elements_contiguous< + __gnu_cxx::__normal_iterator<P, std::vector<T, A> > +> : boost::true_type +{}; + +#elif defined(_LIBCPP_VERSION) + +// TODO - test it first +//template <typename P> +//struct are_elements_contiguous< +// __wrap_iter<P> +//> : boost::true_type +//{}; + +#else // OTHER_STDLIB + +// TODO - add other iterators implementations + +#endif // STDLIB + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +// True if iterator values are the same and both iterators points to the ranges of contiguous elements + +template <typename I, typename O> +struct are_corresponding : + ::boost::mpl::and_< + ::boost::is_same< + ::boost::remove_const< + typename ::boost::iterator_value<I>::type + >, + ::boost::remove_const< + typename ::boost::iterator_value<O>::type + > + >, + are_elements_contiguous<I>, + are_elements_contiguous<O> + > +{}; + +template <typename I, typename V> +struct is_corresponding_value : + ::boost::is_same< + ::boost::remove_const< + typename ::boost::iterator_value<I>::type + >, + ::boost::remove_const<V> + > +{}; + +// destroy(I, I) + +template <typename I> +void destroy_dispatch(I /*first*/, I /*last*/, + boost::true_type const& /*has_trivial_destructor*/) +{} + +template <typename I> +void destroy_dispatch(I first, I last, + boost::false_type const& /*has_trivial_destructor*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + for ( ; first != last ; ++first ) + first->~value_type(); +} + +template <typename I> +void destroy(I first, I last) +{ + typedef typename boost::iterator_value<I>::type value_type; + destroy_dispatch(first, last, has_trivial_destructor<value_type>()); +} + +// destroy(I) + +template <typename I> +void destroy_dispatch(I /*pos*/, + boost::true_type const& /*has_trivial_destructor*/) +{} + +template <typename I> +void destroy_dispatch(I pos, + boost::false_type const& /*has_trivial_destructor*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + pos->~value_type(); +} + +template <typename I> +void destroy(I pos) +{ + typedef typename boost::iterator_value<I>::type value_type; + destroy_dispatch(pos, has_trivial_destructor<value_type>()); +} + +// copy(I, I, O) + +template <typename I, typename O> +inline O copy_dispatch(I first, I last, O dst, + boost::mpl::bool_<true> const& /*use_memmove*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + typename boost::iterator_difference<I>::type d = std::distance(first, last); + + ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template <typename I, typename O> +inline O copy_dispatch(I first, I last, O dst, + boost::mpl::bool_<false> const& /*use_memmove*/) +{ + return std::copy(first, last, dst); // may throw +} + +template <typename I, typename O> +inline O copy(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding<I, O>, + ::boost::has_trivial_assign< + typename ::boost::iterator_value<O>::type + > + >::type + use_memmove; + + return copy_dispatch(first, last, dst, use_memmove()); // may throw +} + +// uninitialized_copy(I, I, O) + +template <typename I, typename O> +inline +O uninitialized_copy_dispatch(I first, I last, O dst, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + typename boost::iterator_difference<I>::type d = std::distance(first, last); + + ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template <typename I, typename F> +inline +F uninitialized_copy_dispatch(I first, I last, F dst, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + return std::uninitialized_copy(first, last, dst); // may throw +} + +template <typename I, typename F> +inline +F uninitialized_copy(I first, I last, F dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding<I, F>, + ::boost::has_trivial_copy< + typename ::boost::iterator_value<F>::type + > + >::type + use_memcpy; + + return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// uninitialized_move(I, I, O) + +template <typename I, typename O> +inline +O uninitialized_move_dispatch(I first, I last, O dst, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + typename boost::iterator_difference<I>::type d = std::distance(first, last); + + ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template <typename I, typename O> +inline +O uninitialized_move_dispatch(I first, I last, O dst, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + //return boost::uninitialized_move(first, last, dst); // may throw + + O o = dst; + + BOOST_TRY + { + typedef typename std::iterator_traits<O>::value_type value_type; + for (; first != last; ++first, ++o ) + new (boost::addressof(*o)) value_type(boost::move(*first)); + } + BOOST_CATCH(...) + { + destroy(dst, o); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return dst; +} + +template <typename I, typename O> +inline +O uninitialized_move(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding<I, O>, + ::boost::has_trivial_copy< + typename ::boost::iterator_value<O>::type + > + >::type + use_memcpy; + + return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// TODO - move uses memmove - implement 2nd version using memcpy? + +// move(I, I, O) + +template <typename I, typename O> +inline +O move_dispatch(I first, I last, O dst, + boost::mpl::bool_<true> const& /*use_memmove*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + typename boost::iterator_difference<I>::type d = std::distance(first, last); + + ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template <typename I, typename O> +inline +O move_dispatch(I first, I last, O dst, + boost::mpl::bool_<false> const& /*use_memmove*/) +{ + return boost::move(first, last, dst); // may throw +} + +template <typename I, typename O> +inline +O move(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding<I, O>, + ::boost::has_trivial_assign< + typename ::boost::iterator_value<O>::type + > + >::type + use_memmove; + + return move_dispatch(first, last, dst, use_memmove()); // may throw +} + +// move_backward(BDI, BDI, BDO) + +template <typename BDI, typename BDO> +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + boost::mpl::bool_<true> const& /*use_memmove*/) +{ + typedef typename boost::iterator_value<BDI>::type value_type; + typename boost::iterator_difference<BDI>::type d = std::distance(first, last); + + BDO foo(dst - d); + ::memmove(boost::addressof(*foo), boost::addressof(*first), sizeof(value_type) * d); + return foo; +} + +template <typename BDI, typename BDO> +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + boost::mpl::bool_<false> const& /*use_memmove*/) +{ + return boost::move_backward(first, last, dst); // may throw +} + +template <typename BDI, typename BDO> +inline +BDO move_backward(BDI first, BDI last, BDO dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding<BDI, BDO>, + ::boost::has_trivial_assign< + typename ::boost::iterator_value<BDO>::type + > + >::type + use_memmove; + + return move_backward_dispatch(first, last, dst, use_memmove()); // may throw +} + +template <typename T> +struct has_nothrow_move : public + ::boost::mpl::or_< + boost::mpl::bool_< + ::boost::has_nothrow_move< + typename ::boost::remove_const<T>::type + >::value + >, + boost::mpl::bool_< + ::boost::has_nothrow_move<T>::value + > + > +{}; + +// uninitialized_move_if_noexcept(I, I, O) + +template <typename I, typename O> +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/) +{ return uninitialized_move(first, last, dst); } + +template <typename I, typename O> +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/) +{ return uninitialized_copy(first, last, dst); } + +template <typename I, typename O> +inline +O uninitialized_move_if_noexcept(I first, I last, O dst) +{ + typedef typename has_nothrow_move< + typename ::boost::iterator_value<O>::type + >::type use_move; + + return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// move_if_noexcept(I, I, O) + +template <typename I, typename O> +inline +O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/) +{ return move(first, last, dst); } + +template <typename I, typename O> +inline +O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/) +{ return copy(first, last, dst); } + +template <typename I, typename O> +inline +O move_if_noexcept(I first, I last, O dst) +{ + typedef typename has_nothrow_move< + typename ::boost::iterator_value<O>::type + >::type use_move; + + return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// uninitialized_fill(I, I) + +template <typename I> +inline +void uninitialized_fill_dispatch(I /*first*/, I /*last*/, + boost::true_type const& /*has_trivial_constructor*/, + boost::true_type const& /*disable_trivial_init*/) +{} + +template <typename I> +inline +void uninitialized_fill_dispatch(I first, I last, + boost::true_type const& /*has_trivial_constructor*/, + boost::false_type const& /*disable_trivial_init*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + for ( ; first != last ; ++first ) + new (boost::addressof(*first)) value_type(); +} + +template <typename I, typename DisableTrivialInit> +inline +void uninitialized_fill_dispatch(I first, I last, + boost::false_type const& /*has_trivial_constructor*/, + DisableTrivialInit const& /*not_used*/) +{ + typedef typename boost::iterator_value<I>::type value_type; + I it = first; + + BOOST_TRY + { + for ( ; it != last ; ++it ) + new (boost::addressof(*it)) value_type(); // may throw + } + BOOST_CATCH(...) + { + destroy(first, it); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +template <typename I, typename DisableTrivialInit> +inline +void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init) +{ + typedef typename boost::iterator_value<I>::type value_type; + uninitialized_fill_dispatch(first, last, boost::has_trivial_constructor<value_type>(), disable_trivial_init); // may throw +} + +// construct(I) + +template <typename I> +inline +void construct_dispatch(boost::mpl::bool_<true> const& /*dont_init*/, I /*pos*/) +{} + +template <typename I> +inline +void construct_dispatch(boost::mpl::bool_<false> const& /*dont_init*/, I pos) +{ + typedef typename ::boost::iterator_value<I>::type value_type; + new (static_cast<void*>(::boost::addressof(*pos))) value_type(); // may throw +} + +template <typename DisableTrivialInit, typename I> +inline +void construct(DisableTrivialInit const&, I pos) +{ + typedef typename ::boost::iterator_value<I>::type value_type; + typedef typename ::boost::mpl::and_< + boost::has_trivial_constructor<value_type>, + DisableTrivialInit + >::type dont_init; + + construct_dispatch(dont_init(), pos); // may throw +} + +// construct(I, V) + +template <typename I, typename V> +inline +void construct_dispatch(I pos, V const& v, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template <typename I, typename P> +inline +void construct_dispatch(I pos, P const& p, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value<I>::type V; + new (static_cast<void*>(boost::addressof(*pos))) V(p); // may throw +} + +template <typename DisableTrivialInit, typename I, typename P> +inline +void construct(DisableTrivialInit const&, + I pos, P const& p) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value<I, P>, + ::boost::has_trivial_copy<P> + >::type + use_memcpy; + + construct_dispatch(pos, p, use_memcpy()); // may throw +} + +// Needed by push_back(V &&) + +template <typename DisableTrivialInit, typename I, typename P> +inline +void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value<I, P>, + ::boost::has_trivial_copy<P> + >::type + use_memcpy; + + typedef typename boost::iterator_value<I>::type V; + new (static_cast<void*>(boost::addressof(*pos))) V(::boost::move(p)); // may throw +} + +// Needed by emplace_back() and emplace() + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + +template <typename DisableTrivialInit, typename I, class ...Args> +inline +void construct(DisableTrivialInit const&, + I pos, + BOOST_FWD_REF(Args) ...args) +{ + typedef typename boost::iterator_value<I>::type V; + new (static_cast<void*>(boost::addressof(*pos))) V(::boost::forward<Args>(args)...); // may throw +} + +#else // !BOOST_NO_VARIADIC_TEMPLATES + +// BOOST_NO_RVALUE_REFERENCES -> P0 const& p0 +// !BOOST_NO_RVALUE_REFERENCES -> P0 && p0 +// which means that version with one parameter may take V const& v + +#define BOOST_PP_LOCAL_MACRO(n) \ +template <typename DisableTrivialInit, typename I, typename P BOOST_PP_ENUM_TRAILING_PARAMS(n, typename P) > \ +inline \ +void construct(DisableTrivialInit const&, \ + I pos, \ + BOOST_CONTAINER_PP_PARAM(P, p) \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ +{ \ + typedef typename boost::iterator_value<I>::type V; \ + new \ + (static_cast<void*>(boost::addressof(*pos))) \ + V(p, BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); /*may throw*/ \ +} \ +// +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif // !BOOST_NO_VARIADIC_TEMPLATES +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + +// assign(I, V) + +template <typename I, typename V> +inline +void assign_dispatch(I pos, V const& v, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template <typename I, typename V> +inline +void assign_dispatch(I pos, V const& v, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + *pos = v; // may throw +} + +template <typename I, typename V> +inline +void assign(I pos, V const& v) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value<I, V>, + ::boost::has_trivial_assign<V> + >::type + use_memcpy; + + assign_dispatch(pos, v, use_memcpy()); // may throw +} + +template <typename I, typename V> +inline +void assign(I pos, BOOST_RV_REF(V) v) +{ + *pos = boost::move(v); // may throw +} + + +// uninitialized_copy_s + +template <typename I, typename F> +inline std::size_t uninitialized_copy_s(I first, I last, F dest, std::size_t max_count) +{ + std::size_t count = 0; + F it = dest; + + BOOST_TRY + { + for ( ; first != last ; ++it, ++first, ++count ) + { + if ( max_count <= count ) + return (std::numeric_limits<std::size_t>::max)(); + + // dummy 0 as DisableTrivialInit + construct(0, it, *first); // may throw + } + } + BOOST_CATCH(...) + { + destroy(dest, it); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return count; +} + +// scoped_destructor + +template<class T> +class scoped_destructor +{ +public: + scoped_destructor(T * ptr) : m_ptr(ptr) {} + + ~scoped_destructor() + { + if(m_ptr) + destroy(m_ptr); + } + + void release() { m_ptr = 0; } + +private: + T * m_ptr; +}; + +}}}}} // namespace boost::geometry::index::detail::varray_detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP diff --git a/boost/geometry/index/distance_predicates.hpp b/boost/geometry/index/distance_predicates.hpp new file mode 100644 index 000000000..59b32af47 --- /dev/null +++ b/boost/geometry/index/distance_predicates.hpp @@ -0,0 +1,204 @@ +// Boost.Geometry Index +// +// Spatial index distance predicates, calculators and checkers used in nearest neighbor query +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP + +#include <boost/geometry/index/detail/distance_predicates.hpp> + +/*! +\defgroup nearest_relations Nearest relations (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +// relations generators + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate to_nearest() relationship. + +Generate a nearest query Point and Value's Indexable relationship while calculating +distances. This function may be used to define that knn query should calculate distances +as smallest as possible between query Point and Indexable's points. In other words it +should be the distance to the nearest Indexable's point. This function may be also used +to define distances bounds which indicates that Indexable's nearest point should be +closer or further than value v. This is default relation. + +\ingroup nearest_relations + +\tparam T Type of wrapped object. This may be a Point for PointRelation or CoordinateType for + MinRelation or MaxRelation + +\param v Point or distance value. +*/ +template <typename T> +detail::to_nearest<T> to_nearest(T const& v) +{ + return detail::to_nearest<T>(v); +} + +/*! +\brief Generate to_centroid() relationship. + +Generate a nearest query Point and Value's Indexable relationship while calculating +distances. This function may be used to define that knn query should calculate distances +between query Point and Indexable's centroid. This function may be also used +to define distances bounds which indicates that Indexable's centroid should be +closer or further than value v. + +\ingroup nearest_relations + +\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for + MinRelation or MaxRelation + +\param v Point or distance value. +*/ +template <typename T> +detail::to_centroid<T> to_centroid(T const& v) +{ + return detail::to_centroid<T>(v); +} + +/*! +\brief Generate to_furthest() relationship. + +Generate a nearest query Point and Value's Indexable relationship while calculating +distances. This function may be used to define that knn query should calculate distances +as biggest as possible between query Point and Indexable's points. In other words it +should be the distance to the furthest Indexable's point. This function may be also used +to define distances bounds which indicates that Indexable's furthest point should be +closer or further than value v. + +\ingroup nearest_relations + +\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for + MinRelation or MaxRelation + +\param v Point or distance value. +*/ +template <typename T> +detail::to_furthest<T> to_furthest(T const& v) +{ + return detail::to_furthest<T>(v); +} + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +// distance predicates generators + +/*! +\brief Generate unbounded() distance predicate. + +Generate a distance predicate. This defines distances bounds which are used by knn query. +This function indicates that there is no distance bounds and Values should be returned +if distances between Point and Indexable are the smallest. Distance calculation is defined +by PointRelation. This is default nearest predicate. + +\ingroup distance_predicates + +\tparam PointRelation PointRelation type. + +\param pr The point relation. This may be generated by \c index::to_nearest(), + \c index::to_centroid() or \c index::to_furthest() with \c Point passed as a parameter. +*/ +//template <typename PointRelation> +//inline detail::unbounded<PointRelation> +//unbounded(PointRelation const& pr) +//{ +// return detail::unbounded<PointRelation>(pr); +//} + +/*! +\brief Generate min_bounded() distance predicate. + +Generate a distance predicate. This defines distances bounds which are used by knn query. +This function indicates that Values should be returned only if distances between Point and +Indexable are greater or equal to some min_distance passed in MinRelation. Check for closest Value is +defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some +Point but only if nearest points are further than some distance. + +\ingroup distance_predicates + +\tparam PointRelation PointRelation type. +\tparam MinRelation MinRelation type. + +\param pr The point relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with \c Point passed as a parameter. +\param minr The minimum bound relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with distance value passed as a parameter. +*/ +//template <typename PointRelation, typename MinRelation> +//inline detail::min_bounded<PointRelation, MinRelation> +//min_bounded(PointRelation const& pr, MinRelation const& minr) +//{ +// return detail::min_bounded<PointRelation, MinRelation>(pr, minr); +//} + +/*! +\brief Generate max_bounded() distance predicate. + +Generate a distance predicate. This defines distances bounds which are used by knn query. +This function indicates that Values should be returned only if distances between Point and +Indexable are lesser or equal to some max_distance passed in MaxRelation. Check for closest Value is +defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some +Point but only if nearest points are closer than some distance. + +\ingroup distance_predicates + +\tparam PointRelation PointRelation type. +\tparam MaxRelation MaxRelation type. + +\param pr The point relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with \c Point passed as a parameter. +\param maxr The maximum bound relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with distance value passed as a parameter. +*/ +//template <typename PointRelation, typename MaxRelation> +//inline detail::max_bounded<PointRelation, MaxRelation> +//max_bounded(PointRelation const& pr, MaxRelation const& maxr) +//{ +// return detail::max_bounded<PointRelation, MaxRelation>(pr, maxr); +//} + +/*! +\brief Generate bounded() distance predicate. + +Generate a distance predicate. This defines distances bounds which are used by knn query. +This function indicates that Values should be returned only if distances between Point and +Indexable are greater or equal to some min_distance passed in MinRelation and lesser or equal to +some max_distance passed in MaxRelation. Check for closest Value is defined by PointRelation. +So it is possible e.g. to return Values with centroids closest to some Point but only if nearest +points are further than some distance and closer than some other distance. + +\ingroup distance_predicates + +\tparam PointRelation PointRelation type. +\tparam MinRelation MinRelation type. +\tparam MaxRelation MaxRelation type. + +\param pr The point relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with \c Point passed as a parameter. +\param minr The minimum bound relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with distance value passed as a parameter. +\param maxr The maximum bound relation. This may be generated by \c to_nearest(), + \c to_centroid() or \c to_furthest() with distance value passed as a parameter. +*/ +//template <typename PointRelation, typename MinRelation, typename MaxRelation> +//inline detail::bounded<PointRelation, MinRelation, MaxRelation> +//bounded(PointRelation const& pr, MinRelation const& minr, MaxRelation const& maxr) +//{ +// return detail::bounded<PointRelation, MinRelation, MaxRelation>(pr, minr, maxr); +//} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP diff --git a/boost/geometry/index/equal_to.hpp b/boost/geometry/index/equal_to.hpp new file mode 100644 index 000000000..8ce5074c3 --- /dev/null +++ b/boost/geometry/index/equal_to.hpp @@ -0,0 +1,221 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP +#define BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP + +#include <boost/geometry/algorithms/equals.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template <typename Geometry, typename Tag> +struct equals +{ + static bool apply(Geometry const& g1, Geometry const& g2) + { + return geometry::equals(g1, g2); + } +}; + +template <typename T> +struct equals<T, void> +{ + static bool apply(T const& v1, T const& v2) + { + return v1 == v2; + } +}; + +template <typename Tuple, size_t I, size_t N> +struct tuple_equals +{ + inline static bool apply(Tuple const& t1, Tuple const& t2) + { + typedef typename boost::tuples::element<I, Tuple>::type T; + return + equals< + T, typename geometry::traits::tag<T>::type + >::apply(boost::get<I>(t1), boost::get<I>(t2)) + && + tuple_equals<Tuple, I+1, N>::apply(t1, t2); + } +}; + +template <typename Tuple, size_t I> +struct tuple_equals<Tuple, I, I> +{ + inline static bool apply(Tuple const&, Tuple const&) + { + return true; + } +}; + +} // namespace detail + +/*! +\brief The function object comparing Values. + +It compares Geometries using geometry::equals() function. Other types are compared using operator==. +The default version handles Values which are Indexables. +This template is also specialized for std::pair<T1, T2> and boost::tuple<...>. + +\tparam Value The type of objects which are compared by this function object. +*/ +template <typename Value> +struct equal_to +{ + /*! \brief The type of result returned by function object. */ + typedef bool result_type; + + /*! + \brief Compare values. If Value is a Geometry geometry::equals() function is used. + + \param l First value. + \param r Second value. + \return true if values are equal. + */ + bool operator()(Value const& l, Value const& r) const + { + return detail::equals<Value, typename geometry::traits::tag<Value>::type>::apply(l ,r); + } +}; + +/*! +\brief The function object comparing Values. + +This specialization compares values of type std::pair<T1, T2>. +It compares pairs' first values, then second values. + +\tparam T1 The first type. +\tparam T2 The second type. +*/ +template <typename T1, typename T2> +struct equal_to< std::pair<T1, T2> > +{ + /*! \brief The type of result returned by function object. */ + typedef bool result_type; + + /*! + \brief Compare values. If pair<> Value member is a Geometry geometry::equals() function is used. + + \param l First value. + \param r Second value. + \return true if values are equal. + */ + bool operator()(std::pair<T1, T2> const& l, std::pair<T1, T2> const& r) const + { + typedef detail::equals<T1, typename geometry::traits::tag<T1>::type> equals1; + typedef detail::equals<T2, typename geometry::traits::tag<T2>::type> equals2; + + return equals1::apply(l.first, r.first) && equals2::apply(l.second, r.second); + } +}; + +/*! +\brief The function object comparing Values. + +This specialization compares values of type boost::tuple<...>. +It compares all members of the tuple from the first one to the last one. +*/ +template <typename T0, typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, typename T9> +struct equal_to< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +{ + typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type; + + /*! \brief The type of result returned by function object. */ + typedef bool result_type; + + /*! + \brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used. + + \param l First value. + \param r Second value. + \return true if values are equal. + */ + bool operator()(value_type const& l, value_type const& r) const + { + return detail::tuple_equals< + value_type, 0, boost::tuples::length<value_type>::value + >::apply(l ,r); + } +}; + +}}} // namespace boost::geometry::index + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include <tuple> + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template <typename Tuple, size_t I, size_t N> +struct std_tuple_equals +{ + inline static bool apply(Tuple const& t1, Tuple const& t2) + { + typedef typename std::tuple_element<I, Tuple>::type T; + return + equals< + T, typename geometry::traits::tag<T>::type + >::apply(std::get<I>(t1), std::get<I>(t2)) + && + std_tuple_equals<Tuple, I+1, N>::apply(t1, t2); + } +}; + +template <typename Tuple, size_t I> +struct std_tuple_equals<Tuple, I, I> +{ + inline static bool apply(Tuple const&, Tuple const&) + { + return true; + } +}; + +} // namespace detail + +/*! +\brief The function object comparing Values. + +This specialization compares values of type std::tuple<Args...>. +It's defined if the compiler supports tuples and variadic templates. +It compares all members of the tuple from the first one to the last one. +*/ +template <typename ...Args> +struct equal_to< std::tuple<Args...> > +{ + typedef std::tuple<Args...> value_type; + + /*! \brief The type of result returned by function object. */ + typedef bool result_type; + + /*! + \brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used. + + \param l First value. + \param r Second value. + \return true if values are equal. + */ + bool operator()(value_type const& l, value_type const& r) const + { + return detail::std_tuple_equals< + value_type, 0, std::tuple_size<value_type>::value + >::apply(l ,r); + } +}; + +}}} // namespace boost::geometry::index + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP diff --git a/boost/geometry/index/indexable.hpp b/boost/geometry/index/indexable.hpp new file mode 100644 index 000000000..9533fcf9e --- /dev/null +++ b/boost/geometry/index/indexable.hpp @@ -0,0 +1,179 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_INDEXABLE_HPP +#define BOOST_GEOMETRY_INDEX_INDEXABLE_HPP + +#include <boost/mpl/assert.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template <typename Geometry, typename GeometryTag> +struct is_indexable_impl { static const bool value = false; }; + +template <typename Point> +struct is_indexable_impl<Point, geometry::point_tag> { static const bool value = true; }; + +template <typename Box> +struct is_indexable_impl<Box, geometry::box_tag> { static const bool value = true; }; + +template <typename Indexable> +struct is_indexable +{ + static const bool value = + is_indexable_impl<Indexable, typename geometry::traits::tag<Indexable>::type>::value; +}; + +} // namespace detail + +/*! +\brief The function object extracting Indexable from Value. + +It translates Value object to Indexable object. The default version handles Values which are Indexables. +This template is also specialized for std::pair<Indexable, T2> and boost::tuple<Indexable, ...>. + +\tparam Value The Value type which may be translated directly to the Indexable. +*/ +template <typename Value> +struct indexable +{ + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable<Value>::value), + NOT_VALID_INDEXABLE_TYPE, + (Value) + ); + /*! \brief The type of result returned by function object. */ + typedef Value const& result_type; + + /*! + \brief Return indexable extracted from the value. + + \param v The value. + \return The indexable. + */ + result_type operator()(Value const& v) const + { + return v; + } +}; + +/*! +\brief The function object extracting Indexable from Value. + +This specialization translates from std::pair<Indexable, T2>. + +\tparam Indexable The Indexable type. +\tparam T2 The second type. +*/ +template <typename Indexable, typename T2> +struct indexable< std::pair<Indexable, T2> > +{ + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable<Indexable>::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + /*! \brief The type of result returned by function object. */ + typedef Indexable const& result_type; + + /*! + \brief Return indexable extracted from the value. + + \param v The value. + \return The indexable. + */ + result_type operator()(std::pair<Indexable, T2> const& v) const + { + return v.first; + } +}; + +/*! +\brief The function object extracting Indexable from Value. + +This specialization translates from boost::tuple<Indexable, ...>. + +\tparam Indexable The Indexable type. +*/ +template <typename Indexable, typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, typename T9> +struct indexable< boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9> > +{ + typedef boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type; + + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable<Indexable>::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + /*! \brief The type of result returned by function object. */ + typedef Indexable const& result_type; + + /*! + \brief Return indexable extracted from the value. + + \param v The value. + \return The indexable. + */ + result_type operator()(value_type const& v) const + { + return boost::get<0>(v); + } +}; + +}}} // namespace boost::geometry::index + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include <tuple> + +namespace boost { namespace geometry { namespace index { + +/*! +\brief The function object extracting Indexable from Value. + +This specialization translates from std::tuple<Indexable, Args...>. +It's defined if the compiler supports tuples and variadic templates. + +\tparam Indexable The Indexable type. +*/ +template <typename Indexable, typename ...Args> +struct indexable< std::tuple<Indexable, Args...> > +{ + typedef std::tuple<Indexable, Args...> value_type; + + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable<Indexable>::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + /*! \brief The type of result returned by function object. */ + typedef Indexable const& result_type; + + /*! + \brief Return indexable extracted from the value. + + \param v The value. + \return The indexable. + */ + result_type operator()(value_type const& v) const + { + return std::get<0>(v); + } +}; + +}}} // namespace boost::geometry::index + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // BOOST_GEOMETRY_INDEX_INDEXABLE_HPP diff --git a/boost/geometry/index/inserter.hpp b/boost/geometry/index/inserter.hpp new file mode 100644 index 000000000..7c489bc3f --- /dev/null +++ b/boost/geometry/index/inserter.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry Index +// +// Insert iterator +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_INSERTER_HPP +#define BOOST_GEOMETRY_INDEX_INSERTER_HPP + +#include <iterator> + +/*! +\defgroup inserters Inserters (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +template <class Container> +class insert_iterator : + public std::iterator<std::output_iterator_tag, void, void, void, void> +{ +public: + typedef Container container_type; + + inline explicit insert_iterator(Container & c) + : container(&c) + {} + + insert_iterator & operator=(typename Container::value_type const& value) + { + container->insert(value); + return *this; + } + + insert_iterator & operator* () + { + return *this; + } + + insert_iterator & operator++ () + { + return *this; + } + + insert_iterator operator++(int) + { + return *this; + } + +private: + Container * container; +}; + +/*! +\brief Insert iterator generator. + +Returns insert iterator capable to insert values to the container +(spatial index) which has member function insert(value_type const&) defined. + +\ingroup inserters + +\param c The reference to the container (spatial index) to which values will be inserted. + +\return The insert iterator inserting values to the container. +*/ +template <typename Container> +insert_iterator<Container> inserter(Container & c) +{ + return insert_iterator<Container>(c); +} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_INSERTER_HPP diff --git a/boost/geometry/index/parameters.hpp b/boost/geometry/index/parameters.hpp new file mode 100644 index 000000000..2516e6d71 --- /dev/null +++ b/boost/geometry/index/parameters.hpp @@ -0,0 +1,257 @@ +// Boost.Geometry Index +// +// R-tree algorithms parameters +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_PARAMETERS_HPP +#define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP + +#include <limits> + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template <size_t MaxElements> +struct default_min_elements_s +{ + // TODO - assert MaxElements <= (std::numeric_limits<size_t>::max)()/3 + static const size_t raw_value = (MaxElements * 3) / 10; + static const size_t value = 1 <= raw_value ? raw_value : 1; +}; + +inline size_t default_min_elements_d() +{ + return (std::numeric_limits<size_t>::max)(); +} + +inline size_t default_min_elements_d_calc(size_t max_elements, size_t min_elements) +{ + if ( default_min_elements_d() == min_elements ) + { + // TODO - assert MaxElements <= (std::numeric_limits<size_t>::max)()/3 + size_t raw_value = (max_elements * 3) / 10; + return 1 <= raw_value ? raw_value : 1; + } + + return min_elements; +} + +template <size_t MaxElements> +struct default_rstar_reinserted_elements_s +{ + // TODO - assert MaxElements <= (std::numeric_limits<size_t>::max)()/3 + static const size_t value = (MaxElements * 3) / 10; +}; + +inline size_t default_rstar_reinserted_elements_d() +{ + return (std::numeric_limits<size_t>::max)(); +} + +inline size_t default_rstar_reinserted_elements_d_calc(size_t max_elements, size_t reinserted_elements) +{ + if ( default_rstar_reinserted_elements_d() == reinserted_elements ) + { + // TODO - assert MaxElements <= (std::numeric_limits<size_t>::max)()/3 + return (max_elements * 3) / 10; + } + + return reinserted_elements; +} + +} // namespace detail + +/*! +\brief Linear r-tree creation algorithm parameters. + +\tparam MaxElements Maximum number of elements in nodes. +\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max. +*/ +template <size_t MaxElements, + size_t MinElements = detail::default_min_elements_s<MaxElements>::value +> +struct linear +{ + BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1), + INVALID_STATIC_MIN_MAX_PARAMETERS, (linear)); + + static const size_t max_elements = MaxElements; + static const size_t min_elements = MinElements; + + static size_t get_max_elements() { return MaxElements; } + static size_t get_min_elements() { return MinElements; } +}; + +/*! +\brief Quadratic r-tree creation algorithm parameters. + +\tparam MaxElements Maximum number of elements in nodes. +\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max. +*/ +template <size_t MaxElements, + size_t MinElements = detail::default_min_elements_s<MaxElements>::value> +struct quadratic +{ + BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1), + INVALID_STATIC_MIN_MAX_PARAMETERS, (quadratic)); + + static const size_t max_elements = MaxElements; + static const size_t min_elements = MinElements; + + static size_t get_max_elements() { return MaxElements; } + static size_t get_min_elements() { return MinElements; } +}; + +/*! +\brief R*-tree creation algorithm parameters. + +\tparam MaxElements Maximum number of elements in nodes. +\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max. +\tparam ReinsertedElements The number of elements reinserted by forced reinsertions algorithm. + If 0 forced reinsertions are disabled. Maximum value is Max+1-Min. + Greater values are truncated. Default: 0.3*Max. +\tparam OverlapCostThreshold The number of most suitable leafs taken into account while choosing + the leaf node to which currently inserted value will be added. If + value is in range (0, MaxElements) - the algorithm calculates + nearly minimum overlap cost, otherwise all leafs are analyzed + and true minimum overlap cost is calculated. Default: 32. +*/ +template <size_t MaxElements, + size_t MinElements = detail::default_min_elements_s<MaxElements>::value, + size_t ReinsertedElements = detail::default_rstar_reinserted_elements_s<MaxElements>::value, + size_t OverlapCostThreshold = 32> +struct rstar +{ + BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1), + INVALID_STATIC_MIN_MAX_PARAMETERS, (rstar)); + + static const size_t max_elements = MaxElements; + static const size_t min_elements = MinElements; + static const size_t reinserted_elements = ReinsertedElements; + static const size_t overlap_cost_threshold = OverlapCostThreshold; + + static size_t get_max_elements() { return MaxElements; } + static size_t get_min_elements() { return MinElements; } + static size_t get_reinserted_elements() { return ReinsertedElements; } + static size_t get_overlap_cost_threshold() { return OverlapCostThreshold; } +}; + +//template <size_t MaxElements, size_t MinElements> +//struct kmeans +//{ +// static const size_t max_elements = MaxElements; +// static const size_t min_elements = MinElements; +//}; + +/*! +\brief Linear r-tree creation algorithm parameters - run-time version. +*/ +class dynamic_linear +{ +public: + /*! + \brief The constructor. + + \param max_elements Maximum number of elements in nodes. + \param min_elements Minimum number of elements in nodes. Default: 0.3*Max. + */ + dynamic_linear(size_t max_elements, + size_t min_elements = detail::default_min_elements_d()) + : m_max_elements(max_elements) + , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) + { + if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1)) + detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_linear"); + } + + size_t get_max_elements() const { return m_max_elements; } + size_t get_min_elements() const { return m_min_elements; } + +private: + size_t m_max_elements; + size_t m_min_elements; +}; + +/*! +\brief Quadratic r-tree creation algorithm parameters - run-time version. +*/ +class dynamic_quadratic +{ +public: + /*! + \brief The constructor. + + \param max_elements Maximum number of elements in nodes. + \param min_elements Minimum number of elements in nodes. Default: 0.3*Max. + */ + dynamic_quadratic(size_t max_elements, + size_t min_elements = detail::default_min_elements_d()) + : m_max_elements(max_elements) + , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) + { + if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1)) + detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_quadratic"); + } + + size_t get_max_elements() const { return m_max_elements; } + size_t get_min_elements() const { return m_min_elements; } + +private: + size_t m_max_elements; + size_t m_min_elements; +}; + +/*! +\brief R*-tree creation algorithm parameters - run-time version. +*/ +class dynamic_rstar +{ +public: + /*! + \brief The constructor. + + \param max_elements Maximum number of elements in nodes. + \param min_elements Minimum number of elements in nodes. Default: 0.3*Max. + \param reinserted_elements The number of elements reinserted by forced reinsertions algorithm. + If 0 forced reinsertions are disabled. Maximum value is Max-Min+1. + Greater values are truncated. Default: 0.3*Max. + \param overlap_cost_threshold The number of most suitable leafs taken into account while choosing + the leaf node to which currently inserted value will be added. If + value is in range (0, MaxElements) - the algorithm calculates + nearly minimum overlap cost, otherwise all leafs are analyzed + and true minimum overlap cost is calculated. Default: 32. + */ + dynamic_rstar(size_t max_elements, + size_t min_elements = detail::default_min_elements_d(), + size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(), + size_t overlap_cost_threshold = 32) + : m_max_elements(max_elements) + , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) + , m_reinserted_elements(detail::default_rstar_reinserted_elements_d_calc(max_elements, reinserted_elements)) + , m_overlap_cost_threshold(overlap_cost_threshold) + { + if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1)) + detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_rstar"); + } + + size_t get_max_elements() const { return m_max_elements; } + size_t get_min_elements() const { return m_min_elements; } + size_t get_reinserted_elements() const { return m_reinserted_elements; } + size_t get_overlap_cost_threshold() const { return m_overlap_cost_threshold; } + +private: + size_t m_max_elements; + size_t m_min_elements; + size_t m_reinserted_elements; + size_t m_overlap_cost_threshold; +}; + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_PARAMETERS_HPP diff --git a/boost/geometry/index/predicates.hpp b/boost/geometry/index/predicates.hpp new file mode 100644 index 000000000..5bf88df05 --- /dev/null +++ b/boost/geometry/index/predicates.hpp @@ -0,0 +1,394 @@ +// Boost.Geometry Index +// +// Spatial query predicates +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_PREDICATES_HPP + +#include <utility> +#include <boost/tuple/tuple.hpp> +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/index/detail/predicates.hpp> +#include <boost/geometry/index/detail/tuples.hpp> + +/*! +\defgroup predicates Predicates (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c contains() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::within(Geometry, Indexable)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::contains(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::contains_tag, false> +contains(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::contains_tag, false>(g); +} + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c covered_by() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::covered_by(Indexable, Geometry)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::covered_by(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::covered_by_tag, false> +covered_by(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::covered_by_tag, false>(g); +} + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c covers() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::covered_by(Geometry, Indexable)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::covers(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::covers_tag, false> +covers(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::covers_tag, false>(g); +} + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c disjoint() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::disjoint(Indexable, Geometry)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::disjoint(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::disjoint_tag, false> +disjoint(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::disjoint_tag, false>(g); +} + +/*! +\brief Generate \c intersects() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::intersects(Indexable, Geometry)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::intersects(box), std::back_inserter(result)); +bgi::query(spatial_index, bgi::intersects(ring), std::back_inserter(result)); +bgi::query(spatial_index, bgi::intersects(polygon), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::intersects_tag, false> +intersects(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::intersects_tag, false>(g); +} + +/*! +\brief Generate \c overlaps() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::overlaps(Indexable, Geometry)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::overlaps(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::overlaps_tag, false> +overlaps(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::overlaps_tag, false>(g); +} + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c touches() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::touches(Indexable, Geometry)</tt> +returns true. + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::touches_tag, false> +touches(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::touches_tag, false>(g); +} + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate \c within() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if <tt>bg::within(Indexable, Geometry)</tt> +returns true. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::within(box), std::back_inserter(result)); +\endverbatim + +\ingroup predicates + +\tparam Geometry The Geometry type. + +\param g The Geometry object. +*/ +template <typename Geometry> inline +detail::spatial_predicate<Geometry, detail::within_tag, false> +within(Geometry const& g) +{ + return detail::spatial_predicate<Geometry, detail::within_tag, false>(g); +} + +/*! +\brief Generate satisfies() predicate. + +A wrapper around user-defined UnaryPredicate checking if Value should be returned by spatial query. + +\par Example +\verbatim +bool is_red(Value const& v) { return v.is_red(); } + +struct is_red_o { +template <typename Value> bool operator()(Value const& v) { return v.is_red(); } +} + +// ... + +rt.query(index::intersects(box) && index::satisfies(is_red), +std::back_inserter(result)); + +rt.query(index::intersects(box) && index::satisfies(is_red_o()), +std::back_inserter(result)); + +#ifndef BOOST_NO_CXX11_LAMBDAS +rt.query(index::intersects(box) && index::satisfies([](Value const& v) { return v.is_red(); }), +std::back_inserter(result)); +#endif +\endverbatim + +\ingroup predicates + +\tparam UnaryPredicate A type of unary predicate function or function object. + +\param pred The unary predicate function or function object. +*/ +template <typename UnaryPredicate> inline +detail::satisfies<UnaryPredicate, false> +satisfies(UnaryPredicate const& pred) +{ + return detail::satisfies<UnaryPredicate, false>(pred); +} + +/*! +\brief Generate nearest() predicate. + +When nearest predicate is passed to the query, k-nearest neighbour search will be performed. +\c nearest() predicate takes a \c Point from which distance to \c Values is calculated +and the maximum number of \c Values that should be returned. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::nearest(pt, 5), std::back_inserter(result)); +bgi::query(spatial_index, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result)); +\endverbatim + +\warning +Only one \c nearest() predicate may be used in a query. + +\ingroup predicates + +\param point The point from which distance is calculated. +\param k The maximum number of values to return. +*/ +template <typename Point> inline +detail::nearest<Point> +nearest(Point const& point, unsigned k) +{ + return detail::nearest<Point>(point, k); +} + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +/*! +\brief Generate path() predicate. + +When path predicate is passed to the query, the returned values are k values along the path closest to +its begin. \c path() predicate takes a \c Segment or a \c Linestring defining the path and the maximum +number of \c Values that should be returned. + +\par Example +\verbatim +bgi::query(spatial_index, bgi::path(segment, 5), std::back_inserter(result)); +bgi::query(spatial_index, bgi::path(linestring, 5) && bgi::intersects(box), std::back_inserter(result)); +\endverbatim + +\warning +Only one distance predicate (\c nearest() or \c path()) may be used in a query. + +\ingroup predicates + +\param linestring The path along which distance is calculated. +\param k The maximum number of values to return. +*/ +template <typename SegmentOrLinestring> inline +detail::path<SegmentOrLinestring> +path(SegmentOrLinestring const& linestring, unsigned k) +{ + return detail::path<SegmentOrLinestring>(linestring, k); +} + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +namespace detail { + +// operator! generators + +template <typename Fun, bool Negated> inline +satisfies<Fun, !Negated> +operator!(satisfies<Fun, Negated> const& p) +{ + return satisfies<Fun, !Negated>(p); +} + +template <typename Geometry, typename Tag, bool Negated> inline +spatial_predicate<Geometry, Tag, !Negated> +operator!(spatial_predicate<Geometry, Tag, Negated> const& p) +{ + return spatial_predicate<Geometry, Tag, !Negated>(p.geometry); +} + +// operator&& generators + +template <typename Pred1, typename Pred2> inline +boost::tuples::cons< + Pred1, + boost::tuples::cons<Pred2, boost::tuples::null_type> +> +operator&&(Pred1 const& p1, Pred2 const& p2) +{ + /*typedef typename boost::mpl::if_c<is_predicate<Pred1>::value, Pred1, Pred1 const&>::type stored1; + typedef typename boost::mpl::if_c<is_predicate<Pred2>::value, Pred2, Pred2 const&>::type stored2;*/ + namespace bt = boost::tuples; + + return + bt::cons< Pred1, bt::cons<Pred2, bt::null_type> > + ( p1, bt::cons<Pred2, bt::null_type>(p2, bt::null_type()) ); +} + +template <typename Head, typename Tail, typename Pred> inline +typename tuples::push_back_impl< + boost::tuples::cons<Head, Tail>, + Pred, + 0, + boost::tuples::length<boost::tuples::cons<Head, Tail> >::value +>::type +operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p) +{ + //typedef typename boost::mpl::if_c<is_predicate<Pred>::value, Pred, Pred const&>::type stored; + namespace bt = boost::tuples; + + return + tuples::push_back_impl< + bt::cons<Head, Tail>, Pred, 0, bt::length< bt::cons<Head, Tail> >::value + >::apply(t, p); +} + +} // namespace detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_PREDICATES_HPP diff --git a/boost/geometry/index/rtree.hpp b/boost/geometry/index/rtree.hpp new file mode 100644 index 000000000..018d508f6 --- /dev/null +++ b/boost/geometry/index/rtree.hpp @@ -0,0 +1,1550 @@ +// Boost.Geometry Index +// +// R-tree implementation +// +// Copyright (c) 2008 Federico J. Fernandez. +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_RTREE_HPP +#define BOOST_GEOMETRY_INDEX_RTREE_HPP + +#include <algorithm> + +#include <boost/tuple/tuple.hpp> +#include <boost/move/move.hpp> + +#include <boost/geometry/geometry.hpp> + +#include <boost/geometry/index/detail/config_begin.hpp> + +#include <boost/geometry/index/detail/assert.hpp> +#include <boost/geometry/index/detail/exception.hpp> + +#include <boost/geometry/index/detail/rtree/options.hpp> + +#include <boost/geometry/index/indexable.hpp> +#include <boost/geometry/index/equal_to.hpp> + +#include <boost/geometry/index/detail/translator.hpp> + +#include <boost/geometry/index/predicates.hpp> +#include <boost/geometry/index/distance_predicates.hpp> +#include <boost/geometry/index/detail/rtree/adaptors.hpp> + +#include <boost/geometry/index/detail/meta.hpp> +#include <boost/geometry/index/detail/utilities.hpp> +#include <boost/geometry/index/detail/rtree/node/node.hpp> + +#include <boost/geometry/index/detail/algorithms/is_valid.hpp> + +#include <boost/geometry/index/detail/rtree/visitors/insert.hpp> +#include <boost/geometry/index/detail/rtree/visitors/remove.hpp> +#include <boost/geometry/index/detail/rtree/visitors/copy.hpp> +#include <boost/geometry/index/detail/rtree/visitors/destroy.hpp> +#include <boost/geometry/index/detail/rtree/visitors/spatial_query.hpp> +#include <boost/geometry/index/detail/rtree/visitors/distance_query.hpp> +#include <boost/geometry/index/detail/rtree/visitors/count.hpp> +#include <boost/geometry/index/detail/rtree/visitors/children_box.hpp> + +#include <boost/geometry/index/detail/rtree/linear/linear.hpp> +#include <boost/geometry/index/detail/rtree/quadratic/quadratic.hpp> +#include <boost/geometry/index/detail/rtree/rstar/rstar.hpp> +//#include <boost/geometry/extensions/index/detail/rtree/kmeans/kmeans.hpp> + +#include <boost/geometry/index/detail/rtree/pack_create.hpp> + +#include <boost/geometry/index/inserter.hpp> + +#include <boost/geometry/index/detail/rtree/utilities/view.hpp> + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL +#include <boost/geometry/index/detail/rtree/query_iterators.hpp> +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_TYPE_ERASED_ITERATORS +#include <boost/geometry/index/detail/type_erased_iterators.hpp> +#endif +#endif + +// TODO change the name to bounding_tree + +/*! +\defgroup rtree_functions R-tree free functions (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +/*! +\brief The R-tree spatial index. + +This is self-balancing spatial index capable to store various types of Values and balancing algorithms. + +\par Parameters +The user must pass a type defining the Parameters which will +be used in rtree creation process. This type is used e.g. to specify balancing algorithm +with specific parameters like min and max number of elements in node. + +\par +Predefined algorithms with compile-time parameters are: +\li <tt>boost::geometry::index::linear</tt>, + \li <tt>boost::geometry::index::quadratic</tt>, + \li <tt>boost::geometry::index::rstar</tt>. + +\par +Predefined algorithms with run-time parameters are: + \li \c boost::geometry::index::dynamic_linear, + \li \c boost::geometry::index::dynamic_quadratic, + \li \c boost::geometry::index::dynamic_rstar. + +\par Translator +The Translator translates from Value to Indexable each time r-tree requires it. Which means that this +operation is done for each Value access. Therefore the Translator should return the Indexable by +const reference instead of a value. Default translator can translate all types adapted to Point +or Box concepts (called Indexables). It also handles <tt>std::pair<Indexable, T></tt> and +<tt>boost::tuple<Indexable, ...></tt>. For example, if <tt>std::pair<Box, int></tt> is stored in the +container, the default translator translates from <tt>std::pair<Box, int> const&</tt> to <tt>Box const&</tt>. + +\tparam Value The type of objects stored in the container. +\tparam Parameters Compile-time parameters. +\tparam IndexableGetter The function object extracting Indexable from Value. +\tparam EqualTo The function object comparing objects of type Value. +\tparam Allocator The allocator used to allocate/deallocate memory, construct/destroy nodes and Values. +*/ +template < + typename Value, + typename Parameters, + typename IndexableGetter = index::indexable<Value>, + typename EqualTo = index::equal_to<Value>, + typename Allocator = std::allocator<Value> +> +class rtree +{ + BOOST_COPYABLE_AND_MOVABLE(rtree) + +public: + /*! \brief The type of Value stored in the container. */ + typedef Value value_type; + /*! \brief R-tree parameters type. */ + typedef Parameters parameters_type; + /*! \brief The function object extracting Indexable from Value. */ + typedef IndexableGetter indexable_getter; + /*! \brief The function object comparing objects of type Value. */ + typedef EqualTo value_equal; + /*! \brief The type of allocator used by the container. */ + typedef Allocator allocator_type; + + // TODO: SHOULD THIS TYPE BE REMOVED? + /*! \brief The Indexable type to which Value is translated. */ + typedef typename index::detail::indexable_type< + detail::translator<IndexableGetter, EqualTo> + >::type indexable_type; + + /*! \brief The Box type used by the R-tree. */ + typedef geometry::model::box< + geometry::model::point< + typename coordinate_type<indexable_type>::type, + dimension<indexable_type>::value, + typename coordinate_system<indexable_type>::type + > + > + bounds_type; + +private: + + typedef detail::translator<IndexableGetter, EqualTo> translator_type; + + typedef bounds_type box_type; + typedef typename detail::rtree::options_type<Parameters>::type options_type; + typedef typename options_type::node_tag node_tag; + typedef detail::rtree::allocators<allocator_type, value_type, typename options_type::parameters_type, box_type, node_tag> allocators_type; + + typedef typename detail::rtree::node<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type node; + typedef typename detail::rtree::internal_node<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type internal_node; + typedef typename detail::rtree::leaf<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type leaf; + + typedef typename allocators_type::node_pointer node_pointer; + typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type; + + friend class detail::rtree::utilities::view<rtree>; + +public: + + /*! \brief Type of reference to Value. */ + typedef typename allocators_type::reference reference; + /*! \brief Type of reference to const Value. */ + typedef typename allocators_type::const_reference const_reference; + /*! \brief Type of pointer to Value. */ + typedef typename allocators_type::pointer pointer; + /*! \brief Type of pointer to const Value. */ + typedef typename allocators_type::const_pointer const_pointer; + /*! \brief Type of difference type. */ + typedef typename allocators_type::difference_type difference_type; + /*! \brief Unsigned integral type used by the container. */ + typedef typename allocators_type::size_type size_type; + +public: + + /*! + \brief The constructor. + + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + + \par Throws + If allocator default constructor throws. + */ + inline explicit rtree(parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal()) + : m_members(getter, equal, parameters) + {} + + /*! + \brief The constructor. + + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + If allocator copy constructor throws. + */ + inline rtree(parameters_type const& parameters, + indexable_getter const& getter, + value_equal const& equal, + allocator_type const& allocator) + : m_members(getter, equal, parameters, allocator) + {} + + /*! + \brief The constructor. + + \param first The beginning of the range of Values. + \param last The end of the range of Values. + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + */ + template<typename Iterator> + inline rtree(Iterator first, Iterator last, + parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal(), + allocator_type const& allocator = allocator_type()) + : m_members(getter, equal, parameters, allocator) + { + typedef detail::rtree::pack<value_type, options_type, translator_type, box_type, allocators_type> pack; + size_type vc = 0, ll = 0; + m_members.root = pack::apply(first, last, vc, ll, + m_members.parameters(), m_members.translator(), m_members.allocators()); + m_members.values_count = vc; + m_members.leafs_level = ll; + } + + /*! + \brief The constructor. + + \param rng The range of Values. + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + */ + template<typename Range> + inline explicit rtree(Range const& rng, + parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal(), + allocator_type const& allocator = allocator_type()) + : m_members(getter, equal, parameters, allocator) + { + typedef detail::rtree::pack<value_type, options_type, translator_type, box_type, allocators_type> pack; + size_type vc = 0, ll = 0; + m_members.root = pack::apply(::boost::begin(rng), ::boost::end(rng), vc, ll, + m_members.parameters(), m_members.translator(), m_members.allocators()); + m_members.values_count = vc; + m_members.leafs_level = ll; + } + + /*! + \brief The destructor. + + \par Throws + Nothing. + */ + inline ~rtree() + { + this->raw_destroy(*this); + } + + /*! + \brief The copy constructor. + + It uses parameters, translator and allocator from the source tree. + + \param src The rtree which content will be copied. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws. + \li If allocation throws or returns invalid value. + */ + inline rtree(rtree const& src) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + allocator_traits_type::select_on_container_copy_construction(src.get_allocator())) + { + this->raw_copy(src, *this, false); + } + + /*! + \brief The copy constructor. + + It uses Parameters and translator from the source tree. + + \param src The rtree which content will be copied. + \param allocator The allocator which will be used. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws. + \li If allocation throws or returns invalid value. + */ + inline rtree(rtree const& src, allocator_type const& allocator) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), allocator) + { + this->raw_copy(src, *this, false); + } + + /*! + \brief The moving constructor. + + It uses parameters, translator and allocator from the source tree. + + \param src The rtree which content will be moved. + + \par Throws + Nothing. + */ + inline rtree(BOOST_RV_REF(rtree) src) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + boost::move(src.m_members.allocators())) + { + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + } + + /*! + \brief The moving constructor. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be moved. + \param allocator The allocator. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws (only if allocators aren't equal). + \li If allocation throws or returns invalid value (only if allocators aren't equal). + */ + inline rtree(BOOST_RV_REF(rtree) src, allocator_type const& allocator) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + allocator) + { + if ( src.m_members.allocators() == allocator ) + { + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + } + else + { + this->raw_copy(src, *this, false); + } + } + + /*! + \brief The assignment operator. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be copied. + + \par Throws + \li If Value copy constructor throws. + \li If allocation throws. + \li If allocation throws or returns invalid value. + */ + inline rtree & operator=(BOOST_COPY_ASSIGN_REF(rtree) src) + { + if ( &src != this ) + { + allocators_type & this_allocs = m_members.allocators(); + allocators_type const& src_allocs = src.m_members.allocators(); + + // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++ + // (allocators stored as base classes of members_holder) + // copying them changes values_count, in this case it doesn't cause errors since data must be copied + + typedef boost::mpl::bool_< + allocator_traits_type::propagate_on_container_copy_assignment::value + > propagate; + + if ( propagate::value && !(this_allocs == src_allocs) ) + this->raw_destroy(*this); + detail::assign_cond(this_allocs, src_allocs, propagate()); + + // It uses m_allocators + this->raw_copy(src, *this, true); + } + + return *this; + } + + /*! + \brief The moving assignment. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be moved. + + \par Throws + Only if allocators aren't equal. + \li If Value copy constructor throws. + \li If allocation throws or returns invalid value. + */ + inline rtree & operator=(BOOST_RV_REF(rtree) src) + { + if ( &src != this ) + { + allocators_type & this_allocs = m_members.allocators(); + allocators_type & src_allocs = src.m_members.allocators(); + + if ( this_allocs == src_allocs ) + { + this->raw_destroy(*this); + + m_members.indexable_getter() = src.m_members.indexable_getter(); + m_members.equal_to() = src.m_members.equal_to(); + m_members.parameters() = src.m_members.parameters(); + + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + + // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++ + // (allocators stored as base classes of members_holder) + // moving them changes values_count + + typedef boost::mpl::bool_< + allocator_traits_type::propagate_on_container_move_assignment::value + > propagate; + detail::move_cond(this_allocs, src_allocs, propagate()); + } + else + { +// TODO - shouldn't here propagate_on_container_copy_assignment be checked like in operator=(const&)? + + // It uses m_allocators + this->raw_copy(src, *this, true); + } + } + + return *this; + } + + /*! + \brief Swaps contents of two rtrees. + + Parameters, translator and allocators are swapped as well. + + \param other The rtree which content will be swapped with this rtree content. + + \par Throws + If allocators swap throws. + */ + void swap(rtree & other) + { + boost::swap(m_members.indexable_getter(), other.m_members.indexable_getter()); + boost::swap(m_members.equal_to(), other.m_members.equal_to()); + boost::swap(m_members.parameters(), other.m_members.parameters()); + + // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++ + // (allocators stored as base classes of members_holder) + // swapping them changes values_count + + typedef boost::mpl::bool_< + allocator_traits_type::propagate_on_container_swap::value + > propagate; + detail::swap_cond(m_members.allocators(), other.m_members.allocators(), propagate()); + + boost::swap(m_members.values_count, other.m_members.values_count); + boost::swap(m_members.leafs_level, other.m_members.leafs_level); + boost::swap(m_members.root, other.m_members.root); + } + + /*! + \brief Insert a value to the index. + + \param value The value which will be stored in the container. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + inline void insert(value_type const& value) + { + if ( !m_members.root ) + this->raw_create(); + + this->raw_insert(value); + } + + /*! + \brief Insert a range of values to the index. + + \param first The beginning of the range of values. + \param last The end of the range of values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + template <typename Iterator> + inline void insert(Iterator first, Iterator last) + { + if ( !m_members.root ) + this->raw_create(); + + for ( ; first != last ; ++first ) + this->raw_insert(*first); + } + + /*! + \brief Insert a range of values to the index. + + \param rng The range of values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + template <typename Range> + inline void insert(Range const& rng) + { + BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value), PASSED_OBJECT_IS_NOT_A_RANGE, (Range)); + + if ( !m_members.root ) + this->raw_create(); + + typedef typename boost::range_const_iterator<Range>::type It; + for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it ) + this->raw_insert(*it); + } + + /*! + \brief Remove a value from the container. + + In contrast to the \c std::set or <tt>std::map erase()</tt> method + this method removes only one value from the container. + + \param value The value which will be removed from the container. + + \return 1 if the value was removed, 0 otherwise. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + inline size_type remove(value_type const& value) + { + return this->raw_remove(value); + } + + /*! + \brief Remove a range of values from the container. + + In contrast to the \c std::set or <tt>std::map erase()</tt> method + it doesn't take iterators pointing to values stored in this container. It removes values equal + to these passed as a range. Furthermore this method removes only one value for each one passed + in the range, not all equal values. + + \param first The beginning of the range of values. + \param last The end of the range of values. + + \return The number of removed values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + template <typename Iterator> + inline size_type remove(Iterator first, Iterator last) + { + size_type result = 0; + for ( ; first != last ; ++first ) + result += this->raw_remove(*first); + return result; + } + + /*! + \brief Remove a range of values from the container. + + In contrast to the \c std::set or <tt>std::map erase()</tt> method + it removes values equal to these passed as a range. Furthermore, this method removes only + one value for each one passed in the range, not all equal values. + + \param rng The range of values. + + \return The number of removed values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws or returns invalid value. + + \warning + This operation only guarantees that there will be no memory leaks. + After an exception is thrown the R-tree may be left in an inconsistent state, + elements must not be inserted or removed. Other operations are allowed however + some of them may return invalid data. + */ + template <typename Range> + inline size_type remove(Range const& rng) + { + BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value), PASSED_OBJECT_IS_NOT_A_RANGE, (Range)); + + size_type result = 0; + typedef typename boost::range_const_iterator<Range>::type It; + for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it ) + result += this->raw_remove(*it); + return result; + } + + /*! + \brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box. + + This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates. + Values will be returned only if all predicates are met. + + <b>Spatial predicates</b> + + Spatial predicates may be generated by one of the functions listed below: + \li \c boost::geometry::index::covered_by(), + \li \c boost::geometry::index::disjoint(), + \li \c boost::geometry::index::intersects(), + \li \c boost::geometry::index::overlaps(), + \li \c boost::geometry::index::within(), + + It is possible to negate spatial predicates: + \li <tt>! boost::geometry::index::covered_by()</tt>, + \li <tt>! boost::geometry::index::disjoint()</tt>, + \li <tt>! boost::geometry::index::intersects()</tt>, + \li <tt>! boost::geometry::index::overlaps()</tt>, + \li <tt>! boost::geometry::index::within()</tt> + + <b>Satisfies predicate</b> + + This is a special kind of predicate which allows to pass a user-defined function or function object which checks + if Value should be returned by the query. It's generated by: + \li \c boost::geometry::index::satisfies(). + + <b>Nearest predicate</b> + + If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result + in returning k values to the output iterator. Only one nearest predicate may be passed to the query. + It may be generated by: + \li \c boost::geometry::index::nearest(). + + <b>Connecting predicates</b> + + Predicates may be passed together connected with \c operator&&(). + + \par Example + \verbatim + // return elements intersecting box + tree.query(bgi::intersects(box), std::back_inserter(result)); + // return elements intersecting poly but not within box + tree.query(bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result)); + // return elements overlapping box and meeting my_fun unary predicate + tree.query(bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result)); + // return 5 elements nearest to pt and elements are intersecting box + tree.query(bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result)); + \endverbatim + + \par Throws + If Value copy constructor or copy assignment throws. + + \warning + Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error. + + \param predicates Predicates. + \param out_it The output iterator, e.g. generated by std::back_inserter(). + + \return The number of values found. + */ + template <typename Predicates, typename OutIter> + size_type query(Predicates const& predicates, OutIter out_it) const + { + if ( !m_members.root ) + return 0; + + static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value; + static const bool is_distance_predicate = 0 < distance_predicates_count; + BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates)); + + return query_dispatch(predicates, out_it, boost::mpl::bool_<is_distance_predicate>()); + } + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_TYPE_ERASED_ITERATORS + + // BEWARE! + // Don't use this type-erased iterator after assigning values returned by qbegin(Pred) and qend() + // e.g. don't pass them into the std::copy() or compare them like this: + // const_query_iterator i1 = qbegin(...); + // const_query_iterator i2 = qend(); + // i1 == i2; // BAM! + // now this will cause undefined behaviour. + // using native types is ok: + // qbegin(...) == qend(); + + typedef typename index::detail::single_pass_iterator_type< + value_type, const_reference, const_pointer, difference_type + >::type const_query_iterator; + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_TYPE_ERASED_ITERATORS + + template <typename Predicates> + typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::distance_query_iterator< + value_type, options_type, translator_type, box_type, allocators_type, Predicates, + detail::predicates_find_distance<Predicates>::value + > + >::type + qbegin(Predicates const& predicates) const + { + static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value; + BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates)); + + typedef typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::distance_query_iterator< + value_type, options_type, translator_type, box_type, allocators_type, Predicates, + detail::predicates_find_distance<Predicates>::value + > + >::type iterator_type; + + if ( !m_members.root ) + return iterator_type(m_members.translator(), predicates); + + return iterator_type(m_members.root, m_members.translator(), predicates); + } + + template <typename Predicates> + typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::distance_query_iterator< + value_type, options_type, translator_type, box_type, allocators_type, Predicates, + detail::predicates_find_distance<Predicates>::value + > + >::type + qend(Predicates const& predicates) const + { + static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value; + BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates)); + + typedef typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::distance_query_iterator< + value_type, options_type, translator_type, box_type, allocators_type, Predicates, + detail::predicates_find_distance<Predicates>::value + > + >::type iterator_type; + + return iterator_type(m_members.translator(), predicates); + } + + detail::rtree::end_query_iterator<value_type, allocators_type> + qend() const + { + return detail::rtree::end_query_iterator<value_type, allocators_type>(); + } + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + + /*! + \brief Returns the number of stored values. + + \return The number of stored values. + + \par Throws + Nothing. + */ + inline size_type size() const + { + return m_members.values_count; + } + + /*! + \brief Query if the container is empty. + + \return true if the container is empty. + + \par Throws + Nothing. + */ + inline bool empty() const + { + return 0 == m_members.values_count; + } + + /*! + \brief Removes all values stored in the container. + + \par Throws + Nothing. + */ + inline void clear() + { + this->raw_destroy(*this); + } + + /*! + \brief Returns the box able to contain all values stored in the container. + + Returns the box able to contain all values stored in the container. + If the container is empty the result of \c geometry::assign_inverse() is returned. + + \return The box able to contain all values stored in the container or an invalid box if + there are no values in the container. + + \par Throws + Nothing. + */ + inline bounds_type bounds() const + { + bounds_type result; + if ( !m_members.root ) + { + geometry::assign_inverse(result); + return result; + } + + detail::rtree::visitors::children_box<value_type, options_type, translator_type, box_type, allocators_type> + box_v(result, m_members.translator()); + detail::rtree::apply_visitor(box_v, *m_members.root); + + return result; + } + + /*! + \brief Count Values or Indexables stored in the container. + + For indexable_type it returns the number of values which indexables equals the parameter. + For value_type it returns the number of values which equals the parameter. + + \param vori The value or indexable which will be counted. + + \return The number of values found. + + \par Throws + Nothing. + */ + template <typename ValueOrIndexable> + size_type count(ValueOrIndexable const& vori) const + { + if ( !m_members.root ) + return 0; + + detail::rtree::visitors::count<ValueOrIndexable, value_type, options_type, translator_type, box_type, allocators_type> + count_v(vori, m_members.translator()); + + detail::rtree::apply_visitor(count_v, *m_members.root); + + return count_v.found_count; + } + + /*! + \brief Returns parameters. + + \return The parameters object. + + \par Throws + Nothing. + */ + inline parameters_type parameters() const + { + return m_members.parameters(); + } + + /*! + \brief Returns function retrieving Indexable from Value. + + \return The indexable_getter object. + + \par Throws + Nothing. + */ + indexable_getter indexable_get() const + { + return m_members.indexable_getter(); + } + + /*! + \brief Returns function comparing Values + + \return The value_equal function. + + \par Throws + Nothing. + */ + value_equal value_eq() const + { + return m_members.equal_to(); + } + + /*! + \brief Returns allocator used by the rtree. + + \return The allocator. + + \par Throws + If allocator copy constructor throws. + */ + allocator_type get_allocator() const + { + return m_members.allocators().allocator(); + } + +private: + + /*! + \brief Returns the translator object. + + \return The translator object. + + \par Throws + Nothing. + */ + inline translator_type translator() const + { + return m_members.translator(); + } + + /*! + \brief Apply a visitor to the nodes structure in order to perform some operator. + + This function is not a part of the 'official' interface. However it makes + possible e.g. to pass a visitor drawing the tree structure. + + \param visitor The visitor object. + + \par Throws + If Visitor::operator() throws. + */ + template <typename Visitor> + inline void apply_visitor(Visitor & visitor) const + { + if ( m_members.root ) + detail::rtree::apply_visitor(visitor, *m_members.root); + } + + /*! + \brief Returns the depth of the R-tree. + + This function is not a part of the 'official' interface. + + \return The depth of the R-tree. + + \par Throws + Nothing. + */ + inline size_type depth() const + { + return m_members.leafs_level; + } + +private: + + /*! + \pre Root node must exist - m_root != 0. + + \brief Insert a value to the index. + + \param value The value which will be stored in the container. + + \par Exception-safety + basic + */ + inline void raw_insert(value_type const& value) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(m_members.translator()(value)), "Indexable is invalid"); + + detail::rtree::visitors::insert< + value_type, + value_type, options_type, translator_type, box_type, allocators_type, + typename options_type::insert_tag + > insert_v(m_members.root, m_members.leafs_level, value, + m_members.parameters(), m_members.translator(), m_members.allocators()); + + detail::rtree::apply_visitor(insert_v, *m_members.root); + +// TODO +// Think about this: If exception is thrown, may the root be removed? +// Or it is just cleared? + +// TODO +// If exception is thrown, m_values_count may be invalid + ++m_members.values_count; + } + + /*! + \brief Remove the value from the container. + + \param value The value which will be removed from the container. + + \par Exception-safety + basic + */ + inline size_type raw_remove(value_type const& value) + { + // TODO: awulkiew - assert for correct value (indexable) ? + BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + + detail::rtree::visitors::remove< + value_type, options_type, translator_type, box_type, allocators_type + > remove_v(m_members.root, m_members.leafs_level, value, + m_members.parameters(), m_members.translator(), m_members.allocators()); + + detail::rtree::apply_visitor(remove_v, *m_members.root); + + // If exception is thrown, m_values_count may be invalid + + if ( remove_v.is_value_removed() ) + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_members.values_count, "unexpected state"); + + --m_members.values_count; + + return 1; + } + + return 0; + } + + /*! + \brief Create an empty R-tree i.e. new empty root node and clear other attributes. + + \par Exception-safety + strong + */ + inline void raw_create() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 == m_members.root, "the tree is already created"); + + m_members.root = detail::rtree::create_node<allocators_type, leaf>::apply(m_members.allocators()); // MAY THROW (N: alloc) + m_members.values_count = 0; + m_members.leafs_level = 0; + } + + /*! + \brief Destroy the R-tree i.e. all nodes and clear attributes. + + \param t The container which is going to be destroyed. + + \par Exception-safety + nothrow + */ + inline void raw_destroy(rtree & t) + { + if ( t.m_members.root ) + { + detail::rtree::visitors::destroy<value_type, options_type, translator_type, box_type, allocators_type> + del_v(t.m_members.root, t.m_members.allocators()); + detail::rtree::apply_visitor(del_v, *t.m_members.root); + + t.m_members.root = 0; + } + t.m_members.values_count = 0; + t.m_members.leafs_level = 0; + } + + /*! + \brief Copy the R-tree i.e. whole nodes structure, values and other attributes. + It uses destination's allocators to create the new structure. + + \param src The source R-tree. + \param dst The destination R-tree. + \param copy_tr_and_params If true, translator and parameters will also be copied. + + \par Exception-safety + strong + */ + inline void raw_copy(rtree const& src, rtree & dst, bool copy_tr_and_params) const + { + detail::rtree::visitors::copy<value_type, options_type, translator_type, box_type, allocators_type> + copy_v(dst.m_members.allocators()); + + if ( src.m_members.root ) + detail::rtree::apply_visitor(copy_v, *src.m_members.root); // MAY THROW (V, E: alloc, copy, N: alloc) + + if ( copy_tr_and_params ) + { + dst.m_members.indexable_getter() = src.m_members.indexable_getter(); + dst.m_members.equal_to() = src.m_members.equal_to(); + dst.m_members.parameters() = src.m_members.parameters(); + } + + if ( dst.m_members.root ) + { + detail::rtree::visitors::destroy<value_type, options_type, translator_type, box_type, allocators_type> + del_v(dst.m_members.root, dst.m_members.allocators()); + detail::rtree::apply_visitor(del_v, *dst.m_members.root); + dst.m_members.root = 0; + } + + dst.m_members.root = copy_v.result; + dst.m_members.values_count = src.m_members.values_count; + dst.m_members.leafs_level = src.m_members.leafs_level; + } + + /*! + \brief Return values meeting predicates. + + \par Exception-safety + strong + */ + template <typename Predicates, typename OutIter> + size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_<false> const& /*is_distance_predicate*/) const + { + detail::rtree::visitors::spatial_query<value_type, options_type, translator_type, box_type, allocators_type, Predicates, OutIter> + find_v(m_members.translator(), predicates, out_it); + + detail::rtree::apply_visitor(find_v, *m_members.root); + + return find_v.found_count; + } + + /*! + \brief Perform nearest neighbour search. + + \par Exception-safety + strong + */ + template <typename Predicates, typename OutIter> + size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_<true> const& /*is_distance_predicate*/) const + { + static const unsigned distance_predicate_index = detail::predicates_find_distance<Predicates>::value; + detail::rtree::visitors::distance_query< + value_type, + options_type, + translator_type, + box_type, + allocators_type, + Predicates, + distance_predicate_index, + OutIter + > distance_v(m_members.parameters(), m_members.translator(), predicates, out_it); + + detail::rtree::apply_visitor(distance_v, *m_members.root); + + return distance_v.finish(); + } + + struct members_holder + : public translator_type + , public Parameters + , public allocators_type + { + private: + members_holder(members_holder const&); + members_holder & operator=(members_holder const&); + + public: + template <typename IndGet, typename ValEq, typename Alloc> + members_holder(IndGet const& ind_get, + ValEq const& val_eq, + Parameters const& parameters, + BOOST_FWD_REF(Alloc) alloc) + : translator_type(ind_get, val_eq) + , Parameters(parameters) + , allocators_type(boost::forward<Alloc>(alloc)) + , values_count(0) + , leafs_level(0) + , root(0) + {} + + template <typename IndGet, typename ValEq> + members_holder(IndGet const& ind_get, + ValEq const& val_eq, + Parameters const& parameters) + : translator_type(ind_get, val_eq) + , Parameters(parameters) + , allocators_type() + , values_count(0) + , leafs_level(0) + , root(0) + {} + + translator_type const& translator() const { return *this; } + + IndexableGetter const& indexable_getter() const { return *this; } + IndexableGetter & indexable_getter() { return *this; } + EqualTo const& equal_to() const { return *this; } + EqualTo & equal_to() { return *this; } + Parameters const& parameters() const { return *this; } + Parameters & parameters() { return *this; } + allocators_type const& allocators() const { return *this; } + allocators_type & allocators() { return *this; } + + size_type values_count; + size_type leafs_level; + node_pointer root; + }; + + members_holder m_members; +}; + +/*! +\brief Insert a value to the index. + +It calls <tt>rtree::insert(value_type const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param v The value which will be stored in the index. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Value const& v) +{ + tree.insert(v); +} + +/*! +\brief Insert a range of values to the index. + +It calls <tt>rtree::insert(Iterator, Iterator)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param first The beginning of the range of values. +\param last The end of the range of values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, typename Iterator> +inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Iterator first, Iterator last) +{ + tree.insert(first, last); +} + +/*! +\brief Insert a range of values to the index. + +It calls <tt>rtree::insert(Range const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param rng The range of values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, typename Range> +inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Range const& rng) +{ + tree.insert(rng); +} + +/*! +\brief Remove a value from the container. + +Remove a value from the container. In contrast to the \c std::set or <tt>std::map erase()</tt> method +this function removes only one value from the container. + +It calls <tt>rtree::remove(value_type const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param v The value which will be removed from the index. + +\return 1 if value was removed, 0 otherwise. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type +remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Value const& v) +{ + return tree.remove(v); +} + +/*! +\brief Remove a range of values from the container. + +Remove a range of values from the container. In contrast to the \c std::set or <tt>std::map erase()</tt> method +it doesn't take iterators pointing to values stored in this container. It removes values equal +to these passed as a range. Furthermore this function removes only one value for each one passed +in the range, not all equal values. + +It calls <tt>rtree::remove(Iterator, Iterator)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param first The beginning of the range of values. +\param last The end of the range of values. + +\return The number of removed values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, typename Iterator> +inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type +remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Iterator first, Iterator last) +{ + return tree.remove(first, last); +} + +/*! +\brief Remove a range of values from the container. + +Remove a range of values from the container. In contrast to the \c std::set or <tt>std::map erase()</tt> method +it removes values equal to these passed as a range. Furthermore this method removes only +one value for each one passed in the range, not all equal values. + +It calls <tt>rtree::remove(Range const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param rng The range of values. + +\return The number of removed values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, typename Range> +inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type +remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, Range const& rng) +{ + return tree.remove(rng); +} + +/*! +\brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box. + +This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates. +Values will be returned only if all predicates are met. + +<b>Spatial predicates</b> + +Spatial predicates may be generated by one of the functions listed below: +\li \c boost::geometry::index::covered_by(), +\li \c boost::geometry::index::disjoint(), +\li \c boost::geometry::index::intersects(), +\li \c boost::geometry::index::overlaps(), +\li \c boost::geometry::index::within(), + +It is possible to negate spatial predicates: +\li <tt>! boost::geometry::index::covered_by()</tt>, +\li <tt>! boost::geometry::index::disjoint()</tt>, +\li <tt>! boost::geometry::index::intersects()</tt>, +\li <tt>! boost::geometry::index::overlaps()</tt>, +\li <tt>! boost::geometry::index::within()</tt> + +<b>Satisfies predicate</b> + +This is a special kind of predicate which allows to pass a user-defined function or function object which checks +if Value should be returned by the query. It's generated by: +\li \c boost::geometry::index::satisfies(). + +<b>Nearest predicate</b> + +If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result +in returning k values to the output iterator. Only one nearest predicate may be passed to the query. +It may be generated by: +\li \c boost::geometry::index::nearest(). + +<b>Connecting predicates</b> + +Predicates may be passed together connected with \c operator&&(). + +\par Example +\verbatim +// return elements intersecting box +bgi::query(tree, bgi::intersects(box), std::back_inserter(result)); +// return elements intersecting poly but not within box +bgi::query(tree, bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result)); +// return elements overlapping box and meeting my_fun value predicate +bgi::query(tree, bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result)); +// return 5 elements nearest to pt and elements are intersecting box +bgi::query(tree, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result)); +\endverbatim + +\par Throws +If Value copy constructor or copy assignment throws. + +\warning +Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error. + +\ingroup rtree_functions + +\param tree The rtree. +\param predicates Predicates. +\param out_it The output iterator, e.g. generated by std::back_inserter(). + +\return The number of values found. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, + typename Predicates, typename OutIter> inline +typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type +query(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree, + Predicates const& predicates, + OutIter out_it) +{ + return tree.query(predicates, out_it); +} + +/*! +\brief Remove all values from the index. + +It calls \c rtree::clear(). + +\ingroup rtree_functions + +\param tree The spatial index. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline void clear(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree) +{ + return tree.clear(); +} + +/*! +\brief Get the number of values stored in the index. + +It calls \c rtree::size(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return The number of values stored in the index. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline size_t size(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree) +{ + return tree.size(); +} + +/*! +\brief Query if there are no values stored in the index. + +It calls \c rtree::empty(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return true if there are no values in the index. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline bool empty(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree) +{ + return tree.bounds(); +} + +/*! +\brief Get the box containing all stored values or an invalid box if the index has no values. + +It calls \c rtree::envelope(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return The box containing all stored values or an invalid box. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::bounds_type +bounds(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree) +{ + return tree.bounds(); +} + +/*! +\brief Exchanges the contents of the container with those of other. + +It calls \c rtree::swap(). + +\ingroup rtree_functions + +\param l The first rtree. +\param r The second rtree. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> +inline void swap(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & l, + rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & r) +{ + return l.swap(r); +} + +}}} // namespace boost::geometry::index + +#include <boost/geometry/index/detail/config_end.hpp> + +#endif // BOOST_GEOMETRY_INDEX_RTREE_HPP diff --git a/boost/geometry/io/dsv/write.hpp b/boost/geometry/io/dsv/write.hpp new file mode 100644 index 000000000..62929f807 --- /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 000000000..934006077 --- /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/svg/svg_mapper.hpp b/boost/geometry/io/svg/svg_mapper.hpp new file mode 100644 index 000000000..1252cc806 --- /dev/null +++ b/boost/geometry/io/svg/svg_mapper.hpp @@ -0,0 +1,392 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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_IO_SVG_MAPPER_HPP +#define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP + +#include <cstdio> + +#include <vector> + +#include <boost/mpl/assert.hpp> +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_const.hpp> + +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> + + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/tag_cast.hpp> + +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/transform.hpp> +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/strategies/transform.hpp> +#include <boost/geometry/strategies/transform/map_transformer.hpp> +#include <boost/geometry/views/segment_view.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/algorithms/envelope.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + +#include <boost/geometry/io/svg/write_svg.hpp> + +// Helper geometries (all points are transformed to integer-points) +#include <boost/geometry/geometries/geometries.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace svg +{ + typedef model::point<int, 2, cs::cartesian> svg_point_type; +}} +#endif + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + + +template <typename GeometryTag, typename Geometry> +struct svg_map +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (Geometry) + ); +}; + + +template <typename Point> +struct svg_map<point_tag, Point> +{ + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Point const& point, TransformStrategy const& strategy) + { + detail::svg::svg_point_type ipoint; + geometry::transform(point, ipoint, strategy); + stream << geometry::svg(ipoint, style, size) << std::endl; + } +}; + +template <typename Box> +struct svg_map<box_tag, Box> +{ + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Box const& box, TransformStrategy const& strategy) + { + model::box<detail::svg::svg_point_type> ibox; + geometry::transform(box, ibox, strategy); + + stream << geometry::svg(ibox, style, size) << std::endl; + } +}; + + +template <typename Range1, typename Range2> +struct svg_map_range +{ + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Range1 const& range, TransformStrategy const& strategy) + { + Range2 irange; + geometry::transform(range, irange, strategy); + stream << geometry::svg(irange, style, size) << std::endl; + } +}; + +template <typename Segment> +struct svg_map<segment_tag, Segment> +{ + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Segment const& segment, TransformStrategy const& strategy) + { + typedef segment_view<Segment> view_type; + view_type range(segment); + svg_map_range + < + view_type, + model::linestring<detail::svg::svg_point_type> + >::apply(stream, style, size, range, strategy); + } +}; + + +template <typename Ring> +struct svg_map<ring_tag, Ring> + : svg_map_range<Ring, model::ring<detail::svg::svg_point_type> > +{}; + + +template <typename Linestring> +struct svg_map<linestring_tag, Linestring> + : svg_map_range<Linestring, model::linestring<detail::svg::svg_point_type> > +{}; + + +template <typename Polygon> +struct svg_map<polygon_tag, Polygon> +{ + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Polygon const& polygon, TransformStrategy const& strategy) + { + model::polygon<detail::svg::svg_point_type> ipoly; + geometry::transform(polygon, ipoly, strategy); + stream << geometry::svg(ipoly, style, size) << std::endl; + } +}; + + +template <typename Multi> +struct svg_map<multi_tag, Multi> +{ + typedef typename single_tag_of + < + typename geometry::tag<Multi>::type + >::type stag; + + template <typename TransformStrategy> + static inline void apply(std::ostream& stream, + std::string const& style, int size, + Multi const& multi, TransformStrategy const& strategy) + { + for (typename boost::range_iterator<Multi const>::type it + = boost::begin(multi); + it != boost::end(multi); + ++it) + { + svg_map + < + stag, + typename boost::range_value<Multi>::type + >::apply(stream, style, size, *it, strategy); + } + } +}; + + +} // namespace dispatch +#endif + + +template <typename Geometry, typename TransformStrategy> +inline void svg_map(std::ostream& stream, + std::string const& style, int size, + Geometry const& geometry, TransformStrategy const& strategy) +{ + dispatch::svg_map + < + typename tag_cast + < + typename tag<Geometry>::type, + multi_tag + >::type, + typename boost::remove_const<Geometry>::type + >::apply(stream, style, size, geometry, strategy); +} + + +/*! +\brief Helper class to create SVG maps +\tparam Point Point type, for input geometries. +\tparam SameScale Boolean flag indicating if horizontal and vertical scale should + be the same. The default value is true +\ingroup svg + +\qbk{[include reference/io/svg.qbk]} +*/ +template <typename Point, bool SameScale = true> +class svg_mapper : boost::noncopyable +{ + typedef strategy::transform::map_transformer + < + Point, + detail::svg::svg_point_type, + true, + SameScale + > transformer_type; + + model::box<Point> m_bounding_box; + boost::scoped_ptr<transformer_type> m_matrix; + std::ostream& m_stream; + int m_width, m_height; + std::string m_width_height; // for <svg> tag only, defaults to 2x 100% + + void init_matrix() + { + if (! m_matrix) + { + m_matrix.reset(new transformer_type(m_bounding_box, + m_width, m_height)); + + m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>" + << std::endl + << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" + << std::endl + << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" + << std::endl + << "<svg " << m_width_height << " version=\"1.1\"" + << std::endl + << "xmlns=\"http://www.w3.org/2000/svg\">" + << std::endl; + } + } + +public : + + /*! + \brief Constructor, initializing the SVG map. Opens and initializes the SVG. + Should be called explicitly. + \param stream Output stream, should be a stream already open + \param width Width of the SVG map (in SVG pixels) + \param height Height of the SVG map (in SVG pixels) + \param width_height Optional information to increase width and/or height + */ + explicit svg_mapper(std::ostream& stream, int width, int height + , std::string const& width_height = "width=\"100%\" height=\"100%\"") + : m_stream(stream) + , m_width(width) + , m_height(height) + , m_width_height(width_height) + { + assign_inverse(m_bounding_box); + } + + /*! + \brief Destructor, called automatically. Closes the SVG by streaming <\/svg> + */ + virtual ~svg_mapper() + { + m_stream << "</svg>" << std::endl; + } + + /*! + \brief Adds a geometry to the transformation matrix. After doing this, + the specified geometry can be mapped fully into the SVG map + \tparam Geometry \tparam_geometry + \param geometry \param_geometry + */ + template <typename Geometry> + void add(Geometry const& geometry) + { + if (num_points(geometry) > 0) + { + expand(m_bounding_box, + return_envelope + < + model::box<Point> + >(geometry)); + } + } + + /*! + \brief Maps a geometry into the SVG map using the specified style + \tparam Geometry \tparam_geometry + \param geometry \param_geometry + \param style String containing verbatim SVG style information + \param size Optional size (used for SVG points) in SVG pixels. For linestrings, + specify linewidth in the SVG style information + */ + template <typename Geometry> + void map(Geometry const& geometry, std::string const& style, + int size = -1) + { + BOOST_MPL_ASSERT_MSG + ( + ( boost::is_same + < + Point, + typename point_type<Geometry>::type + >::value ) + , POINT_TYPES_ARE_NOT_SAME_FOR_MAPPER_AND_MAP + , (types<Point, typename point_type<Geometry>::type>) + ); + + + init_matrix(); + svg_map(m_stream, style, size, geometry, *m_matrix); + } + + /*! + \brief Adds a text to the SVG map + \tparam TextPoint \tparam_point + \param point Location of the text (in map units) + \param s The text itself + \param style String containing verbatim SVG style information, of the text + \param offset_x Offset in SVG pixels, defaults to 0 + \param offset_y Offset in SVG pixels, defaults to 0 + \param lineheight Line height in SVG pixels, in case the text contains \n + */ + template <typename TextPoint> + void text(TextPoint const& point, std::string const& s, + std::string const& style, + int offset_x = 0, int offset_y = 0, int lineheight = 10) + { + init_matrix(); + detail::svg::svg_point_type map_point; + transform(point, map_point, *m_matrix); + m_stream + << "<text style=\"" << style << "\"" + << " x=\"" << get<0>(map_point) + offset_x << "\"" + << " y=\"" << get<1>(map_point) + offset_y << "\"" + << ">"; + if (s.find("\n") == std::string::npos) + { + m_stream << s; + } + else + { + // Multi-line modus + + std::vector<std::string> splitted; + boost::split(splitted, s, boost::is_any_of("\n")); + for (std::vector<std::string>::const_iterator it + = splitted.begin(); + it != splitted.end(); + ++it, offset_y += lineheight) + { + m_stream + << "<tspan x=\"" << get<0>(map_point) + offset_x + << "\"" + << " y=\"" << get<1>(map_point) + offset_y + << "\"" + << ">" << *it << "</tspan>"; + } + } + m_stream << "</text>" << std::endl; + } +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP diff --git a/boost/geometry/io/svg/write_svg.hpp b/boost/geometry/io/svg/write_svg.hpp new file mode 100644 index 000000000..15fa9c11c --- /dev/null +++ b/boost/geometry/io/svg/write_svg.hpp @@ -0,0 +1,277 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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_IO_SVG_WRITE_SVG_HPP +#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP + +#include <ostream> +#include <string> + +#include <boost/config.hpp> +#include <boost/mpl/assert.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/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace svg +{ + + +template <typename Point> +struct svg_point +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Point const& p, std::string const& style, int size) + { + os << "<circle cx=\"" << geometry::get<0>(p) + << "\" cy=\"" << geometry::get<1>(p) + << "\" r=\"" << (size < 0 ? 5 : size) + << "\" style=\"" << style << "\"/>"; + } +}; + + +template <typename Box> +struct svg_box +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Box const& box, std::string const& style, int ) + { + // Prevent invisible boxes, making them >=1, using "max" + BOOST_USING_STD_MAX(); + + typedef typename coordinate_type<Box>::type ct; + ct x = geometry::get<geometry::min_corner, 0>(box); + ct y = geometry::get<geometry::min_corner, 1>(box); + ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION(1, + geometry::get<geometry::max_corner, 0>(box) - x); + ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (1, + geometry::get<geometry::max_corner, 1>(box) - y); + + os << "<rect x=\"" << x << "\" y=\"" << y + << "\" width=\"" << width << "\" height=\"" << height + << "\" style=\"" << style << "\"/>"; + } +}; + + +/*! +\brief Stream ranges as SVG +\note policy is used to select type (polyline/polygon) +*/ +template <typename Range, typename Policy> +struct svg_range +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range, std::string const& style, int ) + { + typedef typename boost::range_iterator<Range const>::type iterator; + + bool first = true; + + os << "<" << Policy::prefix() << " points=\""; + + for (iterator it = boost::begin(range); + it != boost::end(range); + ++it, first = false) + { + os << (first ? "" : " " ) + << geometry::get<0>(*it) + << "," + << geometry::get<1>(*it); + } + os << "\" style=\"" << style << Policy::style() << "\"/>"; + } +}; + + + +template <typename Polygon> +struct svg_poly +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Polygon const& polygon, std::string const& style, int ) + { + typedef typename geometry::ring_type<Polygon>::type ring_type; + typedef typename boost::range_iterator<ring_type const>::type iterator_type; + + bool first = true; + os << "<g fill-rule=\"evenodd\"><path d=\""; + + ring_type const& ring = geometry::exterior_ring(polygon); + for (iterator_type it = boost::begin(ring); + it != boost::end(ring); + ++it, first = false) + { + os << (first ? "M" : " L") << " " + << geometry::get<0>(*it) + << "," + << geometry::get<1>(*it); + } + + // Inner rings: + { + typename interior_return_type<Polygon const>::type rings + = interior_rings(polygon); + for (BOOST_AUTO_TPL(rit, boost::begin(rings)); + rit != boost::end(rings); ++rit) + { + first = true; + for (BOOST_AUTO_TPL(it, boost::begin(*rit)); it != boost::end(*rit); + ++it, first = false) + { + os << (first ? "M" : " L") << " " + << geometry::get<0>(*it) + << "," + << geometry::get<1>(*it); + } + } + } + os << " z \" style=\"" << style << "\"/></g>"; + + } +}; + + + +struct prefix_linestring +{ + static inline const char* prefix() { return "polyline"; } + static inline const char* style() { return ";fill:none"; } +}; + + +struct prefix_ring +{ + static inline const char* prefix() { return "polygon"; } + static inline const char* style() { return ""; } +}; + + + +}} // namespace detail::svg +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +/*! +\brief Dispatching base struct for SVG streaming, specialized below per geometry type +\details Specializations should implement a static method "stream" to stream a geometry +The static method should have the signature: + +template <typename Char, typename Traits> +static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry) +*/ +template <typename GeometryTag, typename Geometry> +struct svg +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (Geometry) + ); +}; + +template <typename Point> +struct svg<point_tag, Point> : detail::svg::svg_point<Point> {}; + +template <typename Box> +struct svg<box_tag, Box> : detail::svg::svg_box<Box> {}; + +template <typename Linestring> +struct svg<linestring_tag, Linestring> + : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {}; + +template <typename Ring> +struct svg<ring_tag, Ring> + : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {}; + +template <typename Polygon> +struct svg<polygon_tag, Polygon> + : detail::svg::svg_poly<Polygon> {}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief Generic geometry template manipulator class, takes corresponding output class from traits class +\ingroup svg +\details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics) +*/ +template <typename G> +class svg_manipulator +{ +public: + + inline svg_manipulator(G const& g, std::string const& style, int size) + : m_geometry(g) + , m_style(style) + , m_size(size) + {} + + template <typename Char, typename Traits> + inline friend std::basic_ostream<Char, Traits>& operator<<( + std::basic_ostream<Char, Traits>& os, svg_manipulator const& m) + { + dispatch::svg + < + typename tag<G>::type, G + >::apply(os, m.m_geometry, m.m_style, m.m_size); + os.flush(); + return os; + } + +private: + G const& m_geometry; + std::string const& m_style; + int m_size; +}; + +/*! +\brief Manipulator to stream geometries as SVG +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param style String containing verbatim SVG style information +\param size Optional size (used for SVG points) in SVG pixels. For linestrings, + specify linewidth in the SVG style information +\ingroup svg +*/ +template <typename Geometry> +inline svg_manipulator<Geometry> svg(Geometry const& geometry, std::string const& style, int size = -1) +{ + concept::check<Geometry const>(); + + return svg_manipulator<Geometry>(geometry, style, size); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP diff --git a/boost/geometry/io/svg/write_svg_multi.hpp b/boost/geometry/io/svg/write_svg_multi.hpp new file mode 100644 index 000000000..a794120c0 --- /dev/null +++ b/boost/geometry/io/svg/write_svg_multi.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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_IO_SVG_WRITE_SVG_MULTI_HPP +#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP + + +#include <boost/geometry/io/svg/write_svg.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace svg +{ + + +template <typename MultiGeometry, typename Policy> +struct svg_multi +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + MultiGeometry const& multi, std::string const& style, int size) + { + for (typename boost::range_iterator<MultiGeometry const>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(os, *it, style, size); + } + + } + +}; + + + +}} // namespace detail::svg +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPolygon> +struct svg<multi_polygon_tag, MultiPolygon> + : detail::svg::svg_multi + < + MultiPolygon, + detail::svg::svg_poly + < + typename boost::range_value<MultiPolygon>::type + > + + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP diff --git a/boost/geometry/io/wkt/detail/prefix.hpp b/boost/geometry/io/wkt/detail/prefix.hpp new file mode 100644 index 000000000..45e43b88d --- /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 000000000..0e5abbca8 --- /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 000000000..24e93a02f --- /dev/null +++ b/boost/geometry/io/wkt/read.hpp @@ -0,0 +1,697 @@ +// 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); + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + + if (has_z && dimension<Geometry>::type::value < 3) + { + throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt); + } + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + 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 000000000..86e49fdaf --- /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 000000000..28bd1e42a --- /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 000000000..4ed02e0f8 --- /dev/null +++ b/boost/geometry/io/wkt/write.hpp @@ -0,0 +1,421 @@ +// 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/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/not_implemented.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> + +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +namespace boost { namespace geometry +{ + +// Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4512) +#endif + +#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 Geometry, typename Tag = typename tag<Geometry>::type> +struct wkt: not_implemented<Tag> +{}; + +template <typename Point> +struct wkt<Point, point_tag> + : detail::wkt::wkt_point + < + Point, + detail::wkt::prefix_point + > +{}; + +template <typename Linestring> +struct wkt<Linestring, linestring_tag> + : 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, box_tag> + : detail::wkt::wkt_box<Box> +{}; + +template <typename Segment> +struct wkt<Segment, segment_tag> + : 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, ring_tag> + : 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, polygon_tag> + : detail::wkt::wkt_poly + < + Polygon, + detail::wkt::prefix_polygon + > +{}; + + +template <typename Geometry> +struct devarianted_wkt +{ + template <typename OutputStream> + static inline void apply(OutputStream& os, Geometry const& geometry) + { + wkt<Geometry>::apply(os, geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename OutputStream> + struct visitor: static_visitor<void> + { + OutputStream& m_os; + + visitor(OutputStream& os) + : m_os(os) + {} + + template <typename Geometry> + inline void operator()(Geometry const& geometry) const + { + devarianted_wkt<Geometry>::apply(m_os, geometry); + } + }; + + template <typename OutputStream> + static inline void apply( + OutputStream& os, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry + ) + { + apply_visitor(visitor<OutputStream>(os), geometry); + } +}; + + +} // 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::devarianted_wkt<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); +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..1e824654e --- /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 000000000..7cd8fa015 --- /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 000000000..8119a73b5 --- /dev/null +++ b/boost/geometry/iterators/ever_circling_iterator.hpp @@ -0,0 +1,212 @@ +// 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> +struct ever_circling_range_iterator + : public boost::iterator_facade + < + ever_circling_range_iterator<Range>, + typename boost::range_value<Range>::type const, + boost::random_access_traversal_tag + > +{ + /// Constructor including the range it is based on + explicit inline ever_circling_range_iterator(Range& range) + : m_range(&range) + , m_iterator(boost::begin(range)) + , m_size(boost::size(range)) + , m_index(0) + {} + + /// Default constructor + explicit inline ever_circling_range_iterator() + : m_range(NULL) + , m_size(0) + , m_index(0) + {} + + inline ever_circling_range_iterator<Range>& operator=(ever_circling_range_iterator<Range> const& source) + { + m_range = source.m_range; + m_iterator = source.m_iterator; + 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(ever_circling_range_iterator<Range> const& other) const + { + return other.m_index - this->m_index; + } + + inline bool equal(ever_circling_range_iterator<Range> const& other) const + { + return this->m_range == other.m_range + && this->m_index == other.m_index; + } + + inline void increment() + { + ++m_index; + if (m_index >= 0 && m_index < m_size) + { + ++m_iterator; + } + else + { + update_iterator(); + } + } + + inline void decrement() + { + --m_index; + if (m_index >= 0 && m_index < m_size) + { + --m_iterator; + } + else + { + update_iterator(); + } + } + + inline void advance(difference_type n) + { + if (m_index >= 0 && m_index < m_size + && m_index + n >= 0 && m_index + n < m_size) + { + m_index += n; + m_iterator += n; + } + else + { + m_index += n; + update_iterator(); + } + } + + inline void update_iterator() + { + while (m_index < 0) + { + m_index += m_size; + } + m_index = m_index % m_size; + this->m_iterator = boost::begin(*m_range) + m_index; + } + + Range* m_range; + typename boost::range_iterator<Range>::type m_iterator; + difference_type m_size; + difference_type m_index; +}; + + +}} // 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 000000000..bb97af1aa --- /dev/null +++ b/boost/geometry/multi/algorithms/append.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_APPEND_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP + +#include <boost/geometry/algorithms/append.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..333499748 --- /dev/null +++ b/boost/geometry/multi/algorithms/area.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_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/tags.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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> +struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum +{ + template <typename Strategy> + static inline typename Strategy::return_type + apply(MultiGeometry const& multi, Strategy const& strategy) + { + return multi_sum::apply + < + typename Strategy::return_type, + area<typename boost::range_value<MultiGeometry>::type> + >(multi, strategy); + } +}; + + +} // 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 000000000..82e6a8af8 --- /dev/null +++ b/boost/geometry/multi/algorithms/centroid.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_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/tags.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 +*/ +struct centroid_multi_point_state +{ + template <typename Point, typename Strategy> + 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 Policy> +struct centroid_multi +{ + template <typename Multi, typename Point, typename Strategy> + 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> +struct centroid<MultiLinestring, multi_linestring_tag> + : detail::centroid::centroid_multi + < + detail::centroid::centroid_range_state<closed> + > +{}; + +template <typename MultiPolygon> +struct centroid<MultiPolygon, multi_polygon_tag> + : detail::centroid::centroid_multi + < + detail::centroid::centroid_polygon_state + > +{}; + + +template <typename MultiPoint> +struct centroid<MultiPoint, multi_point_tag> + : detail::centroid::centroid_multi + < + detail::centroid::centroid_multi_point_state + > +{}; + + +} // 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 000000000..ea32ee8b4 --- /dev/null +++ b/boost/geometry/multi/algorithms/clear.hpp @@ -0,0 +1,44 @@ +// 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/multi/geometries/concepts/check.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 000000000..1712964d4 --- /dev/null +++ b/boost/geometry/multi/algorithms/convert.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_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> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..d28d1e78e --- /dev/null +++ b/boost/geometry/multi/algorithms/correct.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_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> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..c957c485b --- /dev/null +++ b/boost/geometry/multi/algorithms/covered_by.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_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/geometries/concepts/check.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 000000000..0938d6a2e --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/for_each_range.hpp @@ -0,0 +1,87 @@ +// 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> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..b52efd251 --- /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 000000000..4ae79058d --- /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 000000000..704c3e6a9 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/multi_sum.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_SUM_HPP +#define BOOST_GEOMETRY_MULTI_SUM_HPP + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +struct multi_sum +{ + template <typename ReturnType, typename Policy, typename MultiGeometry, typename Strategy> + 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 000000000..940480b3c --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.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_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/multi/geometries/concepts/check.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 < int(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 000000000..f3a0532ac --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp @@ -0,0 +1,105 @@ +// 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> +#include <boost/geometry/multi/geometries/concepts/check.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 < int(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 000000000..2d04f7ccd --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/get_ring.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_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> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 < int(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 000000000..6bc0aae25 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp @@ -0,0 +1,113 @@ +// 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/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..acb91f7dd --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp @@ -0,0 +1,65 @@ +// 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/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..d9820837b --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp @@ -0,0 +1,57 @@ +// 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/multi/geometries/concepts/check.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 000000000..dd3bcd5d1 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/point_on_border.hpp @@ -0,0 +1,96 @@ +// 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/multi/geometries/concepts/check.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 Point, + typename MultiGeometry, + typename Policy +> +struct point_on_multi +{ + static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint) + { + // 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(point, *it, midpoint)) + { + return true; + } + } + return false; + } +}; + + + + +}} // namespace detail::point_on_border +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template<typename Point, typename Multi> +struct point_on_border<multi_polygon_tag, Point, Multi> + : detail::point_on_border::point_on_multi + < + Point, + Multi, + detail::point_on_border::point_on_polygon + < + Point, + typename boost::range_value<Multi>::type + > + > +{}; + + + +} // 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 000000000..47bc8a863 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp @@ -0,0 +1,91 @@ +// 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/geometries/concepts/check.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 < int(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 000000000..1e1056f37 --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp @@ -0,0 +1,97 @@ +// 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/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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/disjoint.hpp b/boost/geometry/multi/algorithms/disjoint.hpp new file mode 100644 index 000000000..c01e520f5 --- /dev/null +++ b/boost/geometry/multi/algorithms/disjoint.hpp @@ -0,0 +1,44 @@ +// 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_MULTI_ALGORITHMS_DISJOINT_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP + + +#include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/multi/algorithms/covered_by.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Point, typename MultiPolygon> +struct disjoint<Point, MultiPolygon, 2, point_tag, multi_polygon_tag, false> + : detail::disjoint::reverse_covered_by<Point, MultiPolygon> +{}; + +} // namespace dispatch + + +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP diff --git a/boost/geometry/multi/algorithms/distance.hpp b/boost/geometry/multi/algorithms/distance.hpp new file mode 100644 index 000000000..32b41fcef --- /dev/null +++ b/boost/geometry/multi/algorithms/distance.hpp @@ -0,0 +1,158 @@ +// 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/multi/geometries/concepts/check.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 000000000..b70aab41e --- /dev/null +++ b/boost/geometry/multi/algorithms/envelope.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_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/tags.hpp> +#include <boost/geometry/multi/core/point_type.hpp> +#include <boost/geometry/multi/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail { namespace envelope +{ + + +struct envelope_multi_linestring +{ + template<typename MultiLinestring, typename Box> + 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 +struct envelope_multi_polygon +{ + template<typename MultiPolygon, typename Box> + 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> +struct envelope<Multi, multi_point_tag> + : detail::envelope::envelope_range +{}; + +template <typename Multi> +struct envelope<Multi, multi_linestring_tag> + : detail::envelope::envelope_multi_linestring +{}; + + +template <typename Multi> +struct envelope<Multi, multi_polygon_tag> + : detail::envelope::envelope_multi_polygon +{}; + + +} // 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 000000000..54cd07504 --- /dev/null +++ b/boost/geometry/multi/algorithms/equals.hpp @@ -0,0 +1,65 @@ +// 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/multi/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/equals.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse> +struct equals + < + MultiPolygon1, MultiPolygon2, + multi_polygon_tag, multi_polygon_tag, + 2, + Reverse + > + : detail::equals::equals_by_collection<detail::equals::area_check> +{}; + + +template <typename Polygon, typename MultiPolygon, bool Reverse> +struct equals + < + Polygon, MultiPolygon, + polygon_tag, multi_polygon_tag, + 2, + Reverse + > + : detail::equals::equals_by_collection<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 000000000..9712b9c45 --- /dev/null +++ b/boost/geometry/multi/algorithms/for_each.hpp @@ -0,0 +1,101 @@ +// 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/multi/geometries/concepts/check.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 Policy> +struct for_each_multi +{ + template <typename MultiGeometry, typename Functor> + static inline void apply(MultiGeometry& multi, Functor& f) + { + for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it) + { + Policy::apply(*it, f); + } + } +}; + + +}} // namespace detail::for_each +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiGeometry> +struct for_each_point<MultiGeometry, multi_tag> + : detail::for_each::for_each_multi + < + // Specify the dispatch of the single-version as policy + for_each_point + < + typename add_const_if_c + < + is_const<MultiGeometry>::value, + typename boost::range_value<MultiGeometry>::type + >::type + > + > +{}; + + +template <typename MultiGeometry> +struct for_each_segment<MultiGeometry, multi_tag> + : detail::for_each::for_each_multi + < + // Specify the dispatch of the single-version as policy + for_each_segment + < + typename add_const_if_c + < + is_const<MultiGeometry>::value, + typename boost::range_value<MultiGeometry>::type + >::type + > + > +{}; + + +} // 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 000000000..ddb9aed81 --- /dev/null +++ b/boost/geometry/multi/algorithms/intersection.hpp @@ -0,0 +1,402 @@ +// 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/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 PointOut> +struct intersection_multi_linestring_multi_linestring_point +{ + template + < + typename MultiLinestring1, typename MultiLinestring2, + typename OutputIterator, typename Strategy + > + 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<PointOut> + ::apply(*it1, *it2, out, strategy); + } + } + + return out; + } +}; + + +template <typename PointOut> +struct intersection_linestring_multi_linestring_point +{ + template + < + typename Linestring, typename MultiLinestring, + typename OutputIterator, typename Strategy + > + 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<PointOut> + ::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 +< + bool ReverseAreal, + typename LineStringOut, + overlay_type OverlayType +> +struct intersection_of_multi_linestring_with_areal +{ + template + < + typename MultiLinestring, typename Areal, + typename OutputIterator, typename Strategy + > + 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 + < + ReverseAreal, LineStringOut, OverlayType + >::apply(*it, areal, out, strategy); + } + + return out; + + } +}; + +// This one calls the one above with reversed arguments +template +< + bool ReverseAreal, + typename LineStringOut, + overlay_type OverlayType +> +struct intersection_of_areal_with_multi_linestring +{ + template + < + typename Areal, typename MultiLinestring, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, + OutputIterator out, + Strategy const& strategy) + { + return intersection_of_multi_linestring_with_areal + < + ReverseAreal, LineStringOut, OverlayType + >::apply(ml, areal, out, strategy); + } +}; + + + +template <typename LinestringOut> +struct clip_multi_linestring +{ + template + < + typename MultiLinestring, typename Box, + typename OutputIterator, typename Strategy + > + 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, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + MultiLinestring1, MultiLinestring2, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + multi_linestring_tag, multi_linestring_tag, point_tag, + false, false, false + > : detail::intersection::intersection_multi_linestring_multi_linestring_point + < + GeometryOut + > +{}; + + +template +< + typename Linestring, typename MultiLinestring, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Linestring, MultiLinestring, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + linestring_tag, multi_linestring_tag, point_tag, + false, false, false + > : detail::intersection::intersection_linestring_multi_linestring_point + < + GeometryOut + > +{}; + + +template +< + typename MultiLinestring, typename Box, + typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + MultiLinestring, Box, + GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + multi_linestring_tag, box_tag, linestring_tag, + false, true, false + > : detail::intersection::clip_multi_linestring + < + GeometryOut + > +{}; + + +template +< + typename Linestring, typename MultiPolygon, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut +> +struct intersection_insert + < + Linestring, MultiPolygon, + GeometryOut, + OverlayType, + ReverseLinestring, ReverseMultiPolygon, ReverseOut, + linestring_tag, multi_polygon_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_linestring_with_areal + < + ReverseMultiPolygon, + GeometryOut, + OverlayType + > +{}; + + +// Derives from areal/mls because runtime arguments are in that order. +// areal/mls reverses it itself to mls/areal +template +< + typename Polygon, typename MultiLinestring, + typename GeometryOut, + overlay_type OverlayType, + bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut +> +struct intersection_insert + < + Polygon, MultiLinestring, + GeometryOut, + OverlayType, + ReversePolygon, ReverseMultiLinestring, ReverseOut, + polygon_tag, multi_linestring_tag, linestring_tag, + true, false, false + > : detail::intersection::intersection_of_areal_with_multi_linestring + < + ReversePolygon, + GeometryOut, + OverlayType + > +{}; + + +template +< + typename MultiLinestring, typename Ring, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut +> +struct intersection_insert + < + MultiLinestring, Ring, + GeometryOut, + OverlayType, + ReverseMultiLinestring, ReverseRing, ReverseOut, + multi_linestring_tag, ring_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + ReverseRing, + GeometryOut, + OverlayType + > +{}; + +template +< + typename MultiLinestring, typename Polygon, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut +> +struct intersection_insert + < + MultiLinestring, Polygon, + GeometryOut, + OverlayType, + ReverseMultiLinestring, ReverseRing, ReverseOut, + multi_linestring_tag, polygon_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + ReverseRing, + GeometryOut, + OverlayType + > +{}; + + + +template +< + typename MultiLinestring, typename MultiPolygon, + typename GeometryOut, + overlay_type OverlayType, + bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut +> +struct intersection_insert + < + MultiLinestring, MultiPolygon, + GeometryOut, + OverlayType, + ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut, + multi_linestring_tag, multi_polygon_tag, linestring_tag, + false, true, false + > : detail::intersection::intersection_of_multi_linestring_with_areal + < + ReverseMultiPolygon, + GeometryOut, + OverlayType + > +{}; + + +} // 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 000000000..e18cbe3d9 --- /dev/null +++ b/boost/geometry/multi/algorithms/length.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_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/geometries/concepts/check.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> +struct length<MultiLinestring, multi_linestring_tag> : detail::multi_sum +{ + template <typename Strategy> + static inline typename default_length_result<MultiLinestring>::type + apply(MultiLinestring const& multi, Strategy const& strategy) + { + return multi_sum::apply + < + typename default_length_result<MultiLinestring>::type, + detail::length::range_length + < + typename boost::range_value<MultiLinestring>::type, + closed // no need to close it explicitly + > + >(multi, strategy); + + } +}; + + +} // 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 000000000..a102d08f2 --- /dev/null +++ b/boost/geometry/multi/algorithms/num_geometries.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_NUM_GEOMETRIES_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/num_geometries.hpp> +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename MultiGeometry> +struct num_geometries<MultiGeometry, multi_tag> +{ + 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 000000000..e43b31d16 --- /dev/null +++ b/boost/geometry/multi/algorithms/num_interior_rings.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_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/geometries/concepts/check.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<MultiPolygon, multi_polygon_tag> +{ + 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 000000000..294c08603 --- /dev/null +++ b/boost/geometry/multi/algorithms/num_points.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_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/multi/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace num_points +{ + + +struct multi_count +{ + template <typename MultiGeometry> + 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<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<Geometry, multi_tag> + : detail::num_points::multi_count {}; + + +} // 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 000000000..5b37525b8 --- /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/geometries/concepts/check.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> +struct perimeter<MultiPolygon, multi_polygon_tag> : detail::multi_sum +{ + template <typename Strategy> + static inline typename default_length_result<MultiPolygon>::type + apply(MultiPolygon const& multi, Strategy const& strategy) + { + return multi_sum::apply + < + typename default_length_result<MultiPolygon>::type, + perimeter<typename boost::range_value<MultiPolygon>::type> + >(multi, 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 000000000..7a4938ef8 --- /dev/null +++ b/boost/geometry/multi/algorithms/reverse.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_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> +#include <boost/geometry/multi/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry> +struct reverse<Geometry, multi_linestring_tag> + : detail::multi_modify + < + Geometry, + detail::reverse::range_reverse + > +{}; + + +template <typename Geometry> +struct reverse<Geometry, multi_polygon_tag> + : detail::multi_modify + < + Geometry, + detail::reverse::polygon_reverse + > +{}; + + +} // 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 000000000..2c7461b66 --- /dev/null +++ b/boost/geometry/multi/algorithms/simplify.hpp @@ -0,0 +1,92 @@ +// 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/geometries/concepts/check.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 Policy> +struct simplify_multi +{ + template <typename MultiGeometry, typename Strategy> + 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> +struct simplify<MultiPoint, multi_point_tag> + : detail::simplify::simplify_copy +{}; + + +template <typename MultiLinestring> +struct simplify<MultiLinestring, multi_linestring_tag> + : detail::simplify::simplify_multi<detail::simplify::simplify_range<2> > +{}; + + +template <typename MultiPolygon> +struct simplify<MultiPolygon, multi_polygon_tag> + : detail::simplify::simplify_multi<detail::simplify::simplify_polygon> +{}; + + +} // 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 000000000..13c53e615 --- /dev/null +++ b/boost/geometry/multi/algorithms/transform.hpp @@ -0,0 +1,91 @@ +// 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> +#include <boost/geometry/multi/geometries/concepts/check.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 Policy> +struct transform_multi +{ + template <typename Multi1, typename Multi2, 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> +struct transform + < + Multi1, Multi2, + multi_tag, multi_tag + > + : detail::transform::transform_multi + < + transform + < + typename boost::range_value<Multi1>::type, + typename boost::range_value<Multi2>::type + > + > +{}; + +} // 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 000000000..64c56aafb --- /dev/null +++ b/boost/geometry/multi/algorithms/unique.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_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> +#include <boost/geometry/multi/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace unique +{ + + +template <typename Policy> +struct multi_unique +{ + template <typename MultiGeometry, typename ComparePolicy> + 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> +struct unique<MultiLineString, multi_linestring_tag> + : detail::unique::multi_unique<detail::unique::range_unique> +{}; + + +template <typename MultiPolygon> +struct unique<MultiPolygon, multi_polygon_tag> + : detail::unique::multi_unique<detail::unique::polygon_unique> +{}; + + +} // 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 000000000..4094dcc2d --- /dev/null +++ b/boost/geometry/multi/algorithms/within.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_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> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..3964db256 --- /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 000000000..9d69cb20d --- /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 000000000..5a200d486 --- /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 000000000..ad8daeb49 --- /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 000000000..6b08468e8 --- /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 000000000..3c77e973b --- /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 000000000..faafaed02 --- /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 000000000..dcfca65b2 --- /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 000000000..55118f1c7 --- /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 000000000..61afc913c --- /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<Geometry, multi_point_tag, true> + : detail::concept_check::check<concept::ConstMultiPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, multi_point_tag, false> + : detail::concept_check::check<concept::MultiPoint<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, multi_linestring_tag, true> + : detail::concept_check::check<concept::ConstMultiLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, multi_linestring_tag, false> + : detail::concept_check::check<concept::MultiLinestring<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, multi_polygon_tag, true> + : detail::concept_check::check<concept::ConstMultiPolygon<Geometry> > +{}; + + +template <typename Geometry> +struct check<Geometry, multi_polygon_tag, 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 000000000..b0519f07e --- /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 000000000..f5942df07 --- /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 000000000..ca730d4f6 --- /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 000000000..90cf85a0f --- /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 000000000..67d4da06b --- /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 000000000..002d8f8a4 --- /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 000000000..af8d04287 --- /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 000000000..5ececdb8e --- /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 000000000..813f54733 --- /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 000000000..801b98cf2 --- /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 000000000..1a054659a --- /dev/null +++ b/boost/geometry/multi/io/dsv/write.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_IO_DSV_WRITE_HPP +#define BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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 000000000..37b07979b --- /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 000000000..2bfa830cf --- /dev/null +++ b/boost/geometry/multi/io/wkt/read.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_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/geometries/concepts/check.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); + } + + check_end(it, tokens.end(), wkt); + } +}; + +template <typename P> +struct noparenthesis_point_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, P& point) + { + parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt); + } +}; + +template <typename MultiGeometry, typename PrefixPolicy> +struct multi_point_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); + + // If first point definition starts with "(" then parse points as (x y) + // otherwise as "x y" + bool using_brackets = (it != tokens.end() && *it == "("); + + while(it != tokens.end() && *it != ")") + { + traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1); + + if (using_brackets) + { + point_parser + < + typename boost::range_value<MultiGeometry>::type + >::apply(it, tokens.end(), wkt, geometry.back()); + } + else + { + noparenthesis_point_parser + < + typename boost::range_value<MultiGeometry>::type + >::apply(it, tokens.end(), wkt, geometry.back()); + } + + if (it != tokens.end() && *it == ",") + { + // Skip "," after point is parsed + ++it; + } + } + + handle_close_parenthesis(it, tokens.end(), wkt); + } + + check_end(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_point_parser + < + MultiGeometry, + 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 000000000..55f1713d4 --- /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 000000000..47087e944 --- /dev/null +++ b/boost/geometry/multi/io/wkt/write.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_MULTI_IO_WKT_WRITE_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP + +#include <boost/geometry/multi/core/tags.hpp> +#include <boost/geometry/multi/geometries/concepts/check.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, multi_point_tag> + : 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, multi_linestring_tag> + : 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, multi_polygon_tag> + : 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 000000000..df10392cb --- /dev/null +++ b/boost/geometry/multi/multi.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_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/disjoint.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 000000000..f28daf20b --- /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 000000000..172feb251 --- /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 000000000..2e952d3e1 --- /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 000000000..766d80b22 --- /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 000000000..62859f33b --- /dev/null +++ b/boost/geometry/policies/relate/direction.hpp @@ -0,0 +1,362 @@ +// 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; + + + template <typename R> + static inline return_type segments_intersect(side_info const& sides, + R const&, + 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 000000000..ff8ec1949 --- /dev/null +++ b/boost/geometry/policies/relate/intersection_points.hpp @@ -0,0 +1,165 @@ +// 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; + + template <typename R> + static inline return_type segments_intersect(side_info const&, + R const& r, + coordinate_type const& dx1, coordinate_type const& dy1, + coordinate_type const& , coordinate_type const& , + S1 const& s1, S2 const& ) + { + typedef typename geometry::coordinate_type + < + typename return_type::point_type + >::type return_coordinate_type; + + coordinate_type const s1x = get<0, 0>(s1); + coordinate_type const s1y = get<0, 1>(s1); + + return_type result; + result.count = 1; + set<0>(result.intersections[0], + boost::numeric_cast<return_coordinate_type>(R(s1x) + r * R(dx1))); + set<1>(result.intersections[0], + boost::numeric_cast<return_coordinate_type>(R(s1y) + r * R(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 000000000..e78ccfbc1 --- /dev/null +++ b/boost/geometry/policies/relate/tupled.hpp @@ -0,0 +1,175 @@ +// 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; + + template <typename R> + static inline return_type segments_intersect(side_info const& sides, + R const& r, + 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, r, + dx1, dy1, dx2, dy2, s1, s2), + Policy2::segments_intersect(sides, r, + 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 000000000..747c14075 --- /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 000000000..1398ddb68 --- /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 000000000..423948fff --- /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 000000000..69188650d --- /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 000000000..8825791db --- /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 000000000..e192d9b28 --- /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 000000000..74b63532c --- /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 000000000..7680b8362 --- /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 000000000..678e9d7c2 --- /dev/null +++ b/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -0,0 +1,754 @@ +// 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 <std::size_t Dimension, typename Segment, typename T> +static inline void segment_arrange(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) + { + typedef side::side_by_triangle<coordinate_type> side; + side_info sides; + + coordinate_type const zero = 0; + bool const a_is_point = math::equals(dx_a, zero) && math::equals(dy_a, zero); + bool const b_is_point = math::equals(dx_b, zero) && math::equals(dy_b, zero); + + if(a_is_point && b_is_point) + { + if(math::equals(get<1,0>(a), get<1,0>(b)) && math::equals(get<1,1>(a), get<1,1>(b))) + { + Policy::degenerate(a, true); + } + else + { + return Policy::disjoint(); + } + } + + bool collinear_use_first = math::abs(dx_a) + math::abs(dx_b) >= math::abs(dy_a) + math::abs(dy_b); + + 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)) + ); + 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)) + ); + + bool collinear = sides.collinear(); + + robustness_verify_collinear(a, b, a_is_point, b_is_point, sides, collinear); + robustness_verify_meeting(a, b, sides, collinear, collinear_use_first); + + if (sides.same<0>() || sides.same<1>()) + { + // Both points are at same side of other segment, we can leave + if (robustness_verify_same_side(a, b, sides)) + { + return Policy::disjoint(); + } + } + + // Degenerate cases: segments of single point, lying on other segment, non disjoint + if (a_is_point) + { + return Policy::degenerate(a, true); + } + if (b_is_point) + { + return Policy::degenerate(b, false); + } + + typedef typename select_most_precise + < + coordinate_type, double + >::type promoted_type; + + // r: ratio 0-1 where intersection divides A/B + // (only calculated for non-collinear segments) + promoted_type r; + if (! collinear) + { + // Calculate determinants - Cramers rule + coordinate_type const wx = get<0, 0>(a) - get<0, 0>(b); + coordinate_type const wy = get<0, 1>(a) - get<0, 1>(b); + coordinate_type const d = geometry::detail::determinant<coordinate_type>(dx_a, dy_a, dx_b, dy_b); + coordinate_type const da = geometry::detail::determinant<coordinate_type>(dx_b, dy_b, wx, wy); + + coordinate_type const zero = coordinate_type(); + if (math::equals(d, zero)) + { + // This is still a collinear case (because of FP imprecision this can occur here) + // sides.debug(); + sides.set<0>(0,0); + sides.set<1>(0,0); + collinear = true; + } + else + { + r = promoted_type(da) / promoted_type(d); + + if (! robustness_verify_r(a, b, r)) + { + return Policy::disjoint(); + } + + //robustness_handle_meeting(a, b, sides, dx_a, dy_a, wx, wy, d, r); + + if (robustness_verify_disjoint_at_one_collinear(a, b, sides)) + { + return Policy::disjoint(); + } + + } + } + + if(collinear) + { + if (collinear_use_first) + { + return relate_collinear<0>(a, b); + } + else + { + // Y direction contains larger segments (maybe dx is zero) + return relate_collinear<1>(a, b); + } + } + + return Policy::segments_intersect(sides, r, + dx_a, dy_a, dx_b, dy_b, + a, b); + } + +private : + + + // Ratio should lie between 0 and 1 + // Also these three conditions might be of FP imprecision, the segments were actually (nearly) collinear + template <typename T> + static inline bool robustness_verify_r( + segment_type1 const& a, segment_type2 const& b, + T& r) + { + T const zero = 0; + T const one = 1; + if (r < zero || r > one) + { + if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b)) + { + // Can still be disjoint (even if not one is left or right from another) + // This is e.g. in case #snake4 of buffer test. + return false; + } + + //std::cout << "ROBUSTNESS: correction of r " << r << std::endl; + // sides.debug(); + + // ROBUSTNESS: the r value can in epsilon-cases much larger than 1, while (with perfect arithmetic) + // it should be one. It can be 1.14 or even 1.98049 or 2 (while still intersecting) + + // If segments are crossing (we can see that with the sides) + // and one is inside the other, there must be an intersection point. + // We correct for that. + // This is (only) in case #ggl_list_20110820_christophe in unit tests + + // If segments are touching (two sides zero), of course they should intersect + // This is (only) in case #buffer_rt_i in the unit tests) + + // If one touches in the middle, they also should intersect (#buffer_rt_j) + + // Note that even for ttmath r is occasionally > 1, e.g. 1.0000000000000000000000036191231203575 + + if (r > one) + { + r = one; + } + else if (r < zero) + { + r = zero; + } + } + return true; + } + + static inline void robustness_verify_collinear( + segment_type1 const& , segment_type2 const& , + bool a_is_point, bool b_is_point, + side_info& sides, + bool& collinear) + { + if ((sides.zero<0>() && ! b_is_point && ! sides.zero<1>()) || (sides.zero<1>() && ! a_is_point && ! sides.zero<0>())) + { + // If one of the segments is collinear, the other must be as well. + // So handle it as collinear. + // (In float/double epsilon margins it can easily occur that one or two of them are -1/1) + // sides.debug(); + sides.set<0>(0,0); + sides.set<1>(0,0); + collinear = true; + } + } + + static inline void robustness_verify_meeting( + segment_type1 const& a, segment_type2 const& b, + side_info& sides, + bool& collinear, bool& collinear_use_first) + { + if (sides.meeting()) + { + // If two segments meet each other at their segment-points, two sides are zero, + // the other two are not (unless collinear but we don't mean those here). + // However, in near-epsilon ranges it can happen that two sides are zero + // but they do not meet at their segment-points. + // In that case they are nearly collinear and handled as such. + if (! point_equals + ( + select(sides.zero_index<0>(), a), + select(sides.zero_index<1>(), b) + ) + ) + { + sides.set<0>(0,0); + sides.set<1>(0,0); + collinear = true; + + if (collinear_use_first && analyse_equal<0>(a, b)) + { + collinear_use_first = false; + } + else if (! collinear_use_first && analyse_equal<1>(a, b)) + { + collinear_use_first = true; + } + + } + } + } + + // Verifies and if necessary correct missed touch because of robustness + // This is the case at multi_polygon_buffer unittest #rt_m + static inline bool robustness_verify_same_side( + segment_type1 const& a, segment_type2 const& b, + side_info& sides) + { + int corrected = 0; + if (sides.one_touching<0>()) + { + if (point_equals( + select(sides.zero_index<0>(), a), + select(0, b) + )) + { + sides.correct_to_zero<1, 0>(); + corrected = 1; + } + if (point_equals + ( + select(sides.zero_index<0>(), a), + select(1, b) + )) + { + sides.correct_to_zero<1, 1>(); + corrected = 2; + } + } + else if (sides.one_touching<1>()) + { + if (point_equals( + select(sides.zero_index<1>(), b), + select(0, a) + )) + { + sides.correct_to_zero<0, 0>(); + corrected = 3; + } + if (point_equals + ( + select(sides.zero_index<1>(), b), + select(1, a) + )) + { + sides.correct_to_zero<0, 1>(); + corrected = 4; + } + } + + return corrected == 0; + } + + static inline bool robustness_verify_disjoint_at_one_collinear( + segment_type1 const& a, segment_type2 const& b, + side_info const& sides) + { + if (sides.one_of_all_zero()) + { + if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b)) + { + return true; + } + } + return false; + } + +/* + // If r is one, or zero, segments should meet and their endpoints. + // Robustness issue: check if this is really the case. + // It turns out to be no problem, see buffer test #rt_s1 (and there are many cases generated) + // It generates an "ends in the middle" situation which is correct. + template <typename T, typename R> + static inline void robustness_handle_meeting(segment_type1 const& a, segment_type2 const& b, + side_info& sides, + T const& dx_a, T const& dy_a, T const& wx, T const& wy, + T const& d, R const& r) + { + return; + + T const db = geometry::detail::determinant<T>(dx_a, dy_a, wx, wy); + + R const zero = 0; + R const one = 1; + if (math::equals(r, zero) || math::equals(r, one)) + { + R rb = db / d; + if (rb <= 0 || rb >= 1 || math::equals(rb, 0) || math::equals(rb, 1)) + { + if (sides.one_zero<0>() && ! sides.one_zero<1>()) // or vice versa + { +#if defined(BOOST_GEOMETRY_COUNT_INTERSECTION_EQUAL) + extern int g_count_intersection_equal; + g_count_intersection_equal++; +#endif + sides.debug(); + std::cout << "E r=" << r << " r.b=" << rb << " "; + } + } + } + } +*/ + template <std::size_t Dimension> + static inline bool verify_disjoint(segment_type1 const& a, + segment_type2 const& b) + { + coordinate_type a_1, a_2, b_1, b_2; + bool a_swapped = false, b_swapped = false; + detail::segment_arrange<Dimension>(a, a_1, a_2, a_swapped); + detail::segment_arrange<Dimension>(b, b_1, b_2, b_swapped); + return math::smaller(a_2, b_1) || math::larger(a_1, b_2); + } + + template <typename Segment> + static inline typename point_type<Segment>::type select(int index, Segment const& segment) + { + return index == 0 + ? detail::get_from_index<0>(segment) + : detail::get_from_index<1>(segment) + ; + } + + // We cannot use geometry::equals here. Besides that this will be changed + // to compare segment-coordinate-values directly (not necessary to retrieve point first) + template <typename Point1, typename Point2> + static inline bool point_equals(Point1 const& point1, Point2 const& point2) + { + return math::equals(get<0>(point1), get<0>(point2)) + && math::equals(get<1>(point1), get<1>(point2)) + ; + } + + // We cannot use geometry::equals here. Besides that this will be changed + // to compare segment-coordinate-values directly (not necessary to retrieve point first) + template <typename Point1, typename Point2> + static inline bool point_equality(Point1 const& point1, Point2 const& point2, + bool& equals_0, bool& equals_1) + { + equals_0 = math::equals(get<0>(point1), get<0>(point2)); + equals_1 = math::equals(get<1>(point1), get<1>(point2)); + return equals_0 && equals_1; + } + + template <std::size_t Dimension> + static inline bool analyse_equal(segment_type1 const& a, segment_type2 const& b) + { + coordinate_type const a_1 = geometry::get<0, Dimension>(a); + coordinate_type const a_2 = geometry::get<1, Dimension>(a); + coordinate_type const b_1 = geometry::get<0, Dimension>(b); + coordinate_type const b_2 = geometry::get<1, Dimension>(b); + return math::equals(a_1, b_1) + || math::equals(a_2, b_1) + || math::equals(a_1, b_2) + || math::equals(a_2, b_2) + ; + } + + template <std::size_t Dimension> + static inline return_type relate_collinear(segment_type1 const& a, + segment_type2 const& b) + { + coordinate_type a_1, a_2, b_1, b_2; + bool a_swapped = false, b_swapped = false; + detail::segment_arrange<Dimension>(a, a_1, a_2, a_swapped); + detail::segment_arrange<Dimension>(b, b_1, b_2, b_swapped); + if (math::smaller(a_2, b_1) || math::larger(a_1, b_2)) + //if (a_2 < b_1 || a_1 > b_2) + { + return Policy::disjoint(); + } + return relate_collinear(a, b, a_1, a_2, b_1, b_2, a_swapped, b_swapped); + } + + /// 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 + + bool const opposite = a_swapped ^ b_swapped; + bool const both_swapped = a_swapped && b_swapped; + + // Check if segments are equal or opposite equal... + bool const swapped_a1_eq_b1 = math::equals(a_1, b_1); + bool const swapped_a2_eq_b2 = math::equals(a_2, b_2); + + if (swapped_a1_eq_b1 && swapped_a2_eq_b2) + { + return Policy::segment_equal(a, opposite); + } + + bool const swapped_a2_eq_b1 = math::equals(a_2, b_1); + bool const swapped_a1_eq_b2 = math::equals(a_1, b_2); + + bool const a1_eq_b1 = both_swapped ? swapped_a2_eq_b2 : a_swapped ? swapped_a2_eq_b1 : b_swapped ? swapped_a1_eq_b2 : swapped_a1_eq_b1; + bool const a2_eq_b2 = both_swapped ? swapped_a1_eq_b1 : a_swapped ? swapped_a1_eq_b2 : b_swapped ? swapped_a2_eq_b1 : swapped_a2_eq_b2; + + bool const a1_eq_b2 = both_swapped ? swapped_a2_eq_b1 : a_swapped ? swapped_a2_eq_b2 : b_swapped ? swapped_a1_eq_b1 : swapped_a1_eq_b2; + bool const a2_eq_b1 = both_swapped ? swapped_a1_eq_b2 : a_swapped ? swapped_a1_eq_b1 : b_swapped ? swapped_a2_eq_b2 : swapped_a2_eq_b1; + + + + + // 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 = swapped_a1_eq_b1 || swapped_a1_eq_b2 || swapped_a2_eq_b1 || swapped_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 ((swapped_a2_eq_b1 || swapped_a1_eq_b2) && ! swapped_a1_eq_b1 && ! swapped_a2_eq_b2) + { + 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); + } + + + + // "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. + */ + + 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 + // std::cout << "Robustness issue, non-logical behaviour" << std::endl; + 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 000000000..8b42715e0 --- /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 000000000..48feae51d --- /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 000000000..9cff4d8af --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_projected_point.hpp @@ -0,0 +1,320 @@ +// 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 : + // 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 + < + typename strategy::distance::services::return_type + < + Strategy + >::type + >::type calculation_type; + +private : + + // A projected point of points in Integer coordinates must be able to be + // represented in FP. + typedef model::point + < + calculation_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(); + calculation_type const c1 = dot_product(w, v); + if (c1 <= zero) + { + return strategy.apply(p, p1); + } + calculation_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 + calculation_type const b = c1 / c2; + + fp_strategy_type fp_strategy + = strategy::distance::services::get_similar + < + Strategy, Point, fp_point_type + >::apply(strategy); + boost::ignore_unused_variable_warning(fp_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 000000000..c62cf749e --- /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>(p1)); + T const c2 = boost::numeric_cast<T>(get<I-1>(p2)); + 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 000000000..275f7550e --- /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 000000000..94da5cc67 --- /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 000000000..a774d3c52 --- /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 000000000..967090c50 --- /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 000000000..4963e6b40 --- /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 000000000..295831922 --- /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 000000000..75821b52a --- /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 000000000..f493ef681 --- /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 000000000..b31f0caa4 --- /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 000000000..ba347d015 --- /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 000000000..43bcccf37 --- /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 000000000..92e5156b5 --- /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 000000000..a9684b98e --- /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 000000000..f4edc5ba3 --- /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 000000000..a5aae7703 --- /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_THESE_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 000000000..8adfa5d6e --- /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 000000000..ea5f3ff76 --- /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 000000000..706941b9e --- /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 000000000..ef9a7ee10 --- /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 000000000..fc628c063 --- /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 000000000..15917a9eb --- /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 000000000..376f2fdf1 --- /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 000000000..3c2c1798a --- /dev/null +++ b/boost/geometry/strategies/side_info.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_SIDE_INFO_HPP +#define BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP + +#include <cmath> +#include <utility> +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION +#include <iostream> +#endif + +namespace boost { namespace geometry +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + +/*! +\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 void correct_to_zero() + { + if (Index == 0) + { + sides[Which].first = 0; + } + else + { + sides[Which].second = 0; + } + } + + 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; + } + + inline bool crossing() const + { + return sides[0].first * sides[0].second == -1 + && sides[1].first * sides[1].second == -1; + } + + inline bool touching() const + { + return (sides[0].first * sides[1].first == -1 + && sides[0].second == 0 && sides[1].second == 0) + || (sides[1].first * sides[0].first == -1 + && sides[1].second == 0 && sides[0].second == 0); + } + + template <int Which> + inline bool one_touching() const + { + // This is normally a situation which can't occur: + // If one is completely left or right, the other cannot touch + return one_zero<Which>() + && sides[1 - Which].first * sides[1 - Which].second == 1; + } + + inline bool meeting() const + { + // Two of them (in each segment) zero, two not + return one_zero<0>() && one_zero<1>(); + } + + template <int Which> + inline bool zero() const + { + return sides[Which].first == 0 && sides[Which].second == 0; + } + + template <int Which> + inline bool one_zero() const + { + return (sides[Which].first == 0 && sides[Which].second != 0) + || (sides[Which].first != 0 && sides[Which].second == 0); + } + + inline bool one_of_all_zero() const + { + int const sum = std::abs(sides[0].first) + + std::abs(sides[0].second) + + std::abs(sides[1].first) + + std::abs(sides[1].second); + return sum == 3; + } + + + template <int Which> + inline int zero_index() const + { + return sides[Which].first == 0 ? 0 : 1; + } + +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION + inline void debug() const + { + std::cout << sides[0].first << " " + << sides[0].second << " " + << sides[1].first << " " + << sides[1].second + << std::endl; + } +#endif + + inline void reverse() + { + std::swap(sides[0], sides[1]); + } + +//private : + std::pair<int, int> sides[2]; + +}; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..1bef9b5f2 --- /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 000000000..2f890dfd8 --- /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 000000000..7b353020e --- /dev/null +++ b/boost/geometry/strategies/spherical/distance_cross_track.hpp @@ -0,0 +1,382 @@ +// 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); + return_type d3 = m_strategy.apply(sp1, sp2); + + if (geometry::math::equals(d3, 0.0)) + { + // "Degenerate" segment, return either d1 or d2 + return d1; + } + + return_type d2 = m_strategy.apply(sp2, p); + + return_type crs_AD = course(sp1, p); + return_type crs_AB = course(sp1, sp2); + return_type crs_BA = crs_AB - geometry::math::pi<return_type>(); + return_type crs_BD = course(sp2, p); + return_type d_crs1 = crs_AD - crs_AB; + return_type d_crs2 = crs_BD - crs_BA; + + // d1, d2, d3 are in principle not needed, only the sign matters + return_type projection1 = cos( d_crs1 ) * d1 / d3; + return_type projection2 = cos( d_crs2 ) * d2 / d3; + +#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 << "Course " << dsv(sp2) << " to " << dsv(p) << " " << crs_BD * geometry::math::r2d << std::endl; + std::cout << "Projection AD-AB " << projection1 << " : " << d_crs1 * geometry::math::r2d << std::endl; + std::cout << "Projection BD-BA " << projection2 << " : " << d_crs2 * geometry::math::r2d << std::endl; +#endif + + if(projection1 > 0.0 && projection2 > 0.0) + { + return_type XTD = m_radius * geometry::math::abs( asin( sin( d1 / m_radius ) * sin( d_crs1 ) )); + + #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK + std::cout << "Projection ON the segment" << std::endl; + std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; +#endif + + // Return shortest distance, projected point on segment sp1-sp2 + return return_type(XTD); + } + else + { +#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK + std::cout << "Projection OUTSIDE the segment" << std::endl; +#endif + + // Return shortest distance, project either on point sp1 or sp2 + return return_type( (std::min)( d1 , d2 ) ); + } + } + + 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 000000000..5a866c2ed --- /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 (from Wiki:) 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)) + + +\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 000000000..b7cf279d5 --- /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 000000000..ab7c67559 --- /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 000000000..3aa9ab00f --- /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 000000000..2b75d202e --- /dev/null +++ b/boost/geometry/strategies/strategy_transform.hpp @@ -0,0 +1,504 @@ +// 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/radian_access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/strategies/transform.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; + } + + template <typename P, typename T> + inline bool cartesian_to_spherical_equatorial3(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, asin(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); + } +}; + +template <typename P1, typename P2> +struct from_cartesian_3_to_spherical_equatorial_3 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension<P1, 3>(); + return detail::cartesian_to_spherical_equatorial3(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; +}; +template <typename CoordSys1, typename CoordSys2, typename P1, typename P2> +struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2> +{ + typedef from_cartesian_3_to_spherical_equatorial_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 000000000..39f2f2303 --- /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 000000000..3c806acac --- /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 000000000..845a71ded --- /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 000000000..2755d5353 --- /dev/null +++ b/boost/geometry/strategies/transform/map_transformer.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_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 +{ + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + +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 + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..b37a3712e --- /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; + +public : + 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) {} + + 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; + +public : + 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 000000000..d625bc40e --- /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_THESE_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 000000000..9e0c01299 --- /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/bare_type.hpp b/boost/geometry/util/bare_type.hpp new file mode 100644 index 000000000..1b49de643 --- /dev/null +++ b/boost/geometry/util/bare_type.hpp @@ -0,0 +1,38 @@ +// 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_BARE_TYPE_HPP +#define BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP + +#include <boost/type_traits.hpp> + + +namespace boost { namespace geometry +{ + +namespace util +{ + +template <typename T> +struct bare_type +{ + typedef typename boost::remove_const + < + typename boost::remove_pointer<T>::type + >::type type; +}; + + +} // namespace util + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP diff --git a/boost/geometry/util/calculation_type.hpp b/boost/geometry/util/calculation_type.hpp new file mode 100644 index 000000000..aef58909e --- /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 000000000..57fcd5280 --- /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 000000000..16a15cca5 --- /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 000000000..7a1f55b00 --- /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 000000000..8c152edd2 --- /dev/null +++ b/boost/geometry/util/math.hpp @@ -0,0 +1,237 @@ +// 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 Type get_max(Type const& a, Type const& b, Type const& c) + { + return (std::max)((std::max)(a, b), c); + } + + static inline bool apply(Type const& a, Type const& b) + { + if (a == b) + { + return true; + } + + // 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() * get_max(std::abs(a), std::abs(b), 1.0); + } +}; + +template <typename Type, bool IsFloatingPoint> +struct smaller +{ + static inline bool apply(Type const& a, Type const& b) + { + return a < b; + } +}; + +template <typename Type> +struct smaller<Type, true> +{ + static inline bool apply(Type const& a, Type const& b) + { + if (equals<Type, true>::apply(a, b)) + { + return false; + } + return a < b; + } +}; + + +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>(); + } +}; + +template <typename T> +struct relaxed_epsilon +{ + static inline T apply(const T& factor) + { + return factor * std::numeric_limits<T>::epsilon(); + } +}; + + +} // namespace detail +#endif + + +template <typename T> +inline T pi() { return detail::define_pi<T>::apply(); } + +template <typename T> +inline T relaxed_epsilon(T const& factor) +{ + return detail::relaxed_epsilon<T>::apply(factor); +} + + +// 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); +} + +template <typename T1, typename T2> +inline bool smaller(T1 const& a, T2 const& b) +{ + typedef typename select_most_precise<T1, T2>::type select_type; + return detail::smaller + < + select_type, + boost::is_floating_point<select_type>::type::value + >::apply(a, b); +} + +template <typename T1, typename T2> +inline bool larger(T1 const& a, T2 const& b) +{ + typedef typename select_most_precise<T1, T2>::type select_type; + return detail::smaller + < + select_type, + boost::is_floating_point<select_type>::type::value + >::apply(b, a); +} + + + +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 000000000..6895ebf3f --- /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 000000000..b8872d52b --- /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 000000000..0c74cb8d6 --- /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 000000000..b397532bc --- /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 000000000..7a1bf88be --- /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 000000000..4946c45e8 --- /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 000000000..8309da42b --- /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 000000000..d55fdbfd9 --- /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 000000000..26608b086 --- /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 000000000..882de1ae6 --- /dev/null +++ b/boost/geometry/views/closeable_view.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_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 +{ + +// Silence warning C4512: assignment operator could not be generated +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4512) +#endif + +#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 + + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..91fbc41c1 --- /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 000000000..a40670cf9 --- /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 000000000..5cb9d91f7 --- /dev/null +++ b/boost/geometry/views/identity_view.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_VIEWS_IDENTITY_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_IDENTITY_VIEW_HPP + + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + +// Silence warning C4512: assignment operator could not be generated +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4512) +#endif + +/*! +\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; +}; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +}} // 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 000000000..ad22136c8 --- /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 000000000..50ff617a8 --- /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 |