diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
commit | 08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch) | |
tree | 7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/geometry | |
parent | bb4dd8289b351fae6b55e303f189127a394a1edd (diff) | |
download | boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2 boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip |
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/geometry')
504 files changed, 65332 insertions, 12074 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp index 72b2bbadab..1a8828ba4b 100644 --- a/boost/geometry/algorithms/append.hpp +++ b/boost/geometry/algorithms/append.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,17 +20,20 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP #define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP -#include <boost/range.hpp> +#include <boost/range.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.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/algorithms/num_interior_rings.hpp> -#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/geometries/variant.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -92,7 +101,7 @@ struct point_to_polygon else if (ring_index < int(num_interior_rings(polygon))) { append_point<ring_type, Point>::apply( - interior_rings(polygon)[ring_index], point); + range::at(interior_rings(polygon), ring_index), point); } } }; @@ -104,7 +113,7 @@ 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 ) + int ring_index, int = 0) { if (ring_index == -1) { @@ -114,7 +123,7 @@ struct range_to_polygon else if (ring_index < int(num_interior_rings(polygon))) { append_range<ring_type, Range>::apply( - interior_rings(polygon)[ring_index], range); + range::at(interior_rings(polygon), ring_index), range); } } }; @@ -174,7 +183,7 @@ 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 @@ -193,12 +202,143 @@ struct append<Geometry, RangeOrPoint, point_tag> : splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint> {}; +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace append +{ + +template <typename MultiGeometry, typename RangeOrPoint> +struct append_to_multigeometry +{ + static inline void apply(MultiGeometry& multigeometry, + RangeOrPoint const& range_or_point, + int ring_index, int multi_index) + { + + dispatch::append + < + typename boost::range_value<MultiGeometry>::type, + RangeOrPoint + >::apply(range::at(multigeometry, multi_index), range_or_point, ring_index); + } +}; + +}} // namespace detail::append +#endif // DOXYGEN_NO_DETAIL + +#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> +{}; + +template <typename MultiGeometry, typename RangeOrPoint> +struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint> + : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> +{}; + +template <typename MultiGeometry, typename RangeOrPoint> +struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint> + : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> +{}; + +template <typename MultiGeometry, typename RangeOrPoint> +struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint> + : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> +{}; + +template <typename MultiGeometry, typename RangeOrPoint> +struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint> + : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> +{}; + +} // namespace splitted_dispatch } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH +namespace resolve_variant { + +template <typename Geometry> +struct append +{ + template <typename RangeOrPoint> + static inline void apply(Geometry& geometry, + RangeOrPoint const& range_or_point, + int ring_index, + int multi_index) + { + concept::check<Geometry>(); + dispatch::append<Geometry, RangeOrPoint>::apply(geometry, + range_or_point, + ring_index, + multi_index); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct 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 + { + append<Geometry>::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 resolve_variant; + + /*! \brief Appends one or more points to a linestring, ring, polygon, multi-geometry \ingroup append @@ -208,22 +348,17 @@ struct append<Geometry, RangeOrPoint, point_tag> \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 +\param multi_index The index of the geometry to which the points are appended \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) + int ring_index = -1, int multi_index = 0) { - concept::check<Geometry>(); - - dispatch::append - < - Geometry, - RangeOrPoint - >::apply(geometry, range_or_point, ring_index, multi_index); + resolve_variant::append<Geometry> + ::apply(geometry, range_or_point, ring_index, multi_index); } diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp index 8193200ab9..7377798719 100644 --- a/boost/geometry/algorithms/area.hpp +++ b/boost/geometry/algorithms/area.hpp @@ -18,18 +18,24 @@ #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/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tags.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/algorithms/detail/multi_sum.hpp> #include <boost/geometry/strategies/area.hpp> #include <boost/geometry/strategies/default_area_result.hpp> @@ -49,41 +55,33 @@ namespace boost { namespace geometry namespace detail { namespace area { -template<typename Box, typename Strategy> struct box_area { - typedef typename coordinate_type<Box>::type return_type; - - static inline return_type apply(Box const& box, Strategy const&) + 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_type const dx = get<max_corner, 0>(box) - - get<min_corner, 0>(box); - return_type const dy = get<max_corner, 1>(box) - - get<min_corner, 1>(box); - - return dx * dy; + return (get<max_corner, 0>(box) - get<min_corner, 0>(box)) + * (get<max_corner, 1>(box) - get<min_corner, 1>(box)); } }; template < - typename Ring, iterate_direction Direction, - closure_selector Closure, - typename Strategy + closure_selector Closure > struct ring_area { - BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) ); - - typedef typename Strategy::return_type type; - - static inline type apply(Ring const& ring, Strategy const& strategy) + 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 @@ -92,10 +90,10 @@ struct ring_area // 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)) + if (boost::size(ring) < core_detail::closure::minimum_ring_size<Closure>::value) { - return type(); + return typename Strategy::return_type(); } typedef typename reversible_view<Ring const, Direction>::type rview_type; @@ -136,77 +134,112 @@ namespace dispatch template < typename Geometry, - typename Strategy = typename strategy::area::services::default_strategy - < - typename cs_tag - < - typename point_type<Geometry>::type - >::type, - typename point_type<Geometry>::type - >::type, typename Tag = typename tag<Geometry>::type > -struct area - : detail::calculate_null - < - typename Strategy::return_type, - Geometry, - Strategy - > {}; +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, - typename Strategy -> -struct area<Geometry, Strategy, box_tag> - : detail::area::box_area<Geometry, Strategy> +template <typename Geometry> +struct area<Geometry, box_tag> : detail::area::box_area {}; -template -< - typename Ring, - typename Strategy -> -struct area<Ring, Strategy, ring_tag> +template <typename Ring> +struct area<Ring, ring_tag> : detail::area::ring_area < - Ring, order_as_direction<geometry::point_order<Ring>::value>::value, - geometry::closure<Ring>::value, - Strategy + geometry::closure<Ring>::value > {}; -template -< - typename Polygon, - typename Strategy -> -struct area<Polygon, Strategy, polygon_tag> - : detail::calculate_polygon_sum - < +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, - Polygon, - Strategy, detail::area::ring_area < - typename ring_type<Polygon const>::type, order_as_direction<geometry::point_order<Polygon>::value>::value, - geometry::closure<Polygon>::value, - Strategy + geometry::closure<Polygon>::value > - > -{}; + >(polygon, strategy); + } +}; + + +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 // DOXYGEN_NO_DISPATCH +namespace resolve_variant { + +template <typename Geometry> +struct area +{ + template <typename Strategy> + static inline typename Strategy::return_type apply(Geometry const& geometry, + Strategy const& strategy) + { + return dispatch::area<Geometry>::apply(geometry, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct 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 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 resolve_variant + /*! \brief \brief_calc{area} @@ -234,6 +267,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr { concept::check<Geometry const>(); + // TODO put this into a resolve_strategy stage + // (and take the return type from resolve_variant) typedef typename point_type<Geometry>::type point_type; typedef typename strategy::area::services::default_strategy < @@ -242,11 +277,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr >::type strategy_type; // detail::throw_on_empty_input(geometry); - - return dispatch::area - < - Geometry - >::apply(geometry, strategy_type()); + + return resolve_variant::area<Geometry>::apply(geometry, strategy_type()); } /*! @@ -280,12 +312,8 @@ inline typename Strategy::return_type area( concept::check<Geometry const>(); // detail::throw_on_empty_input(geometry); - - return dispatch::area - < - Geometry, - Strategy - >::apply(geometry, strategy); + + return resolve_variant::area<Geometry>::apply(geometry, strategy); } diff --git a/boost/geometry/algorithms/assign.hpp b/boost/geometry/algorithms/assign.hpp index 8c153c878d..32f095b9ac 100644 --- a/boost/geometry/algorithms/assign.hpp +++ b/boost/geometry/algorithms/assign.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -40,6 +41,8 @@ #include <boost/geometry/util/for_each_coordinate.hpp> +#include <boost/variant/variant_fwd.hpp> + namespace boost { namespace geometry { @@ -122,9 +125,232 @@ inline void assign_zero(Geometry& geometry) } /*! +\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 resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct assign +{ + static inline void + apply( + Geometry1& geometry1, + const Geometry2& geometry2) + { + concept::check<Geometry1>(); + concept::check<Geometry2 const>(); + 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); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + struct visitor: static_visitor<void> + { + Geometry2 const& m_geometry2; + + visitor(Geometry2 const& geometry2) + : m_geometry2(geometry2) + {} + + template <typename Geometry1> + result_type operator()(Geometry1& geometry1) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (geometry1, m_geometry2); + } + }; + + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1, + Geometry2 const& geometry2) + { + return apply_visitor(visitor(geometry2), geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: static_visitor<void> + { + Geometry1& m_geometry1; + + visitor(Geometry1 const& geometry1) + : m_geometry1(geometry1) + {} + + template <typename Geometry2> + result_type operator()(Geometry2 const& geometry2) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (m_geometry1, geometry2); + } + }; + + static inline void + apply(Geometry1& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + { + return apply_visitor(visitor(geometry1), geometry2); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)> +struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> > +{ + struct visitor: static_visitor<void> + { + template <typename Geometry1, typename Geometry2> + result_type operator()( + Geometry1& geometry1, + Geometry2 const& geometry2) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (geometry1, geometry2); + } + }; + + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2) + { + return apply_visitor(visitor(), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + +/*! \brief Assigns one geometry to another geometry -\details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only -if it is possible and applicable. +\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 @@ -142,25 +368,7 @@ if it is possible and applicable. 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); + resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2); } diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp index e22e36addc..b8b07ad4d9 100644 --- a/boost/geometry/algorithms/buffer.hpp +++ b/boost/geometry/algorithms/buffer.hpp @@ -17,15 +17,19 @@ #include <cstddef> #include <boost/numeric/conversion/cast.hpp> - +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/clear.hpp> -#include <boost/geometry/algorithms/detail/disjoint.hpp> +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/geometries/segment.hpp> +#include <boost/geometry/geometries/box.hpp> #include <boost/geometry/util/math.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp> namespace boost { namespace geometry { @@ -75,29 +79,87 @@ inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out) namespace dispatch { -template <typename TagIn, typename TagOut, typename Input, typename T, typename Output> -struct buffer {}; +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 T, typename BoxOut> -struct buffer<box_tag, box_tag, BoxIn, T, BoxOut> +template <typename BoxIn, typename BoxOut> +struct buffer<BoxIn, BoxOut, box_tag, box_tag> { - static inline void apply(BoxIn const& box_in, T const& distance, - T const& , BoxIn& box_out) + template <typename Distance> + static inline void apply(BoxIn const& box_in, Distance const& distance, + Distance const& , BoxOut& 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 +namespace resolve_variant { + +template <typename Geometry> +struct buffer +{ + template <typename Distance, typename GeometryOut> + static inline void apply(Geometry const& geometry, + Distance const& distance, + Distance const& chord_length, + GeometryOut& out) + { + dispatch::buffer<Geometry, GeometryOut>::apply(geometry, distance, chord_length, out); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct buffer<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Distance, typename GeometryOut> + struct visitor: boost::static_visitor<void> + { + Distance const& m_distance; + Distance const& m_chord_length; + GeometryOut& m_out; + + visitor(Distance const& distance, + Distance const& chord_length, + GeometryOut& out) + : m_distance(distance), + m_chord_length(chord_length), + m_out(out) + {} + + template <typename Geometry> + void operator()(Geometry const& geometry) const + { + buffer<Geometry>::apply(geometry, m_distance, m_chord_length, m_out); + } + }; + + template <typename Distance, typename GeometryOut> + static inline void apply( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Distance const& distance, + Distance const& chord_length, + GeometryOut& out + ) + { + boost::apply_visitor(visitor<Distance, GeometryOut>(distance, chord_length, out), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc{buffer} \ingroup buffer @@ -109,7 +171,6 @@ struct buffer<box_tag, box_tag, BoxIn, T, BoxOut> \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]} */ @@ -120,14 +181,7 @@ inline void buffer(Input const& geometry_in, Output& geometry_out, concept::check<Input const>(); concept::check<Output>(); - dispatch::buffer - < - typename tag<Input>::type, - typename tag<Output>::type, - Input, - Distance, - Output - >::apply(geometry_in, distance, chord_length, geometry_out); + resolve_variant::buffer<Input>::apply(geometry_in, distance, chord_length, geometry_out); } /*! @@ -139,29 +193,90 @@ inline void buffer(Input const& geometry_in, Output& geometry_out, \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 +\param chord_length (optional) The length of the chord's in the generated arcs + around points or bends (RESERVED, NOT YET USED) \return \return_calc{buffer} */ -template <typename Output, typename Input, typename T> -Output return_buffer(Input const& geometry, T const& distance, T const& chord_length = -1) +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 - < - typename tag<Input>::type, - typename tag<Output>::type, - Input, - T, - Output - >::apply(geometry, distance, chord_length, geometry_out); + resolve_variant::buffer<Input>::apply(geometry, distance, chord_length, geometry_out); return geometry_out; } +/*! +\brief \brief_calc{buffer} +\ingroup buffer +\details \details_calc{buffer, \det_buffer}. +\tparam GeometryIn \tparam_geometry +\tparam MultiPolygon \tparam_geometry{MultiPolygon} +\tparam DistanceStrategy A strategy defining distance (or radius) +\tparam SideStrategy A strategy defining creation along sides +\tparam JoinStrategy A strategy defining creation around convex corners +\tparam EndStrategy A strategy defining creation at linestring ends +\tparam PointStrategy A strategy defining creation around points +\param geometry_in \param_geometry +\param geometry_out output multi polygon (or std:: collection of polygons), + will contain a buffered version of the input geometry +\param distance_strategy The distance strategy to be used +\param side_strategy The side strategy to be used +\param join_strategy The join strategy to be used +\param end_strategy The end strategy to be used +\param point_strategy The point strategy to be used + +\qbk{distinguish,with strategies} +\qbk{[include reference/algorithms/buffer_with_strategies.qbk]} + */ +template +< + typename GeometryIn, + typename MultiPolygon, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy +> +inline void buffer(GeometryIn const& geometry_in, + MultiPolygon& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy) +{ + typedef typename boost::range_value<MultiPolygon>::type polygon_type; + concept::check<GeometryIn const>(); + concept::check<polygon_type>(); + + typedef typename point_type<GeometryIn>::type point_type; + typedef typename rescale_policy_type<point_type>::type rescale_policy_type; + + geometry_out.clear(); + + model::box<point_type> box; + envelope(geometry_in, box); + buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy)); + + rescale_policy_type rescale_policy + = boost::geometry::get_rescale_policy<rescale_policy_type>(box); + + detail::buffer::buffer_inserter<polygon_type>(geometry_in, std::back_inserter(geometry_out), + distance_strategy, + side_strategy, + join_strategy, + end_strategy, + point_strategy, + rescale_policy); +} + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp index 69ad9fe829..65dc9c3753 100644 --- a/boost/geometry/algorithms/centroid.hpp +++ b/boost/geometry/algorithms/centroid.hpp @@ -3,6 +3,12 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,7 +24,9 @@ #include <cstddef> #include <boost/range.hpp> -#include <boost/typeof/typeof.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/cs.hpp> @@ -27,17 +35,27 @@ #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/point_type.hpp> -#include <boost/geometry/algorithms/convert.hpp> -#include <boost/geometry/algorithms/distance.hpp> #include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/centroid.hpp> #include <boost/geometry/strategies/concepts/centroid_concept.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/util/for_each_coordinate.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/multi/algorithms/num_points.hpp> + +#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp> namespace boost { namespace geometry @@ -62,8 +80,15 @@ class centroid_exception : public geometry::exception { public: + /*! + \brief The default constructor + */ inline centroid_exception() {} + /*! + \brief Returns the explanatory string. + \return Pointer to a null-terminated string with explanatory information. + */ virtual char const* what() const throw() { return "Boost.Geometry Centroid calculation exception"; @@ -77,9 +102,9 @@ public: namespace detail { namespace centroid { -template<typename Point, typename PointCentroid, typename Strategy> struct centroid_point { + template<typename Point, typename PointCentroid, typename Strategy> static inline void apply(Point const& point, PointCentroid& centroid, Strategy const&) { @@ -89,55 +114,56 @@ struct centroid_point template < - typename Box, + typename Indexed, typename Point, std::size_t Dimension, std::size_t DimensionCount > -struct centroid_box_calculator +struct centroid_indexed_calculator { typedef typename select_coordinate_type < - Box, Point + Indexed, Point >::type coordinate_type; - static inline void apply(Box const& box, Point& centroid) + static inline void apply(Indexed const& indexed, Point& centroid) { - coordinate_type const c1 = get<min_corner, Dimension>(box); - coordinate_type const c2 = get<max_corner, Dimension>(box); + coordinate_type const c1 = get<min_corner, Dimension>(indexed); + coordinate_type const c2 = get<max_corner, Dimension>(indexed); coordinate_type m = c1 + c2; - m /= 2.0; + coordinate_type const two = 2; + m /= two; set<Dimension>(centroid, m); - centroid_box_calculator + centroid_indexed_calculator < - Box, Point, + Indexed, Point, Dimension + 1, DimensionCount - >::apply(box, centroid); + >::apply(indexed, centroid); } }; -template<typename Box, typename Point, std::size_t DimensionCount> -struct centroid_box_calculator<Box, Point, DimensionCount, DimensionCount> +template<typename Indexed, typename Point, std::size_t DimensionCount> +struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount> { - static inline void apply(Box const& , Point& ) + static inline void apply(Indexed const& , Point& ) { } }; -template<typename Box, typename Point, typename Strategy> -struct centroid_box +struct centroid_indexed { - static inline void apply(Box const& box, Point& centroid, + template<typename Indexed, typename Point, typename Strategy> + static inline void apply(Indexed const& indexed, Point& centroid, Strategy const&) { - centroid_box_calculator + centroid_indexed_calculator < - Box, Point, - 0, dimension<Box>::type::value - >::apply(box, centroid); + Indexed, Point, + 0, dimension<Indexed>::type::value + >::apply(indexed, centroid); } }; @@ -169,16 +195,19 @@ inline bool range_ok(Range const& range, Point& centroid) return true; } - /*! - \brief Calculate the centroid of a ring. + \brief Calculate the centroid of a Ring or a Linestring. */ -template<typename Ring, closure_selector Closure, typename Strategy> +template <closure_selector Closure> struct centroid_range_state { + template<typename Ring, typename PointTransformer, typename Strategy> static inline void apply(Ring const& ring, - Strategy const& strategy, typename Strategy::state_type& state) + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) { + typedef typename geometry::point_type<Ring const>::type point_type; typedef typename closeable_view<Ring const, Closure>::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator_type; @@ -187,31 +216,42 @@ struct centroid_range_state iterator_type it = boost::begin(view); iterator_type end = boost::end(view); - for (iterator_type previous = it++; - it != end; - ++previous, ++it) + typename PointTransformer::result_type + previous_pt = transformer.apply(*it); + + for ( ++it ; it != end ; ++it) { - strategy.apply(*previous, *it, state); + typename PointTransformer::result_type + pt = transformer.apply(*it); + + strategy.apply(static_cast<point_type const&>(previous_pt), + static_cast<point_type const&>(pt), + state); + + previous_pt = pt; } } }; -template<typename Range, typename Point, closure_selector Closure, typename Strategy> +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) + Strategy const& strategy) { if (range_ok(range, centroid)) { + // prepare translation transformer + translating_transformer<Range> transformer(*boost::begin(range)); + typename Strategy::state_type state; - centroid_range_state - < - Range, - Closure, - Strategy - >::apply(range, strategy, state); + centroid_range_state<Closure>::apply(range, transformer, + strategy, state); strategy.result(state, centroid); + + // translate the result back + transformer.apply_reverse(centroid); } } }; @@ -222,48 +262,112 @@ struct centroid_range \note Because outer ring is clockwise, inners are counter clockwise, triangle approach is OK and works for polygons with rings. */ -template<typename Polygon, typename Strategy> struct centroid_polygon_state { - typedef typename ring_type<Polygon>::type ring_type; - + template<typename Polygon, typename PointTransformer, typename Strategy> static inline void apply(Polygon const& poly, - Strategy const& strategy, typename Strategy::state_type& state) + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) { - typedef centroid_range_state - < - ring_type, - geometry::closure<ring_type>::value, - Strategy - > per_ring; + 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); + per_ring::apply(exterior_ring(poly), transformer, 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(poly); + + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { - per_ring::apply(*it, strategy, state); + per_ring::apply(*it, transformer, strategy, state); } } }; -template<typename Polygon, typename Point, typename Strategy> 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)) { + // prepare translation transformer + translating_transformer<Polygon> + transformer(*boost::begin(exterior_ring(poly))); + typename Strategy::state_type state; - centroid_polygon_state - < - Polygon, - Strategy - >::apply(poly, strategy, state); + centroid_polygon_state::apply(poly, transformer, strategy, state); strategy.result(state, centroid); + + // translate the result back + transformer.apply_reverse(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 PointTransformer, typename Strategy> + static inline void apply(Point const& point, + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) + { + strategy.apply(static_cast<Point const&>(transformer.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 + + // prepare translation transformer + translating_transformer<Multi> transformer(multi); + + 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, transformer, strategy, state); + } + Strategy::result(state, centroid); + + // translate the result back + transformer.apply_reverse(centroid); } }; @@ -278,64 +382,153 @@ namespace dispatch template < - typename Tag, typename Geometry, - typename Point, - typename Strategy + typename Tag = typename tag<Geometry>::type > -struct centroid {}; +struct centroid: not_implemented<Tag> +{}; -template -< - typename Geometry, - typename Point, - typename Strategy -> -struct centroid<point_tag, Geometry, Point, Strategy> - : detail::centroid::centroid_point<Geometry, Point, Strategy> +template <typename Geometry> +struct centroid<Geometry, point_tag> + : detail::centroid::centroid_point {}; -template -< - typename Box, - typename Point, - typename Strategy -> -struct centroid<box_tag, Box, Point, Strategy> - : detail::centroid::centroid_box<Box, Point, Strategy> +template <typename Box> +struct centroid<Box, box_tag> + : detail::centroid::centroid_indexed +{}; + +template <typename Segment> +struct centroid<Segment, segment_tag> + : detail::centroid::centroid_indexed +{}; + +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 Ring, typename Point, typename Strategy> -struct centroid<ring_tag, Ring, Point, Strategy> - : detail::centroid::centroid_range +template <typename Polygon> +struct centroid<Polygon, polygon_tag> + : detail::centroid::centroid_polygon +{}; + +template <typename MultiLinestring> +struct centroid<MultiLinestring, multi_linestring_tag> + : detail::centroid::centroid_multi < - Ring, - Point, - geometry::closure<Ring>::value, - Strategy + detail::centroid::centroid_range_state<closed> > {}; -template <typename Linestring, typename Point, typename Strategy> -struct centroid<linestring_tag, Linestring, Point, Strategy> - : detail::centroid::centroid_range +template <typename MultiPolygon> +struct centroid<MultiPolygon, multi_polygon_tag> + : detail::centroid::centroid_multi < - Linestring, - Point, - closed, - Strategy + detail::centroid::centroid_polygon_state + > +{}; + +template <typename MultiPoint> +struct centroid<MultiPoint, multi_point_tag> + : detail::centroid::centroid_multi + < + detail::centroid::centroid_multi_point_state > - {}; +{}; -template <typename Polygon, typename Point, typename Strategy> -struct centroid<polygon_tag, Polygon, Point, Strategy> - : detail::centroid::centroid_polygon<Polygon, Point, Strategy> - {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy { + +template <typename Geometry> +struct centroid +{ + template <typename Point, typename Strategy> + static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy) + { + dispatch::centroid<Geometry>::apply(geometry, out, strategy); + } + + template <typename Point> + static inline void apply(Geometry const& geometry, Point& out, default_strategy) + { + 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; + + dispatch::centroid<Geometry>::apply(geometry, out, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry> +struct centroid +{ + template <typename Point, typename Strategy> + static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy) + { + concept::check_concepts_and_equal_dimensions<Point, Geometry const>(); + resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Point, typename Strategy> + struct visitor: boost::static_visitor<void> + { + Point& m_out; + Strategy const& m_strategy; + + visitor(Point& out, Strategy const& strategy) + : m_out(out), m_strategy(strategy) + {} + + template <typename Geometry> + void operator()(Geometry const& geometry) const + { + centroid<Geometry>::apply(geometry, m_out, m_strategy); + } + }; + + template <typename Point, typename Strategy> + static inline void + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Point& out, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc{centroid} \brief_strategy \ingroup centroid @@ -357,21 +550,7 @@ template<typename Geometry, typename Point, typename Strategy> inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy) { - //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) ); - - concept::check_concepts_and_equal_dimensions<Point, Geometry const>(); - - typedef typename point_type<Geometry>::type point_type; - - // Call dispatch apply method. That one returns true if centroid - // should be taken from state. - dispatch::centroid - < - typename tag<Geometry>::type, - Geometry, - Point, - Strategy - >::apply(geometry, c, strategy); + resolve_variant::centroid<Geometry>::apply(geometry, c, strategy); } @@ -394,24 +573,7 @@ inline void centroid(Geometry const& geometry, Point& c, 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()); + centroid(geometry, c, default_strategy()); } @@ -429,8 +591,6 @@ inline void centroid(Geometry const& geometry, Point& c) 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; @@ -454,10 +614,6 @@ inline Point return_centroid(Geometry const& geometry) 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; diff --git a/boost/geometry/algorithms/clear.hpp b/boost/geometry/algorithms/clear.hpp index d7336587ee..1850816b1b 100644 --- a/boost/geometry/algorithms/clear.hpp +++ b/boost/geometry/algorithms/clear.hpp @@ -14,15 +14,19 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP -#include <boost/mpl/assert.hpp> + #include <boost/type_traits/remove_const.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.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/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -72,6 +76,7 @@ struct no_action } }; + }} // namespace detail::clear #endif // DOXYGEN_NO_DETAIL @@ -84,14 +89,8 @@ template typename Geometry, typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type > -struct clear -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry>) - ); -}; +struct clear: not_implemented<Tag> +{}; // Point/box/segment do not have clear. So specialize to do nothing. template <typename Geometry> @@ -127,10 +126,48 @@ struct clear<Polygon, polygon_tag> {}; +template <typename Geometry> +struct clear<Geometry, multi_tag> + : detail::clear::collection_clear<Geometry> +{}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH +namespace resolve_variant { + +template <typename Geometry> +struct clear +{ + static inline void apply(Geometry& geometry) + { + dispatch::clear<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct 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 resolve_variant + + /*! \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 @@ -149,7 +186,7 @@ inline void clear(Geometry& geometry) { concept::check<Geometry>(); - dispatch::clear<Geometry>::apply(geometry); + resolve_variant::clear<Geometry>::apply(geometry); } diff --git a/boost/geometry/algorithms/comparable_distance.hpp b/boost/geometry/algorithms/comparable_distance.hpp index 3467045ca2..6f009da3ed 100644 --- a/boost/geometry/algorithms/comparable_distance.hpp +++ b/boost/geometry/algorithms/comparable_distance.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,61 +19,7 @@ #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 - +#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp> +#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP diff --git a/boost/geometry/algorithms/convert.hpp b/boost/geometry/algorithms/convert.hpp index fbbf74c17f..914ef8f420 100644 --- a/boost/geometry/algorithms/convert.hpp +++ b/boost/geometry/algorithms/convert.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -20,6 +21,10 @@ #include <boost/numeric/conversion/cast.hpp> #include <boost/range.hpp> #include <boost/type_traits/is_array.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> @@ -31,19 +36,32 @@ #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/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> +#include <boost/geometry/util/range.hpp> + #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tags.hpp> + #include <boost/geometry/geometries/concepts/check.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 { @@ -95,7 +113,7 @@ struct box_to_range assign_box_corners_oriented<Reverse>(box, range); if (Close) { - range[4] = range[0]; + range::at(range, 4) = range::at(range, 0); } } }; @@ -115,22 +133,22 @@ struct segment_to_range } }; -template +template < - typename Range1, - typename Range2, + typename Range1, + typename Range2, bool Reverse = false > struct range_to_range { typedef typename reversible_view < - Range1 const, + Range1 const, Reverse ? iterate_reverse : iterate_forward >::type rview_type; typedef typename closeable_view < - rview_type const, + rview_type const, geometry::closure<Range1>::value >::type view_type; @@ -144,13 +162,17 @@ struct range_to_range // point for open output. view_type view(rview); - int n = boost::size(view); + typedef typename boost::range_size<Range1>::type size_type; + size_type n = boost::size(view); if (geometry::closure<Range2>::value == geometry::open) { n--; } - int i = 0; + // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max() + // but ok, sice below it == end() + + size_type i = 0; for (typename boost::range_iterator<view_type const>::type it = boost::begin(view); it != boost::end(view) && i < n; @@ -166,7 +188,7 @@ struct polygon_to_polygon { typedef range_to_range < - typename geometry::ring_type<Polygon1>::type, + typename geometry::ring_type<Polygon1>::type, typename geometry::ring_type<Polygon2>::type, geometry::point_order<Polygon1>::value != geometry::point_order<Polygon2>::value @@ -176,7 +198,7 @@ struct polygon_to_polygon { // Clearing managed per ring, and in the resizing of interior rings - per_ring::apply(geometry::exterior_ring(source), + per_ring::apply(geometry::exterior_ring(source), geometry::exterior_ring(destination)); // Container should be resizeable @@ -188,13 +210,15 @@ struct polygon_to_polygon >::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); + 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)); + typename detail::interior_iterator<Polygon1 const>::type + it_source = boost::begin(rings_source); + typename detail::interior_iterator<Polygon2>::type + it_dest = boost::begin(rings_dest); for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest) { @@ -203,6 +227,37 @@ struct polygon_to_polygon } }; +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::conversion #endif // DOXYGEN_NO_DETAIL @@ -280,8 +335,8 @@ struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, 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, + < + Ring1, Ring2, geometry::point_order<Ring1>::value != geometry::point_order<Ring2>::value @@ -302,8 +357,8 @@ template <typename Box, typename Ring> struct convert<Box, Ring, box_tag, ring_tag, 2, false> : detail::conversion::box_to_range < - Box, - Ring, + Box, + Ring, geometry::closure<Ring>::value == closed, geometry::point_order<Ring>::value == counterclockwise > @@ -377,16 +432,108 @@ struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false> }; +// 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 resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct convert +{ + static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2) + { + concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>(); + dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct 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 + { + 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); + } +}; + +} + + /*! \brief Converts one geometry to another geometry \details The convert algorithm converts one geometry, e.g. a BOX, to another -geometry, e.g. a RING. This only if it is possible and applicable. -If the point-order is different, or the closure is different between two -geometry types, it will be converted correctly by explicitly reversing the +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 @@ -399,13 +546,13 @@ points or closing or opening the polygon rings. template <typename Geometry1, typename Geometry2> inline void convert(Geometry1 const& geometry1, Geometry2& geometry2) { - concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>(); - - dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2); + resolve_variant::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 index 56b87c8c15..09f4c5142d 100644 --- a/boost/geometry/algorithms/convex_hull.hpp +++ b/boost/geometry/algorithms/convex_hull.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -15,15 +20,20 @@ #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP #include <boost/array.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/closure.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/strategies/default_strategy.hpp> #include <boost/geometry/views/detail/range_type.hpp> @@ -40,45 +50,34 @@ namespace boost { namespace geometry namespace detail { namespace convex_hull { -template -< - typename Geometry, - order_selector Order, - typename Strategy -> +template <order_selector Order, closure_selector Closure> struct hull_insert { // Member template function (to avoid inconvenient declaration // of output-iterator-type, from hull_to_geometry) - template <typename OutputIterator> + 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); + strategy.result(state, out, Order == clockwise, Closure != open); return out; } }; -template -< - typename Geometry, - typename Strategy -> struct hull_to_geometry { - template <typename OutputGeometry> + template <typename Geometry, typename OutputGeometry, typename Strategy> static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { hull_insert < - Geometry, geometry::point_order<OutputGeometry>::value, - Strategy + geometry::closure<OutputGeometry>::value >::apply(geometry, std::back_inserter( // Handle linestring, ring and polygon the same: @@ -89,18 +88,6 @@ struct hull_to_geometry } }; - -// 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 @@ -113,21 +100,16 @@ namespace dispatch template < typename Geometry, - typename Strategy = typename detail::convex_hull::default_strategy<Geometry>::type, typename Tag = typename tag<Geometry>::type > struct convex_hull - : detail::convex_hull::hull_to_geometry<Geometry, Strategy> + : detail::convex_hull::hull_to_geometry {}; -template -< - typename Box, - typename Strategy -> -struct convex_hull<Box, Strategy, box_tag> +template <typename Box> +struct convex_hull<Box, box_tag> { - template <typename OutputGeometry> + template <typename OutputGeometry, typename Strategy> static inline void apply(Box const& box, OutputGeometry& out, Strategy const& ) { @@ -149,13 +131,9 @@ struct convex_hull<Box, Strategy, box_tag> -template -< - order_selector Order, - typename Geometry, typename Strategy -> +template <order_selector Order, closure_selector Closure> struct convex_hull_insert - : detail::convex_hull::hull_insert<Geometry, Order, Strategy> + : detail::convex_hull::hull_insert<Order, Closure> {}; @@ -163,29 +141,170 @@ struct convex_hull_insert #endif // DOXYGEN_NO_DISPATCH -template<typename Geometry, typename OutputGeometry, typename Strategy> -inline void convex_hull(Geometry const& geometry, - OutputGeometry& out, Strategy const& strategy) +namespace resolve_strategy { + +struct convex_hull { - concept::check_concepts_and_equal_dimensions - < + template <typename Geometry, typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) ); + dispatch::convex_hull<Geometry>::apply(geometry, out, strategy); + } + + template <typename Geometry, typename OutputGeometry> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + default_strategy) + { + typedef typename strategy_convex_hull< + Geometry, + typename point_type<Geometry>::type + >::type strategy_type; + + apply(geometry, out, strategy_type()); + } +}; + +struct convex_hull_insert +{ + template <typename Geometry, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Geometry const& geometry, + OutputIterator& out, + Strategy const& strategy) + { + BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) ); + + return dispatch::convex_hull_insert< + geometry::point_order<Geometry>::value, + geometry::closure<Geometry>::value + >::apply(geometry, out, strategy); + } + + template <typename Geometry, typename OutputIterator> + static inline OutputIterator apply(Geometry const& geometry, + OutputIterator& out, + default_strategy) + { + typedef typename strategy_convex_hull< + Geometry, + typename point_type<Geometry>::type + >::type strategy_type; + + return apply(geometry, out, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry> +struct convex_hull +{ + template <typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) + { + concept::check_concepts_and_equal_dimensions< const Geometry, OutputGeometry >(); - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) ); + resolve_strategy::convex_hull::apply(geometry, out, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename OutputGeometry, typename Strategy> + struct visitor: boost::static_visitor<void> + { + OutputGeometry& m_out; + Strategy const& m_strategy; + + visitor(OutputGeometry& out, Strategy const& strategy) + : m_out(out), m_strategy(strategy) + {} + + template <typename Geometry> + void operator()(Geometry const& geometry) const + { + convex_hull<Geometry>::apply(geometry, m_out, m_strategy); + } + }; + + template <typename OutputGeometry, typename Strategy> + static inline void + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + boost::apply_visitor(visitor<OutputGeometry, Strategy>(out, strategy), geometry); + } +}; + +template <typename Geometry> +struct convex_hull_insert +{ + template <typename OutputIterator, typename Strategy> + static inline OutputIterator apply(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>(); + + return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename OutputIterator, typename Strategy> + struct visitor: boost::static_visitor<OutputIterator> + { + OutputIterator& m_out; + Strategy const& m_strategy; + + visitor(OutputIterator& out, Strategy const& strategy) + : m_out(out), m_strategy(strategy) + {} + template <typename Geometry> + OutputIterator operator()(Geometry const& geometry) const + { + return convex_hull_insert<Geometry>::apply(geometry, m_out, m_strategy); + } + }; + + template <typename OutputIterator, typename Strategy> + static inline OutputIterator + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + OutputIterator& out, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<OutputIterator, Strategy>(out, strategy), geometry); + } +}; + +} // namespace resolve_variant + + +template<typename Geometry, typename OutputGeometry, typename Strategy> +inline void convex_hull(Geometry const& geometry, + OutputGeometry& out, Strategy const& strategy) +{ if (geometry::num_points(geometry) == 0) { // Leave output empty return; } - dispatch::convex_hull - < - Geometry, - Strategy - >::apply(geometry, out, strategy); + resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy); } @@ -193,8 +312,8 @@ inline void convex_hull(Geometry const& geometry, \brief \brief_calc{convex hull} \ingroup convex_hull \details \details_calc{convex_hull,convex hull}. -\tparam Geometry1 \tparam_geometry -\tparam Geometry2 \tparam_geometry +\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} @@ -204,15 +323,7 @@ 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()); + convex_hull(geometry, hull, default_strategy()); } #ifndef DOXYGEN_NO_DETAIL @@ -224,17 +335,8 @@ template<typename Geometry, typename OutputIterator, typename Strategy> inline OutputIterator convex_hull_insert(Geometry const& geometry, OutputIterator out, Strategy const& strategy) { - // Concept: output point type = point type of input geometry - concept::check<Geometry const>(); - concept::check<typename point_type<Geometry>::type>(); - - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) ); - - return dispatch::convex_hull_insert - < - geometry::point_order<Geometry>::value, - Geometry, Strategy - >::apply(geometry, out, strategy); + return resolve_variant::convex_hull_insert<Geometry> + ::apply(geometry, out, strategy); } @@ -255,13 +357,7 @@ 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()); + return convex_hull_insert(geometry, out, default_strategy()); } diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp index 583e395f8e..3c61b2c0d2 100644 --- a/boost/geometry/algorithms/correct.hpp +++ b/boost/geometry/algorithms/correct.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -21,25 +22,37 @@ #include <boost/mpl/assert.hpp> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/algorithms/detail/interior_iterator.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/core/mutable_range.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/algorithms/detail/multi_modify.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 { @@ -119,10 +132,8 @@ struct correct_ring typedef detail::area::ring_area < - Ring, order_as_direction<geometry::point_order<Ring>::value>::value, - geometry::closure<Ring>::value, - strategy_type + geometry::closure<Ring>::value > ring_area_type; @@ -139,7 +150,7 @@ struct correct_ring { geometry::append(r, *boost::begin(r)); } - if (! disjoint && geometry::closure<Ring>::value != closed) + if (! disjoint && s != closed) { // Open it by removing last point geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1); @@ -172,9 +183,10 @@ struct correct_polygon 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) + typename interior_return_type<Polygon>::type + rings = interior_rings(poly); + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { correct_ring < @@ -234,10 +246,69 @@ struct correct<Polygon, polygon_tag> {}; +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 resolve_variant { + +template <typename Geometry> +struct correct +{ + static inline void apply(Geometry& geometry) + { + concept::check<Geometry const>(); + dispatch::correct<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<void> + { + template <typename Geometry> + void operator()(Geometry& geometry) const + { + correct<Geometry>::apply(geometry); + } + }; + + static inline void + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) + { + boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief Corrects a geometry \details Corrects a geometry: all rings which are wrongly oriented with respect @@ -253,11 +324,12 @@ struct correct<Polygon, polygon_tag> template <typename Geometry> inline void correct(Geometry& geometry) { - concept::check<Geometry const>(); - - dispatch::correct<Geometry>::apply(geometry); + resolve_variant::correct<Geometry>::apply(geometry); } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp index c3c406c4ca..e50dc338af 100644 --- a/boost/geometry/algorithms/covered_by.hpp +++ b/boost/geometry/algorithms/covered_by.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,21 +14,52 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP #define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP #include <cstddef> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #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> +#include <boost/geometry/strategies/default_strategy.hpp> namespace boost { namespace geometry { +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace covered_by { + +struct use_point_in_geometry +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0; + } +}; + +struct use_relate +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/) + { + return Strategy::apply(geometry1, geometry2); + } +}; + +}} // namespace detail::covered_by +#endif // DOXYGEN_NO_DETAIL + #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -37,7 +71,8 @@ template typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > -struct covered_by: not_implemented<Tag1, Tag2> +struct covered_by + : not_implemented<Tag1, Tag2> {}; @@ -47,6 +82,7 @@ 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); } }; @@ -58,48 +94,332 @@ struct covered_by<Box1, Box2, box_tag, box_tag> 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); } }; +// P/P + +template <typename Point1, typename Point2> +struct covered_by<Point1, Point2, point_tag, point_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +template <typename Point, typename MultiPoint> +struct covered_by<Point, MultiPoint, point_tag, multi_point_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +// P/L + +template <typename Point, typename Segment> +struct covered_by<Point, Segment, point_tag, segment_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +template <typename Point, typename Linestring> +struct covered_by<Point, Linestring, point_tag, linestring_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +template <typename Point, typename MultiLinestring> +struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +// P/A template <typename Point, typename Ring> struct covered_by<Point, Ring, point_tag, ring_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +template <typename Point, typename Polygon> +struct covered_by<Point, Polygon, point_tag, polygon_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +template <typename Point, typename MultiPolygon> +struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag> + : public detail::covered_by::use_point_in_geometry +{}; + +// L/L + +template <typename Linestring1, typename Linestring2> +struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Linestring, typename MultiLinestring> +struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiLinestring, typename Linestring> +struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiLinestring1, typename MultiLinestring2> +struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag> + : public detail::covered_by::use_relate +{}; + +// L/A + +template <typename Linestring, typename Ring> +struct covered_by<Linestring, Ring, linestring_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiLinestring, typename Ring> +struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Linestring, typename Polygon> +struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiLinestring, typename Polygon> +struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Linestring, typename MultiPolygon> +struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiLinestring, typename MultiPolygon> +struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +// A/A + +template <typename Ring1, typename Ring2> +struct covered_by<Ring1, Ring2, ring_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Ring, typename Polygon> +struct covered_by<Ring, Polygon, ring_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Polygon, typename Ring> +struct covered_by<Polygon, Ring, polygon_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Polygon1, typename Polygon2> +struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Ring, typename MultiPolygon> +struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiPolygon, typename Ring> +struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Polygon, typename MultiPolygon> +struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiPolygon, typename Polygon> +struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename MultiPolygon1, typename MultiPolygon2> +struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_strategy { + +struct covered_by { - template <typename Strategy> - static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return detail::within::point_in_ring + concept::within::check < - Point, - Ring, - order_as_direction<geometry::point_order<Ring>::value>::value, - geometry::closure<Ring>::value, + typename tag<Geometry1>::type, + typename tag<Geometry2>::type, + typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, Strategy - >::apply(point, ring, strategy) >= 0; + >(); + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + assert_dimension_equal<Geometry1, Geometry2>(); + + return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1, + geometry2, + strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + 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 covered_by::apply(geometry1, geometry2, strategy_type()); } }; -template <typename Point, typename Polygon> -struct covered_by<Point, Polygon, point_tag, polygon_tag> +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct covered_by { template <typename Strategy> - static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy) + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + 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; + return resolve_strategy::covered_by + ::apply(geometry1, geometry2, strategy); } }; -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, Strategy const& strategy) + : m_geometry2(geometry2), m_strategy(strategy) {} + + template <typename Geometry1> + bool operator()(Geometry1 const& geometry1) const + { + return covered_by<Geometry1, Geometry2> + ::apply(geometry1, m_geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + } +}; + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Geometry1 const& m_geometry1; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, Strategy const& strategy) + : m_geometry1(geometry1), m_strategy(strategy) {} + + template <typename Geometry2> + bool operator()(Geometry2 const& geometry2) const + { + return covered_by<Geometry1, Geometry2> + ::apply(m_geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + } +}; + +template < + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) +> +struct covered_by< + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> +> +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy): m_strategy(strategy) {} + + template <typename Geometry1, typename Geometry2> + bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return covered_by<Geometry1, Geometry2> + ::apply(geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + } +}; + +} // namespace resolve_variant /*! @@ -120,36 +440,8 @@ struct covered_by<Point, Polygon, point_tag, polygon_tag> 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()); + return resolve_variant::covered_by<Geometry1, Geometry2> + ::apply(geometry1, geometry2, default_strategy()); } /*! @@ -172,22 +464,8 @@ 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); + return resolve_variant::covered_by<Geometry1, Geometry2> + ::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/crosses.hpp b/boost/geometry/algorithms/crosses.hpp new file mode 100644 index 0000000000..91ed3e0806 --- /dev/null +++ b/boost/geometry/algorithms/crosses.hpp @@ -0,0 +1,194 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP + +#include <cstddef> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/core/access.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/detail/relate/relate.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 crosses + : detail::relate::relate_base + < + detail::relate::static_mask_crosses_type, + Geometry1, + Geometry2 + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant +{ + template <typename Geometry1, typename Geometry2> + struct crosses + { + static inline bool + apply( + const Geometry1& geometry1, + const Geometry2& geometry2) + { + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2); + } + }; + + + template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> + struct crosses<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> + result_type operator()(Geometry1 const& geometry1) const + { + return crosses + < + Geometry1, + Geometry2 + >::apply + (geometry1, m_geometry2); + } + }; + + static inline bool + apply(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 crosses<Geometry1, 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> + result_type operator()(Geometry2 const& geometry2) const + { + return crosses + < + Geometry1, + Geometry2 + >::apply + (m_geometry1, geometry2); + } + }; + + static inline bool + apply( + Geometry1 const& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2) + { + return apply_visitor(visitor(geometry1), geometry2); + } + }; + + + template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)> + struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> > + { + struct visitor: static_visitor<bool> + { + template <typename Geometry1, typename Geometry2> + result_type operator()( + Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return crosses + < + Geometry1, + Geometry2 + >::apply + (geometry1, geometry2); + } + }; + + static inline bool + apply( + const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2) + { + return apply_visitor(visitor(), geometry1, geometry2); + } + }; + +} // namespace resolve_variant + + +/*! +\brief \brief_check2{crosses} +\ingroup crosses +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\return \return_check2{crosses} + +\qbk{[include reference/algorithms/crosses.qbk]} +*/ +template <typename Geometry1, typename Geometry2> +inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + return resolve_variant::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP diff --git a/boost/geometry/algorithms/detail/assign_box_corners.hpp b/boost/geometry/algorithms/detail/assign_box_corners.hpp index 1fd41733f2..669d6d3655 100644 --- a/boost/geometry/algorithms/detail/assign_box_corners.hpp +++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp @@ -19,14 +19,14 @@ #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> - +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL -namespace detail +namespace detail { // Note: this is moved to namespace detail because the names and parameter orders // are not yet 100% clear. @@ -67,20 +67,34 @@ inline void assign_box_corners(Box const& box, <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]); + assign_box_corners(box, + range::at(corners, 0), range::at(corners, 1), + range::at(corners, 3), range::at(corners, 2)); } else { // make clockwise ll,ul,ur,lr - assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]); + assign_box_corners(box, + range::at(corners, 0), range::at(corners, 3), + range::at(corners, 1), range::at(corners, 2)); } } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } // namespace detail diff --git a/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/boost/geometry/algorithms/detail/assign_indexed_point.hpp index a1cffb80a7..acfc37e250 100644 --- a/boost/geometry/algorithms/detail/assign_indexed_point.hpp +++ b/boost/geometry/algorithms/detail/assign_indexed_point.hpp @@ -25,7 +25,7 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL -namespace detail +namespace detail { /*! diff --git a/boost/geometry/algorithms/detail/assign_values.hpp b/boost/geometry/algorithms/detail/assign_values.hpp index ed4713493f..5e4a1795b5 100644 --- a/boost/geometry/algorithms/detail/assign_values.hpp +++ b/boost/geometry/algorithms/detail/assign_values.hpp @@ -46,36 +46,30 @@ namespace detail { namespace assign { -template -< - typename Box, std::size_t Index, - std::size_t Dimension, std::size_t DimensionCount -> +template <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) + template <typename Box> + static inline void apply(Box& box, typename coordinate_type<Box>::type const& value) { geometry::set<Index, Dimension>(box, value); - initialize<Box, Index, Dimension + 1, DimensionCount>::apply(box, value); + initialize<Index, Dimension + 1, DimensionCount>::apply(box, value); } }; -template <typename Box, std::size_t Index, std::size_t DimensionCount> -struct initialize<Box, Index, DimensionCount, DimensionCount> +template <std::size_t Index, std::size_t DimensionCount> +struct initialize<Index, DimensionCount, DimensionCount> { - typedef typename coordinate_type<Box>::type coordinate_type; - - static inline void apply(Box&, coordinate_type const& ) + template <typename Box> + static inline void apply(Box&, typename coordinate_type<Box>::type const&) {} }; -template <typename Point> struct assign_zero_point { + template <typename Point> static inline void apply(Point& point) { geometry::assign_value(point, 0); @@ -83,44 +77,38 @@ struct assign_zero_point }; -template <typename BoxOrSegment> struct assign_inverse_box_or_segment { - typedef typename point_type<BoxOrSegment>::type point_type; + template <typename BoxOrSegment> static inline void apply(BoxOrSegment& geometry) { + typedef typename point_type<BoxOrSegment>::type point_type; 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()); + initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply( + geometry, boost::numeric::bounds<bound_type>::highest() + ); + initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply( + geometry, boost::numeric::bounds<bound_type>::lowest() + ); } }; -template <typename BoxOrSegment> struct assign_zero_box_or_segment { + template <typename BoxOrSegment> 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()); + initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply( + geometry, coordinate_type() + ); + initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply( + geometry, coordinate_type() + ); } }; @@ -312,17 +300,17 @@ struct assign_zero {}; template <typename Point> struct assign_zero<point_tag, Point> - : detail::assign::assign_zero_point<Point> + : detail::assign::assign_zero_point {}; template <typename Box> struct assign_zero<box_tag, Box> - : detail::assign::assign_zero_box_or_segment<Box> + : detail::assign::assign_zero_box_or_segment {}; template <typename Segment> struct assign_zero<segment_tag, Segment> - : detail::assign::assign_zero_box_or_segment<Segment> + : detail::assign::assign_zero_box_or_segment {}; @@ -331,112 +319,18 @@ struct assign_inverse {}; template <typename Box> struct assign_inverse<box_tag, Box> - : detail::assign::assign_inverse_box_or_segment<Box> + : detail::assign::assign_inverse_box_or_segment {}; template <typename Segment> struct assign_inverse<segment_tag, Segment> - : detail::assign::assign_inverse_box_or_segment<Segment> + : detail::assign::assign_inverse_box_or_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 diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp new file mode 100644 index 0000000000..c959ee849b --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -0,0 +1,940 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_BUFFER_INSERTER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP + +#include <cstddef> +#include <iterator> + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp> +#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp> +#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp> + +#include <boost/geometry/algorithms/simplify.hpp> + +#include <boost/geometry/views/detail/normalized_view.hpp> + +#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX) +#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp> +#endif + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template <typename Range, typename DistanceStrategy> +inline void simplify_input(Range const& range, + DistanceStrategy const& distance, + Range& simplified) +{ + // We have to simplify the ring before to avoid very small-scaled + // features in the original (convex/concave/convex) being enlarged + // in a very large scale and causing issues (IP's within pieces). + // This might be reconsidered later. Simplifying with a very small + // distance (1%% of the buffer) will never be visible in the result, + // if it is using round joins. For miter joins they are even more + // sensitive to small scale input features, however the result will + // look better. + // It also gets rid of duplicate points +#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX) + geometry::simplify(range, simplified, distance.simplify_distance()); +#else + + typedef typename boost::range_value<Range>::type point_type; + typedef strategy::distance::detail::projected_point_ax<> ax_type; + typedef typename strategy::distance::services::return_type + < + strategy::distance::detail::projected_point_ax<>, + point_type, + point_type + >::type return_type; + + typedef strategy::distance::detail::projected_point_ax_less + < + return_type + > comparator_type; + + typedef strategy::simplify::detail::douglas_peucker + < + point_type, + strategy::distance::detail::projected_point_ax<>, + comparator_type + > dp_ax; + + return_type max_distance(distance.simplify_distance() * 2.0, + distance.simplify_distance()); + comparator_type comparator(max_distance); + dp_ax strategy(comparator); + + geometry::simplify(range, simplified, max_distance, strategy); +#endif + + if (boost::size(simplified) == 2 + && geometry::equals(geometry::range::front(simplified), + geometry::range::back(simplified))) + { + traits::resize<Range>::apply(simplified, 1); + } +} + + +template <typename RingOutput> +struct buffer_range +{ + typedef typename point_type<RingOutput>::type output_point_type; + typedef typename coordinate_type<RingOutput>::type coordinate_type; + + template + < + typename Collection, + typename Point, + typename DistanceStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline + void add_join(Collection& collection, + Point const& penultimate_input, + Point const& previous_input, + output_point_type const& prev_perp1, + output_point_type const& prev_perp2, + Point const& input, + output_point_type const& perp1, + output_point_type const& perp2, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& ) + { + output_point_type intersection_point; + + strategy::buffer::join_selector join + = get_join_type(penultimate_input, previous_input, input); + if (join == strategy::buffer::join_convex) + { + // Calculate the intersection-point formed by the two sides. + // It might be that the two sides are not convex, but continue + // or spikey, we then change the join-type + join = line_line_intersection::apply( + perp1, perp2, prev_perp1, prev_perp2, + intersection_point); + + } + switch(join) + { + case strategy::buffer::join_continue : + // No join, we get two consecutive sides + return; + case strategy::buffer::join_concave : + collection.add_piece(strategy::buffer::buffered_concave, + previous_input, prev_perp2, perp1); + return; + case strategy::buffer::join_spike : + { + // For linestrings, only add spike at one side to avoid + // duplicates + std::vector<output_point_type> range_out; + end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out); + collection.add_endcap(end_strategy, range_out, previous_input); + } + return; + case strategy::buffer::join_convex : + break; // All code below handles this + } + + // The corner is convex, we create a join + // TODO (future) - avoid a separate vector, add the piece directly + std::vector<output_point_type> range_out; + if (join_strategy.apply(intersection_point, + previous_input, prev_perp2, perp1, + distance.apply(previous_input, input, side), + range_out)) + { + collection.add_piece(strategy::buffer::buffered_join, + previous_input, range_out); + } + } + + static inline strategy::buffer::join_selector get_join_type( + output_point_type const& p0, + output_point_type const& p1, + output_point_type const& p2) + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<output_point_type>::type + >::type side_strategy; + + int const side = side_strategy::apply(p0, p1, p2); + return side == -1 ? strategy::buffer::join_convex + : side == 1 ? strategy::buffer::join_concave + : parallel_continue + ( + get<0>(p2) - get<0>(p1), + get<1>(p2) - get<1>(p1), + get<0>(p1) - get<0>(p0), + get<1>(p1) - get<1>(p0) + ) ? strategy::buffer::join_continue + : strategy::buffer::join_spike; + } + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy, + output_point_type& first_p1, + output_point_type& first_p2, + output_point_type& last_p1, + output_point_type& last_p2) + { + typedef typename std::iterator_traits + < + Iterator + >::value_type point_type; + + typedef typename robust_point_type + < + point_type, + RobustPolicy + >::type robust_point_type; + + robust_point_type previous_robust_input; + point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end + + /* + * last.p1 last.p2 these are the "previous (last) perpendicular points" + * -------------- + * | | + * *------------*____ <- *prev + * pup | | p1 "current perpendicular point 1" + * | | + * | | this forms a "side", a side is a piece + * | | + * *____| p2 + * + * ^ + * *it + * + * pup: penultimate_point + */ + + bool result = false; + bool first = true; + + Iterator it = begin; + + geometry::recalculate(previous_robust_input, *begin, robust_policy); + + std::vector<output_point_type> generated_side; + generated_side.reserve(2); + + for (Iterator prev = it++; it != end; ++it) + { + robust_point_type robust_input; + geometry::recalculate(robust_input, *it, robust_policy); + // Check on equality - however, if input is simplified, this is + // unlikely (though possible by rescaling or for degenerated pointlike polygons) + if (! detail::equals::equals_point_point(previous_robust_input, robust_input)) + { + generated_side.clear(); + side_strategy.apply(*prev, *it, side, + distance_strategy, generated_side); + + if (generated_side.empty()) + { + break; + } + + result = true; + + if (! first) + { + add_join(collection, + penultimate_point, + *prev, last_p1, last_p2, + *it, generated_side.front(), generated_side.back(), + side, + distance_strategy, join_strategy, end_strategy, + robust_policy); + } + + collection.add_side_piece(*prev, *it, generated_side, first); + + penultimate_point = *prev; + ultimate_point = *it; + last_p1 = generated_side.front(); + last_p2 = generated_side.back(); + prev = it; + if (first) + { + first = false; + second_point = *it; + first_p1 = generated_side.front(); + first_p2 = generated_side.back(); + } + } + previous_robust_input = robust_input; + } + return result; + } +}; + +template +< + typename Multi, + typename PolygonOutput, + typename Policy +> +struct buffer_multi +{ + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Multi const& multi, + Collection& collection, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + for (typename boost::range_iterator<Multi const>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it, collection, + distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + } + } +}; + +struct visit_pieces_default_policy +{ + template <typename Collection> + static inline void apply(Collection const&, int) + {} +}; + +template +< + typename OutputPointType, + typename Point, + typename Collection, + typename DistanceStrategy, + typename PointStrategy +> +inline void buffer_point(Point const& point, Collection& collection, + DistanceStrategy const& distance_strategy, + PointStrategy const& point_strategy) +{ + collection.start_new_ring(); + std::vector<OutputPointType> range_out; + point_strategy.apply(point, distance_strategy, range_out); + collection.add_piece(strategy::buffer::buffered_point, range_out, false); + collection.finish_ring(); +} + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Tag, + typename RingInput, + typename RingOutput +> +struct buffer_inserter +{}; + + + +template +< + typename Point, + typename RingOutput +> +struct buffer_inserter<point_tag, Point, RingOutput> +{ + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Point const& point, Collection& collection, + DistanceStrategy const& distance_strategy, + SideStrategy const& , + JoinStrategy const& , + EndStrategy const& , + PointStrategy const& point_strategy, + RobustPolicy const& ) + { + detail::buffer::buffer_point + < + typename point_type<RingOutput>::type + >(point, collection, distance_strategy, point_strategy); + } +}; + + +template +< + typename RingInput, + typename RingOutput +> +struct buffer_inserter<ring_tag, RingInput, RingOutput> +{ + typedef typename point_type<RingOutput>::type output_point_type; + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy) + { + output_point_type first_p1, first_p2, last_p1, last_p2; + + typedef detail::buffer::buffer_range<RingOutput> buffer_range; + + bool result = buffer_range::iterate(collection, begin, end, + side, + distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + // Generate closing join + if (result) + { + buffer_range::add_join(collection, + *(end - 2), + *(end - 1), last_p1, last_p2, + *(begin + 1), first_p1, first_p2, + side, + distance_strategy, join_strategy, end_strategy, + robust_policy); + } + + // Buffer is closed automatically by last closing corner + return result; + } + + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(RingInput const& ring, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + RingInput simplified; + detail::buffer::simplify_input(ring, distance, simplified); + + bool has_output = false; + + std::size_t n = boost::size(simplified); + std::size_t const min_points = core_detail::closure::minimum_ring_size + < + geometry::closure<RingInput>::value + >::value; + + if (n >= min_points) + { + detail::normalized_view<RingInput const> view(simplified); + if (distance.negative()) + { + // Walk backwards (rings will be reversed afterwards) + // It might be that this will be changed later. + // TODO: decide this. + has_output = iterate(collection, boost::rbegin(view), boost::rend(view), + strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, robust_policy); + } + else + { + has_output = iterate(collection, boost::begin(view), boost::end(view), + strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, robust_policy); + } + } + + if (! has_output && n >= 1) + { + // Use point_strategy to buffer degenerated ring + detail::buffer::buffer_point<output_point_type> + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); + } + } +}; + + +template +< + typename Linestring, + typename Polygon +> +struct buffer_inserter<linestring_tag, Linestring, Polygon> +{ + typedef typename ring_type<Polygon>::type output_ring_type; + typedef typename point_type<output_ring_type>::type output_point_type; + typedef typename point_type<Linestring>::type input_point_type; + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy, + output_point_type& first_p1) + { + input_point_type const& ultimate_point = *(end - 1); + input_point_type const& penultimate_point = *(end - 2); + + // For the end-cap, we need to have the last perpendicular point on the + // other side of the linestring. If it is the second pass (right), + // we have it already from the first phase (left). + // But for the first pass, we have to generate it + output_point_type reverse_p1; + if (side == strategy::buffer::buffer_side_right) + { + reverse_p1 = first_p1; + } + else + { + std::vector<output_point_type> generated_side; + side_strategy.apply(ultimate_point, penultimate_point, + strategy::buffer::buffer_side_right, + distance_strategy, generated_side); + if (generated_side.empty()) + { + return false; + } + reverse_p1 = generated_side.front(); + } + + output_point_type first_p2, last_p1, last_p2; + + detail::buffer::buffer_range<output_ring_type>::iterate(collection, + begin, end, side, + distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + std::vector<output_point_type> range_out; + end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out); + collection.add_endcap(end_strategy, range_out, ultimate_point); + return true; + } + + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Linestring const& linestring, Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + Linestring simplified; + detail::buffer::simplify_input(linestring, distance, simplified); + + bool has_output = false; + std::size_t n = boost::size(simplified); + if (n > 1) + { + collection.start_new_ring(); + output_point_type first_p1; + has_output = iterate(collection, + boost::begin(simplified), boost::end(simplified), + strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1); + + if (has_output) + { + iterate(collection, boost::rbegin(simplified), boost::rend(simplified), + strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1); + } + collection.finish_ring(); + } + if (! has_output && n >= 1) + { + // Use point_strategy to buffer degenerated linestring + detail::buffer::buffer_point<output_point_type> + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); + } + } +}; + + +template +< + typename PolygonInput, + typename PolygonOutput +> +struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput> +{ +private: + typedef typename ring_type<PolygonInput>::type input_ring_type; + typedef typename ring_type<PolygonOutput>::type output_ring_type; + + typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy; + + + template + < + typename Iterator, + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline + void iterate(Iterator begin, Iterator end, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy, + bool is_interior) + { + for (Iterator it = begin; it != end; ++it) + { + collection.start_new_ring(); + policy::apply(*it, collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + collection.finish_ring(is_interior); + } + } + + template + < + typename InteriorRings, + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline + void apply_interior_rings(InteriorRings const& interior_rings, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + iterate(boost::begin(interior_rings), boost::end(interior_rings), + collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy, true); + } + +public: + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(PolygonInput const& polygon, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + { + collection.start_new_ring(); + policy::apply(exterior_ring(polygon), collection, + distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + collection.finish_ring(); + } + + apply_interior_rings(interior_rings(polygon), + collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + } +}; + + +template +< + typename Multi, + typename PolygonOutput +> +struct buffer_inserter<multi_tag, Multi, PolygonOutput> + : public detail::buffer::buffer_multi + < + Multi, + PolygonOutput, + dispatch::buffer_inserter + < + typename single_tag_of + < + typename tag<Multi>::type + >::type, + typename boost::range_value<Multi const>::type, + typename geometry::ring_type<PolygonOutput>::type + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template +< + typename GeometryOutput, + typename GeometryInput, + typename OutputIterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy, + typename VisitPiecesPolicy +> +inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy, + VisitPiecesPolicy& visit_pieces_policy + ) +{ + typedef detail::buffer::buffered_piece_collection + < + typename geometry::ring_type<GeometryOutput>::type, + RobustPolicy + > collection_type; + collection_type collection(robust_policy); + collection_type const& const_collection = collection; + + bool const areal = boost::is_same + < + typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type, + areal_tag + >::type::value; + + dispatch::buffer_inserter + < + typename tag_cast + < + typename tag<GeometryInput>::type, + multi_tag + >::type, + GeometryInput, + GeometryOutput + >::apply(geometry_input, collection, + distance_strategy, side_strategy, join_strategy, + end_strategy, point_strategy, + robust_policy); + + collection.get_turns(); + if (areal) + { + collection.check_remaining_points(distance_strategy.factor()); + } + + // Visit the piece collection. This does nothing (by default), but + // optionally a debugging tool can be attached (e.g. console or svg), + // or the piece collection can be unit-tested + // phase 0: turns (before discarded) + visit_pieces_policy.apply(const_collection, 0); + + collection.discard_rings(); + collection.block_turns(); + collection.enrich(); + collection.traverse(); + + // Reverse all offsetted rings / traversed rings if: + // - they were generated on the negative side (deflate) of polygons + // - the output is counter clockwise + // and avoid reversing twice + bool reverse = distance_strategy.negative() && areal; + if (geometry::point_order<GeometryOutput>::value == counterclockwise) + { + reverse = ! reverse; + } + if (reverse) + { + collection.reverse(); + } + + collection.template assign<GeometryOutput>(out); + + // Visit collection again + // phase 1: rings (after discarding and traversing) + visit_pieces_policy.apply(const_collection, 1); +} + +template +< + typename GeometryOutput, + typename GeometryInput, + typename OutputIterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy +> +inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) +{ + detail::buffer::visit_pieces_default_policy visitor; + buffer_inserter<GeometryOutput>(geometry_input, out, + distance_strategy, side_strategy, join_strategy, + end_strategy, point_strategy, + robust_policy, visitor); +} +#endif // DOXYGEN_NO_DETAIL + +}} // namespace detail::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp new file mode 100644 index 0000000000..6a2e6b32c5 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_BUFFER_POLICIES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +enum intersection_location_type +{ + location_ok, inside_buffer, inside_original +}; + +class backtrack_for_buffer +{ +public : + typedef detail::overlay::backtrack_state state_type; + + template <typename Operation, typename Rings, typename Turns, typename Geometry, typename RobustPolicy> + 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*/, + Geometry const& , + Geometry const& , + RobustPolicy const& , + state_type& state + ) + { +#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS) +extern int g_backtrack_warning_count; +g_backtrack_warning_count++; +#endif +//std::cout << "!"; +//std::cout << "WARNING " << reason << std::endl; + + state.m_good = false; + + // 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); + } +}; + +// Should follow traversal-turn-concept (enrichment, visit structure) +// and adds index in piece vector to find it back +template <typename Point, typename SegmentRatio> +struct buffer_turn_operation + : public detail::overlay::traversal_turn_operation<Point, SegmentRatio> +{ + int piece_index; + int index_in_robust_ring; + + inline buffer_turn_operation() + : piece_index(-1) + , index_in_robust_ring(-1) + {} +}; + +// Version for buffer including type of location, is_opposite, and helper variables +template <typename Point, typename RobustPoint, typename SegmentRatio> +struct buffer_turn_info + : public detail::overlay::turn_info + < + Point, + SegmentRatio, + buffer_turn_operation<Point, SegmentRatio> + > +{ + typedef Point point_type; + typedef RobustPoint robust_point_type; + + int turn_index; // TODO: this might go if partition can operate on non-const input + + RobustPoint robust_point; +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + // Will (most probably) be removed later + RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours +#endif + + + inline RobustPoint const& get_robust_point() const + { +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + return mapped_robust_point; +#endif + return robust_point; + } + + + intersection_location_type location; + + int count_within; + int count_on_offsetted; + int count_on_helper; + int count_within_near_offsetted; + + bool remove_on_multi; + + // Obsolete: + int count_on_occupied; + int count_on_multi; + + inline buffer_turn_info() + : turn_index(-1) + , location(location_ok) + , count_within(0) + , count_on_offsetted(0) + , count_on_helper(0) + , count_within_near_offsetted(0) + , remove_on_multi(false) + , count_on_occupied(0) + , count_on_multi(0) + {} +}; + +struct buffer_operation_less +{ + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + segment_identifier const& sl = left.seg_id; + segment_identifier const& sr = right.seg_id; + + // Sort them descending + return sl == sr + ? left.fraction < right.fraction + : sl < sr; + } +}; + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp new file mode 100644 index 0000000000..558a61fcb4 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -0,0 +1,954 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_BUFFERED_PIECE_COLLECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP + +#include <algorithm> +#include <cstddef> +#include <set> +#include <boost/range.hpp> + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/envelope.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + +#include <boost/geometry/geometries/ring.hpp> +#include <boost/geometry/geometries/polygon.hpp> + +#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> +#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp> +#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.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/enrichment_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp> +#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp> +#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/traverse.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/occupation_info.hpp> +#include <boost/geometry/algorithms/detail/partition.hpp> + +#include <boost/geometry/util/range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +enum segment_relation_code +{ + segment_relation_on_left, + segment_relation_on_right, + segment_relation_within, + segment_relation_disjoint +}; + +/* + * Terminology + * + * Suppose we make a buffer (using blocked corners) of this rectangle: + * + * +-------+ + * | | + * | rect | + * | | + * +-------+ + * + * For the sides we get these four buffered side-pieces (marked with s) + * and four buffered corner pieces (marked with c) + * + * c---+---s---+---c + * | | piece | | <- see below for details of the middle top-side-piece + * +---+-------+---+ + * | | | | + * s | rect | s <- two side pieces left/right of rect + * | | | | + * +---+-------+---+ + * | | piece | | <- one side-piece below, and two corner pieces + * c---+---s---+---c + * + * The outer part of the picture above, using all pieces, + * form together the offsetted ring (marked with o below) + * The 8 pieces are part of the piece collection and use for inside-checks + * The inner parts form (using 1 or 2 points per piece, often co-located) + * form together the robust_ring (marked with r below) + * The remaining piece-segments are helper-segments (marked with h) + * + * ooooooooooooooooo + * o h h o + * ohhhrrrrrrrrrhhho + * o r r o + * o r r o + * o r r o + * ohhhrrrrrrrrrhhho + * o h h o + * ooooooooooooooooo + * + */ + + +template <typename Ring, typename RobustPolicy> +struct buffered_piece_collection +{ + typedef buffered_piece_collection<Ring, RobustPolicy> this_type; + + typedef typename geometry::point_type<Ring>::type point_type; + typedef typename geometry::coordinate_type<Ring>::type coordinate_type; + typedef typename geometry::robust_point_type + < + point_type, + RobustPolicy + >::type robust_point_type; + + // Robust ring/polygon type, always clockwise + typedef geometry::model::ring<robust_point_type> robust_ring_type; + typedef geometry::model::polygon<robust_point_type> robust_polygon_type; + + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<point_type>::type + >::type side_strategy; + + typedef typename geometry::rescale_policy_type + < + typename geometry::point_type<Ring>::type + >::type rescale_policy_type; + + typedef typename geometry::segment_ratio_type + < + point_type, + RobustPolicy + >::type segment_ratio_type; + + typedef buffer_turn_info + < + point_type, + robust_point_type, + segment_ratio_type + > buffer_turn_info_type; + + typedef buffer_turn_operation + < + point_type, + segment_ratio_type + > buffer_turn_operation_type; + + typedef std::vector<buffer_turn_info_type> turn_vector_type; + + struct robust_turn + { + int turn_index; + int operation_index; + robust_point_type point; + segment_identifier seg_id; + segment_ratio_type fraction; + }; + + struct piece + { + strategy::buffer::piece_type type; + int index; + + int left_index; // points to previous piece of same ring + int right_index; // points to next piece of same ring + + // The next two members (1, 2) form together a complete clockwise ring + // for each piece (with one dupped point) + // The complete clockwise ring is also included as a robust ring (3) + + // 1: half, part of offsetted_rings + segment_identifier first_seg_id; + int last_segment_index; // no segment-identifier - it is the same as first_seg_id + int offsetted_count; // part in robust_ring which is part of offsetted ring + +#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS) + // 2: half, not part of offsetted rings - part of robust ring + std::vector<point_type> helper_points; // 4 points for segment, 3 points for join - 0 points for flat-end +#endif + + // Robust representations + // 3: complete ring + robust_ring_type robust_ring; + + geometry::model::box<robust_point_type> robust_envelope; + + std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead + }; + + typedef std::vector<piece> piece_vector_type; + + piece_vector_type m_pieces; + turn_vector_type m_turns; + int m_first_piece_index; + + buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index + buffered_ring_collection<robust_polygon_type> robust_polygons; // robust representation of the original(s) + robust_ring_type current_robust_ring; + buffered_ring_collection<Ring> traversed_rings; + segment_identifier current_segment_id; + + RobustPolicy const& m_robust_policy; + + struct redundant_turn + { + inline bool operator()(buffer_turn_info_type const& turn) const + { + return turn.remove_on_multi; + } + }; + + buffered_piece_collection(RobustPolicy const& robust_policy) + : m_first_piece_index(-1) + , m_robust_policy(robust_policy) + {} + + +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + // Will (most probably) be removed later + template <typename OccupationMap> + inline void adapt_mapped_robust_point(OccupationMap const& map, + buffer_turn_info_type& turn, int distance) const + { + for (int x = -distance; x <= distance; x++) + { + for (int y = -distance; y <= distance; y++) + { + robust_point_type rp = turn.robust_point; + geometry::set<0>(rp, geometry::get<0>(rp) + x); + geometry::set<1>(rp, geometry::get<1>(rp) + y); + if (map.find(rp) != map.end()) + { + turn.mapped_robust_point = rp; + return; + } + } + } + } +#endif + + inline void get_occupation( +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + int distance = 0 +#endif + ) + { + typedef occupation_info<angle_info<robust_point_type, coordinate_type> > + buffer_occupation_info; + + typedef std::map + < + robust_point_type, + buffer_occupation_info, + geometry::less<robust_point_type> + > occupation_map_type; + + occupation_map_type occupation_map; + + // 1: Add all intersection points to occupation map + typedef typename boost::range_iterator<turn_vector_type>::type + iterator_type; + + for (iterator_type it = boost::begin(m_turns); + it != boost::end(m_turns); + ++it) + { + if (it->location == location_ok) + { +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + if (distance > 0 && ! occupation_map.empty()) + { + adapt_mapped_robust_point(occupation_map, *it, distance); + } +#endif + occupation_map[it->get_robust_point()].count++; + } + } + + // Remove all points with one or more u/u points from the map + // (Alternatively, we could NOT do this here and change all u/u + // behaviour in overlay. Currently nothing is done: each polygon is + // just followed there. We could also always switch polygons there. For + // buffer behaviour, where 3 pieces might meet of which 2 (or more) form + // a u/u turn, this last option would have been better, probably). + for (iterator_type it = boost::begin(m_turns); + it != boost::end(m_turns); + ++it) + { + if (it->both(detail::overlay::operation_union)) + { + typename occupation_map_type::iterator mit = + occupation_map.find(it->get_robust_point()); + + if (mit != occupation_map.end()) + { + occupation_map.erase(mit); + } + } + } + + // 2: Remove all points from map which has only one + typename occupation_map_type::iterator it = occupation_map.begin(); + while (it != occupation_map.end()) + { + if (it->second.count <= 1) + { + typename occupation_map_type::iterator to_erase = it; + ++it; + occupation_map.erase(to_erase); + } + else + { + ++it; + } + } + + if (occupation_map.empty()) + { + return; + } + + // 3: Add vectors (incoming->intersection-point, + // intersection-point -> outgoing) + // for all (co-located) points still present in the map + + for (iterator_type it = boost::begin(m_turns); + it != boost::end(m_turns); + ++it) + { + typename occupation_map_type::iterator mit = + occupation_map.find(it->get_robust_point()); + + if (mit != occupation_map.end()) + { + buffer_occupation_info& info = mit->second; + for (int i = 0; i < 2; i++) + { + add_incoming_and_outgoing_angles(it->get_robust_point(), *it, + m_pieces, + i, it->operations[i].seg_id, + info); + } + + it->count_on_multi++; + } + } + +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + // X: Check rounding issues + if (distance == 0) + { + for (typename occupation_map_type::const_iterator it = occupation_map.begin(); + it != occupation_map.end(); ++it) + { + if (it->second.has_rounding_issues(it->first)) + { + if(distance == 0) + { + get_occupation(distance + 1); + return; + } + } + } + } +#endif + + // Get left turns from all clusters + for (typename occupation_map_type::iterator it = occupation_map.begin(); + it != occupation_map.end(); ++it) + { + it->second.get_left_turns(it->first, m_turns); + } + } + + inline void classify_turns() + { + for (typename boost::range_iterator<turn_vector_type>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + if (it->count_within > 0) + { + it->location = inside_buffer; + } + if (it->count_within_near_offsetted > 0) + { + // Within can have in rare cases a rounding issue. We don't discard this + // point, so it can be used to continue started rings in traversal. But + // will never start a new ring from this type of points. + it->selectable_start = false; + } + + } + } + + inline void check_remaining_points(int factor) + { + // TODO: use partition + + for (typename boost::range_iterator<turn_vector_type>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + if (it->location == location_ok) + { + int code = -1; + for (std::size_t i = 0; i < robust_polygons.size(); i++) + { + if (geometry::covered_by(it->robust_point, robust_polygons[i])) + { + code = 1; + break; + } + } + if (code * factor == 1) + { + it->location = inside_original; + } + } + } + } + + inline bool assert_indices_in_robust_rings() const + { + geometry::equal_to<robust_point_type> comparator; + for (typename boost::range_iterator<turn_vector_type const>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + for (int i = 0; i < 2; i++) + { + robust_point_type const &p1 + = m_pieces[it->operations[i].piece_index].robust_ring + [it->operations[i].index_in_robust_ring]; + robust_point_type const &p2 = it->robust_point; + if (! comparator(p1, p2)) + { + return false; + } + } + } + return true; + } + + inline void insert_rescaled_piece_turns() + { + // Add rescaled turn points to corresponding pieces + // (after this, each turn occurs twice) + int index = 0; + for (typename boost::range_iterator<turn_vector_type>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) + { + geometry::recalculate(it->robust_point, it->point, m_robust_policy); +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + it->mapped_robust_point = it->robust_point; +#endif + + robust_turn turn; + it->turn_index = index; + turn.turn_index = index; + turn.point = it->robust_point; + for (int i = 0; i < 2; i++) + { + turn.operation_index = i; + turn.seg_id = it->operations[i].seg_id; + turn.fraction = it->operations[i].fraction; + + piece& pc = m_pieces[it->operations[i].piece_index]; + pc.robust_turns.push_back(turn); + + // Take into account for the box (intersection points should fall inside, + // but in theory they can be one off because of rounding + geometry::expand(pc.robust_envelope, it->robust_point); + } + } + + // Insert all rescaled turn-points into these rings, to form a + // reliable integer-based ring. All turns can be compared (inside) to this + // rings to see if they are inside. + + for (typename piece_vector_type::iterator it = boost::begin(m_pieces); + it != boost::end(m_pieces); + ++it) + { + piece& pc = *it; + int piece_segment_index = pc.first_seg_id.segment_index; + if (! pc.robust_turns.empty()) + { + if (pc.robust_turns.size() > 1u) + { + std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less()); + } + // Walk through them, in reverse to insert at right index + int index_offset = pc.robust_turns.size() - 1; + for (typename std::vector<robust_turn>::const_reverse_iterator + rit = pc.robust_turns.rbegin(); + rit != pc.robust_turns.rend(); + ++rit, --index_offset) + { + int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index; + BOOST_ASSERT + ( + index_in_vector > 0 && index_in_vector < pc.offsetted_count + ); + + pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point); + pc.offsetted_count++; + + m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset; + } + } + } + + BOOST_ASSERT(assert_indices_in_robust_rings()); + } + + inline void get_turns() + { + { + // Calculate the turns + piece_turn_visitor + < + buffered_ring_collection<buffered_ring<Ring> >, + turn_vector_type, + RobustPolicy + > visitor(offsetted_rings, m_turns, m_robust_policy); + + geometry::partition + < + model::box<robust_point_type>, piece_get_box, piece_ovelaps_box + >::apply(m_pieces, visitor); + } + + insert_rescaled_piece_turns(); + + { + // Check if it is inside any of the pieces + turn_in_piece_visitor + < + turn_vector_type, piece_vector_type + > visitor(m_turns, m_pieces); + + geometry::partition + < + model::box<robust_point_type>, + turn_get_box, turn_ovelaps_box, + piece_get_box, piece_ovelaps_box + >::apply(m_turns, m_pieces, visitor); + + } + + classify_turns(); + + //get_occupation(); + } + + inline void start_new_ring() + { + int const n = offsetted_rings.size(); + current_segment_id.source_index = 0; + current_segment_id.multi_index = n; + current_segment_id.ring_index = -1; + current_segment_id.segment_index = 0; + + offsetted_rings.resize(n + 1); + current_robust_ring.clear(); + + m_first_piece_index = boost::size(m_pieces); + } + + inline void finish_ring(bool is_interior = false) + { + if (m_first_piece_index == -1) + { + return; + } + + if (m_first_piece_index < static_cast<int>(boost::size(m_pieces))) + { + // If piece was added + // Reassign left-of-first and right-of-last + geometry::range::at(m_pieces, m_first_piece_index).left_index + = boost::size(m_pieces) - 1; + geometry::range::back(m_pieces).right_index = m_first_piece_index; + } + m_first_piece_index = -1; + + if (!current_robust_ring.empty()) + { + BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back())); + + if (is_interior) + { + if (!robust_polygons.empty()) + { + robust_polygons.back().inners().push_back(current_robust_ring); + } + } + else + { + robust_polygons.resize(robust_polygons.size() + 1); + robust_polygons.back().outer() = current_robust_ring; + } + } + } + + inline int add_point(point_type const& p) + { + BOOST_ASSERT + ( + boost::size(offsetted_rings) > 0 + ); + + current_segment_id.segment_index++; + offsetted_rings.back().push_back(p); + return offsetted_rings.back().size(); + } + + //------------------------------------------------------------------------- + + inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one) + { + piece pc; + pc.type = type; + pc.index = boost::size(m_pieces); + pc.first_seg_id = current_segment_id; + + // Assign left/right (for first/last piece per ring they will be re-assigned later) + pc.left_index = pc.index - 1; + pc.right_index = pc.index + 1; + + std::size_t const n = boost::size(offsetted_rings.back()); + pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n; + + m_pieces.push_back(pc); + return m_pieces.back(); + } + + inline void init_rescale_piece(piece& pc, std::size_t helper_points_size) + { + pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index; + BOOST_ASSERT(pc.offsetted_count >= 0); + + pc.robust_ring.reserve(pc.offsetted_count + helper_points_size); + + // Add rescaled offsetted segments + { + buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index]; + + typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type; + for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index; + it != boost::begin(ring) + pc.last_segment_index; + ++it) + { + robust_point_type point; + geometry::recalculate(point, *it, m_robust_policy); + pc.robust_ring.push_back(point); + } + } + } + + inline robust_point_type add_helper_point(piece& pc, const point_type& point) + { +#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS) + pc.helper_points.push_back(point); +#endif + + robust_point_type rob_point; + geometry::recalculate(rob_point, point, m_robust_policy); + pc.robust_ring.push_back(rob_point); + return rob_point; + } + + inline void calculate_robust_envelope(piece& pc) + { + geometry::detail::envelope::envelope_range::apply(pc.robust_ring, + pc.robust_envelope); + } + + inline void finish_piece(piece& pc) + { + init_rescale_piece(pc, 0u); + calculate_robust_envelope(pc); + } + + inline void finish_piece(piece& pc, + const point_type& point1, + const point_type& point2, + const point_type& point3) + { + init_rescale_piece(pc, 3u); + add_helper_point(pc, point1); + robust_point_type mid_point = add_helper_point(pc, point2); + add_helper_point(pc, point3); + calculate_robust_envelope(pc); + + current_robust_ring.push_back(mid_point); + } + + inline void finish_piece(piece& pc, + const point_type& point1, + const point_type& point2, + const point_type& point3, + const point_type& point4) + { + init_rescale_piece(pc, 4u); + add_helper_point(pc, point1); + robust_point_type mid_point2 = add_helper_point(pc, point2); + robust_point_type mid_point1 = add_helper_point(pc, point3); + add_helper_point(pc, point4); + calculate_robust_envelope(pc); + + // Add mid-points in other order to current helper_ring + current_robust_ring.push_back(mid_point1); + current_robust_ring.push_back(mid_point2); + } + + inline void add_piece(strategy::buffer::piece_type type, point_type const& p, + point_type const& b1, point_type const& b2) + { + piece& pc = create_piece(type, false); + add_point(b1); + pc.last_segment_index = add_point(b2); + finish_piece(pc, b2, p, b1); + } + + template <typename Range> + inline void add_range_to_piece(piece& pc, Range const& range, bool add_front) + { + if (boost::size(range) == 0u) + { + return; + } + + typename Range::const_iterator it = boost::begin(range); + + // If it follows a non-join (so basically the same piece-type) point b1 should be added. + // There should be two intersections later and it should be discarded. + // But for now we need it to calculate intersections + if (add_front) + { + add_point(*it); + } + + for (++it; it != boost::end(range); ++it) + { + pc.last_segment_index = add_point(*it); + } + } + + + template <typename Range> + inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one) + { + piece& pc = create_piece(type, decrease_segment_index_by_one); + add_range_to_piece(pc, range, offsetted_rings.back().empty()); + finish_piece(pc); + } + + template <typename Range> + inline void add_side_piece(point_type const& p1, point_type const& p2, + Range const& range, bool first) + { + BOOST_ASSERT(boost::size(range) >= 2u); + + piece& pc = create_piece(strategy::buffer::buffered_segment, ! first); + add_range_to_piece(pc, range, first); + finish_piece(pc, range.back(), p2, p1, range.front()); + } + + template <typename Range> + inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range) + { + piece& pc = create_piece(type, true); + + add_range_to_piece(pc, range, offsetted_rings.back().empty()); + if (boost::size(range) > 0) + { + finish_piece(pc, range.back(), p, range.front()); + } + else + { + finish_piece(pc); + } + } + + template <typename EndcapStrategy, typename Range> + inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point) + { + if (range.empty()) + { + return; + } + strategy::buffer::piece_type pt = strategy.get_piece_type(); + if (pt == strategy::buffer::buffered_flat_end) + { + // It is flat, should just be added, without helper segments + add_piece(pt, range, true); + } + else + { + // Normal case, it has an "inside", helper segments should be added + add_piece(pt, end_point, range); + } + } + + //------------------------------------------------------------------------- + + inline void enrich() + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Ring>::type + >::type side_strategy_type; + + enrich_intersection_points<false, false>(m_turns, + detail::overlay::operation_union, + offsetted_rings, offsetted_rings, + m_robust_policy, side_strategy_type()); + } + + // Discards all rings which do have not-OK intersection points only. + // Those can never be traversed and should not be part of the output. + inline void discard_rings() + { + for (typename boost::range_iterator<turn_vector_type const>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + if (it->location != location_ok) + { + offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true; + offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true; + } + else if (! it->both(detail::overlay::operation_union)) + { + offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true; + offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true; + } + } + } + + inline void block_turns() + { + // To fix left-turn issues like #rt_u13 + // But currently it causes more other issues than it fixes +// m_turns.erase +// ( +// std::remove_if(boost::begin(m_turns), boost::end(m_turns), +// redundant_turn()), +// boost::end(m_turns) +// ); + + for (typename boost::range_iterator<turn_vector_type>::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + if (it->location != location_ok) + { + // Set it to blocked. They should not be discarded, to avoid + // generating rings over these turns + // Performance goes down a tiny bit from 161 s to 173 because there + // are sometimes much more turns. + // We might speed it up a bit by keeping only one blocked + // intersection per segment, but that is complex to program + // because each turn involves two segments + it->operations[0].operation = detail::overlay::operation_blocked; + it->operations[1].operation = detail::overlay::operation_blocked; + } + } + } + + inline void traverse() + { + typedef detail::overlay::traverse + < + false, false, + buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >, + backtrack_for_buffer + > traverser; + + traversed_rings.clear(); + traverser::apply(offsetted_rings, offsetted_rings, + detail::overlay::operation_union, + m_robust_policy, m_turns, traversed_rings); + } + + inline void reverse() + { + for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings); + it != boost::end(offsetted_rings); + ++it) + { + if (! it->has_intersections()) + { + std::reverse(it->begin(), it->end()); + } + } + for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type + it = boost::begin(traversed_rings); + it != boost::end(traversed_rings); + ++it) + { + std::reverse(it->begin(), it->end()); + } + + } + + template <typename GeometryOutput, typename OutputIterator> + inline OutputIterator assign(OutputIterator out) const + { + typedef detail::overlay::ring_properties<point_type> properties; + + std::map<ring_identifier, properties> selected; + + // Select all rings which do not have any self-intersection (other ones should be traversed) + int index = 0; + for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings); + it != boost::end(offsetted_rings); + ++it, ++index) + { + if (! it->has_intersections()) + { + ring_identifier id(0, index, -1); + selected[id] = properties(*it, true); + } + } + + // Select all created rings + index = 0; + for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type + it = boost::begin(traversed_rings); + it != boost::end(traversed_rings); + ++it, ++index) + { + ring_identifier id(2, index, -1); + selected[id] = properties(*it, true); + } + + detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true); + return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out); + } + +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp new file mode 100644 index 0000000000..03ec598c90 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp @@ -0,0 +1,238 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_BUFFERED_RING +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> +#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + +#include <boost/geometry/multi/algorithms/within.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +struct buffered_ring_collection_tag : polygonal_tag, multi_tag +{}; + + +template <typename Ring> +struct buffered_ring : public Ring +{ + bool has_accepted_intersections; + bool has_discarded_intersections; + + inline buffered_ring() + : has_accepted_intersections(false) + , has_discarded_intersections(false) + {} + + inline bool discarded() const + { + return has_discarded_intersections && ! has_accepted_intersections; + } + inline bool has_intersections() const + { + return has_discarded_intersections || has_accepted_intersections; + } +}; + +// This is a collection now special for overlay (needs vector of rings) +template <typename Ring> +struct buffered_ring_collection : public std::vector<Ring> +{ +}; + +}} // namespace detail::buffer + + +// Turn off concept checking (for now) +namespace dispatch +{ +template <typename Geometry, bool IsConst> +struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst> +{ +}; + +} + + +#endif // DOXYGEN_NO_DETAIL + + + +// Register the types +namespace traits +{ + + +template <typename Ring> +struct tag<detail::buffer::buffered_ring<Ring> > +{ + typedef ring_tag type; +}; + + +template <typename Ring> +struct point_order<detail::buffer::buffered_ring<Ring> > +{ + static const order_selector value = geometry::point_order<Ring>::value; +}; + + +template <typename Ring> +struct closure<detail::buffer::buffered_ring<Ring> > +{ + static const closure_selector value = geometry::closure<Ring>::value; +}; + + +template <typename Ring> +struct point_type<detail::buffer::buffered_ring_collection<Ring> > +{ + typedef typename geometry::point_type<Ring>::type type; +}; + +template <typename Ring> +struct tag<detail::buffer::buffered_ring_collection<Ring> > +{ + typedef detail::buffer::buffered_ring_collection_tag type; +}; + + +} // namespace traits + + + + +namespace core_dispatch +{ + +template <typename Ring> +struct ring_type +< + detail::buffer::buffered_ring_collection_tag, + detail::buffer::buffered_ring_collection<Ring> +> +{ + typedef Ring type; +}; + +} + +namespace dispatch +{ + +template +< + typename MultiRing, + bool Reverse, + typename SegmentIdentifier, + typename PointOut +> +struct copy_segment_point + < + detail::buffer::buffered_ring_collection_tag, + MultiRing, + Reverse, + SegmentIdentifier, + PointOut + > + : detail::copy_segments::copy_segment_point_multi + < + MultiRing, + SegmentIdentifier, + PointOut, + detail::copy_segments::copy_segment_point_range + < + typename boost::range_value<MultiRing>::type, + Reverse, + SegmentIdentifier, + PointOut + > + > +{}; + + +template<bool Reverse> +struct copy_segments + < + detail::buffer::buffered_ring_collection_tag, + Reverse + > + : detail::copy_segments::copy_segments_multi + < + detail::copy_segments::copy_segments_ring<Reverse> + > +{}; + +template <typename Point, typename MultiGeometry> +struct within +< + Point, + MultiGeometry, + point_tag, + detail::buffer::buffered_ring_collection_tag +> +{ + template <typename Strategy> + static inline bool apply(Point const& point, + MultiGeometry const& multi, Strategy const& strategy) + { + return detail::within::point_in_geometry(point, multi, strategy) == 1; + } +}; + + +} // namespace dispatch + +namespace detail { namespace overlay +{ + +template<> +struct get_ring<detail::buffer::buffered_ring_collection_tag> +{ + template<typename MultiGeometry> + static inline typename ring_type<MultiGeometry>::type const& apply( + ring_identifier const& id, + MultiGeometry const& multi_ring) + { + BOOST_ASSERT + ( + id.multi_index >= 0 + && id.multi_index < int(boost::size(multi_ring)) + ); + return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]); + } +}; + +}} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp new file mode 100644 index 0000000000..395921ccaa --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -0,0 +1,191 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_GET_PIECE_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> +#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +struct piece_get_box +{ + template <typename Box, typename Piece> + static inline void apply(Box& total, Piece const& piece) + { + geometry::expand(total, piece.robust_envelope); + } +}; + +struct piece_ovelaps_box +{ + template <typename Box, typename Piece> + static inline bool apply(Box const& box, Piece const& piece) + { + return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope); + } +}; + +template +< + typename Rings, + typename Turns, + typename RobustPolicy +> +class piece_turn_visitor +{ + Rings const& m_rings; + Turns& m_turns; + RobustPolicy const& m_robust_policy; + + template <typename Piece> + inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const + { + if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index) + { + return false; + } + + return piece1.index == piece2.left_index + || piece1.index == piece2.right_index; + } + + template <typename Range, typename Iterator> + inline void move_to_next_point(Range const& range, Iterator& next) const + { + ++next; + if (next == boost::end(range)) + { + next = boost::begin(range) + 1; + } + } + + template <typename Range, typename Iterator> + inline Iterator next_point(Range const& range, Iterator it) const + { + Iterator result = it; + move_to_next_point(range, result); + // TODO: we could use either piece-boundaries, or comparison with + // robust points, to check if the point equals the last one + while(geometry::equals(*it, *result)) + { + move_to_next_point(range, result); + } + return result; + } + + template <typename Piece> + inline void calculate_turns(Piece const& piece1, Piece const& piece2) + { + typedef typename boost::range_value<Rings const>::type ring_type; + typedef typename boost::range_value<Turns const>::type turn_type; + typedef typename boost::range_iterator<ring_type const>::type iterator; + + segment_identifier seg_id1 = piece1.first_seg_id; + segment_identifier seg_id2 = piece2.first_seg_id; + + if (seg_id1.segment_index < 0 || seg_id2.segment_index < 0) + { + return; + } + + ring_type const& ring1 = m_rings[seg_id1.multi_index]; + iterator it1_first = boost::begin(ring1) + seg_id1.segment_index; + iterator it1_last = boost::begin(ring1) + piece1.last_segment_index; + + ring_type const& ring2 = m_rings[seg_id2.multi_index]; + iterator it2_first = boost::begin(ring2) + seg_id2.segment_index; + iterator it2_last = boost::begin(ring2) + piece2.last_segment_index; + + turn_type the_model; + the_model.operations[0].piece_index = piece1.index; + the_model.operations[0].seg_id = piece1.first_seg_id; + + iterator it1 = it1_first; + for (iterator prev1 = it1++; + it1 != it1_last; + prev1 = it1++, the_model.operations[0].seg_id.segment_index++) + { + the_model.operations[1].piece_index = piece2.index; + the_model.operations[1].seg_id = piece2.first_seg_id; + + iterator next1 = next_point(ring1, it1); + + iterator it2 = it2_first; + for (iterator prev2 = it2++; + it2 != it2_last; + prev2 = it2++, the_model.operations[1].seg_id.segment_index++) + { + iterator next2 = next_point(ring2, it2); + + // TODO: internally get_turn_info calculates robust points. + // But they are already calculated. + // We should be able to use them. + // this means passing them to this visitor, + // and iterating in sync with them... + typedef detail::overlay::get_turn_info + < + detail::overlay::assign_null_policy + > turn_policy; + + turn_policy::apply(*prev1, *it1, *next1, + *prev2, *it2, *next2, + false, false, false, false, + the_model, m_robust_policy, + std::back_inserter(m_turns)); + } + } + } + +public: + + piece_turn_visitor(Rings const& ring_collection, + Turns& turns, + RobustPolicy const& robust_policy) + : m_rings(ring_collection) + , m_turns(turns) + , m_robust_policy(robust_policy) + {} + + template <typename Piece> + inline void apply(Piece const& piece1, Piece const& piece2, + bool first = true) + { + boost::ignore_unused_variable_warning(first); + if ( is_adjacent(piece1, piece2) + || detail::disjoint::disjoint_box_box(piece1.robust_envelope, + piece2.robust_envelope)) + { + return; + } + calculate_turns(piece1, piece2); + } +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp new file mode 100644 index 0000000000..618afe5fba --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_LINE_LINE_INTERSECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP + + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +// TODO: once change this to proper strategy +// It is different from current segment intersection because these are not segments but lines +// If we have the Line concept, we can create a strategy +// Assumes a convex corner +struct line_line_intersection +{ + + template <typename Point> + static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj, + Point const& qi, Point const& qj, Point& ip) + { + // See http://mathworld.wolfram.com/Line-LineIntersection.html + typedef typename coordinate_type<Point>::type coordinate_type; + + coordinate_type const denominator + = determinant<coordinate_type>(get<0>(pi) - get<0>(pj), + get<1>(pi) - get<1>(pj), + get<0>(qi) - get<0>(qj), + get<1>(qi) - get<1>(qj)); + + // Even if the corner was checked before (so it is convex now), that + // was done on the original geometry. This function runs on the buffered + // geometries, where sides are generated and might be slightly off. In + // Floating Point, that slightly might just exceed the limit and we have + // to check it again. + + // For round joins, it will not be used at all. + // For miter joints, there is a miter limit + // If segments are parallel/collinear we must be distinguish two cases: + // they continue each other, or they form a spike + if (math::equals(denominator, coordinate_type())) + { + return parallel_continue(get<0>(qj) - get<0>(qi), + get<1>(qj) - get<1>(qi), + get<0>(pj) - get<0>(pi), + get<1>(pj) - get<1>(pi)) + ? strategy::buffer::join_continue + : strategy::buffer::join_spike + ; + } + + coordinate_type d1 = determinant<coordinate_type>(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj)); + coordinate_type d2 = determinant<coordinate_type>(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj)); + + double const multiplier = 1.0 / denominator; + + set<0>(ip, determinant<coordinate_type>(d1, get<0>(pi) - get<0>(pj), d2, get<0>(qi) - get<0>(qj)) * multiplier); + set<1>(ip, determinant<coordinate_type>(d1, get<1>(pi) - get<1>(pj), d2, get<1>(qi) - get<1>(qj)) * multiplier); + + return strategy::buffer::join_convex; + } +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP diff --git a/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp new file mode 100644 index 0000000000..119d64de74 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp @@ -0,0 +1,33 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_PARALLEL_CONTINUE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template <typename T> +inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2) +{ + T const dot = dx1 * dx2 + dy1 * dy2; + return dot > 0; +} + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp new file mode 100644 index 0000000000..2b1c33d291 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp @@ -0,0 +1,98 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_TURN_IN_INPUT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/algorithms/covered_by.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +// Checks if an turn/intersection point is inside (or covered by) the input geometry + +template <typename Tag> +struct turn_in_input +{ +}; + +template <> +struct turn_in_input<polygon_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& point, Geometry const& geometry) + { + return geometry::covered_by(point, geometry) ? 1 : -1; + } +}; + +template <> +struct turn_in_input<linestring_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& , Geometry const& ) + { + return 0; + } +}; + +template <> +struct turn_in_input<point_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& , Geometry const& ) + { + return 0; + } +}; + +template <> +struct turn_in_input<multi_polygon_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& point, Geometry const& geometry) + { + return geometry::covered_by(point, geometry) ? 1 : -1; + } +}; + +template <> +struct turn_in_input<multi_linestring_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& , Geometry const& ) + { + return 0; + } +}; + +template <> +struct turn_in_input<multi_point_tag> +{ + template <typename Point, typename Geometry> + static inline int apply(Point const& , Geometry const& ) + { + return 0; + } +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp new file mode 100644 index 0000000000..c02f56de3f --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -0,0 +1,246 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BUFFER_TURN_IN_PIECE_VISITOR +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR + +#include <boost/range.hpp> + +#include <boost/geometry/arithmetic/dot_product.hpp> +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> +#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/strategies/buffer.hpp> + +#include <boost/geometry/geometries/linestring.hpp> +#include <boost/geometry/algorithms/comparable_distance.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +struct turn_get_box +{ + template <typename Box, typename Turn> + static inline void apply(Box& total, Turn const& turn) + { + geometry::expand(total, turn.robust_point); + } +}; + +struct turn_ovelaps_box +{ + template <typename Box, typename Turn> + static inline bool apply(Box const& box, Turn const& turn) + { + return ! dispatch::disjoint + < + typename Turn::robust_point_type, + Box + >::apply(turn.robust_point, box); + } +}; + +template <typename Turns, typename Pieces> +class turn_in_piece_visitor +{ + Turns& m_turns; // because partition is currently operating on const input only + Pieces const& m_pieces; // to check for piece-type + + typedef boost::long_long_type calculation_type; + + template <typename Point> + static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) + { + typedef Point vector_type; + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + vector_type v = q; + vector_type w = subject; + subtract_point(v, p); + subtract_point(w, p); + + coordinate_type const zero = coordinate_type(); + coordinate_type const c1 = dot_product(w, v); + + if (c1 < zero) + { + return false; + } + coordinate_type const c2 = dot_product(v, v); + if (c2 < c1) + { + return false; + } + + return true; + } + + template <typename Point, typename Piece> + inline bool on_offsetted(Point const& point, Piece const& piece) const + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type side_strategy; + geometry::equal_to<Point> comparator; + + for (int i = 1; i < piece.offsetted_count; i++) + { + Point const& previous = piece.robust_ring[i - 1]; + Point const& current = piece.robust_ring[i]; + + // The robust ring contains duplicates, avoid applying side on them (will be 0) + if (! comparator(previous, current)) + { + int const side = side_strategy::apply(previous, current, point); + if (side == 0) + { + // Collinear, check if projection falls on it + if (projection_on_segment(point, previous, current)) + { + return true; + } + } + } + } + return false; + } + + template <typename Point, typename Piece> + static inline + calculation_type comparable_distance_from_offsetted(Point const& point, + Piece const& piece) + { + // TODO: pass subrange to dispatch to avoid making copy + geometry::model::linestring<Point> ls; + std::copy(piece.robust_ring.begin(), + piece.robust_ring.begin() + piece.offsetted_count, + std::back_inserter(ls)); + typename default_comparable_distance_result<Point, Point>::type + const comp = geometry::comparable_distance(point, ls); + + return static_cast<calculation_type>(comp); + } + +public: + + inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces) + : m_turns(turns) + , m_pieces(pieces) + {} + + template <typename Turn, typename Piece> + inline void apply(Turn const& turn, Piece const& piece, bool first = true) + { + boost::ignore_unused_variable_warning(first); + + if (turn.count_within > 0) + { + // Already inside - no need to check again + return; + } + + if (piece.type == strategy::buffer::buffered_flat_end + || piece.type == strategy::buffer::buffered_concave) + { + // Turns cannot be inside a flat end (though they can be on border) + // Neither we need to check if they are inside concave helper pieces + return; + } + + bool neighbour = false; + for (int i = 0; i < 2; i++) + { + // Don't compare against one of the two source-pieces + if (turn.operations[i].piece_index == piece.index) + { + return; + } + + typename boost::range_value<Pieces>::type const& pc + = m_pieces[turn.operations[i].piece_index]; + if (pc.left_index == piece.index + || pc.right_index == piece.index) + { + if (pc.type == strategy::buffer::buffered_flat_end) + { + // If it is a flat end, don't compare against its neighbor: + // it will always be located on one of the helper segments + return; + } + neighbour = true; + } + } + + int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring); + + if (geometry_code == -1) + { + return; + } + if (geometry_code == 0 && neighbour) + { + return; + } + + Turn& mutable_turn = m_turns[turn.turn_index]; + if (geometry_code == 0) + { + // If it is on the border and they are not neighbours, it should be + // on the offsetted ring + + if (! on_offsetted(turn.robust_point, piece)) + { + // It is on the border but not on the offsetted ring. + // Then it is somewhere on the helper-segments + // Classify it as "within" + geometry_code = 1; + mutable_turn.count_on_helper++; // can still become "near_offsetted" + } + else + { + mutable_turn.count_on_offsetted++; // value is not used anymore + } + } + + if (geometry_code == 1) + { + calculation_type const distance + = comparable_distance_from_offsetted(turn.robust_point, piece); + if (distance >= 4) + { + // This is too far from the border, it counts as "really within" + mutable_turn.count_within++; + } + else + { + // Other points count as still "on border" because they might be + // travelled through, but not used as starting point + mutable_turn.count_within_near_offsetted++; + } + } + } +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR diff --git a/boost/geometry/algorithms/detail/calculate_null.hpp b/boost/geometry/algorithms/detail/calculate_null.hpp index 4b48d62fc2..3ebca83506 100644 --- a/boost/geometry/algorithms/detail/calculate_null.hpp +++ b/boost/geometry/algorithms/detail/calculate_null.hpp @@ -21,9 +21,9 @@ namespace boost { namespace geometry namespace detail { -template<typename ReturnType, typename Geometry, typename Strategy> struct calculate_null { + template<typename ReturnType, typename Geometry, typename Strategy> static inline ReturnType apply(Geometry const& , Strategy const&) { return ReturnType(); diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp index 2ad349080b..b23e70171b 100644 --- a/boost/geometry/algorithms/detail/calculate_sum.hpp +++ b/boost/geometry/algorithms/detail/calculate_sum.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,9 +15,7 @@ #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 { @@ -26,20 +25,14 @@ namespace detail { -template -< - typename ReturnType, - typename Polygon, - typename Strategy, - typename Policy -> class calculate_polygon_sum { - template <typename Rings> + 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) + for (typename boost::range_iterator<Rings const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { sum += Policy::apply(*it, strategy); } @@ -47,10 +40,11 @@ class calculate_polygon_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(interior_rings(poly), strategy) + + sum_interior_rings<ReturnType, Policy>(interior_rings(poly), strategy) ; } }; diff --git a/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp new file mode 100644 index 0000000000..56a7e3ec91 --- /dev/null +++ b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_CENTROID_TRANSLATING_TRANSFORMER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP + + +#include <cstddef> + +#include <boost/core/addressof.hpp> +#include <boost/core/ref.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/arithmetic/arithmetic.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace centroid +{ + + +// NOTE: There is no need to translate in other coordinate systems than +// cartesian. But if it was needed then one should translate using +// CS-specific technique, e.g. in spherical/geographic a translation +// vector should contain coordinates being multiplies of 2PI or 360 deg. +template <typename Geometry, + typename CastedTag = typename tag_cast + < + typename tag<Geometry>::type, + areal_tag + >::type, + typename CSTag = typename cs_tag<Geometry>::type> +struct translating_transformer +{ + typedef typename geometry::point_type<Geometry>::type point_type; + typedef boost::reference_wrapper<point_type const> result_type; + + explicit translating_transformer(Geometry const&) {} + explicit translating_transformer(point_type const&) {} + + result_type apply(point_type const& pt) const + { + return result_type(pt); + } + + template <typename ResPt> + void apply_reverse(ResPt &) const {} +}; + +// Specialization for Areal Geometries in cartesian CS +template <typename Geometry> +struct translating_transformer<Geometry, areal_tag, cartesian_tag> +{ + typedef typename geometry::point_type<Geometry>::type point_type; + typedef point_type result_type; + + explicit translating_transformer(Geometry const& geom) + : m_origin(NULL) + { + geometry::point_iterator<Geometry const> + pt_it = geometry::points_begin(geom); + if ( pt_it != geometry::points_end(geom) ) + { + m_origin = boost::addressof(*pt_it); + } + } + + explicit translating_transformer(point_type const& origin) + : m_origin(boost::addressof(origin)) + {} + + result_type apply(point_type const& pt) const + { + point_type res = pt; + if ( m_origin ) + geometry::subtract_point(res, *m_origin); + return res; + } + + template <typename ResPt> + void apply_reverse(ResPt & res_pt) const + { + if ( m_origin ) + geometry::add_point(res_pt, *m_origin); + } + + const point_type * m_origin; +}; + + +}} // namespace detail::centroid +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP diff --git a/boost/geometry/algorithms/detail/check_iterator_range.hpp b/boost/geometry/algorithms/detail/check_iterator_range.hpp new file mode 100644 index 0000000000..09ea7f79a0 --- /dev/null +++ b/boost/geometry/algorithms/detail/check_iterator_range.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP + +#include <boost/core/ignore_unused.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Check whether (each element of) an iterator range satisfies a given +// predicate. +// The predicate must be implemented as having a static apply unary +// method that returns a bool. +// By default an empty range is accepted +template <typename Predicate, bool AllowEmptyRange = true> +struct check_iterator_range +{ + template <typename InputIterator> + static inline bool apply(InputIterator first, InputIterator beyond) + { + for (InputIterator it = first; it != beyond; ++it) + { + if ( !Predicate::apply(*it) ) + { + return false; + } + } + return AllowEmptyRange || first != beyond; + } + + + // version where we can pass a predicate object + template <typename InputIterator> + static inline bool apply(InputIterator first, + InputIterator beyond, + Predicate const& predicate) + { + // in case predicate's apply method is static, MSVC will + // complain that predicate is not used + boost::ignore_unused(predicate); + + for (InputIterator it = first; it != beyond; ++it) + { + if ( !predicate.apply(*it) ) + { + return false; + } + } + return AllowEmptyRange || first != beyond; + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp new file mode 100644 index 0000000000..c7558b4ff1 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp @@ -0,0 +1,147 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP + +#include <iterator> + +#include <boost/assert.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_feature +{ + + + +// returns the range iterator the realizes the closest +// distance between the geometry and the element of the range +class geometry_to_range +{ +private: + template + < + typename Geometry, + typename RangeIterator, + typename Strategy, + typename Distance + > + static inline void apply(Geometry const& geometry, + RangeIterator first, + RangeIterator last, + Strategy const& strategy, + RangeIterator& it_min, + Distance& dist_min) + { + BOOST_ASSERT( first != last ); + + Distance const zero = Distance(0); + + // start with first distance + it_min = first; + dist_min = dispatch::distance + < + Geometry, + typename std::iterator_traits<RangeIterator>::value_type, + Strategy + >::apply(geometry, *it_min, strategy); + + // check if other elements in the range are closer + RangeIterator it = first; + for (++it; it != last; ++it) + { + Distance dist = dispatch::distance + < + Geometry, + typename std::iterator_traits<RangeIterator>::value_type, + Strategy + >::apply(geometry, *it, strategy); + + if (geometry::math::equals(dist, zero)) + { + dist_min = dist; + it_min = it; + return; + } + else if (dist < dist_min) + { + dist_min = dist; + it_min = it; + } + } + } + +public: + template + < + typename Geometry, + typename RangeIterator, + typename Strategy, + typename Distance + > + static inline RangeIterator apply(Geometry const& geometry, + RangeIterator first, + RangeIterator last, + Strategy const& strategy, + Distance& dist_min) + { + RangeIterator it_min; + apply(geometry, first, last, strategy, it_min, dist_min); + + return it_min; + } + + + template + < + typename Geometry, + typename RangeIterator, + typename Strategy + > + static inline RangeIterator apply(Geometry const& geometry, + RangeIterator first, + RangeIterator last, + Strategy const& strategy) + { + typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Geometry>::type, + typename point_type + < + typename std::iterator_traits + < + RangeIterator + >::value_type + >::type + >::type dist_min; + + return apply(geometry, first, last, strategy, dist_min); + } +}; + + + +}} // namespace detail::closest_feature +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp new file mode 100644 index 0000000000..91be6b0ad0 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp @@ -0,0 +1,250 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP + +#include <utility> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_feature +{ + + +// returns the segment (pair of iterators) that realizes the closest +// distance of the point to the range +template +< + typename Point, + typename Range, + closure_selector Closure, + typename Strategy +> +class point_to_point_range +{ +protected: + typedef typename boost::range_iterator<Range const>::type iterator_type; + + template <typename Distance> + static inline void apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy, + iterator_type& it_min1, + iterator_type& it_min2, + Distance& dist_min) + { + BOOST_ASSERT( first != last ); + + Distance const zero = Distance(0); + + iterator_type it = first; + iterator_type prev = it++; + if (it == last) + { + it_min1 = it_min2 = first; + dist_min = strategy.apply(point, *first, *first); + return; + } + + // start with first segment distance + dist_min = strategy.apply(point, *prev, *it); + iterator_type prev_min_dist = prev; + + // check if other segments are closer + for (++prev, ++it; it != last; ++prev, ++it) + { + Distance dist = strategy.apply(point, *prev, *it); + if (geometry::math::equals(dist, zero)) + { + dist_min = zero; + it_min1 = prev; + it_min2 = it; + return; + } + else if (dist < dist_min) + { + dist_min = dist; + prev_min_dist = prev; + } + } + + it_min1 = it_min2 = prev_min_dist; + ++it_min2; + } + +public: + typedef typename std::pair<iterator_type, iterator_type> return_type; + + template <typename Distance> + static inline return_type apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy, + Distance& dist_min) + { + iterator_type it_min1, it_min2; + apply(point, first, last, strategy, it_min1, it_min2, dist_min); + + return std::make_pair(it_min1, it_min2); + } + + static inline return_type apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy) + { + typename strategy::distance::services::return_type + < + Strategy, + Point, + typename boost::range_value<Range>::type + >::type dist_min; + + return apply(point, first, last, strategy, dist_min); + } + + template <typename Distance> + static inline return_type apply(Point const& point, + Range const& range, + Strategy const& strategy, + Distance& dist_min) + { + return apply(point, + boost::begin(range), + boost::end(range), + strategy, + dist_min); + } + + static inline return_type apply(Point const& point, + Range const& range, + Strategy const& strategy) + { + return apply(point, boost::begin(range), boost::end(range), strategy); + } +}; + + + +// specialization for open ranges +template <typename Point, typename Range, typename Strategy> +class point_to_point_range<Point, Range, open, Strategy> + : point_to_point_range<Point, Range, closed, Strategy> +{ +private: + typedef point_to_point_range<Point, Range, closed, Strategy> base_type; + typedef typename base_type::iterator_type iterator_type; + + template <typename Distance> + static inline void apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy, + iterator_type& it_min1, + iterator_type& it_min2, + Distance& dist_min) + { + BOOST_ASSERT( first != last ); + + base_type::apply(point, first, last, strategy, + it_min1, it_min2, dist_min); + + iterator_type it_back = --last; + Distance const zero = Distance(0); + Distance dist = strategy.apply(point, *it_back, *first); + + if (geometry::math::equals(dist, zero)) + { + dist_min = zero; + it_min1 = it_back; + it_min2 = first; + } + else if (dist < dist_min) + { + dist_min = dist; + it_min1 = it_back; + it_min2 = first; + } + } + +public: + typedef typename std::pair<iterator_type, iterator_type> return_type; + + template <typename Distance> + static inline return_type apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy, + Distance& dist_min) + { + iterator_type it_min1, it_min2; + + apply(point, first, last, strategy, it_min1, it_min2, dist_min); + + return std::make_pair(it_min1, it_min2); + } + + static inline return_type apply(Point const& point, + iterator_type first, + iterator_type last, + Strategy const& strategy) + { + typedef typename strategy::distance::services::return_type + < + Strategy, + Point, + typename boost::range_value<Range>::type + >::type distance_return_type; + + distance_return_type dist_min; + + return apply(point, first, last, strategy, dist_min); + } + + template <typename Distance> + static inline return_type apply(Point const& point, + Range const& range, + Strategy const& strategy, + Distance& dist_min) + { + return apply(point, + boost::begin(range), + boost::end(range), + strategy, + dist_min); + } + + static inline return_type apply(Point const& point, + Range const& range, + Strategy const& strategy) + { + return apply(point, boost::begin(range), boost::end(range), strategy); + } +}; + + +}} // namespace detail::closest_feature +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp new file mode 100644 index 0000000000..90248767ec --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp @@ -0,0 +1,196 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP + +#include <cstddef> + +#include <iterator> +#include <utility> + +#include <boost/assert.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/algorithms/dispatch/distance.hpp> +#include <boost/geometry/index/rtree.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_feature +{ + + +// returns a pair of a objects where the first is an object of the +// r-tree range and the second an object of the query range that +// realizes the closest feature of the two ranges +class range_to_range_rtree +{ +private: + template + < + typename RTreeRangeIterator, + typename QueryRangeIterator, + typename Strategy, + typename RTreeValueType, + typename Distance + > + static inline void apply(RTreeRangeIterator rtree_first, + RTreeRangeIterator rtree_last, + QueryRangeIterator queries_first, + QueryRangeIterator queries_last, + Strategy const& strategy, + RTreeValueType& rtree_min, + QueryRangeIterator& qit_min, + Distance& dist_min) + { + typedef index::rtree<RTreeValueType, index::linear<8> > rtree_type; + + BOOST_ASSERT( rtree_first != rtree_last ); + BOOST_ASSERT( queries_first != queries_last ); + + Distance const zero = Distance(0); + + // create -- packing algorithm + rtree_type rt(rtree_first, rtree_last); + + RTreeValueType t_v; + bool first = true; + + for (QueryRangeIterator qit = queries_first; + qit != queries_last; ++qit, first = false) + { + std::size_t n = rt.query(index::nearest(*qit, 1), &t_v); + + BOOST_ASSERT( n > 0 ); + // n above is unused outside BOOST_ASSERT, hence the call + // to boost::ignore_unused below + // + // however, t_v (initialized by the call to rt.query(...)) + // is used below, which is why we cannot put the call to + // rt.query(...) inside BOOST_ASSERT + boost::ignore_unused(n); + + Distance dist = dispatch::distance + < + RTreeValueType, + typename std::iterator_traits + < + QueryRangeIterator + >::value_type, + Strategy + >::apply(t_v, *qit, strategy); + + if (first || dist < dist_min) + { + dist_min = dist; + rtree_min = t_v; + qit_min = qit; + if ( math::equals(dist_min, zero) ) + { + return; + } + } + } + } + +public: + template <typename RTreeRangeIterator, typename QueryRangeIterator> + struct return_type + { + typedef std::pair + < + typename std::iterator_traits<RTreeRangeIterator>::value_type, + QueryRangeIterator + > type; + }; + + + template + < + typename RTreeRangeIterator, + typename QueryRangeIterator, + typename Strategy, + typename Distance + > + static inline typename return_type + < + RTreeRangeIterator, QueryRangeIterator + >::type apply(RTreeRangeIterator rtree_first, + RTreeRangeIterator rtree_last, + QueryRangeIterator queries_first, + QueryRangeIterator queries_last, + Strategy const& strategy, + Distance& dist_min) + { + typedef typename std::iterator_traits + < + RTreeRangeIterator + >::value_type rtree_value_type; + + rtree_value_type rtree_min; + QueryRangeIterator qit_min; + + apply(rtree_first, rtree_last, queries_first, queries_last, + strategy, rtree_min, qit_min, dist_min); + + return std::make_pair(rtree_min, qit_min); + } + + + template + < + typename RTreeRangeIterator, + typename QueryRangeIterator, + typename Strategy + > + static inline typename return_type + < + RTreeRangeIterator, QueryRangeIterator + >::type apply(RTreeRangeIterator rtree_first, + RTreeRangeIterator rtree_last, + QueryRangeIterator queries_first, + QueryRangeIterator queries_last, + Strategy const& strategy) + { + typedef typename std::iterator_traits + < + RTreeRangeIterator + >::value_type rtree_value_type; + + typename strategy::distance::services::return_type + < + Strategy, + typename point_type<rtree_value_type>::type, + typename point_type + < + typename std::iterator_traits + < + QueryRangeIterator + >::value_type + >::type + >::type dist_min; + + return apply(rtree_first, rtree_last, queries_first, queries_last, + strategy, dist_min); + } +}; + + +}} // namespace detail::closest_feature +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp new file mode 100644 index 0000000000..b6eb7a27f1 --- /dev/null +++ b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp @@ -0,0 +1,24 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP + +#include <boost/geometry/algorithms/detail/distance/implementation.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp new file mode 100644 index 0000000000..1a57c8f4b3 --- /dev/null +++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp @@ -0,0 +1,363 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_COMPARABLE_DISTANCE_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/strategies/comparable_distance_result.hpp> +#include <boost/geometry/strategies/default_comparable_distance_result.hpp> +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/algorithms/detail/distance/interface.hpp> + + +namespace boost { namespace geometry +{ + + +namespace resolve_strategy +{ + +struct comparable_distance +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline + typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy_type; + + return dispatch::distance + < + Geometry1, Geometry2, comparable_strategy_type + >::apply(geometry1, + geometry2, + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy)); + } + + template <typename Geometry1, typename Geometry2> + static inline typename comparable_distance_result + < + Geometry1, Geometry2, default_strategy + >::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename strategy::distance::services::comparable_type + < + typename detail::distance::default_strategy + < + Geometry1, Geometry2 + >::type + >::type comparable_strategy_type; + + return dispatch::distance + < + Geometry1, Geometry2, comparable_strategy_type + >::apply(geometry1, geometry2, comparable_strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant +{ + + +template <typename Geometry1, typename Geometry2> +struct comparable_distance +{ + template <typename Strategy> + static inline + typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return resolve_strategy::comparable_distance::apply(geometry1, + geometry2, + strategy); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct comparable_distance + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2 + > +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + >::type + > + { + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, + Strategy const& strategy) + : m_geometry2(geometry2), + m_strategy(strategy) + {} + + template <typename Geometry1> + typename comparable_distance_result + < + Geometry1, Geometry2, Strategy + >::type + operator()(Geometry1 const& geometry1) const + { + return comparable_distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(geometry1, m_geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + >::type + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct comparable_distance + < + Geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> + > +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename comparable_distance_result + < + Geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + >::type + > + { + Geometry1 const& m_geometry1; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, + Strategy const& strategy) + : m_geometry1(geometry1), + m_strategy(strategy) + {} + + template <typename Geometry2> + typename comparable_distance_result + < + Geometry1, Geometry2, Strategy + >::type + operator()(Geometry2 const& geometry2) const + { + return comparable_distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(m_geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename comparable_distance_result + < + Geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + >::type + apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + } +}; + + +template +< + BOOST_VARIANT_ENUM_PARAMS(typename A), + BOOST_VARIANT_ENUM_PARAMS(typename B) +> +struct comparable_distance + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> + > +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + Strategy + >::type + > + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + + template <typename Geometry1, typename Geometry2> + typename comparable_distance_result + < + Geometry1, Geometry2, Strategy + >::type + operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const + { + return comparable_distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + Strategy + >::type + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + + +/*! +\brief \brief_calc2{comparable distance measurement} \brief_strategy +\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 +\tparam Strategy \tparam_strategy{Distance} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{distance} +\return \return_calc{comparable distance} + +\qbk{distinguish,with strategy} + */ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type +comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) +{ + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + return resolve_variant::comparable_distance + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); +} + + + +/*! +\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_comparable_distance_result<Geometry1, Geometry2>::type +comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + return comparable_distance(geometry1, geometry2, default_strategy()); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp index d39824a61d..fccdf4bb1d 100644 --- a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp +++ b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp @@ -33,9 +33,9 @@ namespace detail { namespace conversion template < - typename Source, - typename Destination, - std::size_t Dimension, + typename Source, + typename Destination, + std::size_t Dimension, std::size_t DimensionCount > struct indexed_to_indexed @@ -44,25 +44,25 @@ struct indexed_to_indexed { typedef typename coordinate_type<Destination>::type coordinate_type; - geometry::set<min_corner, Dimension>(destination, + geometry::set<min_corner, Dimension>(destination, boost::numeric_cast<coordinate_type>( geometry::get<min_corner, Dimension>(source))); - geometry::set<max_corner, Dimension>(destination, + geometry::set<max_corner, Dimension>(destination, boost::numeric_cast<coordinate_type>( geometry::get<max_corner, Dimension>(source))); - + indexed_to_indexed < - Source, Destination, + Source, Destination, Dimension + 1, DimensionCount >::apply(source, destination); } }; -template +template < - typename Source, - typename Destination, + typename Source, + typename Destination, std::size_t DimensionCount > struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount> diff --git a/boost/geometry/algorithms/detail/counting.hpp b/boost/geometry/algorithms/detail/counting.hpp new file mode 100644 index 0000000000..dc5bb26c10 --- /dev/null +++ b/boost/geometry/algorithms/detail/counting.hpp @@ -0,0 +1,107 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_COUNTING_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace counting +{ + + +template <std::size_t D> +struct other_count +{ + template <typename Geometry> + static inline std::size_t apply(Geometry const&) + { + return D; + } + + template <typename Geometry> + static inline std::size_t apply(Geometry const&, bool) + { + return D; + } +}; + + +template <typename RangeCount> +struct polygon_count +{ + template <typename Polygon> + static inline std::size_t apply(Polygon const& poly) + { + std::size_t n = RangeCount::apply(exterior_ring(poly)); + + typename interior_return_type<Polygon const>::type + rings = interior_rings(poly); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) + { + n += RangeCount::apply(*it); + } + + return n; + } +}; + + +template <typename SingleCount> +struct multi_count +{ + template <typename MultiGeometry> + static inline std::size_t apply(MultiGeometry const& geometry) + { + std::size_t n = 0; + for (typename boost::range_iterator<MultiGeometry const>::type + it = boost::begin(geometry); + it != boost::end(geometry); + ++it) + { + n += SingleCount::apply(*it); + } + return n; + } +}; + + +}} // namespace detail::counting +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP diff --git a/boost/geometry/algorithms/detail/course.hpp b/boost/geometry/algorithms/detail/course.hpp new file mode 100644 index 0000000000..e1a74c0fee --- /dev/null +++ b/boost/geometry/algorithms/detail/course.hpp @@ -0,0 +1,56 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_COURSE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/util/math.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/// Calculate course (bearing) between two points. +template <typename ReturnType, typename Point1, typename Point2> +inline ReturnType course(Point1 const& p1, Point2 const& p2) +{ + // http://williams.best.vwh.net/avform.htm#Crs + ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1); + ReturnType cos_p2lat = cos(get_as_radian<1>(p2)); + + // An optimization which should kick in often for Boxes + //if ( math::equals(dlon, ReturnType(0)) ) + //if ( get<0>(p1) == get<0>(p2) ) + //{ + // return - sin(get_as_radian<1>(p1)) * cos_p2lat); + //} + + // "An alternative formula, not requiring the pre-computation of d" + // In the formula below dlon is used as "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)); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP diff --git a/boost/geometry/algorithms/detail/disjoint.hpp b/boost/geometry/algorithms/detail/disjoint.hpp deleted file mode 100644 index 2ced5b1ce3..0000000000 --- a/boost/geometry/algorithms/detail/disjoint.hpp +++ /dev/null @@ -1,225 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. - -// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library -// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP - -// Note: contrary to most files, the geometry::detail::disjoint namespace -// is partly implemented in a separate file, to avoid circular references -// disjoint -> get_turns -> disjoint - -#include <cstddef> - -#include <boost/range.hpp> - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/reverse_dispatch.hpp> - - -#include <boost/geometry/util/math.hpp> - - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace disjoint -{ - - -struct disjoint_interrupt_policy -{ - static bool const enabled = true; - bool has_intersections; - - inline disjoint_interrupt_policy() - : has_intersections(false) - {} - - template <typename Range> - inline bool apply(Range const& range) - { - // If there is any IP in the range, it is NOT disjoint - if (boost::size(range) > 0) - { - has_intersections = true; - return true; - } - return false; - } -}; - - - -template -< - typename Point1, typename Point2, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_point -{ - static inline bool apply(Point1 const& p1, Point2 const& p2) - { - if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2))) - { - return true; - } - return point_point - < - Point1, Point2, - Dimension + 1, DimensionCount - >::apply(p1, p2); - } -}; - - -template <typename Point1, typename Point2, std::size_t DimensionCount> -struct point_point<Point1, Point2, DimensionCount, DimensionCount> -{ - static inline bool apply(Point1 const& , Point2 const& ) - { - return false; - } -}; - - -template -< - typename Point, typename Box, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_box -{ - static inline bool apply(Point const& point, Box const& box) - { - if (get<Dimension>(point) < get<min_corner, Dimension>(box) - || get<Dimension>(point) > get<max_corner, Dimension>(box)) - { - return true; - } - return point_box - < - Point, Box, - Dimension + 1, DimensionCount - >::apply(point, box); - } -}; - - -template <typename Point, typename Box, std::size_t DimensionCount> -struct point_box<Point, Box, DimensionCount, DimensionCount> -{ - static inline bool apply(Point const& , Box const& ) - { - return false; - } -}; - - -template -< - typename Box1, typename Box2, - std::size_t Dimension, std::size_t DimensionCount -> -struct box_box -{ - static inline bool apply(Box1 const& box1, Box2 const& box2) - { - if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2)) - { - return true; - } - if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2)) - { - return true; - } - return box_box - < - Box1, Box2, - Dimension + 1, DimensionCount - >::apply(box1, box2); - } -}; - - -template <typename Box1, typename Box2, std::size_t DimensionCount> -struct box_box<Box1, Box2, DimensionCount, DimensionCount> -{ - static inline bool apply(Box1 const& , Box2 const& ) - { - return false; - } -}; - - - -/*! - \brief Internal utility function to detect of boxes are disjoint - \note Is used from other algorithms, declared separately - to avoid circular references - */ -template <typename Box1, typename Box2> -inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2) -{ - return box_box - < - Box1, Box2, - 0, dimension<Box1>::type::value - >::apply(box1, box2); -} - - - -/*! - \brief Internal utility function to detect of points are disjoint - \note To avoid circular references - */ -template <typename Point1, typename Point2> -inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2) -{ - return point_point - < - Point1, Point2, - 0, dimension<Point1>::type::value - >::apply(point1, point2); -} - - -}} // namespace detail::disjoint -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace equals -{ - -/*! - \brief Internal utility function to detect of points are disjoint - \note To avoid circular references - */ -template <typename Point1, typename Point2> -inline bool equals_point_point(Point1 const& point1, Point2 const& point2) -{ - return ! detail::disjoint::disjoint_point_point(point1, point2); -} - - -}} // namespace detail::equals -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp new file mode 100644 index 0000000000..284858a130 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_AREAL_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> + +#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template<typename Geometry> +struct check_each_ring_for_within +{ + bool not_disjoint; + Geometry const& m_geometry; + + inline check_each_ring_for_within(Geometry const& g) + : not_disjoint(false) + , m_geometry(g) + {} + + template <typename Range> + inline void apply(Range const& range) + { + typename point_type<Range>::type pt; + not_disjoint = not_disjoint + || ( geometry::point_on_border(pt, range) + && geometry::covered_by(pt, m_geometry) ); + } +}; + + + +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.not_disjoint; +} + + + +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 + + // We check that using a point on the border (external boundary), + // and see if that is contained in the other geometry. And vice versa. + + 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 Areal1, typename Areal2> +struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false> + : detail::disjoint::general_areal<Areal1, Areal2> +{}; + + +template <typename Areal, typename Box> +struct disjoint<Areal, Box, 2, areal_tag, box_tag, false> + : detail::disjoint::general_areal<Areal, Box> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp new file mode 100644 index 0000000000..ccff9799fd --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp @@ -0,0 +1,114 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BOX_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template +< + typename Box1, typename Box2, + std::size_t Dimension, std::size_t DimensionCount +> +struct box_box +{ + static inline bool apply(Box1 const& box1, Box2 const& box2) + { + if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2)) + { + return true; + } + if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2)) + { + return true; + } + return box_box + < + Box1, Box2, + Dimension + 1, DimensionCount + >::apply(box1, box2); + } +}; + + +template <typename Box1, typename Box2, std::size_t DimensionCount> +struct box_box<Box1, Box2, DimensionCount, DimensionCount> +{ + static inline bool apply(Box1 const& , Box2 const& ) + { + return false; + } +}; + + +/*! + \brief Internal utility function to detect of boxes are disjoint + \note Is used from other algorithms, declared separately + to avoid circular references + */ +template <typename Box1, typename Box2> +inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2) +{ + return box_box + < + Box1, Box2, + 0, dimension<Box1>::type::value + >::apply(box1, box2); +} + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Box1, typename Box2, std::size_t DimensionCount> +struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false> + : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp new file mode 100644 index 0000000000..0c8079b8e4 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP + + +#include <boost/geometry/algorithms/detail/disjoint/areal_areal.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp> + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp new file mode 100644 index 0000000000..ec9057ba0d --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/interface.hpp @@ -0,0 +1,187 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP + +#include <cstddef> + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// 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> +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + return disjoint + < + Geometry2, Geometry1, + DimensionCount, + Tag2, Tag1 + >::apply(g2, g1); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct disjoint +{ + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + concept::check_concepts_and_equal_dimensions + < + Geometry1 const, + Geometry2 const + >(); + + return dispatch::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct disjoint<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + struct visitor: boost::static_visitor<bool> + { + Geometry2 const& m_geometry2; + + visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {} + + template <typename Geometry1> + bool operator()(Geometry1 const& geometry1) const + { + return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2); + } + }; + + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2) + { + return boost::apply_visitor(visitor(geometry2), geometry1); + } +}; + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<bool> + { + Geometry1 const& m_geometry1; + + visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {} + + template <typename Geometry2> + bool operator()(Geometry2 const& geometry2) const + { + return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2); + } + }; + + static inline bool + apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + { + return boost::apply_visitor(visitor(geometry1), geometry2); + } +}; + +template < + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) +> +struct disjoint< + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> +> +{ + struct visitor: boost::static_visitor<bool> + { + template <typename Geometry1, typename Geometry2> + bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return disjoint<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 boost::apply_visitor(visitor(), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + + +/*! +\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) +{ + return resolve_variant::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp new file mode 100644 index 0000000000..eefd351b8d --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp @@ -0,0 +1,244 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_LINEAR_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP + +#include <iterator> + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_type.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/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> + +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template<typename Geometry1, typename Geometry2> +struct disjoint_linear_areal +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + // if there are intersections - return false + if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2) ) + return false; + + typedef typename point_type<Geometry1>::type point1_type; + point1_type p; + geometry::point_on_border(p, g1); + return !geometry::covered_by(p, g2); + } +}; + + + + +template +< + typename Segment, + typename Areal, + typename Tag = typename tag<Areal>::type +> +struct disjoint_segment_areal + : not_implemented<Segment, Areal> +{}; + + +template <typename Segment, typename Polygon> +class disjoint_segment_areal<Segment, Polygon, polygon_tag> +{ +private: + template <typename RingIterator> + static inline bool check_interior_rings(RingIterator first, + RingIterator beyond, + Segment const& segment) + { + for (RingIterator it = first; it != beyond; ++it) + { + if ( !disjoint_range_segment_or_box + < + typename std::iterator_traits + < + RingIterator + >::value_type, + closure<Polygon>::value, + Segment + >::apply(*it, segment) ) + { + return false; + } + } + return true; + } + + + template <typename InteriorRings> + static inline + bool check_interior_rings(InteriorRings const& interior_rings, + Segment const& segment) + { + return check_interior_rings(boost::begin(interior_rings), + boost::end(interior_rings), + segment); + } + + +public: + static inline bool apply(Segment const& segment, Polygon const& polygon) + { + typedef typename geometry::ring_type<Polygon>::type ring; + + if ( !disjoint_range_segment_or_box + < + ring, closure<Polygon>::value, Segment + >::apply(geometry::exterior_ring(polygon), segment) ) + { + return false; + } + + if ( !check_interior_rings(geometry::interior_rings(polygon), segment) ) + { + return false; + } + + typename point_type<Segment>::type p; + detail::assign_point_from_index<0>(segment, p); + + return !geometry::covered_by(p, polygon); + } +}; + + +template <typename Segment, typename MultiPolygon> +struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag> +{ + static inline + bool apply(Segment const& segment, MultiPolygon const& multipolygon) + { + return disjoint_multirange_segment_or_box + < + MultiPolygon, Segment + >::apply(multipolygon, segment); + } +}; + + +template <typename Segment, typename Ring> +struct disjoint_segment_areal<Segment, Ring, ring_tag> +{ + static inline bool apply(Segment const& segment, Ring const& ring) + { + if ( !disjoint_range_segment_or_box + < + Ring, closure<Ring>::value, Segment + >::apply(ring, segment) ) + { + return false; + } + + typename point_type<Segment>::type p; + detail::assign_point_from_index<0>(segment, p); + + return !geometry::covered_by(p, ring); + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Linear, typename Areal> +struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false> + : public detail::disjoint::disjoint_linear_areal<Linear, Areal> +{}; + + +template <typename Areal, typename Linear> +struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false> +{ + static inline + bool apply(Areal const& areal, Linear const& linear) + { + return detail::disjoint::disjoint_linear_areal + < + Linear, Areal + >::apply(linear, areal); + } +}; + + +template <typename Areal, typename Segment> +struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false> +{ + static inline bool apply(Areal const& g1, Segment const& g2) + { + return detail::disjoint::disjoint_segment_areal + < + Segment, Areal + >::apply(g2, g1); + } +}; + + +template <typename Segment, typename Areal> +struct disjoint<Segment, Areal, 2, segment_tag, areal_tag, false> + : detail::disjoint::disjoint_segment_areal<Segment, Areal> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp new file mode 100644 index 0000000000..ad84d7191d --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp @@ -0,0 +1,174 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_LINEAR_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP + +#include <cstddef> +#include <deque> + +#include <boost/range.hpp> +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.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/do_reverse.hpp> + +#include <boost/geometry/policies/disjoint_interrupt_policy.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + +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; + + // We don't need to rescale to detect disjointness + typedef no_rescale_policy rescale_policy_type; + rescale_policy_type robust_policy; + + typedef segment_intersection_points + < + point_type, + typename segment_ratio_type + < + point_type, + rescale_policy_type + >::type + > intersection_return_type; + + intersection_return_type is + = strategy::intersection::relate_cartesian_segments + < + policies::relate::segments_intersection_points + < + intersection_return_type + > + >::apply(segment1, segment2, robust_policy); + + return is.count == 0; + } +}; + + +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 detail::no_rescale_policy rescale_policy_type; + typedef overlay::turn_info + < + point_type, + typename segment_ratio_type<point_type, rescale_policy_type>::type + > turn_info; + std::deque<turn_info> turns; + + static const bool reverse1 = overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; // should be false + static const bool reverse2 = overlay::do_reverse<geometry::point_order<Geometry2>::value>::value; // should be false + + // Specify two policies: + // 1) Stop at any intersection + // 2) In assignment, include also degenerate points (which are normally skipped) + disjoint_interrupt_policy policy; + rescale_policy_type robust_policy; + geometry::get_turns + < + reverse1, reverse2, + assign_disjoint_policy + >(geometry1, geometry2, robust_policy, turns, policy); + + return !policy.has_intersections; + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Linear1, typename Linear2> +struct disjoint<Linear1, Linear2, 2, linear_tag, linear_tag, false> + : detail::disjoint::disjoint_linear<Linear1, Linear2> +{}; + + +template <typename Segment1, typename Segment2> +struct disjoint<Segment1, Segment2, 2, segment_tag, segment_tag, false> + : detail::disjoint::disjoint_segment<Segment1, Segment2> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp new file mode 100644 index 0000000000..d181726e2e --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp @@ -0,0 +1,195 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_LINEAR_SEGMENT_OR_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP + +#include <boost/range.hpp> +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/core/closure.hpp> + +#include <boost/geometry/geometries/segment.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/views/closeable_view.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template <typename MultiRange, typename SegmentOrBox> +struct disjoint_multirange_segment_or_box +{ + static inline + bool apply(MultiRange const& multirange, SegmentOrBox const& segment_or_box) + { + typedef typename boost::range_iterator + < + MultiRange const + >::type const_iterator; + + for (const_iterator it = boost::begin(multirange); + it != boost::end(multirange); ++it) + { + if ( !dispatch::disjoint + < + typename boost::range_value<MultiRange>::type, + SegmentOrBox + >::apply(*it, segment_or_box) ) + { + return false; + } + } + return true; + } +}; + + +template +< + typename Range, + closure_selector Closure, + typename SegmentOrBox +> +struct disjoint_range_segment_or_box +{ + static inline + bool apply(Range const& range, SegmentOrBox const& segment_or_box) + { + typedef typename closeable_view<Range const, Closure>::type view_type; + + typedef typename ::boost::range_value<view_type>::type point_type; + typedef typename ::boost::range_iterator + < + view_type const + >::type const_iterator; + + typedef typename ::boost::range_size<view_type>::type size_type; + + typedef typename geometry::model::referring_segment + < + point_type const + > range_segment; + + view_type view(range); + + const size_type count = ::boost::size(view); + + if ( count == 0 ) + { + return false; + } + else if ( count == 1 ) + { + return dispatch::disjoint + < + point_type, SegmentOrBox + >::apply(geometry::range::front<view_type const>(view), + segment_or_box); + } + else + { + const_iterator it0 = ::boost::begin(view); + const_iterator it1 = ::boost::begin(view) + 1; + const_iterator last = ::boost::end(view); + + for ( ; it1 != last ; ++it0, ++it1 ) + { + range_segment rng_segment(*it0, *it1); + if ( !dispatch::disjoint + < + range_segment, SegmentOrBox + >::apply(rng_segment, segment_or_box) ) + { + return false; + } + } + return true; + } + } +}; + + + + +template +< + typename Linear, + typename SegmentOrBox, + typename Tag = typename tag<Linear>::type +> +struct disjoint_linear_segment_or_box + : not_implemented<Linear, SegmentOrBox> +{}; + + +template <typename Linestring, typename SegmentOrBox> +struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag> + : disjoint_range_segment_or_box<Linestring, closed, SegmentOrBox> +{}; + + +template <typename MultiLinestring, typename SegmentOrBox> +struct disjoint_linear_segment_or_box + < + MultiLinestring, SegmentOrBox, multi_linestring_tag + > : disjoint_multirange_segment_or_box<MultiLinestring, SegmentOrBox> +{}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Linear, typename Segment> +struct disjoint<Linear, Segment, 2, linear_tag, segment_tag, false> + : detail::disjoint::disjoint_linear_segment_or_box<Linear, Segment> +{}; + + +template <typename Linear, typename Box, std::size_t DimensionCount> +struct disjoint<Linear, Box, DimensionCount, linear_tag, box_tag, false> + : detail::disjoint::disjoint_linear_segment_or_box<Linear, Box> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp new file mode 100644 index 0000000000..ea6609a153 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_POINT_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +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; + } +}; + + +}} // namespace detail::equals +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Point, typename Box, std::size_t DimensionCount> +struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false> + : detail::disjoint::point_box<Point, Box, 0, DimensionCount> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp new file mode 100644 index 0000000000..a58bff41da --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_POINT_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP + +#include <boost/geometry/geometries/segment.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> + +#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template<typename Point, typename Geometry> +struct disjoint_point_linear +{ + static inline + bool apply(Point const& pt, Geometry const& g) + { + return !geometry::covered_by(pt, g); + } +}; + + +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); + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template<typename Point, typename Linear, std::size_t DimensionCount> +struct disjoint<Point, Linear, DimensionCount, point_tag, linear_tag, false> + : public detail::disjoint::disjoint_point_linear<Point, Linear> +{}; + + +template <typename Point, typename Areal, std::size_t DimensionCount> +struct disjoint<Point, Areal, DimensionCount, point_tag, areal_tag, false> + : detail::disjoint::reverse_covered_by<Point, Areal> +{}; + + +template<typename Point, typename Segment, std::size_t DimensionCount> +struct disjoint<Point, Segment, DimensionCount, point_tag, segment_tag, false> +{ + static inline bool apply(Point const& point, Segment const& segment) + { + typedef geometry::model::referring_segment<Point const> other_segment; + + other_segment other(point, point); + return detail::disjoint::disjoint_segment + < + Segment, other_segment + >::apply(segment, other); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/point_point.hpp b/boost/geometry/algorithms/detail/disjoint/point_point.hpp new file mode 100644 index 0000000000..b1d32bf95e --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/point_point.hpp @@ -0,0 +1,112 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_POINT_POINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + +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; + } +}; + + +/*! + \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_DISPATCH +namespace dispatch +{ + + +template <typename Point1, typename Point2, std::size_t DimensionCount> +struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false> + : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp new file mode 100644 index 0000000000..5368432ed4 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp @@ -0,0 +1,291 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_SEGMENT_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP + +#include <cstddef> +#include <utility> + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/calculation_type.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template <std::size_t I> +struct compute_tmin_tmax_per_dim +{ + template <typename SegmentPoint, typename Box, typename RelativeDistance> + static inline void apply(SegmentPoint const& p0, + SegmentPoint const& p1, + Box const& box, + RelativeDistance& ti_min, + RelativeDistance& ti_max, + RelativeDistance& diff) + { + typedef typename coordinate_type<Box>::type box_coordinate_type; + typedef typename coordinate_type + < + SegmentPoint + >::type point_coordinate_type; + + RelativeDistance c_p0 = boost::numeric_cast + < + point_coordinate_type + >( geometry::get<I>(p0) ); + + RelativeDistance c_p1 = boost::numeric_cast + < + point_coordinate_type + >( geometry::get<I>(p1) ); + + RelativeDistance c_b_min = boost::numeric_cast + < + box_coordinate_type + >( geometry::get<geometry::min_corner, I>(box) ); + + RelativeDistance c_b_max = boost::numeric_cast + < + box_coordinate_type + >( geometry::get<geometry::max_corner, I>(box) ); + + if ( geometry::get<I>(p1) >= geometry::get<I>(p0) ) + { + diff = c_p1 - c_p0; + ti_min = c_b_min - c_p0; + ti_max = c_b_max - c_p0; + } + else + { + diff = c_p0 - c_p1; + ti_min = c_p0 - c_b_max; + ti_max = c_p0 - c_b_min; + } + } +}; + + +template +< + typename RelativeDistance, + typename SegmentPoint, + typename Box, + std::size_t I, + std::size_t Dimension +> +struct disjoint_segment_box_impl +{ + template <typename RelativeDistancePair> + static inline bool apply(SegmentPoint const& p0, + SegmentPoint const& p1, + Box const& box, + RelativeDistancePair& t_min, + RelativeDistancePair& t_max) + { + RelativeDistance ti_min, ti_max, diff; + + compute_tmin_tmax_per_dim<I>::apply(p0, p1, box, ti_min, ti_max, diff); + + if ( geometry::math::equals(diff, 0) ) + { + if ( (geometry::math::equals(t_min.second, 0) + && t_min.first > ti_max) + || + (geometry::math::equals(t_max.second, 0) + && t_max.first < ti_min) ) + { + return true; + } + } + + RelativeDistance t_min_x_diff = t_min.first * diff; + RelativeDistance t_max_x_diff = t_max.first * diff; + + if ( t_min_x_diff > ti_max * t_min.second + || t_max_x_diff < ti_min * t_max.second ) + { + return true; + } + + if ( ti_min * t_min.second > t_min_x_diff ) + { + t_min.first = ti_min; + t_min.second = diff; + } + if ( ti_max * t_max.second < t_max_x_diff ) + { + t_max.first = ti_max; + t_max.second = diff; + } + + if ( t_min.first > t_min.second || t_max.first < 0 ) + { + return true; + } + + return disjoint_segment_box_impl + < + RelativeDistance, + SegmentPoint, + Box, + I + 1, + Dimension + >::apply(p0, p1, box, t_min, t_max); + } +}; + + +template +< + typename RelativeDistance, + typename SegmentPoint, + typename Box, + std::size_t Dimension +> +struct disjoint_segment_box_impl + < + RelativeDistance, SegmentPoint, Box, 0, Dimension + > +{ + static inline bool apply(SegmentPoint const& p0, + SegmentPoint const& p1, + Box const& box) + { + std::pair<RelativeDistance, RelativeDistance> t_min, t_max; + RelativeDistance diff; + + compute_tmin_tmax_per_dim<0>::apply(p0, p1, box, + t_min.first, t_max.first, diff); + + if ( geometry::math::equals(diff, 0) ) + { + if ( geometry::math::equals(t_min.first, 0) ) { t_min.first = -1; } + if ( geometry::math::equals(t_max.first, 0) ) { t_max.first = 1; } + } + + if ( t_min.first > diff || t_max.first < 0 ) + { + return true; + } + + t_min.second = t_max.second = diff; + + return disjoint_segment_box_impl + < + RelativeDistance, SegmentPoint, Box, 1, Dimension + >::apply(p0, p1, box, t_min, t_max); + } +}; + + +template +< + typename RelativeDistance, + typename SegmentPoint, + typename Box, + std::size_t Dimension +> +struct disjoint_segment_box_impl + < + RelativeDistance, SegmentPoint, Box, Dimension, Dimension + > +{ + template <typename RelativeDistancePair> + static inline bool apply(SegmentPoint const&, SegmentPoint const&, + Box const&, + RelativeDistancePair&, RelativeDistancePair&) + { + return false; + } +}; + + +//========================================================================= + + +template <typename Segment, typename Box> +struct disjoint_segment_box +{ + static inline bool apply(Segment const& segment, Box const& box) + { + assert_dimension_equal<Segment, Box>(); + + typedef typename util::calculation_type::geometric::binary + < + Segment, Box, void + >::type relative_distance_type; + + typedef typename point_type<Segment>::type segment_point_type; + segment_point_type p0, p1; + geometry::detail::assign_point_from_index<0>(segment, p0); + geometry::detail::assign_point_from_index<1>(segment, p1); + + return disjoint_segment_box_impl + < + relative_distance_type, segment_point_type, Box, + 0, dimension<Box>::value + >::apply(p0, p1, box); + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Segment, typename Box, std::size_t DimensionCount> +struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false> + : detail::disjoint::disjoint_segment_box<Segment, Box> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP diff --git a/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp new file mode 100644 index 0000000000..5b49e571dd --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp @@ -0,0 +1,333 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DISTANCE_BACKWARD_COMPATIBILITY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/assign.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> +#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> +#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template<typename Point, typename Segment, typename Strategy> +struct point_to_segment +{ + static inline typename strategy::distance::services::return_type + < + Strategy, + Point, + typename point_type<Segment>::type + >::type + apply(Point const& point, Segment const& segment, Strategy const& ) + { + typename detail::distance::default_ps_strategy + < + Point, + typename point_type<Segment>::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]); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// 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-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 strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Linestring>::type + >::type + apply(Point const& point, + Linestring const& linestring, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + Point, + typename point_type<Linestring>::type, + Strategy + >::type ps_strategy_type; + + return detail::distance::point_to_range + < + Point, Linestring, closed, ps_strategy_type + >::apply(point, linestring, ps_strategy_type()); + } +}; + + +// Point-ring , where point-point 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 strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Ring>::type + >::type return_type; + + static inline return_type apply(Point const& point, + Ring const& ring, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + Point, + typename point_type<Ring>::type, + Strategy + >::type ps_strategy_type; + + return detail::distance::point_to_ring + < + Point, Ring, + geometry::closure<Ring>::value, + ps_strategy_type + >::apply(point, ring, ps_strategy_type()); + } +}; + + +// Point-polygon , where point-point 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 strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Polygon>::type + >::type return_type; + + static inline return_type apply(Point const& point, + Polygon const& polygon, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + Point, + typename point_type<Polygon>::type, + Strategy + >::type ps_strategy_type; + + return detail::distance::point_to_polygon + < + Point, + Polygon, + geometry::closure<Polygon>::value, + ps_strategy_type + >::apply(point, polygon, ps_strategy_type()); + } +}; + + + + +template +< + typename Point, + typename MultiGeometry, + typename MultiGeometryTag, + typename Strategy +> +struct distance + < + Point, MultiGeometry, Strategy, + point_tag, MultiGeometryTag, + strategy_tag_distance_point_point, false + > +{ + typedef typename strategy::distance::services::return_type + < + Strategy, Point, typename point_type<MultiGeometry>::type + >::type return_type; + + static inline return_type apply(Point const& point, + MultiGeometry const& multigeometry, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + Point, + typename point_type<MultiGeometry>::type, + Strategy + >::type ps_strategy_type; + + return distance + < + Point, MultiGeometry, ps_strategy_type, + point_tag, MultiGeometryTag, + strategy_tag_distance_point_segment, false + >::apply(point, multigeometry, ps_strategy_type()); + } +}; + + +template +< + typename Geometry, + typename MultiPoint, + typename GeometryTag, + typename Strategy +> +struct distance + < + Geometry, MultiPoint, Strategy, + GeometryTag, multi_point_tag, + strategy_tag_distance_point_point, false + > +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<MultiPoint>::type, + typename point_type<Geometry>::type + >::type return_type; + + static inline return_type apply(Geometry const& geometry, + MultiPoint const& multipoint, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + typename point_type<MultiPoint>::type, + typename point_type<Geometry>::type, + Strategy + >::type ps_strategy_type; + + return distance + < + Geometry, MultiPoint, ps_strategy_type, + GeometryTag, multi_point_tag, + strategy_tag_distance_point_segment, false + >::apply(geometry, multipoint, ps_strategy_type()); + } +}; + + +template +< + typename MultiPoint, + typename MultiGeometry, + typename MultiGeometryTag, + typename Strategy +> +struct distance + < + MultiPoint, MultiGeometry, Strategy, + multi_point_tag, MultiGeometryTag, + strategy_tag_distance_point_point, false + > +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<MultiPoint>::type, + typename point_type<MultiGeometry>::type + >::type return_type; + + static inline return_type apply(MultiPoint const& multipoint, + MultiGeometry const& multigeometry, + Strategy const&) + { + typedef typename detail::distance::default_ps_strategy + < + typename point_type<MultiPoint>::type, + typename point_type<MultiGeometry>::type, + Strategy + >::type ps_strategy_type; + + return distance + < + MultiPoint, MultiGeometry, ps_strategy_type, + multi_point_tag, MultiGeometryTag, + strategy_tag_distance_point_segment, false + >::apply(multipoint, multigeometry, ps_strategy_type()); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP diff --git a/boost/geometry/algorithms/detail/distance/box_to_box.hpp b/boost/geometry/algorithms/detail/distance/box_to_box.hpp new file mode 100644 index 0000000000..44778e9e06 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/box_to_box.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP + +#include <boost/core/ignore_unused.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Box1, typename Box2, typename Strategy> +struct distance + < + Box1, Box2, Strategy, box_tag, box_tag, + strategy_tag_distance_box_box, false + > +{ + static inline typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Box1>::type, + typename point_type<Box2>::type + >::type + apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) + { + boost::ignore_unused(strategy); + return strategy.apply(box1, box2); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP diff --git a/boost/geometry/algorithms/detail/distance/default_strategies.hpp b/boost/geometry/algorithms/detail/distance/default_strategies.hpp new file mode 100644 index 0000000000..a01ace2b58 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/default_strategies.hpp @@ -0,0 +1,137 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DISTANCE_DEFAULT_STRATEGIES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP + +#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> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/reverse_dispatch.hpp> + +#include <boost/geometry/strategies/distance.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + + +// Helper metafunction for default strategy retrieval +template +< + typename Geometry1, + typename Geometry2 = Geometry1, + typename Tag1 = typename tag_cast + < + typename tag<Geometry1>::type, pointlike_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag<Geometry2>::type, pointlike_tag + >::type, + bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct default_strategy + : strategy::distance::services::default_strategy + < + point_tag, segment_tag, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + > +{}; + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1, + typename Tag2 +> +struct default_strategy<Geometry1, Geometry2, Tag1, Tag2, true> + : default_strategy<Geometry2, Geometry1, Tag2, Tag1, false> +{}; + + +template <typename Pointlike1, typename Pointlike2> +struct default_strategy + < + Pointlike1, Pointlike2, + pointlike_tag, pointlike_tag, false + > : strategy::distance::services::default_strategy + < + point_tag, point_tag, + typename point_type<Pointlike1>::type, + typename point_type<Pointlike2>::type + > +{}; + + +template <typename Pointlike, typename Box> +struct default_strategy<Pointlike, Box, pointlike_tag, box_tag, false> + : strategy::distance::services::default_strategy + < + point_tag, box_tag, + typename point_type<Pointlike>::type, + typename point_type<Box>::type + > +{}; + + +template <typename Box1, typename Box2> +struct default_strategy<Box1, Box2, box_tag, box_tag, false> + : strategy::distance::services::default_strategy + < + box_tag, box_tag, + typename point_type<Box1>::type, + typename point_type<Box2>::type + > +{}; + + + +// Helper metafunction for default point-segment strategy retrieval +template <typename Geometry1, typename Geometry2, typename Strategy> +struct default_ps_strategy + : strategy::distance::services::default_strategy + < + point_tag, segment_tag, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type, + typename cs_tag<typename point_type<Geometry1>::type>::type, + typename cs_tag<typename point_type<Geometry2>::type>::type, + Strategy + > +{}; + + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP diff --git a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp new file mode 100644 index 0000000000..04d1095cba --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp @@ -0,0 +1,462 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP + +#include <iterator> + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> +#include <boost/geometry/iterators/segment_iterator.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> +#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> + +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +// closure of segment or box point range +template +< + typename SegmentOrBox, + typename Tag = typename tag<SegmentOrBox>::type +> +struct segment_or_box_point_range_closure + : not_implemented<SegmentOrBox> +{}; + +template <typename Segment> +struct segment_or_box_point_range_closure<Segment, segment_tag> +{ + static const closure_selector value = closed; +}; + +template <typename Box> +struct segment_or_box_point_range_closure<Box, box_tag> +{ + static const closure_selector value = open; +}; + + + +template +< + typename Geometry, + typename SegmentOrBox, + typename Strategy, + typename Tag = typename tag<Geometry>::type +> +class geometry_to_segment_or_box +{ +private: + typedef typename point_type<SegmentOrBox>::type segment_or_box_point; + + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef detail::closest_feature::point_to_point_range + < + typename point_type<Geometry>::type, + std::vector<segment_or_box_point>, + segment_or_box_point_range_closure<SegmentOrBox>::value, + comparable_strategy + > point_to_point_range; + + typedef detail::closest_feature::geometry_to_range geometry_to_range; + + typedef typename strategy::distance::services::return_type + < + comparable_strategy, + typename point_type<Geometry>::type, + segment_or_box_point + >::type comparable_return_type; + + + // assign the new minimum value for an iterator of the point range + // of a segment or a box + template + < + typename SegOrBox, + typename SegOrBoxTag = typename tag<SegOrBox>::type + > + struct assign_new_min_iterator + : not_implemented<SegOrBox> + {}; + + template <typename Segment> + struct assign_new_min_iterator<Segment, segment_tag> + { + template <typename Iterator> + static inline void apply(Iterator&, Iterator) + { + } + }; + + template <typename Box> + struct assign_new_min_iterator<Box, box_tag> + { + template <typename Iterator> + static inline void apply(Iterator& it_min, Iterator it) + { + it_min = it; + } + }; + + + // assign the points of a segment or a box to a range + template + < + typename SegOrBox, + typename PointRange, + typename SegOrBoxTag = typename tag<SegOrBox>::type + > + struct assign_segment_or_box_points + {}; + + template <typename Segment, typename PointRange> + struct assign_segment_or_box_points<Segment, PointRange, segment_tag> + { + static inline void apply(Segment const& segment, PointRange& range) + { + detail::assign_point_from_index<0>(segment, range[0]); + detail::assign_point_from_index<1>(segment, range[1]); + } + }; + + template <typename Box, typename PointRange> + struct assign_segment_or_box_points<Box, PointRange, box_tag> + { + static inline void apply(Box const& box, PointRange& range) + { + detail::assign_box_corners_oriented<true>(box, range); + } + }; + + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Geometry>::type, + segment_or_box_point + >::type return_type; + + static inline return_type apply(Geometry const& geometry, + SegmentOrBox const& segment_or_box, + Strategy const& strategy, + bool check_intersection = true) + { + typedef geometry::point_iterator<Geometry const> point_iterator_type; + typedef geometry::segment_iterator + < + Geometry const + > segment_iterator_type; + + typedef typename std::vector + < + segment_or_box_point + >::const_iterator seg_or_box_iterator_type; + + typedef assign_new_min_iterator<SegmentOrBox> assign_new_value; + + + if (check_intersection + && geometry::intersects(geometry, segment_or_box)) + { + return 0; + } + + comparable_strategy cstrategy = + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy); + + // get all points of the segment or the box + std::vector<segment_or_box_point> + seg_or_box_points(geometry::num_points(segment_or_box)); + + assign_segment_or_box_points + < + SegmentOrBox, + std::vector<segment_or_box_point> + >::apply(segment_or_box, seg_or_box_points); + + // consider all distances of the points in the geometry to the + // segment or box + comparable_return_type cd_min1; + point_iterator_type pit_min; + seg_or_box_iterator_type it_min1 = seg_or_box_points.begin(); + seg_or_box_iterator_type it_min2 = ++seg_or_box_points.begin(); + bool first = true; + + for (point_iterator_type pit = points_begin(geometry); + pit != points_end(geometry); ++pit, first = false) + { + comparable_return_type cd; + std::pair + < + seg_or_box_iterator_type, seg_or_box_iterator_type + > it_pair + = point_to_point_range::apply(*pit, + seg_or_box_points.begin(), + seg_or_box_points.end(), + cstrategy, + cd); + + if (first || cd < cd_min1) + { + cd_min1 = cd; + pit_min = pit; + assign_new_value::apply(it_min1, it_pair.first); + assign_new_value::apply(it_min2, it_pair.second); + } + } + + // consider all distances of the points in the segment or box to the + // segments of the geometry + comparable_return_type cd_min2; + segment_iterator_type sit_min; + typename std::vector<segment_or_box_point>::const_iterator it_min; + + first = true; + for (typename std::vector<segment_or_box_point>::const_iterator it + = seg_or_box_points.begin(); + it != seg_or_box_points.end(); ++it, first = false) + { + comparable_return_type cd; + segment_iterator_type sit + = geometry_to_range::apply(*it, + segments_begin(geometry), + segments_end(geometry), + cstrategy, + cd); + + if (first || cd < cd_min2) + { + cd_min2 = cd; + it_min = it; + sit_min = sit; + } + } + + if (is_comparable<Strategy>::value) + { + return (std::min)(cd_min1, cd_min2); + } + + if (cd_min1 < cd_min2) + { + return strategy.apply(*pit_min, *it_min1, *it_min2); + } + else + { + return dispatch::distance + < + segment_or_box_point, + typename std::iterator_traits + < + segment_iterator_type + >::value_type, + Strategy + >::apply(*it_min, *sit_min, strategy); + } + } + + + static inline return_type + apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, + Strategy const& strategy, bool check_intersection = true) + { + return apply(geometry, segment_or_box, strategy, check_intersection); + } +}; + + + +template <typename MultiPoint, typename SegmentOrBox, typename Strategy> +class geometry_to_segment_or_box + < + MultiPoint, SegmentOrBox, Strategy, multi_point_tag + > +{ +private: + typedef detail::closest_feature::geometry_to_range base_type; + + typedef typename boost::range_iterator + < + MultiPoint const + >::type iterator_type; + + typedef detail::closest_feature::geometry_to_range geometry_to_range; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<SegmentOrBox>::type, + typename point_type<MultiPoint>::type + >::type return_type; + + static inline return_type apply(MultiPoint const& multipoint, + SegmentOrBox const& segment_or_box, + Strategy const& strategy) + { + namespace sds = strategy::distance::services; + + typename sds::return_type + < + typename sds::comparable_type<Strategy>::type, + typename point_type<SegmentOrBox>::type, + typename point_type<MultiPoint>::type + >::type cd_min; + + iterator_type it_min + = geometry_to_range::apply(segment_or_box, + boost::begin(multipoint), + boost::end(multipoint), + sds::get_comparable + < + Strategy + >::apply(strategy), + cd_min); + + return + is_comparable<Strategy>::value + ? + cd_min + : + dispatch::distance + < + typename point_type<MultiPoint>::type, + SegmentOrBox, + Strategy + >::apply(*it_min, segment_or_box, strategy); + } +}; + + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Linear, typename Segment, typename Strategy> +struct distance + < + Linear, Segment, Strategy, linear_tag, segment_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy> +{}; + + +template <typename Areal, typename Segment, typename Strategy> +struct distance + < + Areal, Segment, Strategy, areal_tag, segment_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> +{}; + + +template <typename Segment, typename Areal, typename Strategy> +struct distance + < + Segment, Areal, Strategy, segment_tag, areal_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> +{}; + + +template <typename Linear, typename Box, typename Strategy> +struct distance + < + Linear, Box, Strategy, linear_tag, box_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box + < + Linear, Box, Strategy + > +{}; + + +template <typename Areal, typename Box, typename Strategy> +struct distance + < + Areal, Box, Strategy, areal_tag, box_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy> +{}; + + +template <typename MultiPoint, typename Segment, typename Strategy> +struct distance + < + MultiPoint, Segment, Strategy, + multi_point_tag, segment_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::geometry_to_segment_or_box + < + MultiPoint, Segment, Strategy + > +{}; + + +template <typename MultiPoint, typename Box, typename Strategy> +struct distance + < + MultiPoint, Box, Strategy, + multi_point_tag, box_tag, + strategy_tag_distance_point_box, false + > : detail::distance::geometry_to_segment_or_box + < + MultiPoint, Box, Strategy + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP diff --git a/boost/geometry/algorithms/detail/distance/implementation.hpp b/boost/geometry/algorithms/detail/distance/implementation.hpp new file mode 100644 index 0000000000..7c009f4d79 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/implementation.hpp @@ -0,0 +1,35 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DISTANCE_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP + +// the implementation details +#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> +#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp> +#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp> +#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp> +#include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp> +#include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp> +#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp> +#include <boost/geometry/algorithms/detail/distance/box_to_box.hpp> + +#include <boost/geometry/algorithms/detail/distance/backward_compatibility.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp new file mode 100644 index 0000000000..9b377f524b --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/interface.hpp @@ -0,0 +1,403 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DISTANCE_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP + +#include <boost/concept_check.hpp> + +#include <boost/mpl/always.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/vector.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/default_distance_result.hpp> +#include <boost/geometry/strategies/distance_result.hpp> + +#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// 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> +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Geometry2>::type, + typename point_type<Geometry1>::type + >::type return_type; + + static inline return_type apply( + Geometry1 const& g1, + Geometry2 const& g2, + Strategy const& strategy) + { + return distance + < + Geometry2, Geometry1, Strategy, + Tag2, Tag1, StrategyTag, + false + >::apply(g2, g1, strategy); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_strategy +{ + +struct distance +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline typename distance_result<Geometry1, Geometry2, Strategy>::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return dispatch::distance + < + Geometry1, Geometry2, Strategy + >::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline + typename distance_result<Geometry1, Geometry2, default_strategy>::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename detail::distance::default_strategy + < + Geometry1, Geometry2 + >::type strategy_type; + + return dispatch::distance + < + Geometry1, Geometry2, strategy_type + >::apply(geometry1, geometry2, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant +{ + + +template <typename Geometry1, typename Geometry2> +struct distance +{ + template <typename Strategy> + static inline typename distance_result<Geometry1, Geometry2, Strategy>::type + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return + resolve_strategy::distance::apply(geometry1, geometry2, strategy); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename distance_result + < + variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + >::type + > + { + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, + Strategy const& strategy) + : m_geometry2(geometry2), + m_strategy(strategy) + {} + + template <typename Geometry1> + typename distance_result<Geometry1, Geometry2, Strategy>::type + operator()(Geometry1 const& geometry1) const + { + return distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(geometry1, m_geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename distance_result + < + variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + >::type + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename distance_result + < + Geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + >::type + > + { + Geometry1 const& m_geometry1; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, + Strategy const& strategy) + : m_geometry1(geometry1), + m_strategy(strategy) + {} + + template <typename Geometry2> + typename distance_result<Geometry1, Geometry2, Strategy>::type + operator()(Geometry2 const& geometry2) const + { + return distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(m_geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename distance_result + < + Geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + >::type + apply( + Geometry1 const& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + } +}; + + +template +< + BOOST_VARIANT_ENUM_PARAMS(typename A), + BOOST_VARIANT_ENUM_PARAMS(typename B) +> +struct distance + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> + > +{ + template <typename Strategy> + struct visitor: static_visitor + < + typename distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + Strategy + >::type + > + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + + template <typename Geometry1, typename Geometry2> + typename distance_result<Geometry1, Geometry2, Strategy>::type + operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const + { + return distance + < + Geometry1, + Geometry2 + >::template apply + < + Strategy + >(geometry1, geometry2, m_strategy); + } + }; + + template <typename Strategy> + static inline typename distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + Strategy + >::type + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + +/*! +\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 distance_result<Geometry1, Geometry2, 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 resolve_variant::distance + < + Geometry1, + Geometry2 + >::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, default_strategy()); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/distance/is_comparable.hpp b/boost/geometry/algorithms/detail/distance/is_comparable.hpp new file mode 100644 index 0000000000..d13cc6c740 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/is_comparable.hpp @@ -0,0 +1,45 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP +#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP + +#include <boost/type_traits/is_same.hpp> + +#include <boost/geometry/strategies/distance.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +// metafunction to determine is a strategy is comparable or not +template <typename Strategy> +struct is_comparable + : boost::is_same + < + Strategy, + typename strategy::distance::services::comparable_type + < + Strategy + >::type + > +{}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP diff --git a/boost/geometry/algorithms/detail/distance/iterator_selector.hpp b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp new file mode 100644 index 0000000000..363ec465a4 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP +#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> +#include <boost/geometry/iterators/segment_iterator.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +// class to choose between point_iterator and segment_iterator +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct iterator_selector +{ + typedef geometry::segment_iterator<Geometry> iterator_type; + + static inline iterator_type begin(Geometry& geometry) + { + return segments_begin(geometry); + } + + static inline iterator_type end(Geometry& geometry) + { + return segments_end(geometry); + } +}; + +template <typename MultiPoint> +struct iterator_selector<MultiPoint, multi_point_tag> +{ + typedef geometry::point_iterator<MultiPoint> iterator_type; + + static inline iterator_type begin(MultiPoint& multipoint) + { + return points_begin(multipoint); + } + + static inline iterator_type end(MultiPoint& multipoint) + { + return points_end(multipoint); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP diff --git a/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp new file mode 100644 index 0000000000..b63104da7d --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp @@ -0,0 +1,147 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/algorithms/intersects.hpp> + +#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template <typename Linear, typename Areal, typename Strategy> +struct linear_to_areal +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Linear>::type, + typename point_type<Areal>::type + >::type return_type; + + static inline return_type apply(Linear const& linear, + Areal const& areal, + Strategy const& strategy) + { + if ( geometry::intersects(linear, areal) ) + { + return 0; + } + + return linear_to_linear + < + Linear, Areal, Strategy + >::apply(linear, areal, strategy, false); + } + + + static inline return_type apply(Areal const& areal, + Linear const& linear, + Strategy const& strategy) + { + return apply(linear, areal, strategy); + } +}; + + +template <typename Areal1, typename Areal2, typename Strategy> +struct areal_to_areal +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Areal1>::type, + typename point_type<Areal2>::type + >::type return_type; + + static inline return_type apply(Areal1 const& areal1, + Areal2 const& areal2, + Strategy const& strategy) + { + if ( geometry::intersects(areal1, areal2) ) + { + return 0; + } + + return linear_to_linear + < + Areal1, Areal2, Strategy + >::apply(areal1, areal2, strategy, false); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Linear, typename Areal, typename Strategy> +struct distance + < + Linear, Areal, Strategy, + linear_tag, areal_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::linear_to_areal + < + Linear, Areal, Strategy + > +{}; + + +template <typename Areal, typename Linear, typename Strategy> +struct distance + < + Areal, Linear, Strategy, + areal_tag, linear_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::linear_to_areal + < + Linear, Areal, Strategy + > +{}; + + +template <typename Areal1, typename Areal2, typename Strategy> +struct distance + < + Areal1, Areal2, Strategy, + areal_tag, areal_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::areal_to_areal + < + Areal1, Areal2, Strategy + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp new file mode 100644 index 0000000000..e44b372842 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp @@ -0,0 +1,123 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> +#include <boost/geometry/iterators/segment_iterator.hpp> + +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/algorithms/num_segments.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template <typename Linear1, typename Linear2, typename Strategy> +struct linear_to_linear +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Linear1>::type, + typename point_type<Linear2>::type + >::type return_type; + + static inline return_type apply(Linear1 const& linear1, + Linear2 const& linear2, + Strategy const& strategy, + bool = false) + { + if (geometry::num_points(linear1) == 1) + { + return dispatch::distance + < + typename point_type<Linear1>::type, + Linear2, + Strategy + >::apply(*points_begin(linear1), linear2, strategy); + } + + if (geometry::num_points(linear2) == 1) + { + return dispatch::distance + < + typename point_type<Linear2>::type, + Linear1, + Strategy + >::apply(*points_begin(linear2), linear1, strategy); + } + + if (geometry::num_segments(linear2) < geometry::num_segments(linear1)) + { + return point_or_segment_range_to_geometry_rtree + < + geometry::segment_iterator<Linear2 const>, + Linear1, + Strategy + >::apply(geometry::segments_begin(linear2), + geometry::segments_end(linear2), + linear1, + strategy); + + } + + return point_or_segment_range_to_geometry_rtree + < + geometry::segment_iterator<Linear1 const>, + Linear2, + Strategy + >::apply(geometry::segments_begin(linear1), + geometry::segments_end(linear1), + linear2, + strategy); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Linear1, typename Linear2, typename Strategy> +struct distance + < + Linear1, Linear2, Strategy, + linear_tag, linear_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::linear_to_linear + < + Linear1, Linear2, Strategy + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp new file mode 100644 index 0000000000..5f2c6e34fb --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp @@ -0,0 +1,240 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template <typename MultiPoint1, typename MultiPoint2, typename Strategy> +struct multipoint_to_multipoint +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<MultiPoint1>::type, + typename point_type<MultiPoint2>::type + >::type return_type; + + static inline return_type apply(MultiPoint1 const& multipoint1, + MultiPoint2 const& multipoint2, + Strategy const& strategy) + { + if (boost::size(multipoint2) < boost::size(multipoint1)) + + { + return point_or_segment_range_to_geometry_rtree + < + typename boost::range_iterator<MultiPoint2 const>::type, + MultiPoint1, + Strategy + >::apply(boost::begin(multipoint2), + boost::end(multipoint2), + multipoint1, + strategy); + } + + return point_or_segment_range_to_geometry_rtree + < + typename boost::range_iterator<MultiPoint1 const>::type, + MultiPoint2, + Strategy + >::apply(boost::begin(multipoint1), + boost::end(multipoint1), + multipoint2, + strategy); + } +}; + + +template <typename MultiPoint, typename Linear, typename Strategy> +struct multipoint_to_linear +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<MultiPoint>::type, + typename point_type<Linear>::type + >::type return_type; + + static inline return_type apply(MultiPoint const& multipoint, + Linear const& linear, + Strategy const& strategy) + { + return detail::distance::point_or_segment_range_to_geometry_rtree + < + typename boost::range_iterator<MultiPoint const>::type, + Linear, + Strategy + >::apply(boost::begin(multipoint), + boost::end(multipoint), + linear, + strategy); + } + + static inline return_type apply(Linear const& linear, + MultiPoint const& multipoint, + Strategy const& strategy) + { + return apply(multipoint, linear, strategy); + } +}; + + +template <typename MultiPoint, typename Areal, typename Strategy> +class multipoint_to_areal +{ +private: + struct within_areal + { + within_areal(Areal const& areal) + : m_areal(areal) + {} + + template <typename Point> + inline bool apply(Point const& point) const + { + return geometry::within(point, m_areal); + } + + Areal const& m_areal; + }; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<MultiPoint>::type, + typename point_type<Areal>::type + >::type return_type; + + static inline return_type apply(MultiPoint const& multipoint, + Areal const& areal, + Strategy const& strategy) + { + within_areal predicate(areal); + + if (check_iterator_range + < + within_areal, false + >::apply(boost::begin(multipoint), + boost::end(multipoint), + predicate)) + { + return 0; + } + + return detail::distance::point_or_segment_range_to_geometry_rtree + < + typename boost::range_iterator<MultiPoint const>::type, + Areal, + Strategy + >::apply(boost::begin(multipoint), + boost::end(multipoint), + areal, + strategy); + } + + static inline return_type apply(Areal const& areal, + MultiPoint const& multipoint, + Strategy const& strategy) + { + return apply(multipoint, areal, strategy); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPoint1, typename MultiPoint2, typename Strategy> +struct distance + < + MultiPoint1, MultiPoint2, Strategy, + multi_point_tag, multi_point_tag, + strategy_tag_distance_point_point, false + > : detail::distance::multipoint_to_multipoint + < + MultiPoint1, MultiPoint2, Strategy + > +{}; + +template <typename MultiPoint, typename Linear, typename Strategy> +struct distance + < + MultiPoint, Linear, Strategy, multi_point_tag, linear_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy> +{}; + + +template <typename Linear, typename MultiPoint, typename Strategy> +struct distance + < + Linear, MultiPoint, Strategy, linear_tag, multi_point_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy> +{}; + + +template <typename MultiPoint, typename Areal, typename Strategy> +struct distance + < + MultiPoint, Areal, Strategy, multi_point_tag, areal_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy> +{}; + + +template <typename Areal, typename MultiPoint, typename Strategy> +struct distance + < + Areal, MultiPoint, Strategy, areal_tag, multi_point_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp new file mode 100644 index 0000000000..ab5de3d9b2 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp @@ -0,0 +1,518 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DISTANCE_POINT_TO_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP + +#include <iterator> + +#include <boost/core/ignore_unused.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> +#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template <typename P1, typename P2, typename Strategy> +struct point_to_point +{ + static inline + typename strategy::distance::services::return_type<Strategy, P1, P2>::type + apply(P1 const& p1, P2 const& p2, Strategy const& strategy) + { + boost::ignore_unused(strategy); + return strategy.apply(p1, p2); + } +}; + + +template +< + typename Point, + typename Range, + closure_selector Closure, + typename Strategy +> +class point_to_range +{ +private: + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef detail::closest_feature::point_to_point_range + < + Point, Range, Closure, comparable_strategy + > point_to_point_range; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + Point, + typename boost::range_value<Range>::type + >::type return_type; + + static inline return_type apply(Point const& point, Range const& range, + Strategy const& strategy) + { + return_type const zero = return_type(0); + + if (boost::size(range) == 0) + { + return zero; + } + + namespace sds = strategy::distance::services; + + typename sds::return_type + < + comparable_strategy, + Point, + typename point_type<Range>::type + >::type cd_min; + + std::pair + < + typename boost::range_iterator<Range const>::type, + typename boost::range_iterator<Range const>::type + > it_pair + = point_to_point_range::apply(point, + boost::begin(range), + boost::end(range), + sds::get_comparable + < + Strategy + >::apply(strategy), + cd_min); + + return + is_comparable<Strategy>::value + ? + cd_min + : + strategy.apply(point, *it_pair.first, *it_pair.second); + } +}; + + +template +< + typename Point, + typename Ring, + closure_selector Closure, + typename Strategy +> +struct point_to_ring +{ + typedef typename strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Ring>::type + >::type return_type; + + static inline return_type apply(Point const& point, + Ring const& ring, + Strategy const& strategy) + { + if (geometry::within(point, ring)) + { + return return_type(0); + } + + return point_to_range + < + Point, Ring, closure<Ring>::value, Strategy + >::apply(point, ring, strategy); + } +}; + + +template +< + typename Point, + typename Polygon, + closure_selector Closure, + typename Strategy +> +class point_to_polygon +{ +public: + typedef typename strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Polygon>::type + >::type return_type; + +private: + typedef point_to_range + < + Point, typename ring_type<Polygon>::type, Closure, Strategy + > per_ring; + + struct distance_to_interior_rings + { + template <typename InteriorRingIterator> + static inline return_type apply(Point const& point, + InteriorRingIterator first, + InteriorRingIterator last, + Strategy const& strategy) + { + for (InteriorRingIterator it = first; it != last; ++it) + { + if (geometry::within(point, *it)) + { + // the point is inside a polygon hole, so its distance + // to the polygon its distance to the polygon's + // hole boundary + return per_ring::apply(point, *it, strategy); + } + } + return 0; + } + + template <typename InteriorRings> + static inline return_type apply(Point const& point, + InteriorRings const& interior_rings, + Strategy const& strategy) + { + return apply(point, + boost::begin(interior_rings), + boost::end(interior_rings), + strategy); + } + }; + + +public: + static inline return_type apply(Point const& point, + Polygon const& polygon, + Strategy const& strategy) + { + if (!geometry::covered_by(point, exterior_ring(polygon))) + { + // the point is outside the exterior ring, so its distance + // to the polygon is its distance to the polygon's exterior ring + return per_ring::apply(point, exterior_ring(polygon), strategy); + } + + // Check interior rings + return distance_to_interior_rings::apply(point, + interior_rings(polygon), + strategy); + } +}; + + +template +< + typename Point, + typename MultiGeometry, + typename Strategy, + bool CheckCoveredBy = boost::is_same + < + typename tag<MultiGeometry>::type, multi_polygon_tag + >::value +> +class point_to_multigeometry +{ +private: + typedef detail::closest_feature::geometry_to_range geometry_to_range; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + Point, + typename point_type<MultiGeometry>::type + >::type return_type; + + static inline return_type apply(Point const& point, + MultiGeometry const& multigeometry, + Strategy const& strategy) + { + typedef iterator_selector<MultiGeometry const> selector_type; + + namespace sds = strategy::distance::services; + + typename sds::return_type + < + typename sds::comparable_type<Strategy>::type, + Point, + typename point_type<MultiGeometry>::type + >::type cd; + + typename selector_type::iterator_type it_min + = geometry_to_range::apply(point, + selector_type::begin(multigeometry), + selector_type::end(multigeometry), + sds::get_comparable + < + Strategy + >::apply(strategy), + cd); + + return + is_comparable<Strategy>::value + ? + cd + : + dispatch::distance + < + Point, + typename std::iterator_traits + < + typename selector_type::iterator_type + >::value_type, + Strategy + >::apply(point, *it_min, strategy); + } +}; + + +// this is called only for multipolygons, hence the change in the +// template parameter name MultiGeometry to MultiPolygon +template <typename Point, typename MultiPolygon, typename Strategy> +struct point_to_multigeometry<Point, MultiPolygon, Strategy, true> +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + Point, + typename point_type<MultiPolygon>::type + >::type return_type; + + static inline return_type apply(Point const& point, + MultiPolygon const& multipolygon, + Strategy const& strategy) + { + if (geometry::covered_by(point, multipolygon)) + { + return 0; + } + + return point_to_multigeometry + < + Point, MultiPolygon, Strategy, false + >::apply(point, multipolygon, strategy); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// 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 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 + > : detail::distance::point_to_range<Point, Linestring, closed, 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_segment, false + > : detail::distance::point_to_ring + < + Point, Ring, closure<Ring>::value, Strategy + > +{}; + + +// 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_segment, false + > : detail::distance::point_to_polygon + < + Point, Polygon, closure<Polygon>::value, 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 strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Segment>::type + >::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]); + + boost::ignore_unused(strategy); + return strategy.apply(point, p[0], p[1]); + } +}; + + +template <typename Point, typename Box, typename Strategy> +struct distance + < + Point, Box, Strategy, point_tag, box_tag, + strategy_tag_distance_point_box, false + > +{ + static inline typename strategy::distance::services::return_type + < + Strategy, Point, typename point_type<Box>::type + >::type + apply(Point const& point, Box const& box, Strategy const& strategy) + { + boost::ignore_unused(strategy); + return strategy.apply(point, box); + } +}; + + +template<typename Point, typename MultiPoint, typename Strategy> +struct distance + < + Point, MultiPoint, Strategy, point_tag, multi_point_tag, + strategy_tag_distance_point_point, false + > : detail::distance::point_to_multigeometry + < + Point, MultiPoint, Strategy + > +{}; + + +template<typename Point, typename MultiLinestring, typename Strategy> +struct distance + < + Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::point_to_multigeometry + < + Point, MultiLinestring, Strategy + > +{}; + + +template<typename Point, typename MultiPolygon, typename Strategy> +struct distance + < + Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag, + strategy_tag_distance_point_segment, false + > : detail::distance::point_to_multigeometry + < + Point, MultiPolygon, Strategy + > +{}; + + +template <typename Point, typename Linear, typename Strategy> +struct distance + < + Point, Linear, Strategy, point_tag, linear_tag, + strategy_tag_distance_point_segment, false + > : distance + < + Point, Linear, Strategy, + point_tag, typename tag<Linear>::type, + strategy_tag_distance_point_segment, false + > +{}; + + +template <typename Point, typename Areal, typename Strategy> +struct distance + < + Point, Areal, Strategy, point_tag, areal_tag, + strategy_tag_distance_point_segment, false + > : distance + < + Point, Areal, Strategy, + point_tag, typename tag<Areal>::type, + strategy_tag_distance_point_segment, false + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp new file mode 100644 index 0000000000..78189794a1 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp @@ -0,0 +1,131 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP + +#include <iterator> +#include <utility> + +#include <boost/assert.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/iterators/has_one_element.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template +< + typename PointOrSegmentIterator, + typename Geometry, + typename Strategy +> +class point_or_segment_range_to_geometry_rtree +{ +private: + typedef typename std::iterator_traits + < + PointOrSegmentIterator + >::value_type point_or_segment_type; + + typedef iterator_selector<Geometry const> selector_type; + + typedef detail::closest_feature::range_to_range_rtree range_to_range; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<point_or_segment_type>::type, + typename point_type<Geometry>::type + >::type return_type; + + static inline return_type apply(PointOrSegmentIterator first, + PointOrSegmentIterator last, + Geometry const& geometry, + Strategy const& strategy) + { + namespace sds = strategy::distance::services; + + BOOST_ASSERT( first != last ); + + if ( geometry::has_one_element(first, last) ) + { + return dispatch::distance + < + point_or_segment_type, Geometry, Strategy + >::apply(*first, geometry, strategy); + } + + typename sds::return_type + < + typename sds::comparable_type<Strategy>::type, + typename point_type<point_or_segment_type>::type, + typename point_type<Geometry>::type + >::type cd_min; + + std::pair + < + point_or_segment_type, + typename selector_type::iterator_type + > closest_features + = range_to_range::apply(first, + last, + selector_type::begin(geometry), + selector_type::end(geometry), + sds::get_comparable + < + Strategy + >::apply(strategy), + cd_min); + + return + is_comparable<Strategy>::value + ? + cd_min + : + dispatch::distance + < + point_or_segment_type, + typename std::iterator_traits + < + typename selector_type::iterator_type + >::value_type, + Strategy + >::apply(closest_features.first, + *closest_features.second, + strategy); + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp new file mode 100644 index 0000000000..f64a3e9fca --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp @@ -0,0 +1,886 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP + +#include <cstddef> + +#include <functional> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/core/ignore_unused.hpp> +#include <boost/mpl/if.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/calculation_type.hpp> +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/policies/compare.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/algorithms/detail/assign_box_corners.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template +< + typename Segment, + typename Box, + typename Strategy, + bool UsePointBoxStrategy = false +> +class segment_to_box_2D_generic +{ +private: + typedef typename point_type<Segment>::type segment_point; + typedef typename point_type<Box>::type box_point; + + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef detail::closest_feature::point_to_point_range + < + segment_point, + std::vector<box_point>, + open, + comparable_strategy + > point_to_point_range; + + typedef typename strategy::distance::services::return_type + < + comparable_strategy, segment_point, box_point + >::type comparable_return_type; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, segment_point, box_point + >::type return_type; + + static inline return_type apply(Segment const& segment, + Box const& box, + Strategy const& strategy, + bool check_intersection = true) + { + if (check_intersection && geometry::intersects(segment, box)) + { + return 0; + } + + comparable_strategy cstrategy = + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy); + + // get segment points + segment_point p[2]; + detail::assign_point_from_index<0>(segment, p[0]); + detail::assign_point_from_index<1>(segment, p[1]); + + // get box points + std::vector<box_point> box_points(4); + detail::assign_box_corners_oriented<true>(box, box_points); + + comparable_return_type cd[6]; + for (unsigned int i = 0; i < 4; ++i) + { + cd[i] = cstrategy.apply(box_points[i], p[0], p[1]); + } + + std::pair + < + typename std::vector<box_point>::const_iterator, + typename std::vector<box_point>::const_iterator + > bit_min[2]; + + bit_min[0] = point_to_point_range::apply(p[0], + box_points.begin(), + box_points.end(), + cstrategy, + cd[4]); + bit_min[1] = point_to_point_range::apply(p[1], + box_points.begin(), + box_points.end(), + cstrategy, + cd[5]); + + unsigned int imin = 0; + for (unsigned int i = 1; i < 6; ++i) + { + if (cd[i] < cd[imin]) + { + imin = i; + } + } + + if (is_comparable<Strategy>::value) + { + return cd[imin]; + } + + if (imin < 4) + { + return strategy.apply(box_points[imin], p[0], p[1]); + } + else + { + unsigned int bimin = imin - 4; + return strategy.apply(p[bimin], + *bit_min[bimin].first, + *bit_min[bimin].second); + } + } +}; + + +template +< + typename Segment, + typename Box, + typename Strategy +> +class segment_to_box_2D_generic<Segment, Box, Strategy, true> +{ +private: + typedef typename point_type<Segment>::type segment_point; + typedef typename point_type<Box>::type box_point; + + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef typename strategy::distance::services::return_type + < + comparable_strategy, segment_point, box_point + >::type comparable_return_type; + + typedef typename detail::distance::default_strategy + < + segment_point, Box + >::type point_box_strategy; + + typedef typename strategy::distance::services::comparable_type + < + point_box_strategy + >::type point_box_comparable_strategy; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, segment_point, box_point + >::type return_type; + + static inline return_type apply(Segment const& segment, + Box const& box, + Strategy const& strategy, + bool check_intersection = true) + { + if (check_intersection && geometry::intersects(segment, box)) + { + return 0; + } + + comparable_strategy cstrategy = + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy); + boost::ignore_unused(cstrategy); + + // get segment points + segment_point p[2]; + detail::assign_point_from_index<0>(segment, p[0]); + detail::assign_point_from_index<1>(segment, p[1]); + + // get box points + std::vector<box_point> box_points(4); + detail::assign_box_corners_oriented<true>(box, box_points); + + comparable_return_type cd[6]; + for (unsigned int i = 0; i < 4; ++i) + { + cd[i] = cstrategy.apply(box_points[i], p[0], p[1]); + } + + point_box_comparable_strategy pb_cstrategy; + boost::ignore_unused(pb_cstrategy); + cd[4] = pb_cstrategy.apply(p[0], box); + cd[5] = pb_cstrategy.apply(p[1], box); + + unsigned int imin = 0; + for (unsigned int i = 1; i < 6; ++i) + { + if (cd[i] < cd[imin]) + { + imin = i; + } + } + + if (is_comparable<Strategy>::value) + { + return cd[imin]; + } + + if (imin < 4) + { + strategy.apply(box_points[imin], p[0], p[1]); + } + else + { + return point_box_strategy().apply(p[imin - 4], box); + } + } +}; + + + + +template +< + typename ReturnType, + typename SegmentPoint, + typename BoxPoint, + typename PPStrategy, + typename PSStrategy +> +class segment_to_box_2D +{ +private: + template <typename Result> + struct cast_to_result + { + template <typename T> + static inline Result apply(T const& t) + { + return boost::numeric_cast<Result>(t); + } + }; + + + template <typename T, bool IsLess /* true */> + struct compare_less_equal + { + typedef compare_less_equal<T, !IsLess> other; + + template <typename T1, typename T2> + inline bool operator()(T1 const& t1, T2 const& t2) const + { + return std::less_equal<T>()(cast_to_result<T>::apply(t1), + cast_to_result<T>::apply(t2)); + } + }; + + template <typename T> + struct compare_less_equal<T, false> + { + typedef compare_less_equal<T, true> other; + + template <typename T1, typename T2> + inline bool operator()(T1 const& t1, T2 const& t2) const + { + return std::greater_equal<T>()(cast_to_result<T>::apply(t1), + cast_to_result<T>::apply(t2)); + } + }; + + + template <typename LessEqual> + struct other_compare + { + typedef typename LessEqual::other type; + }; + + + // it is assumed here that p0 lies to the right of the box (so the + // entire segment lies to the right of the box) + template <typename LessEqual> + struct right_of_box + { + static inline ReturnType apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& bottom_right, + BoxPoint const& top_right, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy) + { + boost::ignore_unused(pp_strategy, ps_strategy); + + // the implementation below is written for non-negative slope + // segments + // + // for negative slope segments swap the roles of bottom_right + // and top_right and use greater_equal instead of less_equal. + + typedef cast_to_result<ReturnType> cast; + + LessEqual less_equal; + + if (less_equal(geometry::get<1>(top_right), geometry::get<1>(p0))) + { + // closest box point is the top-right corner + return cast::apply(pp_strategy.apply(p0, top_right)); + } + else if (less_equal(geometry::get<1>(bottom_right), + geometry::get<1>(p0))) + { + // distance is realized between p0 and right-most + // segment of box + ReturnType diff = cast::apply(geometry::get<0>(p0)) + - cast::apply(geometry::get<0>(bottom_right)); + return strategy::distance::services::result_from_distance + < + PSStrategy, BoxPoint, SegmentPoint + >::apply(ps_strategy, math::abs(diff)); + } + else + { + // distance is realized between the bottom-right + // corner of the box and the segment + return cast::apply(ps_strategy.apply(bottom_right, p0, p1)); + } + } + }; + + + // it is assumed here that p0 lies above the box (so the + // entire segment lies above the box) + template <typename LessEqual> + struct above_of_box + { + static inline ReturnType apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + PSStrategy const& ps_strategy) + { + boost::ignore_unused(ps_strategy); + + // the segment lies above the box + + typedef cast_to_result<ReturnType> cast; + + LessEqual less_equal; + + // p0 is above the upper segment of the box + // (and inside its band) + if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p0))) + { + ReturnType diff = cast::apply(geometry::get<1>(p0)) + - cast::apply(geometry::get<1>(top_left)); + return strategy::distance::services::result_from_distance + < + PSStrategy, SegmentPoint, BoxPoint + >::apply(ps_strategy, math::abs(diff)); + } + + // p0 is to the left of the box, but p1 is above the box + // in this case the distance is realized between the + // top-left corner of the box and the segment + return cast::apply(ps_strategy.apply(top_left, p0, p1)); + } + }; + + + template <typename LessEqual> + struct check_right_left_of_box + { + static inline bool apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + BoxPoint const& top_right, + BoxPoint const& bottom_left, + BoxPoint const& bottom_right, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy, + ReturnType& result) + { + // p0 lies to the right of the box + if (geometry::get<0>(p0) >= geometry::get<0>(top_right)) + { + result = right_of_box + < + LessEqual + >::apply(p0, p1, bottom_right, top_right, + pp_strategy, ps_strategy); + return true; + } + + // p1 lies to the left of the box + if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left)) + { + result = right_of_box + < + typename other_compare<LessEqual>::type + >::apply(p1, p0, top_left, bottom_left, + pp_strategy, ps_strategy); + return true; + } + + return false; + } + }; + + + template <typename LessEqual> + struct check_above_below_of_box + { + static inline bool apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + BoxPoint const& top_right, + BoxPoint const& bottom_left, + BoxPoint const& bottom_right, + PSStrategy const& ps_strategy, + ReturnType& result) + { + // the segment lies below the box + if (geometry::get<1>(p1) < geometry::get<1>(bottom_left)) + { + result = above_of_box + < + typename other_compare<LessEqual>::type + >::apply(p1, p0, bottom_right, ps_strategy); + return true; + } + + // the segment lies above the box + if (geometry::get<1>(p0) > geometry::get<1>(top_right)) + { + result = above_of_box + < + LessEqual + >::apply(p0, p1, top_left, ps_strategy); + return true; + } + return false; + } + }; + + struct check_generic_position + { + static inline bool apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& bottom_left0, + BoxPoint const& top_right0, + BoxPoint const& bottom_left1, + BoxPoint const& top_right1, + BoxPoint const& corner1, + BoxPoint const& corner2, + PSStrategy const& ps_strategy, + ReturnType& result) + { + typedef cast_to_result<ReturnType> cast; + + ReturnType diff0 = cast::apply(geometry::get<0>(p1)) + - cast::apply(geometry::get<0>(p0)); + ReturnType t_min0 = cast::apply(geometry::get<0>(bottom_left0)) + - cast::apply(geometry::get<0>(p0)); + ReturnType t_max0 = cast::apply(geometry::get<0>(top_right0)) + - cast::apply(geometry::get<0>(p0)); + + ReturnType diff1 = cast::apply(geometry::get<1>(p1)) + - cast::apply(geometry::get<1>(p0)); + ReturnType t_min1 = cast::apply(geometry::get<1>(bottom_left1)) + - cast::apply(geometry::get<1>(p0)); + ReturnType t_max1 = cast::apply(geometry::get<1>(top_right1)) + - cast::apply(geometry::get<1>(p0)); + + if (diff1 < 0) + { + diff1 = -diff1; + t_min1 = -t_min1; + t_max1 = -t_max1; + } + + // t_min0 > t_max1 + if (t_min0 * diff1 > t_max1 * diff0) + { + result = cast::apply(ps_strategy.apply(corner1, p0, p1)); + return true; + } + + // t_max0 < t_min1 + if (t_max0 * diff1 < t_min1 * diff0) + { + result = cast::apply(ps_strategy.apply(corner2, p0, p1)); + return true; + } + return false; + } + }; + + static inline ReturnType + non_negative_slope_segment(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + BoxPoint const& top_right, + BoxPoint const& bottom_left, + BoxPoint const& bottom_right, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy) + { + typedef compare_less_equal<ReturnType, true> less_equal; + + // assert that the segment has non-negative slope + BOOST_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1)) + && geometry::get<1>(p0) < geometry::get<1>(p1)) + || + ( geometry::get<0>(p0) < geometry::get<0>(p1) + && geometry::get<1>(p0) <= geometry::get<1>(p1) ) + ); + + ReturnType result(0); + + if (check_right_left_of_box + < + less_equal + >::apply(p0, p1, + top_left, top_right, bottom_left, bottom_right, + pp_strategy, ps_strategy, result)) + { + return result; + } + + if (check_above_below_of_box + < + less_equal + >::apply(p0, p1, + top_left, top_right, bottom_left, bottom_right, + ps_strategy, result)) + { + return result; + } + + if (check_generic_position::apply(p0, p1, + bottom_left, top_right, + bottom_left, top_right, + top_left, bottom_right, + ps_strategy, result)) + { + return result; + } + + // in all other cases the box and segment intersect, so return 0 + return result; + } + + + static inline ReturnType + negative_slope_segment(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + BoxPoint const& top_right, + BoxPoint const& bottom_left, + BoxPoint const& bottom_right, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy) + { + typedef compare_less_equal<ReturnType, false> greater_equal; + + // assert that the segment has negative slope + BOOST_ASSERT( geometry::get<0>(p0) < geometry::get<0>(p1) + && geometry::get<1>(p0) > geometry::get<1>(p1) ); + + ReturnType result(0); + + if (check_right_left_of_box + < + greater_equal + >::apply(p0, p1, + bottom_left, bottom_right, top_left, top_right, + pp_strategy, ps_strategy, result)) + { + return result; + } + + if (check_above_below_of_box + < + greater_equal + >::apply(p1, p0, + top_right, top_left, bottom_right, bottom_left, + ps_strategy, result)) + { + return result; + } + + if (check_generic_position::apply(p0, p1, + bottom_left, top_right, + top_right, bottom_left, + bottom_left, top_right, + ps_strategy, result)) + { + return result; + } + + // in all other cases the box and segment intersect, so return 0 + return result; + } + +public: + static inline ReturnType apply(SegmentPoint const& p0, + SegmentPoint const& p1, + BoxPoint const& top_left, + BoxPoint const& top_right, + BoxPoint const& bottom_left, + BoxPoint const& bottom_right, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy) + { + BOOST_ASSERT( geometry::less<SegmentPoint>()(p0, p1) ); + + if (geometry::get<0>(p0) < geometry::get<0>(p1) + && geometry::get<1>(p0) > geometry::get<1>(p1)) + { + return negative_slope_segment(p0, p1, + top_left, top_right, + bottom_left, bottom_right, + pp_strategy, ps_strategy); + } + + return non_negative_slope_segment(p0, p1, + top_left, top_right, + bottom_left, bottom_right, + pp_strategy, ps_strategy); + } +}; + + +//========================================================================= + + +template +< + typename Segment, + typename Box, + typename std::size_t Dimension, + typename PPStrategy, + typename PSStrategy +> +class segment_to_box + : not_implemented<Segment, Box> +{}; + + +template +< + typename Segment, + typename Box, + typename PPStrategy, + typename PSStrategy +> +class segment_to_box<Segment, Box, 2, PPStrategy, PSStrategy> +{ +private: + typedef typename point_type<Segment>::type segment_point; + typedef typename point_type<Box>::type box_point; + + typedef typename strategy::distance::services::comparable_type + < + PPStrategy + >::type pp_comparable_strategy; + + typedef typename strategy::distance::services::comparable_type + < + PSStrategy + >::type ps_comparable_strategy; + + typedef typename strategy::distance::services::return_type + < + ps_comparable_strategy, segment_point, box_point + >::type comparable_return_type; +public: + typedef typename strategy::distance::services::return_type + < + PSStrategy, segment_point, box_point + >::type return_type; + + static inline return_type apply(Segment const& segment, + Box const& box, + PPStrategy const& pp_strategy, + PSStrategy const& ps_strategy) + { + segment_point p[2]; + detail::assign_point_from_index<0>(segment, p[0]); + detail::assign_point_from_index<1>(segment, p[1]); + + if (geometry::equals(p[0], p[1])) + { + typedef typename boost::mpl::if_ + < + boost::is_same + < + ps_comparable_strategy, + PSStrategy + >, + typename strategy::distance::services::comparable_type + < + typename detail::distance::default_strategy + < + segment_point, Box + >::type + >::type, + typename detail::distance::default_strategy + < + segment_point, Box + >::type + >::type point_box_strategy_type; + + return dispatch::distance + < + segment_point, + Box, + point_box_strategy_type + >::apply(p[0], box, point_box_strategy_type()); + } + + box_point top_left, top_right, bottom_left, bottom_right; + detail::assign_box_corners(box, bottom_left, bottom_right, + top_left, top_right); + + if (geometry::less<segment_point>()(p[0], p[1])) + { + return segment_to_box_2D + < + return_type, + segment_point, + box_point, + PPStrategy, + PSStrategy + >::apply(p[0], p[1], + top_left, top_right, bottom_left, bottom_right, + pp_strategy, + ps_strategy); + } + else + { + return segment_to_box_2D + < + return_type, + segment_point, + box_point, + PPStrategy, + PSStrategy + >::apply(p[1], p[0], + top_left, top_right, bottom_left, bottom_right, + pp_strategy, + ps_strategy); + } + } +}; + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Segment, typename Box, typename Strategy> +struct distance + < + Segment, Box, Strategy, segment_tag, box_tag, + strategy_tag_distance_point_segment, false + > +{ + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Segment>::type, + typename point_type<Box>::type + >::type return_type; + + + static inline return_type apply(Segment const& segment, + Box const& box, + Strategy const& strategy) + { + assert_dimension_equal<Segment, Box>(); + + typedef typename boost::mpl::if_ + < + boost::is_same + < + typename strategy::distance::services::comparable_type + < + Strategy + >::type, + Strategy + >, + typename strategy::distance::services::comparable_type + < + typename detail::distance::default_strategy + < + typename point_type<Segment>::type, + typename point_type<Box>::type + >::type + >::type, + typename detail::distance::default_strategy + < + typename point_type<Segment>::type, + typename point_type<Box>::type + >::type + >::type pp_strategy_type; + + + return detail::distance::segment_to_box + < + Segment, + Box, + dimension<Segment>::value, + pp_strategy_type, + Strategy + >::apply(segment, box, pp_strategy_type(), strategy); + } +}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP diff --git a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp new file mode 100644 index 0000000000..2dcde64946 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp @@ -0,0 +1,150 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP + +#include <algorithm> +#include <iterator> + +#include <boost/core/addressof.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/intersects.hpp> + +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + + +// compute segment-segment distance +template<typename Segment1, typename Segment2, typename Strategy> +class segment_to_segment +{ +private: + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef typename strategy::distance::services::return_type + < + comparable_strategy, + typename point_type<Segment1>::type, + typename point_type<Segment2>::type + >::type comparable_return_type; + +public: + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type<Segment1>::type, + typename point_type<Segment2>::type + >::type return_type; + + static inline return_type + apply(Segment1 const& segment1, Segment2 const& segment2, + Strategy const& strategy) + { + if (geometry::intersects(segment1, segment2)) + { + return 0; + } + + typename point_type<Segment1>::type p[2]; + detail::assign_point_from_index<0>(segment1, p[0]); + detail::assign_point_from_index<1>(segment1, p[1]); + + typename point_type<Segment2>::type q[2]; + detail::assign_point_from_index<0>(segment2, q[0]); + detail::assign_point_from_index<1>(segment2, q[1]); + + comparable_strategy cstrategy = + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy); + + comparable_return_type d[4]; + d[0] = cstrategy.apply(q[0], p[0], p[1]); + d[1] = cstrategy.apply(q[1], p[0], p[1]); + d[2] = cstrategy.apply(p[0], q[0], q[1]); + d[3] = cstrategy.apply(p[1], q[0], q[1]); + + std::size_t imin = std::distance(boost::addressof(d[0]), + std::min_element(d, d + 4)); + + if (is_comparable<Strategy>::value) + { + return d[imin]; + } + + switch (imin) + { + case 0: + return strategy.apply(q[0], p[0], p[1]); + case 1: + return strategy.apply(q[1], p[0], p[1]); + case 2: + return strategy.apply(p[0], q[0], q[1]); + default: + return strategy.apply(p[1], q[0], q[1]); + } + } +}; + + + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + + +// segment-segment +template <typename Segment1, typename Segment2, typename Strategy> +struct distance + < + Segment1, Segment2, Strategy, segment_tag, segment_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::segment_to_segment<Segment1, Segment2, Strategy> +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index 9c2fe28057..5bcb5ffaa0 100644 --- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -17,12 +18,13 @@ #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/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tags.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/math.hpp> @@ -75,9 +77,9 @@ struct collected_vector inline bool same_direction(collected_vector<T> const& other) const { - // For high precision arithmetic, we have to be + // 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) ) + // 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); @@ -111,6 +113,9 @@ struct range_collect_vectors return; } + typedef typename boost::range_size<Collection>::type collection_size_t; + collection_size_t c_old_size = boost::size(collection); + typedef typename boost::range_iterator<Range const>::type iterator; bool first = true; @@ -131,7 +136,7 @@ struct range_collect_vectors // Normalize the vector -> this results in points+direction // and is comparible between geometries - calculation_type magnitude = sqrt( + calculation_type magnitude = math::sqrt( boost::numeric_cast<calculation_type>(v.dx * v.dx + v.dy * v.dy)); // Avoid non-duplicate points (AND division by zero) @@ -150,10 +155,19 @@ struct range_collect_vectors } // If first one has same direction as last one, remove first one - if (boost::size(collection) > 1 - && collection.front().same_direction(collection.back())) + collection_size_t collected_count = boost::size(collection) - c_old_size; + if ( collected_count > 1 ) { - collection.erase(collection.begin()); + typedef typename boost::range_iterator<Collection>::type c_iterator; + c_iterator first = collection.begin() + c_old_size; + + if ( first->same_direction(collection.back()) ) + { + //collection.erase(first); + // O(1) instead of O(N) + *first = collection.back(); + collection.pop_back(); + } } } }; @@ -194,9 +208,10 @@ struct polygon_collect_vectors 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { per_range::apply(collection, *it); } diff --git a/boost/geometry/algorithms/detail/equals/point_point.hpp b/boost/geometry/algorithms/detail/equals/point_point.hpp new file mode 100644 index 0000000000..12daa85e9d --- /dev/null +++ b/boost/geometry/algorithms/detail/equals/point_point.hpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_POINT_POINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP + +#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> + + +namespace boost { namespace geometry +{ + + +#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_EQUALS_POINT_POINT_HPP diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp new file mode 100644 index 0000000000..61839d296a --- /dev/null +++ b/boost/geometry/algorithms/detail/extreme_points.hpp @@ -0,0 +1,520 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 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_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP + + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/iterators/ever_circling_iterator.hpp> + +#include <boost/geometry/algorithms/detail/assign_box_corners.hpp> + +#include <boost/geometry/strategies/side.hpp> + +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace extreme_points +{ + +template <std::size_t Dimension> +struct compare +{ + template <typename Point> + inline bool operator()(Point const& lhs, Point const& rhs) + { + return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs); + } +}; + + +template <std::size_t Dimension, typename PointType, typename CoordinateType> +inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value) +{ + // Moves a point along the vector (point, extreme) in the direction of the extreme point + // This adapts the possibly uneven legs of the triangle (or trapezium-like shape) + // _____extreme _____ + // / \ / \ . + // /base \ => / \ point . + // \ point . + // + // For so-called intruders, it can be used to adapt both legs to the level of "base" + // For the base, it can be used to adapt both legs to the level of the max-value of the intruders + // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector + + CoordinateType const value = geometry::get<Dimension>(point); + //if (geometry::math::equals(value, base_value)) + if (value >= base_value) + { + return; + } + + PointType vector = point; + subtract_point(vector, extreme); + + CoordinateType const diff = geometry::get<Dimension>(vector); + + // diff should never be zero + // because of the way our triangle/trapezium is build. + // We just return if it would be the case. + if (geometry::math::equals(diff, 0)) + { + return; + } + + CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme); + + multiply_value(vector, base_diff); + divide_value(vector, diff); + + // The real move: + point = extreme; + add_point(point, vector); +} + + +template <std::size_t Dimension, typename Range, typename CoordinateType> +inline void move_along_vector(Range& range, CoordinateType const& base_value) +{ + if (range.size() >= 3) + { + move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value); + move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value); + } +} + + +template<typename Ring, std::size_t Dimension> +struct extreme_points_on_ring +{ + + typedef typename geometry::coordinate_type<Ring>::type coordinate_type; + typedef typename boost::range_iterator<Ring const>::type range_iterator; + typedef typename geometry::point_type<Ring>::type point_type; + + typedef typename geometry::strategy::side::services::default_strategy + < + typename geometry::cs_tag<point_type>::type + >::type side_strategy; + + + template <typename CirclingIterator, typename Points> + static inline bool extend(CirclingIterator& it, + std::size_t n, + coordinate_type max_coordinate_value, + Points& points, int direction) + { + std::size_t safe_index = 0; + do + { + it += direction; + + points.push_back(*it); + + if (safe_index++ >= n) + { + // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop) + return false; + } + } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value)); + + return true; + } + + // Overload without adding to poinst + template <typename CirclingIterator> + static inline bool extend(CirclingIterator& it, + std::size_t n, + coordinate_type max_coordinate_value, + int direction) + { + std::size_t safe_index = 0; + do + { + it += direction; + + if (safe_index++ >= n) + { + // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop) + return false; + } + } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value)); + + return true; + } + + template <typename CirclingIterator> + static inline bool extent_both_sides(Ring const& ring, + point_type extreme, + CirclingIterator& left, + CirclingIterator& right) + { + std::size_t const n = boost::size(ring); + coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme); + + if (! extend(left, n, max_coordinate_value, -1)) + { + return false; + } + if (! extend(right, n, max_coordinate_value, +1)) + { + return false; + } + + return true; + } + + template <typename Collection, typename CirclingIterator> + static inline bool collect(Ring const& ring, + point_type extreme, + Collection& points, + CirclingIterator& left, + CirclingIterator& right) + { + std::size_t const n = boost::size(ring); + coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme); + + // Collects first left, which is reversed (if more than one point) then adds the top itself, then right + if (! extend(left, n, max_coordinate_value, points, -1)) + { + return false; + } + std::reverse(points.begin(), points.end()); + points.push_back(extreme); + if (! extend(right, n, max_coordinate_value, points, +1)) + { + return false; + } + + return true; + } + + template <typename Extremes, typename Intruders, typename CirclingIterator> + static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right, + Extremes const& extremes, + Intruders& intruders) + { + if (boost::size(extremes) < 3) + { + return; + } + coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>())); + + // Also select left/right (if Dimension=1) + coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>())); + coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>())); + + std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too + std::size_t const n = boost::size(ring); + while (left != right && defensive_check_index < n) + { + coordinate_type const coordinate = geometry::get<Dimension>(*right); + coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right); + if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max) + { + int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1; + int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor; + int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor; + + // If not lying left from any of the extemes side + if (first_side != 1 && last_side != 1) + { + //std::cout << "first " << first_side << " last " << last_side << std::endl; + + // we start at this intrusion until it is handled, and don't affect our initial left iterator + CirclingIterator left_intrusion_it = right; + typename boost::range_value<Intruders>::type intruder; + collect(ring, *right, intruder, left_intrusion_it, right); + + // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies + // (we might postpone this action, it is often not necessary. However it is not time-consuming) + move_along_vector<Dimension>(intruder, min_value); + intruders.push_back(intruder); + --right; + } + } + ++right; + defensive_check_index++; + } + } + + template <typename Extremes, typename Intruders> + static inline void get_intruders(Ring const& ring, + Extremes const& extremes, + Intruders& intruders) + { + std::size_t const n = boost::size(ring); + if (n >= 3) + { + geometry::ever_circling_range_iterator<Ring const> left(ring); + geometry::ever_circling_range_iterator<Ring const> right(ring); + ++right; + + get_intruders(ring, left, right, extremes, intruders); + } + } + + template <typename Iterator> + static inline bool right_turn(Ring const& ring, Iterator it) + { + typename std::iterator_traits<Iterator>::difference_type const index + = std::distance(boost::begin(ring), it); + geometry::ever_circling_range_iterator<Ring const> left(ring); + geometry::ever_circling_range_iterator<Ring const> right(ring); + left += index; + right += index; + + if (! extent_both_sides(ring, *it, left, right)) + { + return false; + } + + int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1; + int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor; + int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor; + +//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl; + + // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases) + return first_side != 1 && last_side != 1; + } + + + // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring + template <typename Extremes, typename Intruders> + static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders) + { + std::size_t const n = boost::size(ring); + if (n < 3) + { + return false; + } + + // Get all maxima, usually one. In case of self-tangencies, or self-crossings, + // the max might be is not valid. A valid max should make a right turn + range_iterator max_it = boost::begin(ring); + compare<Dimension> smaller; + for (range_iterator it = max_it + 1; it != boost::end(ring); ++it) + { + if (smaller(*max_it, *it) && right_turn(ring, it)) + { + max_it = it; + } + } + + if (max_it == boost::end(ring)) + { + return false; + } + + typename std::iterator_traits<range_iterator>::difference_type const + index = std::distance(boost::begin(ring), max_it); +//std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl; + + geometry::ever_circling_range_iterator<Ring const> left(ring); + geometry::ever_circling_range_iterator<Ring const> right(ring); + left += index; + right += index; + + // Collect all points (often 3) in a temporary vector + std::vector<point_type> points; + points.reserve(3); + if (! collect(ring, *max_it, points, left, right)) + { + return false; + } + +//std::cout << "Built vector of " << points.size() << std::endl; + + coordinate_type const front_value = geometry::get<Dimension>(points.front()); + coordinate_type const back_value = geometry::get<Dimension>(points.back()); + coordinate_type const base_value = (std::max)(front_value, back_value); + if (front_value < back_value) + { + move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value); + } + else + { + move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value); + } + + std::copy(points.begin(), points.end(), std::back_inserter(extremes)); + + get_intruders(ring, left, right, extremes, intruders); + + return true; + } +}; + + + + + +}} // namespace detail::extreme_points +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, + std::size_t Dimension, + typename GeometryTag = typename tag<Geometry>::type +> +struct extreme_points +{}; + + +template<typename Ring, std::size_t Dimension> +struct extreme_points<Ring, Dimension, ring_tag> + : detail::extreme_points::extreme_points_on_ring<Ring, Dimension> +{}; + + +template<typename Polygon, std::size_t Dimension> +struct extreme_points<Polygon, Dimension, polygon_tag> +{ + template <typename Extremes, typename Intruders> + static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders) + { + typedef typename geometry::ring_type<Polygon>::type ring_type; + typedef detail::extreme_points::extreme_points_on_ring + < + ring_type, Dimension + > ring_implementation; + + if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders)) + { + return false; + } + + // For a polygon, its interior rings can contain intruders + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) + { + ring_implementation::get_intruders(*it, extremes, intruders); + } + + return true; + } +}; + +template<typename Box> +struct extreme_points<Box, 1, box_tag> +{ + template <typename Extremes, typename Intruders> + static inline bool apply(Box const& box, Extremes& extremes, Intruders& ) + { + extremes.resize(4); + geometry::detail::assign_box_corners_oriented<false>(box, extremes); + // ll,ul,ur,lr, contains too exactly the right info + return true; + } +}; + +template<typename Box> +struct extreme_points<Box, 0, box_tag> +{ + template <typename Extremes, typename Intruders> + static inline bool apply(Box const& box, Extremes& extremes, Intruders& ) + { + extremes.resize(4); + geometry::detail::assign_box_corners_oriented<false>(box, extremes); + // ll,ul,ur,lr, rotate one to start with UL and end with LL + std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end()); + return true; + } +}; + +template<typename MultiPolygon, std::size_t Dimension> +struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag> +{ + template <typename Extremes, typename Intruders> + static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders) + { + // Get one for the very first polygon, that is (for the moment) enough. + // It is not guaranteed the "extreme" then, but for the current purpose + // (point_on_surface) it can just be this point. + if (boost::size(multi) >= 1) + { + return extreme_points + < + typename boost::range_value<MultiPolygon const>::type, + Dimension, + polygon_tag + >::apply(*boost::begin(multi), extremes, intruders); + } + + return false; + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief Returns extreme points (for Edge=1 in dimension 1, so the top, + for Edge=0 in dimension 0, the right side) +\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that. + */ +template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders> +inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders) +{ + concept::check<Geometry const>(); + + // Extremes is not required to follow a geometry concept (but it should support an output iterator), + // but its elements should fulfil the point-concept + concept::check<typename boost::range_value<Extremes>::type>(); + + // Intruders should contain collections which value type is point-concept + // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept + concept::check + < + typename boost::range_value + < + typename boost::range_value<Intruders>::type + >::type + const + >(); + + return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders); +} + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP diff --git a/boost/geometry/algorithms/detail/for_each_range.hpp b/boost/geometry/algorithms/detail/for_each_range.hpp index 7cb01fa9b4..e8c92160f1 100644 --- a/boost/geometry/algorithms/detail/for_each_range.hpp +++ b/boost/geometry/algorithms/detail/for_each_range.hpp @@ -17,9 +17,13 @@ #include <boost/mpl/assert.hpp> #include <boost/concept/requires.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/remove_const.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/add_const_if_c.hpp> #include <boost/geometry/views/box_view.hpp> @@ -34,24 +38,20 @@ namespace detail { namespace for_each { -template <typename Range, typename Actor, bool IsConst> +template <typename Range, typename Actor> struct fe_range_range { - static inline void apply( - typename add_const_if_c<IsConst, Range>::type& range, - Actor& actor) + static inline void apply(Range & range, Actor & actor) { actor.apply(range); } }; -template <typename Polygon, typename Actor, bool IsConst> +template <typename Polygon, typename Actor> struct fe_range_polygon { - static inline void apply( - typename add_const_if_c<IsConst, Polygon>::type& polygon, - Actor& actor) + static inline void apply(Polygon & polygon, Actor & actor) { actor.apply(exterior_ring(polygon)); @@ -60,17 +60,27 @@ struct fe_range_polygon } }; -template <typename Box, typename Actor, bool IsConst> +template <typename Box, typename Actor> struct fe_range_box { - static inline void apply( - typename add_const_if_c<IsConst, Box>::type& box, - Actor& actor) + static inline void apply(Box & box, Actor & actor) { - actor.apply(box_view<Box>(box)); + actor.apply(box_view<typename boost::remove_const<Box>::type>(box)); } }; +template <typename Multi, typename Actor, typename SinglePolicy> +struct fe_range_multi +{ + static inline void apply(Multi & multi, Actor & actor) + { + for ( typename boost::range_iterator<Multi>::type + it = boost::begin(multi); it != boost::end(multi); ++it) + { + SinglePolicy::apply(*it, actor); + } + } +}; }} // namespace detail::for_each #endif // DOXYGEN_NO_DETAIL @@ -83,10 +93,9 @@ namespace dispatch template < - typename Tag, typename Geometry, typename Actor, - bool IsConst + typename Tag = typename tag<Geometry>::type > struct for_each_range { @@ -98,26 +107,71 @@ struct for_each_range }; -template <typename Linestring, typename Actor, bool IsConst> -struct for_each_range<linestring_tag, Linestring, Actor, IsConst> - : detail::for_each::fe_range_range<Linestring, Actor, IsConst> +template <typename Linestring, typename Actor> +struct for_each_range<Linestring, Actor, linestring_tag> + : detail::for_each::fe_range_range<Linestring, Actor> +{}; + + +template <typename Ring, typename Actor> +struct for_each_range<Ring, Actor, ring_tag> + : detail::for_each::fe_range_range<Ring, Actor> +{}; + + +template <typename Polygon, typename Actor> +struct for_each_range<Polygon, Actor, polygon_tag> + : detail::for_each::fe_range_polygon<Polygon, Actor> +{}; + + +template <typename Box, typename Actor> +struct for_each_range<Box, Actor, box_tag> + : detail::for_each::fe_range_box<Box, Actor> {}; -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 MultiPoint, typename Actor> +struct for_each_range<MultiPoint, Actor, multi_point_tag> + : detail::for_each::fe_range_range<MultiPoint, Actor> {}; -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 Geometry, typename Actor> +struct for_each_range<Geometry, Actor, multi_linestring_tag> + : detail::for_each::fe_range_multi + < + Geometry, + Actor, + detail::for_each::fe_range_range + < + typename add_const_if_c + < + boost::is_const<Geometry>::value, + typename boost::range_value<Geometry>::type + >::type, + Actor + > + > {}; -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> + +template <typename Geometry, typename Actor> +struct for_each_range<Geometry, Actor, multi_polygon_tag> + : detail::for_each::fe_range_multi + < + Geometry, + Actor, + detail::for_each::fe_range_polygon + < + typename add_const_if_c + < + boost::is_const<Geometry>::value, + typename boost::range_value<Geometry>::type + >::type, + Actor + > + > {}; @@ -128,14 +182,12 @@ namespace detail { template <typename Geometry, typename Actor> -inline void for_each_range(Geometry const& geometry, Actor& actor) +inline void for_each_range(Geometry const& geometry, Actor & actor) { dispatch::for_each_range < - typename tag<Geometry>::type, - Geometry, - Actor, - true + Geometry const, + Actor >::apply(geometry, actor); } diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp index 62f0f7f0f4..0fd243d8e3 100644 --- a/boost/geometry/algorithms/detail/get_left_turns.hpp +++ b/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -9,7 +9,12 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/iterators/closing_iterator.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> +#include <boost/geometry/strategies/side.hpp> namespace boost { namespace geometry { @@ -21,342 +26,286 @@ namespace detail // TODO: move this to /util/ template <typename T> -static inline std::pair<T, T> ordered_pair(T const& first, T const& second) +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) +namespace left_turns { -#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) +template <typename Vector> +inline int get_quadrant(Vector const& vector) { - 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) - ; + // Return quadrant as layouted in the code below: + // 3 | 0 + // ----- + // 2 | 1 + return geometry::get<1>(vector) >= 0 + ? (geometry::get<0>(vector) < 0 ? 3 : 0) + : (geometry::get<0>(vector) < 0 ? 2 : 1) + ; } -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) +template <typename Vector> +inline int squared_length(Vector const& vector) { - 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; + return geometry::get<0>(vector) * geometry::get<0>(vector) + + geometry::get<1>(vector) * geometry::get<1>(vector) + ; } -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) + +template <typename Point> +struct angle_less { - 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; + typedef Point vector_type; + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type side_strategy_type; - 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); - } + angle_less(Point const& origin) + : m_origin(origin) + {} - bool result = false; - std::pair<segment_identifier, segment_identifier> pair = ordered_pair(outgoing_seg_id, incoming_seg_id); - auto it = turn_segment_indices.find(pair); - if (it != turn_segment_indices.end()) + template <typename Angle> + inline bool operator()(Angle const& p, Angle const& q) const { - for (auto sit = it->second.begin(); sit != it->second.end(); ++sit) + // Vector origin -> p and origin -> q + vector_type pv = p.point; + vector_type qv = q.point; + geometry::subtract_point(pv, m_origin); + geometry::subtract_point(qv, m_origin); + + int const quadrant_p = get_quadrant(pv); + int const quadrant_q = get_quadrant(qv); + if (quadrant_p != quadrant_q) { - if (process_include(outgoing_seg_id, incoming_seg_id, *sit, turns[*sit], keep_indices, priority)) - { - result = true; - } + return quadrant_p < quadrant_q; } + // Same quadrant, check if p is located left of q + int const side = side_strategy_type::apply(m_origin, q.point, + p.point); + if (side != 0) + { + return side == 1; + } + // Collinear, check if one is incoming, incoming angles come first + if (p.incoming != q.incoming) + { + return int(p.incoming) < int(q.incoming); + } + // Same quadrant/side/direction, return longest first + // TODO: maybe not necessary, decide this + int const length_p = squared_length(pv); + int const length_q = squared_length(qv); + if (length_p != length_q) + { + return squared_length(pv) > squared_length(qv); + } + // They are still the same. Just compare on seg_id + return p.seg_id < q.seg_id; } - return result; -} -template <std::size_t Index, typename Turn> -inline bool corresponds(Turn const& turn, segment_identifier const& seg_id) +private: + Point m_origin; +}; + +template <typename Point> +struct angle_equal_to { - return turn.operations[Index].operation == detail::overlay::operation_union - && turn.operations[Index].seg_id == seg_id; -} + typedef Point vector_type; + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type side_strategy_type; + inline angle_equal_to(Point const& origin) + : m_origin(origin) + {} -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 (auto sit = indices.begin(); sit != indices.end(); ++sit) + template <typename Angle> + inline bool operator()(Angle const& p, Angle const& q) const { - map[turns[*sit].operations[0].seg_id]++; - map[turns[*sit].operations[1].seg_id]++; - } + // Vector origin -> p and origin -> q + vector_type pv = p.point; + vector_type qv = q.point; + geometry::subtract_point(pv, m_origin); + geometry::subtract_point(qv, m_origin); - std::set<segment_identifier> segment_occuring_once; - for (auto mit = map.begin(); mit != map.end(); ++mit) - { - if (mit->second == 1) + if (get_quadrant(pv) != get_quadrant(qv)) { - segment_occuring_once.insert(mit->first); + return false; } -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER - std::cout << si(mit->first) << " " << mit->second << std::endl; -#endif + // Same quadrant, check if p/q are collinear + int const side = side_strategy_type::apply(m_origin, q.point, + p.point); + return side == 0; } - if (segment_occuring_once.size() == 2) - { - // Try to find within all turns a turn with these two segments +private: + Point m_origin; +}; - std::set<segment_identifier>::const_iterator soo_it = segment_occuring_once.begin(); - segment_identifier front = *soo_it; - soo_it++; - segment_identifier back = *soo_it; +template <typename AngleCollection, typename Turns> +inline void get_left_turns(AngleCollection const& sorted_angles, + Turns& turns) +{ + std::set<int> good_incoming; + std::set<int> good_outgoing; - std::pair<segment_identifier, segment_identifier> pair = ordered_pair(front, back); - auto it = turn_segment_indices.find(pair); - if (it != turn_segment_indices.end()) + for (typename boost::range_iterator<AngleCollection const>::type it = + sorted_angles.begin(); it != sorted_angles.end(); ++it) + { + if (!it->blocked) { - // debug_turns_by_indices("Found", it->second); - // Check which is the union/continue - segment_identifier good; - for (auto sit = it->second.begin(); sit != it->second.end(); ++sit) + if (it->incoming) { - 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; - } + good_incoming.insert(it->turn_index); } - -#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 (auto sit = indices.begin(); sit != indices.end(); ++sit) + else { - 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; + good_outgoing.insert(it->turn_index); } } } - 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 (auto 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) + if (good_incoming.empty() || good_outgoing.empty()) { return; } - // Only keep indices with high prio - std::set<int> ok_indices; - for (auto sit = indices.begin(); sit != indices.end(); ++sit) + for (typename boost::range_iterator<AngleCollection const>::type it = + sorted_angles.begin(); it != sorted_angles.end(); ++it) { - if (turns[*sit].priority >= max_prio) + if (good_incoming.count(it->turn_index) == 0 + || good_outgoing.count(it->turn_index) == 0) { - ok_indices.insert(*sit); + turns[it->turn_index].remove_on_multi = true; } } - 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); +//! Returns the number of clusters +template <typename Point, typename AngleCollection> +inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin) +{ + // Assign same cluster_index for all turns in same direction + BOOST_ASSERT(boost::size(sorted) >= 4u); - typedef geometry::ever_circling_range_iterator<Angles const> circling_iterator; - circling_iterator cit(angles); + angle_equal_to<Point> comparator(origin); + typename boost::range_iterator<AngleCollection>::type it = sorted.begin(); - debug_left_turn(*cit, *cit); - for(circling_iterator prev = cit++; i < n; prev = cit++, i++) + std::size_t cluster_index = 0; + it->cluster_index = cluster_index; + typename boost::range_iterator<AngleCollection>::type previous = it++; + for (; it != sorted.end(); ++it) { - debug_left_turn(*cit, *prev); - - bool const include = ! geometry::math::equals(prev->angle, cit->angle) - && ! prev->incoming - && cit->incoming; - - if (include) + if (!comparator(*previous, *it)) { - // 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; - } + cluster_index++; + previous = it; + } + it->cluster_index = cluster_index; + } + return cluster_index + 1; +} - // 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; - } +template <typename AngleCollection> +inline void block_turns(AngleCollection& sorted, std::size_t cluster_size) +{ + BOOST_ASSERT(boost::size(sorted) >= 4u && cluster_size > 0); -#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); - } - } - } + std::vector<std::pair<bool, bool> > directions; + for (std::size_t i = 0; i < cluster_size; i++) + { + directions.push_back(std::make_pair(false, false)); } - if (debug_indicate_size) + for (typename boost::range_iterator<AngleCollection const>::type it = sorted.begin(); + it != sorted.end(); ++it) { - std::cout << " size=" << keep_indices.size(); + if (it->incoming) + { + directions[it->cluster_index].first = true; + } + else + { + directions[it->cluster_index].second = true; + } } - if (keep_indices.size() >= 2) + for (typename boost::range_iterator<AngleCollection>::type it = sorted.begin(); + it != sorted.end(); ++it) { - prefer_by_other(turns, turn_segment_indices, keep_indices); + int cluster_index = it->cluster_index; + int previous_index = cluster_index - 1; + if (previous_index < 0) + { + previous_index = cluster_size - 1; + } + int next_index = cluster_index + 1; + if (next_index >= static_cast<int>(cluster_size)) + { + next_index = 0; + } + + if (directions[cluster_index].first + && directions[cluster_index].second) + { + it->blocked = true; + } + else if (!directions[cluster_index].first + && directions[cluster_index].second + && directions[previous_index].second) + { + // Only outgoing, previous was also outgoing: block this one + it->blocked = true; + } + else if (directions[cluster_index].first + && !directions[cluster_index].second + && !directions[previous_index].first + && directions[previous_index].second) + { + // Only incoming, previous was only outgoing: block this one + it->blocked = true; + } + else if (directions[cluster_index].first + && !directions[cluster_index].second + && directions[next_index].first + && !directions[next_index].second) + { + // Only incoming, next also incoming, block this one + it->blocked = true; + } } - if (keep_indices.size() >= 2) +} + +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) +template <typename AngleCollection, typename Point> +inline bool has_rounding_issues(AngleCollection const& angles, Point const& origin) +{ + for (typename boost::range_iterator<AngleCollection const>::type it = + angles.begin(); it != angles.end(); ++it) { - prefer_by_priority(turns, keep_indices); + // Vector origin -> p and origin -> q + typedef Point vector_type; + vector_type v = it->point; + geometry::subtract_point(v, origin); + return geometry::math::abs(geometry::get<0>(v)) <= 1 + || geometry::math::abs(geometry::get<1>(v)) <= 1 + ; } + return false; } +#endif + + +} // namespace left_turns } // namespace detail #endif // DOXYGEN_NO_DETAIL diff --git a/boost/geometry/algorithms/detail/get_max_size.hpp b/boost/geometry/algorithms/detail/get_max_size.hpp new file mode 100644 index 0000000000..8ac43e78b8 --- /dev/null +++ b/boost/geometry/algorithms/detail/get_max_size.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 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_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP + + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/util/math.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Box, std::size_t Dimension> +struct get_max_size_box +{ + static inline typename coordinate_type<Box>::type apply(Box const& box) + { + typename coordinate_type<Box>::type s + = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box)); + + return (std::max)(s, get_max_size_box<Box, Dimension - 1>::apply(box)); + } +}; + +template <typename Box> +struct get_max_size_box<Box, 0> +{ + static inline typename coordinate_type<Box>::type apply(Box const& box) + { + return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box)); + } +}; + +// This might be implemented later on for other geometries too. +// Not dispatched yet. +template <typename Box> +inline typename coordinate_type<Box>::type get_max_size(Box const& box) +{ + return get_max_size_box<Box, dimension<Box>::value - 1>::apply(box); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp index 1e6215ed93..24746ac627 100644 --- a/boost/geometry/algorithms/detail/has_self_intersections.hpp +++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -17,7 +17,10 @@ #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> +#include <boost/geometry/policies/disjoint_interrupt_policy.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> @@ -56,26 +59,33 @@ namespace detail { namespace overlay { -template <typename Geometry> -inline bool has_self_intersections(Geometry const& geometry) +template <typename Geometry, typename RobustPolicy> +inline bool has_self_intersections(Geometry const& geometry, + RobustPolicy const& robust_policy, + bool throw_on_self_intersection = true) { typedef typename point_type<Geometry>::type point_type; - typedef detail::overlay::turn_info<point_type> turn_info; + typedef turn_info + < + point_type, + typename segment_ratio_type<point_type, RobustPolicy>::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); - + + geometry::self_turns<detail::overlay::assign_null_policy>(geometry, robust_policy, 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); +#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 = + 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 = + bool const both_intersection_turn = info.operations[0].operation == detail::overlay::operation_intersection && info.operations[1].operation == detail::overlay::operation_intersection; @@ -95,19 +105,40 @@ inline bool has_self_intersections(Geometry const& geometry) for (int i = 0; i < 2; i++) { std::cout << " " << operation_char(info.operations[i].operation); + std::cout << " " << info.operations[i].seg_id; } std::cout << " " << geometry::dsv(info.point) << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) - throw overlay_invalid_input_exception(); + if (throw_on_self_intersection) + { + throw overlay_invalid_input_exception(); + } #endif + return true; } } return false; } +// For backward compatibility +template <typename Geometry> +inline bool has_self_intersections(Geometry const& geometry, + bool throw_on_self_intersection = true) +{ + typedef typename geometry::point_type<Geometry>::type point_type; + typedef typename geometry::rescale_policy_type<point_type>::type + rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry); + + return has_self_intersections(geometry, robust_policy, + throw_on_self_intersection); +} + }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL diff --git a/boost/geometry/algorithms/detail/interior_iterator.hpp b/boost/geometry/algorithms/detail/interior_iterator.hpp new file mode 100644 index 0000000000..3582773c3d --- /dev/null +++ b/boost/geometry/algorithms/detail/interior_iterator.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry + +// Copyright (c) 2014 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_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP + +#include <boost/range/iterator.hpp> +#include <boost/range/value_type.hpp> + +#include <boost/geometry/core/interior_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/*! +\brief Structure defining the type of interior rings iterator +\note If the Geometry is const, const iterator is defined. +\tparam Geometry \tparam_geometry + */ +template <typename Geometry> +struct interior_iterator +{ + typedef typename boost::range_iterator + < + typename geometry::interior_type<Geometry>::type + >::type type; +}; + +template <typename BaseT, typename T> +struct copy_const +{ + typedef T type; +}; + +template <typename BaseT, typename T> +struct copy_const<BaseT const, T> +{ + typedef T const type; +}; + +template <typename Geometry> +struct interior_ring_iterator +{ + typedef typename boost::range_iterator + < + typename copy_const + < + typename geometry::interior_type<Geometry>::type, + typename boost::range_value + < + typename geometry::interior_type<Geometry>::type + >::type + >::type + >::type type; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP diff --git a/boost/geometry/algorithms/detail/intersection/box_box.hpp b/boost/geometry/algorithms/detail/intersection/box_box.hpp new file mode 100644 index 0000000000..30c31ff1e5 --- /dev/null +++ b/boost/geometry/algorithms/detail/intersection/box_box.hpp @@ -0,0 +1,54 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_INTERSECTION_BOX_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP + + +#include <boost/geometry/algorithms/detail/intersection/interface.hpp> +#include <boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +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 + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP diff --git a/boost/geometry/algorithms/detail/intersection/implementation.hpp b/boost/geometry/algorithms/detail/intersection/implementation.hpp new file mode 100644 index 0000000000..d8fb2ec38c --- /dev/null +++ b/boost/geometry/algorithms/detail/intersection/implementation.hpp @@ -0,0 +1,22 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_INTERSECTION_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP + + +#include <boost/geometry/algorithms/detail/intersection/box_box.hpp> +#include <boost/geometry/algorithms/detail/intersection/multi.hpp> + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp new file mode 100644 index 0000000000..323ab7c850 --- /dev/null +++ b/boost/geometry/algorithms/detail/intersection/interface.hpp @@ -0,0 +1,309 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_INTERSECTION_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP + + +// TODO: those headers probably may be removed +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/algorithms/intersects.hpp> + +#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> + + +namespace boost { namespace geometry +{ + + +#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 RobustPolicy, typename GeometryOut, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + GeometryOut& geometry_out, + Strategy const& strategy) + { + typedef typename boost::range_value<GeometryOut>::type OneOut; + + intersection_insert + < + Geometry1, Geometry2, OneOut, + overlay_intersection + >::apply(geometry1, geometry2, robust_policy, 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 RobustPolicy, typename GeometryOut, typename Strategy> + static inline bool apply( + Geometry1 const& g1, + Geometry2 const& g2, + RobustPolicy const& robust_policy, + GeometryOut& out, + Strategy const& strategy) + { + return intersection< + Geometry2, Geometry1, + Tag2, Tag1, + false + >::apply(g2, g1, robust_policy, out, strategy); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct intersection +{ + template <typename GeometryOut> + static inline bool + apply( + const Geometry1& geometry1, + const Geometry2& geometry2, + GeometryOut& geometry_out) + { + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); + + typedef strategy_intersection + < + typename cs_tag<Geometry1>::type, + Geometry1, + Geometry2, + typename geometry::point_type<Geometry1>::type, + rescale_policy_type + > strategy; + + return dispatch::intersection + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy()); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename GeometryOut> + struct visitor: static_visitor<bool> + { + Geometry2 const& m_geometry2; + GeometryOut& m_geometry_out; + + visitor(Geometry2 const& geometry2, + GeometryOut& geometry_out) + : m_geometry2(geometry2), + m_geometry_out(geometry_out) + {} + + template <typename Geometry1> + result_type operator()(Geometry1 const& geometry1) const + { + return intersection + < + Geometry1, + Geometry2 + >::template apply + < + GeometryOut + > + (geometry1, m_geometry2, m_geometry_out); + } + }; + + template <typename GeometryOut> + static inline bool + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out) + { + return apply_visitor(visitor<GeometryOut>(geometry2, geometry_out), geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename GeometryOut> + struct visitor: static_visitor<bool> + { + Geometry1 const& m_geometry1; + GeometryOut& m_geometry_out; + + visitor(Geometry1 const& geometry1, + GeometryOut& geometry_out) + : m_geometry1(geometry1), + m_geometry_out(geometry_out) + {} + + template <typename Geometry2> + result_type operator()(Geometry2 const& geometry2) const + { + return intersection + < + Geometry1, + Geometry2 + >::template apply + < + GeometryOut + > + (m_geometry1, geometry2, m_geometry_out); + } + }; + + template <typename GeometryOut> + static inline bool + apply( + Geometry1 const& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2, + GeometryOut& geometry_out) + { + return apply_visitor(visitor<GeometryOut>(geometry1, geometry_out), geometry2); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)> +struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> > +{ + template <typename GeometryOut> + struct visitor: static_visitor<bool> + { + GeometryOut& m_geometry_out; + + visitor(GeometryOut& geometry_out) + : m_geometry_out(geometry_out) + {} + + template <typename Geometry1, typename Geometry2> + result_type operator()( + Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return intersection + < + Geometry1, + Geometry2 + >::template apply + < + GeometryOut + > + (geometry1, geometry2, m_geometry_out); + } + }; + + template <typename GeometryOut> + static inline bool + apply( + const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2, + GeometryOut& geometry_out) + { + return apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + +/*! +\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) +{ + return resolve_variant::intersection + < + Geometry1, + Geometry2 + >::template apply + < + GeometryOut + > + (geometry1, geometry2, geometry_out); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/intersection/multi.hpp b/boost/geometry/algorithms/detail/intersection/multi.hpp new file mode 100644 index 0000000000..b1f13862fc --- /dev/null +++ b/boost/geometry/algorithms/detail/intersection/multi.hpp @@ -0,0 +1,423 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_INTERSECTION_MULTI_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/geometry_id.hpp> +#include <boost/geometry/core/is_areal.hpp> +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> + +// TODO: those headers probably may be removed +#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> +#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> +#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> + +#include <boost/geometry/algorithms/detail/intersection/interface.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + +// TODO: remove this after moving num_point from multi directory +#include <boost/geometry/multi/algorithms/num_points.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 RobustPolicy, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(MultiLinestring1 const& ml1, + MultiLinestring2 const& ml2, + RobustPolicy const& robust_policy, + 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, robust_policy, out, strategy); + } + } + + return out; + } +}; + + +template <typename PointOut> +struct intersection_linestring_multi_linestring_point +{ + template + < + typename Linestring, typename MultiLinestring, + typename RobustPolicy, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(Linestring const& linestring, + MultiLinestring const& ml, + RobustPolicy const& robust_policy, + 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, robust_policy, 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 RobustPolicy, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal, + RobustPolicy const& robust_policy, + 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, robust_policy, 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 RobustPolicy, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, + RobustPolicy const& robust_policy, + OutputIterator out, + Strategy const& strategy) + { + return intersection_of_multi_linestring_with_areal + < + ReverseAreal, LineStringOut, OverlayType + >::apply(ml, areal, robust_policy, out, strategy); + } +}; + + + +template <typename LinestringOut> +struct clip_multi_linestring +{ + template + < + typename MultiLinestring, typename Box, + typename RobustPolicy, + typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(MultiLinestring const& multi_linestring, + Box const& box, + RobustPolicy const& robust_policy, + 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, robust_policy, 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_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP + diff --git a/boost/geometry/algorithms/detail/is_simple/always_simple.hpp b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp new file mode 100644 index 0000000000..91e2ef76bd --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP + +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/dispatch/is_simple.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_simple +{ + + +template <typename Geometry> +struct always_simple +{ + static inline bool apply(Geometry const&) + { + return true; + } +}; + + +}} // namespace detail::is_simple +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A point is always simple +template <typename Point> +struct is_simple<Point, point_tag> + : detail::is_simple::always_simple<Point> +{}; + + +// A valid segment is always simple. +// A segment is a curve. +// A curve is simple if it does not pass through the same point twice, +// with the possible exception of its two endpoints +// +// Reference: OGC 06-103r4 (6.1.6.1) +template <typename Segment> +struct is_simple<Segment, segment_tag> + : detail::is_simple::always_simple<Segment> +{}; + + +// A valid box is always simple +// A box is a Polygon, and it satisfies the conditions for Polygon validity. +// +// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) +template <typename Box> +struct is_simple<Box, box_tag> + : detail::is_simple::always_simple<Box> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp new file mode 100644 index 0000000000..9a1a16507a --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp @@ -0,0 +1,141 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP + +#include <boost/range.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/tags.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> + +#include <boost/geometry/algorithms/dispatch/is_simple.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_simple +{ + + +template <typename Ring> +struct is_simple_ring +{ + static inline bool apply(Ring const& ring) + { + return + !detail::is_valid::has_duplicates + < + Ring, geometry::closure<Ring>::value + >::apply(ring); + } +}; + + +template <typename Polygon> +class is_simple_polygon +{ +private: + template <typename InteriorRings> + static inline + bool are_simple_interior_rings(InteriorRings const& interior_rings) + { + return + detail::check_iterator_range + < + is_simple_ring + < + typename boost::range_value<InteriorRings>::type + > + >::apply(boost::begin(interior_rings), + boost::end(interior_rings)); + } + +public: + static inline bool apply(Polygon const& polygon) + { + return + is_simple_ring + < + typename ring_type<Polygon>::type + >::apply(exterior_ring(polygon)) + && + are_simple_interior_rings(geometry::interior_rings(polygon)); + } +}; + + +}} // namespace detail::is_simple +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A Ring is a Polygon. +// A Polygon is always a simple geometric object provided that it is valid. +// +// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) +template <typename Ring> +struct is_simple<Ring, ring_tag> + : detail::is_simple::is_simple_ring<Ring> +{}; + + +// A Polygon is always a simple geometric object provided that it is valid. +// +// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1) +template <typename Polygon> +struct is_simple<Polygon, polygon_tag> + : detail::is_simple::is_simple_polygon<Polygon> +{}; + + +// Not clear what the definition is. +// Right now we consider a MultiPolygon as simple if it is valid. +// +// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14) +template <typename MultiPolygon> +struct is_simple<MultiPolygon, multi_polygon_tag> +{ + static inline bool apply(MultiPolygon const& multipolygon) + { + return + detail::check_iterator_range + < + detail::is_simple::is_simple_polygon + < + typename boost::range_value<MultiPolygon>::type + >, + false // do not allow empty multi-polygon + >::apply(boost::begin(multipolygon), boost::end(multipolygon)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp new file mode 100644 index 0000000000..75c37c68f8 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/io/dsv/write.hpp> + +#include <boost/geometry/policies/compare.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#endif + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_simple +{ + + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename MultiLinestring> +inline void debug_print_boundary_points(MultiLinestring const& multilinestring) +{ + typedef typename point_type<MultiLinestring>::type point_type; + typedef std::vector<point_type> point_vector; + + point_vector boundary_points; + for (typename boost::range_iterator<MultiLinestring const>::type it + = boost::begin(multilinestring); + it != boost::end(multilinestring); ++it) + { + if ( boost::size(*it) > 1 + && !geometry::equals(range::front(*it), range::back(*it)) ) + { + boundary_points.push_back( range::front(*it) ); + boundary_points.push_back( range::back(*it) ); + } + } + + std::sort(boundary_points.begin(), boundary_points.end(), + geometry::less<point_type>()); + + std::cout << "boundary points: "; + for (typename point_vector::const_iterator pit = boundary_points.begin(); + pit != boundary_points.end(); ++pit) + { + std::cout << " " << geometry::dsv(*pit); + } + std::cout << std::endl << std::endl; +} +#else +template <typename MultiLinestring> +inline void debug_print_boundary_points(MultiLinestring const&) +{ +} +#endif // BOOST_GEOMETRY_TEST_DEBUG + + +}} // namespace detail::is_simple + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/implementation.hpp b/boost/geometry/algorithms/detail/is_simple/implementation.hpp new file mode 100644 index 0000000000..e69b273ce3 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/implementation.hpp @@ -0,0 +1,18 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP + +#include <boost/geometry/algorithms/detail/is_simple/always_simple.hpp> +#include <boost/geometry/algorithms/detail/is_simple/areal.hpp> +#include <boost/geometry/algorithms/detail/is_simple/linear.hpp> +#include <boost/geometry/algorithms/detail/is_simple/multipoint.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp new file mode 100644 index 0000000000..4239664ed1 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp @@ -0,0 +1,80 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/dispatch/is_simple.hpp> + + +namespace boost { namespace geometry +{ + + +namespace resolve_variant { + +template <typename Geometry> +struct is_simple +{ + static inline bool apply(Geometry const& geometry) + { + concept::check<Geometry const>(); + return dispatch::is_simple<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor : boost::static_visitor<bool> + { + template <typename Geometry> + bool operator()(Geometry const& geometry) const + { + return is_simple<Geometry>::apply(geometry); + } + }; + + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + + + +/*! +\brief \brief_check{is simple} +\ingroup is_simple +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\return \return_check{is simple} + +\qbk{[include reference/algorithms/is_simple.qbk]} +*/ +template <typename Geometry> +inline bool is_simple(Geometry const& geometry) +{ + return resolve_variant::is_simple<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp new file mode 100644 index 0000000000..f2efcb309d --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -0,0 +1,248 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP + +#include <algorithm> +#include <deque> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/segment_ratio.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/intersects.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> + +#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> + +#include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp> +#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> + +#include <boost/geometry/algorithms/dispatch/is_simple.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_simple +{ + + +template <typename Linestring, bool CheckSelfIntersections = true> +struct is_simple_linestring +{ + static inline bool apply(Linestring const& linestring) + { + return !detail::is_valid::has_duplicates + < + Linestring, closed + >::apply(linestring) + && !detail::is_valid::has_spikes + < + Linestring, closed + >::apply(linestring) + && !(CheckSelfIntersections && geometry::intersects(linestring)); + } +}; + + + +template <typename MultiLinestring> +class is_simple_multilinestring +{ +private: + class is_acceptable_turn + { + private: + template <typename Point, typename Linestring> + static inline bool is_boundary_point_of(Point const& point, + Linestring const& linestring) + { + BOOST_ASSERT( boost::size(linestring) > 1 ); + return + !geometry::equals(range::front(linestring), + range::back(linestring)) + && + ( geometry::equals(point, range::front(linestring)) + || geometry::equals(point, range::back(linestring)) ); + } + + template <typename Linestring1, typename Linestring2> + static inline bool have_same_boundary_points(Linestring1 const& ls1, + Linestring2 const& ls2) + { + return + geometry::equals(range::front(ls1), range::front(ls2)) + ? + geometry::equals(range::back(ls1), range::back(ls2)) + : + (geometry::equals(range::front(ls1), range::back(ls2)) + && + geometry::equals(range::back(ls1), range::front(ls2)) + ) + ; + } + + public: + is_acceptable_turn(MultiLinestring const& multilinestring) + : m_multilinestring(multilinestring) + {} + + template <typename Turn> + inline bool apply(Turn const& turn) const + { + typedef typename boost::range_value + < + MultiLinestring + >::type linestring; + + linestring const& ls1 = + range::at(m_multilinestring, + turn.operations[0].seg_id.multi_index); + + linestring const& ls2 = + range::at(m_multilinestring, + turn.operations[1].seg_id.multi_index); + + return + is_boundary_point_of(turn.point, ls1) + && is_boundary_point_of(turn.point, ls2) + && + ( boost::size(ls1) != 2 + || boost::size(ls2) != 2 + || !have_same_boundary_points(ls1, ls2) ); + } + + private: + MultiLinestring const& m_multilinestring; + }; + + +public: + static inline bool apply(MultiLinestring const& multilinestring) + { + typedef typename boost::range_value<MultiLinestring>::type linestring; + typedef typename point_type<MultiLinestring>::type point_type; + typedef point_type point; + + + // check each of the linestrings for simplicity + if ( !detail::check_iterator_range + < + is_simple_linestring<linestring>, + false // do not allow empty multilinestring + >::apply(boost::begin(multilinestring), + boost::end(multilinestring)) + ) + { + return false; + } + + + // compute self turns + typedef detail::overlay::turn_info + < + point_type, + geometry::segment_ratio + < + typename geometry::coordinate_type<point>::type + > + > turn_info; + + std::deque<turn_info> turns; + + typedef detail::overlay::get_turn_info + < + detail::disjoint::assign_disjoint_policy + > turn_policy; + + is_acceptable_turn predicate(multilinestring); + detail::overlay::predicate_based_interrupt_policy + < + is_acceptable_turn + > interrupt_policy(predicate); + + detail::self_get_turn_points::get_turns + < + turn_policy + >::apply(multilinestring, + detail::no_rescale_policy(), + turns, + interrupt_policy); + + detail::is_valid::debug_print_turns(turns.begin(), turns.end()); + debug_print_boundary_points(multilinestring); + + return !interrupt_policy.has_intersections; + } + +}; + + + +}} // namespace detail::is_simple +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// A linestring is a curve. +// A curve is simple if it does not pass through the same point twice, +// with the possible exception of its two endpoints +// +// Reference: OGC 06-103r4 (6.1.6.1) +template <typename Linestring> +struct is_simple<Linestring, linestring_tag> + : detail::is_simple::is_simple_linestring<Linestring> +{}; + + +// A MultiLinestring is a MultiCurve +// A MultiCurve is simple if all of its elements are simple and the +// only intersections between any two elements occur at Points that +// are on the boundaries of both elements. +// +// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9) +template <typename MultiLinestring> +struct is_simple<MultiLinestring, multi_linestring_tag> + : detail::is_simple::is_simple_multilinestring<MultiLinestring> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp new file mode 100644 index 0000000000..d996eb64e9 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp @@ -0,0 +1,84 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP + +#include <algorithm> + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/policies/compare.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> + +#include <boost/geometry/algorithms/dispatch/is_simple.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_simple +{ + + +template <typename MultiPoint> +struct is_simple_multipoint +{ + static inline bool apply(MultiPoint const& multipoint) + { + if ( boost::size(multipoint) == 0 ) + { + return false; + } + + MultiPoint mp(multipoint); + std::sort(boost::begin(mp), boost::end(mp), + geometry::less<typename point_type<MultiPoint>::type>()); + + return !detail::is_valid::has_duplicates<MultiPoint, closed>::apply(mp); + } +}; + + +}} // namespace detail::is_simple +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A MultiPoint is simple if no two Points in the MultiPoint are equal +// (have identical coordinate values in X and Y) +// +// Reference: OGC 06-103r4 (6.1.5) +template <typename MultiPoint> +struct is_simple<MultiPoint, multi_point_tag> + : detail::is_simple::is_simple_multipoint<MultiPoint> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp new file mode 100644 index 0000000000..f82b3f9bf1 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/box.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + +template <typename Box, std::size_t I> +struct has_valid_corners +{ + static inline bool apply(Box const& box) + { + if ( geometry::get<geometry::max_corner, I-1>(box) + <= + geometry::get<geometry::min_corner, I-1>(box) ) + { + return false; + } + return has_valid_corners<Box, I-1>::apply(box); + } +}; + + +template <typename Box> +struct has_valid_corners<Box, 0> +{ + static inline bool apply(Box const&) + { + return true; + } +}; + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A box is always simple +// A box is a Polygon, and it satisfies the conditions for Polygon validity. +// +// The only thing we have to check is whether the max corner lies in +// the upper-right quadrant as defined by the min corner +// +// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) +template <typename Box> +struct is_valid<Box, box_tag> + : detail::is_valid::has_valid_corners<Box, dimension<Box>::value> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp new file mode 100644 index 0000000000..c59139a92e --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp @@ -0,0 +1,239 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP + +#include <cstddef> + +#include <set> +#include <stack> +#include <utility> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/core/addressof.hpp> + +#include <boost/geometry/policies/compare.hpp> + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + + +template <typename TurnPoint> +class complement_graph_vertex +{ +public: + complement_graph_vertex(std::size_t id) + : m_id(id) + , m_turn_point(NULL) + {} + + complement_graph_vertex(TurnPoint const* turn_point, + std::size_t expected_id) + : m_id(expected_id) + , m_turn_point(turn_point) + {} + + inline std::size_t id() const { return m_id; } + + inline bool operator<(complement_graph_vertex const& other) const + { + if ( m_turn_point != NULL && other.m_turn_point != NULL ) + { + return geometry::less + < + TurnPoint + >()(*m_turn_point, *other.m_turn_point); + } + if ( m_turn_point == NULL && other.m_turn_point == NULL ) + { + return m_id < other.m_id; + } + return m_turn_point == NULL; + } + +private: + // the value of m_turn_point determines the type of the vertex + // non-NULL: vertex corresponds to an IP + // NULL : vertex corresponds to a hole or outer space, and the id + // is the ring id of the corresponding ring of the polygon + std::size_t m_id; + TurnPoint const* m_turn_point; +}; + + + + +template <typename TurnPoint> +class complement_graph +{ +private: + typedef complement_graph_vertex<TurnPoint> vertex; + typedef std::set<vertex> vertex_container; + +public: + typedef typename vertex_container::const_iterator vertex_handle; + +private: + struct vertex_handle_less + { + inline bool operator()(vertex_handle v1, vertex_handle v2) const + { + return v1->id() < v2->id(); + } + }; + + typedef std::set<vertex_handle, vertex_handle_less> neighbor_container; + + class has_cycles_dfs_data + { + public: + has_cycles_dfs_data(std::size_t num_nodes) + : m_visited(num_nodes, false) + , m_parent_id(num_nodes, -1) + {} + + inline signed_index_type parent_id(vertex_handle v) const + { + return m_parent_id[v->id()]; + } + + inline void set_parent_id(vertex_handle v, signed_index_type id) + { + m_parent_id[v->id()] = id; + } + + inline bool visited(vertex_handle v) const + { + return m_visited[v->id()]; + } + + inline void set_visited(vertex_handle v, bool value) + { + m_visited[v->id()] = value; + } + private: + std::vector<bool> m_visited; + std::vector<signed_index_type> m_parent_id; + }; + + + inline bool has_cycles(vertex_handle start_vertex, + has_cycles_dfs_data& data) const + { + std::stack<vertex_handle> stack; + stack.push(start_vertex); + + while ( !stack.empty() ) + { + vertex_handle v = stack.top(); + stack.pop(); + + data.set_visited(v, true); + for (typename neighbor_container::const_iterator nit + = m_neighbors[v->id()].begin(); + nit != m_neighbors[v->id()].end(); ++nit) + { + if ( static_cast<signed_index_type>((*nit)->id()) != data.parent_id(v) ) + { + if ( data.visited(*nit) ) + { + return true; + } + else + { + data.set_parent_id(*nit, static_cast<signed_index_type>(v->id())); + stack.push(*nit); + } + } + } + } + return false; + } + +public: + // num_rings: total number of rings, including the exterior ring + complement_graph(std::size_t num_rings) + : m_num_rings(num_rings) + , m_num_turns(0) + , m_vertices() + , m_neighbors(num_rings) + {} + + // inserts a ring vertex in the graph and returns its handle + // ring id's are zero-based (so the first interior ring has id 1) + inline vertex_handle add_vertex(signed_index_type id) + { + return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first; + } + + // inserts an IP in the graph and returns its id + inline vertex_handle add_vertex(TurnPoint const& turn_point) + { + std::pair<vertex_handle, bool> res + = m_vertices.insert(vertex(boost::addressof(turn_point), + m_num_rings + m_num_turns) + ); + + if ( res.second ) + { + // a new element is inserted + m_neighbors.push_back(neighbor_container()); + ++m_num_turns; + } + return res.first; + } + + inline void add_edge(vertex_handle v1, vertex_handle v2) + { + BOOST_ASSERT( v1 != m_vertices.end() ); + BOOST_ASSERT( v2 != m_vertices.end() ); + m_neighbors[v1->id()].insert(v2); + m_neighbors[v2->id()].insert(v1); + } + + inline bool has_cycles() const + { + // initialize all vertices as non-visited and with no parent set + // this is done by the constructor of has_cycles_dfs_data + has_cycles_dfs_data data(m_num_rings + m_num_turns); + + // for each non-visited vertex, start a DFS from that vertex + for (vertex_handle it = m_vertices.begin(); + it != m_vertices.end(); ++it) + { + if ( !data.visited(it) && has_cycles(it, data) ) + { + return true; + } + } + return false; + } + + template <typename OStream, typename TP> + friend inline + void debug_print_complement_graph(OStream&, complement_graph<TP> const&); + +private: + std::size_t m_num_rings, m_num_turns; + vertex_container m_vertices; + std::vector<neighbor_container> m_neighbors; +}; + + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp new file mode 100644 index 0000000000..60f597e296 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include <iostream> +#endif + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename OutputStream, typename TurnPoint> +inline void +debug_print_complement_graph(OutputStream& os, + complement_graph<TurnPoint> const& graph) +{ + typedef typename complement_graph<TurnPoint>::vertex_handle vertex_handle; + + os << "num rings: " << graph.m_num_rings << std::endl; + os << "vertex ids: {"; + for (vertex_handle it = graph.m_vertices.begin(); + it != graph.m_vertices.end(); ++it) + { + os << " " << it->id(); + } + os << " }" << std::endl; + + for (vertex_handle it = graph.m_vertices.begin(); + it != graph.m_vertices.end(); ++it) + { + os << "neighbors of " << it->id() << ": {"; + for (typename complement_graph + < + TurnPoint + >::neighbor_container::const_iterator + nit = graph.m_neighbors[it->id()].begin(); + nit != graph.m_neighbors[it->id()].end(); ++nit) + { + os << " " << (*nit)->id(); + } + os << "}" << std::endl; + } +} +#else +template <typename OutputStream, typename TurnPoint> +inline void debug_print_complement_graph(OutputStream&, + complement_graph<TurnPoint> const&) +{ +} +#endif + + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp new file mode 100644 index 0000000000..6824921b63 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include <iostream> + +#include <boost/geometry/io/dsv/write.hpp> +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +#endif + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename TurnIterator> +inline void debug_print_turns(TurnIterator first, TurnIterator beyond) +{ + std::cout << "turns:"; + for (TurnIterator tit = first; tit != beyond; ++tit) + { + std::cout << " [" + << geometry::method_char(tit->method) + << "," + << geometry::operation_char(tit->operations[0].operation) + << "/" + << geometry::operation_char(tit->operations[1].operation) + << " {" + << tit->operations[0].seg_id.multi_index + << ", " + << tit->operations[1].seg_id.multi_index + << "} {" + << tit->operations[0].seg_id.ring_index + << ", " + << tit->operations[1].seg_id.ring_index + << "} " + << geometry::dsv(tit->point) + << "]"; + } + std::cout << std::endl << std::endl; +} +#else +template <typename TurnIterator> +inline void debug_print_turns(TurnIterator, TurnIterator) +{} +#endif // BOOST_GEOMETRY_TEST_DEBUG + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp new file mode 100644 index 0000000000..6f1c263646 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp @@ -0,0 +1,68 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP + +#ifdef GEOMETRY_TEST_DEBUG +#include <iostream> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#endif + + +namespace boost { namespace geometry +{ + +namespace detail { namespace is_valid +{ + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct debug_validity_phase +{ + static inline void apply(int) + { + } +}; + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename Polygon> +struct debug_validity_phase<Polygon, polygon_tag> +{ + static inline void apply(int phase) + { + switch (phase) + { + case 1: + std::cout << "checking exterior ring..." << std::endl; + break; + case 2: + std::cout << "checking interior rings..." << std::endl; + break; + case 3: + std::cout << "computing and analyzing turns..." << std::endl; + break; + case 4: + std::cout << "checking if holes are inside the exterior ring..." + << std::endl; + break; + case 5: + std::cout << "checking connectivity of interior..." << std::endl; + break; + } + } +}; +#endif + +}} // namespace detail::is_valid + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp new file mode 100644 index 0000000000..dd0922bb2b --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> + +#include <boost/geometry/policies/compare.hpp> + +#include <boost/geometry/views/closeable_view.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + +template <typename Range, closure_selector Closure> +struct has_duplicates +{ + static inline bool apply(Range const& range) + { + typedef typename closeable_view<Range const, Closure>::type view_type; + typedef typename boost::range_iterator<view_type const>::type iterator; + + view_type view(range); + + if ( boost::size(view) < 2 ) + { + return false; + } + + geometry::equal_to<typename boost::range_value<Range>::type> equal; + + iterator it = boost::begin(view); + iterator next = ++boost::begin(view); + for (; next != boost::end(view); ++it, ++next) + { + if ( equal(*it, *next) ) + { + return true; + } + } + return false; + } +}; + + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp new file mode 100644 index 0000000000..9b95017482 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -0,0 +1,139 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP + +#include <algorithm> + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/views/closeable_view.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + +template <typename Point> +struct equal_to +{ + Point const& m_point; + + equal_to(Point const& point) + : m_point(point) + {} + + template <typename OtherPoint> + inline bool operator()(OtherPoint const& other) const + { + return geometry::equals(m_point, other); + } +}; + +template <typename Point> +struct not_equal_to +{ + Point const& m_point; + + not_equal_to(Point const& point) + : m_point(point) + {} + + template <typename OtherPoint> + inline bool operator()(OtherPoint const& other) const + { + return !geometry::equals(other, m_point); + } +}; + + + +template <typename Range, closure_selector Closure> +struct has_spikes +{ + static inline bool apply(Range const& range) + { + typedef not_equal_to<typename point_type<Range>::type> not_equal; + + typedef typename closeable_view<Range const, Closure>::type view_type; + typedef typename boost::range_iterator<view_type const>::type iterator; + + view_type const view(range); + + iterator prev = boost::begin(view); + + iterator cur = std::find_if(prev, boost::end(view), not_equal(*prev)); + if ( cur == boost::end(view) ) + { + // the range has only one distinct point, so it + // cannot have a spike + return false; + } + + iterator next = std::find_if(cur, boost::end(view), not_equal(*cur)); + if ( next == boost::end(view) ) + { + // the range has only two distinct points, so it + // cannot have a spike + return false; + } + + while ( next != boost::end(view) ) + { + if ( geometry::detail::point_is_spike_or_equal(*prev, + *next, + *cur) ) + { + return true; + } + prev = cur; + cur = next; + next = std::find_if(cur, boost::end(view), not_equal(*cur)); + } + + if ( geometry::equals(range::front(view), range::back(view)) ) + { + iterator cur = boost::begin(view); + typename boost::range_reverse_iterator + < + view_type const + >::type prev = std::find_if(boost::rbegin(view), + boost::rend(view), + not_equal(range::back(view))); + iterator next = + std::find_if(cur, boost::end(view), not_equal(*cur)); + return detail::point_is_spike_or_equal(*prev, *next, *cur); + } + + return false; + } +}; + + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp new file mode 100644 index 0000000000..220a67bcd1 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> + +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +template +< + typename Geometry, + typename IsAcceptableTurn = is_acceptable_turn<Geometry> +> +class has_valid_self_turns +{ +private: + typedef typename point_type<Geometry>::type point_type; + + typedef typename geometry::rescale_policy_type + < + point_type + >::type rescale_policy_type; + + typedef detail::overlay::get_turn_info + < + detail::overlay::assign_null_policy + > turn_policy; + +public: + typedef detail::overlay::turn_info + < + point_type, + typename geometry::segment_ratio_type + < + point_type, + rescale_policy_type + >::type + > turn_type; + + // returns true if all turns are valid + template <typename Turns> + static inline bool apply(Geometry const& geometry, Turns& turns) + { + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry); + + detail::overlay::stateless_predicate_based_interrupt_policy + < + IsAcceptableTurn + > interrupt_policy; + + geometry::self_turns<turn_policy>(geometry, + robust_policy, + turns, + interrupt_policy); + + return !interrupt_policy.has_intersections; + } +}; + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/implementation.hpp b/boost/geometry/algorithms/detail/is_valid/implementation.hpp new file mode 100644 index 0000000000..4a515a3073 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/implementation.hpp @@ -0,0 +1,21 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP + +#include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp> +#include <boost/geometry/algorithms/detail/is_valid/linear.hpp> +#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp> +#include <boost/geometry/algorithms/detail/is_valid/multipolygon.hpp> +#include <boost/geometry/algorithms/detail/is_valid/ring.hpp> +#include <boost/geometry/algorithms/detail/is_valid/segment.hpp> +#include <boost/geometry/algorithms/detail/is_valid/box.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp new file mode 100644 index 0000000000..4b232fd436 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + +namespace resolve_variant { + +template <typename Geometry> +struct is_valid +{ + static inline bool apply(Geometry const& geometry) + { + concept::check<Geometry const>(); + return dispatch::is_valid<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor : boost::static_visitor<bool> + { + template <typename Geometry> + bool operator()(Geometry const& geometry) const + { + return is_valid<Geometry>::apply(geometry); + } + }; + + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + + +/*! +\brief \brief_check{is valid (in the OGC sense)} +\ingroup is_valid +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\return \return_check{is valid (in the OGC sense)} + +\qbk{[include reference/algorithms/is_valid.qbk]} +*/ +template <typename Geometry> +inline bool is_valid(Geometry const& geometry) +{ + return resolve_variant::is_valid<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp new file mode 100644 index 0000000000..f9d926770e --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +template +< + typename Geometry, + order_selector Order = geometry::point_order<Geometry>::value, + typename Tag = typename tag<Geometry>::type +> +struct acceptable_operation +{}; + +template <typename Polygon> +struct acceptable_operation<Polygon, counterclockwise, polygon_tag> +{ + static const detail::overlay::operation_type value = + detail::overlay::operation_union; +}; + +template <typename Polygon> +struct acceptable_operation<Polygon, clockwise, polygon_tag> +{ + static const detail::overlay::operation_type value = + detail::overlay::operation_intersection; +}; + +template <typename MultiPolygon> +struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag> +{ + static const detail::overlay::operation_type value = + detail::overlay::operation_intersection; +}; + +template <typename MultiPolygon> +struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag> +{ + static const detail::overlay::operation_type value = + detail::overlay::operation_union; +}; + + + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct is_acceptable_turn +{}; + +template <typename Polygon> +class is_acceptable_turn<Polygon, polygon_tag> +{ +protected: + template <typename Turn, typename Method, typename Operation> + static inline bool check_turn(Turn const& turn, + Method method, + Operation operation) + { + return turn.method == method + && turn.operations[0].operation == operation + && turn.operations[1].operation == operation; + } + + +public: + template <typename Turn> + static inline bool apply(Turn const& turn) + { + using namespace detail::overlay; + + if ( turn.operations[0].seg_id.ring_index + == turn.operations[1].seg_id.ring_index ) + { + return false; + } + + operation_type const op = acceptable_operation<Polygon>::value; + + return check_turn(turn, method_touch_interior, op) + || check_turn(turn, method_touch, op) + ; + } +}; + +template <typename MultiPolygon> +class is_acceptable_turn<MultiPolygon, multi_polygon_tag> + : is_acceptable_turn<typename boost::range_value<MultiPolygon>::type> +{ +private: + typedef typename boost::range_value<MultiPolygon>::type polygon; + typedef is_acceptable_turn<polygon> base; + +public: + template <typename Turn> + static inline bool apply(Turn const& turn) + { + using namespace detail::overlay; + + if ( turn.operations[0].seg_id.multi_index + == turn.operations[1].seg_id.multi_index ) + { + return base::apply(turn); + } + + operation_type const op = acceptable_operation<MultiPolygon>::value; + + return base::check_turn(turn, method_touch_interior, op) + || base::check_turn(turn, method_touch, op) + ; + } +}; + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp new file mode 100644 index 0000000000..244df9b035 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -0,0 +1,125 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> +#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +template <typename Linestring, bool AllowSpikes> +struct is_valid_linestring +{ + static inline bool apply(Linestring const& linestring) + { + std::size_t num_distinct = detail::num_distinct_consecutive_points + < + Linestring, + 3u, + true, + not_equal_to<typename point_type<Linestring>::type> + >::apply(linestring); + + if ( num_distinct < 2u ) + { + return false; + } + + return num_distinct == 2u + || AllowSpikes + || !has_spikes<Linestring, closed>::apply(linestring); + } +}; + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A linestring is a curve. +// A curve is 1-dimensional so it has to have at least two distinct +// points. +// A curve is simple if it does not pass through the same point twice, +// with the possible exception of its two endpoints +// +// There is an option here as to whether spikes are allowed for linestrings; +// here we pass this as an additional template parameter: allow_spikes +// If allow_spikes is set to true, spikes are allowed, false otherwise. +// By default, spikes are disallowed +// +// Reference: OGC 06-103r4 (6.1.6.1) +template <typename Linestring, bool AllowSpikes> +struct is_valid<Linestring, linestring_tag, AllowSpikes> + : detail::is_valid::is_valid_linestring<Linestring, AllowSpikes> +{}; + + +// A MultiLinestring is a MultiCurve +// A MultiCurve is simple if all of its elements are simple and the +// only intersections between any two elements occur at Points that +// are on the boundaries of both elements. +// +// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9) +template <typename MultiLinestring, bool AllowSpikes> +struct is_valid<MultiLinestring, multi_linestring_tag, AllowSpikes> +{ + static inline bool apply(MultiLinestring const& multilinestring) + { + return detail::check_iterator_range + < + detail::is_valid::is_valid_linestring + < + typename boost::range_value<MultiLinestring>::type, + AllowSpikes + >, + false // do not allow empty multilinestring + >::apply(boost::begin(multilinestring), + boost::end(multilinestring)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp new file mode 100644 index 0000000000..3d0ebb5f82 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp @@ -0,0 +1,297 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP + +#include <deque> +#include <vector> + +#include <boost/iterator/filter_iterator.hpp> +#include <boost/range.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/tags.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/geometries/box.hpp> + +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/partition.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> +#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> +#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> +#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +template <typename MultiPolygon, bool AllowDuplicates> +class is_valid_multipolygon + : is_valid_polygon + < + typename boost::range_value<MultiPolygon>::type, + AllowDuplicates, + true // check only the validity of rings + > +{ +private: + typedef is_valid_polygon + < + typename boost::range_value<MultiPolygon>::type, + AllowDuplicates, + true + > base; + + + + template <typename PolygonIterator, typename TurnIterator> + static inline + bool are_polygon_interiors_disjoint(PolygonIterator polygons_first, + PolygonIterator polygons_beyond, + TurnIterator turns_first, + TurnIterator turns_beyond) + { + // collect all polygons that have turns + std::set<signed_index_type> multi_indices; + for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) + { + multi_indices.insert(tit->operations[0].seg_id.multi_index); + multi_indices.insert(tit->operations[1].seg_id.multi_index); + } + + // put polygon iterators without turns in a vector + std::vector<PolygonIterator> polygon_iterators; + signed_index_type multi_index = 0; + for (PolygonIterator it = polygons_first; it != polygons_beyond; + ++it, ++multi_index) + { + if ( multi_indices.find(multi_index) == multi_indices.end() ) + { + polygon_iterators.push_back(it); + } + } + + typename base::item_visitor visitor; + + geometry::partition + < + geometry::model::box<typename point_type<MultiPolygon>::type>, + typename base::expand_box, + typename base::overlaps_box + >::apply(polygon_iterators, visitor); + + return !visitor.items_overlap; + } + + + + class has_multi_index + { + public: + has_multi_index(signed_index_type multi_index) + : m_multi_index(multi_index) + {} + + template <typename Turn> + inline bool operator()(Turn const& turn) const + { + return turn.operations[0].seg_id.multi_index == m_multi_index + && turn.operations[1].seg_id.multi_index == m_multi_index; + } + + private: + signed_index_type const m_multi_index; + }; + + + + template <typename Predicate> + struct has_property_per_polygon + { + template <typename PolygonIterator, typename TurnIterator> + static inline bool apply(PolygonIterator polygons_first, + PolygonIterator polygons_beyond, + TurnIterator turns_first, + TurnIterator turns_beyond) + { + signed_index_type multi_index = 0; + for (PolygonIterator it = polygons_first; it != polygons_beyond; + ++it, ++multi_index) + { + has_multi_index index_predicate(multi_index); + + typedef boost::filter_iterator + < + has_multi_index, TurnIterator + > filtered_turn_iterator; + + filtered_turn_iterator filtered_turns_first(index_predicate, + turns_first, + turns_beyond); + + filtered_turn_iterator filtered_turns_beyond(index_predicate, + turns_beyond, + turns_beyond); + + if ( !Predicate::apply(*it, + filtered_turns_first, + filtered_turns_beyond) ) + { + return false; + } + } + return true; + } + }; + + + + template <typename PolygonIterator, typename TurnIterator> + static inline bool have_holes_inside(PolygonIterator polygons_first, + PolygonIterator polygons_beyond, + TurnIterator turns_first, + TurnIterator turns_beyond) + { + return has_property_per_polygon + < + typename base::has_holes_inside + >::apply(polygons_first, polygons_beyond, + turns_first, turns_beyond); + } + + + + template <typename PolygonIterator, typename TurnIterator> + static inline bool have_connected_interior(PolygonIterator polygons_first, + PolygonIterator polygons_beyond, + TurnIterator turns_first, + TurnIterator turns_beyond) + { + return has_property_per_polygon + < + typename base::has_connected_interior + >::apply(polygons_first, polygons_beyond, + turns_first, turns_beyond); + } + + +public: + static inline bool apply(MultiPolygon const& multipolygon) + { + typedef debug_validity_phase<MultiPolygon> debug_phase; + + // check validity of all polygons ring + debug_phase::apply(1); + + if ( !detail::check_iterator_range + < + base, + false // do not allow empty multi-polygons + >::apply(boost::begin(multipolygon), + boost::end(multipolygon)) ) + { + return false; + } + + + // compute turns and check if all are acceptable + debug_phase::apply(2); + + typedef has_valid_self_turns<MultiPolygon> has_valid_turns; + + std::deque<typename has_valid_turns::turn_type> turns; + bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns); + debug_print_turns(turns.begin(), turns.end()); + + if ( has_invalid_turns ) + { + return false; + } + + + // check if each polygon's interior rings are inside the + // exterior and not one inside the other + debug_phase::apply(3); + + if ( !have_holes_inside(boost::begin(multipolygon), + boost::end(multipolygon), + turns.begin(), + turns.end()) ) + { + return false; + } + + + // check that each polygon's interior is connected + debug_phase::apply(4); + + if ( !have_connected_interior(boost::begin(multipolygon), + boost::end(multipolygon), + turns.begin(), + turns.end()) ) + { + return false; + } + + + // check if polygon interiors are disjoint + debug_phase::apply(5); + return are_polygon_interiors_disjoint(boost::begin(multipolygon), + boost::end(multipolygon), + turns.begin(), + turns.end()); + } +}; + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// Not clear what the definition is. +// Right now we check that each element is simple (in fact valid), and +// that the MultiPolygon is also valid. +// +// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14) +template <typename MultiPolygon, bool AllowSpikes, bool AllowDuplicates> +struct is_valid<MultiPolygon, multi_polygon_tag, AllowSpikes, AllowDuplicates> + : detail::is_valid::is_valid_multipolygon<MultiPolygon, AllowDuplicates> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp new file mode 100644 index 0000000000..8a4818ef15 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// A point is always simple +template <typename Point> +struct is_valid<Point, point_tag> +{ + static inline bool apply(Point const&) + { + return true; + } +}; + + + +// A MultiPoint is simple if no two Points in the MultiPoint are equal +// (have identical coordinate values in X and Y) +// +// Reference: OGC 06-103r4 (6.1.5) +template <typename MultiPoint> +struct is_valid<MultiPoint, multi_point_tag> +{ + static inline bool apply(MultiPoint const& multipoint) + { + return boost::size(multipoint) > 0; + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp new file mode 100644 index 0000000000..3a91999208 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -0,0 +1,376 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP + +#include <cstddef> + +#include <algorithm> +#include <deque> +#include <iterator> +#include <set> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/range.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/tags.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/geometries/box.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/partition.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> +#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> +#include <boost/geometry/algorithms/detail/is_valid/ring.hpp> + +#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> +#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp> +#include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +template +< + typename Polygon, + bool AllowDuplicates, + bool CheckRingValidityOnly = false +> +class is_valid_polygon +{ +protected: + typedef debug_validity_phase<Polygon> debug_phase; + + + + template <typename InteriorRings> + static bool has_valid_interior_rings(InteriorRings const& interior_rings) + { + return + detail::check_iterator_range + < + detail::is_valid::is_valid_ring + < + typename boost::range_value<InteriorRings>::type, + AllowDuplicates, + false, // do not check self-intersections + true // indicate that the ring is interior + > + >::apply(boost::begin(interior_rings), + boost::end(interior_rings)); + } + + struct has_valid_rings + { + static inline bool apply(Polygon const& polygon) + { + typedef typename ring_type<Polygon>::type ring_type; + + // check validity of exterior ring + debug_phase::apply(1); + + if ( !detail::is_valid::is_valid_ring + < + ring_type, + AllowDuplicates, + false // do not check self intersections + >::apply(exterior_ring(polygon)) ) + { + return false; + } + + // check validity of interior rings + debug_phase::apply(2); + + return has_valid_interior_rings(geometry::interior_rings(polygon)); + } + }; + + + // structs from partition -- start + struct expand_box + { + template <typename Box, typename Iterator> + static inline void apply(Box& total, Iterator const& it) + { + geometry::expand(total, geometry::return_envelope<Box>(*it)); + } + + }; + + struct overlaps_box + { + template <typename Box, typename Iterator> + static inline bool apply(Box const& box, Iterator const& it) + { + return !geometry::disjoint(*it, box); + } + }; + + + struct item_visitor + { + bool items_overlap; + + item_visitor() : items_overlap(false) {} + + template <typename Item1, typename Item2> + inline void apply(Item1 const& item1, Item2 const& item2) + { + if ( !items_overlap + && (geometry::within(*points_begin(*item1), *item2) + || geometry::within(*points_begin(*item2), *item1)) + ) + { + items_overlap = true; + } + } + }; + // structs for partition -- end + + + template + < + typename RingIterator, + typename ExteriorRing, + typename TurnIterator + > + static inline bool are_holes_inside(RingIterator rings_first, + RingIterator rings_beyond, + ExteriorRing const& exterior_ring, + TurnIterator turns_first, + TurnIterator turns_beyond) + { + // collect the interior ring indices that have turns with the + // exterior ring + std::set<signed_index_type> ring_indices; + for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) + { + if ( tit->operations[0].seg_id.ring_index == -1 ) + { + BOOST_ASSERT( tit->operations[1].seg_id.ring_index != -1 ); + ring_indices.insert(tit->operations[1].seg_id.ring_index); + } + else if ( tit->operations[1].seg_id.ring_index == -1 ) + { + BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 ); + ring_indices.insert(tit->operations[0].seg_id.ring_index); + } + } + + signed_index_type ring_index = 0; + for (RingIterator it = rings_first; it != rings_beyond; + ++it, ++ring_index) + { + // do not examine interior rings that have turns with the + // exterior ring + if ( ring_indices.find(ring_index) == ring_indices.end() + && !geometry::covered_by(range::front(*it), exterior_ring) ) + { + return false; + } + } + + // collect all rings (exterior and/or interior) that have turns + for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) + { + ring_indices.insert(tit->operations[0].seg_id.ring_index); + ring_indices.insert(tit->operations[1].seg_id.ring_index); + } + + // put iterators for interior rings without turns in a vector + std::vector<RingIterator> ring_iterators; + ring_index = 0; + for (RingIterator it = rings_first; it != rings_beyond; + ++it, ++ring_index) + { + if ( ring_indices.find(ring_index) == ring_indices.end() ) + { + ring_iterators.push_back(it); + } + } + + // call partition to check is interior rings are disjoint from + // each other + item_visitor visitor; + + geometry::partition + < + geometry::model::box<typename point_type<Polygon>::type>, + expand_box, + overlaps_box + >::apply(ring_iterators, visitor); + + return !visitor.items_overlap; + } + + template + < + typename InteriorRings, + typename ExteriorRing, + typename TurnIterator + > + static inline bool are_holes_inside(InteriorRings const& interior_rings, + ExteriorRing const& exterior_ring, + TurnIterator first, + TurnIterator beyond) + { + return are_holes_inside(boost::begin(interior_rings), + boost::end(interior_rings), + exterior_ring, + first, + beyond); + } + + struct has_holes_inside + { + template <typename TurnIterator> + static inline bool apply(Polygon const& polygon, + TurnIterator first, + TurnIterator beyond) + { + return are_holes_inside(geometry::interior_rings(polygon), + geometry::exterior_ring(polygon), + first, + beyond); + } + }; + + + + + struct has_connected_interior + { + template <typename TurnIterator> + static inline bool apply(Polygon const& polygon, + TurnIterator first, + TurnIterator beyond) + { + typedef typename std::iterator_traits + < + TurnIterator + >::value_type turn_type; + typedef complement_graph<typename turn_type::point_type> graph; + + graph g(geometry::num_interior_rings(polygon) + 1); + for (TurnIterator tit = first; tit != beyond; ++tit) + { + typename graph::vertex_handle v1 = g.add_vertex + ( tit->operations[0].seg_id.ring_index + 1 ); + typename graph::vertex_handle v2 = g.add_vertex + ( tit->operations[1].seg_id.ring_index + 1 ); + typename graph::vertex_handle vip = g.add_vertex(tit->point); + + g.add_edge(v1, vip); + g.add_edge(v2, vip); + } + + debug_print_complement_graph(std::cout, g); + + return !g.has_cycles(); + } + }; + +public: + static inline bool apply(Polygon const& polygon) + { + if ( !has_valid_rings::apply(polygon) ) + { + return false; + } + + if ( CheckRingValidityOnly ) + { + return true; + } + + // compute turns and check if all are acceptable + debug_phase::apply(3); + + typedef has_valid_self_turns<Polygon> has_valid_turns; + + std::deque<typename has_valid_turns::turn_type> turns; + bool has_invalid_turns = !has_valid_turns::apply(polygon, turns); + debug_print_turns(turns.begin(), turns.end()); + + if ( has_invalid_turns ) + { + return false; + } + + // check if all interior rings are inside the exterior ring + debug_phase::apply(4); + + if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) ) + { + return false; + } + + // check whether the interior of the polygon is a connected set + debug_phase::apply(5); + + return has_connected_interior::apply(polygon, + turns.begin(), + turns.end()); + } +}; + + +}} // namespace detail::is_valid +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A Polygon is always a simple geometric object provided that it is valid. +// +// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1) +template <typename Polygon, bool AllowSpikes, bool AllowDuplicates> +struct is_valid<Polygon, polygon_tag, AllowSpikes, AllowDuplicates> + : detail::is_valid::is_valid_polygon<Polygon, AllowDuplicates> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp new file mode 100644 index 0000000000..c88df79b05 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -0,0 +1,173 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_order.hpp> + +#include <boost/geometry/util/order_as_direction.hpp> +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/equals.hpp> + +#include <boost/geometry/views/reversible_view.hpp> +#include <boost/geometry/views/closeable_view.hpp> + +#include <boost/geometry/algorithms/area.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> + +#include <boost/geometry/strategies/area.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_valid +{ + + +// struct to check whether a ring is topologically closed +template <typename Ring, closure_selector Closure /* open */> +struct is_topologically_closed +{ + static inline bool apply(Ring const&) + { + return true; + } +}; + +template <typename Ring> +struct is_topologically_closed<Ring, closed> +{ + static inline bool apply(Ring const& ring) + { + return geometry::equals(range::front(ring), range::back(ring)); + } +}; + + + +template <typename ResultType, bool IsInteriorRing /* false */> +struct ring_area_predicate +{ + typedef std::greater<ResultType> type; +}; + +template <typename ResultType> +struct ring_area_predicate<ResultType, true> +{ + typedef std::less<ResultType> type; +}; + + + +template <typename Ring, bool IsInteriorRing> +struct is_properly_oriented +{ + typedef typename point_type<Ring>::type point_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; + + typedef typename default_area_result<Ring>::type area_result_type; + + static inline bool apply(Ring const& ring) + { + typename ring_area_predicate + < + area_result_type, IsInteriorRing + >::type predicate; + + // Check area + area_result_type const zero = area_result_type(); + return predicate(ring_area_type::apply(ring, strategy_type()), zero); + } +}; + + + +template +< + typename Ring, + bool AllowDuplicates, + bool CheckSelfIntersections = true, + bool IsInteriorRing = false +> +struct is_valid_ring +{ + static inline bool apply(Ring const& ring) + { + // return invalid if any of the following condition holds: + // (a) the ring's size is below the minimal one + // (b) the ring is not topologically closed + // (c) the ring has spikes + // (d) the ring has duplicate points (if AllowDuplicates is false) + // (e) the boundary of the ring has self-intersections + // (f) the order of the points is inconsistent with the defined order + // + // Note: no need to check if the area is zero. If this is the + // case, then the ring must have at least two spikes, which is + // checked by condition (c). + + closure_selector const closure = geometry::closure<Ring>::value; + + return + ( boost::size(ring) + >= core_detail::closure::minimum_ring_size<closure>::value ) + && is_topologically_closed<Ring, closure>::apply(ring) + && (AllowDuplicates || !has_duplicates<Ring, closure>::apply(ring)) + && !has_spikes<Ring, closure>::apply(ring) + && !(CheckSelfIntersections && geometry::intersects(ring)) + && is_properly_oriented<Ring, IsInteriorRing>::apply(ring); + } +}; + + +}} // namespace dispatch +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// A Ring is a Polygon with exterior boundary only. +// The Ring's boundary must be a LinearRing (see OGC 06-103-r4, +// 6.1.7.1, for the definition of LinearRing) +// +// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) +template <typename Ring, bool AllowSpikes, bool AllowDuplicates> +struct is_valid<Ring, ring_tag, AllowSpikes, AllowDuplicates> + : detail::is_valid::is_valid_ring<Ring, AllowDuplicates> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp new file mode 100644 index 0000000000..486289dabe --- /dev/null +++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp @@ -0,0 +1,61 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/equals.hpp> + +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> + + +namespace boost { namespace geometry +{ + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// A segment is a curve. +// A curve is simple if it does not pass through the same point twice, +// with the possible exception of its two endpoints +// A curve is 1-dimensional, hence we have to check is the two +// endpoints of the segment coincide, since in this case it is +// 0-dimensional. +// +// Reference: OGC 06-103r4 (6.1.6.1) +template <typename Segment> +struct is_valid<Segment, segment_tag> +{ + static inline bool apply(Segment const& segment) + { + typename point_type<Segment>::type p[2]; + detail::assign_point_from_index<0>(segment, p[0]); + detail::assign_point_from_index<1>(segment, p[1]); + + return !geometry::equals(p[0], p[1]); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp new file mode 100644 index 0000000000..f0b9ddd3e6 --- /dev/null +++ b/boost/geometry/algorithms/detail/multi_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_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_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_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP diff --git a/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp new file mode 100644 index 0000000000..c3787f9a10 --- /dev/null +++ b/boost/geometry/algorithms/detail/multi_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_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_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_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP diff --git a/boost/geometry/algorithms/detail/multi_sum.hpp b/boost/geometry/algorithms/detail/multi_sum.hpp new file mode 100644 index 0000000000..af3f425c9c --- /dev/null +++ b/boost/geometry/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_ALGORITHMS_DETAIL_MULTI_SUM_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_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_ALGORITHMS_DETAIL_MULTI_SUM_HPP diff --git a/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp new file mode 100644 index 0000000000..16fba72fe0 --- /dev/null +++ b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP + +#include <cstddef> + +#include <algorithm> + +#include <boost/range.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +// returns the number of distinct values in the range; +// return values are 0u through MaximumNumber, where MaximumNumber +// corresponds to MaximumNumber or more distinct values +// +// FUTURE: take into account topologically closed ranges; +// add appropriate template parameter(s) to control whether +// the closing point for topologically closed ranges is to be +// accounted for separately or not +template +< + typename Range, + std::size_t MaximumNumber, + bool AllowDuplicates /* true */, + typename NotEqualTo +> +struct num_distinct_consecutive_points +{ + static inline std::size_t apply(Range const& range) + { + typedef typename boost::range_iterator<Range const>::type iterator; + + std::size_t const size = boost::size(range); + + if ( size < 2u ) + { + return (size < MaximumNumber) ? size : MaximumNumber; + } + + iterator current = boost::begin(range); + std::size_t counter(0); + do + { + ++counter; + iterator next = std::find_if(current, + boost::end(range), + NotEqualTo(*current)); + current = next; + } + while ( current != boost::end(range) && counter <= MaximumNumber ); + + return counter; + } +}; + + +template <typename Range, std::size_t MaximumNumber, typename NotEqualTo> +struct num_distinct_consecutive_points<Range, MaximumNumber, false, NotEqualTo> +{ + static inline std::size_t apply(Range const& range) + { + std::size_t const size = boost::size(range); + return (size < MaximumNumber) ? size : MaximumNumber; + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp index e147ba12d8..d90f3cf7cf 100644 --- a/boost/geometry/algorithms/detail/occupation_info.hpp +++ b/boost/geometry/algorithms/detail/occupation_info.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -9,17 +9,13 @@ #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/policies/compare.hpp> #include <boost/geometry/iterators/closing_iterator.hpp> #include <boost/geometry/algorithms/detail/get_left_turns.hpp> @@ -33,291 +29,159 @@ namespace boost { namespace geometry 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 T angle_type; typedef Point point_type; segment_identifier seg_id; int turn_index; int operation_index; + std::size_t cluster_index; Point intersection_point; - Point direction_point; - T angle; + Point point; // either incoming or outgoing point bool incoming; + bool blocked; + bool included; + + inline angle_info() + : blocked(false) + , included(false) + {} }; 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) - {} + typedef std::vector<AngleInfo> collection_type; - template <typename PointC, typename Point1, typename Point2> - inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point, + template <typename RobustPoint> + inline void add(RobustPoint const& incoming_point, + RobustPoint const& outgoing_point, + RobustPoint 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; - } + segment_identifier const& seg_id) + { + geometry::equal_to<RobustPoint> comparator; + if (comparator(incoming_point, intersection_point)) + { + return; + } + if (comparator(outgoing_point, intersection_point)) + { + 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; + { + info.point = incoming_point; + info.incoming = true; + m_angles.push_back(info); + } + { + info.point = outgoing_point; + info.incoming = false; + m_angles.push_back(info); + } + } - if (comparator.equals(intersection_point, *it)) + template <typename RobustPoint, typename Turns> + inline void get_left_turns(RobustPoint const& origin, Turns& turns) { - // It should be equal only once. But otherwise we skip it (in "add") - it = advance_circular(it, ring, seg_id, false); + // Sort on angle + std::sort(m_angles.begin(), m_angles.end(), + detail::left_turns::angle_less<typename AngleInfo::point_type>(origin)); + + // Group same-angled elements + std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin); + // Block all turns on the right side of any turn + detail::left_turns::block_turns(m_angles, cluster_size); + detail::left_turns::get_left_turns(m_angles, turns); } - 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++) +#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS) + template <typename RobustPoint> + inline bool has_rounding_issues(RobustPoint const& origin) const { - it = advance_circular(it, ring, real_seg_id); + return detail::left_turns::has_rounding_issues(angles, origin); } +#endif - info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false); -} - +private : + collection_type m_angles; // each turn splitted in incoming/outgoing vectors +}; -// 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 +template<typename Pieces> +inline void move_index(Pieces const& pieces, int& index, int& piece_index, int direction) { -public : - typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type; + BOOST_ASSERT(direction == 1 || direction == -1); + BOOST_ASSERT(piece_index >= 0 && piece_index < static_cast<int>(boost::size(pieces)) ); + BOOST_ASSERT(index >= 0 && index < static_cast<int>(boost::size(pieces[piece_index].robust_ring))); - map_type map; - std::set<int> turn_indices; - - inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point) + index += direction; + if (direction == -1 && index < 0) { - typename map_type::iterator it = map.find(point); - if (it == boost::end(map)) + piece_index--; + if (piece_index < 0) { - std::pair<typename map_type::iterator, bool> pair - = map.insert(std::make_pair(point, OccupationInfo())); - it = pair.first; + piece_index = boost::size(pieces) - 1; } - mapped_point = it->first; - return it->second; + index = boost::size(pieces[piece_index].robust_ring) - 1; } - - inline bool contains(Point const& point) const + if (direction == 1 + && index >= static_cast<int>(boost::size(pieces[piece_index].robust_ring))) { - typename map_type::const_iterator it = map.find(point); - return it != boost::end(map); + piece_index++; + if (piece_index >= static_cast<int>(boost::size(pieces))) + { + piece_index = 0; + } + index = 0; } +} - inline bool contains_turn_index(int index) const - { - return turn_indices.count(index) > 0; - } - inline void insert_turn_index(int index) +template +< + typename RobustPoint, + typename Turn, + typename Pieces, + typename Info +> +inline void add_incoming_and_outgoing_angles( + RobustPoint const& intersection_point, // rescaled + Turn const& turn, + Pieces const& pieces, // using rescaled offsets of it + int operation_index, + segment_identifier seg_id, + Info& info) +{ + segment_identifier real_seg_id = seg_id; + geometry::equal_to<RobustPoint> comparator; + + // Move backward and forward + RobustPoint direction_points[2]; + for (int i = 0; i < 2; i++) { - turn_indices.insert(index); + int index = turn.operations[operation_index].index_in_robust_ring; + int piece_index = turn.operations[operation_index].piece_index; + while(comparator(pieces[piece_index].robust_ring[index], intersection_point)) + { + move_index(pieces, index, piece_index, i == 0 ? -1 : 1); + } + direction_points[i] = pieces[piece_index].robust_ring[index]; } -}; + + info.add(direction_points[0], direction_points[1], intersection_point, + turn.turn_index, operation_index, real_seg_id); +} } // namespace detail diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp index 74595fedd0..5ff0b57d6e 100644 --- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp @@ -75,15 +75,15 @@ inline OutputIterator add_rings(SelectionMap const& map, 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 + 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 @@ -117,15 +117,14 @@ inline OutputIterator add_rings(SelectionMap const& map, } } - // 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) - // TODO: individual rings can still contain less than 3 points. - if (geometry::num_points(result) >= min_num_points - && math::larger(geometry::area(result), zero)) - { - *out++ = result; - } + // 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; diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp index 2c0f88e2aa..0fd1fe4de9 100644 --- a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp +++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp @@ -13,7 +13,7 @@ #include <boost/range.hpp> #include <boost/geometry/algorithms/append.hpp> -#include <boost/geometry/algorithms/detail/disjoint.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> @@ -29,7 +29,7 @@ template <typename Range, typename Point> inline void append_no_duplicates(Range& range, Point const& point, bool force = false) { if (boost::size(range) == 0 - || force + || force || ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point)) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp new file mode 100644 index 0000000000..d44db17ad3 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -0,0 +1,160 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_DUPS_OR_SPIKES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> + +#include <boost/geometry/util/range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +// TODO: move this / rename this +template <typename Point1, typename Point2, typename RobustPolicy> +inline bool points_equal_or_close(Point1 const& point1, + Point2 const& point2, + RobustPolicy const& robust_policy) +{ + if (detail::equals::equals_point_point(point1, point2)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type point1_rob, point2_rob; + geometry::recalculate(point1_rob, point1, robust_policy); + geometry::recalculate(point2_rob, point2, robust_policy); + + return detail::equals::equals_point_point(point1_rob, point2_rob); +} + + +template <typename Range, typename Point, typename RobustPolicy> +inline void append_no_dups_or_spikes(Range& range, Point const& point, + RobustPolicy const& robust_policy) +{ +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION + std::cout << " add: (" + << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" + << std::endl; +#endif + // The code below thies condition checks all spikes/dups + // for geometries >= 3 points. + // So we have to check the first potential duplicate differently + if (boost::size(range) == 1 + && points_equal_or_close(*(boost::begin(range)), point, robust_policy)) + { + return; + } + + traits::push_back<Range>::apply(range, point); + + // If a point is equal, or forming a spike, remove the pen-ultimate point + // because this one caused the spike. + // If so, the now-new-pen-ultimate point can again cause a spike + // (possibly at a corner). So keep doing this. + // Besides spikes it will also avoid adding duplicates. + while(boost::size(range) >= 3 + && point_is_spike_or_equal(point, + *(boost::end(range) - 3), + *(boost::end(range) - 2), + robust_policy)) + { + // Use the Concept/traits, so resize and append again + traits::resize<Range>::apply(range, boost::size(range) - 2); + traits::push_back<Range>::apply(range, point); + } +} + +template <typename Range, typename RobustPolicy> +inline void clean_closing_dups_and_spikes(Range& range, + RobustPolicy const& robust_policy) +{ + std::size_t const minsize + = core_detail::closure::minimum_ring_size + < + geometry::closure<Range>::value + >::value; + + if (boost::size(range) <= minsize) + { + return; + } + + typedef typename boost::range_iterator<Range>::type iterator_type; + static bool const closed = geometry::closure<Range>::value == geometry::closed; + +// TODO: the following algorithm could be rewritten to first look for spikes +// and then erase some number of points from the beginning of the Range + + bool found = false; + do + { + found = false; + iterator_type first = boost::begin(range); + iterator_type second = first + 1; + iterator_type ultimate = boost::end(range) - 1; + if (closed) + { + ultimate--; + } + + // Check if closing point is a spike (this is so if the second point is + // considered as a spike w.r.t. the last segment) + if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) + { + range::erase(range, first); + if (closed) + { + // Remove closing last point + range::resize(range, boost::size(range) - 1); + // Add new closing point + range::push_back(range, range::front(range)); + } + found = true; + } + } while(found && boost::size(range) > minsize); +} + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 5063f49eb4..67b48cc471 100644 --- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -18,6 +18,10 @@ #include <boost/geometry/geometries/box.hpp> +#ifdef BOOST_GEOMETRY_TIME_OVERLAY +# include <boost/timer.hpp> +#endif + namespace boost { namespace geometry { @@ -123,30 +127,30 @@ struct assign_visitor template <typename Item> inline void apply(Item const& outer, Item const& inner, bool first = true) { - if (first && outer.real_area < 0) + if (first && outer.abs_area < inner.abs_area) { - // Reverse arguments + // Apply with reversed arguments apply(inner, outer, false); return; } - if (math::larger(outer.real_area, 0)) + if (m_check_for_orientation + || (math::larger(outer.real_area, 0) + && math::smaller(inner.real_area, 0))) { - if (inner.real_area < 0 || m_check_for_orientation) - { - ring_info_type& inner_in_map = m_ring_map[inner.id]; + 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) - ) + if (geometry::within(inner_in_map.point, outer.envelope) + && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection) + ) + { + // Assign a parent if there was no earlier parent, or the newly + // found parent is smaller than the previous one + if (inner_in_map.parent.source_index == -1 + || outer.abs_area < inner_in_map.parent_area) { - // 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; - } + inner_in_map.parent = outer.id; + inner_in_map.parent_area = outer.abs_area; } } } @@ -243,7 +247,7 @@ inline void assign_parents(Geometry1 const& geometry1, // 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; + index = 0; for (vector_iterator_type it = boost::begin(vector); it != boost::end(vector); ++it, ++index) { @@ -284,13 +288,21 @@ inline void assign_parents(Geometry1 const& geometry1, { it->second.discarded = true; } - else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0) + else if (it->second.parent.source_index >= 0 + && math::larger(it->second.get_area(), 0)) { - // Discard positive inner ring with parent - it->second.discarded = true; + const ring_info_type& parent = ring_map[it->second.parent]; + + if (math::larger(parent.area, 0)) + { + // Discard positive inner ring with positive parent + it->second.discarded = true; + } + // Remove parent ID from any positive inner ring it->second.parent.source_index = -1; } - else if (it->second.parent.source_index < 0 && it->second.get_area() < 0) + else if (it->second.parent.source_index < 0 + && math::smaller(it->second.get_area(), 0)) { // Reverse negative ring without parent it->second.reversed = true; @@ -309,6 +321,8 @@ inline void assign_parents(Geometry1 const& geometry1, } } + +// Version for one geometry (called by buffer) template < typename Geometry, @@ -320,7 +334,7 @@ inline void assign_parents(Geometry const& geometry, RingMap& ring_map, bool check_for_orientation) { - // Call it with an empty geometry + // Call it with an empty geometry as second geometry (source_id == 1) // (ring_map should be empty for source_id==1) Geometry empty; diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp index 012b3aca30..90901dee70 100644 --- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp +++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -55,8 +55,8 @@ inline void clear_visit_info(Turns& turns) struct backtrack_state { bool m_good; - - inline backtrack_state() : m_good(true) {} + + inline backtrack_state() : m_good(true) {} inline void reset() { m_good = true; } inline bool good() const { return m_good; } }; @@ -79,29 +79,30 @@ class backtrack_check_self_intersections 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, + template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy> + static inline void apply(std::size_t size_at_start, + Rings& rings, Ring& ring, Turns& turns, Operation& operation, std::string const& , Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, 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); + has_self_intersections(geometry1, robust_policy); + has_self_intersections(geometry2, robust_policy); } // Make bad output clean rings.resize(size_at_start); - ring.clear(); + geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring); // Reject this as a starting point operation.visited.set_rejected(); @@ -123,7 +124,7 @@ public : typedef backtrack_state state_type; template <typename Operation, typename Rings, typename Turns> - static inline void apply(std::size_t size_at_start, + 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, @@ -133,7 +134,7 @@ public : ) { std::cout << " REJECT " << reason << std::endl; - + state.m_good = false; rings.resize(size_at_start); diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp deleted file mode 100644 index 2003d2350d..0000000000 --- a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// 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 index b210fd04b1..03be18e07a 100644 --- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp +++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp @@ -137,7 +137,7 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation) it != boost::end(meta_turns); ++it) { - if (! (it->turn->blocked() || it->turn->is_discarded())) + if (! (it->turn->blocked() || it->turn->discarded)) { for (int i = 0 ; i < 2; i++) { diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp index 05bd721e7f..51955b515d 100644 --- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp +++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp @@ -77,12 +77,23 @@ struct convert_ring<polygon_tag> } else { - interior_rings(destination).resize( - interior_rings(destination).size() + 1); - geometry::convert(source, interior_rings(destination).back()); - if (reverse) + // 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) { - boost::reverse(interior_rings(destination).back()); + interior_rings(destination).resize( + interior_rings(destination).size() + 1); + geometry::convert(source, interior_rings(destination).back()); + if (reverse) + { + boost::reverse(interior_rings(destination).back()); + } } } } diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp index 5e18d0453a..20a6d7f48d 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp @@ -17,8 +17,10 @@ #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/tags.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> @@ -51,7 +53,7 @@ struct copy_segment_point_range SegmentIdentifier const& seg_id, bool second, PointOut& point) { - int index = seg_id.segment_index; + signed_index_type index = seg_id.segment_index; if (second) { index++; @@ -94,8 +96,8 @@ struct copy_segment_point_polygon >::apply ( seg_id.ring_index < 0 - ? geometry::exterior_ring(polygon) - : geometry::interior_rings(polygon)[seg_id.ring_index], + ? geometry::exterior_ring(polygon) + : range::at(geometry::interior_rings(polygon), seg_id.ring_index), seg_id, second, point ); @@ -110,7 +112,7 @@ struct copy_segment_point_box SegmentIdentifier const& seg_id, bool second, PointOut& point) { - int index = seg_id.segment_index; + signed_index_type index = seg_id.segment_index; if (second) { index++; @@ -124,6 +126,30 @@ struct copy_segment_point_box }; +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(range::at(multi, seg_id.multi_index), seg_id, second, point); + } +}; }} // namespace detail::copy_segments @@ -188,6 +214,66 @@ struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut> {}; +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 + > + > +{}; + +template +< + typename MultiGeometry, + bool Reverse, + typename SegmentIdentifier, + typename PointOut +> +struct copy_segment_point + < + multi_linestring_tag, + MultiGeometry, + Reverse, + SegmentIdentifier, + PointOut + > + : detail::copy_segments::copy_segment_point_multi + < + MultiGeometry, + SegmentIdentifier, + PointOut, + detail::copy_segments::copy_segment_point_range + < + typename boost::range_value<MultiGeometry>::type, + Reverse, + SegmentIdentifier, + PointOut + > + > +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 805f3923e3..ceeb1a3b8b 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -1,6 +1,12 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,24 +16,32 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP -#include <boost/array.hpp> -#include <boost/mpl/assert.hpp> #include <vector> +#include <boost/array.hpp> #include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> #include <boost/range.hpp> +#include <boost/type_traits/integral_constant.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/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/algorithms/not_implemented.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> +#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp> + +#include <boost/geometry/util/range.hpp> + namespace boost { namespace geometry { @@ -38,34 +52,38 @@ namespace detail { namespace copy_segments { -template -< - typename Ring, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template <bool Reverse> struct copy_segments_ring { - typedef typename closeable_view + template + < + typename Ring, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > + static inline void apply(Ring const& ring, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, + RangeOut& current_output) + { + typedef typename closeable_view < Ring const, closure<Ring>::value >::type cview_type; - typedef typename reversible_view + 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; + 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); @@ -75,10 +93,10 @@ struct copy_segments_ring // So we use the ever-circling iterator and determine when to step out - int const from_index = seg_id.segment_index + 1; + signed_index_type const from_index = seg_id.segment_index + 1; // Sanity check - BOOST_ASSERT(from_index < int(boost::size(view))); + BOOST_ASSERT(from_index < static_cast<signed_index_type>(boost::size(view))); ec_iterator it(boost::begin(view), boost::end(view), boost::begin(view) + from_index); @@ -86,103 +104,130 @@ struct copy_segments_ring // [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 + signed_index_type const count = from_index <= to_index ? to_index - from_index + 1 - : int(boost::size(view)) - from_index + to_index + 1; + : static_cast<signed_index_type>(boost::size(view)) + - from_index + to_index + 1; - for (size_type i = 0; i < count; ++i, ++it) + for (signed_index_type i = 0; i < count; ++i, ++it) { - detail::overlay::append_no_duplicates(current_output, *it); + detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy); } } }; -template -< - typename LineString, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments_linestring +template <bool Reverse, bool RemoveSpikes = true> +class copy_segments_linestring { +private: + // remove spikes + template <typename RangeOut, typename Point, typename RobustPolicy> + static inline void append_to_output(RangeOut& current_output, + Point const& point, + RobustPolicy const& robust_policy, + boost::true_type const&) + { + detail::overlay::append_no_dups_or_spikes(current_output, point, + robust_policy); + } - typedef typename boost::range_iterator<LineString const>::type iterator; + // keep spikes + template <typename RangeOut, typename Point, typename RobustPolicy> + static inline void append_to_output(RangeOut& current_output, + Point const& point, + RobustPolicy const&, + boost::false_type const&) + { + detail::overlay::append_no_duplicates(current_output, point); + } +public: + template + < + typename LineString, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(LineString const& ls, - SegmentIdentifier const& seg_id, int to_index, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { - int const from_index = seg_id.segment_index + 1; + signed_index_type const from_index = seg_id.segment_index + 1; // Sanity check - if (from_index > to_index || from_index < 0 || to_index >= int(boost::size(ls))) + if ( from_index > to_index + || from_index < 0 + || to_index >= static_cast<signed_index_type>(boost::size(ls)) ) { return; } - typedef typename boost::range_difference<LineString>::type size_type; - size_type const count = to_index - from_index + 1; + signed_index_type const count = to_index - from_index + 1; - typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index; + typename boost::range_iterator<LineString const>::type + it = boost::begin(ls) + from_index; - for (size_type i = 0; i < count; ++i, ++it) + for (signed_index_type i = 0; i < count; ++i, ++it) { - detail::overlay::append_no_duplicates(current_output, *it); + append_to_output(current_output, *it, robust_policy, + boost::integral_constant<bool, RemoveSpikes>()); } } }; -template -< - typename Polygon, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template <bool Reverse> struct copy_segments_polygon { + template + < + typename Polygon, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(Polygon const& polygon, - SegmentIdentifier const& seg_id, int to_index, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, 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 + copy_segments_ring<Reverse>::apply + ( + seg_id.ring_index < 0 ? geometry::exterior_ring(polygon) - : geometry::interior_rings(polygon)[seg_id.ring_index], - seg_id, to_index, - current_output - ); + : range::at(geometry::interior_rings(polygon), seg_id.ring_index), + seg_id, to_index, + robust_policy, + current_output + ); } }; -template -< - typename Box, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template <bool Reverse> struct copy_segments_box { + template + < + typename Box, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(Box const& box, - SegmentIdentifier const& seg_id, int to_index, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { - int index = seg_id.segment_index + 1; + signed_index_type index = seg_id.segment_index + 1; BOOST_ASSERT(index < 5); - int const count = index <= to_index + signed_index_type const count = index <= to_index ? to_index - index + 1 : 5 - index + to_index + 1; @@ -193,15 +238,48 @@ struct copy_segments_box // (possibly cyclic) copy to output // (see comments in ring-version) - for (int i = 0; i < count; i++, index++) + for (signed_index_type i = 0; i < count; i++, index++) { - detail::overlay::append_no_duplicates(current_output, bp[index % 5]); + detail::overlay::append_no_dups_or_spikes(current_output, + bp[index % 5], robust_policy); } } }; +template<typename Policy> +struct copy_segments_multi +{ + template + < + typename MultiGeometry, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > + static inline void apply(MultiGeometry const& multi_geometry, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, + 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(range::at(multi_geometry, seg_id.multi_index), + seg_id, to_index, + robust_policy, + current_output); + } +}; + + }} // namespace detail::copy_segments #endif // DOXYGEN_NO_DETAIL @@ -213,82 +291,44 @@ namespace dispatch template < typename Tag, - typename GeometryIn, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut + bool Reverse > -struct copy_segments -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<GeometryIn>) - ); -}; +struct copy_segments : not_implemented<Tag> +{}; -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 <bool Reverse> +struct copy_segments<ring_tag, Reverse> + : detail::copy_segments::copy_segments_ring<Reverse> {}; +template <bool Reverse> +struct copy_segments<linestring_tag, Reverse> + : detail::copy_segments::copy_segments_linestring<Reverse> +{}; -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 <bool Reverse> +struct copy_segments<polygon_tag, Reverse> + : detail::copy_segments::copy_segments_polygon<Reverse> {}; -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 <bool Reverse> +struct copy_segments<box_tag, Reverse> + : detail::copy_segments::copy_segments_box<Reverse> {}; -template -< - typename Box, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut> - : detail::copy_segments::copy_segments_box +template<bool Reverse> +struct copy_segments<multi_polygon_tag, Reverse> + : detail::copy_segments::copy_segments_multi < - Box, Reverse, SegmentIdentifier, RangeOut + detail::copy_segments::copy_segments_polygon<Reverse> > {}; - } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -303,10 +343,13 @@ template bool Reverse, typename Geometry, typename SegmentIdentifier, + typename RobustPolicy, typename RangeOut > inline void copy_segments(Geometry const& geometry, - SegmentIdentifier const& seg_id, int to_index, + SegmentIdentifier const& seg_id, + signed_index_type to_index, + RobustPolicy const& robust_policy, RangeOut& range_out) { concept::check<Geometry const>(); @@ -314,11 +357,8 @@ inline void copy_segments(Geometry const& geometry, dispatch::copy_segments < typename tag<Geometry>::type, - Geometry, - Reverse, - SegmentIdentifier, - RangeOut - >::apply(geometry, seg_id, to_index, range_out); + Reverse + >::apply(geometry, seg_id, to_index, robust_policy, range_out); } diff --git a/boost/geometry/algorithms/detail/overlay/do_reverse.hpp b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp new file mode 100644 index 0000000000..15100f8d0b --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 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_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP + +#include <boost/geometry/core/point_order.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +// 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_DO_REVERSE_HPP diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index e4842d35f1..9484479b45 100644 --- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -27,8 +27,9 @@ #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> +#include <boost/geometry/policies/robustness/robust_type.hpp> +#include <boost/geometry/strategies/side.hpp> #ifdef BOOST_GEOMETRY_DEBUG_ENRICH # include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp> #endif @@ -47,17 +48,23 @@ struct indexed_turn_operation { typedef TurnOperation type; - int index; - int operation_index; + std::size_t turn_index; + std::size_t operation_index; bool discarded; - TurnOperation subject; - - inline indexed_turn_operation(int i, int oi, TurnOperation const& s) - : index(i) + // use pointers to avoid copies, const& is not possible because of usage in vector + segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments + TurnOperation const* subject; + + inline indexed_turn_operation(std::size_t ti, std::size_t oi, + TurnOperation const& s, + segment_identifier const& oid) + : turn_index(ti) , operation_index(oi) , discarded(false) - , subject(s) + , other_seg_id(&oid) + , subject(&s) {} + }; template <typename IndexedTurnOperation> @@ -75,19 +82,22 @@ template typename TurnPoints, typename Indexed, typename Geometry1, typename Geometry2, + typename RobustPolicy, bool Reverse1, bool Reverse2, typename Strategy > -struct sort_on_segment_and_distance +struct sort_on_segment_and_ratio { - inline sort_on_segment_and_distance(TurnPoints const& turn_points + inline sort_on_segment_and_ratio(TurnPoints const& turn_points , Geometry1 const& geometry1 , Geometry2 const& geometry2 + , RobustPolicy const& robust_policy , Strategy const& strategy , bool* clustered) : m_turn_points(turn_points) , m_geometry1(geometry1) , m_geometry2(geometry2) + , m_robust_policy(robust_policy) , m_strategy(strategy) , m_clustered(clustered) { @@ -98,31 +108,47 @@ private : TurnPoints const& m_turn_points; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; + RobustPolicy const& m_robust_policy; Strategy const& m_strategy; mutable bool* m_clustered; + typedef typename geometry::point_type<Geometry1>::type point_type; + 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, + left.subject->seg_id, pi, pj); geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, - left.subject.other_id, + *left.other_seg_id, ri, rj); geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, - right.subject.other_id, + *right.other_seg_id, si, sj); - int const order = get_relative_order + typedef typename strategy::side::services::default_strategy < - point_type - >::apply(pi, pj,ri, rj, si, sj); - //debug("r/o", order == -1); - return order == -1; + typename cs_tag<point_type>::type + >::type strategy; + + int const side_rj_p = strategy::apply(pi, pj, rj); + int const side_sj_p = strategy::apply(pi, pj, sj); + + // Put the one turning left (1; right == -1) as last + if (side_rj_p != side_sj_p) + { + return side_rj_p < side_sj_p; + } + + int const side_sj_r = strategy::apply(ri, rj, sj); + int const side_rj_s = strategy::apply(si, sj, rj); + + // If they both turn left: the most left as last + // If they both turn right: this is not relevant, but take also here most left + return side_rj_s < side_sj_r; } public : @@ -131,33 +157,30 @@ public : // 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; + segment_identifier const& sl = left.subject->seg_id; + segment_identifier const& sr = right.subject->seg_id; - if (sl == sr - && geometry::math::equals(left.subject.enriched.distance - , right.subject.enriched.distance)) + if (sl == sr) { // Both left and right are located on the SAME segment. - - // First check "real" intersection (crosses) - // -> distance zero due to precision, solve it by sorting - if (m_turn_points[left.index].method == method_crosses - && m_turn_points[right.index].method == method_crosses) + if (left.subject->fraction == right.subject->fraction) { - return consider_relative_order(left, right); - } - - // If that is not the case, cluster it later on. - // Indicate that this is necessary. - *m_clustered = true; + // First check "real" intersection (crosses) + // -> distance zero due to precision, solve it by sorting + if (m_turn_points[left.turn_index].method == method_crosses + && m_turn_points[right.turn_index].method == method_crosses) + { + return consider_relative_order(left, right); + } - return left.index < right.index; + // If that is not the case, cluster it later on. + // Indicate that this is necessary. + *m_clustered = true; + } } return sl == sr - ? left.subject.enriched.distance < right.subject.enriched.distance + ? left.subject->fraction < right.subject->fraction : sl < sr; - } }; @@ -171,13 +194,13 @@ inline void update_discarded(Turns& turn_points, Operations& operations) it != boost::end(operations); ++it) { - if (turn_points[it->index].discarded) + if (turn_points[it->turn_index].discarded) { it->discarded = true; } else if (it->discarded) { - turn_points[it->index].discarded = true; + turn_points[it->turn_index].discarded = true; } } } @@ -195,12 +218,14 @@ template typename Container, typename TurnPoints, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename Strategy > inline void enrich_sort(Container& operations, TurnPoints& turn_points, operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, Strategy const& strategy) { typedef typename IndexType::type operations_type; @@ -208,14 +233,15 @@ inline void enrich_sort(Container& operations, bool clustered = false; std::sort(boost::begin(operations), boost::end(operations), - sort_on_segment_and_distance + sort_on_segment_and_ratio < TurnPoints, IndexType, Geometry1, Geometry2, + RobustPolicy, Reverse1, Reverse2, Strategy - >(turn_points, geometry1, geometry2, strategy, &clustered)); + >(turn_points, geometry1, geometry2, robust_policy, 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 @@ -230,16 +256,15 @@ inline void enrich_sort(Container& operations, it != boost::end(operations); prev = it++) { - operations_type& prev_op = turn_points[prev->index] + operations_type& prev_op = turn_points[prev->turn_index] .operations[prev->operation_index]; - operations_type& op = turn_points[it->index] + operations_type& op = turn_points[it->turn_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)) + && (turn_points[prev->turn_index].method != method_crosses + || turn_points[it->turn_index].method != method_crosses) + && prev_op.fraction == op.fraction) { if (begin_cluster == boost::end(operations)) { @@ -249,14 +274,14 @@ inline void enrich_sort(Container& operations, else if (begin_cluster != boost::end(operations)) { handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points, - for_operation, geometry1, geometry2, strategy); + for_operation, geometry1, geometry2, robust_policy, 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); + for_operation, geometry1, geometry2, robust_policy, strategy); } } @@ -315,19 +340,19 @@ inline void enrich_assign(Container& operations, prev = it++) { operations_type& prev_op - = turn_points[prev->index].operations[prev->operation_index]; + = turn_points[prev->turn_index].operations[prev->operation_index]; operations_type& op - = turn_points[it->index].operations[it->operation_index]; + = turn_points[it->turn_index].operations[it->operation_index]; prev_op.enriched.travels_to_ip_index - = it->index; + = static_cast<int>(it->turn_index); prev_op.enriched.travels_to_vertex_index - = it->subject.seg_id.segment_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; + prev_op.enriched.next_ip_index = static_cast<int>(it->turn_index); } first = false; } @@ -340,16 +365,16 @@ inline void enrich_assign(Container& operations, it != boost::end(operations); ++it) { - operations_type& op = turn_points[it->index] + operations_type& op = turn_points[it->turn_index] .operations[it->operation_index]; - std::cout << it->index - << " meth: " << method_char(turn_points[it->index].method) + std::cout << it->turn_index + << " meth: " << method_char(turn_points[it->turn_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") + << " dst: " << op.fraction // needs define + << " op: " << operation_char(turn_points[it->turn_index].operations[0].operation) + << operation_char(turn_points[it->turn_index].operations[1].operation) + << " dsc: " << (turn_points[it->turn_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 @@ -370,7 +395,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto typedef typename boost::range_value<TurnPoints>::type turn_point_type; typedef typename turn_point_type::container_type container_type; - int index = 0; + std::size_t index = 0; for (typename boost::range_iterator<TurnPoints const>::type it = boost::begin(turn_points); it != boost::end(turn_points); @@ -379,7 +404,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto // Add operations on this ring, but skip discarded ones if (! it->discarded) { - int op_index = 0; + std::size_t op_index = 0; for (typename boost::range_iterator<container_type const>::type op_it = boost::begin(it->operations); op_it != boost::end(it->operations); @@ -397,7 +422,8 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto ); mapped_vector[ring_id].push_back ( - IndexedType(index, op_index, *op_it) + IndexedType(index, op_index, *op_it, + it->operations[1 - op_index].seg_id) ); } } @@ -422,6 +448,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto \param for_operation operation_type (union or intersection) \param geometry1 \param_geometry \param geometry2 \param_geometry +\param robust_policy policy to handle robustness issues \param strategy strategy */ template @@ -429,11 +456,13 @@ template bool Reverse1, bool Reverse2, typename TurnPoints, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename Strategy > inline void enrich_intersection_points(TurnPoints& turn_points, detail::overlay::operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, Strategy const& strategy) { typedef typename boost::range_value<TurnPoints>::type turn_point_type; @@ -462,6 +491,10 @@ inline void enrich_intersection_points(TurnPoints& turn_points, { it->discarded = true; } + if (it->both(detail::overlay::operation_none)) + { + it->discarded = true; + } } @@ -484,7 +517,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points, << mit->first << std::endl; #endif detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation, - geometry1, geometry2, strategy); + geometry1, geometry2, robust_policy, strategy); } for (typename mapped_vector_type::iterator mit diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp index 8c8ed96189..ef32edeefa 100644 --- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp @@ -10,9 +10,6 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP -#include <boost/geometry/strategies/distance.hpp> - - namespace boost { namespace geometry { @@ -31,37 +28,22 @@ namespace detail { namespace overlay 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; + signed_index_type 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 }; diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp index b110cc9602..acf38d09ab 100644 --- a/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -1,6 +1,11 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -20,6 +25,7 @@ #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/clear.hpp> namespace boost { namespace geometry @@ -32,7 +38,7 @@ 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) { @@ -44,43 +50,43 @@ static inline bool is_entering(Turn const& /* TODO remove this parameter */, Ope ; } -template +template < - typename Turn, - typename Operation, - typename LineString, + typename Turn, + typename Operation, + typename LineString, typename Polygon > -static inline bool last_covered_by(Turn const& turn, Operation const& op, +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 + // 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); + >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point); return geometry::covered_by(point_in_between, polygon); } -template +template < - typename Turn, - typename Operation, - typename LineString, + typename Turn, + typename Operation, + typename LineString, typename Polygon > -static inline bool is_leaving(Turn const& turn, Operation const& op, - bool entered, bool first, +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 + return entered || turn.method == method_crosses || (first && last_covered_by(turn, op, linestring, polygon)) ; @@ -89,20 +95,20 @@ static inline bool is_leaving(Turn const& turn, Operation const& op, } -template +template < - typename Turn, - typename Operation, - typename LineString, + typename Turn, + typename Operation, + typename LineString, typename Polygon > -static inline bool is_staying_inside(Turn const& turn, Operation const& op, - bool entered, bool first, +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 + // The normal case, this is completely covered with entering/leaving // so stay out of this time consuming "covered_by" return false; } @@ -115,11 +121,11 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op, return false; } -template +template < - typename Turn, - typename Operation, - typename Linestring, + typename Turn, + typename Operation, + typename Linestring, typename Polygon > static inline bool was_entered(Turn const& turn, Operation const& op, bool first, @@ -134,7 +140,7 @@ static inline bool was_entered(Turn const& turn, Operation const& op, bool first // Template specialization structure to call the right actions for the right type -template<overlay_type OverlayType> +template <overlay_type OverlayType, bool RemoveSpikes = true> struct action_selector { // If you get here the overlay type is not intersection or difference @@ -142,51 +148,86 @@ struct action_selector }; // Specialization for intersection, containing the implementation -template<> -struct action_selector<overlay_intersection> +template <bool RemoveSpikes> +struct action_selector<overlay_intersection, RemoveSpikes> { template < - typename OutputIterator, - typename LineStringOut, - typename LineString, - typename Point, - typename Operation + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation, + typename RobustPolicy > static inline void enter(LineStringOut& current_piece, - LineString const& , + LineString const& , segment_identifier& segment_id, - int , Point const& point, - Operation const& operation, OutputIterator& ) + signed_index_type , Point const& point, + Operation const& operation, + RobustPolicy const& , + OutputIterator& ) { // On enter, append the intersection point and remember starting point + // TODO: we don't check on spikes for linestrings (?). Consider this. detail::overlay::append_no_duplicates(current_piece, point); segment_id = operation.seg_id; } template < - typename OutputIterator, - typename LineStringOut, - typename LineString, - typename Point, - typename Operation + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation, + typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, - int index, Point const& point, - Operation const& , OutputIterator& out) + signed_index_type index, Point const& point, + Operation const& , + RobustPolicy const& robust_policy, + 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::copy_segments::copy_segments_linestring + < + false, RemoveSpikes + >::apply(linestring, segment_id, index, robust_policy, current_piece); detail::overlay::append_no_duplicates(current_piece, point); - if (current_piece.size() > 1) + if (::boost::size(current_piece) > 1) { *out++ = current_piece; } - current_piece.clear(); + + geometry::clear(current_piece); + } + + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void isolated_point(LineStringOut&, + LineString const&, + segment_identifier&, + signed_index_type, Point const& point, + Operation const& , OutputIterator& out) + { + LineStringOut isolated_point_ls; + geometry::append(isolated_point_ls, point); + +#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS + geometry::append(isolated_point_ls, point); +#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS + + *out++ = isolated_point_ls; } static inline bool is_entered(bool entered) @@ -194,8 +235,15 @@ struct action_selector<overlay_intersection> return entered; } - template <typename Point, typename Geometry> - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& ) { return geometry::covered_by(point, geometry); } @@ -203,45 +251,67 @@ struct action_selector<overlay_intersection> }; // Specialization for difference, which reverses these actions -template<> -struct action_selector<overlay_difference> +template <bool RemoveSpikes> +struct action_selector<overlay_difference, RemoveSpikes> { - typedef action_selector<overlay_intersection> normal_action; + typedef action_selector<overlay_intersection, RemoveSpikes> normal_action; template < - typename OutputIterator, - typename LineStringOut, - typename LineString, - typename Point, - typename Operation + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation, + typename RobustPolicy > - static inline void enter(LineStringOut& current_piece, - LineString const& linestring, - segment_identifier& segment_id, - int index, Point const& point, - Operation const& operation, OutputIterator& out) + static inline void enter(LineStringOut& current_piece, + LineString const& linestring, + segment_identifier& segment_id, + signed_index_type index, Point const& point, + Operation const& operation, + RobustPolicy const& robust_policy, + OutputIterator& out) { - normal_action::leave(current_piece, linestring, segment_id, index, - point, operation, out); + normal_action::leave(current_piece, linestring, segment_id, index, + point, operation, robust_policy, out); } template < - typename OutputIterator, - typename LineStringOut, - typename LineString, - typename Point, - typename Operation + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation, + typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, - int index, Point const& point, - Operation const& operation, OutputIterator& out) + signed_index_type index, Point const& point, + Operation const& operation, + RobustPolicy const& robust_policy, + OutputIterator& out) { normal_action::enter(current_piece, linestring, segment_id, index, - point, operation, out); + point, operation, robust_policy, out); + } + + template + < + typename OutputIterator, + typename LineStringOut, + typename LineString, + typename Point, + typename Operation + > + static inline void isolated_point(LineStringOut&, + LineString const&, + segment_identifier&, + signed_index_type, Point const&, + Operation const&, OutputIterator&) + { } static inline bool is_entered(bool entered) @@ -249,10 +319,17 @@ struct action_selector<overlay_difference> return ! normal_action::is_entered(entered); } - template <typename Point, typename Geometry> - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& robust_policy) { - return ! normal_action::included(point, geometry); + return ! normal_action::included(point, geometry, robust_policy); } }; @@ -269,12 +346,13 @@ template typename LineStringOut, typename LineString, typename Polygon, - overlay_type OverlayType + overlay_type OverlayType, + bool RemoveSpikes = true > class follow { - template<typename Turn> + template <typename Turn> struct sort_on_segment { // In case of turn point at the same location, we want to have continue/blocked LAST @@ -296,15 +374,15 @@ class follow inline bool use_operation(Turn const& left, Turn const& right) const { - // If they are the same, OK. + // 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) + return left.operations[0].fraction == right.operations[0].fraction ? use_operation(left, right) - : left.operations[0].enriched.distance < right.operations[0].enriched.distance + : left.operations[0].fraction < right.operations[0].fraction ; } @@ -325,16 +403,33 @@ class follow public : - template <typename Point, typename Geometry> - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& robust_policy) { - return following::action_selector<OverlayType>::included(point, geometry); + return following::action_selector + < + OverlayType, RemoveSpikes + >::included(point, geometry, robust_policy); } - template<typename Turns, typename OutputIterator> + template + < + typename Turns, + typename OutputIterator, + typename RobustPolicy + > static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon, detail::overlay::operation_type , // TODO: this parameter might be redundant - Turns& turns, OutputIterator out) + Turns& turns, + RobustPolicy const& robust_policy, + OutputIterator out) { typedef typename boost::range_iterator<Turns>::type turn_iterator; typedef typename boost::range_value<Turns>::type turn_type; @@ -343,7 +438,7 @@ public : typename turn_type::container_type >::type turn_operation_iterator_type; - typedef following::action_selector<OverlayType> action; + typedef following::action_selector<OverlayType, RemoveSpikes> action; // Sort intersection points on segments-along-linestring, and distance // (like in enrich is done for poly/poly) @@ -376,27 +471,38 @@ public : debug_traverse(*it, *iit, "-> Entering"); entered = true; - action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); + action::enter(current_piece, linestring, current_segment_id, + iit->seg_id.segment_index, it->point, *iit, + robust_policy, + 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); + action::leave(current_piece, linestring, current_segment_id, + iit->seg_id.segment_index, it->point, *iit, + robust_policy, + out); } first = false; } if (action::is_entered(entered)) { - geometry::copy_segments<false>(linestring, current_segment_id, - boost::size(linestring) - 1, - current_piece); + detail::copy_segments::copy_segments_linestring + < + false, RemoveSpikes + >::apply(linestring, + current_segment_id, + static_cast<signed_index_type>(boost::size(linestring) - 1), + robust_policy, + current_piece); } // Output the last one, if applicable - if (current_piece.size() > 1) + if (::boost::size(current_piece) > 1) { *out++ = current_piece; } diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp new file mode 100644 index 0000000000..85378e08b0 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -0,0 +1,536 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP + +#include <cstddef> +#include <algorithm> +#include <iterator> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/algorithms/detail/overlay/follow.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + +#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp> + +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +namespace following { namespace linear +{ + + + + +// follower for linear/linear geometries set operations + +template <typename Turn, typename Operation> +static inline bool is_entering(Turn const& turn, + Operation const& operation) +{ + if ( turn.method != method_touch && turn.method != method_touch_interior ) + { + return false; + } + return operation.operation == operation_intersection; +} + + + +template <typename Turn, typename Operation> +static inline bool is_staying_inside(Turn const& turn, + Operation const& operation, + bool entered) +{ + if ( !entered ) + { + return false; + } + + if ( turn.method != method_equal && turn.method != method_collinear ) + { + return false; + } + return operation.operation == operation_continue; +} + + + +template <typename Turn, typename Operation> +static inline bool is_leaving(Turn const& turn, + Operation const& operation, + bool entered) +{ + if ( !entered ) + { + return false; + } + + if ( turn.method != method_touch + && turn.method != method_touch_interior + && turn.method != method_equal + && turn.method != method_collinear ) + { + return false; + } + + if ( operation.operation == operation_blocked ) + { + return true; + } + + if ( operation.operation != operation_union ) + { + return false; + } + + return operation.is_collinear; +} + + + +template <typename Turn, typename Operation> +static inline bool is_isolated_point(Turn const& turn, + Operation const& operation, + bool entered) +{ + if ( entered ) + { + return false; + } + + if ( turn.method == method_none ) + { + BOOST_ASSERT( operation.operation == operation_continue ); + return true; + } + + if ( turn.method == method_crosses ) + { + return true; + } + + if ( turn.method != method_touch && turn.method != method_touch_interior ) + { + return false; + } + + if ( operation.operation == operation_blocked ) + { + return true; + } + + if ( operation.operation != operation_union ) + { + return false; + } + + return !operation.is_collinear; +} + + + + + + + + + +template +< + typename LinestringOut, + typename Linestring, + typename Linear, + overlay_type OverlayType, + bool FollowIsolatedPoints, + bool FollowContinueTurns +> +class follow_linestring_linear_linestring +{ +protected: + // allow spikes (false indicates: do not remove spikes) + typedef following::action_selector<OverlayType, false> action; + + template + < + typename TurnIterator, + typename TurnOperationIterator, + typename SegmentIdentifier, + typename OutputIterator + > + static inline OutputIterator + process_turn(TurnIterator it, + TurnOperationIterator op_it, + bool& entered, + std::size_t& enter_count, + Linestring const& linestring, + LinestringOut& current_piece, + SegmentIdentifier& current_segment_id, + OutputIterator oit) + { + // We don't rescale linear/linear + detail::no_rescale_policy robust_policy; + + if ( is_entering(*it, *op_it) ) + { + detail::turns::debug_turn(*it, *op_it, "-> Entering"); + + entered = true; + if ( enter_count == 0 ) + { + action::enter(current_piece, linestring, + current_segment_id, + op_it->seg_id.segment_index, + it->point, *op_it, robust_policy, oit); + } + ++enter_count; + } + else if ( is_leaving(*it, *op_it, entered) ) + { + detail::turns::debug_turn(*it, *op_it, "-> Leaving"); + + --enter_count; + if ( enter_count == 0 ) + { + entered = false; + action::leave(current_piece, linestring, + current_segment_id, + op_it->seg_id.segment_index, + it->point, *op_it, robust_policy, oit); + } + } + else if ( FollowIsolatedPoints + && is_isolated_point(*it, *op_it, entered) ) + { + detail::turns::debug_turn(*it, *op_it, "-> Isolated point"); + + action::isolated_point(current_piece, linestring, + current_segment_id, + op_it->seg_id.segment_index, + it->point, *op_it, oit); + } + else if ( FollowContinueTurns + && is_staying_inside(*it, *op_it, entered) ) + { + detail::turns::debug_turn(*it, *op_it, "-> Staying inside"); + + entered = true; + } + return oit; + } + + template + < + typename SegmentIdentifier, + typename OutputIterator + > + static inline OutputIterator + process_end(bool entered, + Linestring const& linestring, + SegmentIdentifier const& current_segment_id, + LinestringOut& current_piece, + OutputIterator oit) + { + if ( action::is_entered(entered) ) + { + // We don't rescale linear/linear + detail::no_rescale_policy robust_policy; + + detail::copy_segments::copy_segments_linestring + < + false, false // do not reverse; do not remove spikes + >::apply(linestring, + current_segment_id, + static_cast<signed_index_type>(boost::size(linestring) - 1), + robust_policy, + current_piece); + } + + // Output the last one, if applicable + if (::boost::size(current_piece) > 1) + { + *oit++ = current_piece; + } + + return oit; + } + +public: + template <typename TurnIterator, typename OutputIterator> + static inline OutputIterator + apply(Linestring const& linestring, Linear const&, + TurnIterator first, TurnIterator beyond, + OutputIterator oit) + { + // Iterate through all intersection points (they are + // ordered along the each line) + + LinestringOut current_piece; + geometry::segment_identifier current_segment_id(0, -1, -1, -1); + + bool entered = false; + std::size_t enter_count = 0; + + for (TurnIterator it = first; it != beyond; ++it) + { + oit = process_turn(it, boost::begin(it->operations), + entered, enter_count, + linestring, + current_piece, current_segment_id, + oit); + } + + BOOST_ASSERT( enter_count == 0 ); + + return process_end(entered, linestring, + current_segment_id, current_piece, + oit); + } +}; + + + + +template +< + typename LinestringOut, + typename MultiLinestring, + typename Linear, + overlay_type OverlayType, + bool FollowIsolatedPoints, + bool FollowContinueTurns +> +class follow_multilinestring_linear_linestring + : follow_linestring_linear_linestring + < + LinestringOut, + typename boost::range_value<MultiLinestring>::type, + Linear, + OverlayType, + FollowIsolatedPoints, + FollowContinueTurns + > +{ +protected: + typedef typename boost::range_value<MultiLinestring>::type Linestring; + + typedef follow_linestring_linear_linestring + < + LinestringOut, Linestring, Linear, + OverlayType, FollowIsolatedPoints, FollowContinueTurns + > Base; + + typedef following::action_selector<OverlayType> action; + + typedef typename boost::range_iterator + < + MultiLinestring const + >::type linestring_iterator; + + + template <typename OutputIt, overlay_type OT> + struct copy_linestrings_in_range + { + static inline OutputIt + apply(linestring_iterator, linestring_iterator, OutputIt oit) + { + return oit; + } + }; + + template <typename OutputIt> + struct copy_linestrings_in_range<OutputIt, overlay_difference> + { + static inline OutputIt + apply(linestring_iterator first, linestring_iterator beyond, + OutputIt oit) + { + for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it) + { + LinestringOut line_out; + geometry::convert(*ls_it, line_out); + *oit++ = line_out; + } + return oit; + } + }; + + template <typename TurnIterator> + static inline signed_index_type get_multi_index(TurnIterator it) + { + return boost::begin(it->operations)->seg_id.multi_index; + } + + class has_other_multi_id + { + private: + signed_index_type m_multi_id; + + public: + has_other_multi_id(signed_index_type multi_id) + : m_multi_id(multi_id) {} + + template <typename Turn> + bool operator()(Turn const& turn) const + { + return boost::begin(turn.operations)->seg_id.multi_index + != m_multi_id; + } + }; + +public: + template <typename TurnIterator, typename OutputIterator> + static inline OutputIterator + apply(MultiLinestring const& multilinestring, Linear const& linear, + TurnIterator first, TurnIterator beyond, + OutputIterator oit) + { + BOOST_ASSERT( first != beyond ); + + typedef copy_linestrings_in_range + < + OutputIterator, OverlayType + > copy_linestrings; + + linestring_iterator ls_first = boost::begin(multilinestring); + linestring_iterator ls_beyond = boost::end(multilinestring); + + // Iterate through all intersection points (they are + // ordered along the each linestring) + + signed_index_type current_multi_id = get_multi_index(first); + + oit = copy_linestrings::apply(ls_first, + ls_first + current_multi_id, + oit); + + TurnIterator per_ls_next = first; + do { + TurnIterator per_ls_current = per_ls_next; + + // find turn with different multi-index + per_ls_next = std::find_if(per_ls_current, beyond, + has_other_multi_id(current_multi_id)); + + oit = Base::apply(*(ls_first + current_multi_id), + linear, per_ls_current, per_ls_next, oit); + + signed_index_type next_multi_id(-1); + linestring_iterator ls_next = ls_beyond; + if ( per_ls_next != beyond ) + { + next_multi_id = get_multi_index(per_ls_next); + ls_next = ls_first + next_multi_id; + } + oit = copy_linestrings::apply(ls_first + current_multi_id + 1, + ls_next, + oit); + + current_multi_id = next_multi_id; + } + while ( per_ls_next != beyond ); + + return oit; + } +}; + + + + + + +template +< + typename LinestringOut, + typename Geometry1, + typename Geometry2, + overlay_type OverlayType, + bool FollowIsolatedPoints, + bool FollowContinueTurns, + typename TagOut = typename tag<LinestringOut>::type, + typename TagIn1 = typename tag<Geometry1>::type +> +struct follow + : not_implemented<LinestringOut, Geometry1> +{}; + + + +template +< + typename LinestringOut, + typename Linestring, + typename Linear, + overlay_type OverlayType, + bool FollowIsolatedPoints, + bool FollowContinueTurns +> +struct follow + < + LinestringOut, Linestring, Linear, + OverlayType, FollowIsolatedPoints, FollowContinueTurns, + linestring_tag, linestring_tag + > : follow_linestring_linear_linestring + < + LinestringOut, Linestring, Linear, + OverlayType, FollowIsolatedPoints, FollowContinueTurns + > +{}; + + +template +< + typename LinestringOut, + typename MultiLinestring, + typename Linear, + overlay_type OverlayType, + bool FollowIsolatedPoints, + bool FollowContinueTurns +> +struct follow + < + LinestringOut, MultiLinestring, Linear, + OverlayType, FollowIsolatedPoints, FollowContinueTurns, + linestring_tag, multi_linestring_tag + > : follow_multilinestring_linear_linestring + < + LinestringOut, MultiLinestring, Linear, + OverlayType, FollowIsolatedPoints, FollowContinueTurns + > +{}; + + + +}} // namespace following::linear + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp index 019c3ba3f9..63011c7d48 100644 --- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -17,6 +17,7 @@ #include <boost/geometry/geometries/segment.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> namespace boost { namespace geometry { @@ -35,32 +36,45 @@ template > 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> + template <typename RobustPolicy, typename OutputIterator> static inline OutputIterator apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/, + Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/, + bool /*is_p_first*/, bool /*is_p_last*/, + bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& , + RobustPolicy const& robust_policy, OutputIterator out) { + typedef strategy_intersection + < + typename cs_tag<typename TurnInfo::point_type>::type, + Point1, + Point2, + typename TurnInfo::point_type, + RobustPolicy + > si; + + typedef typename si::segment_intersection_strategy_type strategy; + 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); + segment_type1 p1(pi, pj); + segment_type2 q1(qi, qj); - // - typename strategy::return_type result = strategy::apply(p1, q1); + typedef typename geometry::robust_point_type + < + Point1, RobustPolicy + >::type robust_point_type; + + robust_point_type pi_rob, pj_rob, qi_rob, qj_rob; + geometry::recalculate(pi_rob, pi, robust_policy); + geometry::recalculate(pj_rob, pj, robust_policy); + geometry::recalculate(qi_rob, qi, robust_policy); + geometry::recalculate(qj_rob, qj, robust_policy); + typename strategy::return_type result + = strategy::apply(p1, q1, robust_policy, + pi_rob, pj_rob, qi_rob, qj_rob); for (std::size_t i = 0; i < result.template get<0>().count; i++) { @@ -84,10 +98,12 @@ template < typename Geometry1, typename Geometry2, + typename RobustPolicy, typename Turns > inline void get_intersection_points(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, Turns& turns) { concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>(); @@ -99,14 +115,6 @@ inline void get_intersection_points(Geometry1 const& geometry1, 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 @@ -118,9 +126,7 @@ inline void get_intersection_points(Geometry1 const& geometry1, typename tag<Geometry2>::type, Geometry1, Geometry2, false, false, - Turns, TurnPolicy, - //segment_intersection_strategy_type, - detail::get_turns::no_interrupt_policy + TurnPolicy >, dispatch::get_turns < @@ -128,13 +134,12 @@ inline void get_intersection_points(Geometry1 const& geometry1, typename tag<Geometry2>::type, Geometry1, Geometry2, false, false, - Turns, TurnPolicy, - //segment_intersection_strategy_type, - detail::get_turns::no_interrupt_policy + TurnPolicy > >::type::apply( 0, geometry1, 1, geometry2, + robust_policy, turns, interrupt_policy); } diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp index 522ef68382..d71f4ad51f 100644 --- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp @@ -10,8 +10,6 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP -#include <boost/geometry/algorithms/distance.hpp> - #include <boost/geometry/strategies/intersection.hpp> @@ -36,15 +34,10 @@ namespace detail { namespace overlay template <typename Point1> struct get_relative_order { - typedef strategy_intersection + typedef typename strategy::side::services::default_strategy < - typename cs_tag<Point1>::type, - Point1, - Point1, - Point1 - > si; - - typedef typename si::side_strategy_type strategy; + typename cs_tag<Point1>::type + >::type strategy; template <typename Point> static inline int value_via_product(Point const& ti, Point const& tj, diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp index c2c6980577..131d58d582 100644 --- a/boost/geometry/algorithms/detail/overlay/get_ring.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp @@ -13,11 +13,13 @@ #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/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -33,16 +35,16 @@ template<typename Tag> struct get_ring {}; -// A container of rings (multi-ring but that does not exist) +// A range 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) + template<typename Range> + static inline typename boost::range_value<Range>::type const& + apply(ring_identifier const& id, Range const& container) { - return container[id.multi_index]; + return range::at(container, id.multi_index); } }; @@ -87,7 +89,26 @@ struct get_ring<polygon_tag> ); return id.ring_index < 0 ? exterior_ring(polygon) - : interior_rings(polygon)[id.ring_index]; + : range::at(interior_rings(polygon), id.ring_index); + } +}; + + +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, + range::at(multi_polygon, id.multi_index)); } }; diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index b8320d9b7b..240b6de036 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -16,9 +16,19 @@ #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/geometries/segment.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp> + +// Silence warning C4127: conditional expression is constant +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + namespace boost { namespace geometry { @@ -30,7 +40,7 @@ class turn_info_exception : public geometry::exception public: // NOTE: "char" will be replaced by enum in future version - inline turn_info_exception(char const method) + inline turn_info_exception(char const method) { message = "Boost.Geometry Turn exception: "; message += method; @@ -50,7 +60,6 @@ public: namespace detail { namespace overlay { - struct base_turn_handler { // Returns true if both sides are opposite @@ -91,13 +100,32 @@ struct base_turn_handler { both(ti, condition ? operation_union : operation_intersection); } + + template <typename TurnInfo, typename IntersectionInfo> + static inline void assign_point(TurnInfo& ti, + method_type method, + IntersectionInfo const& info, int index) + { + ti.method = method; + BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this + geometry::convert(info.intersections[index], ti.point); + ti.operations[0].fraction = info.fractions[index].robust_ra; + ti.operations[1].fraction = info.fractions[index].robust_rb; + } + + template <typename IntersectionInfo> + static inline int non_opposite_to_index(IntersectionInfo const& info) + { + return info.fractions[0].robust_rb < info.fractions[1].robust_rb + ? 1 : 0; + } + }; template < - typename TurnInfo, - typename SideStrategy + typename TurnInfo > struct touch_interior : public base_turn_handler { @@ -108,17 +136,18 @@ struct touch_interior : public base_turn_handler typename Point1, typename Point2, typename IntersectionInfo, - typename DirInfo + typename DirInfo, + typename SidePolicy > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& , - Point2 const& qi, Point2 const& qj, Point2 const& qk, + Point1 const& , Point1 const& , Point1 const& , + Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, IntersectionInfo const& intersection_info, - DirInfo const& dir_info) + DirInfo const& dir_info, + SidePolicy const& side) { - ti.method = method_touch_interior; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_touch_interior, intersection_info, 0); // Both segments of q touch segment p somewhere in its interior // 1) We know: if q comes from LEFT or RIGHT @@ -130,7 +159,7 @@ struct touch_interior : public base_turn_handler 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); + int const side_qk_p = side.qk_wrt_p1(); if (side_qi_p == -side_qk_p) { @@ -143,7 +172,7 @@ struct touch_interior : public base_turn_handler return; } - int const side_qk_q = SideStrategy::apply(qi, qj, qk); + int const side_qk_q = side.qk_wrt_q1(); if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1) { @@ -203,8 +232,7 @@ struct touch_interior : public base_turn_handler template < - typename TurnInfo, - typename SideStrategy + typename TurnInfo > struct touch : public base_turn_handler { @@ -227,37 +255,34 @@ struct touch : public base_turn_handler typename Point1, typename Point2, typename IntersectionInfo, - typename DirInfo + typename DirInfo, + typename SidePolicy > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + Point1 const& , Point1 const& , Point1 const& , + Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, IntersectionInfo const& intersection_info, - DirInfo const& dir_info) + DirInfo const& dir_info, + SidePolicy const& side) { - ti.method = method_touch; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_touch, intersection_info, 0); int const side_qi_p1 = dir_info.sides.template get<1, 0>(); - int const side_qk_p1 = SideStrategy::apply(pi, pj, qk); + int const side_qk_p1 = side.qk_wrt_p1(); // 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; + int const side_pk_q2 = side.pk_wrt_q2(); + int const side_pk_p = side.pk_wrt_p1(); + int const side_qk_q = side.qk_wrt_q1(); 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 @@ -276,7 +301,7 @@ struct touch : public base_turn_handler return; } - int const side_pk_q1 = SideStrategy::apply(qi, qj, pk); + int const side_pk_q1 = side.pk_wrt_q1(); // Collinear opposite case -> block P @@ -329,9 +354,6 @@ struct touch : public base_turn_handler 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; @@ -347,13 +369,13 @@ struct touch : public base_turn_handler else { // From left to right or from right to left - int const side_pk_p = SideStrategy::apply(pi, pj, pk); + int const side_pk_p = side.pk_wrt_p1(); 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); + int const side_pk_q1 = side.pk_wrt_q1(); // Collinear opposite case -> block P if (side_pk_q1 == 0) @@ -374,7 +396,7 @@ struct touch : public base_turn_handler // 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); + int const side_pk_q2 = side.pk_wrt_q2(); // Collinear case -> lines join, continue if (side_pk_q2 == 0) @@ -413,8 +435,7 @@ struct touch : public base_turn_handler template < - typename TurnInfo, - typename SideStrategy + typename TurnInfo > struct equal : public base_turn_handler { @@ -423,22 +444,24 @@ struct equal : public base_turn_handler typename Point1, typename Point2, typename IntersectionInfo, - typename DirInfo + typename DirInfo, + typename SidePolicy > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& , Point2 const& qj, Point2 const& qk, + Point1 const& , Point1 const& , Point1 const& , + Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, - IntersectionInfo const& intersection_info, - DirInfo const& ) + IntersectionInfo const& info, + DirInfo const& , + SidePolicy const& side) { - ti.method = method_equal; - // Copy the SECOND intersection point - geometry::convert(intersection_info.intersections[1], ti.point); + // Copy the intersection point in TO direction + assign_point(ti, method_equal, info, non_opposite_to_index(info)); + + int const side_pk_q2 = side.pk_wrt_q2(); + int const side_pk_p = side.pk_wrt_p1(); + int const side_qk_p = side.qk_wrt_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_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 @@ -447,6 +470,7 @@ struct equal : public base_turn_handler if (side_pk_q2 == 0 && side_pk_p == side_qk_p) { both(ti, operation_continue); + return; } @@ -454,8 +478,6 @@ struct equal : public base_turn_handler // 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); } @@ -485,33 +507,32 @@ struct equal_opposite : public base_turn_handler typename DirInfo > static inline void apply(Point1 const& pi, Point2 const& qi, - /* by value: */ TurnInfo tp, + /* 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; - } - } + 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++) + { + assign_point(tp, method_none, intersection_info, i); + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *out++ = tp; + } + } } }; template < - typename TurnInfo, - typename SideStrategy + typename TurnInfo > struct collinear : public base_turn_handler { @@ -543,7 +564,7 @@ struct collinear : public base_turn_handler 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) + If p arrives, q is further, so the angle qk//p1 is (normally) more precise than pk//p1 */ @@ -552,24 +573,26 @@ struct collinear : public base_turn_handler typename Point1, typename Point2, typename IntersectionInfo, - typename DirInfo + typename DirInfo, + typename SidePolicy > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + Point1 const& , Point1 const& , Point1 const& , + Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, - IntersectionInfo const& intersection_info, - DirInfo const& dir_info) + IntersectionInfo const& info, + DirInfo const& dir_info, + SidePolicy const& side) { - ti.method = method_collinear; - geometry::convert(intersection_info.intersections[1], ti.point); + // Copy the intersection point in TO direction + assign_point(ti, method_collinear, info, non_opposite_to_index(info)); 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); + int const side_p = side.pk_wrt_p1(); + int const side_q = side.qk_wrt_q1(); // If p arrives, use p, else use q int const side_p_or_q = arrival == 1 @@ -577,9 +600,6 @@ struct collinear : public base_turn_handler : 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 @@ -587,15 +607,7 @@ struct collinear : public base_turn_handler 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) + if(product == 0) { both(ti, operation_continue); } @@ -605,43 +617,11 @@ struct collinear : public base_turn_handler } } - 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 @@ -674,14 +654,19 @@ private : template < int Index, - typename Point, + typename Point1, + typename Point2, typename IntersectionInfo > - static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk, + static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r, + bool const handle_robustness, + Point2 const& , Point2 const& , int side_rk_s, TurnInfo& tp, IntersectionInfo const& intersection_info) { - int const side_rk_r = SideStrategy::apply(ri, rj, rk); - operation_type blocked = operation_blocked; + boost::ignore_unused_variable_warning(handle_robustness); + boost::ignore_unused_variable_warning(side_rk_s); + + operation_type blocked = operation_blocked; switch(side_rk_r) { @@ -699,16 +684,16 @@ private : // 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; + 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 @@ -717,18 +702,21 @@ private : // 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); + assign_point(tp, method_collinear, intersection_info, 1 - Index); return true; } public: + static inline void empty_transformer(TurnInfo &) {} + template < typename Point1, typename Point2, typename OutputIterator, typename IntersectionInfo, - typename DirInfo + typename DirInfo, + typename SidePolicy > static inline void apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, @@ -739,46 +727,79 @@ public: OutputIterator& out, IntersectionInfo const& intersection_info, - DirInfo const& dir_info) + DirInfo const& dir_info, + SidePolicy const& side) { - TurnInfo tp = tp_model; + apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer); + } - tp.method = method_collinear; +public: + template + < + typename Point1, + typename Point2, + typename OutputIterator, + typename IntersectionInfo, + typename DirInfo, + typename SidePolicy, + typename TurnTransformer + > + 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, + SidePolicy const& side, + TurnTransformer turn_transformer, + bool const is_pk_valid = true, bool const is_qk_valid = true) + { + TurnInfo tp = tp_model; // If P arrives within Q, there is a turn dependent on P - if (dir_info.arrival[0] == 1 - && set_tp<0>(pi, pj, pk, tp, intersection_info)) + if ( dir_info.arrival[0] == 1 + && is_pk_valid + && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) ) { + turn_transformer(tp); + 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, tp, intersection_info)) + if ( dir_info.arrival[1] == 1 + && is_qk_valid + && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) ) { + turn_transformer(tp); + 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; - } - } - } + 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++) + { + assign_point(tp, method_collinear, intersection_info, i); + AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + *out++ = tp; + } + } + } } }; @@ -786,8 +807,7 @@ public: template < - typename TurnInfo, - typename SideStrategy + typename TurnInfo > struct crosses : public base_turn_handler { @@ -805,8 +825,7 @@ struct crosses : public base_turn_handler IntersectionInfo const& intersection_info, DirInfo const& dir_info) { - ti.method = method_crosses; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_crosses, intersection_info, 0); // In all casees: // If Q crosses P from left to right @@ -820,14 +839,12 @@ struct crosses : public base_turn_handler } }; -template<typename TurnInfo> -struct only_convert +struct only_convert : public base_turn_handler { - template<typename IntersectionInfo> + template<typename TurnInfo, typename IntersectionInfo> static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info) { - ti.method = method_collinear; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_none, intersection_info, 0); // was collinear ti.operations[0].operation = operation_continue; ti.operations[1].operation = operation_continue; } @@ -845,14 +862,14 @@ struct assign_null_policy static bool const include_degenerate = false; static bool const include_opposite = false; - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo, - typename DirInfo - > + template + < + typename Info, + typename Point1, + typename Point2, + typename IntersectionInfo, + typename DirInfo + > static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&) {} @@ -873,48 +890,39 @@ struct assign_null_policy It also defines if a certain class of points (degenerate, non-turns) should be included. */ -template -< - typename Point1, - typename Point2, - typename TurnInfo, - typename AssignPolicy -> +template<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> + // The points pk and qk are used do determine more information + // about the turn (turn left/right) + template + < + typename Point1, + typename Point2, + typename TurnInfo, + typename RobustPolicy, + typename OutputIterator + > static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool /*is_p_first*/, bool /*is_p_last*/, + bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& tp_model, + RobustPolicy const& robust_policy, 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); + typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> + inters_info; - typename strategy::return_type result = strategy::apply(p1, q1); + inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); - char const method = result.template get<1>().how; + char const method = inters.d_info().how; // Copy, to copy possibly extended fields TurnInfo tp = tp_model; - // Select method and apply switch(method) { @@ -922,11 +930,10 @@ struct get_turn_info case 'f' : // collinear, "from" case 's' : // starts from the middle if (AssignPolicy::include_no_turn - && result.template get<0>().count > 0) + && inters.i_info().count > 0) { - only_convert<TurnInfo>::apply(tp, - result.template get<0>()); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + only_convert::apply(tp, inters.i_info()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } break; @@ -938,113 +945,94 @@ struct get_turn_info { typedef touch_interior < - TurnInfo, - typename si::side_strategy_type + TurnInfo > policy; // If Q (1) arrives (1) - if (result.template get<1>().arrival[1] == 1) + if ( inters.d_info().arrival[1] == 1 ) { policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>()); + tp, inters.i_info(), inters.d_info(), + inters.sides()); } else { // Swap p/q + side_calculator + < + typename inters_info::robust_point2_type, + typename inters_info::robust_point1_type + > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), + inters.rpi(), inters.rpj(), inters.rpk()); policy::template apply<1>(qi, qj, qk, pi, pj, pk, - tp, result.template get<0>(), result.template get<1>()); + tp, inters.i_info(), inters.d_info(), + swapped_side_calc); } - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *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>()); + crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *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>()); + touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } break; case 'e': { - if (! result.template get<1>().opposite) + if ( ! inters.d_info().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>()); + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } - else - { + else + { equal_opposite < TurnInfo, AssignPolicy >::apply(pi, qi, - tp, out, result.template get<0>(), result.template get<1>()); - } + tp, out, inters.i_info(), inters.d_info()); + } } break; case 'c' : { // Collinear - if (! result.template get<1>().opposite) + if ( ! inters.d_info().opposite ) { - if (result.template get<1>().arrival[0] == 0) + if ( inters.d_info().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>()); + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); // 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>()); + collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); } - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } else @@ -1052,10 +1040,9 @@ struct get_turn_info 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>()); + tp, out, inters.i_info(), inters.d_info(), inters.sides()); } } break; @@ -1064,14 +1051,17 @@ struct get_turn_info // 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>()); + only_convert::apply(tp, inters.i_info()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } } break; default : { +#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) + std::cout << "TURN: Unknown method: " << method << std::endl; +#endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) throw turn_info_exception(method); #endif @@ -1091,4 +1081,8 @@ struct get_turn_info }} // 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_turn_info_for_endpoint.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp new file mode 100644 index 0000000000..ca1b9d9d0c --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp @@ -0,0 +1,657 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP + +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay { + +// SEGMENT_INTERSECTION RESULT + +// C H0 H1 A0 A1 O IP1 IP2 + +// D0 and D1 == 0 + +// |--------> 2 0 0 0 0 F i/i x/x +// |--------> +// +// |--------> 2 0 0 0 0 T i/x x/i +// <--------| +// +// |-----> 1 0 0 0 0 T x/x +// <-----| +// + +// |---------> 2 0 0 0 1 T i/x x/i +// <----| +// +// |---------> 2 0 0 0 0 F i/i x/x +// |----> +// +// |---------> 2 0 0 -1 1 F i/i u/x +// |----> +// +// |---------> 2 0 0 -1 0 T i/x u/i +// <----| + +// |-------> 2 0 0 1 -1 F and i/i x/u +// |-------> 2 0 0 -1 1 F symetric i/i u/x +// |-------> +// +// |-------> 2 0 0 -1 -1 T i/u u/i +// <-------| +// +// |-------> 2 0 0 1 1 T i/x x/i +// <-------| +// +// |--------> 2 0 0 -1 1 F i/i u/x +// |----> +// +// |--------> 2 0 0 -1 1 T i/x u/i +// <----| + +// |-----> 1 -1 -1 -1 -1 T u/u +// <-----| +// +// |-----> 1 -1 0 -1 0 F and u/x +// |-----> 1 0 -1 0 -1 F symetric x/u +// |-----> + +// D0 or D1 != 0 + +// ^ +// | +// + 1 -1 1 -1 1 F and u/x (P is vertical) +// |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal) +// ^ +// | +// + +// +// + +// | +// v +// |--------> 1 1 1 1 1 F x/x (P is vertical) +// +// ^ +// | +// + +// |--------> 1 -1 -1 -1 -1 F u/u (P is vertical) +// +// ^ +// | +// + +// |--------> 1 0 -1 0 -1 F u/u (P is vertical) +// +// + +// | +// v +// |--------> 1 0 1 0 1 F u/x (P is vertical) +// + +class linear_intersections +{ +public: + template <typename Point1, typename Point2, typename IntersectionResult> + linear_intersections(Point1 const& pi, + Point2 const& qi, + IntersectionResult const& result, + bool is_p_last, bool is_q_last) + { + int arrival_a = result.template get<1>().arrival[0]; + int arrival_b = result.template get<1>().arrival[1]; + bool same_dirs = result.template get<1>().dir_a == 0 + && result.template get<1>().dir_b == 0; + + if ( same_dirs ) + { + if ( result.template get<0>().count == 2 ) + { + if ( ! result.template get<1>().opposite ) + { + ips[0].p_operation = operation_intersection; + ips[0].q_operation = operation_intersection; + ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); + + ips[0].is_pi + = equals::equals_point_point( + pi, result.template get<0>().intersections[0]); + ips[0].is_qi + = equals::equals_point_point( + qi, result.template get<0>().intersections[0]); + ips[1].is_pj = arrival_a != -1; + ips[1].is_qj = arrival_b != -1; + } + else + { + ips[0].p_operation = operation_intersection; + ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); + ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[1].q_operation = operation_intersection; + + ips[0].is_pi = arrival_b != 1; + ips[0].is_qj = arrival_b != -1; + ips[1].is_pj = arrival_a != -1; + ips[1].is_qi = arrival_a != 1; + } + } + else + { + BOOST_ASSERT(result.template get<0>().count == 1); + ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); + + ips[0].is_pi = arrival_a == -1; + ips[0].is_qi = arrival_b == -1; + ips[0].is_pj = arrival_a == 0; + ips[0].is_qj = arrival_b == 0; + } + } + else + { + ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last); + ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last); + + ips[0].is_pi = arrival_a == -1; + ips[0].is_qi = arrival_b == -1; + ips[0].is_pj = arrival_a == 1; + ips[0].is_qj = arrival_b == 1; + } + } + + struct ip_info + { + inline ip_info() + : p_operation(operation_none), q_operation(operation_none) + , is_pi(false), is_pj(false), is_qi(false), is_qj(false) + {} + + operation_type p_operation, q_operation; + bool is_pi, is_pj, is_qi, is_qj; + }; + + template <std::size_t I> + ip_info const& get() const + { + BOOST_STATIC_ASSERT(I < 2); + return ips[I]; + } + +private: + + // only if collinear (same_dirs) + static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last) + { + if ( arrival == 1 ) + return operation_blocked; + else if ( arrival == -1 ) + return operation_union; + else + return is_last ? operation_blocked : operation_union; + //return operation_blocked; + } + + // only if not collinear (!same_dirs) + static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last) + { + if ( arrival == 1 ) + //return operation_blocked; + return is_last ? operation_blocked : operation_union; + else + return operation_union; + } + + ip_info ips[2]; +}; + +template <typename AssignPolicy, bool EnableFirst, bool EnableLast> +struct get_turn_info_for_endpoint +{ + BOOST_STATIC_ASSERT(EnableFirst || EnableLast); + + template<typename Point1, + typename Point2, + typename TurnInfo, + typename IntersectionInfo, + typename OutputIterator + > + static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool is_p_first, bool is_p_last, + bool is_q_first, bool is_q_last, + TurnInfo const& tp_model, + IntersectionInfo const& inters, + method_type /*method*/, + OutputIterator out) + { + std::size_t ip_count = inters.i_info().count; + // no intersection points + if ( ip_count == 0 ) + return false; + + if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) + return false; + + linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); + + bool append0_last + = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + intersections.template get<0>(), + tp_model, inters, 0, out); + + // NOTE: opposite && ip_count == 1 may be true! + bool opposite = inters.d_info().opposite; + + // don't ignore only for collinear opposite + bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite ); + + if ( intersections.template get<1>().p_operation == operation_none ) + return result_ignore_ip0; + + bool append1_last + = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + intersections.template get<1>(), + tp_model, inters, 1, out); + + // don't ignore only for collinear opposite + bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/; + + return result_ignore_ip0 || result_ignore_ip1; + } + + template <typename Point1, + typename Point2, + typename TurnInfo, + typename IntersectionInfo, + typename OutputIterator> + static inline + bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool is_p_first, bool is_p_last, + bool is_q_first, bool is_q_last, + linear_intersections::ip_info const& ip_info, + TurnInfo const& tp_model, + IntersectionInfo const& inters, + int ip_index, + OutputIterator out) + { +#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR + // may this give false positives for INTs? + typename IntersectionResult::point_type const& + inters_pt = result.template get<0>().intersections[ip_index]; + BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt)); + BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt)); + BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt)); + BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt)); +#endif + + // TODO - calculate first/last only if needed + bool is_p_first_ip = is_p_first && ip_info.is_pi; + bool is_p_last_ip = is_p_last && ip_info.is_pj; + bool is_q_first_ip = is_q_first && ip_info.is_qi; + bool is_q_last_ip = is_q_last && ip_info.is_qj; + bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip); + bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip); + + operation_type p_operation = ip_info.p_operation; + operation_type q_operation = ip_info.q_operation; + + if ( append_first || append_last ) + { + bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk, + inters.rpi(), inters.rpj(), inters.rpk(), + inters.rqi(), inters.rqj(), inters.rqk(), + is_p_first_ip, is_p_last_ip, + is_q_first_ip, is_q_last_ip, + ip_info.is_qi, ip_info.is_qj, + tp_model, inters, ip_index, + p_operation, q_operation); + if ( !handled ) + { + handle_internal<1>(qi, qj, qk, pi, pj, pk, + inters.rqi(), inters.rqj(), inters.rqk(), + inters.rpi(), inters.rpj(), inters.rpk(), + is_q_first_ip, is_q_last_ip, + is_p_first_ip, is_p_last_ip, + ip_info.is_pi, ip_info.is_pj, + tp_model, inters, ip_index, + q_operation, p_operation); + } + + if ( p_operation != operation_none ) + { + method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj, + ip_info.is_qi, ip_info.is_qj); + turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip); + turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip); + + // handle spikes + + // P is spike and should be handled + if ( !is_p_last + && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster + && inters.i_info().count == 2 + && inters.is_spike_p() ) + { + assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation, + p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); + assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation, + p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); + } + // Q is spike and should be handled + else if ( !is_q_last + && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster + && inters.i_info().count == 2 + && inters.is_spike_q() ) + { + assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked, + p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); + assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection, + p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); + } + // no spikes + else + { + assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation, + p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out); + } + } + } + + return append_last; + } + + // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment + // however now it's lazily calculated and then it would be always calculated + + template<std::size_t G1Index, + typename Point1, + typename Point2, + typename RobustPoint1, + typename RobustPoint2, + typename TurnInfo, + typename IntersectionInfo + > + static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/, + Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/, + RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/, + RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2, + bool first1, bool last1, bool first2, bool last2, + bool ip_i2, bool ip_j2, TurnInfo const& tp_model, + IntersectionInfo const& inters, int ip_index, + operation_type & op1, operation_type & op2) + { + boost::ignore_unused_variable_warning(i2); + boost::ignore_unused_variable_warning(j2); + boost::ignore_unused_variable_warning(ip_index); + boost::ignore_unused_variable_warning(tp_model); + + if ( !first2 && !last2 ) + { + if ( first1 ) + { +#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR + // may this give false positives for INTs? + typename IntersectionResult::point_type const& + inters_pt = inters.i_info().intersections[ip_index]; + BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); + BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); +#endif + if ( ip_i2 ) + { + // don't output this IP - for the first point of other geometry segment + op1 = operation_none; + op2 = operation_none; + return true; + } + else if ( ip_j2 ) + { + side_calculator<RobustPoint1, RobustPoint2, RobustPoint2> + side_calc(ri2, ri1, rj1, ri2, rj2, rk2); + + std::pair<operation_type, operation_type> + operations = operations_of_equal(side_calc); + +// TODO: must the above be calculated? +// wouldn't it be enough to check if segments are collinear? + + if ( operations_both(operations, operation_continue) ) + { + if ( op1 != operation_union + || op2 != operation_union + || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) + { + // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! + bool opposite = inters.d_info().opposite; + + op1 = operation_intersection; + op2 = opposite ? operation_union : operation_intersection; + } + } + else + { + BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union)); + //op1 = operation_union; + //op2 = operation_union; + } + + return true; + } + // else do nothing - shouldn't be handled this way + } + else if ( last1 ) + { +#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR + // may this give false positives for INTs? + typename IntersectionResult::point_type const& + inters_pt = inters.i_info().intersections[ip_index]; + BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); + BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); +#endif + if ( ip_i2 ) + { + // don't output this IP - for the first point of other geometry segment + op1 = operation_none; + op2 = operation_none; + return true; + } + else if ( ip_j2 ) + { + side_calculator<RobustPoint1, RobustPoint2, RobustPoint2> + side_calc(ri2, rj1, ri1, ri2, rj2, rk2); + + std::pair<operation_type, operation_type> + operations = operations_of_equal(side_calc); + +// TODO: must the above be calculated? +// wouldn't it be enough to check if segments are collinear? + + if ( operations_both(operations, operation_continue) ) + { + if ( op1 != operation_blocked + || op2 != operation_union + || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) + { + // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! + bool second_going_out = inters.i_info().count > 1; + + op1 = operation_blocked; + op2 = second_going_out ? operation_union : operation_intersection; + } + } + else + { + BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union)); + //op1 = operation_blocked; + //op2 = operation_union; + } + + return true; + } + // else do nothing - shouldn't be handled this way + } + // else do nothing - shouldn't be handled this way + } + + return false; + } + + static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj) + { + if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) ) + return method_touch; + else + return method_touch_interior; + } + + static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j) + { + return is_ip_first_i ? position_front : + ( is_ip_last_j ? position_back : position_middle ); + } + + template <typename Point1, + typename Point2, + typename IntersectionResult, + typename TurnInfo, + typename OutputIterator> + static inline void assign(Point1 const& pi, Point2 const& qi, + IntersectionResult const& result, + int ip_index, + method_type method, + operation_type op0, operation_type op1, + turn_position pos0, turn_position pos1, + bool is_p_first_ip, bool is_q_first_ip, + bool is_p_spike, bool is_q_spike, + TurnInfo const& tp_model, + OutputIterator out) + { + TurnInfo tp = tp_model; + + //geometry::convert(ip, tp.point); + //tp.method = method; + base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index); + + tp.operations[0].operation = op0; + tp.operations[1].operation = op1; + tp.operations[0].position = pos0; + tp.operations[1].position = pos1; + + if ( result.template get<0>().count > 1 ) + { + // NOTE: is_collinear is NOT set for the first endpoint + // for which there is no preceding segment + + //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); + if ( ! is_p_first_ip ) + { + tp.operations[0].is_collinear = op0 != operation_intersection + || is_p_spike; + } + + if ( ! is_q_first_ip ) + { + tp.operations[1].is_collinear = op1 != operation_intersection + || is_q_spike; + } + } + else //if ( result.template get<0>().count == 1 ) + { + if ( op0 == operation_blocked && op1 == operation_intersection ) + { + tp.operations[0].is_collinear = true; + } + else if ( op0 == operation_intersection && op1 == operation_blocked ) + { + tp.operations[1].is_collinear = true; + } + } + + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + + template <typename SidePolicy> + static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side) + { + int const side_pk_q2 = side.pk_wrt_q2(); + int const side_pk_p = side.pk_wrt_p1(); + int const side_qk_p = side.qk_wrt_p1(); + + // 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 ) + { + return std::make_pair(operation_continue, operation_continue); + } + + // If they turn to same side (not opposite sides) + if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) ) + { + // If pk is left of q2 or collinear: p: union, q: intersection + if ( side_pk_q2 != -1 ) + { + return std::make_pair(operation_union, operation_intersection); + } + else + { + return std::make_pair(operation_intersection, operation_union); + } + } + else + { + // They turn opposite sides. If p turns left (or collinear), + // p: union, q: intersection + if ( side_pk_p != -1 ) + { + return std::make_pair(operation_union, operation_intersection); + } + else + { + return std::make_pair(operation_intersection, operation_union); + } + } + } + + static inline bool operations_both( + std::pair<operation_type, operation_type> const& operations, + operation_type const op) + { + return operations.first == op && operations.second == op; + } + + static inline bool operations_combination( + std::pair<operation_type, operation_type> const& operations, + operation_type const op1, operation_type const op2) + { + return ( operations.first == op1 && operations.second == op2 ) + || ( operations.first == op2 && operations.second == op1 ); + } +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp new file mode 100644 index 0000000000..eead0d719b --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -0,0 +1,329 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP + +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay { + +enum turn_position { position_middle, position_front, position_back }; + +template <typename SegmentRatio> +struct turn_operation_linear + : public turn_operation<SegmentRatio> +{ + turn_operation_linear() + : position(position_middle) + , is_collinear(false) + {} + + turn_position position; + bool is_collinear; // valid only for Linear geometry +}; + +template <typename PointP, typename PointQ, + typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, + typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ +> +struct side_calculator +{ + typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system + + inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, + Qi const& qi, Qj const& qj, Qk const& qk) + : m_pi(pi), m_pj(pj), m_pk(pk) + , m_qi(qi), m_qj(qj), m_qk(qk) + {} + + inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); } + inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); } + inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); } + inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); } + + inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); } + inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); } + + Pi const& m_pi; + Pj const& m_pj; + Pk const& m_pk; + Qi const& m_qi; + Qj const& m_qj; + Qk const& m_qk; +}; + +template <typename Point1, typename Point2, typename RobustPolicy> +struct robust_points +{ + typedef typename geometry::robust_point_type + < + Point1, RobustPolicy + >::type robust_point1_type; + // TODO: define robust_point2_type using Point2? + typedef robust_point1_type robust_point2_type; + + inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + RobustPolicy const& robust_policy) + { + geometry::recalculate(m_rpi, pi, robust_policy); + geometry::recalculate(m_rpj, pj, robust_policy); + geometry::recalculate(m_rpk, pk, robust_policy); + geometry::recalculate(m_rqi, qi, robust_policy); + geometry::recalculate(m_rqj, qj, robust_policy); + geometry::recalculate(m_rqk, qk, robust_policy); + } + + robust_point1_type m_rpi, m_rpj, m_rpk; + robust_point2_type m_rqi, m_rqj, m_rqk; +}; + +template <typename Point1, typename Point2, typename RobustPolicy> +class intersection_info_base + : private robust_points<Point1, Point2, RobustPolicy> +{ + typedef robust_points<Point1, Point2, RobustPolicy> base_t; + +public: + typedef Point1 point1_type; + typedef Point2 point2_type; + + typedef typename base_t::robust_point1_type robust_point1_type; + typedef typename base_t::robust_point2_type robust_point2_type; + + typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type; + + intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + RobustPolicy const& robust_policy) + : base_t(pi, pj, pk, qi, qj, qk, robust_policy) + , m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk, + base_t::m_rqi, base_t::m_rqj, base_t::m_rqk) + , m_pi(pi), m_pj(pj), m_pk(pk) + , m_qi(qi), m_qj(qj), m_qk(qk) + {} + + inline Point1 const& pi() const { return m_pi; } + inline Point1 const& pj() const { return m_pj; } + inline Point1 const& pk() const { return m_pk; } + + inline Point2 const& qi() const { return m_qi; } + inline Point2 const& qj() const { return m_qj; } + inline Point2 const& qk() const { return m_qk; } + + inline robust_point1_type const& rpi() const { return base_t::m_rpi; } + inline robust_point1_type const& rpj() const { return base_t::m_rpj; } + inline robust_point1_type const& rpk() const { return base_t::m_rpk; } + + inline robust_point2_type const& rqi() const { return base_t::m_rqi; } + inline robust_point2_type const& rqj() const { return base_t::m_rqj; } + inline robust_point2_type const& rqk() const { return base_t::m_rqk; } + + inline side_calculator_type const& sides() const { return m_side_calc; } + +private: + side_calculator_type m_side_calc; + + point1_type const& m_pi; + point1_type const& m_pj; + point1_type const& m_pk; + point2_type const& m_qi; + point2_type const& m_qj; + point2_type const& m_qk; +}; + +template <typename Point1, typename Point2> +class intersection_info_base<Point1, Point2, detail::no_rescale_policy> +{ +public: + typedef Point1 point1_type; + typedef Point2 point2_type; + + typedef Point1 robust_point1_type; + typedef Point2 robust_point2_type; + + typedef side_calculator<Point1, Point2> side_calculator_type; + + intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + no_rescale_policy const& /*robust_policy*/) + : m_side_calc(pi, pj, pk, qi, qj, qk) + {} + + inline Point1 const& pi() const { return m_side_calc.m_pi; } + inline Point1 const& pj() const { return m_side_calc.m_pj; } + inline Point1 const& pk() const { return m_side_calc.m_pk; } + + inline Point2 const& qi() const { return m_side_calc.m_qi; } + inline Point2 const& qj() const { return m_side_calc.m_qj; } + inline Point2 const& qk() const { return m_side_calc.m_qk; } + + inline Point1 const& rpi() const { return pi(); } + inline Point1 const& rpj() const { return pj(); } + inline Point1 const& rpk() const { return pk(); } + + inline Point2 const& rqi() const { return qi(); } + inline Point2 const& rqj() const { return qj(); } + inline Point2 const& rqk() const { return qk(); } + + inline side_calculator_type const& sides() const { return m_side_calc; } + +private: + side_calculator_type m_side_calc; +}; + + +template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy> +class intersection_info + : public intersection_info_base<Point1, Point2, RobustPolicy> +{ + typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t; + + typedef typename strategy_intersection + < + typename cs_tag<TurnPoint>::type, + Point1, + Point2, + TurnPoint, + RobustPolicy + >::segment_intersection_strategy_type strategy; + +public: + typedef model::referring_segment<Point1 const> segment_type1; + typedef model::referring_segment<Point2 const> segment_type2; + typedef typename base_t::side_calculator_type side_calculator_type; + + typedef typename strategy::return_type result_type; + typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info + typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info + + intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + RobustPolicy const& robust_policy) + : base_t(pi, pj, pk, qi, qj, qk, robust_policy) + , m_result(strategy::apply(segment_type1(pi, pj), + segment_type2(qi, qj), + robust_policy)) + , m_robust_policy(robust_policy) + {} + + inline result_type const& result() const { return m_result; } + inline i_info_type const& i_info() const { return m_result.template get<0>(); } + inline d_info_type const& d_info() const { return m_result.template get<1>(); } + + // TODO: it's more like is_spike_ip_p + inline bool is_spike_p() const + { + if ( base_t::sides().pk_wrt_p1() == 0 ) + { + if ( ! is_ip_j<0>() ) + return false; + + int const qk_p1 = base_t::sides().qk_wrt_p1(); + int const qk_p2 = base_t::sides().qk_wrt_p2(); + + if ( qk_p1 == -qk_p2 ) + { + if ( qk_p1 == 0 ) + { + return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk()); + } + + return true; + } + } + + return false; + } + + // TODO: it's more like is_spike_ip_q + inline bool is_spike_q() const + { + if ( base_t::sides().qk_wrt_q1() == 0 ) + { + if ( ! is_ip_j<1>() ) + return false; + + int const pk_q1 = base_t::sides().pk_wrt_q1(); + int const pk_q2 = base_t::sides().pk_wrt_q2(); + + if ( pk_q1 == -pk_q2 ) + { + if ( pk_q1 == 0 ) + { + return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk()); + } + + return true; + } + } + + return false; + } + +private: + template <typename Point> + inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const + { + typedef model::referring_segment<Point const> seg_t; + + typedef strategy_intersection + < + typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy + > si; + + typedef typename si::segment_intersection_strategy_type strategy; + + typename strategy::return_type result + = strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy); + + return result.template get<0>().count == 2; + } + + template <std::size_t OpId> + bool is_ip_j() const + { + int arrival = d_info().arrival[OpId]; + bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0; + + if ( same_dirs ) + { + if ( i_info().count == 2 ) + { + return arrival != -1; + } + else + { + return arrival == 0; + } + } + else + { + return arrival == 1; + } + } + + result_type m_result; + RobustPolicy const& m_robust_policy; +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp new file mode 100644 index 0000000000..873567bbf5 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -0,0 +1,805 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP + +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> + +// TEMP, for spikes detector +//#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay { + +template<typename AssignPolicy> +struct get_turn_info_linear_areal +{ + static const bool handle_spikes = true; + + template + < + typename Point1, + typename Point2, + typename TurnInfo, + typename RobustPolicy, + typename OutputIterator + > + static inline OutputIterator apply( + Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool is_p_first, bool is_p_last, + bool is_q_first, bool is_q_last, + TurnInfo const& tp_model, + RobustPolicy const& robust_policy, + OutputIterator out) + { + typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> + inters_info; + + inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); + + char const method = inters.d_info().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 + get_turn_info_for_endpoint<true, true>( + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_none, out); + break; + + case 'd' : // disjoint: never do anything + break; + + case 'm' : + { + if ( get_turn_info_for_endpoint<false, true>( + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_touch_interior, out) ) + { + // do nothing + } + else + { + typedef touch_interior + < + TurnInfo + > policy; + + // If Q (1) arrives (1) + if ( inters.d_info().arrival[1] == 1 ) + { + policy::template apply<0>(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), + inters.sides()); + } + else + { + // Swap p/q + side_calculator + < + typename inters_info::robust_point2_type, + typename inters_info::robust_point1_type + > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), + inters.rpi(), inters.rpj(), inters.rpk()); + policy::template apply<1>(qi, qj, qk, pi, pj, pk, + tp, inters.i_info(), inters.d_info(), + swapped_side_calc); + } + + if ( tp.operations[1].operation == operation_blocked ) + { + tp.operations[0].is_collinear = true; + } + + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); + + // this function assumes that 'u' must be set for a spike + calculate_spike_operation(tp.operations[0].operation, + inters, is_p_last); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + *out++ = tp; + } + } + break; + case 'i' : + { + crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info()); + + replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + break; + case 't' : + { + // Both touch (both arrive there) + if ( get_turn_info_for_endpoint<false, true>( + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_touch, out) ) + { + // do nothing + } + else + { + touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + if ( tp.operations[1].operation == operation_blocked ) + { + tp.operations[0].is_collinear = true; + } + + // workarounds for touch<> not taking spikes into account starts here + // those was discovered empirically + // touch<> is not symmetrical! + // P spikes and Q spikes may produce various operations! + // Only P spikes are valid for L/A + // TODO: this is not optimal solution - think about rewriting touch<> + + if ( tp.operations[0].operation == operation_blocked ) + { + // a spike on P on the same line with Q1 + if ( inters.is_spike_p() ) + { + if ( inters.sides().qk_wrt_p1() == 0 ) + { + tp.operations[0].is_collinear = true; + } + else + { + tp.operations[0].operation = operation_union; + } + } + } + else if ( tp.operations[0].operation == operation_continue + && tp.operations[1].operation == operation_continue ) + { + // P spike on the same line with Q2 (opposite) + if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1() + && inters.is_spike_p() ) + { + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_union; + } + } + else if ( tp.operations[0].operation == operation_none + && tp.operations[1].operation == operation_none ) + { + // spike not handled by touch<> + if ( inters.is_spike_p() ) + { + tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_union; + + if ( inters.sides().pk_wrt_q2() == 0 ) + { + tp.operations[0].operation = operation_continue; // will be converted to i + tp.operations[0].is_collinear = true; + } + } + } + + // workarounds for touch<> not taking spikes into account ends here + + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); + + bool ignore_spike + = calculate_spike_operation(tp.operations[0].operation, + inters, is_p_last); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + if ( ! handle_spikes + || ignore_spike + || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i??? + tp, inters, is_p_last, is_q_last, out) ) + { + *out++ = tp; + } + } + } + break; + case 'e': + { + if ( get_turn_info_for_endpoint<true, true>( + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_equal, out) ) + { + // do nothing + } + else + { + tp.operations[0].is_collinear = true; + + if ( ! inters.d_info().opposite ) + { + // Both equal + // or collinear-and-ending at intersection point + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + turn_transformer_ec<false> transformer(method_touch); + transformer(tp); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + method_touch, append_equal, out) ) + { + *out++ = tp; // no spikes + } + } + else + { + equal_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, qi, + tp, out, inters.i_info(), inters.d_info()); + } + } + } + break; + case 'c' : + { + // Collinear + if ( get_turn_info_for_endpoint<true, true>( + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_collinear, out) ) + { + // do nothing + } + else + { + tp.operations[0].is_collinear = true; + + if ( ! inters.d_info().opposite ) + { + method_type method_replace = method_touch_interior; + append_version_c version = append_collinear; + + if ( inters.d_info().arrival[0] == 0 ) + { + // Collinear, but similar thus handled as equal + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + method_replace = method_touch; + version = append_equal; + } + else + { + collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + //method_replace = method_touch_interior; + //version = append_collinear; + } + + turn_transformer_ec<false> transformer(method_replace); + transformer(tp); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + method_replace, version, out) ) + { + // no spikes + *out++ = tp; + } + } + else + { + // Is this always 'm' ? + turn_transformer_ec<false> transformer(method_touch_interior); + + // conditionally handle spikes + if ( handle_spikes ) + { + append_opposite_spikes<append_collinear_opposite>( + tp, inters, is_p_last, is_q_last, out); + } + + // TODO: ignore for spikes? + // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, + // the same with is_q_valid + + collinear_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, pj, pk, qi, qj, qk, + tp, out, inters.i_info(), inters.d_info(), + inters.sides(), transformer); + } + } + } + break; + case '0' : + { + // degenerate points + if (AssignPolicy::include_degenerate) + { + only_convert::apply(tp, inters.i_info()); + + if ( is_p_first + && equals::equals_point_point(pi, tp.point) ) + { + tp.operations[0].position = position_front; + } + else if ( is_p_last + && equals::equals_point_point(pj, tp.point) ) + { + tp.operations[0].position = position_back; + } + // tp.operations[1].position = position_middle; + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + } + break; + default : + { +#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) + std::cout << "TURN: Unknown method: " << method << std::endl; +#endif +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) + throw turn_info_exception(method); +#endif + } + break; + } + + return out; + } + + template <typename Operation, + typename IntersectionInfo> + static inline bool calculate_spike_operation(Operation & op, + IntersectionInfo const& inters, + bool is_p_last) + { + bool is_p_spike = ( op == operation_union || op == operation_intersection ) + && ! is_p_last + && inters.is_spike_p(); + + if ( is_p_spike ) + { + bool going_in = false, going_out = false; + + int const pk_q1 = inters.sides().pk_wrt_q1(); + int const pk_q2 = inters.sides().pk_wrt_q2(); + + if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C + { + going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both + going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them + } + else + { + going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them + going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both + } + + if ( going_in ) + { + op = operation_intersection; + return true; + } + else if ( going_out ) + { + op = operation_union; + return true; + } + } + + return false; + } + + enum append_version_c { append_equal, append_collinear }; + + template <typename TurnInfo, + typename IntersectionInfo, + typename OutIt> + static inline bool append_collinear_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool /*is_q_last*/, + method_type method, append_version_c version, + OutIt out) + { + // method == touch || touch_interior + // both position == middle + + bool is_p_spike = ( version == append_equal ? + ( tp.operations[0].operation == operation_union + || tp.operations[0].operation == operation_intersection ) : + tp.operations[0].operation == operation_continue ) + && ! is_p_last + && inters.is_spike_p(); + + // TODO: throw an exception for spike in Areal? + /*bool is_q_spike = tp.operations[1].operation == spike_op + && ! is_q_last + && inters.is_spike_q();*/ + + if ( is_p_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_union; + *out++ = tp; + tp.operations[0].operation = operation_continue; // boundary + //tp.operations[1].operation = operation_union; + *out++ = tp; + + return true; + } + + return false; + } + + enum append_version_o { append_touches, append_collinear_opposite }; + + template <append_version_o Version, + typename TurnInfo, + typename IntersectionInfo, + typename OutIt> + static inline bool append_opposite_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool /*is_q_last*/, + OutIt out) + { + bool is_p_spike = ( Version == append_touches ? + ( tp.operations[0].operation == operation_continue + || tp.operations[0].operation == operation_intersection ) : // i ??? + true ) + && ! is_p_last + && inters.is_spike_p(); + // TODO: throw an exception for spike in Areal? + /*bool is_q_spike = ( Version == append_touches ? + ( tp.operations[1].operation == operation_continue + || tp.operations[1].operation == operation_intersection ) : + true ) + && ! is_q_last + && inters.is_spike_q();*/ + + if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + { + if ( Version == append_touches ) + { + tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = false; + tp.method = method_touch; + } + else + { + tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = false; + + BOOST_ASSERT(inters.i_info().count > 1); + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_continue; // boundary + *out++ = tp; + tp.operations[0].operation = operation_continue; // boundary + //tp.operations[1].operation = operation_continue; // boundary + *out++ = tp; + + return true; + } + + return false; + } + + static inline void replace_method_and_operations_tm(method_type & method, + operation_type & op0, + operation_type & op1) + { + if ( op0 == operation_blocked && op1 == operation_blocked ) + { + // NOTE: probably only if methods are WRT IPs, not segments! + method = (method == method_touch ? method_equal : method_collinear); + } + + // Assuming G1 is always Linear + if ( op0 == operation_blocked ) + { + op0 = operation_continue; + } + + if ( op1 == operation_blocked ) + { + op1 = operation_continue; + } + else if ( op1 == operation_intersection ) + { + op1 = operation_union; + } + + // spikes in 'm' + if ( method == method_error ) + { + method = method_touch_interior; + op0 = operation_union; + op1 = operation_union; + } + } + + template <bool IsFront> + class turn_transformer_ec + { + public: + explicit turn_transformer_ec(method_type method_t_or_m) + : m_method(method_t_or_m) + {} + + template <typename Turn> + void operator()(Turn & turn) const + { + operation_type & op0 = turn.operations[0].operation; + operation_type & op1 = turn.operations[1].operation; + + // NOTE: probably only if methods are WRT IPs, not segments! + if ( IsFront + || op0 == operation_intersection || op0 == operation_union + || op1 == operation_intersection || op1 == operation_union ) + { + turn.method = m_method; + } + + turn.operations[0].is_collinear = op0 != operation_blocked; + + // Assuming G1 is always Linear + if ( op0 == operation_blocked ) + { + op0 = operation_continue; + } + + if ( op1 == operation_blocked ) + { + op1 = operation_continue; + } + else if ( op1 == operation_intersection ) + { + op1 = operation_union; + } + } + + private: + method_type m_method; + }; + + static inline void replace_operations_i(operation_type & /*op0*/, operation_type & op1) + { + // assuming Linear is always the first one + op1 = operation_union; + } + + // NOTE: Spikes may NOT be handled for Linear endpoints because it's not + // possible to define a spike on an endpoint. Areal geometries must + // NOT have spikes at all. One thing that could be done is to throw + // an exception when spike is detected in Areal geometry. + + template <bool EnableFirst, + bool EnableLast, + typename Point1, + typename Point2, + typename TurnInfo, + typename IntersectionInfo, + typename OutputIterator> + static inline bool get_turn_info_for_endpoint( + Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/, + Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/, + bool is_p_first, bool is_p_last, + bool /*is_q_first*/, bool is_q_last, + TurnInfo const& tp_model, + IntersectionInfo const& inters, + method_type /*method*/, + OutputIterator out) + { + namespace ov = overlay; + typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e; + + const std::size_t ip_count = inters.i_info().count; + // no intersection points + if ( ip_count == 0 ) + return false; + + if ( !is_p_first && !is_p_last ) + return false; + +// TODO: is_q_last could probably be replaced by false and removed from parameters + + linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); + linear_intersections::ip_info const& ip0 = intersections.template get<0>(); + linear_intersections::ip_info const& ip1 = intersections.template get<1>(); + + const bool opposite = inters.d_info().opposite; + + // ANALYSE AND ASSIGN FIRST + + // IP on the first point of Linear Geometry + if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication + { + TurnInfo tp = tp_model; + tp.operations[0].position = position_front; + tp.operations[1].position = position_middle; + + if ( opposite ) // opposite -> collinear + { + tp.operations[0].operation = operation_continue; + tp.operations[1].operation = operation_union; + tp.method = ip0.is_qj ? method_touch : method_touch_interior; + } + else + { + method_type replaced_method = method_touch_interior; + + if ( ip0.is_qj ) + { + side_calculator + < + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::robust_point2_type + > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), + inters.rqi(), inters.rqj(), inters.rqk()); + + std::pair<operation_type, operation_type> + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; + + replaced_method = method_touch; + } + else + { + side_calculator + < + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point2_type + > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), + inters.rqi(), inters.rpi(), inters.rqj()); + + std::pair<operation_type, operation_type> + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; + } + + turn_transformer_ec<true> transformer(replaced_method); + transformer(tp); + } + + // equals<> or collinear<> will assign the second point, + // we'd like to assign the first one + base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0); + + // NOTE: is_collinear is not set for the first endpoint of L + // for which there is no preceding segment + // here is_p_first_ip == true + tp.operations[0].is_collinear = false; + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + + // ANALYSE AND ASSIGN LAST + + // IP on the last point of Linear Geometry + if ( EnableLast + && is_p_last + && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication + { + TurnInfo tp = tp_model; + + if ( inters.i_info().count > 1 ) + { + //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); + tp.operations[0].is_collinear = true; + tp.operations[1].operation = opposite ? operation_continue : operation_union; + } + else //if ( result.template get<0>().count == 1 ) + { + side_calculator + < + typename IntersectionInfo::robust_point1_type, + typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::robust_point2_type + > side_calc(inters.rqi(), inters.rpj(), inters.rpi(), + inters.rqi(), inters.rqj(), inters.rqk()); + + std::pair<operation_type, operation_type> + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; + + turn_transformer_ec<false> transformer(method_none); + transformer(tp); + + tp.operations[0].is_collinear = tp.both(operation_continue); + } + + tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior; + tp.operations[0].operation = operation_blocked; + tp.operations[0].position = position_back; + tp.operations[1].position = position_middle; + + // equals<> or collinear<> will assign the second point, + // we'd like to assign the first one + int ip_index = ip_count > 1 ? 1 : 0; + base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + + return true; + } + + // don't ignore anything for now + return false; + } +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp new file mode 100644 index 0000000000..4f0384877f --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -0,0 +1,720 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP + +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay { + +template<typename AssignPolicy> +struct get_turn_info_linear_linear +{ + static const bool handle_spikes = true; + + template + < + typename Point1, + typename Point2, + typename TurnInfo, + typename RobustPolicy, + typename OutputIterator + > + static inline OutputIterator apply( + Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool is_p_first, bool is_p_last, + bool is_q_first, bool is_q_last, + TurnInfo const& tp_model, + RobustPolicy const& robust_policy, + OutputIterator out) + { + typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> + inters_info; + + inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); + + char const method = inters.d_info().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 + get_turn_info_for_endpoint<AssignPolicy, true, true> + ::apply(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_none, out); + break; + + case 'd' : // disjoint: never do anything + break; + + case 'm' : + { + if ( get_turn_info_for_endpoint<AssignPolicy, false, true> + ::apply(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_touch_interior, out) ) + { + // do nothing + } + else + { + typedef touch_interior + < + TurnInfo + > policy; + + // If Q (1) arrives (1) + if ( inters.d_info().arrival[1] == 1) + { + policy::template apply<0>(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), + inters.sides()); + } + else + { + // Swap p/q + side_calculator + < + typename inters_info::robust_point2_type, + typename inters_info::robust_point1_type + > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), + inters.rpi(), inters.rpj(), inters.rpk()); + + policy::template apply<1>(qi, qj, qk, pi, pj, pk, + tp, inters.i_info(), inters.d_info(), + swapped_side_calc); + } + + if ( tp.operations[0].operation == operation_blocked ) + { + tp.operations[1].is_collinear = true; + } + if ( tp.operations[1].operation == operation_blocked ) + { + tp.operations[0].is_collinear = true; + } + + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + } + break; + case 'i' : + { + crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info()); + + replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + break; + case 't' : + { + // Both touch (both arrive there) + if ( get_turn_info_for_endpoint<AssignPolicy, false, true> + ::apply(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_touch, out) ) + { + // do nothing + } + else + { + touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + // workarounds for touch<> not taking spikes into account starts here + // those was discovered empirically + // touch<> is not symmetrical! + // P spikes and Q spikes may produce various operations! + // TODO: this is not optimal solution - think about rewriting touch<> + + if ( tp.operations[0].operation == operation_blocked + && tp.operations[1].operation == operation_blocked ) + { + // two touching spikes on the same line + if ( inters.is_spike_p() && inters.is_spike_q() ) + { + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_union; + } + else + { + tp.operations[0].is_collinear = true; + tp.operations[1].is_collinear = true; + } + } + else if ( tp.operations[0].operation == operation_blocked ) + { + // a spike on P on the same line with Q1 + if ( inters.is_spike_p() ) + { + if ( inters.sides().qk_wrt_p1() == 0 ) + { + tp.operations[0].is_collinear = true; + } + else + { + tp.operations[0].operation = operation_union; + } + } + else + { + tp.operations[1].is_collinear = true; + } + } + else if ( tp.operations[1].operation == operation_blocked ) + { + // a spike on Q on the same line with P1 + if ( inters.is_spike_q() ) + { + if ( inters.sides().pk_wrt_q1() == 0 ) + { + tp.operations[1].is_collinear = true; + } + else + { + tp.operations[1].operation = operation_union; + } + } + else + { + tp.operations[0].is_collinear = true; + } + } + else if ( tp.operations[0].operation == operation_continue + && tp.operations[1].operation == operation_continue ) + { + // P spike on the same line with Q2 (opposite) + if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1() + && inters.is_spike_p() ) + { + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_union; + } + } + else if ( tp.operations[0].operation == operation_none + && tp.operations[1].operation == operation_none ) + { + // spike not handled by touch<> + bool const is_p = inters.is_spike_p(); + bool const is_q = inters.is_spike_q(); + + if ( is_p || is_q ) + { + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_union; + + if ( inters.sides().pk_wrt_q2() == 0 ) + { + tp.operations[0].operation = operation_continue; // will be converted to i + if ( is_p ) + { + tp.operations[0].is_collinear = true; + } + } + + if ( inters.sides().qk_wrt_p2() == 0 ) + { + tp.operations[1].operation = operation_continue; // will be converted to i + if ( is_q ) + { + tp.operations[1].is_collinear = true; + } + } + } + } + + // workarounds for touch<> not taking spikes into account ends here + + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + if ( ! handle_spikes + || ! append_opposite_spikes<append_touches>(tp, inters, + is_p_last, is_q_last, + out) ) + { + *out++ = tp; + } + } + } + break; + case 'e': + { + if ( get_turn_info_for_endpoint<AssignPolicy, true, true> + ::apply(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_equal, out) ) + { + // do nothing + } + else + { + tp.operations[0].is_collinear = true; + tp.operations[1].is_collinear = true; + + if ( ! inters.d_info().opposite ) + { + // Both equal + // or collinear-and-ending at intersection point + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + // transform turn + turn_transformer_ec transformer(method_touch); + transformer(tp); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, + is_p_last, is_q_last, + method_touch, operation_union, + out) ) + { + *out++ = tp; // no spikes + } + } + else + { + // TODO: ignore for spikes or generate something else than opposite? + + equal_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info()); + } + } + } + break; + case 'c' : + { + // Collinear + if ( get_turn_info_for_endpoint<AssignPolicy, true, true> + ::apply(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + tp_model, inters, method_collinear, out) ) + { + // do nothing + } + else + { + // NOTE: this is for spikes since those are set in the turn_transformer_ec + tp.operations[0].is_collinear = true; + tp.operations[1].is_collinear = true; + + if ( ! inters.d_info().opposite ) + { + method_type method_replace = method_touch_interior; + operation_type spike_op = operation_continue; + + if ( inters.d_info().arrival[0] == 0 ) + { + // Collinear, but similar thus handled as equal + equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + method_replace = method_touch; + spike_op = operation_union; + } + else + { + collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + tp, inters.i_info(), inters.d_info(), inters.sides()); + + //method_replace = method_touch_interior; + //spike_op = operation_continue; + } + + // transform turn + turn_transformer_ec transformer(method_replace); + transformer(tp); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, + is_p_last, is_q_last, + method_replace, spike_op, + out) ) + { + // no spikes + *out++ = tp; + } + } + else + { + // If this always 'm' ? + turn_transformer_ec transformer(method_touch_interior); + + // conditionally handle spikes + if ( handle_spikes ) + { + append_opposite_spikes<append_collinear_opposite>(tp, inters, + is_p_last, is_q_last, + out); + } + + // TODO: ignore for spikes? + // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, + // the same with is_q_valid + + collinear_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, pj, pk, qi, qj, qk, + tp, out, inters.i_info(), inters.d_info(), inters.sides(), + transformer, !is_p_last, !is_q_last); + } + } + } + break; + case '0' : + { + // degenerate points + if (AssignPolicy::include_degenerate) + { + only_convert::apply(tp, inters.i_info()); + + // if any, only one of those should be true + if ( is_p_first + && equals::equals_point_point(pi, tp.point) ) + { + tp.operations[0].position = position_front; + } + else if ( is_p_last + && equals::equals_point_point(pj, tp.point) ) + { + tp.operations[0].position = position_back; + } + else if ( is_q_first + && equals::equals_point_point(qi, tp.point) ) + { + tp.operations[1].position = position_front; + } + else if ( is_q_last + && equals::equals_point_point(qj, tp.point) ) + { + tp.operations[1].position = position_back; + } + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; + } + } + break; + default : + { +#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) + std::cout << "TURN: Unknown method: " << method << std::endl; +#endif +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) + throw turn_info_exception(method); +#endif + } + break; + } + + return out; + } + + template <typename TurnInfo, + typename IntersectionInfo, + typename OutIt> + static inline bool append_collinear_spikes(TurnInfo & tp, + IntersectionInfo const& inters_info, + bool is_p_last, bool is_q_last, + method_type method, operation_type spike_op, + OutIt out) + { + // method == touch || touch_interior + // both position == middle + + bool is_p_spike = tp.operations[0].operation == spike_op + && ! is_p_last + && inters_info.is_spike_p(); + bool is_q_spike = tp.operations[1].operation == spike_op + && ! is_q_last + && inters_info.is_spike_q(); + + if ( is_p_spike && is_q_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + return true; + } + else if ( is_p_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_union; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + //tp.operations[1].operation = operation_union; + *out++ = tp; + + return true; + } + else if ( is_q_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + //tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + return true; + } + + return false; + } + + enum append_version { append_touches, append_collinear_opposite }; + + template <append_version Version, + typename TurnInfo, + typename IntersectionInfo, + typename OutIt> + static inline bool append_opposite_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool is_q_last, + OutIt out) + { + bool is_p_spike = ( Version == append_touches ? + ( tp.operations[0].operation == operation_continue + || tp.operations[0].operation == operation_intersection ) : + true ) + && ! is_p_last + && inters.is_spike_p(); + bool is_q_spike = ( Version == append_touches ? + ( tp.operations[1].operation == operation_continue + || tp.operations[1].operation == operation_intersection ) : + true ) + && ! is_q_last + && inters.is_spike_q(); + + bool res = false; + + if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + { + if ( Version == append_touches ) + { + tp.operations[0].is_collinear = true; + tp.operations[1].is_collinear = false; + tp.method = method_touch; + } + else // Version == append_collinear_opposite + { + tp.operations[0].is_collinear = true; + tp.operations[1].is_collinear = false; + + BOOST_ASSERT(inters.i_info().count > 1); + + base_turn_handler::assign_point(tp, method_touch_interior, + inters.i_info(), 1); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), + inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + //tp.operations[1].operation = operation_intersection; + *out++ = tp; + + res = true; + } + + if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) ) + { + if ( Version == append_touches ) + { + tp.operations[0].is_collinear = false; + tp.operations[1].is_collinear = true; + tp.method = method_touch; + } + else // Version == append_collinear_opposite + { + tp.operations[0].is_collinear = false; + tp.operations[1].is_collinear = true; + + BOOST_ASSERT(inters.i_info().count > 0); + + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), + inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + //tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + res = true; + } + + return res; + } + + static inline void replace_method_and_operations_tm(method_type & method, + operation_type & op0, + operation_type & op1) + { + if ( op0 == operation_blocked && op1 == operation_blocked ) + { + // NOTE: probably only if methods are WRT IPs, not segments! + method = (method == method_touch ? method_equal : method_collinear); + op0 = operation_continue; + op1 = operation_continue; + } + else + { + if ( op0 == operation_continue || op0 == operation_blocked ) + { + op0 = operation_intersection; + } + else if ( op0 == operation_intersection ) + { + op0 = operation_union; + } + + if ( op1 == operation_continue || op1 == operation_blocked ) + { + op1 = operation_intersection; + } + else if ( op1 == operation_intersection ) + { + op1 = operation_union; + } + + // spikes in 'm' + if ( method == method_error ) + { + method = method_touch_interior; + op0 = operation_union; + op1 = operation_union; + } + } + } + + class turn_transformer_ec + { + public: + explicit turn_transformer_ec(method_type method_t_or_m) + : m_method(method_t_or_m) + {} + + template <typename Turn> + void operator()(Turn & turn) const + { + operation_type & op0 = turn.operations[0].operation; + operation_type & op1 = turn.operations[1].operation; + + BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked ); + + if ( op0 == operation_blocked ) + { + op0 = operation_intersection; + } + else if ( op0 == operation_intersection ) + { + op0 = operation_union; + } + + if ( op1 == operation_blocked ) + { + op1 = operation_intersection; + } + else if ( op1 == operation_intersection ) + { + op1 = operation_union; + } + + if ( op0 == operation_intersection || op0 == operation_union + || op1 == operation_intersection || op1 == operation_union ) + { + turn.method = m_method; + } + +// TODO: is this correct? +// it's equivalent to comparing to operation_blocked at the beginning of the function + turn.operations[0].is_collinear = op0 != operation_intersection; + turn.operations[1].is_collinear = op1 != operation_intersection; + } + + private: + method_type m_method; + }; + + static inline void replace_operations_i(operation_type & op0, operation_type & op1) + { + if ( op0 == operation_intersection ) + { + op0 = operation_union; + } + + if ( op1 == operation_intersection ) + { + op1 = operation_union; + } + } +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 26629043cb..a96538c43a 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -1,11 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP @@ -14,19 +20,17 @@ #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/tuple/tuple.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/reverse_dispatch.hpp> - #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -44,17 +48,22 @@ #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/disjoint/box_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> + +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> -#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> - #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> #include <boost/geometry/algorithms/expand.hpp> -#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION # include <sstream> @@ -65,6 +74,12 @@ 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 @@ -88,9 +103,7 @@ template typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename Section1, typename Section2, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > class get_turns_in_sections { @@ -138,16 +151,21 @@ class get_turns_in_sections // 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, + typename geometry::tag<Geometry>::type, areal_tag - >::type, + >::type, areal_tag >::value - && index1 == 0 + && index1 == 0 && index2 >= n - 2 ; } @@ -155,13 +173,27 @@ class get_turns_in_sections public : // Returns true if terminated, false if interrupted + template <typename Turns, typename RobustPolicy, typename InterruptPolicy> 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, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { + boost::ignore_unused_variable_warning(interrupt_policy); + + if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count) + || (sec2.duplicate && (sec2.count + 1) < sec2.range_count)) + { + // Skip sections containig only duplicates. + // They are still important (can indicate non-disjointness) + // but they will be found processing adjacent sections. + // Do NOT skip if they are the ONLY section + return true; + } + cview_type1 cview1(range_by_section(geometry1, sec1)); cview_type2 cview2(range_by_section(geometry2, sec2)); view_type1 view1(cview1); @@ -186,7 +218,7 @@ public : range1_iterator prev1, it1, end1; get_start_point_iterator(sec1, view1, prev1, it1, end1, - index1, ndi1, dir1, sec2.bounding_box); + index1, ndi1, dir1, sec2.bounding_box, robust_policy); // We need a circular iterator because it might run through the closing point. // One circle is actually enough but this one is just convenient. @@ -197,12 +229,12 @@ public : // section 2: [--------------] // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; - it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box); + it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy); ++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); + advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy); int index2 = sec2.begin_index; int ndi2 = sec2.non_duplicate_index; @@ -210,12 +242,12 @@ public : range2_iterator prev2, it2, end2; get_start_point_iterator(sec2, view2, prev2, it2, end2, - index2, ndi2, dir2, sec1.bounding_box); + index2, ndi2, dir2, sec1.bounding_box, robust_policy); 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); + it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy); ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = same_source; @@ -241,24 +273,28 @@ public : // 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); + advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy); 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; + 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); std::size_t const size_before = boost::size(turns); + bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index; + bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index; + bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index; + bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index; + TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2, - ti, std::back_inserter(turns)); + is_1_first, is_1_last, is_2_first, is_2_last, + ti, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -283,24 +319,34 @@ private : 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) + template <size_t Dim, typename Point, typename Box, typename RobustPolicy> + static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) { - return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box)) - || (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box)); + typename robust_point_type<Point, RobustPolicy>::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get<Dim>(robust_point) < get<min_corner, Dim>(box)) + || (dir == -1 && get<Dim>(robust_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) + template <size_t Dim, typename Point, typename Box, typename RobustPolicy> + static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) { - return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box)) - || (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box)); + typename robust_point_type<Point, RobustPolicy>::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get<Dim>(robust_point) > get<max_corner, Dim>(box)) + || (dir == -1 && get<Dim>(robust_point) < get<min_corner, Dim>(box)); } - template <typename Iterator, typename RangeIterator, typename Section> + template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy> static inline void advance_to_non_duplicate_next(Iterator& next, - RangeIterator const& it, Section const& section) + RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy) { + typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type; + robust_point_type robust_point_from_it; + robust_point_type robust_point_from_next; + geometry::recalculate(robust_point_from_it, *it, robust_policy); + geometry::recalculate(robust_point_from_next, *next, robust_policy); + // 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. @@ -311,10 +357,14 @@ private : // 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) + while(! detail::disjoint::disjoint_point_point + ( + robust_point_from_it, robust_point_from_next + ) && check++ < section.range_count) { next++; + geometry::recalculate(robust_point_from_next, *next, robust_policy); } } @@ -322,14 +372,14 @@ private : // 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> + template <typename Range, typename Section, typename Box, typename RobustPolicy> 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) + int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy) { it = boost::begin(range) + section.begin_index; end = boost::begin(range) + section.end_index + 1; @@ -337,7 +387,7 @@ private : // Mimic section-iterator: // Skip to point such that section interects other box prev = it++; - for(; it != end && preceding<0>(dir, *it, other_bounding_box); + for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy); prev = it++, index++, ndi++) {} // Go back one step because we want to start completely preceding @@ -369,6 +419,7 @@ template bool Reverse1, bool Reverse2, typename Turns, typename TurnPolicy, + typename RobustPolicy, typename InterruptPolicy > struct section_visitor @@ -377,14 +428,17 @@ struct section_visitor Geometry1 const& m_geometry1; int m_source_id2; Geometry2 const& m_geometry2; + RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; section_visitor(int id1, Geometry1 const& g1, int id2, Geometry2 const& g2, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& ip) : m_source_id1(id1), m_geometry1(g1) , m_source_id2(id2), m_geometry2(g2) + , m_rescale_policy(robust_policy) , m_turns(turns) , m_interrupt_policy(ip) {} @@ -400,13 +454,12 @@ struct section_visitor Geometry2, Reverse1, Reverse2, Section, Section, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy >::apply( m_source_id1, m_geometry1, sec1, m_source_id2, m_geometry2, sec2, false, + m_rescale_policy, m_turns, m_interrupt_policy); } return true; @@ -418,37 +471,45 @@ template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > class get_turns_generic { public: + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Geometry1 const& geometry1, int source_id2, Geometry2 const& geometry2, - Turns& turns, InterruptPolicy& interrupt_policy) + RobustPolicy const& robust_policy, + 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 model::box + < + typename geometry::robust_point_type + < + point_type, RobustPolicy + >::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); + geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0); + geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, 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); + Turns, TurnPolicy, RobustPolicy, InterruptPolicy + > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy); geometry::partition < @@ -463,13 +524,10 @@ template < typename Range, typename Box, bool ReverseRange, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > 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; @@ -491,14 +549,16 @@ struct get_turns_cs >::type iterator_type; + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Range const& range, int source_id2, Box const& box, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int multi_index = -1, int ring_index = -1) { - if (boost::size(range) <= 1) + if ( boost::size(range) <= 1) { return; } @@ -509,6 +569,8 @@ struct get_turns_cs cview_type cview(range); view_type view(cview); + typename boost::range_size<view_type>::type segments_count1 = boost::size(view) - 1; + iterator_type it = boost::begin(view); ever_circling_iterator<iterator_type> next( @@ -557,9 +619,13 @@ struct get_turns_cs get_turns_with_box(seg_id, source_id2, *prev, *it, *next, bp[0], bp[1], bp[2], bp[3], + // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes + index == 0, + unsigned(index) == segments_count1, + robust_policy, turns, interrupt_policy); - // Future performance enhancement: - // return if told by the interrupt policy + // Future performance enhancement: + // return if told by the interrupt policy } } } @@ -585,6 +651,7 @@ private: else return 0; } + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2, // Points from a range: point_type const& rp0, @@ -595,34 +662,45 @@ private: box_point_type const& bp1, box_point_type const& bp2, box_point_type const& bp3, + bool const is_range_first, + bool const is_range_last, + RobustPolicy const& robust_policy, // 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)); + is_range_first, is_range_last, + true, false, + ti, robust_policy, 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)); + is_range_first, is_range_last, + false, false, + ti, robust_policy, 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)); + is_range_first, is_range_last, + false, false, + ti, robust_policy, 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)); + is_range_first, is_range_last, + false, true, + ti, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -638,15 +716,15 @@ template < typename Polygon, typename Box, bool Reverse, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct get_turns_polygon_cs { + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Polygon const& polygon, int source_id2, Box const& box, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int multi_index = -1) { @@ -656,32 +734,118 @@ struct get_turns_polygon_cs < ring_type, Box, Reverse, ReverseBox, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > intersector_type; intersector_type::apply( source_id1, geometry::exterior_ring(polygon), - source_id2, box, turns, interrupt_policy, + source_id2, box, + robust_policy, + 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it, ++i) { intersector_type::apply( source_id1, *it, - source_id2, box, turns, interrupt_policy, + source_id2, box, + robust_policy, + turns, interrupt_policy, multi_index, i); } } }; + +template +< + typename Multi, typename Box, + bool Reverse, bool ReverseBox, + typename TurnPolicy +> +struct get_turns_multi_polygon_cs +{ + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + static inline void apply( + int source_id1, Multi const& multi, + int source_id2, Box const& box, + RobustPolicy const& robust_policy, + 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, + TurnPolicy + >::apply(source_id1, *it, source_id2, box, + robust_policy, turns, interrupt_policy, i); + } + } +}; + + +// GET_TURN_INFO_TYPE + +template <typename Geometry> +struct topological_tag_base +{ + typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type; +}; + +template <typename Geometry1, typename Geometry2, typename AssignPolicy, + typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, + typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type> +struct get_turn_info_type + : overlay::get_turn_info<AssignPolicy> +{}; + +template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2> +struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag> + : overlay::get_turn_info_linear_linear<AssignPolicy> +{}; + +template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2> +struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag> + : overlay::get_turn_info_linear_areal<AssignPolicy> +{}; + +template <typename Geometry1, typename Geometry2, typename SegmentRatio, + typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, + typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type> +struct turn_operation_type +{ + typedef overlay::turn_operation<SegmentRatio> type; +}; + +template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> +struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag> +{ + typedef overlay::turn_operation_linear<SegmentRatio> type; +}; + +template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> +struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag> +{ + typedef overlay::turn_operation_linear<SegmentRatio> type; +}; + }} // namespace detail::get_turns #endif // DOXYGEN_NO_DETAIL @@ -697,18 +861,14 @@ template typename GeometryTag1, typename GeometryTag2, typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct get_turns : detail::get_turns::get_turns_generic < Geometry1, Geometry2, Reverse1, Reverse2, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > {}; @@ -717,23 +877,19 @@ template < typename Polygon, typename Box, bool ReversePolygon, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct get_turns < polygon_tag, box_tag, Polygon, Box, ReversePolygon, ReverseBox, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > : detail::get_turns::get_turns_polygon_cs < Polygon, Box, ReversePolygon, ReverseBox, - Turns, TurnPolicy, InterruptPolicy + TurnPolicy > {}; @@ -742,22 +898,18 @@ template < typename Ring, typename Box, bool ReverseRing, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct get_turns < ring_tag, box_tag, Ring, Box, ReverseRing, ReverseBox, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > : detail::get_turns::get_turns_cs < Ring, Box, ReverseRing, ReverseBox, - Turns, TurnPolicy, InterruptPolicy + TurnPolicy > {}; @@ -765,28 +917,52 @@ struct get_turns template < + typename MultiPolygon, + typename Box, + bool ReverseMultiPolygon, bool ReverseBox, + typename TurnPolicy +> +struct get_turns + < + multi_polygon_tag, box_tag, + MultiPolygon, Box, + ReverseMultiPolygon, ReverseBox, + TurnPolicy + > + : detail::get_turns::get_turns_multi_polygon_cs + < + MultiPolygon, Box, + ReverseMultiPolygon, ReverseBox, + TurnPolicy + > +{}; + + +template +< typename GeometryTag1, typename GeometryTag2, typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct get_turns_reversed { + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Geometry1 const& g1, int source_id2, Geometry2 const& g2, - Turns& turns, InterruptPolicy& interrupt_policy) + RobustPolicy const& robust_policy, + 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); + TurnPolicy + >::apply(source_id2, g2, source_id1, g1, robust_policy, + turns, interrupt_policy); } }; @@ -804,6 +980,7 @@ struct get_turns_reversed \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s) \param geometry1 \param_geometry \param geometry2 \param_geometry +\param robust_policy policy to handle robustness issues \param turns container which will contain turn points \param interrupt_policy policy determining if process is stopped when intersection is found @@ -814,31 +991,20 @@ template typename AssignPolicy, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void get_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, 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; + typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy; + //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy; boost::mpl::if_c < @@ -849,8 +1015,7 @@ inline void get_turns(Geometry1 const& geometry1, typename tag<Geometry2>::type, Geometry1, Geometry2, Reverse1, Reverse2, - Turns, TurnPolicy, - InterruptPolicy + TurnPolicy >, dispatch::get_turns < @@ -858,15 +1023,18 @@ inline void get_turns(Geometry1 const& geometry1, typename tag<Geometry2>::type, Geometry1, Geometry2, Reverse1, Reverse2, - Turns, TurnPolicy, - InterruptPolicy + TurnPolicy > >::type::apply( 0, geometry1, 1, geometry2, + robust_policy, turns, interrupt_policy); } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp index 1e878ca525..085933dd7a 100644 --- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp +++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -14,7 +14,17 @@ #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/algorithms/detail/recalculate.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/robust_type.hpp> + +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +#endif + +#include <boost/geometry/geometries/point.hpp> #include <boost/geometry/geometries/segment.hpp> @@ -31,6 +41,7 @@ template typename TurnPoints, typename Indexed, typename Geometry1, typename Geometry2, + typename RobustPolicy, bool Reverse1, bool Reverse2, typename Strategy > @@ -39,10 +50,12 @@ struct sort_in_cluster inline sort_in_cluster(TurnPoints const& turn_points , Geometry1 const& geometry1 , Geometry2 const& geometry2 + , RobustPolicy const& robust_policy , Strategy const& strategy) : m_turn_points(turn_points) , m_geometry1(geometry1) , m_geometry2(geometry2) + , m_rescale_policy(robust_policy) , m_strategy(strategy) {} @@ -51,49 +64,100 @@ private : TurnPoints const& m_turn_points; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; + RobustPolicy const& m_rescale_policy; 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; + + typedef typename geometry::robust_point_type + < + point_type, + RobustPolicy + >::type robust_point_type; + + // Still necessary in some situations, + // for example #case_102_multi, #case_107_multi, #case_recursive_boxes_3 + inline void get_situation_map(Indexed const& left, Indexed const& right, + robust_point_type& pi_rob, robust_point_type& pj_rob, + robust_point_type& ri_rob, robust_point_type& rj_rob, + robust_point_type& si_rob, robust_point_type& sj_rob) const + { + 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.other_seg_id, + ri, rj); + geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, + *right.other_seg_id, + si, sj); + + geometry::recalculate(pi_rob, pi, m_rescale_policy); + geometry::recalculate(pj_rob, pj, m_rescale_policy); + geometry::recalculate(ri_rob, ri, m_rescale_policy); + geometry::recalculate(rj_rob, rj, m_rescale_policy); + geometry::recalculate(si_rob, si, m_rescale_policy); + geometry::recalculate(sj_rob, sj, m_rescale_policy); + } + +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO + // This method was still called but did no effect whatsoever on the results, + // with or without robustness-rescaling. + // Probable cause: we rescale in this file ourselves, ignoring passed policy + // TODO: check this more. + // Besides this, it currently does not compile for yet unknown reasons + // (does not find specialization for segment_ratio_type) + // It is currently only called from the Unit Test "multi_intersection.cpp" // 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) + inline void overlap_info( + robust_point_type const& pi, robust_point_type const& pj, + robust_point_type const& ri, robust_point_type const& rj, + robust_point_type const& si, robust_point_type const& sj, + bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const { // Determine how p/r and p/s are located. // One of them is coming from opposite direction. + typedef segment_intersection_points + < + point_type, + typename segment_ratio_type + < + point_type, RobustPolicy + >::type + > intersection_return_type; + typedef strategy::intersection::relate_cartesian_segments < policies::relate::segments_intersection_points < - segment_type, - segment_type, - segment_intersection_points<point_type> + intersection_return_type > > policy; + typedef model::referring_segment<robust_point_type const> segment_type; 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); + intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj); + intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj); + intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj); // Check on overlap pr_overlap = pr.count == 2; ps_overlap = ps.count == 2; rs_overlap = rs.count == 2; } +#endif -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES inline void debug_consider(int order, Indexed const& left, Indexed const& right, std::string const& header, bool skip = true, @@ -102,19 +166,15 @@ private : { 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); + std::cout << "Case: " << header << " for " << left.turn_index << " / " << right.turn_index << std::endl; + + robust_point_type pi, pj, ri, rj, si, sj; + get_situation_map(left, right, pi, pj, ri, rj, si, sj); +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO bool prc = false, psc = false, rsc = false; overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc); +#endif int const side_ri_p = m_strategy.apply(pi, pj, ri); int const side_rj_p = m_strategy.apply(pi, pj, rj); @@ -123,8 +183,7 @@ private : 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 +#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_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; @@ -136,13 +195,15 @@ private : std::cout << header //<< " order: " << order - << " ops: " << operation_char(left.subject.operation) - << "/" << operation_char(right.subject.operation) + << " 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 +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO << " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc) - //<< " idx: " << left.index << "/" << right.index +#endif + //<< " idx: " << left.turn_index << "/" << right.turn_index ; if (! extra.empty()) @@ -167,23 +228,23 @@ private : , std::string const& // header ) const { - bool ret = left.index < right.index; + bool ret = left.turn_index < right.turn_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) + 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) + else if (left.subject->operation == operation_blocked + && right.subject->operation == operation_union) { ret = false; } else { -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) std::cout << "ux/ux unhandled" << std::endl; #endif } @@ -201,32 +262,32 @@ private : { bool ret = false; - if (left.subject.operation == operation_union - && right.subject.operation == operation_union) + 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) + 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) + else if (right.subject->operation == operation_union + && left.subject->operation == operation_blocked) { ret = false; } - else if (left.subject.operation == operation_union) + else if (left.subject->operation == operation_union) { ret = true; } - else if (right.subject.operation == operation_union) + else if (right.subject->operation == operation_union) { ret = false; } else { -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) // this still happens in the traverse.cpp test std::cout << " iu/ux unhandled" << std::endl; #endif @@ -245,43 +306,61 @@ private : { //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 + 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 + +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) + std::cout << "ix/ix unhandled" << std::endl; +#endif + //debug_consider(0, left, right, header, false, "-> return", ret); + + return left.turn_index < right.turn_index; + } + inline bool consider_iu_iu(Indexed const& left, Indexed const& right, - std::string const& header) const + std::string const& header, bool redo = false) 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) + 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) + 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); + robust_point_type pi, pj, ri, rj, si, sj; + get_situation_map(left, right, pi, pj, ri, rj, si, sj); int const side_ri_p = m_strategy.apply(pi, pj, ri); int const side_si_p = m_strategy.apply(pi, pj, si); @@ -291,8 +370,8 @@ private : 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) + 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); @@ -311,14 +390,18 @@ private : debug_consider(0, left, right, header, false, "opp.", ret); return ret; } -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) std::cout << " iu/iu coming from opposite unhandled" << std::endl; #endif } +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO // 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); +#else + // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl; +#endif // One coming from right (#83,#90) // One coming from left (#90, #94, #95) @@ -326,12 +409,14 @@ private : { bool ret = false; +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO if (pr_ov || ps_ov) { int r = side_ri_p != 0 ? side_ri_p : side_si_p; ret = r * side_si_r == 1; } else +#endif { ret = side_si_r == 1; } @@ -348,6 +433,7 @@ private : // Take the one NOT overlapping bool ret = false; bool found = false; +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO if (pr_ov && ! ps_ov) { ret = true; @@ -358,6 +444,7 @@ private : ret = false; found = true; } +#endif debug_consider(0, left, right, header, false, "aligned", ret); if (found) @@ -366,11 +453,18 @@ private : } } -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) std::cout << " iu/iu unhandled" << std::endl; - debug_consider(0, left, right, header, false, "unhandled", left.index < right.index); + debug_consider(0, left, right, header, false, "unhandled", left.turn_index < right.turn_index); #endif - return left.index < right.index; + if (! redo) + { + // In some cases behaviour is not symmetrical. TODO: fix this properly + // OR: alternatively we might consider calling all these functions one-way anyway + return ! consider_iu_iu(right, left, header, true); + } + + return left.turn_index < right.turn_index; } inline bool consider_ii(Indexed const& left, Indexed const& right, @@ -378,16 +472,8 @@ private : { 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); + robust_point_type pi, pj, ri, rj, si, sj; + get_situation_map(left, right, pi, pj, ri, rj, si, sj); int const side_ri_p = m_strategy.apply(pi, pj, ri); int const side_si_p = m_strategy.apply(pi, pj, si); @@ -402,84 +488,89 @@ private : bool const ret = side_si_r != 1; return ret; } - return left.index < right.index; + return left.turn_index < right.turn_index; } public : inline bool operator()(Indexed const& left, Indexed const& right) const { - bool const default_order = left.index < right.index; + bool const default_order = left.turn_index < right.turn_index; - if ((m_turn_points[left.index].discarded || left.discarded) - && (m_turn_points[right.index].discarded || right.discarded)) + if ((m_turn_points[left.turn_index].discarded || left.discarded) + && (m_turn_points[right.turn_index].discarded || right.discarded)) { return default_order; } - else if (m_turn_points[left.index].discarded || left.discarded) + else if (m_turn_points[left.turn_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) + else if (m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_blocked, operation_union) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].both(operation_union) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union) + && m_turn_points[right.turn_index].combination(operation_intersection, operation_union)) { return consider_iu_iu(left, right, "iu/iu"); } - else if (m_turn_points[left.index].both(operation_intersection) - && m_turn_points[right.index].both(operation_intersection)) + else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked) + && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked)) + { + return consider_ix_ix(left, right, "ix/ix"); + } + else if (m_turn_points[left.turn_index].both(operation_intersection) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_union, operation_blocked) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked) + && m_turn_points[right.turn_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)) + else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union) + && m_turn_points[right.turn_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 + else if (m_turn_points[left.turn_index].method != method_equal + && m_turn_points[right.turn_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 + else if (m_turn_points[left.turn_index].method == method_equal + && m_turn_points[right.turn_index].method != method_equal ) { return true; @@ -487,13 +578,13 @@ public : // Now we have no clue how to sort. -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH - std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation) - << operation_char(m_turn_points[left.index].operations[1].operation) - << "/" << operation_char(m_turn_points[right.index].operations[0].operation) - << operation_char(m_turn_points[right.index].operations[1].operation) - << " " << " Take " << left.index << " < " << right.index - << std::cout; +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) + std::cout << " Consider: " << operation_char(m_turn_points[left.turn_index].operations[0].operation) + << operation_char(m_turn_points[left.turn_index].operations[1].operation) + << "/" << operation_char(m_turn_points[right.turn_index].operations[0].operation) + << operation_char(m_turn_points[right.turn_index].operations[1].operation) + << " " << " Take " << left.turn_index << " < " << right.turn_index + << std::endl; #endif return default_order; @@ -523,8 +614,8 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster, 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; + operation_type first = turn_points[it->turn_index].operations[0].operation; + operation_type second = turn_points[it->turn_index].operations[1].operation; if (first > second) { std::swap(first, second); @@ -553,7 +644,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster, // 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)) + if (turn_points[it->turn_index].combination(operation_intersection, operation_union)) { it->discarded = true; } @@ -569,7 +660,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster, if (! it->discarded) { nd_count++; - if (turn_points[it->index].both(operation_continue)) + if (turn_points[it->turn_index].both(operation_continue)) { cc_count++; } @@ -585,7 +676,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster, { for (Iterator it = begin_cluster; it != end_cluster; ++it) { - if (turn_points[it->index].both(operation_continue)) + if (turn_points[it->turn_index].both(operation_continue)) { it->discarded = true; } @@ -602,12 +693,14 @@ template typename TurnPoints, typename Geometry1, typename Geometry2, + typename RobustPolicy, 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, + RobustPolicy& robust_policy, Strategy const& strategy) { // First inspect and (possibly) discard rows @@ -622,31 +715,31 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, TurnPoints, IndexType, Geometry1, Geometry2, + RobustPolicy, Reverse1, Reverse2, Strategy - >(turn_points, geometry1, geometry2, strategy)); - + >(turn_points, geometry1, geometry2, robust_policy, strategy)); -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) 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 "; + operations_type const& op = turn_points[begin_cluster->turn_index].operations[begin_cluster->operation_index]; + std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl; + std::cout << "->Indexes "; for (Iterator it = begin_cluster; it != end_cluster; ++it) { - std::cout << " " << it->index; + std::cout << " " << it->turn_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 << " " << method_char(turn_points[it->turn_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 << " " << operation_char(turn_points[it->turn_index].operations[0].operation) + << operation_char(turn_points[it->turn_index].operations[1].operation); } std::cout << std::endl << "->Discarded: "; for (Iterator it = begin_cluster; it != end_cluster; ++it) @@ -656,7 +749,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, 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) + //<< geometry::distance(turn_points[prev->turn_index].point, turn_points[it->turn_index].point) #endif } diff --git a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp new file mode 100644 index 0000000000..dd041b0d7d --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp @@ -0,0 +1,84 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_BOX_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_type.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 RobustPolicy, + typename BoxOut, + typename Strategy + > + static inline bool apply(Box1 const& box1, + Box2 const& box2, + RobustPolicy const& robust_policy, + 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, robust_policy, box_out, strategy); + } +}; + +template <std::size_t DimensionCount> +struct intersection_box_box<DimensionCount, DimensionCount> +{ + template + < + typename Box1, typename Box2, + typename RobustPolicy, + typename BoxOut, + typename Strategy + > + static inline bool apply(Box1 const&, Box2 const&, + RobustPolicy const&, BoxOut&, Strategy const&) + { + return true; + } +}; + + +}} // namespace detail::intersection +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index 8bca790d74..a13a627456 100644 --- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -1,6 +1,11 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -28,8 +33,17 @@ #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/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> + #include <boost/geometry/views/segment_view.hpp> +#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> + + #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) #include <boost/foreach.hpp> #endif @@ -41,31 +55,64 @@ namespace boost { namespace geometry namespace detail { namespace intersection { -template -< - typename Segment1, typename Segment2, - typename OutputIterator, typename PointOut, - typename Strategy -> +template <typename PointOut> struct intersection_segment_segment_point { + template + < + typename Segment1, typename Segment2, + typename RobustPolicy, + typename OutputIterator, typename Strategy + > static inline OutputIterator apply(Segment1 const& segment1, - Segment2 const& segment2, OutputIterator out, + Segment2 const& segment2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { typedef typename point_type<PointOut>::type point_type; + typedef typename geometry::robust_point_type + < + typename geometry::point_type<Segment1>::type, + RobustPolicy + >::type robust_point_type; + + // TODO: rescale segment -> robust points + robust_point_type pi_rob, pj_rob, qi_rob, qj_rob; + { + // Workaround: + point_type pi, pj, qi, qj; + assign_point_from_index<0>(segment1, pi); + assign_point_from_index<1>(segment1, pj); + assign_point_from_index<0>(segment2, qi); + assign_point_from_index<1>(segment2, qj); + geometry::recalculate(pi_rob, pi, robust_policy); + geometry::recalculate(pj_rob, pj, robust_policy); + geometry::recalculate(qi_rob, qi, robust_policy); + geometry::recalculate(qj_rob, qj, robust_policy); + } + // Get the intersection point (or two points) - segment_intersection_points<point_type> is - = strategy::intersection::relate_cartesian_segments + typedef segment_intersection_points + < + point_type, + typename segment_ratio_type + < + point_type, RobustPolicy + >::type + > intersection_return_type; + + typedef strategy::intersection::relate_cartesian_segments < policies::relate::segments_intersection_points < - Segment1, - Segment2, - segment_intersection_points<point_type> + intersection_return_type > - >::apply(segment1, segment2); + > policy; + + intersection_return_type is = policy::apply(segment1, segment2, + robust_policy, pi_rob, pj_rob, qi_rob, qj_rob); for (std::size_t i = 0; i < is.count; i++) { @@ -77,24 +124,31 @@ struct intersection_segment_segment_point } }; -template -< - typename Linestring1, typename Linestring2, - typename OutputIterator, typename PointOut, - typename Strategy -> +template <typename PointOut> struct intersection_linestring_linestring_point { + template + < + typename Linestring1, typename Linestring2, + typename RobustPolicy, + typename OutputIterator, typename Strategy + > static inline OutputIterator apply(Linestring1 const& linestring1, - Linestring2 const& linestring2, OutputIterator out, + Linestring2 const& linestring2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { typedef typename point_type<PointOut>::type point_type; - typedef detail::overlay::turn_info<point_type> turn_info; + typedef detail::overlay::turn_info + < + point_type, + typename segment_ratio_type<point_type, RobustPolicy>::type + > turn_info; std::deque<turn_info> turns; - geometry::get_intersection_points(linestring1, linestring2, turns); + geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns); for (typename boost::range_iterator<std::deque<turn_info> const>::type it = boost::begin(turns); it != boost::end(turns); ++it) @@ -112,25 +166,15 @@ struct intersection_linestring_linestring_point */ template < - typename LineString, typename Areal, bool ReverseAreal, - typename OutputIterator, typename LineStringOut, - overlay_type OverlayType, - typename Strategy + typename LineStringOut, + overlay_type OverlayType > struct intersection_of_linestring_with_areal { - typedef detail::overlay::follow - < - LineStringOut, - LineString, - Areal, - OverlayType - > follower; - #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) template <typename Turn, typename Operation> - static inline void debug_follow(Turn const& turn, Operation op, + static inline void debug_follow(Turn const& turn, Operation op, int index) { std::cout << index @@ -145,7 +189,14 @@ struct intersection_of_linestring_with_areal } #endif + template + < + typename LineString, typename Areal, + typename RobustPolicy, + typename OutputIterator, typename Strategy + > static inline OutputIterator apply(LineString const& linestring, Areal const& areal, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { @@ -154,9 +205,20 @@ struct intersection_of_linestring_with_areal return out; } - typedef typename point_type<LineStringOut>::type point_type; + typedef detail::overlay::follow + < + LineStringOut, + LineString, + Areal, + OverlayType + > follower; - typedef detail::overlay::traversal_turn_info<point_type> turn_info; + typedef typename point_type<LineStringOut>::type point_type; + typedef detail::overlay::traversal_turn_info + < + point_type, + typename geometry::segment_ratio_type<point_type, RobustPolicy>::type + > turn_info; std::deque<turn_info> turns; detail::get_turns::no_interrupt_policy policy; @@ -164,12 +226,12 @@ struct intersection_of_linestring_with_areal < false, (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), - detail::overlay::calculate_distance_policy - >(linestring, areal, turns, policy); + detail::overlay::assign_null_policy + >(linestring, areal, robust_policy, turns, policy); if (turns.empty()) { - // No intersection points, it is either completely + // No intersection points, it is either completely // inside (interior + borders) // or completely outside @@ -181,8 +243,7 @@ struct intersection_of_linestring_with_areal return out; } - - if (follower::included(border_point, areal)) + if (follower::included(border_point, areal, robust_policy)) { LineStringOut copy; geometry::convert(linestring, copy); @@ -203,7 +264,7 @@ struct intersection_of_linestring_with_areal ( linestring, areal, geometry::detail::overlay::operation_intersection, - turns, out + turns, robust_policy, out ); } }; @@ -220,18 +281,22 @@ namespace dispatch template < - // tag dispatching: - typename TagIn1, typename TagIn2, typename TagOut, - // orientation - // metafunction finetuning helpers: - bool Areal1, bool Areal2, bool ArealOut, // real types typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, overlay_type OverlayType, - typename Strategy + // 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 { @@ -245,124 +310,106 @@ struct intersection_insert template < - typename TagIn1, typename TagIn2, typename TagOut, typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut, + typename TagIn1, typename TagIn2, typename TagOut > struct intersection_insert < - TagIn1, TagIn2, TagOut, - true, true, true, Geometry1, Geometry2, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, + GeometryOut, OverlayType, - Strategy + Reverse1, Reverse2, ReverseOut, + TagIn1, TagIn2, TagOut, + true, true, true > : detail::overlay::overlay - <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy> + <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType> {}; // Any areal type with box: template < - typename TagIn, typename TagOut, typename Geometry, typename Box, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut, + typename TagIn, typename TagOut > struct intersection_insert < - TagIn, box_tag, TagOut, - true, true, true, Geometry, Box, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, + GeometryOut, OverlayType, - Strategy + Reverse1, Reverse2, ReverseOut, + TagIn, box_tag, TagOut, + true, true, true > : detail::overlay::overlay - <Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy> + <Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType> {}; template < typename Segment1, typename Segment2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct intersection_insert < - segment_tag, segment_tag, point_tag, - false, false, false, Segment1, Segment2, + GeometryOut, + OverlayType, Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, Strategy - > : detail::intersection::intersection_segment_segment_point - < - Segment1, Segment2, - OutputIterator, GeometryOut, - Strategy - > + segment_tag, segment_tag, point_tag, + false, false, false + > : detail::intersection::intersection_segment_segment_point<GeometryOut> {}; template < typename Linestring1, typename Linestring2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct intersection_insert < - linestring_tag, linestring_tag, point_tag, - false, false, false, Linestring1, Linestring2, + GeometryOut, + OverlayType, Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, Strategy - > : detail::intersection::intersection_linestring_linestring_point - < - Linestring1, Linestring2, - OutputIterator, GeometryOut, - Strategy - > + linestring_tag, linestring_tag, point_tag, + false, false, false + > : detail::intersection::intersection_linestring_linestring_point<GeometryOut> {}; template < typename Linestring, typename Box, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy + typename GeometryOut, + bool Reverse1, bool Reverse2, bool ReverseOut > struct intersection_insert < - linestring_tag, box_tag, linestring_tag, - false, true, false, Linestring, Box, + GeometryOut, + overlay_intersection, Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy + linestring_tag, box_tag, linestring_tag, + false, true, false > { + template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Linestring const& linestring, - Box const& box, OutputIterator out, Strategy const& ) + Box const& box, + RobustPolicy const& , + OutputIterator out, Strategy const& ) { typedef typename point_type<GeometryOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; @@ -375,27 +422,23 @@ struct intersection_insert template < typename Linestring, typename Polygon, - bool ReverseLinestring, bool ReversePolygon, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool ReverseLinestring, bool ReversePolygon, bool ReverseOut > struct intersection_insert < - linestring_tag, polygon_tag, linestring_tag, - false, true, false, Linestring, Polygon, - ReverseLinestring, ReversePolygon, ReverseOut, - OutputIterator, GeometryOut, + GeometryOut, OverlayType, - Strategy + ReverseLinestring, ReversePolygon, ReverseOut, + linestring_tag, polygon_tag, linestring_tag, + false, true, false > : detail::intersection::intersection_of_linestring_with_areal < - Linestring, Polygon, ReversePolygon, - OutputIterator, GeometryOut, - OverlayType, - Strategy + GeometryOut, + OverlayType > {}; @@ -403,51 +446,48 @@ struct intersection_insert template < typename Linestring, typename Ring, - bool ReverseLinestring, bool ReverseRing, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool ReverseLinestring, bool ReverseRing, bool ReverseOut > struct intersection_insert < - linestring_tag, ring_tag, linestring_tag, - false, true, false, Linestring, Ring, - ReverseLinestring, ReverseRing, ReverseOut, - OutputIterator, GeometryOut, + GeometryOut, OverlayType, - Strategy + ReverseLinestring, ReverseRing, ReverseOut, + linestring_tag, ring_tag, linestring_tag, + false, true, false > : detail::intersection::intersection_of_linestring_with_areal < - Linestring, Ring, ReverseRing, - OutputIterator, GeometryOut, - OverlayType, - Strategy + GeometryOut, + OverlayType > {}; template < typename Segment, typename Box, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct intersection_insert < - segment_tag, box_tag, linestring_tag, - false, true, false, Segment, Box, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, + GeometryOut, OverlayType, - Strategy + Reverse1, Reverse2, ReverseOut, + segment_tag, box_tag, linestring_tag, + false, true, false > { + template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Segment const& segment, - Box const& box, OutputIterator out, Strategy const& ) + Box const& box, + RobustPolicy const& ,// TODO: propagate to clip_range_with_box + OutputIterator out, Strategy const& ) { geometry::segment_view<Segment> range(segment); @@ -460,37 +500,42 @@ struct intersection_insert template < - typename Tag1, typename Tag2, - bool Areal1, bool Areal2, typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename PointOut, + typename PointOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut, + typename Tag1, typename Tag2, + bool Areal1, bool Areal2 > struct intersection_insert < - Tag1, Tag2, point_tag, - Areal1, Areal2, false, Geometry1, Geometry2, - Reverse1, Reverse2, ReverseOut, - OutputIterator, PointOut, + PointOut, OverlayType, - Strategy + Reverse1, Reverse2, ReverseOut, + Tag1, Tag2, point_tag, + Areal1, Areal2, false > { + template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, Strategy const& ) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { - typedef detail::overlay::turn_info<PointOut> turn_info; + typedef detail::overlay::turn_info + < + PointOut, + typename segment_ratio_type<PointOut, RobustPolicy>::type + > 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); + >(geometry1, geometry2, robust_policy, turns, policy); for (typename std::vector<turn_info>::const_iterator it = turns.begin(); it != turns.end(); ++it) { @@ -504,35 +549,156 @@ struct intersection_insert template < - typename GeometryTag1, typename GeometryTag2, typename GeometryTag3, - bool Areal1, bool Areal2, bool ArealOut, - typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, + typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct intersection_insert_reversed { + template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, - Geometry2 const& g2, OutputIterator out, + Geometry2 const& g2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { return intersection_insert < - GeometryTag2, GeometryTag1, GeometryTag3, - Areal2, Areal1, ArealOut, - Geometry2, Geometry1, - Reverse2, Reverse1, ReverseOut, - OutputIterator, GeometryOut, + Geometry2, Geometry1, GeometryOut, OverlayType, - Strategy - >::apply(g2, g1, out, strategy); + Reverse2, Reverse1, ReverseOut + >::apply(g2, g1, robust_policy, out, strategy); } }; +// dispatch for non-areal geometries +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename TagIn1, typename TagIn2 +> +struct intersection_insert + < + Geometry1, Geometry2, GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + TagIn1, TagIn2, linestring_tag, + false, false, false + > : intersection_insert + < + Geometry1, Geometry2, GeometryOut, + OverlayType, + Reverse1, Reverse2, ReverseOut, + typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type, + typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type, + linestring_tag, + false, false, false + > +{}; + + +// dispatch for difference/intersection of linear geometries +template +< + typename Linear1, typename Linear2, typename LineStringOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Linear1, Linear2, LineStringOut, OverlayType, + Reverse1, Reverse2, ReverseOut, + linear_tag, linear_tag, linestring_tag, + false, false, false + > : detail::overlay::linear_linear_linestring + < + Linear1, Linear2, LineStringOut, OverlayType + > +{}; + + +// dispatch for difference/intersection of point-like geometries + +template +< + typename Point1, typename Point2, typename PointOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Point1, Point2, PointOut, OverlayType, + Reverse1, Reverse2, ReverseOut, + point_tag, point_tag, point_tag, + false, false, false + > : detail::overlay::point_point_point + < + Point1, Point2, PointOut, OverlayType + > +{}; + + +template +< + typename MultiPoint, typename Point, typename PointOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + MultiPoint, Point, PointOut, OverlayType, + Reverse1, Reverse2, ReverseOut, + multi_point_tag, point_tag, point_tag, + false, false, false + > : detail::overlay::multipoint_point_point + < + MultiPoint, Point, PointOut, OverlayType + > +{}; + + +template +< + typename Point, typename MultiPoint, typename PointOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + Point, MultiPoint, PointOut, OverlayType, + Reverse1, Reverse2, ReverseOut, + point_tag, multi_point_tag, point_tag, + false, false, false + > : detail::overlay::point_multipoint_point + < + Point, MultiPoint, PointOut, OverlayType + > +{}; + + +template +< + typename MultiPoint1, typename MultiPoint2, typename PointOut, + overlay_type OverlayType, + bool Reverse1, bool Reverse2, bool ReverseOut +> +struct intersection_insert + < + MultiPoint1, MultiPoint2, PointOut, OverlayType, + Reverse1, Reverse2, ReverseOut, + multi_point_tag, multi_point_tag, point_tag, + false, false, false + > : detail::overlay::multipoint_multipoint_point + < + MultiPoint1, MultiPoint2, PointOut, OverlayType + > +{}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -548,50 +714,37 @@ template bool ReverseSecond, overlay_type OverlayType, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator insert(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy robust_policy, OutputIterator out, Strategy const& strategy) { return boost::mpl::if_c + < + geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, + geometry::dispatch::intersection_insert_reversed < - geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, - geometry::dispatch::intersection_insert_reversed - < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, - Geometry1, Geometry2, - overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value, - overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, - OverlayType, - Strategy - >, - geometry::dispatch::intersection_insert - < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, - Geometry1, Geometry2, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > - >::type::apply(geometry1, geometry2, out, strategy); + 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, robust_policy, out, strategy); } @@ -630,10 +783,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); + typedef typename Strategy::rescale_policy_type rescale_policy_type; + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); + return detail::intersection::insert < GeometryOut, false, overlay_intersection - >(geometry1, geometry2, out, strategy); + >(geometry1, geometry2, robust_policy, out, strategy); } @@ -667,12 +824,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); + typedef typename geometry::rescale_policy_type + < + typename geometry::point_type<Geometry1>::type // TODO from both + >::type rescale_policy_type; + typedef strategy_intersection < typename cs_tag<GeometryOut>::type, Geometry1, Geometry2, - typename geometry::point_type<GeometryOut>::type + typename geometry::point_type<GeometryOut>::type, + rescale_policy_type > strategy; return intersection_insert<GeometryOut>(geometry1, geometry2, out, diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp new file mode 100644 index 0000000000..3a7a7a7f3e --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -0,0 +1,326 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP + +#include <algorithm> +#include <vector> + +#include <boost/range.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/detail/relate/turns.hpp> + +#include <boost/geometry/algorithms/detail/turns/compare_turns.hpp> +#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp> +#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp> + +#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp> + +#include <boost/geometry/algorithms/convert.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + typename LineStringOut, + overlay_type OverlayType, + typename Geometry, + typename GeometryTag +> +struct linear_linear_no_intersections; + + +template <typename LineStringOut, typename LineString> +struct linear_linear_no_intersections + < + LineStringOut, overlay_difference, LineString, linestring_tag + > +{ + template <typename OutputIterator> + static inline OutputIterator apply(LineString const& linestring, + OutputIterator oit) + { + LineStringOut ls_out; + geometry::convert(linestring, ls_out); + *oit++ = ls_out; + return oit; + } +}; + + +template <typename LineStringOut, typename MultiLineString> +struct linear_linear_no_intersections + < + LineStringOut, + overlay_difference, + MultiLineString, + multi_linestring_tag + > +{ + template <typename OutputIterator> + static inline OutputIterator apply(MultiLineString const& multilinestring, + OutputIterator oit) + { + for (typename boost::range_iterator<MultiLineString const>::type + it = boost::begin(multilinestring); + it != boost::end(multilinestring); ++it) + { + LineStringOut ls_out; + geometry::convert(*it, ls_out); + *oit++ = ls_out; + } + return oit; + } +}; + + +template <typename LineStringOut, typename Geometry, typename GeometryTag> +struct linear_linear_no_intersections + < + LineStringOut, overlay_intersection, Geometry, GeometryTag + > +{ + template <typename OutputIterator> + static inline OutputIterator apply(Geometry const&, + OutputIterator oit) + { + return oit; + } +}; + + + + + + + +template +< + typename Linear1, + typename Linear2, + typename LinestringOut, + overlay_type OverlayType, + bool EnableFilterContinueTurns = false, + bool EnableRemoveDuplicateTurns = false, + bool EnableDegenerateTurns = true, +#ifdef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS + bool EnableFollowIsolatedPoints = false +#else + bool EnableFollowIsolatedPoints = true +#endif +> +class linear_linear_linestring +{ +protected: + struct assign_policy + { + static bool const include_no_turn = false; + static bool const include_degenerate = EnableDegenerateTurns; + 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& ) + { + } + }; + + + template + < + typename Turns, + typename LinearGeometry1, + typename LinearGeometry2 + > + static inline void compute_turns(Turns& turns, + LinearGeometry1 const& linear1, + LinearGeometry2 const& linear2) + { + turns.clear(); + geometry::detail::relate::turns::get_turns + < + LinearGeometry1, + LinearGeometry2, + detail::get_turns::get_turn_info_type + < + LinearGeometry1, + LinearGeometry2, + assign_policy + > + >::apply(turns, linear1, linear2); + } + + + template + < + overlay_type OverlayTypeForFollow, + bool FollowIsolatedPoints, + typename Turns, + typename LinearGeometry1, + typename LinearGeometry2, + typename OutputIterator + > + static inline OutputIterator + sort_and_follow_turns(Turns& turns, + LinearGeometry1 const& linear1, + LinearGeometry2 const& linear2, + OutputIterator oit) + { + // remove turns that have no added value + turns::filter_continue_turns + < + Turns, + EnableFilterContinueTurns && OverlayType != overlay_intersection + >::apply(turns); + + // sort by seg_id, distance, and operation + std::sort(boost::begin(turns), boost::end(turns), + detail::turns::less_seg_fraction_other_op<>()); + + // remove duplicate turns + turns::remove_duplicate_turns + < + Turns, EnableRemoveDuplicateTurns + >::apply(turns); + + return detail::overlay::following::linear::follow + < + LinestringOut, + LinearGeometry1, + LinearGeometry2, + OverlayTypeForFollow, + FollowIsolatedPoints, + !EnableFilterContinueTurns || OverlayType == overlay_intersection + >::apply(linear1, linear2, boost::begin(turns), boost::end(turns), + oit); + } + +public: + template + < + typename RobustPolicy, typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(Linear1 const& linear1, + Linear2 const& linear2, + RobustPolicy const&, + OutputIterator oit, + Strategy const& ) + { + typedef typename detail::relate::turns::get_turns + < + Linear1, Linear2 + >::turn_info turn_info; + + typedef std::vector<turn_info> turns_container; + + turns_container turns; + compute_turns(turns, linear1, linear2); + + if ( turns.empty() ) + { + // the two linear geometries are disjoint + return linear_linear_no_intersections + < + LinestringOut, + OverlayType, + Linear1, + typename tag<Linear1>::type + >::apply(linear1, oit); + } + + return sort_and_follow_turns + < + OverlayType, + EnableFollowIsolatedPoints + && OverlayType == overlay_intersection + >(turns, linear1, linear2, oit); + } +}; + + + + +template +< + typename Linear1, + typename Linear2, + typename LinestringOut, + bool EnableFilterContinueTurns, + bool EnableRemoveDuplicateTurns, + bool EnableDegenerateTurns, + bool EnableFollowIsolatedPoints +> +struct linear_linear_linestring + < + Linear1, Linear2, LinestringOut, overlay_union, + EnableFilterContinueTurns, EnableRemoveDuplicateTurns, + EnableDegenerateTurns, EnableFollowIsolatedPoints + > +{ + template + < + typename RobustPolicy, typename OutputIterator, typename Strategy + > + static inline OutputIterator apply(Linear1 const& linear1, + Linear2 const& linear2, + RobustPolicy const& robust_policy, + OutputIterator oit, + Strategy const& strategy) + { + oit = linear_linear_no_intersections + < + LinestringOut, + overlay_difference, + Linear1, + typename tag<Linear1>::type + >::apply(linear1, oit); + + return linear_linear_linestring + < + Linear2, Linear1, LinestringOut, overlay_difference, + EnableFilterContinueTurns, EnableRemoveDuplicateTurns, + EnableDegenerateTurns, EnableFollowIsolatedPoints + >::apply(linear2, linear1, robust_policy, oit, strategy); + } +}; + + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp index 41665e0af1..44b5a0df3c 100644 --- a/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 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 @@ -17,7 +18,6 @@ #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> @@ -26,6 +26,7 @@ #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/algorithms/reverse.hpp> @@ -34,12 +35,19 @@ #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> +#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> + +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE # include <boost/geometry/io/dsv/write.hpp> #endif +#ifdef BOOST_GEOMETRY_TIME_OVERLAY +# include <boost/timer.hpp> +#endif + namespace boost { namespace geometry { @@ -66,19 +74,17 @@ 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) + ++it) { 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) + ++op_it) { ring_identifier ring_id ( @@ -110,6 +116,12 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1, 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 @@ -120,6 +132,11 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1, 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; @@ -134,25 +151,26 @@ template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type Direction, - typename Strategy + typename GeometryOut, + overlay_type Direction > struct overlay { + template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply( Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { - if (geometry::num_points(geometry1) == 0 - && geometry::num_points(geometry2) == 0) + if ( geometry::num_points(geometry1) == 0 + && geometry::num_points(geometry2) == 0 ) { return out; } - if (geometry::num_points(geometry1) == 0 - || geometry::num_points(geometry2) == 0) + if ( geometry::num_points(geometry1) == 0 + || geometry::num_points(geometry2) == 0 ) { return return_if_one_input_is_empty < @@ -161,7 +179,11 @@ struct overlay } typedef typename geometry::point_type<GeometryOut>::type point_type; - typedef detail::overlay::traversal_turn_info<point_type> turn_info; + typedef detail::overlay::traversal_turn_info + < + point_type, + typename geometry::segment_ratio_type<point_type, RobustPolicy>::type + > turn_info; typedef std::deque<turn_info> container_type; typedef std::deque @@ -182,8 +204,8 @@ std::cout << "get turns" << std::endl; geometry::get_turns < Reverse1, Reverse2, - detail::overlay::calculate_distance_policy - >(geometry1, geometry2, turn_points, policy); + detail::overlay::assign_null_policy + >(geometry1, geometry2, robust_policy, turn_points, policy); #ifdef BOOST_GEOMETRY_TIME_OVERLAY std::cout << "get_turns: " << timer.elapsed() << std::endl; @@ -198,6 +220,7 @@ std::cout << "enrich" << std::endl; ? geometry::detail::overlay::operation_union : geometry::detail::overlay::operation_intersection, geometry1, geometry2, + robust_policy, side_strategy); #ifdef BOOST_GEOMETRY_TIME_OVERLAY @@ -218,6 +241,7 @@ std::cout << "traverse" << std::endl; Direction == overlay_union ? geometry::detail::overlay::operation_union : geometry::detail::overlay::operation_intersection, + robust_policy, turn_points, rings ); @@ -248,8 +272,8 @@ std::cout << "traverse" << std::endl; ring_identifier id(2, 0, -1); for (typename boost::range_iterator<ring_container_type>::type it = boost::begin(rings); - it != boost::end(rings); - ++it) + it != boost::end(rings); + ++it) { selected[id] = properties(*it, true); selected[id].reversed = ReverseOut; @@ -273,24 +297,6 @@ std::cout << "traverse" << std::endl; }; -// 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 diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp new file mode 100644 index 0000000000..0af062d271 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp @@ -0,0 +1,435 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP + +#include <algorithm> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/algorithms/detail/relate/less.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +// struct for copying points of the pointlike geometries to output +template +< + typename PointOut, + typename GeometryIn, + typename TagIn = typename tag<GeometryIn>::type +> +struct copy_points + : not_implemented<PointOut, GeometryIn> +{}; + +template <typename PointOut, typename PointIn> +struct copy_points<PointOut, PointIn, point_tag> +{ + template <typename OutputIterator> + static inline void apply(PointIn const& point_in, + OutputIterator& oit) + { + PointOut point_out; + geometry::convert(point_in, point_out); + *oit++ = point_out; + } +}; + + +template <typename PointOut, typename MultiPointIn> +struct copy_points<PointOut, MultiPointIn, multi_point_tag> +{ + template <typename OutputIterator> + static inline void apply(MultiPointIn const& multi_point_in, + OutputIterator& oit) + { + for (typename boost::range_iterator<MultiPointIn const>::type + it = boost::begin(multi_point_in); + it != boost::end(multi_point_in); ++it) + { + PointOut point_out; + geometry::convert(*it, point_out); + *oit++ = point_out; + } + } +}; + + + +// action struct for difference/intersection +template <typename PointOut, overlay_type OverlayType> +struct action_selector_pl_pl +{}; + +template <typename PointOut> +struct action_selector_pl_pl<PointOut, overlay_intersection> +{ + template + < + typename Point, + typename OutputIterator + > + static inline void apply(Point const& point, + bool is_common, + OutputIterator& oit) + { + if ( is_common ) + { + copy_points<PointOut, Point>::apply(point, oit); + } + } +}; + + + +template <typename PointOut> +struct action_selector_pl_pl<PointOut, overlay_difference> +{ + template + < + typename Point, + typename OutputIterator + > + static inline void apply(Point const& point, + bool is_common, + OutputIterator& oit) + { + if ( !is_common ) + { + copy_points<PointOut, Point>::apply(point, oit); + } + } +}; + + +//=========================================================================== + +// difference/intersection of point-point +template +< + typename Point1, + typename Point2, + typename PointOut, + overlay_type OverlayType +> +struct point_point_point +{ + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Point1 const& point1, + Point2 const& point2, + RobustPolicy const& , + OutputIterator oit, + Strategy const&) + { + action_selector_pl_pl + < + PointOut, OverlayType + >::apply(point1, + detail::equals::equals_point_point(point1, point2), + oit); + + return oit; + } +}; + + + +// difference of multipoint-point +// +// the apply method in the following struct is called only for +// difference; for intersection the reversal will +// always call the point-multipoint version +template +< + typename MultiPoint, + typename Point, + typename PointOut, + overlay_type OverlayType +> +struct multipoint_point_point +{ + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(MultiPoint const& multipoint, + Point const& point, + RobustPolicy const& , + OutputIterator oit, + Strategy const&) + { + BOOST_ASSERT( OverlayType == overlay_difference ); + + for (typename boost::range_iterator<MultiPoint const>::type + it = boost::begin(multipoint); + it != boost::end(multipoint); ++it) + { + action_selector_pl_pl + < + PointOut, OverlayType + >::apply(*it, + detail::equals::equals_point_point(*it, point), + oit); + } + + return oit; + } +}; + + +// difference/intersection of point-multipoint +template +< + typename Point, + typename MultiPoint, + typename PointOut, + overlay_type OverlayType +> +struct point_multipoint_point +{ + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Point const& point, + MultiPoint const& multipoint, + RobustPolicy const& , + OutputIterator oit, + Strategy const&) + { + typedef action_selector_pl_pl<PointOut, OverlayType> action; + + for (typename boost::range_iterator<MultiPoint const>::type + it = boost::begin(multipoint); + it != boost::end(multipoint); ++it) + { + if ( detail::equals::equals_point_point(*it, point) ) + { + action::apply(point, true, oit); + return oit; + } + } + + action::apply(point, false, oit); + return oit; + } +}; + + + +// difference/intersection of multipoint-multipoint +template +< + typename MultiPoint1, + typename MultiPoint2, + typename PointOut, + overlay_type OverlayType +> +struct multipoint_multipoint_point +{ + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(MultiPoint1 const& multipoint1, + MultiPoint2 const& multipoint2, + RobustPolicy const& robust_policy, + OutputIterator oit, + Strategy const& strategy) + { + if ( OverlayType != overlay_difference + && boost::size(multipoint1) > boost::size(multipoint2) ) + { + return multipoint_multipoint_point + < + MultiPoint2, MultiPoint1, PointOut, OverlayType + >::apply(multipoint2, multipoint1, robust_policy, oit, strategy); + } + + std::vector<typename point_type<MultiPoint2>::type> + points2(boost::begin(multipoint2), boost::end(multipoint2)); + + std::sort(points2.begin(), points2.end(), detail::relate::less()); + + for (typename boost::range_iterator<MultiPoint1 const>::type + it1 = boost::begin(multipoint1); + it1 != boost::end(multipoint1); ++it1) + { + bool found = std::binary_search(points2.begin(), points2.end(), + *it1, detail::relate::less()); + + action_selector_pl_pl + < + PointOut, OverlayType + >::apply(*it1, found, oit); + } + return oit; + } +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +//=========================================================================== + + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { namespace overlay +{ + +// dispatch struct for pointlike-pointlike difference/intersection +// computation +template +< + typename PointLike1, + typename PointLike2, + typename PointOut, + overlay_type OverlayType, + typename Tag1, + typename Tag2 +> +struct pointlike_pointlike_point + : not_implemented<PointLike1, PointLike2, PointOut> +{}; + + +template +< + typename Point1, + typename Point2, + typename PointOut, + overlay_type OverlayType +> +struct pointlike_pointlike_point + < + Point1, Point2, PointOut, OverlayType, + point_tag, point_tag + > : detail::overlay::point_point_point + < + Point1, Point2, PointOut, OverlayType + > +{}; + + +template +< + typename Point, + typename MultiPoint, + typename PointOut, + overlay_type OverlayType +> +struct pointlike_pointlike_point + < + Point, MultiPoint, PointOut, OverlayType, + point_tag, multi_point_tag + > : detail::overlay::point_multipoint_point + < + Point, MultiPoint, PointOut, OverlayType + > +{}; + + +template +< + typename MultiPoint, + typename Point, + typename PointOut, + overlay_type OverlayType +> +struct pointlike_pointlike_point + < + MultiPoint, Point, PointOut, OverlayType, + multi_point_tag, point_tag + > : detail::overlay::multipoint_point_point + < + MultiPoint, Point, PointOut, OverlayType + > +{}; + + +template +< + typename MultiPoint1, + typename MultiPoint2, + typename PointOut, + overlay_type OverlayType +> +struct pointlike_pointlike_point + < + MultiPoint1, MultiPoint2, PointOut, OverlayType, + multi_point_tag, multi_point_tag + > : detail::overlay::multipoint_multipoint_point + < + MultiPoint1, MultiPoint2, PointOut, OverlayType + > +{}; + + +}} // namespace detail_dispatch::overlay +#endif // DOXYGEN_NO_DISPATCH + + +//=========================================================================== + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +// generic pointlike-pointlike union implementation +template +< + typename PointLike1, + typename PointLike2, + typename PointOut +> +struct union_pointlike_pointlike_point +{ + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(PointLike1 const& pointlike1, + PointLike2 const& pointlike2, + RobustPolicy const& robust_policy, + OutputIterator oit, + Strategy const& strategy) + { + copy_points<PointOut, PointLike1>::apply(pointlike1, oit); + + return detail_dispatch::overlay::pointlike_pointlike_point + < + PointLike2, PointLike1, PointOut, overlay_difference, + typename tag<PointLike2>::type, + typename tag<PointLike1>::type + >::apply(pointlike2, pointlike1, robust_policy, oit, strategy); + } + +}; + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp index 007113ffba..516ec349e8 100644 --- a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp +++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp @@ -14,19 +14,19 @@ # define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif +#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER) +#include <iostream> +#endif -#include <vector> - - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/algorithms/detail/signed_index_type.hpp> namespace boost { namespace geometry { + // Internal struct to uniquely identify a segment // on a linestring,ring // or polygon (needs ring_index) @@ -40,7 +40,10 @@ struct segment_identifier , segment_index(-1) {} - inline segment_identifier(int src, int mul, int rin, int seg) + inline segment_identifier(signed_index_type src, + signed_index_type mul, + signed_index_type rin, + signed_index_type seg) : source_index(src) , multi_index(mul) , ring_index(rin) @@ -68,20 +71,20 @@ struct segment_identifier #if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER) friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id) { - std::cout + os << "s:" << seg_id.source_index - << ", v:" << seg_id.segment_index // ~vertex + << ", v:" << seg_id.segment_index // v:vertex because s is used for source ; - 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; + if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index; + if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index; return os; } #endif - int source_index; - int multi_index; - int ring_index; - int segment_index; + signed_index_type source_index; + signed_index_type multi_index; + signed_index_type ring_index; + signed_index_type segment_index; }; diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp index f664b19514..385658a190 100644 --- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 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 @@ -9,11 +10,16 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP + #include <map> +#include <boost/range.hpp> + +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/within.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.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> @@ -40,14 +46,14 @@ namespace dispatch struct select_rings<box_tag, Box> { template <typename Geometry, typename Map> - static inline void apply(Box const& box, Geometry const& , + 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, + static inline void apply(Box const& box, ring_identifier const& id, Map& map, bool midpoint) { map[id] = typename Map::mapped_type(box, midpoint); @@ -68,7 +74,7 @@ namespace dispatch } template <typename Map> - static inline void apply(Ring const& ring, + static inline void apply(Ring const& ring, ring_identifier const& id, Map& map, bool midpoint) { if (boost::size(ring) > 0) @@ -91,9 +97,10 @@ namespace dispatch 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, geometry, id, map, midpoint); @@ -109,16 +116,42 @@ namespace dispatch 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, id, map, midpoint); } } }; -} + + 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 dispatch template<overlay_type OverlayType> @@ -213,7 +246,7 @@ inline void update_selection_map(Geometry1 const& geometry1, 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, + // much 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) @@ -248,7 +281,7 @@ template typename IntersectionMap, typename SelectionMap > inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, - IntersectionMap const& intersection_map, + IntersectionMap const& intersection_map, SelectionMap& selection_map, bool midpoint) { typedef typename geometry::tag<Geometry1>::type tag1; @@ -271,16 +304,16 @@ template typename IntersectionMap, typename SelectionMap > inline void select_rings(Geometry const& geometry, - IntersectionMap const& intersection_map, + 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, + dispatch::select_rings<tag, Geometry>::apply(geometry, ring_identifier(0, -1, -1), map_with_all, midpoint); - update_selection_map<OverlayType>(geometry, geometry, intersection_map, + update_selection_map<OverlayType>(geometry, geometry, intersection_map, map_with_all, selection_map); } diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 9c4c99394e..8dffeae283 100644 --- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -9,16 +9,18 @@ #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/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/algorithms/detail/disjoint.hpp> +#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> @@ -55,17 +57,21 @@ template typename Geometry, typename Turns, typename TurnPolicy, + typename RobustPolicy, typename InterruptPolicy > struct self_section_visitor { Geometry const& m_geometry; + RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; inline self_section_visitor(Geometry const& g, + RobustPolicy const& rp, Turns& turns, InterruptPolicy& ip) : m_geometry(g) + , m_rescale_policy(rp) , m_turns(turns) , m_interrupt_policy(ip) {} @@ -82,12 +88,12 @@ struct self_section_visitor Geometry, Geometry, false, false, Section, Section, - Turns, TurnPolicy, - InterruptPolicy + TurnPolicy >::apply( 0, m_geometry, sec1, 0, m_geometry, sec2, false, + m_rescale_policy, m_turns, m_interrupt_policy); } if (m_interrupt_policy.has_intersections) @@ -103,17 +109,13 @@ struct self_section_visitor -template -< - typename Geometry, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy -> +template<typename TurnPolicy> struct get_turns { + template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Geometry const& geometry, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { @@ -127,20 +129,20 @@ struct get_turns > sections_type; sections_type sec; - geometry::sectionalize<false>(geometry, sec); + geometry::sectionalize<false>(geometry, robust_policy, false, sec); self_section_visitor < Geometry, - Turns, TurnPolicy, InterruptPolicy - > visitor(geometry, turns, interrupt_policy); + Turns, TurnPolicy, RobustPolicy, InterruptPolicy + > visitor(geometry, robust_policy, turns, interrupt_policy); try { geometry::partition < - box_type, - detail::get_turns::get_section_box, + box_type, + detail::get_turns::get_section_box, detail::get_turns::ovelaps_section_box >::apply(sec, visitor); } @@ -166,9 +168,7 @@ template < typename GeometryTag, typename Geometry, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct self_get_turn_points { @@ -178,44 +178,32 @@ struct self_get_turn_points template < typename Ring, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct self_get_turn_points < ring_tag, Ring, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > - : detail::self_get_turn_points::get_turns - < - Ring, - Turns, - TurnPolicy, - InterruptPolicy - > + : detail::self_get_turn_points::get_turns<TurnPolicy> {}; template < typename Box, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct self_get_turn_points < box_tag, Box, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy > { + template <typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Box const& , + RobustPolicy const& , Turns& , InterruptPolicy& ) { @@ -227,24 +215,28 @@ struct self_get_turn_points template < typename Polygon, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy + typename TurnPolicy > struct self_get_turn_points < polygon_tag, Polygon, - Turns, - TurnPolicy, - InterruptPolicy + TurnPolicy + > + : detail::self_get_turn_points::get_turns<TurnPolicy> +{}; + + +template +< + typename MultiPolygon, + typename TurnPolicy +> +struct self_get_turn_points + < + multi_polygon_tag, MultiPolygon, + TurnPolicy > - : detail::self_get_turn_points::get_turns - < - Polygon, - Turns, - TurnPolicy, - InterruptPolicy - > + : detail::self_get_turn_points::get_turns<TurnPolicy> {}; @@ -259,6 +251,7 @@ struct self_get_turn_points \tparam Turns type of intersection container (e.g. vector of "intersection/turn point"'s) \param geometry geometry + \param robust_policy policy to handle robustness issues \param turns container which will contain intersection points \param interrupt_policy policy determining if process is stopped when intersection is found @@ -267,38 +260,24 @@ template < typename AssignPolicy, typename Geometry, + typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, + RobustPolicy const& robust_policy, 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; + typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy; dispatch::self_get_turn_points < typename tag<Geometry>::type, Geometry, - Turns, - TurnPolicy, - InterruptPolicy - >::apply(geometry, turns, interrupt_policy); + turn_policy + >::apply(geometry, robust_policy, turns, interrupt_policy); } diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp index eebe381944..51fd1b3dca 100644 --- a/boost/geometry/algorithms/detail/overlay/stream_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp @@ -35,7 +35,6 @@ namespace detail { namespace overlay 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 @@ -54,7 +53,7 @@ namespace detail { namespace overlay << " nxt seg " << info.travels_to_vertex_index << " , ip " << info.travels_to_ip_index << " , or " << info.next_ip_index - << " dst " << double(d) + << " frac " << info.fraction << info.visit_state; if (info.flagged) { diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp index 810a27af04..6ee32c17c0 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp @@ -24,15 +24,21 @@ namespace detail { namespace overlay { -template <typename P> -struct traversal_turn_operation : public turn_operation +template <typename Point, typename SegmentRatio> +struct traversal_turn_operation : public turn_operation<SegmentRatio> { - enrichment_info<P> enriched; + enrichment_info<Point> enriched; visit_info visited; }; -template <typename P> -struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> > +template <typename Point, typename SegmentRatio> +struct traversal_turn_info + : public turn_info + < + Point, + SegmentRatio, + traversal_turn_operation<Point, SegmentRatio> + > {}; diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp index 12daafa0cf..59d2ba703e 100644 --- a/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -13,11 +13,12 @@ #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> @@ -38,7 +39,7 @@ namespace detail { namespace overlay template <typename Turn, typename Operation> #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE -inline void debug_traverse(Turn const& turn, Operation op, +inline void debug_traverse(Turn const& turn, Operation op, std::string const& header) { std::cout << header @@ -57,7 +58,7 @@ inline void debug_traverse(Turn const& turn, Operation op, } } #else -inline void debug_traverse(Turn const& , Operation, std::string const& ) +inline void debug_traverse(Turn const& , Operation, const char*) { } #endif @@ -92,14 +93,16 @@ template typename G1, typename G2, typename Turns, - typename IntersectionInfo + typename IntersectionInfo, + typename RobustPolicy > 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) + segment_identifier& seg_id, + RobustPolicy const& robust_policy) { info.visited.set_visited(); set_visited_for_continue(*ip, info); @@ -107,7 +110,7 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, // If there is no next IP on this segment if (info.enriched.next_ip_index < 0) { - if (info.enriched.travels_to_vertex_index < 0 + if (info.enriched.travels_to_vertex_index < 0 || info.enriched.travels_to_ip_index < 0) { return false; @@ -120,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, { geometry::copy_segments<Reverse1>(g1, info.seg_id, info.enriched.travels_to_vertex_index, + robust_policy, current_output); } else { geometry::copy_segments<Reverse2>(g2, info.seg_id, info.enriched.travels_to_vertex_index, + robust_policy, current_output); } seg_id = info.seg_id; @@ -137,12 +142,16 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, seg_id = info.seg_id; } - detail::overlay::append_no_duplicates(current_output, ip->point); + detail::overlay::append_no_dups_or_spikes(current_output, ip->point, + robust_policy); + return true; } -inline bool select_source(operation_type operation, int source1, int source2) +inline bool select_source(operation_type operation, + signed_index_type source1, + signed_index_type source2) { return (operation == operation_intersection && source1 != source2) || (operation == operation_union && source1 == source2) @@ -227,12 +236,14 @@ template class traverse { public : - template <typename Turns, typename Rings> + template <typename RobustPolicy, typename Turns, typename Rings> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, detail::overlay::operation_type operation, + RobustPolicy const& robust_policy, 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 @@ -240,6 +251,12 @@ public : 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; @@ -253,7 +270,7 @@ public : ++it) { // Skip discarded ones - if (! (it->is_discarded() || it->blocked())) + if (! (it->discarded || ! it->selectable_start || it->blocked())) { for (turn_operation_iterator_type iit = boost::begin(it->operations); state.good() && iit != boost::end(it->operations); @@ -267,9 +284,9 @@ public : { set_visited_for_continue(*it, *iit); - typename boost::range_value<Rings>::type current_output; - detail::overlay::append_no_duplicates(current_output, - it->point, true); + ring_type current_output; + detail::overlay::append_no_dups_or_spikes(current_output, + it->point, robust_policy); turn_iterator current = it; turn_operation_iterator_type current_iit = iit; @@ -279,13 +296,14 @@ public : geometry1, geometry2, turns, current, current_output, - *iit, current_seg_id)) + *iit, current_seg_id, + robust_policy)) { Backtrack::apply( - size_at_start, + size_at_start, rings, current_output, turns, *current_iit, "No next IP", - geometry1, geometry2, state); + geometry1, geometry2, robust_policy, state); } if (! detail::overlay::select_next_ip( @@ -295,10 +313,10 @@ public : current_iit)) { Backtrack::apply( - size_at_start, + size_at_start, rings, current_output, turns, *iit, "Dead end at start", - geometry1, geometry2, state); + geometry1, geometry2, robust_policy, state); } else { @@ -308,7 +326,7 @@ public : detail::overlay::debug_traverse(*current, *current_iit, "Selected "); - unsigned int i = 0; + typename boost::range_size<Turns>::type i = 0; while (current_iit != iit && state.good()) { @@ -317,10 +335,10 @@ public : // It visits a visited node again, without passing the start node. // This makes it suspicious for endless loops Backtrack::apply( - size_at_start, + size_at_start, rings, current_output, turns, *iit, "Visit again", - geometry1, geometry2, state); + geometry1, geometry2, robust_policy, state); } else { @@ -339,7 +357,8 @@ public : detail::overlay::assign_next_ip<Reverse1, Reverse2>( geometry1, geometry2, turns, current, current_output, - *current_iit, current_seg_id); + *current_iit, current_seg_id, + robust_policy); if (! detail::overlay::select_next_ip( operation, @@ -351,12 +370,15 @@ public : // Should not occur in self-intersecting polygons without spikes // Might occur in polygons with spikes Backtrack::apply( - size_at_start, + size_at_start, rings, current_output, turns, *iit, "Dead end", - geometry1, geometry2, state); + geometry1, geometry2, robust_policy, state); + } + else + { + detail::overlay::debug_traverse(*current, *current_iit, "Selected "); } - detail::overlay::debug_traverse(*current, *current_iit, "Selected "); if (i++ > 2 + 2 * turns.size()) { @@ -364,10 +386,10 @@ public : // than turn points. // Turn points marked as "ii" can be visited twice. Backtrack::apply( - size_at_start, + size_at_start, rings, current_output, turns, *iit, "Endless loop", - geometry1, geometry2, state); + geometry1, geometry2, robust_policy, state); } } } @@ -376,7 +398,11 @@ public : { iit->visited.set_finished(); detail::overlay::debug_traverse(*current, *iit, "->Finished"); - rings.push_back(current_output); + if (geometry::num_points(current_output) >= min_num_points) + { + clean_closing_dups_and_spikes(current_output, robust_policy); + rings.push_back(current_output); + } } } } diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp index 89a60b21ab..26669a4b1f 100644 --- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -54,11 +54,12 @@ enum method_type 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. */ +template <typename SegmentRatio> struct turn_operation { operation_type operation; segment_identifier seg_id; - segment_identifier other_id; + SegmentRatio fraction; inline turn_operation() : operation(operation_none) @@ -78,7 +79,8 @@ struct turn_operation template < typename Point, - typename Operation = turn_operation, + typename SegmentRatio, + typename Operation = turn_operation<SegmentRatio>, typename Container = boost::array<Operation, 2> > struct turn_info @@ -90,6 +92,7 @@ struct turn_info Point point; method_type method; bool discarded; + bool selectable_start; // Can be used as starting-turn in traverse Container operations; @@ -97,13 +100,14 @@ struct turn_info inline turn_info() : method(method_none) , discarded(false) + , selectable_start(true) {} inline bool both(operation_type type) const { return has12(type, type); } - + inline bool has(operation_type type) const { return this->operations[0].operation == type @@ -115,8 +119,6 @@ struct turn_info return has12(type1, type2) || has12(type2, type1); } - - inline bool is_discarded() const { return discarded; } inline bool blocked() const { return both(operation_blocked); diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp index 6be63f42b4..4284a801a1 100644 --- a/boost/geometry/algorithms/detail/overlay/visit_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp @@ -10,11 +10,6 @@ #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 { @@ -22,9 +17,6 @@ namespace boost { namespace geometry namespace detail { namespace overlay { - -#if ! defined(BOOST_GEOMETRY_USE_MSM) - class visit_info { private : @@ -66,8 +58,6 @@ public: } } - - #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION friend std::ostream& operator<<(std::ostream &os, visit_info const& v) { @@ -82,50 +72,6 @@ public: }; -#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 diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp index 45ff52ccb1..a44d5637bc 100644 --- a/boost/geometry/algorithms/detail/partition.hpp +++ b/boost/geometry/algorithms/detail/partition.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +10,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP #include <vector> +#include <boost/assert.hpp> #include <boost/range/algorithm/copy.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/core/coordinate_type.hpp> @@ -23,7 +24,7 @@ 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) +void divide_box(Box const& box, Box& lower_box, Box& upper_box) { typedef typename coordinate_type<Box>::type ctype; @@ -39,10 +40,10 @@ inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) } // Divide collection into three subsets: lower, upper and oversized -// (not-fitting) +// (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, +inline void divide_into_subsets(Box const& lower_box, Box const& upper_box, InputCollection const& collection, index_vector_type const& input, @@ -79,14 +80,14 @@ static inline void divide_into_subsets(Box const& lower_box, else { // Is nowhere! Should not occur! - BOOST_ASSERT(true); + BOOST_ASSERT(false); } } } // Match collection with itself template <typename InputCollection, typename Policy> -static inline void handle_one(InputCollection const& collection, +inline void handle_one(InputCollection const& collection, index_vector_type const& input, Policy& policy) { @@ -106,10 +107,15 @@ static inline void handle_one(InputCollection const& collection, } // 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, +template +< + typename InputCollection1, + typename InputCollection2, + typename Policy +> +inline void handle_two( + InputCollection1 const& collection1, index_vector_type const& input1, + InputCollection2 const& collection2, index_vector_type const& input2, Policy& policy) { typedef boost::range_iterator @@ -209,7 +215,8 @@ template < int Dimension, typename Box, - typename OverlapsPolicy, + typename OverlapsPolicy1, + typename OverlapsPolicy2, typename VisitBoxPolicy > class partition_two_collections @@ -220,15 +227,21 @@ class partition_two_collections < 1 - Dimension, Box, - OverlapsPolicy, + OverlapsPolicy1, + OverlapsPolicy2, VisitBoxPolicy > sub_divide; - template <typename InputCollection, typename Policy> + template + < + typename InputCollection1, + typename InputCollection2, + typename Policy + > static inline void next_level(Box const& box, - InputCollection const& collection1, + InputCollection1 const& collection1, index_vector_type const& input1, - InputCollection const& collection2, + InputCollection2 const& collection2, index_vector_type const& input2, int level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) @@ -252,10 +265,15 @@ class partition_two_collections } public : - template <typename InputCollection, typename Policy> + template + < + typename InputCollection1, + typename InputCollection2, + 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, + InputCollection1 const& collection1, index_vector_type const& input1, + InputCollection2 const& collection2, index_vector_type const& input2, int level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) @@ -267,9 +285,9 @@ public : index_vector_type lower1, upper1, exceeding1; index_vector_type lower2, upper2, exceeding2; - divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1, + divide_into_subsets<OverlapsPolicy1>(lower_box, upper_box, collection1, input1, lower1, upper1, exceeding1); - divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2, + divide_into_subsets<OverlapsPolicy2>(lower_box, upper_box, collection2, input2, lower2, upper2, exceeding2); if (boost::size(exceeding1) > 0) @@ -308,15 +326,17 @@ struct visit_no_policy template < typename Box, - typename ExpandPolicy, - typename OverlapsPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2 = ExpandPolicy1, + typename OverlapsPolicy2 = OverlapsPolicy1, typename VisitBoxPolicy = visit_no_policy > class partition { typedef std::vector<std::size_t> index_vector_type; - template <typename InputCollection> + template <typename ExpandPolicy, typename InputCollection> static inline void expand_to_collection(InputCollection const& collection, Box& total, index_vector_type& index_vector) { @@ -344,12 +364,12 @@ public : index_vector_type index_vector; Box total; assign_inverse(total); - expand_to_collection(collection, total, index_vector); + expand_to_collection<ExpandPolicy1>(collection, total, index_vector); detail::partition::partition_one_collection < 0, Box, - OverlapsPolicy, + OverlapsPolicy1, VisitBoxPolicy >::apply(total, collection, index_vector, 0, min_elements, visitor, box_visitor); @@ -373,9 +393,14 @@ public : } } - template <typename InputCollection, typename VisitPolicy> - static inline void apply(InputCollection const& collection1, - InputCollection const& collection2, + template + < + typename InputCollection1, + typename InputCollection2, + typename VisitPolicy + > + static inline void apply(InputCollection1 const& collection1, + InputCollection2 const& collection2, VisitPolicy& visitor, std::size_t min_elements = 16, VisitBoxPolicy box_visitor = visit_no_policy() @@ -387,12 +412,12 @@ public : 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); + expand_to_collection<ExpandPolicy1>(collection1, total, index_vector1); + expand_to_collection<ExpandPolicy2>(collection2, total, index_vector2); detail::partition::partition_two_collections < - 0, Box, OverlapsPolicy, VisitBoxPolicy + 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy >::apply(total, collection1, index_vector1, collection2, index_vector2, @@ -402,13 +427,17 @@ public : { typedef typename boost::range_iterator < - InputCollection const - >::type iterator_type; - for(iterator_type it1 = boost::begin(collection1); + InputCollection1 const + >::type iterator_type1; + typedef typename boost::range_iterator + < + InputCollection2 const + >::type iterator_type2; + for(iterator_type1 it1 = boost::begin(collection1); it1 != boost::end(collection1); ++it1) { - for(iterator_type it2 = boost::begin(collection2); + for(iterator_type2 it2 = boost::begin(collection2); it2 != boost::end(collection2); ++it2) { @@ -417,9 +446,9 @@ public : } } } - }; + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp new file mode 100644 index 0000000000..cd3acb5ba4 --- /dev/null +++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp @@ -0,0 +1,126 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP + +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/util/math.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Checks if a point ("last_point") causes a spike w.r.t. +// the specified two other points (segment_a, segment_b) +// +// x-------x------x +// a lp b +// +// Above, lp generates a spike w.r.t. segment(a,b) +// So specify last point first, then (a,b) (this is unordered, so unintuitive) +template <typename Point1, typename Point2, typename Point3> +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b) +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point1>::type + >::type side_strategy; + + typedef Point1 vector_type; + + int const side = side_strategy::apply(last_point, segment_a, segment_b); + if (side == 0) + { + // Last point is collinear w.r.t previous segment. + // Check if it is equal + vector_type diff1; + conversion::convert_point_to_point(last_point, diff1); + geometry::subtract_point(diff1, segment_b); + int const sgn_x1 = math::sign(geometry::get<0>(diff1)); + int const sgn_y1 = math::sign(geometry::get<1>(diff1)); + if (sgn_x1 == 0 && sgn_y1 == 0) + { + return true; + } + + // Check if it moves forward + vector_type diff2; + conversion::convert_point_to_point(segment_b, diff2); + geometry::subtract_point(diff2, segment_a); + int const sgn_x2 = math::sign(geometry::get<0>(diff2)); + int const sgn_y2 = math::sign(geometry::get<1>(diff2)); + + return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2; + } + return false; +} + +template +< + typename Point1, + typename Point2, + typename Point3, + typename RobustPolicy +> +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b, + RobustPolicy const& robust_policy) +{ + if (point_is_spike_or_equal(last_point, segment_a, segment_b)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type last_point_rob, segment_a_rob, segment_b_rob; + geometry::recalculate(last_point_rob, last_point, robust_policy); + geometry::recalculate(segment_a_rob, segment_a, robust_policy); + geometry::recalculate(segment_b_rob, segment_b, robust_policy); + + return point_is_spike_or_equal + ( + last_point_rob, + segment_a_rob, + segment_b_rob + ); +} + + +} // namespace detail +#endif + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp index b7e15ba3f9..24b88a8d19 100644 --- a/boost/geometry/algorithms/detail/point_on_border.hpp +++ b/boost/geometry/algorithms/detail/point_on_border.hpp @@ -19,6 +19,7 @@ #include <boost/range.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> @@ -26,7 +27,7 @@ #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> -#include <boost/geometry/algorithms/detail/disjoint.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> namespace boost { namespace geometry @@ -153,6 +154,35 @@ struct point_on_box }; +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 @@ -203,6 +233,36 @@ struct point_on_border<box_tag, Point, Box> {}; +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 + > + > +{}; + + +template<typename Point, typename Multi> +struct point_on_border<multi_linestring_tag, Point, Multi> + : detail::point_on_border::point_on_multi + < + Point, + Multi, + detail::point_on_border::point_on_range + < + Point, + typename boost::range_value<Multi>::type + > + > +{}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -229,8 +289,6 @@ inline bool point_on_border(Point& point, concept::check<Point>(); concept::check<Geometry const>(); - typedef typename point_type<Geometry>::type point_type; - return dispatch::point_on_border < typename tag<Geometry>::type, diff --git a/boost/geometry/algorithms/detail/recalculate.hpp b/boost/geometry/algorithms/detail/recalculate.hpp new file mode 100644 index 0000000000..2c3ea7413b --- /dev/null +++ b/boost/geometry/algorithms/detail/recalculate.hpp @@ -0,0 +1,231 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_ALGORITHMS_DETAIL_RECALCULATE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_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/interior_rings.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace recalculate +{ + +template <std::size_t Dimension> +struct recalculate_point +{ + template <typename Point1, typename Point2, typename Strategy> + static inline void apply(Point1& point1, Point2 const& point2, Strategy const& strategy) + { + std::size_t const dim = Dimension - 1; + geometry::set<dim>(point1, strategy.template apply<dim>(geometry::get<dim>(point2))); + recalculate_point<dim>::apply(point1, point2, strategy); + } +}; + +template <> +struct recalculate_point<0> +{ + template <typename Point1, typename Point2, typename Strategy> + static inline void apply(Point1&, Point2 const&, Strategy const&) + { + } +}; + + +template <std::size_t Dimension> +struct recalculate_indexed +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + // Do it for both indices in one dimension + static std::size_t const dim = Dimension - 1; + geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2))); + geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2))); + recalculate_indexed<dim>::apply(geometry1, geometry2, strategy); + } +}; + +template <> +struct recalculate_indexed<0> +{ + + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline void apply(Geometry1& , Geometry2 const& , Strategy const& ) + { + } +}; + +struct range_to_range +{ + template + < + typename Range1, + typename Range2, + typename Strategy + > + static inline void apply(Range1& destination, Range2 const& source, + Strategy const& strategy) + { + typedef typename geometry::point_type<Range2>::type point_type; + typedef recalculate_point<geometry::dimension<point_type>::value> per_point; + geometry::clear(destination); + + for (typename boost::range_iterator<Range2 const>::type it + = boost::begin(source); + it != boost::end(source); + ++it) + { + point_type p; + per_point::apply(p, *it, strategy); + geometry::append(destination, p); + } + } +}; + +struct polygon_to_polygon +{ +private: + template + < + typename IteratorIn, + typename IteratorOut, + typename Strategy + > + static inline void iterate(IteratorIn begin, IteratorIn end, + IteratorOut it_out, + Strategy const& strategy) + { + for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out) + { + range_to_range::apply(*it_out, *it_in, strategy); + } + } + + template + < + typename InteriorRingsOut, + typename InteriorRingsIn, + typename Strategy + > + static inline void apply_interior_rings( + InteriorRingsOut& interior_rings_out, + InteriorRingsIn const& interior_rings_in, + Strategy const& strategy) + { + traits::resize<InteriorRingsOut>::apply(interior_rings_out, + boost::size(interior_rings_in)); + + iterate( + boost::begin(interior_rings_in), boost::end(interior_rings_in), + boost::begin(interior_rings_out), + strategy); + } + +public: + template + < + typename Polygon1, + typename Polygon2, + typename Strategy + > + static inline void apply(Polygon1& destination, Polygon2 const& source, + Strategy const& strategy) + { + range_to_range::apply(geometry::exterior_ring(destination), + geometry::exterior_ring(source), strategy); + + apply_interior_rings(geometry::interior_rings(destination), + geometry::interior_rings(source), strategy); + } +}; + +}} // namespace detail::recalculate +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> +struct recalculate : not_implemented<Tag1, Tag2> +{}; + +template <typename Point1, typename Point2> +struct recalculate<Point1, Point2, point_tag, point_tag> + : detail::recalculate::recalculate_point<geometry::dimension<Point1>::value> +{}; + +template <typename Box1, typename Box2> +struct recalculate<Box1, Box2, box_tag, box_tag> + : detail::recalculate::recalculate_indexed<geometry::dimension<Box1>::value> +{}; + +template <typename Segment1, typename Segment2> +struct recalculate<Segment1, Segment2, segment_tag, segment_tag> + : detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value> +{}; + +template <typename Polygon1, typename Polygon2> +struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag> + : detail::recalculate::polygon_to_polygon +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +template <typename Geometry1, typename Geometry2, typename Strategy> +inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) +{ + concept::check<Geometry1>(); + concept::check<Geometry2 const>(); + + // static assert dimensions (/types) are the same + + dispatch::recalculate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp new file mode 100644 index 0000000000..31d206ac99 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp @@ -0,0 +1,823 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP + +#include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/algorithms/detail/single_geometry.hpp> + +#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/turns.hpp> +#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> +#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// WARNING! +// TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM) +// Use the rtree in this case! + +// may be used to set EI and EB for an Areal geometry for which no turns were generated +template <typename OtherAreal, typename Result, bool TransposeResult> +class no_turns_aa_pred +{ +public: + no_turns_aa_pred(OtherAreal const& other_areal, Result & res) + : m_result(res) + , m_other_areal(other_areal) + , m_flags(0) + { + // check which relations must be analysed + + if ( ! may_update<interior, interior, '2', TransposeResult>(m_result) + && ! may_update<boundary, interior, '1', TransposeResult>(m_result) + && ! may_update<exterior, interior, '2', TransposeResult>(m_result) ) + { + m_flags |= 1; + } + + if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result) + && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) ) + { + m_flags |= 2; + } + } + + template <typename Areal> + bool operator()(Areal const& areal) + { + // if those flags are set nothing will change + if ( m_flags == 3 ) + { + return false; + } + + typedef typename geometry::point_type<Areal>::type point_type; + point_type pt; + bool const ok = boost::geometry::point_on_border(pt, areal); + + // TODO: for now ignore, later throw an exception? + if ( !ok ) + { + return true; + } + + // check if the areal is inside the other_areal + // TODO: This is O(N) + // Run in a loop O(NM) - optimize! + int const pig = detail::within::point_in_geometry(pt, m_other_areal); + //BOOST_ASSERT( pig != 0 ); + + // inside + if ( pig > 0 ) + { + update<interior, interior, '2', TransposeResult>(m_result); + update<boundary, interior, '1', TransposeResult>(m_result); + update<exterior, interior, '2', TransposeResult>(m_result); + m_flags |= 1; + + // TODO: OPTIMIZE! + // Only the interior rings of other ONE single geometry must be checked + // NOT all geometries + + // Check if any interior ring is outside + ring_identifier ring_id(0, -1, 0); + int const irings_count = boost::numeric_cast<int>( + geometry::num_interior_rings(areal) ); + for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index ) + { + typename detail::sub_range_return_type<Areal const>::type + range_ref = detail::sub_range(areal, ring_id); + + if ( boost::empty(range_ref) ) + { + // TODO: throw exception? + continue; // ignore + } + + // TODO: O(N) + // Optimize! + int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal); + + // hole outside + if ( hpig < 0 ) + { + update<interior, exterior, '2', TransposeResult>(m_result); + update<boundary, exterior, '1', TransposeResult>(m_result); + m_flags |= 2; + break; + } + } + } + // outside + else + { + update<interior, exterior, '2', TransposeResult>(m_result); + update<boundary, exterior, '1', TransposeResult>(m_result); + m_flags |= 2; + + // Check if any interior ring is inside + ring_identifier ring_id(0, -1, 0); + int const irings_count = boost::numeric_cast<int>( + geometry::num_interior_rings(areal) ); + for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index ) + { + typename detail::sub_range_return_type<Areal const>::type + range_ref = detail::sub_range(areal, ring_id); + + if ( boost::empty(range_ref) ) + { + // TODO: throw exception? + continue; // ignore + } + + // TODO: O(N) + // Optimize! + int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal); + + // hole inside + if ( hpig > 0 ) + { + update<interior, interior, '2', TransposeResult>(m_result); + update<boundary, interior, '1', TransposeResult>(m_result); + update<exterior, interior, '2', TransposeResult>(m_result); + m_flags |= 1; + break; + } + } + } + + return m_flags != 3 && !m_result.interrupt; + } + +private: + Result & m_result; + OtherAreal const& m_other_areal; + int m_flags; +}; + +// The implementation of an algorithm calculating relate() for A/A +template <typename Geometry1, typename Geometry2> +struct areal_areal +{ + // check Linear / Areal + BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2 + && topological_dimension<Geometry2>::value == 2); + + static const bool interruption_enabled = true; + + typedef typename geometry::point_type<Geometry1>::type point1_type; + typedef typename geometry::point_type<Geometry2>::type point2_type; + + template <typename Result> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { +// TODO: If Areal geometry may have infinite size, change the following line: + + // The result should be FFFFFFFFF + relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T + + if ( result.interrupt ) + return; + + // get and analyse turns + typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type; + std::vector<turn_type> turns; + + interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result); + + turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy); + if ( result.interrupt ) + return; + + no_turns_aa_pred<Geometry2, Result, false> pred1(geometry2, result); + for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); + if ( result.interrupt ) + return; + + no_turns_aa_pred<Geometry1, Result, true> pred2(geometry1, result); + for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); + if ( result.interrupt ) + return; + + if ( turns.empty() ) + return; + + if ( may_update<interior, interior, '2'>(result) + || may_update<interior, exterior, '2'>(result) + || may_update<boundary, interior, '1'>(result) + || may_update<boundary, exterior, '1'>(result) + || may_update<exterior, interior, '2'>(result) ) + { + // sort turns + typedef turns::less<0, turns::less_op_areal_areal<0> > less; + std::sort(turns.begin(), turns.end(), less()); + + /*if ( may_update<interior, exterior, '2'>(result) + || may_update<boundary, exterior, '1'>(result) + || may_update<boundary, interior, '1'>(result) + || may_update<exterior, interior, '2'>(result) )*/ + { + // analyse sorted turns + turns_analyser<turn_type, 0> analyser; + analyse_each_turn(result, analyser, turns.begin(), turns.end()); + + if ( result.interrupt ) + return; + } + + if ( may_update<interior, interior, '2'>(result) + || may_update<interior, exterior, '2'>(result) + || may_update<boundary, interior, '1'>(result) + || may_update<boundary, exterior, '1'>(result) + || may_update<exterior, interior, '2'>(result) ) + { + // analyse rings for which turns were not generated + // or only i/i or u/u was generated + uncertain_rings_analyser<0, Result, Geometry1, Geometry2> rings_analyser(result, geometry1, geometry2); + analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end()); + + if ( result.interrupt ) + return; + } + } + + if ( may_update<interior, interior, '2', true>(result) + || may_update<interior, exterior, '2', true>(result) + || may_update<boundary, interior, '1', true>(result) + || may_update<boundary, exterior, '1', true>(result) + || may_update<exterior, interior, '2', true>(result) ) + { + // sort turns + typedef turns::less<1, turns::less_op_areal_areal<1> > less; + std::sort(turns.begin(), turns.end(), less()); + + /*if ( may_update<interior, exterior, '2', true>(result) + || may_update<boundary, exterior, '1', true>(result) + || may_update<boundary, interior, '1', true>(result) + || may_update<exterior, interior, '2', true>(result) )*/ + { + // analyse sorted turns + turns_analyser<turn_type, 1> analyser; + analyse_each_turn(result, analyser, turns.begin(), turns.end()); + + if ( result.interrupt ) + return; + } + + if ( may_update<interior, interior, '2', true>(result) + || may_update<interior, exterior, '2', true>(result) + || may_update<boundary, interior, '1', true>(result) + || may_update<boundary, exterior, '1', true>(result) + || may_update<exterior, interior, '2', true>(result) ) + { + // analyse rings for which turns were not generated + // or only i/i or u/u was generated + uncertain_rings_analyser<1, Result, Geometry2, Geometry1> rings_analyser(result, geometry2, geometry1); + analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end()); + + //if ( result.interrupt ) + // return; + } + } + } + + // interrupt policy which may be passed to get_turns to interrupt the analysis + // based on the info in the passed result/mask + template <typename Result> + class interrupt_policy_areal_areal + { + public: + static bool const enabled = true; + + interrupt_policy_areal_areal(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Result & result) + : m_result(result) + , m_geometry1(geometry1) + , m_geometry2(geometry2) + {} + + template <typename Range> + inline bool apply(Range const& turns) + { + typedef typename boost::range_iterator<Range const>::type iterator; + + for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + { + per_turn<0>(*it); + per_turn<1>(*it); + } + + return m_result.interrupt; + } + + private: + template <std::size_t OpId, typename Turn> + inline void per_turn(Turn const& turn) + { + static const std::size_t other_op_id = (OpId + 1) % 2; + static const bool transpose_result = OpId != 0; + + overlay::operation_type const op = turn.operations[OpId].operation; + + if ( op == overlay::operation_union ) + { + // ignore u/u + /*if ( turn.operations[other_op_id].operation != overlay::operation_union ) + { + update<interior, exterior, '2', transpose_result>(m_result); + update<boundary, exterior, '1', transpose_result>(m_result); + }*/ + + update<boundary, boundary, '0', transpose_result>(m_result); + } + else if ( op == overlay::operation_intersection ) + { + // ignore i/i + if ( turn.operations[other_op_id].operation != overlay::operation_intersection ) + { + update<interior, interior, '2', transpose_result>(m_result); + //update<boundary, interior, '1', transpose_result>(m_result); + } + + update<boundary, boundary, '0', transpose_result>(m_result); + } + else if ( op == overlay::operation_continue ) + { + update<boundary, boundary, '1', transpose_result>(m_result); + update<interior, interior, '2', transpose_result>(m_result); + } + else if ( op == overlay::operation_blocked ) + { + update<boundary, boundary, '1', transpose_result>(m_result); + update<interior, exterior, '2', transpose_result>(m_result); + } + } + + Result & m_result; + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + }; + + // This analyser should be used like Input or SinglePass Iterator + // IMPORTANT! It should be called also for the end iterator - last + template <typename TurnInfo, std::size_t OpId> + class turns_analyser + { + typedef typename TurnInfo::point_type turn_point_type; + + static const std::size_t op_id = OpId; + static const std::size_t other_op_id = (OpId + 1) % 2; + static const bool transpose_result = OpId != 0; + + public: + turns_analyser() + : m_previous_turn_ptr(0) + , m_previous_operation(overlay::operation_none) + , m_enter_detected(false) + , m_exit_detected(false) + {} + + template <typename Result, + typename TurnIt> + void apply(Result & result, TurnIt it) + { + //BOOST_ASSERT( it != last ); + + overlay::operation_type const op = it->operations[op_id].operation; + + if ( op != overlay::operation_union + && op != overlay::operation_intersection + && op != overlay::operation_blocked + && op != overlay::operation_continue ) + { + return; + } + + segment_identifier const& seg_id = it->operations[op_id].seg_id; + //segment_identifier const& other_id = it->operations[other_op_id].seg_id; + + const bool first_in_range = m_seg_watcher.update(seg_id); + + if ( m_previous_turn_ptr ) + { + if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ ) + { + // real exit point - may be multiple + if ( first_in_range + || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + { + update_exit(result); + m_exit_detected = false; + } + // fake exit point, reset state + else if ( op != overlay::operation_union ) + { + m_exit_detected = false; + } + } + /*else*/ + if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ ) + { + // real entry point + if ( first_in_range + || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + { + update_enter(result); + m_enter_detected = false; + } + // fake entry point, reset state + else if ( op != overlay::operation_intersection ) + { + m_enter_detected = false; + } + } + } + + if ( op == overlay::operation_union ) + { + // already set in interrupt policy + //update<boundary, boundary, '0', transpose_result>(m_result); + + // ignore u/u + //if ( it->operations[other_op_id].operation != overlay::operation_union ) + { + m_exit_detected = true; + } + } + else if ( op == overlay::operation_intersection ) + { + // ignore i/i + if ( it->operations[other_op_id].operation != overlay::operation_intersection ) + { + // already set in interrupt policy + //update<interior, interior, '2', transpose_result>(result); + //update<boundary, boundary, '0', transpose_result>(result); + m_enter_detected = true; + } + } + else if ( op == overlay::operation_blocked ) + { + // already set in interrupt policy + } + else // if ( op == overlay::operation_continue ) + { + // already set in interrupt policy + } + + // store ref to previously analysed (valid) turn + m_previous_turn_ptr = boost::addressof(*it); + // and previously analysed (valid) operation + m_previous_operation = op; + } + + // it == last + template <typename Result> + void apply(Result & result) + { + //BOOST_ASSERT( first != last ); + + if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ ) + { + update_exit(result); + m_exit_detected = false; + } + + if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ ) + { + update_enter(result); + m_enter_detected = false; + } + } + + template <typename Result> + static inline void update_exit(Result & result) + { + update<interior, exterior, '2', transpose_result>(result); + update<boundary, exterior, '1', transpose_result>(result); + } + + template <typename Result> + static inline void update_enter(Result & result) + { + update<boundary, interior, '1', transpose_result>(result); + update<exterior, interior, '2', transpose_result>(result); + } + + private: + segment_watcher<same_ring> m_seg_watcher; + TurnInfo * m_previous_turn_ptr; + overlay::operation_type m_previous_operation; + bool m_enter_detected; + bool m_exit_detected; + }; + + // call analyser.apply() for each turn in range + // IMPORTANT! The analyser is also called for the end iterator - last + template <typename Result, + typename Analyser, + typename TurnIt> + static inline void analyse_each_turn(Result & res, + Analyser & analyser, + TurnIt first, TurnIt last) + { + if ( first == last ) + return; + + for ( TurnIt it = first ; it != last ; ++it ) + { + analyser.apply(res, it); + + if ( res.interrupt ) + return; + } + + analyser.apply(res); + } + + template <std::size_t OpId, typename Result, typename Geometry, typename OtherGeometry> + class uncertain_rings_analyser + { + static const bool transpose_result = OpId != 0; + static const int other_id = (OpId + 1) % 2; + + public: + inline uncertain_rings_analyser(Result & result, + Geometry const& geom, + OtherGeometry const& other_geom) + : geometry(geom), other_geometry(other_geom) + , interrupt(result.interrupt) // just in case, could be false as well + , m_result(result) + , m_flags(0) + { + // check which relations must be analysed + + if ( ! may_update<interior, interior, '2', transpose_result>(m_result) + && ! may_update<boundary, interior, '1', transpose_result>(m_result) ) + { + m_flags |= 1; + } + + if ( ! may_update<interior, exterior, '2', transpose_result>(m_result) + && ! may_update<boundary, exterior, '1', transpose_result>(m_result) ) + { + m_flags |= 2; + } + + if ( ! may_update<boundary, interior, '1', transpose_result>(m_result) + && ! may_update<exterior, interior, '2', transpose_result>(m_result) ) + { + m_flags |= 4; + } + } + + inline void no_turns(segment_identifier const& seg_id) + { + // if those flags are set nothing will change + if ( (m_flags & 3) == 3 ) + { + return; + } + + typename detail::sub_range_return_type<Geometry const>::type + range_ref = detail::sub_range(geometry, seg_id); + + if ( boost::empty(range_ref) ) + { + // TODO: throw an exception? + return; // ignore + } + + // TODO: possible optimization + // if the range is an interior ring we may use other IPs generated for this single geometry + // to know which other single geometries should be checked + + // TODO: optimize! e.g. use spatial index + // O(N) - running it in a loop would gives O(NM) + int const pig = detail::within::point_in_geometry(range::front(range_ref), other_geometry); + + //BOOST_ASSERT(pig != 0); + if ( pig > 0 ) + { + update<boundary, interior, '1', transpose_result>(m_result); + update<interior, interior, '2', transpose_result>(m_result); + m_flags |= 1; + } + else + { + update<boundary, exterior, '1', transpose_result>(m_result); + update<interior, exterior, '2', transpose_result>(m_result); + m_flags |= 2; + } + +// TODO: break if all things are set +// also some of them could be checked outside, before the analysis +// In this case we shouldn't relay just on dummy flags +// Flags should be initialized with proper values +// or the result should be checked directly +// THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A + + interrupt = m_flags == 7 || m_result.interrupt; + } + + template <typename TurnIt> + inline void turns(TurnIt first, TurnIt last) + { + // if those flags are set nothing will change + if ( (m_flags & 6) == 6 ) + { + return; + } + + bool found_ii = false; + bool found_uu = false; + + for ( TurnIt it = first ; it != last ; ++it ) + { + if ( it->operations[0].operation == overlay::operation_intersection + && it->operations[1].operation == overlay::operation_intersection ) + { + // ignore exterior ring + if ( it->operations[OpId].seg_id.ring_index >= 0 ) + { + found_ii = true; + } + } + else if ( it->operations[0].operation == overlay::operation_union + && it->operations[1].operation == overlay::operation_union ) + { + // ignore if u/u is for holes + //if ( it->operations[OpId].seg_id.ring_index >= 0 + // && it->operations[other_id].seg_id.ring_index >= 0 ) + { + found_uu = true; + } + } + else // ignore + { + return; // don't interrupt + } + } + + // only i/i was generated for this ring + if ( found_ii ) + { + //update<interior, interior, '0', transpose_result>(m_result); + //update<boundary, boundary, '0', transpose_result>(m_result); + update<boundary, interior, '1', transpose_result>(m_result); + update<exterior, interior, '2', transpose_result>(m_result); + m_flags |= 4; + } + + // only u/u was generated for this ring + if ( found_uu ) + { + update<boundary, exterior, '1', transpose_result>(m_result); + update<interior, exterior, '2', transpose_result>(m_result); + m_flags |= 2; + + // not necessary since this will be checked in the next iteration + // but increases the pruning strength + // WARNING: this is not reflected in flags + update<exterior, boundary, '1', transpose_result>(m_result); + update<exterior, interior, '2', transpose_result>(m_result); + } + + interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future + } + + Geometry const& geometry; + OtherGeometry const& other_geometry; + bool interrupt; + + private: + Result & m_result; + int m_flags; + }; + + template <std::size_t OpId> + class analyse_uncertain_rings + { + public: + template <typename Analyser, typename TurnIt> + static inline void apply(Analyser & analyser, TurnIt first, TurnIt last) + { + if ( first == last ) + return; + + for_preceding_rings(analyser, *first); + //analyser.per_turn(*first); + + TurnIt prev = first; + for ( ++first ; first != last ; ++first, ++prev ) + { + // same multi + if ( prev->operations[OpId].seg_id.multi_index + == first->operations[OpId].seg_id.multi_index ) + { + // same ring + if ( prev->operations[OpId].seg_id.ring_index + == first->operations[OpId].seg_id.ring_index ) + { + //analyser.per_turn(*first); + } + // same multi, next ring + else + { + //analyser.end_ring(*prev); + analyser.turns(prev, first); + + //if ( prev->operations[OpId].seg_id.ring_index + 1 + // < first->operations[OpId].seg_id.ring_index) + { + for_no_turns_rings(analyser, + *first, + prev->operations[OpId].seg_id.ring_index + 1, + first->operations[OpId].seg_id.ring_index); + } + + //analyser.per_turn(*first); + } + } + // next multi + else + { + //analyser.end_ring(*prev); + analyser.turns(prev, first); + for_following_rings(analyser, *prev); + for_preceding_rings(analyser, *first); + //analyser.per_turn(*first); + } + + if ( analyser.interrupt ) + { + return; + } + } + + //analyser.end_ring(*prev); + analyser.turns(prev, first); // first == last + for_following_rings(analyser, *prev); + } + + private: + template <typename Analyser, typename Turn> + static inline void for_preceding_rings(Analyser & analyser, Turn const& turn) + { + segment_identifier const& seg_id = turn.operations[OpId].seg_id; + + for_no_turns_rings(analyser, turn, -1, seg_id.ring_index); + } + + template <typename Analyser, typename Turn> + static inline void for_following_rings(Analyser & analyser, Turn const& turn) + { + segment_identifier const& seg_id = turn.operations[OpId].seg_id; + + int count = boost::numeric_cast<int>( + geometry::num_interior_rings( + detail::single_geometry(analyser.geometry, seg_id))); + + for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count); + } + + template <typename Analyser, typename Turn> + static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, int first, int last) + { + segment_identifier seg_id = turn.operations[OpId].seg_id; + + for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index ) + { + analyser.no_turns(seg_id); + } + } + }; +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp new file mode 100644 index 0000000000..f98c3e9b82 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp @@ -0,0 +1,134 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP + +#include <boost/geometry/util/range.hpp> +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/algorithms/detail/sub_range.hpp> + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +enum boundary_query { boundary_front, boundary_back, boundary_any }; + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type> +class boundary_checker {}; + +template <typename Geometry> +class boundary_checker<Geometry, linestring_tag> +{ + typedef typename point_type<Geometry>::type point_type; + +public: + boundary_checker(Geometry const& g) + : has_boundary( boost::size(g) >= 2 + && !detail::equals::equals_point_point(range::front(g), range::back(g)) ) + , geometry(g) + {} + + template <boundary_query BoundaryQuery> + bool is_endpoint_boundary(point_type const& pt) const + { + boost::ignore_unused_variable_warning(pt); +#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER + // may give false positives for INT + BOOST_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) + && detail::equals::equals_point_point(pt, range::front(geometry)) + || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) + && detail::equals::equals_point_point(pt, range::back(geometry)) ); +#endif + return has_boundary; + } + +private: + bool has_boundary; + Geometry const& geometry; +}; + +template <typename Geometry> +class boundary_checker<Geometry, multi_linestring_tag> +{ + typedef typename point_type<Geometry>::type point_type; + +public: + boundary_checker(Geometry const& g) + : is_filled(false), geometry(g) + {} + + // First call O(NlogN) + // Each next call O(logN) + template <boundary_query BoundaryQuery> + bool is_endpoint_boundary(point_type const& pt) const + { + typedef typename boost::range_size<Geometry>::type size_type; + size_type multi_count = boost::size(geometry); + + if ( multi_count < 1 ) + return false; + + if ( ! is_filled ) + { + //boundary_points.clear(); + boundary_points.reserve(multi_count * 2); + + typedef typename boost::range_iterator<Geometry const>::type multi_iterator; + for ( multi_iterator it = boost::begin(geometry) ; + it != boost::end(geometry) ; ++ it ) + { + // empty or point - no boundary + if ( boost::size(*it) < 2 ) + continue; + + // linear ring or point - no boundary + if ( equals::equals_point_point(range::front(*it), range::back(*it)) ) + continue; + + boundary_points.push_back(range::front(*it)); + boundary_points.push_back(range::back(*it)); + } + + std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>()); + + is_filled = true; + } + + std::size_t equal_points_count + = boost::size( + std::equal_range(boundary_points.begin(), + boundary_points.end(), + pt, + geometry::less<point_type>()) + ); + + return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0 + } + +private: + mutable bool is_filled; + // TODO: store references/pointers instead of points? + mutable std::vector<point_type> boundary_points; + + Geometry const& geometry; +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp new file mode 100644 index 0000000000..78fa03798d --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp @@ -0,0 +1,401 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP + +#include <boost/geometry/util/range.hpp> +//#include <boost/geometry/algorithms/detail/sub_range.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// NOTE: This iterates through single geometries for which turns were not generated. +// It doesn't mean that the geometry is disjoint, only that no turns were detected. + +template <std::size_t OpId, + typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type, + bool IsMulti = boost::is_base_of<multi_tag, Tag>::value +> +struct for_each_disjoint_geometry_if + : public not_implemented<Tag> +{}; + +template <std::size_t OpId, typename Geometry, typename Tag> +struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false> +{ + template <typename TurnIt, typename Pred> + static inline bool apply(TurnIt first, TurnIt last, + Geometry const& geometry, + Pred & pred) + { + if ( first != last ) + return false; + pred(geometry); + return true; + } +}; + +template <std::size_t OpId, typename Geometry, typename Tag> +struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> +{ + template <typename TurnIt, typename Pred> + static inline bool apply(TurnIt first, TurnIt last, + Geometry const& geometry, + Pred & pred) + { + if ( first != last ) + return for_turns(first, last, geometry, pred); + else + return for_empty(geometry, pred); + } + + template <typename Pred> + static inline bool for_empty(Geometry const& geometry, + Pred & pred) + { + typedef typename boost::range_iterator<Geometry const>::type iterator; + + // O(N) + // check predicate for each contained geometry without generated turn + for ( iterator it = boost::begin(geometry) ; + it != boost::end(geometry) ; ++it ) + { + bool cont = pred(*it); + if ( !cont ) + break; + } + + return !boost::empty(geometry); + } + + template <typename TurnIt, typename Pred> + static inline bool for_turns(TurnIt first, TurnIt last, + Geometry const& geometry, + Pred & pred) + { + BOOST_ASSERT(first != last); + + const std::size_t count = boost::size(geometry); + boost::ignore_unused_variable_warning(count); + + // O(I) + // gather info about turns generated for contained geometries + std::vector<bool> detected_intersections(count, false); + for ( TurnIt it = first ; it != last ; ++it ) + { + int multi_index = it->operations[OpId].seg_id.multi_index; + BOOST_ASSERT(multi_index >= 0); + std::size_t index = static_cast<std::size_t>(multi_index); + BOOST_ASSERT(index < count); + detected_intersections[index] = true; + } + + bool found = false; + + // O(N) + // check predicate for each contained geometry without generated turn + for ( std::vector<bool>::iterator it = detected_intersections.begin() ; + it != detected_intersections.end() ; ++it ) + { + // if there were no intersections for this multi_index + if ( *it == false ) + { + found = true; + bool cont = pred(range::at(geometry, + std::distance(detected_intersections.begin(), it))); + if ( !cont ) + break; + } + } + + return found; + } +}; + +// WARNING! This class stores pointers! +// Passing a reference to local variable will result in undefined behavior! +template <typename Point> +class point_info +{ +public: + point_info() : sid_ptr(NULL), pt_ptr(NULL) {} + point_info(Point const& pt, segment_identifier const& sid) + : sid_ptr(boost::addressof(sid)) + , pt_ptr(boost::addressof(pt)) + {} + segment_identifier const& seg_id() const + { + BOOST_ASSERT(sid_ptr); + return *sid_ptr; + } + Point const& point() const + { + BOOST_ASSERT(pt_ptr); + return *pt_ptr; + } + + //friend bool operator==(point_identifier const& l, point_identifier const& r) + //{ + // return l.seg_id() == r.seg_id() + // && detail::equals::equals_point_point(l.point(), r.point()); + //} + +private: + const segment_identifier * sid_ptr; + const Point * pt_ptr; +}; + +// WARNING! This class stores pointers! +// Passing a reference to local variable will result in undefined behavior! +class same_single +{ +public: + same_single(segment_identifier const& sid) + : sid_ptr(boost::addressof(sid)) + {} + + bool operator()(segment_identifier const& sid) const + { + return sid.multi_index == sid_ptr->multi_index; + } + + template <typename Point> + bool operator()(point_info<Point> const& pid) const + { + return operator()(pid.seg_id()); + } + +private: + const segment_identifier * sid_ptr; +}; + +class same_ring +{ +public: + same_ring(segment_identifier const& sid) + : sid_ptr(boost::addressof(sid)) + {} + + bool operator()(segment_identifier const& sid) const + { + return sid.multi_index == sid_ptr->multi_index + && sid.ring_index == sid_ptr->ring_index; + } + +private: + const segment_identifier * sid_ptr; +}; + +// WARNING! This class stores pointers! +// Passing a reference to local variable will result in undefined behavior! +template <typename SameRange = same_single> +class segment_watcher +{ +public: + segment_watcher() + : m_seg_id_ptr(NULL) + {} + + bool update(segment_identifier const& seg_id) + { + bool result = m_seg_id_ptr == 0 || !SameRange(*m_seg_id_ptr)(seg_id); + m_seg_id_ptr = boost::addressof(seg_id); + return result; + } + +private: + const segment_identifier * m_seg_id_ptr; +}; + +// WARNING! This class stores pointers! +// Passing a reference to local variable will result in undefined behavior! +template <typename TurnInfo, std::size_t OpId> +class exit_watcher +{ + static const std::size_t op_id = OpId; + static const std::size_t other_op_id = (OpId + 1) % 2; + + typedef typename TurnInfo::point_type point_type; + typedef detail::relate::point_info<point_type> point_info; + +public: + exit_watcher() + : m_exit_operation(overlay::operation_none) + , m_exit_turn_ptr(NULL) + {} + + void enter(TurnInfo const& turn) + { + m_other_entry_points.push_back( + point_info(turn.point, turn.operations[other_op_id].seg_id) ); + } + + // TODO: exit_per_geometry parameter looks not very safe + // wrong value may be easily passed + + void exit(TurnInfo const& turn, bool exit_per_geometry = true) + { + //segment_identifier const& seg_id = turn.operations[op_id].seg_id; + segment_identifier const& other_id = turn.operations[other_op_id].seg_id; + overlay::operation_type exit_op = turn.operations[op_id].operation; + + typedef typename std::vector<point_info>::iterator point_iterator; + // search for the entry point in the same range of other geometry + point_iterator entry_it = std::find_if(m_other_entry_points.begin(), + m_other_entry_points.end(), + same_single(other_id)); + + // this end point has corresponding entry point + if ( entry_it != m_other_entry_points.end() ) + { + // erase the corresponding entry point + m_other_entry_points.erase(entry_it); + + if ( exit_per_geometry || m_other_entry_points.empty() ) + { + // here we know that we possibly left LS + // we must still check if we didn't get back on the same point + m_exit_operation = exit_op; + m_exit_turn_ptr = boost::addressof(turn); + } + } + } + + bool is_outside() const + { + // if we didn't entered anything in the past, we're outside + return m_other_entry_points.empty(); + } + + bool is_outside(TurnInfo const& turn) const + { + return m_other_entry_points.empty() + || std::find_if(m_other_entry_points.begin(), + m_other_entry_points.end(), + same_single( + turn.operations[other_op_id].seg_id)) + == m_other_entry_points.end(); + } + + overlay::operation_type get_exit_operation() const + { + return m_exit_operation; + } + + point_type const& get_exit_point() const + { + BOOST_ASSERT(m_exit_operation != overlay::operation_none); + BOOST_ASSERT(m_exit_turn_ptr); + return m_exit_turn_ptr->point; + } + + TurnInfo const& get_exit_turn() const + { + BOOST_ASSERT(m_exit_operation != overlay::operation_none); + BOOST_ASSERT(m_exit_turn_ptr); + return *m_exit_turn_ptr; + } + + void reset_detected_exit() + { + m_exit_operation = overlay::operation_none; + } + + void reset() + { + m_exit_operation = overlay::operation_none; + m_other_entry_points.clear(); + } + +private: + overlay::operation_type m_exit_operation; + const TurnInfo * m_exit_turn_ptr; + std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector? +}; + +template <std::size_t OpId, typename Turn> +inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn) +{ + segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id; + segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id; + + if ( prev_seg_id.multi_index != curr_seg_id.multi_index + || prev_seg_id.ring_index != curr_seg_id.ring_index ) + { + return false; + } + + // TODO: will this work if between segments there will be some number of degenerated ones? + + if ( prev_seg_id.segment_index != curr_seg_id.segment_index + && ( ! curr_turn.operations[OpId].fraction.is_zero() + || prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) ) + { + return false; + } + + return detail::equals::equals_point_point(prev_turn.point, curr_turn.point); +} + +template <boundary_query BoundaryQuery, + typename Point, + typename BoundaryChecker> +static inline bool is_endpoint_on_boundary(Point const& pt, + BoundaryChecker & boundary_checker) +{ + return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt); +} + +template <boundary_query BoundaryQuery, + typename IntersectionPoint, + typename OperationInfo, + typename BoundaryChecker> +static inline bool is_ip_on_boundary(IntersectionPoint const& ip, + OperationInfo const& operation_info, + BoundaryChecker & boundary_checker, + segment_identifier const& seg_id) +{ + boost::ignore_unused_variable_warning(seg_id); + + bool res = false; + + // IP on the last point of the linestring + if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) + && operation_info.position == overlay::position_back ) + { + // check if this point is a boundary + res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip); + } + // IP on the last point of the linestring + else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) + && operation_info.position == overlay::position_front ) + { + // check if this point is a boundary + res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip); + } + + return res; +} + + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP diff --git a/boost/geometry/algorithms/detail/relate/less.hpp b/boost/geometry/algorithms/detail/relate/less.hpp new file mode 100644 index 0000000000..3f11d4e87d --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/less.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { namespace relate { + +// TODO: Integrate it with geometry::less? + +template <typename Point1, + typename Point2, + std::size_t I = 0, + std::size_t D = geometry::dimension<Point1>::value> +struct less +{ + static inline bool apply(Point1 const& left, Point2 const& right) + { + typename geometry::coordinate_type<Point1>::type + cleft = geometry::get<I>(left); + typename geometry::coordinate_type<Point2>::type + cright = geometry::get<I>(right); + + if ( geometry::math::equals(cleft, cright) ) + { + return less<Point1, Point2, I + 1, D>::apply(left, right); + } + else + { + return cleft < cright; + } + } +}; + +template <typename Point1, typename Point2, std::size_t D> +struct less<Point1, Point2, D, D> +{ + static inline bool apply(Point1 const&, Point2 const&) + { + return false; + } +}; + +}} // namespace detail_dispatch::relate + +#endif + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +struct less +{ + template <typename Point1, typename Point2> + inline bool operator()(Point1 const& point1, Point2 const& point2) const + { + return detail_dispatch::relate::less<Point1, Point2>::apply(point1, point2); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp new file mode 100644 index 0000000000..3159ab329d --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -0,0 +1,1115 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP + +#include <boost/core/ignore_unused.hpp> + +#include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/algorithms/detail/single_geometry.hpp> + +#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/turns.hpp> +#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> +#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> + +#include <boost/geometry/views/detail/normalized_view.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// WARNING! +// TODO: In the worst case calling this Pred in a loop for MultiLinestring/MultiPolygon may take O(NM) +// Use the rtree in this case! + +// may be used to set IE and BE for a Linear geometry for which no turns were generated +template <typename Geometry2, typename Result, typename BoundaryChecker, bool TransposeResult> +class no_turns_la_linestring_pred +{ +public: + no_turns_la_linestring_pred(Geometry2 const& geometry2, + Result & res, + BoundaryChecker const& boundary_checker) + : m_geometry2(geometry2) + , m_result(res) + , m_boundary_checker(boundary_checker) + , m_interrupt_flags(0) + { + if ( ! may_update<interior, interior, '1', TransposeResult>(m_result) ) + { + m_interrupt_flags |= 1; + } + + if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) ) + { + m_interrupt_flags |= 2; + } + + if ( ! may_update<boundary, interior, '0', TransposeResult>(m_result) ) + { + m_interrupt_flags |= 4; + } + + if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) ) + { + m_interrupt_flags |= 8; + } + } + + template <typename Linestring> + bool operator()(Linestring const& linestring) + { + std::size_t const count = boost::size(linestring); + + // invalid input + if ( count < 2 ) + { + // ignore + // TODO: throw an exception? + return true; + } + + // if those flags are set nothing will change + if ( m_interrupt_flags == 0xF ) + { + return false; + } + + int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2); + //BOOST_ASSERT_MSG(pig != 0, "There should be no IPs"); + + if ( pig > 0 ) + { + update<interior, interior, '1', TransposeResult>(m_result); + m_interrupt_flags |= 1; + } + else + { + update<interior, exterior, '1', TransposeResult>(m_result); + m_interrupt_flags |= 2; + } + + // check if there is a boundary + if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set + && ( m_boundary_checker.template + is_endpoint_boundary<boundary_front>(range::front(linestring)) + || m_boundary_checker.template + is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) + { + if ( pig > 0 ) + { + update<boundary, interior, '0', TransposeResult>(m_result); + m_interrupt_flags |= 4; + } + else + { + update<boundary, exterior, '0', TransposeResult>(m_result); + m_interrupt_flags |= 8; + } + } + + return m_interrupt_flags != 0xF + && ! m_result.interrupt; + } + +private: + Geometry2 const& m_geometry2; + Result & m_result; + BoundaryChecker const& m_boundary_checker; + unsigned m_interrupt_flags; +}; + +// may be used to set EI and EB for an Areal geometry for which no turns were generated +template <typename Result, bool TransposeResult> +class no_turns_la_areal_pred +{ +public: + no_turns_la_areal_pred(Result & res) + : m_result(res) + , interrupt(! may_update<interior, exterior, '2', TransposeResult>(m_result) + && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) ) + {} + + template <typename Areal> + bool operator()(Areal const& areal) + { + if ( interrupt ) + { + return false; + } + + // TODO: + // handle empty/invalid geometries in a different way than below? + + typedef typename geometry::point_type<Areal>::type point_type; + point_type dummy; + bool const ok = boost::geometry::point_on_border(dummy, areal); + + // TODO: for now ignore, later throw an exception? + if ( !ok ) + { + return true; + } + + update<interior, exterior, '2', TransposeResult>(m_result); + update<boundary, exterior, '1', TransposeResult>(m_result); + + return false; + } + +private: + Result & m_result; + bool const interrupt; +}; + +// The implementation of an algorithm calculating relate() for L/A +template <typename Geometry1, typename Geometry2, bool TransposeResult = false> +struct linear_areal +{ + // check Linear / Areal + BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1 + && topological_dimension<Geometry2>::value == 2); + + static const bool interruption_enabled = true; + + typedef typename geometry::point_type<Geometry1>::type point1_type; + typedef typename geometry::point_type<Geometry2>::type point2_type; + + template <typename Result> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { +// TODO: If Areal geometry may have infinite size, change the following line: + + // The result should be FFFFFFFFF + relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T + + if ( result.interrupt ) + return; + + // get and analyse turns + typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type; + std::vector<turn_type> turns; + + interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result); + + turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy); + if ( result.interrupt ) + return; + + boundary_checker<Geometry1> boundary_checker1(geometry1); + no_turns_la_linestring_pred + < + Geometry2, + Result, + boundary_checker<Geometry1>, + TransposeResult + > pred1(geometry2, result, boundary_checker1); + for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); + if ( result.interrupt ) + return; + + no_turns_la_areal_pred<Result, !TransposeResult> pred2(result); + for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); + if ( result.interrupt ) + return; + + if ( turns.empty() ) + return; + + // This is set here because in the case if empty Areal geometry were passed + // those shouldn't be set + relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd + if ( result.interrupt ) + return; + + { + // for different multi or same ring id: x, u, i, c + // for same multi and different ring id: c, i, u, x + typedef turns::less<0, turns::less_op_linear_areal<0> > less; + std::sort(turns.begin(), turns.end(), less()); + + turns_analyser<turn_type> analyser; + analyse_each_turn(result, analyser, + turns.begin(), turns.end(), + geometry1, geometry2, + boundary_checker1); + + if ( result.interrupt ) + return; + } + + // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings + if ( !interrupt_policy.is_boundary_found ) + { + relate::set<exterior, boundary, '1', TransposeResult>(result); + } + // Don't calculate it if it's required + else if ( may_update<exterior, boundary, '1', TransposeResult>(result) ) + { +// TODO: REVISE THIS CODE AND PROBABLY REWRITE SOME PARTS TO BE MORE HUMAN-READABLE +// IN GENERAL IT ANALYSES THE RINGS OF AREAL GEOMETRY AND DETECTS THE ONES THAT +// MAY OVERLAP THE INTERIOR OF LINEAR GEOMETRY (NO IPs OR NON-FAKE 'u' OPERATION) +// NOTE: For one case std::sort may be called again to sort data by operations for data already sorted by ring index +// In the worst case scenario the complexity will be O( NlogN + R*(N/R)log(N/R) ) +// So always should remain O(NlogN) -> for R==1 <-> 1(N/1)log(N/1), for R==N <-> N(N/N)log(N/N) +// Some benchmarking should probably be done to check if only one std::sort should be used + + // sort by multi_index and rind_index + std::sort(turns.begin(), turns.end(), less_ring()); + + typedef typename std::vector<turn_type>::iterator turn_iterator; + + turn_iterator it = turns.begin(); + segment_identifier * prev_seg_id_ptr = NULL; + // for each ring + for ( ; it != turns.end() ; ) + { + // it's the next single geometry + if ( prev_seg_id_ptr == NULL + || prev_seg_id_ptr->multi_index != it->operations[1].seg_id.multi_index ) + { + // if the first ring has no IPs + if ( it->operations[1].seg_id.ring_index > -1 ) + { + // we can be sure that the exterior overlaps the boundary + relate::set<exterior, boundary, '1', TransposeResult>(result); + break; + } + // if there was some previous ring + if ( prev_seg_id_ptr != NULL ) + { + int const next_ring_index = prev_seg_id_ptr->ring_index + 1; + BOOST_ASSERT(next_ring_index >= 0); + + // if one of the last rings of previous single geometry was ommited + if ( static_cast<std::size_t>(next_ring_index) + < geometry::num_interior_rings( + single_geometry(geometry2, *prev_seg_id_ptr)) ) + { + // we can be sure that the exterior overlaps the boundary + relate::set<exterior, boundary, '1', TransposeResult>(result); + break; + } + } + } + // if it's the same single geometry + else /*if ( previous_multi_index == it->operations[1].seg_id.multi_index )*/ + { + // and we jumped over one of the rings + if ( prev_seg_id_ptr != NULL // just in case + && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index ) + { + // we can be sure that the exterior overlaps the boundary + relate::set<exterior, boundary, '1', TransposeResult>(result); + break; + } + } + + prev_seg_id_ptr = boost::addressof(it->operations[1].seg_id); + + // find the next ring first iterator and check if the analysis should be performed + has_boundary_intersection has_boundary_inters; + turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters); + + // if there is no 1d overlap with the boundary + if ( !has_boundary_inters.result ) + { + // we can be sure that the exterior overlaps the boundary + relate::set<exterior, boundary, '1', TransposeResult>(result); + break; + } + // else there is 1d overlap with the boundary so we must analyse the boundary + else + { + // u, c + typedef turns::less<1, turns::less_op_areal_linear<1> > less; + std::sort(it, next, less()); + + // analyse + areal_boundary_analyser<turn_type> analyser; + for ( turn_iterator rit = it ; rit != next ; ++rit ) + { + // if the analyser requests, break the search + if ( !analyser.apply(it, rit, next) ) + break; + } + + // if the boundary of Areal goes out of the Linear + if ( analyser.is_union_detected ) + { + // we can be sure that the boundary of Areal overlaps the exterior of Linear + relate::set<exterior, boundary, '1', TransposeResult>(result); + break; + } + } + + it = next; + } + + // if there was some previous ring + if ( prev_seg_id_ptr != NULL ) + { + int const next_ring_index = prev_seg_id_ptr->ring_index + 1; + BOOST_ASSERT(next_ring_index >= 0); + + // if one of the last rings of previous single geometry was ommited + if ( static_cast<std::size_t>(next_ring_index) + < geometry::num_interior_rings( + single_geometry(geometry2, *prev_seg_id_ptr)) ) + { + // we can be sure that the exterior overlaps the boundary + relate::set<exterior, boundary, '1', TransposeResult>(result); + } + } + } + } + + // interrupt policy which may be passed to get_turns to interrupt the analysis + // based on the info in the passed result/mask + template <typename Areal, typename Result> + class interrupt_policy_linear_areal + { + public: + static bool const enabled = true; + + interrupt_policy_linear_areal(Areal const& areal, Result & result) + : m_result(result), m_areal(areal) + , is_boundary_found(false) + {} + +// TODO: since we update result for some operations here, we may not do it in the analyser! + + template <typename Range> + inline bool apply(Range const& turns) + { + typedef typename boost::range_iterator<Range const>::type iterator; + + for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + { + if ( it->operations[0].operation == overlay::operation_intersection ) + { + bool const no_interior_rings + = geometry::num_interior_rings( + single_geometry(m_areal, it->operations[1].seg_id)) == 0; + + // WARNING! THIS IS TRUE ONLY IF THE POLYGON IS SIMPLE! + // OR WITHOUT INTERIOR RINGS (AND OF COURSE VALID) + if ( no_interior_rings ) + update<interior, interior, '1', TransposeResult>(m_result); + } + else if ( it->operations[0].operation == overlay::operation_continue ) + { + update<interior, boundary, '1', TransposeResult>(m_result); + is_boundary_found = true; + } + else if ( ( it->operations[0].operation == overlay::operation_union + || it->operations[0].operation == overlay::operation_blocked ) + && it->operations[0].position == overlay::position_middle ) + { +// TODO: here we could also check the boundaries and set BB at this point + update<interior, boundary, '0', TransposeResult>(m_result); + } + } + + return m_result.interrupt; + } + + private: + Result & m_result; + Areal const& m_areal; + + public: + bool is_boundary_found; + }; + + // This analyser should be used like Input or SinglePass Iterator + // IMPORTANT! It should be called also for the end iterator - last + template <typename TurnInfo> + class turns_analyser + { + typedef typename TurnInfo::point_type turn_point_type; + + static const std::size_t op_id = 0; + static const std::size_t other_op_id = 1; + + public: + turns_analyser() + : m_previous_turn_ptr(NULL) + , m_previous_operation(overlay::operation_none) + , m_boundary_counter(0) + , m_interior_detected(false) + , m_first_interior_other_id_ptr(NULL) + {} + + template <typename Result, + typename TurnIt, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker> + void apply(Result & res, TurnIt it, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker) + { + overlay::operation_type op = it->operations[op_id].operation; + + if ( op != overlay::operation_union + && op != overlay::operation_intersection + && op != overlay::operation_blocked + && op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection + { + return; + } + + segment_identifier const& seg_id = it->operations[op_id].seg_id; + segment_identifier const& other_id = it->operations[other_op_id].seg_id; + + const bool first_in_range = m_seg_watcher.update(seg_id); + + // handle possible exit + bool fake_enter_detected = false; + if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) + { + // real exit point - may be multiple + // we know that we entered and now we exit + if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + { + m_exit_watcher.reset_detected_exit(); + + // not the last IP + update<interior, exterior, '1', TransposeResult>(res); + } + // fake exit point, reset state + else if ( op == overlay::operation_intersection + || op == overlay::operation_continue ) // operation_boundary + { + m_exit_watcher.reset_detected_exit(); + fake_enter_detected = true; + } + } + else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) + { + // ignore multiple BLOCKs + if ( op == overlay::operation_blocked ) + return; + + if ( ( op == overlay::operation_intersection + || op == overlay::operation_continue ) + && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + { + fake_enter_detected = true; + } + + m_exit_watcher.reset_detected_exit(); + } + +// NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY) +// BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES +// IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE +// TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED + +// TODO: THIS IS POTENTIALLY ERROREOUS! +// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS +// IT WOULD GIVE WRONG RESULTS E.G. +// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u' + + // handle the interior overlap + if ( m_interior_detected ) + { + // real interior overlap + if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + { + update<interior, interior, '1', TransposeResult>(res); + m_interior_detected = false; + } + // fake interior overlap + else if ( op == overlay::operation_continue ) + { + m_interior_detected = false; + } + else if ( op == overlay::operation_union ) + { +// TODO: this probably is not a good way of handling the interiors/enters +// the solution similar to exit_watcher would be more robust +// all enters should be kept and handled. +// maybe integrate it with the exit_watcher -> enter_exit_watcher + if ( m_first_interior_other_id_ptr + && m_first_interior_other_id_ptr->multi_index == other_id.multi_index ) + { + m_interior_detected = false; + } + } + } + + // i/u, c/u + if ( op == overlay::operation_intersection + || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection + { + bool no_enters_detected = m_exit_watcher.is_outside(); + m_exit_watcher.enter(*it); + + if ( op == overlay::operation_intersection ) + { + if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear ) + --m_boundary_counter; + + if ( m_boundary_counter == 0 ) + { + // interiors overlaps + //update<interior, interior, '1', TransposeResult>(res); + +// TODO: think about the implementation of the more robust version +// this way only the first enter will be handled + if ( !m_interior_detected ) + { + // don't update now + // we might enter a boundary of some other ring on the same IP + m_interior_detected = true; + m_first_interior_other_id_ptr = boost::addressof(other_id); + } + } + } + else // operation_boundary + { + // don't add to the count for all met boundaries + // only if this is the "new" boundary + if ( first_in_range || !it->operations[op_id].is_collinear ) + ++m_boundary_counter; + + update<interior, boundary, '1', TransposeResult>(res); + } + + bool const this_b + = is_ip_on_boundary<boundary_front>(it->point, + it->operations[op_id], + boundary_checker, + seg_id); + // going inside on boundary point + if ( this_b ) + { + update<boundary, boundary, '0', TransposeResult>(res); + } + // going inside on non-boundary point + else + { + update<interior, boundary, '0', TransposeResult>(res); + + // if we didn't enter in the past, we were outside + if ( no_enters_detected + && ! fake_enter_detected + && it->operations[op_id].position != overlay::position_front ) + { +// TODO: calculate_from_inside() is only needed if the current Linestring is not closed + bool const from_inside = first_in_range + && calculate_from_inside(geometry, + other_geometry, + *it); + + if ( from_inside ) + update<interior, interior, '1', TransposeResult>(res); + else + update<interior, exterior, '1', TransposeResult>(res); + + // if it's the first IP then the first point is outside + if ( first_in_range ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(sub_range(geometry, seg_id)), + boundary_checker); + + // if there is a boundary on the first point + if ( front_b ) + { + if ( from_inside ) + update<boundary, interior, '0', TransposeResult>(res); + else + update<boundary, exterior, '0', TransposeResult>(res); + } + } + } + } + } + // u/u, x/u + else if ( op == overlay::operation_union || op == overlay::operation_blocked ) + { + bool const op_blocked = op == overlay::operation_blocked; + bool const no_enters_detected = m_exit_watcher.is_outside() +// TODO: is this condition ok? +// TODO: move it into the exit_watcher? + && m_exit_watcher.get_exit_operation() == overlay::operation_none; + + if ( op == overlay::operation_union ) + { + if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear ) + --m_boundary_counter; + } + else // overlay::operation_blocked + { + m_boundary_counter = 0; + } + + // we're inside, possibly going out right now + if ( ! no_enters_detected ) + { + if ( op_blocked + && it->operations[op_id].position == overlay::position_back ) // ignore spikes! + { + // check if this is indeed the boundary point + // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same + if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) + { + update<boundary, boundary, '0', TransposeResult>(res); + } + } + // union, inside, but no exit -> collinear on self-intersection point + // not needed since we're already inside the boundary + /*else if ( !exit_detected ) + { + update<interior, boundary, '0', TransposeResult>(res); + }*/ + } + // we're outside or inside and this is the first turn + else + { + bool const this_b = is_ip_on_boundary<boundary_any>(it->point, + it->operations[op_id], + boundary_checker, + seg_id); + // if current IP is on boundary of the geometry + if ( this_b ) + { + update<boundary, boundary, '0', TransposeResult>(res); + } + // if current IP is not on boundary of the geometry + else + { + update<interior, boundary, '0', TransposeResult>(res); + } + + // TODO: very similar code is used in the handling of intersection + if ( it->operations[op_id].position != overlay::position_front ) + { +// TODO: calculate_from_inside() is only needed if the current Linestring is not closed + bool const first_from_inside = first_in_range + && calculate_from_inside(geometry, + other_geometry, + *it); + if ( first_from_inside ) + { + update<interior, interior, '1', TransposeResult>(res); + + // notify the exit_watcher that we started inside + m_exit_watcher.enter(*it); + } + else + { + update<interior, exterior, '1', TransposeResult>(res); + } + + // first IP on the last segment point - this means that the first point is outside or inside + if ( first_in_range && ( !this_b || op_blocked ) ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(sub_range(geometry, seg_id)), + boundary_checker); + + // if there is a boundary on the first point + if ( front_b ) + { + if ( first_from_inside ) + update<boundary, interior, '0', TransposeResult>(res); + else + update<boundary, exterior, '0', TransposeResult>(res); + } + } + } + } + + // if we're going along a boundary, we exit only if the linestring was collinear + if ( m_boundary_counter == 0 + || it->operations[op_id].is_collinear ) + { + // notify the exit watcher about the possible exit + m_exit_watcher.exit(*it); + } + } + + // store ref to previously analysed (valid) turn + m_previous_turn_ptr = boost::addressof(*it); + // and previously analysed (valid) operation + m_previous_operation = op; + } + + // it == last + template <typename Result, + typename TurnIt, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker> + void apply(Result & res, + TurnIt first, TurnIt last, + Geometry const& geometry, + OtherGeometry const& /*other_geometry*/, + BoundaryChecker const& boundary_checker) + { + boost::ignore_unused(first, last); + //BOOST_ASSERT( first != last ); + + // here, the possible exit is the real one + // we know that we entered and now we exit + if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT + ||*/ m_previous_operation == overlay::operation_union + && !m_interior_detected ) + { + // for sure + update<interior, exterior, '1', TransposeResult>(res); + + BOOST_ASSERT(first != last); + BOOST_ASSERT(m_previous_turn_ptr); + + segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; + + bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( + range::back(sub_range(geometry, prev_seg_id)), + boundary_checker); + + // if there is a boundary on the last point + if ( prev_back_b ) + { + update<boundary, exterior, '0', TransposeResult>(res); + } + } + // we might enter some Areal and didn't go out, + else if ( m_previous_operation == overlay::operation_intersection + || m_interior_detected ) + { + // just in case + update<interior, interior, '1', TransposeResult>(res); + m_interior_detected = false; + + BOOST_ASSERT(first != last); + BOOST_ASSERT(m_previous_turn_ptr); + + segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; + + bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( + range::back(sub_range(geometry, prev_seg_id)), + boundary_checker); + + // if there is a boundary on the last point + if ( prev_back_b ) + { + update<boundary, interior, '0', TransposeResult>(res); + } + } + + BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue, + "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)"); + + // Reset exit watcher before the analysis of the next Linestring + m_exit_watcher.reset(); + m_boundary_counter = 0; + } + + // check if the passed turn's segment of Linear geometry arrived + // from the inside or the outside of the Areal geometry + template <typename Turn> + static inline bool calculate_from_inside(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Turn const& turn) + { + if ( turn.operations[op_id].position == overlay::position_front ) + return false; + + typename sub_range_return_type<Geometry1 const>::type + range1 = sub_range(geometry1, turn.operations[op_id].seg_id); + + typedef detail::normalized_view<Geometry2 const> const range2_type; + typedef typename boost::range_iterator<range2_type>::type range2_iterator; + range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id)); + + BOOST_ASSERT(boost::size(range1)); + std::size_t const s2 = boost::size(range2); + BOOST_ASSERT(s2 > 2); + std::size_t const seg_count2 = s2 - 1; + + std::size_t const p_seg_ij = turn.operations[op_id].seg_id.segment_index; + std::size_t const q_seg_ij = turn.operations[other_op_id].seg_id.segment_index; + + BOOST_ASSERT(p_seg_ij + 1 < boost::size(range1)); + BOOST_ASSERT(q_seg_ij + 1 < s2); + + point1_type const& pi = range::at(range1, p_seg_ij); + point2_type const& qi = range::at(range2, q_seg_ij); + point2_type const& qj = range::at(range2, q_seg_ij + 1); + point1_type qi_conv; + geometry::convert(qi, qi_conv); + bool const is_ip_qj = equals::equals_point_point(turn.point, qj); +// TODO: test this! +// BOOST_ASSERT(!equals::equals_point_point(turn.point, pi)); +// BOOST_ASSERT(!equals::equals_point_point(turn.point, qi)); + point1_type new_pj; + geometry::convert(turn.point, new_pj); + + if ( is_ip_qj ) + { + std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2; +// TODO: the following function should return immediately, however the worst case complexity is O(N) +// It would be good to replace it with some O(1) mechanism + range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2), + boost::begin(range2) + q_seg_jk, + boost::end(range2)); + + // Will this sequence of points be always correct? + overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it); + + return calculate_from_inside_sides(side_calc); + } + else + { + point1_type new_qj; + geometry::convert(turn.point, new_qj); + + overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj); + + return calculate_from_inside_sides(side_calc); + } + } + + template <typename It> + static inline It find_next_non_duplicated(It first, It current, It last) + { + BOOST_ASSERT( current != last ); + + It it = current; + + for ( ++it ; it != last ; ++it ) + { + if ( !equals::equals_point_point(*current, *it) ) + return it; + } + + // if not found start from the beginning + for ( it = first ; it != current ; ++it ) + { + if ( !equals::equals_point_point(*current, *it) ) + return it; + } + + return current; + } + + // calculate inside or outside based on side_calc + // this is simplified version of a check from equal<> + template <typename SideCalc> + static inline bool calculate_from_inside_sides(SideCalc const& side_calc) + { + int const side_pk_p = side_calc.pk_wrt_p1(); + int const side_qk_p = side_calc.qk_wrt_p1(); + // If they turn to same side (not opposite sides) + if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p)) + { + int const side_pk_q2 = side_calc.pk_wrt_q2(); + return side_pk_q2 == -1; + } + else + { + return side_pk_p == -1; + } + } + + private: + exit_watcher<TurnInfo, op_id> m_exit_watcher; + segment_watcher<same_single> m_seg_watcher; + TurnInfo * m_previous_turn_ptr; + overlay::operation_type m_previous_operation; + unsigned m_boundary_counter; + bool m_interior_detected; + const segment_identifier * m_first_interior_other_id_ptr; + }; + + // call analyser.apply() for each turn in range + // IMPORTANT! The analyser is also called for the end iterator - last + template <typename Result, + typename TurnIt, + typename Analyser, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker> + static inline void analyse_each_turn(Result & res, + Analyser & analyser, + TurnIt first, TurnIt last, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker) + { + if ( first == last ) + return; + + for ( TurnIt it = first ; it != last ; ++it ) + { + analyser.apply(res, it, + geometry, other_geometry, + boundary_checker); + + if ( res.interrupt ) + return; + } + + analyser.apply(res, first, last, + geometry, other_geometry, + boundary_checker); + } + + // less comparator comparing multi_index then ring_index + // may be used to sort turns by ring + struct less_ring + { + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + return left.operations[1].seg_id.multi_index < right.operations[1].seg_id.multi_index + || ( left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index + && left.operations[1].seg_id.ring_index < right.operations[1].seg_id.ring_index ); + } + }; + + // policy/functor checking if a turn's operation is operation_continue + struct has_boundary_intersection + { + has_boundary_intersection() + : result(false) {} + + template <typename Turn> + inline void operator()(Turn const& turn) + { + if ( turn.operations[1].operation == overlay::operation_continue ) + result = true; + } + + bool result; + }; + + // iterate through the range and search for the different multi_index or ring_index + // also call fun for each turn in the current range + template <typename It, typename Fun> + static inline It find_next_ring(It first, It last, Fun & fun) + { + if ( first == last ) + return last; + + int const multi_index = first->operations[1].seg_id.multi_index; + int const ring_index = first->operations[1].seg_id.ring_index; + + fun(*first); + ++first; + + for ( ; first != last ; ++first ) + { + if ( multi_index != first->operations[1].seg_id.multi_index + || ring_index != first->operations[1].seg_id.ring_index ) + { + return first; + } + + fun(*first); + } + + return last; + } + + // analyser which called for turns sorted by seg/distance/operation + // checks if the boundary of Areal geometry really got out + // into the exterior of Linear geometry + template <typename TurnInfo> + class areal_boundary_analyser + { + public: + areal_boundary_analyser() + : is_union_detected(false) + , m_previous_turn_ptr(NULL) + {} + + template <typename TurnIt> + bool apply(TurnIt /*first*/, TurnIt it, TurnIt last) + { + overlay::operation_type op = it->operations[1].operation; + + if ( it != last ) + { + if ( op != overlay::operation_union + && op != overlay::operation_continue ) + { + return true; + } + + if ( is_union_detected ) + { + BOOST_ASSERT(m_previous_turn_ptr != NULL); + if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point) ) + { + // break + return false; + } + else if ( op == overlay::operation_continue ) // operation_boundary + { + is_union_detected = false; + } + } + + if ( op == overlay::operation_union ) + { + is_union_detected = true; + m_previous_turn_ptr = boost::addressof(*it); + } + + return true; + } + else + { + return false; + } + } + + bool is_union_detected; + + private: + const TurnInfo * m_previous_turn_ptr; + }; +}; + +template <typename Geometry1, typename Geometry2> +struct areal_linear +{ + template <typename Result> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { + linear_areal<Geometry2, Geometry1, true>::apply(geometry2, geometry1, result); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp new file mode 100644 index 0000000000..263c82de56 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -0,0 +1,768 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP + +#include <boost/core/ignore_unused.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/algorithms/detail/single_geometry.hpp> + +#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/turns.hpp> +#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> +#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +template <typename Result, typename BoundaryChecker, bool TransposeResult> +class disjoint_linestring_pred +{ +public: + disjoint_linestring_pred(Result & res, + BoundaryChecker const& boundary_checker) + : m_result(res) + , m_boundary_checker(boundary_checker) + , m_flags(0) + { + if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) ) + { + m_flags |= 1; + } + if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) ) + { + m_flags |= 2; + } + } + + template <typename Linestring> + bool operator()(Linestring const& linestring) + { + if ( m_flags == 3 ) + { + return false; + } + + std::size_t const count = boost::size(linestring); + + // invalid input + if ( count < 2 ) + { + // ignore + // TODO: throw an exception? + return true; + } + + // point-like linestring + if ( count == 2 + && equals::equals_point_point(range::front(linestring), + range::back(linestring)) ) + { + update<interior, exterior, '0', TransposeResult>(m_result); + } + else + { + update<interior, exterior, '1', TransposeResult>(m_result); + m_flags |= 1; + + // check if there is a boundary + if ( m_flags < 2 + && ( m_boundary_checker.template + is_endpoint_boundary<boundary_front>(range::front(linestring)) + || m_boundary_checker.template + is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) + { + update<boundary, exterior, '0', TransposeResult>(m_result); + m_flags |= 2; + } + } + + return m_flags != 3 + && ! m_result.interrupt; + } + +private: + Result & m_result; + BoundaryChecker const& m_boundary_checker; + unsigned m_flags; +}; + +template <typename Geometry1, typename Geometry2> +struct linear_linear +{ + static const bool interruption_enabled = true; + + typedef typename geometry::point_type<Geometry1>::type point1_type; + typedef typename geometry::point_type<Geometry2>::type point2_type; + + template <typename Result> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { + // The result should be FFFFFFFFF + relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T + if ( result.interrupt ) + return; + + // get and analyse turns + typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type; + std::vector<turn_type> turns; + + interrupt_policy_linear_linear<Result> interrupt_policy(result); + + turns::get_turns + < + Geometry1, + Geometry2, + detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> > + >::apply(turns, geometry1, geometry2, interrupt_policy); + + if ( result.interrupt ) + return; + + boundary_checker<Geometry1> boundary_checker1(geometry1); + disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1); + for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); + if ( result.interrupt ) + return; + + boundary_checker<Geometry2> boundary_checker2(geometry2); + disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2); + for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); + if ( result.interrupt ) + return; + + if ( turns.empty() ) + return; + + // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point + // for linear geometries union operation must be detected which I guess would be quite often + + if ( may_update<interior, interior, '1'>(result) + || may_update<interior, boundary, '0'>(result) + || may_update<interior, exterior, '1'>(result) + || may_update<boundary, interior, '0'>(result) + || may_update<boundary, boundary, '0'>(result) + || may_update<boundary, exterior, '0'>(result) ) + { + typedef turns::less<0, turns::less_op_linear_linear<0> > less; + std::sort(turns.begin(), turns.end(), less()); + + turns_analyser<turn_type, 0> analyser; + analyse_each_turn(result, analyser, + turns.begin(), turns.end(), + geometry1, geometry2, + boundary_checker1, boundary_checker2); + } + + if ( result.interrupt ) + return; + + if ( may_update<interior, interior, '1', true>(result) + || may_update<interior, boundary, '0', true>(result) + || may_update<interior, exterior, '1', true>(result) + || may_update<boundary, interior, '0', true>(result) + || may_update<boundary, boundary, '0', true>(result) + || may_update<boundary, exterior, '0', true>(result) ) + { + typedef turns::less<1, turns::less_op_linear_linear<1> > less; + std::sort(turns.begin(), turns.end(), less()); + + turns_analyser<turn_type, 1> analyser; + analyse_each_turn(result, analyser, + turns.begin(), turns.end(), + geometry2, geometry1, + boundary_checker2, boundary_checker1); + } + } + + template <typename Result> + class interrupt_policy_linear_linear + { + public: + static bool const enabled = true; + + explicit interrupt_policy_linear_linear(Result & result) + : m_result(result) + {} + +// TODO: since we update result for some operations here, we may not do it in the analyser! + + template <typename Range> + inline bool apply(Range const& turns) + { + typedef typename boost::range_iterator<Range const>::type iterator; + + for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + { + if ( it->operations[0].operation == overlay::operation_intersection + || it->operations[1].operation == overlay::operation_intersection ) + { + update<interior, interior, '1'>(m_result); + } + else if ( ( it->operations[0].operation == overlay::operation_union + || it->operations[0].operation == overlay::operation_blocked + || it->operations[1].operation == overlay::operation_union + || it->operations[1].operation == overlay::operation_blocked ) + && it->operations[0].position == overlay::position_middle + && it->operations[1].position == overlay::position_middle ) + { +// TODO: here we could also check the boundaries and set IB,BI,BB at this point + update<interior, interior, '0'>(m_result); + } + } + + return m_result.interrupt; + } + + private: + Result & m_result; + }; + + // This analyser should be used like Input or SinglePass Iterator + template <typename TurnInfo, std::size_t OpId> + class turns_analyser + { + typedef typename TurnInfo::point_type turn_point_type; + + static const std::size_t op_id = OpId; + static const std::size_t other_op_id = (OpId + 1) % 2; + static const bool transpose_result = OpId != 0; + + public: + turns_analyser() + : m_previous_turn_ptr(NULL) + , m_previous_operation(overlay::operation_none) + , m_degenerated_turn_ptr(NULL) + {} + + template <typename Result, + typename TurnIt, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker, + typename OtherBoundaryChecker> + void apply(Result & res, TurnIt it, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker, + OtherBoundaryChecker const& other_boundary_checker) + { + overlay::operation_type const op = it->operations[op_id].operation; + + segment_identifier const& seg_id = it->operations[op_id].seg_id; + segment_identifier const& other_id = it->operations[other_op_id].seg_id; + + bool const first_in_range = m_seg_watcher.update(seg_id); + + if ( op != overlay::operation_union + && op != overlay::operation_intersection + && op != overlay::operation_blocked ) + { + // degenerated turn + if ( op == overlay::operation_continue + && it->method == overlay::method_none + && m_exit_watcher.is_outside(*it) + /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none + || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ ) + { + // TODO: rewrite the above condition + + // WARNING! For spikes the above condition may be TRUE + // When degenerated turns are be marked in a different way than c,c/c + // different condition will be checked + + handle_degenerated(res, *it, + geometry, other_geometry, + boundary_checker, other_boundary_checker, + first_in_range); + + // TODO: not elegant solution! should be rewritten. + if ( it->operations[op_id].position == overlay::position_back ) + { + m_previous_operation = overlay::operation_blocked; + m_exit_watcher.reset_detected_exit(); + } + } + + return; + } + + // reset + m_degenerated_turn_ptr = NULL; + + // handle possible exit + bool fake_enter_detected = false; + if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) + { + // real exit point - may be multiple + // we know that we entered and now we exit + if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + { + m_exit_watcher.reset_detected_exit(); + + // not the last IP + update<interior, exterior, '1', transpose_result>(res); + } + // fake exit point, reset state + else if ( op == overlay::operation_intersection ) + { + m_exit_watcher.reset_detected_exit(); + fake_enter_detected = true; + } + } + else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) + { + // ignore multiple BLOCKs + if ( op == overlay::operation_blocked ) + return; + + if ( op == overlay::operation_intersection + && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + { + fake_enter_detected = true; + } + + m_exit_watcher.reset_detected_exit(); + } + + // i/i, i/x, i/u + if ( op == overlay::operation_intersection ) + { + bool const was_outside = m_exit_watcher.is_outside(); + m_exit_watcher.enter(*it); + + // interiors overlaps + update<interior, interior, '1', transpose_result>(res); + + bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes! + && is_ip_on_boundary<boundary_front>(it->point, + it->operations[op_id], + boundary_checker, + seg_id); + + // going inside on boundary point + // may be front only + if ( this_b ) + { + // may be front and back + bool const other_b = is_ip_on_boundary<boundary_any>(it->point, + it->operations[other_op_id], + other_boundary_checker, + other_id); + + // it's also the boundary of the other geometry + if ( other_b ) + { + update<boundary, boundary, '0', transpose_result>(res); + } + else + { + update<boundary, interior, '0', transpose_result>(res); + } + } + // going inside on non-boundary point + else + { + // if we didn't enter in the past, we were outside + if ( was_outside + && ! fake_enter_detected + && it->operations[op_id].position != overlay::position_front ) + { + update<interior, exterior, '1', transpose_result>(res); + + // if it's the first IP then the first point is outside + if ( first_in_range ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(sub_range(geometry, seg_id)), + boundary_checker); + + // if there is a boundary on the first point + if ( front_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + } + } + } + // u/i, u/u, u/x, x/i, x/u, x/x + else if ( op == overlay::operation_union || op == overlay::operation_blocked ) + { + // TODO: is exit watcher still needed? + // couldn't is_collinear and some going inside counter be used instead? + + bool const is_collinear = it->operations[op_id].is_collinear; + bool const was_outside = m_exit_watcher.is_outside() + && m_exit_watcher.get_exit_operation() == overlay::operation_none; +// TODO: move the above condition into the exit_watcher? + + // to exit we must be currently inside and the current segment must be collinear + if ( !was_outside && is_collinear ) + { + m_exit_watcher.exit(*it, false); + } + + bool const op_blocked = op == overlay::operation_blocked; + + // we're inside and going out from inside + // possibly going out right now + if ( ! was_outside && is_collinear ) + { + if ( op_blocked + && it->operations[op_id].position == overlay::position_back ) // ignore spikes! + { + // check if this is indeed the boundary point + // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same + if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) + { + // may be front and back + bool const other_b = is_ip_on_boundary<boundary_any>(it->point, + it->operations[other_op_id], + other_boundary_checker, + other_id); + // it's also the boundary of the other geometry + if ( other_b ) + { + update<boundary, boundary, '0', transpose_result>(res); + } + else + { + update<boundary, interior, '0', transpose_result>(res); + } + } + } + } + // we're outside or intersects some segment from the outside + else + { + // if we are truly outside + if ( was_outside + && it->operations[op_id].position != overlay::position_front + /*&& !is_collinear*/ ) + { + update<interior, exterior, '1', transpose_result>(res); + } + + // boundaries don't overlap - just an optimization + if ( it->method == overlay::method_crosses ) + { + // the L1 is going from one side of the L2 to the other through the point + update<interior, interior, '0', transpose_result>(res); + + // it's the first point in range + if ( first_in_range ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(sub_range(geometry, seg_id)), + boundary_checker); + + // if there is a boundary on the first point + if ( front_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + } + // method other than crosses, check more conditions + else + { + bool const this_b = is_ip_on_boundary<boundary_any>(it->point, + it->operations[op_id], + boundary_checker, + seg_id); + + bool const other_b = is_ip_on_boundary<boundary_any>(it->point, + it->operations[other_op_id], + other_boundary_checker, + other_id); + + // if current IP is on boundary of the geometry + if ( this_b ) + { + // it's also the boundary of the other geometry + if ( other_b ) + { + update<boundary, boundary, '0', transpose_result>(res); + } + else + { + update<boundary, interior, '0', transpose_result>(res); + } + } + // if current IP is not on boundary of the geometry + else + { + // it's also the boundary of the other geometry + if ( other_b ) + { + update<interior, boundary, '0', transpose_result>(res); + } + else + { + update<interior, interior, '0', transpose_result>(res); + } + } + + // first IP on the last segment point - this means that the first point is outside + if ( first_in_range + && ( !this_b || op_blocked ) + && was_outside + && it->operations[op_id].position != overlay::position_front + /*&& !is_collinear*/ ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(sub_range(geometry, seg_id)), + boundary_checker); + + // if there is a boundary on the first point + if ( front_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + + } + } + } + + // store ref to previously analysed (valid) turn + m_previous_turn_ptr = boost::addressof(*it); + // and previously analysed (valid) operation + m_previous_operation = op; + } + + // Called for last + template <typename Result, + typename TurnIt, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker, + typename OtherBoundaryChecker> + void apply(Result & res, + TurnIt first, TurnIt last, + Geometry const& geometry, + OtherGeometry const& /*other_geometry*/, + BoundaryChecker const& boundary_checker, + OtherBoundaryChecker const& /*other_boundary_checker*/) + { + boost::ignore_unused(first, last); + //BOOST_ASSERT( first != last ); + + // here, the possible exit is the real one + // we know that we entered and now we exit + if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT + ||*/ m_previous_operation == overlay::operation_union + || m_degenerated_turn_ptr ) + { + update<interior, exterior, '1', transpose_result>(res); + + BOOST_ASSERT(first != last); + + const TurnInfo * turn_ptr = NULL; + if ( m_degenerated_turn_ptr ) + turn_ptr = m_degenerated_turn_ptr; + else if ( m_previous_turn_ptr ) + turn_ptr = m_previous_turn_ptr; + + if ( turn_ptr ) + { + segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id; + + //BOOST_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id))); + bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( + range::back(sub_range(geometry, prev_seg_id)), + boundary_checker); + + // if there is a boundary on the last point + if ( prev_back_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + } + + // Just in case, + // reset exit watcher before the analysis of the next Linestring + // note that if there are some enters stored there may be some error above + m_exit_watcher.reset(); + + m_previous_turn_ptr = NULL; + m_previous_operation = overlay::operation_none; + m_degenerated_turn_ptr = NULL; + } + + template <typename Result, + typename Turn, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker, + typename OtherBoundaryChecker> + void handle_degenerated(Result & res, + Turn const& turn, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker, + OtherBoundaryChecker const& /*other_boundary_checker*/, + bool first_in_range) + { + typename detail::single_geometry_return_type<Geometry const>::type + ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id); + typename detail::single_geometry_return_type<OtherGeometry const>::type + ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id); + + // only one of those should be true: + + if ( turn.operations[op_id].position == overlay::position_front ) + { + // valid, point-sized + if ( boost::size(ls2_ref) == 2 ) + { + bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker); + + if ( front_b ) + { + update<boundary, interior, '0', transpose_result>(res); + } + else + { + update<interior, interior, '0', transpose_result>(res); + } + + // operation 'c' should be last for the same IP so we know that the next point won't be the same + update<interior, exterior, '1', transpose_result>(res); + + m_degenerated_turn_ptr = boost::addressof(turn); + } + } + else if ( turn.operations[op_id].position == overlay::position_back ) + { + // valid, point-sized + if ( boost::size(ls2_ref) == 2 ) + { + update<interior, exterior, '1', transpose_result>(res); + + bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker); + + if ( back_b ) + { + update<boundary, interior, '0', transpose_result>(res); + } + else + { + update<interior, interior, '0', transpose_result>(res); + } + + if ( first_in_range ) + { + //BOOST_ASSERT(!boost::empty(ls1_ref)); + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(ls1_ref), boundary_checker); + if ( front_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + } + } + else if ( turn.operations[op_id].position == overlay::position_middle + && turn.operations[other_op_id].position == overlay::position_middle ) + { + update<interior, interior, '0', transpose_result>(res); + + // here we don't know which one is degenerated + + bool const is_point1 = boost::size(ls1_ref) == 2 + && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref)); + bool const is_point2 = boost::size(ls2_ref) == 2 + && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref)); + + // if the second one is degenerated + if ( !is_point1 && is_point2 ) + { + update<interior, exterior, '1', transpose_result>(res); + + if ( first_in_range ) + { + //BOOST_ASSERT(!boost::empty(ls1_ref)); + bool const front_b = is_endpoint_on_boundary<boundary_front>( + range::front(ls1_ref), boundary_checker); + if ( front_b ) + { + update<boundary, exterior, '0', transpose_result>(res); + } + } + + m_degenerated_turn_ptr = boost::addressof(turn); + } + } + + // NOTE: other.position == front and other.position == back + // will be handled later, for the other geometry + } + + private: + exit_watcher<TurnInfo, OpId> m_exit_watcher; + segment_watcher<same_single> m_seg_watcher; + const TurnInfo * m_previous_turn_ptr; + overlay::operation_type m_previous_operation; + const TurnInfo * m_degenerated_turn_ptr; + }; + + template <typename Result, + typename TurnIt, + typename Analyser, + typename Geometry, + typename OtherGeometry, + typename BoundaryChecker, + typename OtherBoundaryChecker> + static inline void analyse_each_turn(Result & res, + Analyser & analyser, + TurnIt first, TurnIt last, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker, + OtherBoundaryChecker const& other_boundary_checker) + { + if ( first == last ) + return; + + for ( TurnIt it = first ; it != last ; ++it ) + { + analyser.apply(res, it, + geometry, other_geometry, + boundary_checker, other_boundary_checker); + + if ( res.interrupt ) + return; + } + + analyser.apply(res, first, last, + geometry, other_geometry, + boundary_checker, other_boundary_checker); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp new file mode 100644 index 0000000000..86c236d357 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp @@ -0,0 +1,205 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP + +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> +//#include <boost/geometry/algorithms/within.hpp> +//#include <boost/geometry/algorithms/covered_by.hpp> + +#include <boost/geometry/algorithms/detail/relate/topology_check.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// non-point geometry +template <typename Point, typename Geometry, bool Transpose = false> +struct point_geometry +{ + // TODO: interrupt only if the topology check is complex + + static const bool interruption_enabled = true; + + template <typename Result> + static inline void apply(Point const& point, Geometry const& geometry, Result & result) + { + int pig = detail::within::point_in_geometry(point, geometry); + + if ( pig > 0 ) // within + { + set<interior, interior, '0', Transpose>(result); + } + else if ( pig == 0 ) + { + set<interior, boundary, '0', Transpose>(result); + } + else // pig < 0 - not within + { + set<interior, exterior, '0', Transpose>(result); + } + + set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); + + if ( result.interrupt ) + return; + + // the point is on the boundary + if ( pig == 0 ) + { + // NOTE: even for MLs, if there is at least one boundary point, + // somewhere there must be another one + + // check if there are other boundaries outside + typedef detail::relate::topology_check<Geometry> tc_t; + //tc_t tc(geometry, point); + //if ( tc.has_interior ) + set<exterior, interior, tc_t::interior, Transpose>(result); + //if ( tc.has_boundary ) + set<exterior, boundary, tc_t::boundary, Transpose>(result); + } + else + { + // check if there is a boundary in Geometry + typedef detail::relate::topology_check<Geometry> tc_t; + tc_t tc(geometry); + if ( tc.has_interior ) + set<exterior, interior, tc_t::interior, Transpose>(result); + if ( tc.has_boundary ) + set<exterior, boundary, tc_t::boundary, Transpose>(result); + } + } +}; + +// transposed result of point_geometry +template <typename Geometry, typename Point> +struct geometry_point +{ + // TODO: interrupt only if the topology check is complex + + static const bool interruption_enabled = true; + + template <typename Result> + static inline void apply(Geometry const& geometry, Point const& point, Result & result) + { + point_geometry<Point, Geometry, true>::apply(point, geometry, result); + } +}; + +// TODO: rewrite the folowing: + +//// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box) +//// There is no EPS used in those functions, values are compared using < or <= +//// so comparing MIN and MAX in the same way should be fine +// +//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value> +//struct box_has_interior +//{ +// static inline bool apply(Box const& box) +// { +// return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box) +// && box_has_interior<Box, I + 1, D>::apply(box); +// } +//}; +// +//template <typename Box, std::size_t D> +//struct box_has_interior<Box, D, D> +//{ +// static inline bool apply(Box const&) { return true; } +//}; +// +//// NOTE: especially important here (see the NOTE above). +// +//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value> +//struct box_has_equal_min_max +//{ +// static inline bool apply(Box const& box) +// { +// return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box) +// && box_has_equal_min_max<Box, I + 1, D>::apply(box); +// } +//}; +// +//template <typename Box, std::size_t D> +//struct box_has_equal_min_max<Box, D, D> +//{ +// static inline bool apply(Box const&) { return true; } +//}; +// +//template <typename Point, typename Box> +//struct point_box +//{ +// static inline result apply(Point const& point, Box const& box) +// { +// result res; +// +// if ( geometry::within(point, box) ) // this also means that the box has interior +// { +// return result("0FFFFFTTT"); +// } +// else if ( geometry::covered_by(point, box) ) // point is on the boundary +// { +// //if ( box_has_interior<Box>::apply(box) ) +// //{ +// // return result("F0FFFFTTT"); +// //} +// //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point +// //{ +// // return result("F0FFFFFFT"); +// //} +// //else // no interior outside point +// //{ +// // return result("F0FFFFFTT"); +// //} +// return result("F0FFFF**T"); +// } +// else +// { +// /*if ( box_has_interior<Box>::apply(box) ) +// { +// return result("FF0FFFTTT"); +// } +// else +// { +// return result("FF0FFFFTT"); +// }*/ +// return result("FF0FFF*TT"); +// } +// +// return res; +// } +//}; +// +//template <typename Box, typename Point> +//struct box_point +//{ +// static inline result apply(Box const& box, Point const& point) +// { +// if ( geometry::within(point, box) ) +// return result("0FTFFTFFT"); +// else if ( geometry::covered_by(point, box) ) +// return result("FF*0F*FFT"); +// else +// return result("FF*FFT0FT"); +// } +//}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp new file mode 100644 index 0000000000..e623868b92 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/point_point.hpp @@ -0,0 +1,242 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP + +#include <algorithm> +#include <vector> + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/less.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +template <typename Point1, typename Point2> +struct point_point +{ + static const bool interruption_enabled = false; + + template <typename Result> + static inline void apply(Point1 const& point1, Point2 const& point2, Result & result) + { + bool equal = detail::equals::equals_point_point(point1, point2); + if ( equal ) + { + set<interior, interior, '0'>(result); + } + else + { + set<interior, exterior, '0'>(result); + set<exterior, interior, '0'>(result); + } + + set<exterior, exterior, result_dimension<Point1>::value>(result); + } +}; + +template <typename Point, typename MultiPoint> +std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point) +{ + bool found_inside = false; + bool found_outside = false; + + // point_in_geometry could be used here but why iterate over MultiPoint twice? + // we must search for a point in the exterior because all points in MultiPoint can be equal + + typedef typename boost::range_iterator<MultiPoint const>::type iterator; + iterator it = boost::begin(multi_point); + iterator last = boost::end(multi_point); + for ( ; it != last ; ++it ) + { + bool ii = detail::equals::equals_point_point(point, *it); + + if ( ii ) + found_inside = true; + else + found_outside = true; + + if ( found_inside && found_outside ) + break; + } + + return std::make_pair(found_inside, found_outside); +} + +template <typename Point, typename MultiPoint, bool Transpose = false> +struct point_multipoint +{ + static const bool interruption_enabled = false; + + template <typename Result> + static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result) + { + if ( boost::empty(multi_point) ) + { + // TODO: throw on empty input? + set<interior, exterior, '0', Transpose>(result); + return; + } + + std::pair<bool, bool> rel = point_multipoint_check(point, multi_point); + + if ( rel.first ) // some point of MP is equal to P + { + set<interior, interior, '0', Transpose>(result); + + if ( rel.second ) // a point of MP was found outside P + { + set<exterior, interior, '0', Transpose>(result); + } + } + else + { + set<interior, exterior, '0', Transpose>(result); + set<exterior, interior, '0', Transpose>(result); + } + + set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); + } +}; + +template <typename MultiPoint, typename Point> +struct multipoint_point +{ + static const bool interruption_enabled = false; + + template <typename Result> + static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result) + { + point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result); + } +}; + +template <typename MultiPoint1, typename MultiPoint2> +struct multipoint_multipoint +{ + static const bool interruption_enabled = true; + + template <typename Result> + static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result) + { + { + // TODO: throw on empty input? + bool empty1 = boost::empty(multi_point1); + bool empty2 = boost::empty(multi_point2); + if ( empty1 && empty2 ) + { + return; + } + else if ( empty1 ) + { + set<exterior, interior, '0'>(result); + return; + } + else if ( empty2 ) + { + set<interior, exterior, '0'>(result); + return; + } + } + +// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED + +// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed +// so if e.g. only I/I must be analysed we musn't check the other MPt + +// TODO: Also, the geometry with the smaller number of points may be analysed first + //if ( boost::size(multi_point1) < boost::size(multi_point2) ) + + // NlogN + MlogN + bool all_handled = search<false>(multi_point1, multi_point2, result); + + if ( all_handled || result.interrupt ) + return; + + // MlogM + NlogM + search<true>(multi_point2, multi_point1, result); + } + + template <bool Transpose, + typename SortedMultiPoint, + typename IteratedMultiPoint, + typename Result> + static inline bool search(SortedMultiPoint const& sorted_mpt, + IteratedMultiPoint const& iterated_mpt, + Result & result) + { + // sort points from the 1 MPt + typedef typename geometry::point_type<SortedMultiPoint>::type point_type; + std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt)); + std::sort(points.begin(), points.end(), less()); + + bool found_inside = false; + bool found_outside = false; + + // for each point in the second MPt + typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator; + for ( iterator it = boost::begin(iterated_mpt) ; + it != boost::end(iterated_mpt) ; ++it ) + { + bool ii = + std::binary_search(points.begin(), points.end(), *it, less()); + if ( ii ) + found_inside = true; + else + found_outside = true; + + if ( found_inside && found_outside ) + break; + } + + // an optimization + bool all_handled = false; + + if ( found_inside ) // some point of MP2 is equal to some of MP1 + { +// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed +// so if e.g. only I/I must be analysed we musn't check the other MPt + + set<interior, interior, '0', Transpose>(result); + + if ( found_outside ) // some point of MP2 was found outside of MP1 + { + set<exterior, interior, '0', Transpose>(result); + } + } + else + { + set<interior, exterior, '0', Transpose>(result); + set<exterior, interior, '0', Transpose>(result); + + // if no point is intersecting the other MPt then we musn't analyse the reversed case + all_handled = true; + } + + set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result); + + return all_handled; + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP diff --git a/boost/geometry/algorithms/detail/relate/relate.hpp b/boost/geometry/algorithms/detail/relate/relate.hpp new file mode 100644 index 0000000000..946653452a --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/relate.hpp @@ -0,0 +1,339 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP + +#include <cstddef> + +#include <boost/concept_check.hpp> +#include <boost/range.hpp> + +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <boost/type_traits/is_base_of.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/concepts/within_concept.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/within.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> + +#include <boost/geometry/algorithms/detail/relate/result.hpp> + +#include <boost/geometry/algorithms/detail/relate/point_point.hpp> +#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp> +#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// Those are used only to allow dispatch::relate to produce compile-time error + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type> +struct is_supported_by_generic +{ + static const bool value + = boost::is_same<Tag, linestring_tag>::value + || boost::is_same<Tag, multi_linestring_tag>::value + || boost::is_same<Tag, ring_tag>::value + || boost::is_same<Tag, polygon_tag>::value + || boost::is_same<Tag, multi_polygon_tag>::value; +}; + +template <typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type> +struct is_generic +{ + static const bool value = is_supported_by_generic<Geometry1>::value + && is_supported_by_generic<Geometry2>::value; +}; + + +template <typename Point, typename Geometry, typename Tag> +struct is_generic<Point, Geometry, point_tag, Tag> +{ + static const bool value = is_supported_by_generic<Geometry>::value; +}; + +template <typename Geometry, typename Point, typename Tag> +struct is_generic<Geometry, Point, Tag, point_tag> +{ + static const bool value = is_supported_by_generic<Geometry>::value; +}; + +template <typename Point1, typename Point2> +struct is_generic<Point1, Point2, point_tag, point_tag> +{ + static const bool value = false; +}; + + +}} // namespace detail::relate + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { namespace relate { + + +template <typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type, + int TopDim1 = geometry::topological_dimension<Geometry1>::value, + int TopDim2 = geometry::topological_dimension<Geometry2>::value, + bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value +> +struct relate : not_implemented<Tag1, Tag2> +{}; + + +template <typename Point1, typename Point2> +struct relate<Point1, Point2, point_tag, point_tag, 0, 0, false> + : detail::relate::point_point<Point1, Point2> +{}; + +template <typename Point, typename MultiPoint> +struct relate<Point, MultiPoint, point_tag, multi_point_tag, 0, 0, false> + : detail::relate::point_multipoint<Point, MultiPoint> +{}; + +template <typename MultiPoint, typename Point> +struct relate<MultiPoint, Point, multi_point_tag, point_tag, 0, 0, false> + : detail::relate::multipoint_point<MultiPoint, Point> +{}; + +template <typename MultiPoint1, typename MultiPoint2> +struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, 0, 0, false> + : detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2> +{}; + +//template <typename Point, typename Box, int TopDim2> +//struct relate<Point, Box, point_tag, box_tag, 0, TopDim2, false> +// : detail::relate::point_box<Point, Box> +//{}; +// +//template <typename Box, typename Point, int TopDim1> +//struct relate<Box, Point, box_tag, point_tag, TopDim1, 0, false> +// : detail::relate::box_point<Box, Point> +//{}; + + +template <typename Point, typename Geometry, typename Tag2, int TopDim2> +struct relate<Point, Geometry, point_tag, Tag2, 0, TopDim2, true> + : detail::relate::point_geometry<Point, Geometry> +{}; + +template <typename Geometry, typename Point, typename Tag1, int TopDim1> +struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true> + : detail::relate::geometry_point<Geometry, Point> +{}; + + +template <typename Linear1, typename Linear2, typename Tag1, typename Tag2> +struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true> + : detail::relate::linear_linear<Linear1, Linear2> +{}; + + +template <typename Linear, typename Areal, typename Tag1, typename Tag2> +struct relate<Linear, Areal, Tag1, Tag2, 1, 2, true> + : detail::relate::linear_areal<Linear, Areal> +{}; + +template <typename Areal, typename Linear, typename Tag1, typename Tag2> +struct relate<Areal, Linear, Tag1, Tag2, 2, 1, true> + : detail::relate::areal_linear<Areal, Linear> +{}; + + +template <typename Areal1, typename Areal2, typename Tag1, typename Tag2> +struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true> + : detail::relate::areal_areal<Areal1, Areal2> +{}; + + +}} // namespace detail_dispatch::relate +#endif // DOXYGEN_NO_DISPATCH + +namespace detail { namespace relate { + +template <typename Geometry1, typename Geometry2> +struct interruption_enabled +{ + static const bool value = + detail_dispatch::relate::relate<Geometry1, Geometry2>::interruption_enabled; +}; + +template <typename Geometry1, + typename Geometry2, + typename Result, + bool IsSequence = boost::mpl::is_sequence<Result>::value> +struct result_handler_type + : not_implemented<Result> +{}; + +template <typename Geometry1, typename Geometry2> +struct result_handler_type<Geometry1, Geometry2, matrix9, false> +{ + typedef matrix_handler<matrix9> type; +}; + +template <typename Geometry1, typename Geometry2> +struct result_handler_type<Geometry1, Geometry2, mask9, false> +{ + typedef mask_handler + < + mask9, + interruption_enabled + < + Geometry1, + Geometry2 + >::value + > type; +}; + +template <typename Geometry1, typename Geometry2, typename Head, typename Tail> +struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false> +{ + typedef mask_handler + < + boost::tuples::cons<Head, Tail>, + interruption_enabled + < + Geometry1, + Geometry2 + >::value + > type; +}; + +template <typename Geometry1, typename Geometry2, + char II, char IB, char IE, + char BI, char BB, char BE, + char EI, char EB, char EE> +struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, false> +{ + typedef static_mask_handler + < + static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, + interruption_enabled + < + Geometry1, + Geometry2 + >::value + > type; +}; + +template <typename Geometry1, typename Geometry2, typename StaticSequence> +struct result_handler_type<Geometry1, Geometry2, StaticSequence, true> +{ + typedef static_mask_handler + < + StaticSequence, + interruption_enabled + < + Geometry1, + Geometry2 + >::value + > type; +}; + +template <typename MatrixOrMask, typename Geometry1, typename Geometry2> +inline +typename result_handler_type + < + Geometry1, + Geometry2, + MatrixOrMask + >::type::result_type +relate(Geometry1 const& geometry1, + Geometry2 const& geometry2, + MatrixOrMask const& matrix_or_mask = MatrixOrMask()) +{ + typedef typename result_handler_type + < + Geometry1, + Geometry2, + MatrixOrMask + >::type handler_type; + + handler_type handler(matrix_or_mask); + detail_dispatch::relate::relate<Geometry1, Geometry2>::apply(geometry1, geometry2, handler); + return handler.result(); +} + +struct implemented_tag {}; + +template <template <typename, typename> class StaticMaskTrait, + typename Geometry1, + typename Geometry2> +struct relate_base + : boost::mpl::if_ + < + boost::mpl::or_ + < + boost::is_base_of + < + nyi::not_implemented_tag, + StaticMaskTrait<Geometry1, Geometry2> + >, + boost::is_base_of + < + nyi::not_implemented_tag, + detail_dispatch::relate::relate<Geometry1, Geometry2> + > + >, + not_implemented + < + typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type + >, + implemented_tag + >::type +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + typedef typename StaticMaskTrait<Geometry1, Geometry2>::type static_mask; + return detail::relate::relate<static_mask>(g1, g2); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp new file mode 100644 index 0000000000..1bcb5275d2 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/result.hpp @@ -0,0 +1,1390 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP + +#include <boost/tuple/tuple.hpp> + +#include <boost/mpl/is_sequence.hpp> +#include <boost/mpl/begin.hpp> +#include <boost/mpl/end.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/at.hpp> +#include <boost/mpl/vector_c.hpp> + +#include <boost/geometry/core/topological_dimension.hpp> + +// TEMP - move this header to geometry/detail +#include <boost/geometry/index/detail/tuples.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +enum field { interior = 0, boundary = 1, exterior = 2 }; + +// TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES +// THE VALUE ALREADY STORED MUSN'T BE CHECKED +// update() calls chould be replaced with set() in those cases +// but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that +// so some additional function could be added, e.g. set_dim() + +// matrix + +// TODO add height? + +template <std::size_t Width> +class matrix +{ + BOOST_STATIC_ASSERT(Width == 2 || Width == 3); + +public: + + static const std::size_t size = Width * Width; + + inline matrix() + { + ::memset(m_array, 'F', size); + } + + template <field F1, field F2> + inline char get() const + { + static const bool in_bounds = F1 * Width + F2 < size; + return get_dispatch<F1, F2>(integral_constant<bool, in_bounds>()); + } + + template <field F1, field F2, char V> + inline void set() + { + static const bool in_bounds = F1 * Width + F2 < size; + set_dispatch<F1, F2, V>(integral_constant<bool, in_bounds>()); + } + + template <field F1, field F2, char D> + inline void update() + { + static const bool in_bounds = F1 * Width + F2 < size; + update_dispatch<F1, F2, D>(integral_constant<bool, in_bounds>()); + } + + inline const char * data() const + { + return m_array; + } + +private: + template <field F1, field F2> + inline char get_dispatch(integral_constant<bool, true>) const + { + return m_array[F1 * Width + F2]; + } + template <field F1, field F2> + inline char get_dispatch(integral_constant<bool, false>) const + { + return 'F'; + } + + template <field F1, field F2, char V> + inline void set_dispatch(integral_constant<bool, true>) + { + BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); + m_array[F1 * Width + F2] = V; + } + template <field F1, field F2, char V> + inline void set_dispatch(integral_constant<bool, false>) + {} + + template <field F1, field F2, char D> + inline void update_dispatch(integral_constant<bool, true>) + { + BOOST_STATIC_ASSERT('0' <= D && D <= '9'); + char c = m_array[F1 * Width + F2]; + if ( D > c || c > '9') + m_array[F1 * Width + F2] = D; + } + template <field F1, field F2, char D> + inline void update_dispatch(integral_constant<bool, false>) + {} + + char m_array[size]; +}; + +// TODO add EnableDimensions parameter? + +struct matrix9 {}; +//struct matrix4 {}; + +// matrix_width + +template <typename MatrixOrMask> +struct matrix_width + : not_implemented<MatrixOrMask> +{}; + +template <> +struct matrix_width<matrix9> +{ + static const std::size_t value = 3; +}; + +// matrix_handler + +template <typename Matrix> +class matrix_handler + : private matrix<matrix_width<Matrix>::value> +{ + typedef matrix<matrix_width<Matrix>::value> base_t; + +public: + typedef std::string result_type; + + static const bool interrupt = false; + + matrix_handler(Matrix const&) + {} + + result_type result() const + { + return std::string(this->data(), + this->data() + base_t::size); + } + + template <field F1, field F2, char D> + inline bool may_update() const + { + BOOST_STATIC_ASSERT('0' <= D && D <= '9'); + + char const c = static_cast<base_t const&>(*this).template get<F1, F2>(); + return D > c || c > '9'; + } + + //template <field F1, field F2> + //inline char get() const + //{ + // return static_cast<base_t const&>(*this).template get<F1, F2>(); + //} + + template <field F1, field F2, char V> + inline void set() + { + static_cast<base_t&>(*this).template set<F1, F2, V>(); + } + + template <field F1, field F2, char D> + inline void update() + { + static_cast<base_t&>(*this).template update<F1, F2, D>(); + } +}; + +// RUN-TIME MASKS + +// mask9 + +class mask9 +{ +public: + static const std::size_t width = 3; // TEMP + + inline mask9(std::string const& de9im_mask) + { + // TODO: throw an exception here? + BOOST_ASSERT(de9im_mask.size() == 9); + ::memcpy(m_mask, de9im_mask.c_str(), 9); + } + + template <field F1, field F2> + inline char get() const + { + return m_mask[F1 * 3 + F2]; + } + +private: + char m_mask[9]; +}; + +// interrupt() + +template <typename Mask, bool InterruptEnabled> +struct interrupt_dispatch +{ + template <field F1, field F2, char V> + static inline bool apply(Mask const&) + { + return false; + } +}; + +template <typename Mask> +struct interrupt_dispatch<Mask, true> +{ + template <field F1, field F2, char V> + static inline bool apply(Mask const& mask) + { + char m = mask.template get<F1, F2>(); + return check<V>(m); + } + + template <char V> + static inline bool check(char m) + { + if ( V >= '0' && V <= '9' ) + { + return m == 'F' || ( m < V && m >= '0' && m <= '9' ); + } + else if ( V == 'T' ) + { + return m == 'F'; + } + return false; + } +}; + +template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value> +struct interrupt_dispatch_tuple +{ + template <field F1, field F2, char V> + static inline bool apply(Masks const& masks) + { + typedef typename boost::tuples::element<I, Masks>::type mask_type; + mask_type const& mask = boost::get<I>(masks); + return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask) + && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks); + } +}; + +template <typename Masks, int N> +struct interrupt_dispatch_tuple<Masks, N, N> +{ + template <field F1, field F2, char V> + static inline bool apply(Masks const& ) + { + return true; + } +}; + +template <typename T0, typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, typename T9> +struct interrupt_dispatch<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, true> +{ + typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type; + + template <field F1, field F2, char V> + static inline bool apply(mask_type const& mask) + { + return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask); + } +}; + +template <typename Head, typename Tail> +struct interrupt_dispatch<boost::tuples::cons<Head, Tail>, true> +{ + typedef boost::tuples::cons<Head, Tail> mask_type; + + template <field F1, field F2, char V> + static inline bool apply(mask_type const& mask) + { + return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask); + } +}; + +template <field F1, field F2, char V, bool InterruptEnabled, typename Mask> +inline bool interrupt(Mask const& mask) +{ + return interrupt_dispatch<Mask, InterruptEnabled> + ::template apply<F1, F2, V>(mask); +} + +// may_update() + +template <typename Mask> +struct may_update_dispatch +{ + template <field F1, field F2, char D, typename Matrix> + static inline bool apply(Mask const& mask, Matrix const& matrix) + { + BOOST_STATIC_ASSERT('0' <= D && D <= '9'); + + char const m = mask.template get<F1, F2>(); + + if ( m == 'F' ) + { + return true; + } + else if ( m == 'T' ) + { + char const c = matrix.template get<F1, F2>(); + return c == 'F'; // if it's T or between 0 and 9, the result will be the same + } + else if ( m >= '0' && m <= '9' ) + { + char const c = matrix.template get<F1, F2>(); + return D > c || c > '9'; + } + + return false; + } +}; + +template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value> +struct may_update_dispatch_tuple +{ + template <field F1, field F2, char D, typename Matrix> + static inline bool apply(Masks const& masks, Matrix const& matrix) + { + typedef typename boost::tuples::element<I, Masks>::type mask_type; + mask_type const& mask = boost::get<I>(masks); + return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix) + || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix); + } +}; + +template <typename Masks, int N> +struct may_update_dispatch_tuple<Masks, N, N> +{ + template <field F1, field F2, char D, typename Matrix> + static inline bool apply(Masks const& , Matrix const& ) + { + return false; + } +}; + +template <typename T0, typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, typename T9> +struct may_update_dispatch< 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> mask_type; + + template <field F1, field F2, char D, typename Matrix> + static inline bool apply(mask_type const& mask, Matrix const& matrix) + { + return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix); + } +}; + +template <typename Head, typename Tail> +struct may_update_dispatch< boost::tuples::cons<Head, Tail> > +{ + typedef boost::tuples::cons<Head, Tail> mask_type; + + template <field F1, field F2, char D, typename Matrix> + static inline bool apply(mask_type const& mask, Matrix const& matrix) + { + return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix); + } +}; + +template <field F1, field F2, char D, typename Mask, typename Matrix> +inline bool may_update(Mask const& mask, Matrix const& matrix) +{ + return may_update_dispatch<Mask> + ::template apply<F1, F2, D>(mask, matrix); +} + +// check() + +template <typename Mask> +struct check_dispatch +{ + template <typename Matrix> + static inline bool apply(Mask const& mask, Matrix const& matrix) + { + return per_one<interior, interior>(mask, matrix) + && per_one<interior, boundary>(mask, matrix) + && per_one<interior, exterior>(mask, matrix) + && per_one<boundary, interior>(mask, matrix) + && per_one<boundary, boundary>(mask, matrix) + && per_one<boundary, exterior>(mask, matrix) + && per_one<exterior, interior>(mask, matrix) + && per_one<exterior, boundary>(mask, matrix) + && per_one<exterior, exterior>(mask, matrix); + } + + template <field F1, field F2, typename Matrix> + static inline bool per_one(Mask const& mask, Matrix const& matrix) + { + const char mask_el = mask.template get<F1, F2>(); + const char el = matrix.template get<F1, F2>(); + + if ( mask_el == 'F' ) + { + return el == 'F'; + } + else if ( mask_el == 'T' ) + { + return el == 'T' || ( el >= '0' && el <= '9' ); + } + else if ( mask_el >= '0' && mask_el <= '9' ) + { + return el == mask_el; + } + + return true; + } +}; + +template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value> +struct check_dispatch_tuple +{ + template <typename Matrix> + static inline bool apply(Masks const& masks, Matrix const& matrix) + { + typedef typename boost::tuples::element<I, Masks>::type mask_type; + mask_type const& mask = boost::get<I>(masks); + return check_dispatch<mask_type>::apply(mask, matrix) + || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix); + } +}; + +template <typename Masks, int N> +struct check_dispatch_tuple<Masks, N, N> +{ + template <typename Matrix> + static inline bool apply(Masks const&, Matrix const&) + { + return false; + } +}; + +template <typename T0, typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, typename T9> +struct check_dispatch< 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> mask_type; + + template <typename Matrix> + static inline bool apply(mask_type const& mask, Matrix const& matrix) + { + return check_dispatch_tuple<mask_type>::apply(mask, matrix); + } +}; + +template <typename Head, typename Tail> +struct check_dispatch< boost::tuples::cons<Head, Tail> > +{ + typedef boost::tuples::cons<Head, Tail> mask_type; + + template <typename Matrix> + static inline bool apply(mask_type const& mask, Matrix const& matrix) + { + return check_dispatch_tuple<mask_type>::apply(mask, matrix); + } +}; + +template <typename Mask, typename Matrix> +inline bool check(Mask const& mask, Matrix const& matrix) +{ + return check_dispatch<Mask>::apply(mask, matrix); +} + +// matrix_width + +template <> +struct matrix_width<mask9> +{ + static const std::size_t value = 3; +}; + +template <typename Tuple, + int I = 0, + int N = boost::tuples::length<Tuple>::value> +struct matrix_width_tuple +{ + static const std::size_t + current = matrix_width<typename boost::tuples::element<I, Tuple>::type>::value; + static const std::size_t + next = matrix_width_tuple<Tuple, I+1>::value; + + static const std::size_t + value = current > next ? current : next; +}; + +template <typename Tuple, int N> +struct matrix_width_tuple<Tuple, N, N> +{ + static const std::size_t value = 0; +}; + +template <typename Head, typename Tail> +struct matrix_width< boost::tuples::cons<Head, Tail> > +{ + static const std::size_t + value = matrix_width_tuple< boost::tuples::cons<Head, Tail> >::value; +}; + +// matrix_handler + +template <typename Mask, bool Interrupt> +class mask_handler + : private matrix<matrix_width<Mask>::value> +{ + typedef matrix<matrix_width<Mask>::value> base_t; + +public: + typedef bool result_type; + + bool interrupt; + + inline mask_handler(Mask const& m) + : interrupt(false) + , m_mask(m) + {} + + result_type result() const + { + return !interrupt + && check(m_mask, static_cast<base_t const&>(*this)); + } + + template <field F1, field F2, char D> + inline bool may_update() const + { + return detail::relate::may_update<F1, F2, D>( + m_mask, static_cast<base_t const&>(*this) + ); + } + + //template <field F1, field F2> + //inline char get() const + //{ + // return static_cast<base_t const&>(*this).template get<F1, F2>(); + //} + + template <field F1, field F2, char V> + inline void set() + { + if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) + { + interrupt = true; + } + else + { + base_t::template set<F1, F2, V>(); + } + } + + template <field F1, field F2, char V> + inline void update() + { + if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) + { + interrupt = true; + } + else + { + base_t::template update<F1, F2, V>(); + } + } + +private: + Mask const& m_mask; +}; + +// STATIC MASKS + +// static_mask + +template <char II, char IB, char IE, + char BI, char BB, char BE, + char EI, char EB, char EE> +class static_mask +{ + typedef boost::mpl::vector_c + < + char, II, IB, IE, BI, BB, BE, EI, EB, EE + > vector_type; + +public: + template <field F1, field F2> + struct get + { + BOOST_STATIC_ASSERT(F1 * 3 + F2 < boost::mpl::size<vector_type>::value); + + static const char value + = boost::mpl::at_c<vector_type, F1 * 3 + F2>::type::value; + }; +}; + +// static_should_handle_element + +template <typename StaticMask, field F1, field F2, bool IsSequence> +struct static_should_handle_element_dispatch +{ + static const char mask_el = StaticMask::template get<F1, F2>::value; + static const bool value = mask_el == 'F' + || mask_el == 'T' + || ( mask_el >= '0' && mask_el <= '9' ); +}; + +template <typename First, typename Last, field F1, field F2> +struct static_should_handle_element_sequence +{ + typedef typename boost::mpl::deref<First>::type StaticMask; + + static const bool value + = static_should_handle_element_dispatch + < + StaticMask, + F1, F2, + boost::mpl::is_sequence<StaticMask>::value + >::value + || static_should_handle_element_sequence + < + typename boost::mpl::next<First>::type, + Last, + F1, F2 + >::value; +}; + +template <typename Last, field F1, field F2> +struct static_should_handle_element_sequence<Last, Last, F1, F2> +{ + static const bool value = false; +}; + +template <typename StaticMask, field F1, field F2> +struct static_should_handle_element_dispatch<StaticMask, F1, F2, true> +{ + static const bool value + = static_should_handle_element_sequence + < + typename boost::mpl::begin<StaticMask>::type, + typename boost::mpl::end<StaticMask>::type, + F1, F2 + >::value; +}; + +template <typename StaticMask, field F1, field F2> +struct static_should_handle_element +{ + static const bool value + = static_should_handle_element_dispatch + < + StaticMask, + F1, F2, + boost::mpl::is_sequence<StaticMask>::value + >::value; +}; + +// static_interrupt + +template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence> +struct static_interrupt_dispatch +{ + static const bool value = false; +}; + +template <typename StaticMask, char V, field F1, field F2, bool IsSequence> +struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence> +{ + static const char mask_el = StaticMask::template get<F1, F2>::value; + + static const bool value + = ( V >= '0' && V <= '9' ) ? + ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) : + ( ( V == 'T' ) ? mask_el == 'F' : false ); +}; + +template <typename First, typename Last, char V, field F1, field F2> +struct static_interrupt_sequence +{ + typedef typename boost::mpl::deref<First>::type StaticMask; + + static const bool value + = static_interrupt_dispatch + < + StaticMask, + V, F1, F2, + true, + boost::mpl::is_sequence<StaticMask>::value + >::value + && static_interrupt_sequence + < + typename boost::mpl::next<First>::type, + Last, + V, F1, F2 + >::value; +}; + +template <typename Last, char V, field F1, field F2> +struct static_interrupt_sequence<Last, Last, V, F1, F2> +{ + static const bool value = true; +}; + +template <typename StaticMask, char V, field F1, field F2> +struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true> +{ + static const bool value + = static_interrupt_sequence + < + typename boost::mpl::begin<StaticMask>::type, + typename boost::mpl::end<StaticMask>::type, + V, F1, F2 + >::value; +}; + +template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt> +struct static_interrupt +{ + static const bool value + = static_interrupt_dispatch + < + StaticMask, + V, F1, F2, + EnableInterrupt, + boost::mpl::is_sequence<StaticMask>::value + >::value; +}; + +// static_may_update + +template <typename StaticMask, char D, field F1, field F2, bool IsSequence> +struct static_may_update_dispatch +{ + static const char mask_el = StaticMask::template get<F1, F2>::value; + static const int version + = mask_el == 'F' ? 0 + : mask_el == 'T' ? 1 + : mask_el >= '0' && mask_el <= '9' ? 2 + : 3; + + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return apply_dispatch(matrix, integral_constant<int, version>()); + } + + // mask_el == 'F' + template <typename Matrix> + static inline bool apply_dispatch(Matrix const& , integral_constant<int, 0>) + { + return true; + } + // mask_el == 'T' + template <typename Matrix> + static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 1>) + { + char const c = matrix.template get<F1, F2>(); + return c == 'F'; // if it's T or between 0 and 9, the result will be the same + } + // mask_el >= '0' && mask_el <= '9' + template <typename Matrix> + static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 2>) + { + char const c = matrix.template get<F1, F2>(); + return D > c || c > '9'; + } + // else + template <typename Matrix> + static inline bool apply_dispatch(Matrix const&, integral_constant<int, 3>) + { + return false; + } +}; + +template <typename First, typename Last, char D, field F1, field F2> +struct static_may_update_sequence +{ + typedef typename boost::mpl::deref<First>::type StaticMask; + + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_may_update_dispatch + < + StaticMask, + D, F1, F2, + boost::mpl::is_sequence<StaticMask>::value + >::apply(matrix) + || static_may_update_sequence + < + typename boost::mpl::next<First>::type, + Last, + D, F1, F2 + >::apply(matrix); + } +}; + +template <typename Last, char D, field F1, field F2> +struct static_may_update_sequence<Last, Last, D, F1, F2> +{ + template <typename Matrix> + static inline bool apply(Matrix const& /*matrix*/) + { + return false; + } +}; + +template <typename StaticMask, char D, field F1, field F2> +struct static_may_update_dispatch<StaticMask, D, F1, F2, true> +{ + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_may_update_sequence + < + typename boost::mpl::begin<StaticMask>::type, + typename boost::mpl::end<StaticMask>::type, + D, F1, F2 + >::apply(matrix); + } +}; + +template <typename StaticMask, char D, field F1, field F2> +struct static_may_update +{ + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_may_update_dispatch + < + StaticMask, + D, F1, F2, + boost::mpl::is_sequence<StaticMask>::value + >::apply(matrix); + } +}; + +// static_check + +template <typename StaticMask, bool IsSequence> +struct static_check_dispatch +{ + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return per_one<interior, interior>::apply(matrix) + && per_one<interior, boundary>::apply(matrix) + && per_one<interior, exterior>::apply(matrix) + && per_one<boundary, interior>::apply(matrix) + && per_one<boundary, boundary>::apply(matrix) + && per_one<boundary, exterior>::apply(matrix) + && per_one<exterior, interior>::apply(matrix) + && per_one<exterior, boundary>::apply(matrix) + && per_one<exterior, exterior>::apply(matrix); + } + + template <field F1, field F2> + struct per_one + { + static const char mask_el = StaticMask::template get<F1, F2>::value; + static const int version + = mask_el == 'F' ? 0 + : mask_el == 'T' ? 1 + : mask_el >= '0' && mask_el <= '9' ? 2 + : 3; + + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + const char el = matrix.template get<F1, F2>(); + return apply_dispatch(el, integral_constant<int, version>()); + } + + // mask_el == 'F' + static inline bool apply_dispatch(char el, integral_constant<int, 0>) + { + return el == 'F'; + } + // mask_el == 'T' + static inline bool apply_dispatch(char el, integral_constant<int, 1>) + { + return el == 'T' || ( el >= '0' && el <= '9' ); + } + // mask_el >= '0' && mask_el <= '9' + static inline bool apply_dispatch(char el, integral_constant<int, 2>) + { + return el == mask_el; + } + // else + static inline bool apply_dispatch(char /*el*/, integral_constant<int, 3>) + { + return true; + } + }; +}; + +template <typename First, typename Last> +struct static_check_sequence +{ + typedef typename boost::mpl::deref<First>::type StaticMask; + + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_check_dispatch + < + StaticMask, + boost::mpl::is_sequence<StaticMask>::value + >::apply(matrix) + || static_check_sequence + < + typename boost::mpl::next<First>::type, + Last + >::apply(matrix); + } +}; + +template <typename Last> +struct static_check_sequence<Last, Last> +{ + template <typename Matrix> + static inline bool apply(Matrix const& /*matrix*/) + { + return false; + } +}; + +template <typename StaticMask> +struct static_check_dispatch<StaticMask, true> +{ + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_check_sequence + < + typename boost::mpl::begin<StaticMask>::type, + typename boost::mpl::end<StaticMask>::type + >::apply(matrix); + } +}; + +template <typename StaticMask> +struct static_check +{ + template <typename Matrix> + static inline bool apply(Matrix const& matrix) + { + return static_check_dispatch + < + StaticMask, + boost::mpl::is_sequence<StaticMask>::value + >::apply(matrix); + } +}; + +// static_mask_handler + +template <typename StaticMask, bool Interrupt> +class static_mask_handler + : private matrix<3> +{ + typedef matrix<3> base_t; + +public: + typedef bool result_type; + + bool interrupt; + + inline static_mask_handler(StaticMask const& /*dummy*/) + : interrupt(false) + {} + + result_type result() const + { + return (!Interrupt || !interrupt) + && static_check<StaticMask>:: + apply(static_cast<base_t const&>(*this)); + } + + template <field F1, field F2, char D> + inline bool may_update() const + { + return static_may_update<StaticMask, D, F1, F2>:: + apply(static_cast<base_t const&>(*this)); + } + + template <field F1, field F2> + static inline bool expects() + { + return static_should_handle_element<StaticMask, F1, F2>::value; + } + + //template <field F1, field F2> + //inline char get() const + //{ + // return base_t::template get<F1, F2>(); + //} + + template <field F1, field F2, char V> + inline void set() + { + static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; + static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; + static const int version = interrupt_c ? 0 + : should_handle ? 1 + : 2; + + set_dispatch<F1, F2, V>(integral_constant<int, version>()); + } + + template <field F1, field F2, char V> + inline void update() + { + static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; + static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; + static const int version = interrupt_c ? 0 + : should_handle ? 1 + : 2; + + update_dispatch<F1, F2, V>(integral_constant<int, version>()); + } + +private: + // Interrupt && interrupt + template <field F1, field F2, char V> + inline void set_dispatch(integral_constant<int, 0>) + { + interrupt = true; + } + // else should_handle + template <field F1, field F2, char V> + inline void set_dispatch(integral_constant<int, 1>) + { + base_t::template set<F1, F2, V>(); + } + // else + template <field F1, field F2, char V> + inline void set_dispatch(integral_constant<int, 2>) + {} + + // Interrupt && interrupt + template <field F1, field F2, char V> + inline void update_dispatch(integral_constant<int, 0>) + { + interrupt = true; + } + // else should_handle + template <field F1, field F2, char V> + inline void update_dispatch(integral_constant<int, 1>) + { + base_t::template update<F1, F2, V>(); + } + // else + template <field F1, field F2, char V> + inline void update_dispatch(integral_constant<int, 2>) + {} +}; + +// OPERATORS + +template <typename Mask1, typename Mask2> inline +boost::tuples::cons< + Mask1, + boost::tuples::cons<Mask2, boost::tuples::null_type> +> +operator||(Mask1 const& m1, Mask2 const& m2) +{ + namespace bt = boost::tuples; + + return + bt::cons< Mask1, bt::cons<Mask2, bt::null_type> > + ( m1, bt::cons<Mask2, bt::null_type>(m2, bt::null_type()) ); +} + +template <typename Head, typename Tail, typename Mask> inline +typename index::detail::tuples::push_back< + boost::tuples::cons<Head, Tail>, Mask +>::type +operator||(boost::tuples::cons<Head, Tail> const& t, Mask const& m) +{ + namespace bt = boost::tuples; + + return + index::detail::tuples::push_back< + bt::cons<Head, Tail>, Mask + >::apply(t, m); +} + +// PREDEFINED MASKS + +// TODO: +// 1. specialize for simplified masks if available +// e.g. for TOUCHES use 1 mask for A/A +// 2. Think about dimensions > 2 e.g. should TOUCHES be true +// if the interior of the Areal overlaps the boundary of the Volumetric +// like it's true for Linear/Areal + +// EQUALS +template <typename Geometry1, typename Geometry2> +struct static_mask_equals_type +{ + typedef static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia + //typedef static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC +}; + +// DISJOINT +typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_disjoint; + +// TOUCHES - NOT P/P +template <typename Geometry1, + typename Geometry2, + std::size_t Dim1 = topological_dimension<Geometry1>::value, + std::size_t Dim2 = topological_dimension<Geometry2>::value> +struct static_mask_touches_impl +{ + typedef boost::mpl::vector< + static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>, + static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>, + static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'> + > type; +}; +// According to OGC, doesn't apply to P/P +// Using the above mask the result would be always false +template <typename Geometry1, typename Geometry2> +struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0> + : not_implemented<typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type> +{}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_touches_type + : static_mask_touches_impl<Geometry1, Geometry2> +{}; + +// WITHIN +typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within; + +// COVERED_BY (non OGC) +typedef boost::mpl::vector< + static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>, + static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>, + static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>, + static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'> + > static_mask_covered_by; + +// CROSSES +// dim(G1) < dim(G2) - P/L P/A L/A +template <typename Geometry1, + typename Geometry2, + std::size_t Dim1 = topological_dimension<Geometry1>::value, + std::size_t Dim2 = topological_dimension<Geometry2>::value, + bool D1LessD2 = (Dim1 < Dim2) +> +struct static_mask_crosses_impl +{ + typedef static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type; +}; +// TODO: I'm not sure if this one below should be available! +// dim(G1) > dim(G2) - L/P A/P A/L +template <typename Geometry1, typename Geometry2, + std::size_t Dim1, std::size_t Dim2 +> +struct static_mask_crosses_impl<Geometry1, Geometry2, Dim1, Dim2, false> +{ + typedef static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type; +}; +// dim(G1) == dim(G2) - P/P A/A +template <typename Geometry1, typename Geometry2, + std::size_t Dim +> +struct static_mask_crosses_impl<Geometry1, Geometry2, Dim, Dim, false> + : not_implemented<typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type> +{}; +// dim(G1) == 1 && dim(G2) == 1 - L/L +template <typename Geometry1, typename Geometry2> +struct static_mask_crosses_impl<Geometry1, Geometry2, 1, 1, false> +{ + typedef static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type; +}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_crosses_type + : static_mask_crosses_impl<Geometry1, Geometry2> +{}; + +// OVERLAPS + +// dim(G1) != dim(G2) - NOT P/P, L/L, A/A +template <typename Geometry1, + typename Geometry2, + std::size_t Dim1 = topological_dimension<Geometry1>::value, + std::size_t Dim2 = topological_dimension<Geometry2>::value +> +struct static_mask_overlaps_impl + : not_implemented<typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type> +{}; +// dim(G1) == D && dim(G2) == D - P/P A/A +template <typename Geometry1, typename Geometry2, std::size_t Dim> +struct static_mask_overlaps_impl<Geometry1, Geometry2, Dim, Dim> +{ + typedef static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; +}; +// dim(G1) == 1 && dim(G2) == 1 - L/L +template <typename Geometry1, typename Geometry2> +struct static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1> +{ + typedef static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; +}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_overlaps_type + : static_mask_overlaps_impl<Geometry1, Geometry2> +{}; + +// RESULTS/HANDLERS UTILS + +template <field F1, field F2, char V, typename Result> +inline void set(Result & res) +{ + res.template set<F1, F2, V>(); +} + +template <field F1, field F2, char V, bool Transpose> +struct set_dispatch +{ + template <typename Result> + static inline void apply(Result & res) + { + res.template set<F1, F2, V>(); + } +}; + +template <field F1, field F2, char V> +struct set_dispatch<F1, F2, V, true> +{ + template <typename Result> + static inline void apply(Result & res) + { + res.template set<F2, F1, V>(); + } +}; + +template <field F1, field F2, char V, bool Transpose, typename Result> +inline void set(Result & res) +{ + set_dispatch<F1, F2, V, Transpose>::apply(res); +} + +template <char V, typename Result> +inline void set(Result & res) +{ + res.template set<interior, interior, V>(); + res.template set<interior, boundary, V>(); + res.template set<interior, exterior, V>(); + res.template set<boundary, interior, V>(); + res.template set<boundary, boundary, V>(); + res.template set<boundary, exterior, V>(); + res.template set<exterior, interior, V>(); + res.template set<exterior, boundary, V>(); + res.template set<exterior, exterior, V>(); +} + +template <char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE, typename Result> +inline void set(Result & res) +{ + res.template set<interior, interior, II>(); + res.template set<interior, boundary, IB>(); + res.template set<interior, exterior, IE>(); + res.template set<boundary, interior, BI>(); + res.template set<boundary, boundary, BB>(); + res.template set<boundary, exterior, BE>(); + res.template set<exterior, interior, EI>(); + res.template set<exterior, boundary, EB>(); + res.template set<exterior, exterior, EE>(); +} + +template <field F1, field F2, char D, typename Result> +inline void update(Result & res) +{ + res.template update<F1, F2, D>(); +} + +template <field F1, field F2, char D, bool Transpose> +struct update_result_dispatch +{ + template <typename Result> + static inline void apply(Result & res) + { + update<F1, F2, D>(res); + } +}; + +template <field F1, field F2, char D> +struct update_result_dispatch<F1, F2, D, true> +{ + template <typename Result> + static inline void apply(Result & res) + { + update<F2, F1, D>(res); + } +}; + +template <field F1, field F2, char D, bool Transpose, typename Result> +inline void update(Result & res) +{ + update_result_dispatch<F1, F2, D, Transpose>::apply(res); +} + +template <field F1, field F2, char D, typename Result> +inline bool may_update(Result const& res) +{ + return res.template may_update<F1, F2, D>(); +} + +template <field F1, field F2, char D, bool Transpose> +struct may_update_result_dispatch +{ + template <typename Result> + static inline bool apply(Result const& res) + { + return may_update<F1, F2, D>(res); + } +}; + +template <field F1, field F2, char D> +struct may_update_result_dispatch<F1, F2, D, true> +{ + template <typename Result> + static inline bool apply(Result const& res) + { + return may_update<F2, F1, D>(res); + } +}; + +template <field F1, field F2, char D, bool Transpose, typename Result> +inline bool may_update(Result const& res) +{ + return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res); +} + +template <typename Result, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE> +inline Result return_result() +{ + Result res; + set<II, IB, IE, BI, BB, BE, EI, EB, EE>(res); + return res; +} + +template <typename Geometry> +struct result_dimension +{ + BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0); + static const char value + = ( geometry::dimension<Geometry>::value <= 9 ) ? + ( '0' + geometry::dimension<Geometry>::value ) : + 'T'; +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp new file mode 100644 index 0000000000..98b857a488 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp @@ -0,0 +1,241 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/policies/compare.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +// TODO: change the name for e.g. something with the word "exterior" + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type> +struct topology_check + : not_implemented<Tag> +{}; + +//template <typename Point> +//struct topology_check<Point, point_tag> +//{ +// static const char interior = '0'; +// static const char boundary = 'F'; +// +// static const bool has_interior = true; +// static const bool has_boundary = false; +// +// topology_check(Point const&) {} +// template <typename IgnoreBoundaryPoint> +// topology_check(Point const&, IgnoreBoundaryPoint const&) {} +//}; + +template <typename Linestring> +struct topology_check<Linestring, linestring_tag> +{ + static const char interior = '1'; + static const char boundary = '0'; + + bool has_interior; + bool has_boundary; + + topology_check(Linestring const& ls) + { + init(ls, 0); /*dummy param*/ + } + + template <typename IgnoreBoundaryPoint> + topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp) + { + init(ls, ibp); /*dummy param, won't be used*/ + } + + // Even if some point is on the boundary, if the Linestring has the boundary, + // there will be second boundary point different than IgnoreBoundaryPoint + template <typename IgnoreBoundaryPoint> + void init(Linestring const& ls, IgnoreBoundaryPoint const&) + { + std::size_t count = boost::size(ls); + has_interior = count > 0; + // NOTE: Linestring with all points equal is treated as 1d linear ring + has_boundary = count > 1 + && ! detail::equals::equals_point_point(range::front(ls), range::back(ls)); + } +}; + +template <typename MultiLinestring> +struct topology_check<MultiLinestring, multi_linestring_tag> +{ + static const char interior = '1'; + static const char boundary = '0'; + + bool has_interior; + bool has_boundary; + + topology_check(MultiLinestring const& mls) + { + init(mls, not_ignoring_counter()); + } + + template <typename IgnoreBoundaryPoint> + topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp) + { + init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp)); + } + + template <typename OddCounter> + void init(MultiLinestring const& mls, OddCounter const& odd_counter) + { + typedef typename geometry::point_type<MultiLinestring>::type point_type; + std::vector<point_type> endpoints; + endpoints.reserve(boost::size(mls) * 2); + + typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator; + for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it ) + { + std::size_t count = boost::size(*it); + + if ( count > 0 ) + { + has_interior = true; + } + + if ( count > 1 ) + { + // don't store boundaries of linear rings, this doesn't change anything + if ( ! equals::equals_point_point(range::front(*it), range::back(*it)) ) + { + endpoints.push_back(range::front(*it)); + endpoints.push_back(range::back(*it)); + } + } + } + + has_boundary = false; + + if ( !endpoints.empty() ) + { + std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>()); + has_boundary = odd_counter(endpoints.begin(), endpoints.end()); + } + } + + struct not_ignoring_counter + { + template <typename It> + bool operator()(It first, It last) const + { + return find_odd_count(first, last); + } + }; + + template <typename Point> + struct ignoring_counter + { + ignoring_counter(Point const& pt) : m_pt(pt) {} + + template <typename It> + bool operator()(It first, It last) const + { + typedef typename std::iterator_traits<It>::value_type point_type; + + std::pair<It, It> ignore_range + = std::equal_range(first, last, m_pt, + geometry::less<point_type>()); + + if ( find_odd_count(first, ignore_range.first) ) + return true; + + return find_odd_count(ignore_range.second, last); + } + + Point const& m_pt; + }; + + template <typename It> + static inline bool find_odd_count(It first, It last) + { + if ( first == last ) + return false; + + std::size_t count = 1; + It prev = first; + ++first; + for ( ; first != last ; ++first, ++prev ) + { + // the end of the equal points subrange + if ( ! equals::equals_point_point(*first, *prev) ) + { + if ( count % 2 != 0 ) + return true; + + count = 1; + } + else + { + ++count; + } + } + + return count % 2 != 0; + } +}; + +template <typename Ring> +struct topology_check<Ring, ring_tag> +{ + static const char interior = '2'; + static const char boundary = '1'; + static const bool has_interior = true; + static const bool has_boundary = true; + + topology_check(Ring const&) {} + template <typename P> + topology_check(Ring const&, P const&) {} +}; + +template <typename Polygon> +struct topology_check<Polygon, polygon_tag> +{ + static const char interior = '2'; + static const char boundary = '1'; + static const bool has_interior = true; + static const bool has_boundary = true; + + topology_check(Polygon const&) {} + template <typename P> + topology_check(Polygon const&, P const&) {} +}; + +template <typename MultiPolygon> +struct topology_check<MultiPolygon, multi_polygon_tag> +{ + static const char interior = '2'; + static const char boundary = '1'; + static const bool has_interior = true; + static const bool has_boundary = true; + + topology_check(MultiPolygon const&) {} + template <typename P> + topology_check(MultiPolygon const&, P const&) {} +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp new file mode 100644 index 0000000000..a2e56a8882 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/turns.hpp @@ -0,0 +1,253 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> + +#include <boost/type_traits/is_base_of.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { namespace turns { + +template <bool IncludeDegenerate = false> +struct assign_policy + : overlay::assign_null_policy +{ + static bool const include_degenerate = IncludeDegenerate; +}; + +// GET_TURNS + +template <typename Geometry1, + typename Geometry2, + typename GetTurnPolicy + = detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > > +struct get_turns +{ + typedef typename geometry::point_type<Geometry1>::type point1_type; + + typedef overlay::turn_info + < + point1_type, + typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type, + typename detail::get_turns::turn_operation_type + < + Geometry1, Geometry2, + typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type + >::type + > turn_info; + + template <typename Turns> + static inline void apply(Turns & turns, + Geometry1 const& geometry1, + Geometry2 const& geometry2) + { + detail::get_turns::no_interrupt_policy interrupt_policy; + + apply(turns, geometry1, geometry2, interrupt_policy); + } + + template <typename Turns, typename InterruptPolicy> + static inline void apply(Turns & turns, + Geometry1 const& geometry1, + Geometry2 const& geometry2, + InterruptPolicy & interrupt_policy) + { + static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; + static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value; + + dispatch::get_turns + < + typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type, + Geometry1, + Geometry2, + reverse1, + reverse2, + GetTurnPolicy + >::apply(0, geometry1, 1, geometry2, + detail::no_rescale_policy(), turns, interrupt_policy); + } +}; + +// TURNS SORTING AND SEARCHING + +template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0> +struct op_to_int +{ + template <typename SegmentRatio> + inline int operator()(detail::overlay::turn_operation<SegmentRatio> const& op) const + { + switch(op.operation) + { + case detail::overlay::operation_none : return N; + case detail::overlay::operation_union : return U; + case detail::overlay::operation_intersection : return I; + case detail::overlay::operation_blocked : return B; + case detail::overlay::operation_continue : return C; + case detail::overlay::operation_opposite : return O; + } + return -1; + } +}; + +template <std::size_t OpId, typename OpToInt> +struct less_op_xxx_linear +{ + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + static OpToInt op_to_int; + return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]); + } +}; + +template <std::size_t OpId> +struct less_op_linear_linear + : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> > +{}; + +template <std::size_t OpId> +struct less_op_linear_areal +{ + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + static const std::size_t other_op_id = (OpId + 1) % 2; + static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic; + static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc; + + segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; + segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; + + if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index ) + { + typedef typename Turn::turn_operation_type operation_type; + operation_type const& left_operation = left.operations[OpId]; + operation_type const& right_operation = right.operations[OpId]; + + if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index ) + { + return op_to_int_xuic(left_operation) + < op_to_int_xuic(right_operation); + } + else + { + return op_to_int_xiuc(left_operation) + < op_to_int_xiuc(right_operation); + } + } + else + { + //return op_to_int_xuic(left.operations[OpId]) < op_to_int_xuic(right.operations[OpId]); + return left_other_seg_id.multi_index < right_other_seg_id.multi_index; + } + } +}; + +template <std::size_t OpId> +struct less_op_areal_linear + : less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> > +{}; + +template <std::size_t OpId> +struct less_op_areal_areal +{ + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + static const std::size_t other_op_id = (OpId + 1) % 2; + static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc; + static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc; + + segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; + segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; + + typedef typename Turn::turn_operation_type operation_type; + operation_type const& left_operation = left.operations[OpId]; + operation_type const& right_operation = right.operations[OpId]; + + if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index ) + { + if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index ) + { + return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation); + } + else + { + if ( left_other_seg_id.ring_index == -1 ) + { + if ( left_operation.operation == overlay::operation_union ) + return false; + else if ( left_operation.operation == overlay::operation_intersection ) + return true; + } + else if ( right_other_seg_id.ring_index == -1 ) + { + if ( right_operation.operation == overlay::operation_union ) + return true; + else if ( right_operation.operation == overlay::operation_intersection ) + return false; + } + + return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation); + } + } + else + { + return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation); + } + } +}; + +// sort turns by G1 - source_index == 0 by: +// seg_id -> distance -> operation +template <std::size_t OpId = 0, + typename LessOp = less_op_xxx_linear< OpId, op_to_int<> > > +struct less +{ + BOOST_STATIC_ASSERT(OpId < 2); + + template <typename Turn> + static inline bool use_fraction(Turn const& left, Turn const& right) + { + static LessOp less_op; + + return left.operations[OpId].fraction < right.operations[OpId].fraction + || ( left.operations[OpId].fraction == right.operations[OpId].fraction + && less_op(left, right) ); + } + + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + segment_identifier const& sl = left.operations[OpId].seg_id; + segment_identifier const& sr = right.operations[OpId].seg_id; + + return sl < sr || ( sl == sr && use_fraction(left, right) ); + } +}; + +}}} // namespace detail::relate::turns +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/ring_identifier.hpp b/boost/geometry/algorithms/detail/ring_identifier.hpp index 9209ee0304..bc3fe1fef3 100644 --- a/boost/geometry/algorithms/detail/ring_identifier.hpp +++ b/boost/geometry/algorithms/detail/ring_identifier.hpp @@ -10,6 +10,14 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP +#if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER) +#include <iostream> +#endif + + +#include <boost/geometry/algorithms/detail/signed_index_type.hpp> + + namespace boost { namespace geometry { @@ -24,7 +32,9 @@ struct ring_identifier , ring_index(-1) {} - inline ring_identifier(int src, int mul, int rin) + inline ring_identifier(signed_index_type src, + signed_index_type mul, + signed_index_type rin) : source_index(src) , multi_index(mul) , ring_index(rin) @@ -58,9 +68,9 @@ struct ring_identifier #endif - int source_index; - int multi_index; - int ring_index; + signed_index_type source_index; + signed_index_type multi_index; + signed_index_type ring_index; }; diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp index ad62f232bd..63feb12a71 100644 --- a/boost/geometry/algorithms/detail/sections/range_by_section.hpp +++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp @@ -7,14 +7,19 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP - +#include <boost/assert.hpp> #include <boost/mpl/assert.hpp> #include <boost/range.hpp> @@ -22,7 +27,10 @@ #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/tags.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -50,7 +58,29 @@ struct full_section_polygon { return section.ring_id.ring_index < 0 ? geometry::exterior_ring(polygon) - : geometry::interior_rings(polygon)[section.ring_id.ring_index]; + : range::at(geometry::interior_rings(polygon), section.ring_id.ring_index); + } +}; + + +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(range::at(multi, section.ring_id.multi_index), section); } }; @@ -98,6 +128,35 @@ struct range_by_section<polygon_tag, Polygon, Section> {}; +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 + > + > +{}; + +template <typename MultiLinestring, typename Section> +struct range_by_section<multi_linestring_tag, MultiLinestring, Section> + : detail::section::full_section_multi + < + MultiLinestring, + Section, + detail::section::full_section_range + < + typename boost::range_value<MultiLinestring>::type, + Section + > + > +{}; + + } // namespace dispatch #endif diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp index a6e6837fe4..250577c0c2 100644 --- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -3,6 +3,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,33 +15,39 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP #include <cstddef> #include <vector> +#include <boost/concept/requires.hpp> #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/interior_iterator.hpp> +#include <boost/geometry/algorithms/detail/recalculate.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/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/math.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.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 { @@ -71,6 +81,9 @@ struct section bool duplicate; int non_duplicate_index; + bool is_non_duplicate_first; + bool is_non_duplicate_last; + inline section() : id(-1) , begin_index(-1) @@ -79,9 +92,11 @@ struct section , range_count(0) , duplicate(false) , non_duplicate_index(-1) + , is_non_duplicate_first(false) + , is_non_duplicate_last(false) { assign_inverse(bounding_box); - for (register std::size_t i = 0; i < DimensionCount; i++) + for (std::size_t i = 0; i < DimensionCount; i++) { directions[i] = 0; } @@ -107,14 +122,14 @@ struct sections : std::vector<section<Box, DimensionCount> > namespace detail { namespace sectionalize { -template <typename Segment, std::size_t Dimension, std::size_t DimensionCount> +template <std::size_t Dimension, std::size_t DimensionCount> struct get_direction_loop { - typedef typename coordinate_type<Segment>::type coordinate_type; - + template <typename Segment> static inline void apply(Segment const& seg, int directions[DimensionCount]) { + typedef typename coordinate_type<Segment>::type coordinate_type; coordinate_type const diff = geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg); @@ -123,14 +138,15 @@ struct get_direction_loop get_direction_loop < - Segment, Dimension + 1, DimensionCount + Dimension + 1, DimensionCount >::apply(seg, directions); } }; -template <typename Segment, std::size_t DimensionCount> -struct get_direction_loop<Segment, DimensionCount, DimensionCount> +template <std::size_t DimensionCount> +struct get_direction_loop<DimensionCount, DimensionCount> { + template <typename Segment> static inline void apply(Segment const&, int [DimensionCount]) {} }; @@ -182,16 +198,15 @@ struct compare_loop<T, DimensionCount, DimensionCount> }; -template <typename Segment, std::size_t Dimension, std::size_t DimensionCount> +template <std::size_t Dimension, std::size_t DimensionCount> struct check_duplicate_loop { - typedef typename coordinate_type<Segment>::type coordinate_type; - + template <typename Segment> static inline bool apply(Segment const& seg) { if (! geometry::math::equals ( - geometry::get<0, Dimension>(seg), + geometry::get<0, Dimension>(seg), geometry::get<1, Dimension>(seg) ) ) @@ -201,14 +216,15 @@ struct check_duplicate_loop return check_duplicate_loop < - Segment, Dimension + 1, DimensionCount + Dimension + 1, DimensionCount >::apply(seg); } }; -template <typename Segment, std::size_t DimensionCount> -struct check_duplicate_loop<Segment, DimensionCount, DimensionCount> +template <std::size_t DimensionCount> +struct check_duplicate_loop<DimensionCount, DimensionCount> { + template <typename Segment> static inline bool apply(Segment const&) { return true; @@ -236,48 +252,62 @@ struct assign_loop<T, DimensionCount, DimensionCount> /// @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 + std::size_t DimensionCount > struct sectionalize_part { - typedef model::referring_segment<Point const> segment_type; - typedef typename boost::range_value<Sections>::type section_type; + template + < + typename Range, // Can be closeable_view + typename RobustPolicy, + typename Sections + > + static inline void apply(Sections& sections, + Range const& range, + RobustPolicy const& robust_policy, + bool make_rescaled_boxes, + ring_identifier ring_id, + std::size_t max_count) + { + boost::ignore_unused_variable_warning(robust_policy); + boost::ignore_unused_variable_warning(make_rescaled_boxes); - typedef typename boost::range_iterator<Range const>::type iterator_type; + typedef model::referring_segment<Point const> segment_type; + typedef typename boost::range_value<Sections>::type section_type; + typedef model::segment + < + typename robust_point_type<Point, RobustPolicy>::type + > robust_segment_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) + if ( boost::empty(range) ) { return; } - if (index == 0) - { - ndi = 0; - } + int index = 0; + int ndi = 0; // non duplicate index + section_type section; - iterator_type it = boost::begin(range); - it += index; + bool mark_first_non_duplicated = true; + std::size_t last_non_duplicate_index = sections.size(); + iterator_type it = boost::begin(range); + for(iterator_type previous = it++; it != boost::end(range); ++previous, ++it, index++) { segment_type segment(*previous, *it); + robust_segment_type robust_segment; + geometry::recalculate(robust_segment, segment, robust_policy); int direction_classes[DimensionCount] = {0}; get_direction_loop < - segment_type, 0, DimensionCount - >::apply(segment, direction_classes); + 0, DimensionCount + >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. // Those sections might be omitted, if wished, lateron @@ -290,8 +320,8 @@ struct sectionalize_part // (DimensionCount might be < dimension<P>::value) if (check_duplicate_loop < - segment_type, 0, geometry::dimension<Point>::type::value - >::apply(segment) + 0, geometry::dimension<Point>::type::value + >::apply(robust_segment) ) { duplicate = true; @@ -312,10 +342,15 @@ struct sectionalize_part < int, 0, DimensionCount >::apply(direction_classes, section.directions) - || section.count > MaxCount + || section.count > max_count ) ) { + if ( !section.duplicate ) + { + last_non_duplicate_index = sections.size(); + } + sections.push_back(section); section = section_type(); } @@ -328,14 +363,21 @@ struct sectionalize_part section.non_duplicate_index = ndi; section.range_count = boost::size(range); + if ( mark_first_non_duplicated && !duplicate ) + { + section.is_non_duplicate_first = true; + mark_first_non_duplicated = false; + } + copy_loop < int, 0, DimensionCount >::apply(direction_classes, section.directions); - geometry::expand(section.bounding_box, *previous); + + expand_box(*previous, robust_policy, section); } - geometry::expand(section.bounding_box, *it); + expand_box(*it, robust_policy, section); section.end_index = index + 1; section.count++; if (! duplicate) @@ -343,20 +385,58 @@ struct sectionalize_part ndi++; } } + + // Add last section if applicable + if (section.count > 0) + { + if ( !section.duplicate ) + { + last_non_duplicate_index = sections.size(); + } + + sections.push_back(section); + } + + if ( last_non_duplicate_index < sections.size() + && !sections[last_non_duplicate_index].duplicate ) + { + sections[last_non_duplicate_index].is_non_duplicate_last = true; + } + } + + template <typename InputPoint, typename RobustPolicy, typename Section> + static inline void expand_box(InputPoint const& point, + RobustPolicy const& robust_policy, + Section& section) + { + typename geometry::point_type<typename Section::box_type>::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + geometry::expand(section.bounding_box, robust_point); } }; template < - typename Range, closure_selector Closure, bool Reverse, + closure_selector Closure, bool Reverse, typename Point, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > struct sectionalize_range { + template + < + typename Range, + typename RobustPolicy, + typename Sections + > + static inline void apply(Range const& range, + RobustPolicy const& robust_policy, + bool make_rescaled_boxes, + Sections& sections, + ring_identifier ring_id, + std::size_t max_count) + { typedef typename closeable_view<Range const, Closure>::type cview_type; typedef typename reversible_view < @@ -364,11 +444,6 @@ struct sectionalize_range 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); @@ -385,72 +460,69 @@ struct sectionalize_range 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); - } + sectionalize_part<Point, DimensionCount> + ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count); } }; template < - typename Polygon, bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > struct sectionalize_polygon { - static inline void apply(Polygon const& poly, Sections& sections, - ring_identifier ring_id) + template + < + typename Polygon, + typename RobustPolicy, + typename Sections + > + static inline void apply(Polygon const& poly, + RobustPolicy const& robust_policy, + bool make_rescaled_boxes, + Sections& sections, + ring_identifier ring_id, std::size_t max_count) { typedef typename point_type<Polygon>::type point_type; - typedef typename ring_type<Polygon>::type ring_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; + closure<Polygon>::value, Reverse, + point_type, DimensionCount + > per_range; ring_id.ring_index = -1; - sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index); + per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count); 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(poly); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index) { - sectionalizer_type::apply(*it, sections, ring_id); + per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); } } }; template < - typename Box, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > struct sectionalize_box { - static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id) + template + < + typename Box, + typename RobustPolicy, + typename Sections + > + static inline void apply(Box const& box, + RobustPolicy const& robust_policy, + bool make_rescaled_boxes, + Sections& sections, + ring_identifier const& ring_id, std::size_t max_count) { typedef typename point_type<Box>::type point_type; @@ -462,7 +534,7 @@ struct sectionalize_box // (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 + // 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); @@ -476,12 +548,36 @@ struct sectionalize_box sectionalize_range < - std::vector<point_type>, closed, false, + closed, false, point_type, - Sections, - DimensionCount, - MaxCount - >::apply(points, sections, ring_id); + DimensionCount + >::apply(points, robust_policy, make_rescaled_boxes, sections, + ring_id, max_count); + } +}; + +template <std::size_t DimensionCount, typename Policy> +struct sectionalize_multi +{ + template + < + typename MultiGeometry, + typename RobustPolicy, + typename Sections + > + static inline void apply(MultiGeometry const& multi, + RobustPolicy const& robust_policy, + bool make_rescaled_boxes, + Sections& sections, ring_identifier ring_id, std::size_t max_count) + { + 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, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); + } } }; @@ -498,6 +594,29 @@ inline void set_section_unique_ids(Sections& sections) } } +template <typename Sections> +inline void enlarge_sections(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 @@ -512,9 +631,7 @@ template typename Tag, typename Geometry, bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > struct sectionalize { @@ -529,43 +646,29 @@ template < typename Box, bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > -struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount> - : detail::sectionalize::sectionalize_box - < - Box, - Sections, - DimensionCount, - MaxCount - > +struct sectionalize<box_tag, Box, Reverse, DimensionCount> + : detail::sectionalize::sectionalize_box<DimensionCount> {}; template < typename LineString, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > struct sectionalize < linestring_tag, LineString, false, - Sections, - DimensionCount, - MaxCount + DimensionCount > : detail::sectionalize::sectionalize_range < - LineString, closed, false, + closed, false, typename point_type<LineString>::type, - Sections, - DimensionCount, - MaxCount + DimensionCount > {}; @@ -573,18 +676,14 @@ template < typename Ring, bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > -struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount> +struct sectionalize<ring_tag, Ring, Reverse, DimensionCount> : detail::sectionalize::sectionalize_range < - Ring, geometry::closure<Ring>::value, Reverse, + geometry::closure<Ring>::value, Reverse, typename point_type<Ring>::type, - Sections, - DimensionCount, - MaxCount + DimensionCount > {}; @@ -592,17 +691,54 @@ template < typename Polygon, bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount + std::size_t DimensionCount > -struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount> +struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount> : detail::sectionalize::sectionalize_polygon < - Polygon, Reverse, Sections, DimensionCount, MaxCount + Reverse, DimensionCount > {}; +template +< + typename MultiPolygon, + bool Reverse, + std::size_t DimensionCount +> +struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount> + : detail::sectionalize::sectionalize_multi + < + DimensionCount, + detail::sectionalize::sectionalize_polygon + < + Reverse, + DimensionCount + > + > + +{}; + +template +< + typename MultiLinestring, + bool Reverse, + std::size_t DimensionCount +> +struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount> + : detail::sectionalize::sectionalize_multi + < + DimensionCount, + detail::sectionalize::sectionalize_range + < + closed, false, + typename point_type<MultiLinestring>::type, + DimensionCount + > + > + +{}; + } // namespace dispatch #endif @@ -613,33 +749,55 @@ struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, Max \tparam Geometry type of geometry to check \tparam Sections type of sections to create \param geometry geometry to create sections from + \param robust_policy policy to handle robustness issues + \param enlarge_secion_boxes if true, boxes are enlarged a tiny bit to be sure + they really contain all geometries (w.r.t. robustness) \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) +template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy> +inline void sectionalize(Geometry const& geometry, + RobustPolicy const& robust_policy, + bool enlarge_secion_boxes, + 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 + sections.clear(); + + ring_identifier ring_id; + ring_id.source_index = source_index; + // 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 + dispatch::sectionalize < typename tag<Geometry>::type, Geometry, Reverse, - Sections, - Sections::value, - 10 // TODO: max_segments_per_section - > sectionalizer_type; + Sections::value + >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10); - 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); + if (! enlarge_secion_boxes) + { + detail::sectionalize::enlarge_sections(sections); + } +} + + +#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE) +// Backwards compatibility +template<bool Reverse, typename Geometry, typename Sections> +inline void sectionalize(Geometry const& geometry, + Sections& sections, + int source_index = 0) +{ + return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(), + false, sections, + source_index); } +#endif }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/signed_index_type.hpp b/boost/geometry/algorithms/detail/signed_index_type.hpp new file mode 100644 index 0000000000..36dcf4de4c --- /dev/null +++ b/boost/geometry/algorithms/detail/signed_index_type.hpp @@ -0,0 +1,29 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_SIGNED_INDEX_TYPE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP + + +#include <cstddef> +#include <boost/type_traits/make_signed.hpp> + + +namespace boost { namespace geometry +{ + + +typedef boost::make_signed<std::size_t>::type signed_index_type; +//typedef std::ptrdiff_t signed_index_type; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP diff --git a/boost/geometry/algorithms/detail/single_geometry.hpp b/boost/geometry/algorithms/detail/single_geometry.hpp new file mode 100644 index 0000000000..c65ff8bf84 --- /dev/null +++ b/boost/geometry/algorithms/detail/single_geometry.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP + +#include <boost/type_traits/is_base_of.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/util/range.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { + +// Returns single geometry by Id +// for single geometries returns the geometry itself +template <typename Geometry, + bool IsMulti = boost::is_base_of + < + multi_tag, + typename geometry::tag<Geometry>::type + >::value +> +struct single_geometry +{ + typedef Geometry & return_type; + + template <typename Id> + static inline return_type apply(Geometry & g, Id const& ) { return g; } +}; + +// for multi geometries returns one of the stored single geometries +template <typename Geometry> +struct single_geometry<Geometry, true> +{ + typedef typename boost::mpl::if_c + < + boost::is_const<Geometry>::value, + typename boost::range_value<Geometry>::type const&, + typename boost::range_value<Geometry>::type + >::type return_type; + + template <typename Id> + static inline return_type apply(Geometry & g, Id const& id) + { + BOOST_ASSERT(id.multi_index >= 0); + return range::at(g, id.multi_index); + } +}; + +} // namespace detail_dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { + +template <typename Geometry> +struct single_geometry_return_type +{ + typedef typename detail_dispatch::single_geometry<Geometry>::return_type type; +}; + +template <typename Geometry, typename Id> +inline +typename single_geometry_return_type<Geometry>::type +single_geometry(Geometry & geometry, Id const& id) +{ + return detail_dispatch::single_geometry<Geometry>::apply(geometry, id); +} + +template <typename Geometry, typename Id> +inline +typename single_geometry_return_type<Geometry const>::type +single_geometry(Geometry const& geometry, Id const& id) +{ + return detail_dispatch::single_geometry<Geometry const>::apply(geometry, id); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp new file mode 100644 index 0000000000..a68f31362a --- /dev/null +++ b/boost/geometry/algorithms/detail/sub_range.hpp @@ -0,0 +1,113 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP + +#include <boost/geometry/util/range.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type, + bool IsMulti = boost::is_base_of<multi_tag, Tag>::value> +struct sub_range : not_implemented<Tag> +{}; + +template <typename Geometry, typename Tag> +struct sub_range<Geometry, Tag, false> +{ + typedef Geometry & return_type; + + template <typename Id> static inline + return_type apply(Geometry & geometry, Id const&) + { + return geometry; + } +}; + +template <typename Geometry> +struct sub_range<Geometry, polygon_tag, false> +{ + typedef typename geometry::ring_type<Geometry>::type & return_type; + + template <typename Id> static inline + return_type apply(Geometry & geometry, Id const& id) + { + if ( id.ring_index < 0 ) + { + return geometry::exterior_ring(geometry); + } + else + { + std::size_t ri = static_cast<std::size_t>(id.ring_index); + return range::at(geometry::interior_rings(geometry), ri); + } + } +}; + +template <typename Geometry, typename Tag> +struct sub_range<Geometry, Tag, true> +{ + typedef typename boost::range_value<Geometry>::type value_type; + typedef typename boost::mpl::if_c + < + boost::is_const<Geometry>::value, + typename boost::add_const<value_type>::type, + value_type + >::type sub_type; + + typedef detail_dispatch::sub_range<sub_type> sub_sub_range; + + // TODO: shouldn't it be return_type? + typedef typename sub_sub_range::return_type return_type; + + template <typename Id> static inline + return_type apply(Geometry & geometry, Id const& id) + { + BOOST_ASSERT(0 <= id.multi_index); + return sub_sub_range::apply(range::at(geometry, id.multi_index), id); + } +}; + +} // namespace detail_dispatch +#endif // DOXYGEN_NO_DISPATCH + +namespace detail { + +template <typename Geometry> +struct sub_range_return_type +{ + typedef typename detail_dispatch::sub_range<Geometry>::return_type type; +}; + +// This function also works for geometry::segment_identifier + +template <typename Geometry, typename Id> inline +typename sub_range_return_type<Geometry>::type +sub_range(Geometry & geometry, Id const& id) +{ + return detail_dispatch::sub_range<Geometry>::apply(geometry, id); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp index 62328a0d87..21f5fe40b7 100644 --- a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp +++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp @@ -16,7 +16,7 @@ // 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 +// 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... @@ -24,6 +24,10 @@ // So decided that at least for Boost 1.49 this is commented for // scalar results, except distance. +#if defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) +#include <boost/core/ignore_unused.hpp> +#endif + namespace boost { namespace geometry { @@ -39,6 +43,8 @@ inline void throw_on_empty_input(Geometry const& geometry) { throw empty_input_exception(); } +#else + boost::ignore_unused(geometry); #endif } diff --git a/boost/geometry/algorithms/detail/turns/compare_turns.hpp b/boost/geometry/algorithms/detail/turns/compare_turns.hpp new file mode 100644 index 0000000000..c29d5863b7 --- /dev/null +++ b/boost/geometry/algorithms/detail/turns/compare_turns.hpp @@ -0,0 +1,113 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP + +#include <cstddef> +#include <functional> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + + +namespace boost { namespace geometry +{ + +namespace detail { namespace turns +{ + +// TURNS SORTING AND SEARCHING + +// sort turns by G1 - source_index == 0 by: +// seg_id -> fraction -> other_id -> operation +template +< + typename IdLess = std::less<signed_index_type>, + int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0, + std::size_t OpId = 0 +> +struct less_seg_fraction_other_op +{ + BOOST_STATIC_ASSERT(OpId < 2); + static const std::size_t other_op_id = (OpId + 1) % 2; + + template <typename Op> + static inline int order_op(Op const& op) + { + switch (op.operation) + { + case detail::overlay::operation_none : return N; + case detail::overlay::operation_union : return U; + case detail::overlay::operation_intersection : return I; + case detail::overlay::operation_blocked : return B; + case detail::overlay::operation_continue : return C; + case detail::overlay::operation_opposite : return O; + } + return -1; + } + + template <typename Op> + static inline bool use_operation(Op const& left, Op const& right) + { + return order_op(left) < order_op(right); + } + + template <typename Turn> + static inline bool use_other_id(Turn const& left, Turn const& right) + { + segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; + segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; + + if ( left_other_seg_id.multi_index != right_other_seg_id.multi_index ) + { + return left_other_seg_id.multi_index < right_other_seg_id.multi_index; + } + if ( left_other_seg_id.ring_index != right_other_seg_id.ring_index ) + { + return left_other_seg_id.ring_index != right_other_seg_id.ring_index; + } + if ( left_other_seg_id.segment_index != right_other_seg_id.segment_index ) + { + return IdLess()(left_other_seg_id.segment_index, + right_other_seg_id.segment_index); + } + return use_operation(left.operations[OpId], right.operations[OpId]); + } + + template <typename Turn> + static inline bool use_fraction(Turn const& left, Turn const& right) + { + return left.operations[OpId].fraction < right.operations[OpId].fraction + || ( geometry::math::equals(left.operations[OpId].fraction, right.operations[OpId].fraction) + && use_other_id(left, right) + ); + } + + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + segment_identifier const& sl = left.operations[OpId].seg_id; + segment_identifier const& sr = right.operations[OpId].seg_id; + + return sl < sr || ( sl == sr && use_fraction(left, right) ); + } +}; + + + + + +}} // namespace detail::turns + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/turns/debug_turn.hpp b/boost/geometry/algorithms/detail/turns/debug_turn.hpp new file mode 100644 index 0000000000..5c4f03277a --- /dev/null +++ b/boost/geometry/algorithms/detail/turns/debug_turn.hpp @@ -0,0 +1,65 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP + +#ifdef BOOST_GEOMETRY_DEBUG_TURNS +#include <iostream> +#include <string> + +#include <boost/algorithm/string/predicate.hpp> + +#include <boost/geometry/io/wkt/write.hpp> +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +#endif // BOOST_GEOMETRY_DEBUG_TURNS + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace turns +{ + + +#ifdef BOOST_GEOMETRY_DEBUG_TURNS +template <typename Turn, typename Operation> +inline void debug_turn(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) + << " 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 +template <typename Turn, typename Operation> +inline void debug_turn(Turn const& , Operation, const char*) +{ +} +#endif // BOOST_GEOMETRY_DEBUG_TURNS + + +}} // namespace detail::turns +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost:geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP diff --git a/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp new file mode 100644 index 0000000000..17fbd65ddc --- /dev/null +++ b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP + +#include <algorithm> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> + +namespace boost { namespace geometry +{ + +namespace detail { namespace turns +{ + + +template <typename Turns, bool Enable> +struct filter_continue_turns +{ + static inline void apply(Turns&) {} +}; + + +template <typename Turns> +class filter_continue_turns<Turns, true> +{ +private: + class IsContinueTurn + { + private: + template <typename Operation> + inline bool is_continue_or_opposite(Operation const& operation) const + { + return operation == detail::overlay::operation_continue + || operation == detail::overlay::operation_opposite; + } + + public: + template <typename Turn> + bool operator()(Turn const& turn) const + { + if ( turn.method != detail::overlay::method_collinear + && turn.method != detail::overlay::method_equal ) + { + return false; + } + + return is_continue_or_opposite(turn.operations[0].operation) + && is_continue_or_opposite(turn.operations[1].operation); + } + }; + + +public: + static inline void apply(Turns& turns) + { + turns.erase( std::remove_if(turns.begin(), turns.end(), + IsContinueTurn()), + turns.end() + ); + } +}; + + +}} // namespace detail::turns + +}} // namespect boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/turns/print_turns.hpp b/boost/geometry/algorithms/detail/turns/print_turns.hpp new file mode 100644 index 0000000000..b339e11c94 --- /dev/null +++ b/boost/geometry/algorithms/detail/turns/print_turns.hpp @@ -0,0 +1,96 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP + +#include <iostream> + +#include <boost/foreach.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +#include <boost/geometry/io/wkt/write.hpp> +#include <boost/geometry/io/dsv/write.hpp> + +namespace boost { namespace geometry +{ + +namespace detail { namespace turns +{ + + + +template <typename Geometry1, typename Geometry2, typename Turns> +static inline void print_turns(Geometry1 const& g1, + Geometry2 const& g2, + Turns const& turns) +{ + typedef typename boost::range_value<Turns>::type turn_info; + + std::cout << geometry::wkt(g1) << std::endl; + std::cout << geometry::wkt(g2) << std::endl; + int index = 0; + BOOST_FOREACH(turn_info const& turn, turns) + { + std::ostream& out = std::cout; + out << index + << ": " << geometry::method_char(turn.method); + + if ( turn.discarded ) + out << " (discarded)\n"; + else if ( turn.blocked() ) + out << " (blocked)\n"; + else + out << '\n'; + + double fraction[2]; + + fraction[0] = turn.operations[0].fraction.numerator() + / turn.operations[0].fraction.denominator(); + + out << geometry::operation_char(turn.operations[0].operation) + <<": seg: " << turn.operations[0].seg_id.source_index + << ", m: " << turn.operations[0].seg_id.multi_index + << ", r: " << turn.operations[0].seg_id.ring_index + << ", s: " << turn.operations[0].seg_id.segment_index << ", "; + out << ", fr: " << fraction[0]; + out << ", col?: " << turn.operations[0].is_collinear; + out << ' ' << geometry::dsv(turn.point) << ' '; + + out << '\n'; + + fraction[1] = turn.operations[1].fraction.numerator() + / turn.operations[1].fraction.denominator(); + + out << geometry::operation_char(turn.operations[1].operation) + << ": seg: " << turn.operations[1].seg_id.source_index + << ", m: " << turn.operations[1].seg_id.multi_index + << ", r: " << turn.operations[1].seg_id.ring_index + << ", s: " << turn.operations[1].seg_id.segment_index << ", "; + out << ", fr: " << fraction[1]; + out << ", col?: " << turn.operations[1].is_collinear; + out << ' ' << geometry::dsv(turn.point) << ' '; + + ++index; + std::cout << std::endl; + } +} + + + + +}} // namespace detail::turns + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp new file mode 100644 index 0000000000..ccb19efb73 --- /dev/null +++ b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP + +#include <algorithm> +#include <boost/geometry/algorithms/equals.hpp> + +namespace boost { namespace geometry +{ + +namespace detail { namespace turns +{ + +template <typename Turns, bool Enable> +struct remove_duplicate_turns +{ + static inline void apply(Turns&) {} +}; + + + +template <typename Turns> +class remove_duplicate_turns<Turns, true> +{ +private: + struct TurnEqualsTo + { + template <typename Turn> + bool operator()(Turn const& t1, Turn const& t2) const + { + return geometry::equals(t1.point, t2.point) + && t1.operations[0].seg_id == t2.operations[0].seg_id + && t1.operations[1].seg_id == t2.operations[1].seg_id; + } + }; + +public: + static inline void apply(Turns& turns) + { + turns.erase( std::unique(turns.begin(), turns.end(), + TurnEqualsTo()), + turns.end() + ); + } +}; + + + +}} // namespace detail::turns + +}} // namespect boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp new file mode 100644 index 0000000000..6f1c1816cb --- /dev/null +++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -0,0 +1,463 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_reference.hpp> + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/concepts/within_concept.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/within.hpp> +#include <boost/geometry/strategies/covered_by.hpp> + +#include <boost/geometry/views/detail/normalized_view.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace within { + +// TODO: is this needed? +inline int check_result_type(int result) +{ + return result; +} + +template <typename T> +inline T check_result_type(T result) +{ + BOOST_ASSERT(false); + return result; +} + +template <typename Point, typename Range, typename Strategy> inline +int point_in_range(Point const& point, Range const& range, Strategy const& strategy) +{ + boost::ignore_unused_variable_warning(strategy); + + typedef typename boost::range_iterator<Range const>::type iterator_type; + typename Strategy::state_type state; + iterator_type it = boost::begin(range); + iterator_type end = boost::end(range); + + for ( iterator_type previous = it++ ; it != end ; ++previous, ++it ) + { + if ( ! strategy.apply(point, *previous, *it, state) ) + { + break; + } + } + + return check_result_type(strategy.result(state)); +} + +template <typename Geometry, typename Point, typename Range> +inline int point_in_range(Point const& point, Range const& range) +{ + typedef typename point_type<Point>::type point_type1; + typedef typename point_type<Geometry>::type point_type2; + + typedef typename strategy::within::services::default_strategy + < + typename tag<Point>::type, + typename tag<Geometry>::type, + typename tag<Point>::type, + typename tag_cast<typename tag<Geometry>::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, + Point, + Geometry + >::type strategy_type; + + typedef typename strategy::covered_by::services::default_strategy + < + typename tag<Point>::type, + typename tag<Geometry>::type, + typename tag<Point>::type, + typename tag_cast<typename tag<Geometry>::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, + Point, + Geometry + >::type strategy_type2; + + static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value; + BOOST_MPL_ASSERT_MSG((same_strategies), + DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, + (strategy_type, strategy_type2)); + + return point_in_range(point, range, strategy_type()); +} + +}} // namespace detail::within + +namespace detail_dispatch { namespace within { + +// checks the relation between a point P and geometry G +// returns 1 if P is in the interior of G +// returns 0 if P is on the boundry of G +// returns -1 if P is in the exterior of G + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type> +struct point_in_geometry + : not_implemented<Tag> +{}; + +template <typename Point2> +struct point_in_geometry<Point2, point_tag> +{ + template <typename Point1, typename Strategy> static inline + int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy) + { + boost::ignore_unused_variable_warning(strategy); + return strategy.apply(point1, point2) ? 1 : -1; + } +}; + +template <typename Segment> +struct point_in_geometry<Segment, segment_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Segment const& segment, Strategy const& strategy) + { + typedef typename geometry::point_type<Segment>::type point_type; + point_type p0, p1; +// TODO: don't copy points + detail::assign_point_from_index<0>(segment, p0); + detail::assign_point_from_index<1>(segment, p1); + + typename Strategy::state_type state; + strategy.apply(point, p0, p1, state); + int r = detail::within::check_result_type(strategy.result(state)); + + if ( r != 0 ) + return -1; // exterior + + // if the point is equal to the one of the terminal points + if ( detail::equals::equals_point_point(point, p0) + || detail::equals::equals_point_point(point, p1) ) + return 0; // boundary + else + return 1; // interior + } +}; + + +template <typename Linestring> +struct point_in_geometry<Linestring, linestring_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Linestring const& linestring, Strategy const& strategy) + { + std::size_t count = boost::size(linestring); + if ( count > 1 ) + { + if ( detail::within::point_in_range(point, linestring, strategy) != 0 ) + return -1; // exterior + + // if the linestring doesn't have a boundary + if ( detail::equals::equals_point_point(*boost::begin(linestring), *(--boost::end(linestring))) ) + return 1; // interior + // else if the point is equal to the one of the terminal points + else if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) + || detail::equals::equals_point_point(point, *(--boost::end(linestring))) ) + return 0; // boundary + else + return 1; // interior + } +// TODO: for now degenerated linestrings are ignored +// throw an exception here? + /*else if ( count == 1 ) + { + if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) ) + return 1; + }*/ + + return -1; // exterior + } +}; + +template <typename Ring> +struct point_in_geometry<Ring, ring_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Ring const& ring, Strategy const& strategy) + { + if ( boost::size(ring) < core_detail::closure::minimum_ring_size + < + geometry::closure<Ring>::value + >::value ) + { + return -1; + } + + detail::normalized_view<Ring const> view(ring); + return detail::within::point_in_range(point, view, strategy); + } +}; + +// Polygon: in exterior ring, and if so, not within interior ring(s) +template <typename Polygon> +struct point_in_geometry<Polygon, polygon_tag> +{ + template <typename Point, typename Strategy> + static inline int apply(Point const& point, Polygon const& polygon, + Strategy const& strategy) + { + int const code = point_in_geometry + < + typename ring_type<Polygon>::type + >::apply(point, exterior_ring(polygon), strategy); + + if (code == 1) + { + typename interior_return_type<Polygon const>::type + rings = interior_rings(polygon); + + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); + it != boost::end(rings); + ++it) + { + int const interior_code = point_in_geometry + < + typename ring_type<Polygon>::type + >::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; + } +}; + +template <typename Geometry> +struct point_in_geometry<Geometry, multi_point_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) + { + typedef typename boost::range_value<Geometry>::type point_type; + typedef typename boost::range_const_iterator<Geometry>::type iterator; + for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) + { + int pip = point_in_geometry<point_type>::apply(point, *it, strategy); + + //BOOST_ASSERT(pip != 0); + if ( pip > 0 ) // inside + return 1; + } + + return -1; // outside + } +}; + +template <typename Geometry> +struct point_in_geometry<Geometry, multi_linestring_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) + { + int pip = -1; // outside + + typedef typename boost::range_value<Geometry>::type linestring_type; + typedef typename boost::range_value<linestring_type>::type point_type; + typedef typename boost::range_iterator<Geometry const>::type iterator; + iterator it = boost::begin(geometry); + for ( ; it != boost::end(geometry) ; ++it ) + { + pip = point_in_geometry<linestring_type>::apply(point, *it, strategy); + + // inside or on the boundary + if ( pip >= 0 ) + { + ++it; + break; + } + } + + // outside + if ( pip < 0 ) + return -1; + + // TODO: the following isn't needed for covered_by() + + unsigned boundaries = pip == 0 ? 1 : 0; + + for ( ; it != boost::end(geometry) ; ++it ) + { + if ( boost::size(*it) < 2 ) + continue; + + point_type const& front = *boost::begin(*it); + point_type const& back = *(--boost::end(*it)); + + // is closed_ring - no boundary + if ( detail::equals::equals_point_point(front, back) ) + continue; + + // is point on boundary + if ( detail::equals::equals_point_point(point, front) + || detail::equals::equals_point_point(point, back) ) + { + ++boundaries; + } + } + + // if the number of boundaries is odd, the point is on the boundary + return boundaries % 2 ? 0 : 1; + } +}; + +template <typename Geometry> +struct point_in_geometry<Geometry, multi_polygon_tag> +{ + template <typename Point, typename Strategy> static inline + int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) + { + // For invalid multipolygons + //int res = -1; // outside + + typedef typename boost::range_value<Geometry>::type polygon_type; + typedef typename boost::range_const_iterator<Geometry>::type iterator; + for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) + { + int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy); + + // inside or on the boundary + if ( pip >= 0 ) + return pip; + + // For invalid multi-polygons + //if ( 1 == pip ) // inside polygon + // return 1; + //else if ( res < pip ) // point must be inside at least one polygon + // res = pip; + } + + return -1; // for valid multipolygons + //return res; // for invalid multipolygons + } +}; + +}} // namespace detail_dispatch::within + +namespace detail { namespace within { + +// 1 - in the interior +// 0 - in the boundry +// -1 - in the exterior +template <typename Point, typename Geometry, typename Strategy> +inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) +{ + concept::within::check + < + typename tag<Point>::type, + typename tag<Geometry>::type, + typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, + Strategy + >(); + + return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy); +} + +template <typename Point, typename Geometry> +inline int point_in_geometry(Point const& point, Geometry const& geometry) +{ + typedef typename point_type<Point>::type point_type1; + typedef typename point_type<Geometry>::type point_type2; + + typedef typename strategy::within::services::default_strategy + < + typename tag<Point>::type, + typename tag<Geometry>::type, + typename tag<Point>::type, + typename tag_cast<typename tag<Geometry>::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, + Point, + Geometry + >::type strategy_type; + + typedef typename strategy::covered_by::services::default_strategy + < + typename tag<Point>::type, + typename tag<Geometry>::type, + typename tag<Point>::type, + typename tag_cast<typename tag<Geometry>::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, + Point, + Geometry + >::type strategy_type2; + + static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value; + BOOST_MPL_ASSERT_MSG((same_strategies), + DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, + (strategy_type, strategy_type2)); + + return point_in_geometry(point, geometry, strategy_type()); +} + +}} // namespace detail::within +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/within/within_no_turns.hpp b/boost/geometry/algorithms/detail/within/within_no_turns.hpp new file mode 100644 index 0000000000..8da05e58fd --- /dev/null +++ b/boost/geometry/algorithms/detail/within/within_no_turns.hpp @@ -0,0 +1,221 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 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_WITHIN_WITHIN_NO_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP + +#include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail_dispatch { namespace within { + +// returns true if G1 is within G2 +// this function should be called only if there are no intersection points +// otherwise it may return invalid result +// e.g. when non-first point of G1 is outside G2 or when some rings of G1 are the same as rings of G2 + +template <typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type> +struct within_no_turns +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + typedef typename geometry::point_type<Geometry1>::type point1_type; + point1_type p; + if ( !geometry::point_on_border(p, geometry1) ) + return false; + + return detail::within::point_in_geometry(p, geometry2, strategy) >= 0; + } +}; + +template <typename Geometry1, typename Geometry2> +struct within_no_turns<Geometry1, Geometry2, ring_tag, polygon_tag> +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + typedef typename geometry::point_type<Geometry1>::type point1_type; + typedef typename geometry::point_type<Geometry2>::type point2_type; + point1_type p; + if ( !geometry::point_on_border(p, geometry1) ) + return false; + // check if one of ring points is outside the polygon + if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) + return false; + // Now check if holes of G2 aren't inside G1 + typedef typename boost::range_const_iterator + < + typename geometry::interior_type<Geometry2>::type + >::type iterator; + for ( iterator it = boost::begin(geometry::interior_rings(geometry2)) ; + it != boost::end(geometry::interior_rings(geometry2)) ; + ++it ) + { + point2_type p; + if ( !geometry::point_on_border(p, *it) ) + return false; + if ( detail::within::point_in_geometry(p, geometry1, strategy) > 0 ) + return false; + } + return true; + } +}; + +template <typename Geometry1, typename Geometry2> +struct within_no_turns<Geometry1, Geometry2, polygon_tag, polygon_tag> +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + typedef typename geometry::point_type<Geometry1>::type point1_type; + typedef typename geometry::point_type<Geometry2>::type point2_type; + point1_type p; + if ( !geometry::point_on_border(p, geometry1) ) + return false; + // check if one of ring points is outside the polygon + if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) + return false; + // Now check if holes of G2 aren't inside G1 + typedef typename boost::range_const_iterator + < + typename geometry::interior_type<Geometry2>::type + >::type iterator2; + for ( iterator2 it = boost::begin(geometry::interior_rings(geometry2)) ; + it != boost::end(geometry::interior_rings(geometry2)) ; + ++it ) + { + point2_type p2; + if ( !geometry::point_on_border(p2, *it) ) + return false; + // if the hole of G2 is inside G1 + if ( detail::within::point_in_geometry(p2, geometry1, strategy) > 0 ) + { + // if it's also inside one of the G1 holes, it's ok + bool ok = false; + typedef typename boost::range_const_iterator + < + typename geometry::interior_type<Geometry1>::type + >::type iterator1; + for ( iterator1 it1 = boost::begin(geometry::interior_rings(geometry1)) ; + it1 != boost::end(geometry::interior_rings(geometry1)) ; + ++it1 ) + { + if ( detail::within::point_in_geometry(p2, *it1, strategy) < 0 ) + { + ok = true; + break; + } + } + if ( !ok ) + return false; + } + } + return true; + } +}; + +template <typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type, + bool IsMulti1 = boost::is_base_of<geometry::multi_tag, Tag1>::value, + bool IsMulti2 = boost::is_base_of<geometry::multi_tag, Tag2>::value> +struct within_no_turns_multi +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + return within_no_turns<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> +struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, false> +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + // All values of G1 must be inside G2 + typedef typename boost::range_value<Geometry1>::type subgeometry1; + typedef typename boost::range_const_iterator<Geometry1>::type iterator; + for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) + { + if ( !within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) + return false; + } + return true; + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> +struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, false, true> +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + // G1 must be within at least one value of G2 + typedef typename boost::range_value<Geometry2>::type subgeometry2; + typedef typename boost::range_const_iterator<Geometry2>::type iterator; + for ( iterator it = boost::begin(geometry2) ; it != boost::end(geometry2) ; ++it ) + { + if ( within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy) ) + return true; + } + return false; + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> +struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, true> +{ + template <typename Strategy> static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + // each value of G1 must be inside at least one value of G2 + typedef typename boost::range_value<Geometry1>::type subgeometry1; + typedef typename boost::range_const_iterator<Geometry1>::type iterator; + for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) + { + if ( !within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) + return false; + } + return true; + } +}; + +}} // namespace detail_dispatch::within + +namespace detail { namespace within { + +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool within_no_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) +{ + return detail_dispatch::within::within_no_turns_multi<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); +} + +}} // namespace detail::within +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp index 480dd928de..780436f015 100644 --- a/boost/geometry/algorithms/difference.hpp +++ b/boost/geometry/algorithms/difference.hpp @@ -12,6 +12,7 @@ #include <algorithm> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> namespace boost { namespace geometry { @@ -43,33 +44,28 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); concept::check<GeometryOut>(); - + return geometry::dispatch::intersection_insert < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, Geometry1, Geometry2, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, + GeometryOut, overlay_difference, - Strategy - >::apply(geometry1, geometry2, out, strategy); + 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, robust_policy, out, strategy); } /*! @@ -93,10 +89,13 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out) { concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); @@ -107,11 +106,12 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, typename cs_tag<GeometryOut>::type, Geometry1, Geometry2, - typename geometry::point_type<GeometryOut>::type + typename geometry::point_type<GeometryOut>::type, + RobustPolicy > strategy; return difference_insert<GeometryOut>(geometry1, geometry2, - out, strategy()); + robust_policy, out, strategy()); } @@ -148,8 +148,17 @@ inline void difference(Geometry1 const& geometry1, typedef typename boost::range_value<Collection>::type geometry_out; concept::check<geometry_out>(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); + detail::difference::difference_insert<geometry_out>( - geometry1, geometry2, + geometry1, geometry2, robust_policy, std::back_inserter(output_collection)); } diff --git a/boost/geometry/algorithms/disjoint.hpp b/boost/geometry/algorithms/disjoint.hpp index f986cc24af..f997487c71 100644 --- a/boost/geometry/algorithms/disjoint.hpp +++ b/boost/geometry/algorithms/disjoint.hpp @@ -1,8 +1,15 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,288 +21,7 @@ #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 GeometryTag1, typename GeometryTag2, - typename Geometry1, typename Geometry2, - std::size_t DimensionCount -> -struct disjoint - : detail::disjoint::general_areal<Geometry1, Geometry2> -{}; - - -template <typename Point1, typename Point2, std::size_t DimensionCount> -struct disjoint<point_tag, point_tag, Point1, Point2, DimensionCount> - : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount> -{}; - - -template <typename Box1, typename Box2, std::size_t DimensionCount> -struct disjoint<box_tag, box_tag, Box1, Box2, DimensionCount> - : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount> -{}; - - -template <typename Point, typename Box, std::size_t DimensionCount> -struct disjoint<point_tag, box_tag, Point, Box, DimensionCount> - : detail::disjoint::point_box<Point, Box, 0, DimensionCount> -{}; - -template <typename Linestring1, typename Linestring2> -struct disjoint<linestring_tag, linestring_tag, Linestring1, Linestring2, 2> - : detail::disjoint::disjoint_linear<Linestring1, Linestring2> -{}; - -template <typename Linestring1, typename Linestring2> -struct disjoint<segment_tag, segment_tag, Linestring1, Linestring2, 2> - : detail::disjoint::disjoint_segment<Linestring1, Linestring2> -{}; - -template <typename Linestring, typename Segment> -struct disjoint<linestring_tag, segment_tag, Linestring, Segment, 2> - : detail::disjoint::disjoint_linear<Linestring, Segment> -{}; - - -template -< - typename GeometryTag1, typename GeometryTag2, - typename Geometry1, typename Geometry2, - std::size_t DimensionCount -> -struct disjoint_reversed -{ - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) - { - return disjoint - < - GeometryTag2, GeometryTag1, - Geometry2, Geometry1, - DimensionCount - >::apply(g2, g1); - } -}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - - -/*! -\brief \brief_check2{are disjoint} -\ingroup disjoint -\tparam Geometry1 \tparam_geometry -\tparam Geometry2 \tparam_geometry -\param geometry1 \param_geometry -\param geometry2 \param_geometry -\return \return_check2{are disjoint} - -\qbk{[include reference/algorithms/disjoint.qbk]} -*/ -template <typename Geometry1, typename Geometry2> -inline bool disjoint(Geometry1 const& geometry1, - Geometry2 const& geometry2) -{ - concept::check_concepts_and_equal_dimensions - < - Geometry1 const, - Geometry2 const - >(); - - return boost::mpl::if_c - < - reverse_dispatch<Geometry1, Geometry2>::type::value, - dispatch::disjoint_reversed - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - Geometry1, - Geometry2, - dimension<Geometry1>::type::value - >, - dispatch::disjoint - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - Geometry1, - Geometry2, - dimension<Geometry1>::type::value - > - >::type::apply(geometry1, geometry2); -} - - -}} // namespace boost::geometry - +#include <boost/geometry/algorithms/detail/disjoint/interface.hpp> +#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP diff --git a/boost/geometry/algorithms/dispatch/disjoint.hpp b/boost/geometry/algorithms/dispatch/disjoint.hpp new file mode 100644 index 0000000000..627bcff83c --- /dev/null +++ b/boost/geometry/algorithms/dispatch/disjoint.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP + +#include <cstddef> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/reverse_dispatch.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry1, typename Geometry2, + std::size_t DimensionCount = dimension<Geometry1>::type::value, + typename Tag1 = typename tag_cast + < + typename tag<Geometry1>::type, + segment_tag, box_tag, linear_tag, areal_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag<Geometry2>::type, + segment_tag, box_tag, linear_tag, areal_tag + >::type, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct disjoint + : not_implemented<Geometry1, Geometry2> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP diff --git a/boost/geometry/algorithms/dispatch/distance.hpp b/boost/geometry/algorithms/dispatch/distance.hpp new file mode 100644 index 0000000000..cae3ebd0c9 --- /dev/null +++ b/boost/geometry/algorithms/dispatch/distance.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP + + +#include <boost/geometry/core/reverse_dispatch.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry1, typename Geometry2, + typename Strategy = typename detail::distance::default_strategy + < + Geometry1, Geometry2 + >::type, + typename Tag1 = typename tag_cast + < + typename tag<Geometry1>::type, + segment_tag, + box_tag, + linear_tag, + areal_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag<Geometry2>::type, + segment_tag, + box_tag, + linear_tag, + areal_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> +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP diff --git a/boost/geometry/algorithms/dispatch/is_simple.hpp b/boost/geometry/algorithms/dispatch/is_simple.hpp new file mode 100644 index 0000000000..2ac92256b3 --- /dev/null +++ b/boost/geometry/algorithms/dispatch/is_simple.hpp @@ -0,0 +1,38 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP + +#include <boost/geometry/core/tag.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct is_simple + : not_implemented<Geometry> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP diff --git a/boost/geometry/algorithms/dispatch/is_valid.hpp b/boost/geometry/algorithms/dispatch/is_valid.hpp new file mode 100644 index 0000000000..266bab9181 --- /dev/null +++ b/boost/geometry/algorithms/dispatch/is_valid.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP + +#include <boost/geometry/core/tag.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type, + // for linear geometries: determines if spikes are allowed + bool AllowSpikes = true, + // for areal geometries: determines if duplicate points are allowed + bool AllowDuplicates = true +> +struct is_valid + : not_implemented<Geometry> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP diff --git a/boost/geometry/algorithms/distance.hpp b/boost/geometry/algorithms/distance.hpp index 11c2bc929b..dcfe597cd0 100644 --- a/boost/geometry/algorithms/distance.hpp +++ b/boost/geometry/algorithms/distance.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,578 +20,7 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP - -#include <boost/mpl/if.hpp> -#include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> - -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/closure.hpp> -#include <boost/geometry/core/reverse_dispatch.hpp> -#include <boost/geometry/core/tag_cast.hpp> - -#include <boost/geometry/algorithms/not_implemented.hpp> -#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> - -#include <boost/geometry/geometries/segment.hpp> -#include <boost/geometry/geometries/concepts/check.hpp> - -#include <boost/geometry/strategies/distance.hpp> -#include <boost/geometry/strategies/default_distance_result.hpp> -#include <boost/geometry/algorithms/assign.hpp> -#include <boost/geometry/algorithms/within.hpp> - -#include <boost/geometry/views/closeable_view.hpp> -#include <boost/geometry/util/math.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace distance -{ - -// To avoid spurious namespaces here: -using strategy::distance::services::return_type; - -template <typename P1, typename P2, typename Strategy> -struct point_to_point -{ - static inline typename return_type<Strategy>::type apply(P1 const& p1, - P2 const& p2, Strategy const& strategy) - { - return strategy.apply(p1, p2); - } -}; - - -template<typename Point, typename Segment, typename Strategy> -struct point_to_segment -{ - static inline typename return_type<Strategy>::type apply(Point const& point, - Segment const& segment, Strategy const& ) - { - typename strategy::distance::services::default_strategy - < - segment_tag, - Point, - typename point_type<Segment>::type, - typename cs_tag<Point>::type, - typename cs_tag<typename point_type<Segment>::type>::type, - Strategy - >::type segment_strategy; - - typename point_type<Segment>::type p[2]; - geometry::detail::assign_point_from_index<0>(segment, p[0]); - geometry::detail::assign_point_from_index<1>(segment, p[1]); - return segment_strategy.apply(point, p[0], p[1]); - } -}; - - -template -< - typename Point, - typename Range, - closure_selector Closure, - typename PPStrategy, - typename PSStrategy -> -struct point_to_range -{ - typedef typename return_type<PSStrategy>::type return_type; - - static inline return_type apply(Point const& point, Range const& range, - PPStrategy const& pp_strategy, PSStrategy const& ps_strategy) - { - return_type const zero = return_type(0); - - if (boost::size(range) == 0) - { - return zero; - } - - typedef typename closeable_view<Range const, Closure>::type view_type; - - view_type view(range); - - // line of one point: return point distance - typedef typename boost::range_iterator<view_type const>::type iterator_type; - iterator_type it = boost::begin(view); - iterator_type prev = it++; - if (it == boost::end(view)) - { - return pp_strategy.apply(point, *boost::begin(view)); - } - - // Create comparable (more efficient) strategy - typedef typename strategy::distance::services::comparable_type<PSStrategy>::type eps_strategy_type; - eps_strategy_type eps_strategy = strategy::distance::services::get_comparable<PSStrategy>::apply(ps_strategy); - - // start with first segment distance - return_type d = eps_strategy.apply(point, *prev, *it); - return_type rd = ps_strategy.apply(point, *prev, *it); - - // check if other segments are closer - for (++prev, ++it; it != boost::end(view); ++prev, ++it) - { - return_type const ds = 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 - >::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 +#include <boost/geometry/algorithms/detail/distance/interface.hpp> +#include <boost/geometry/algorithms/detail/distance/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP diff --git a/boost/geometry/algorithms/envelope.hpp b/boost/geometry/algorithms/envelope.hpp index da34f6a783..e06ed71e81 100644 --- a/boost/geometry/algorithms/envelope.hpp +++ b/boost/geometry/algorithms/envelope.hpp @@ -14,15 +14,22 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP -#include <boost/mpl/assert.hpp> -#include <boost/range.hpp> +#include <vector> #include <boost/numeric/conversion/cast.hpp> +#include <boost/range.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.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/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> @@ -35,9 +42,9 @@ namespace detail { namespace envelope /// Calculate envelope of an 2D or 3D segment -template<typename Geometry, typename Box> struct envelope_expand_one { + template<typename Geometry, typename Box> static inline void apply(Geometry const& geometry, Box& mbr) { assign_inverse(mbr); @@ -63,10 +70,10 @@ inline void envelope_range_additional(Range const& range, Box& mbr) /// Generic range dispatching struct -template <typename Range, typename Box> 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); @@ -74,6 +81,42 @@ struct envelope_range } }; + +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 // DOXYGEN_NO_DETAIL @@ -82,131 +125,125 @@ namespace dispatch { -// Note, the strategy is for future use (less/greater -> compare spherical -// using other methods), defaults are OK for now. -// However, they are already in the template methods - template < - typename Tag1, typename Tag2, - typename Geometry, typename Box, - typename StrategyLess, typename StrategyGreater + typename Geometry, + typename Tag = typename tag<Geometry>::type > -struct envelope -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry>) - ); -}; +struct envelope: not_implemented<Tag> +{}; -template -< - typename Point, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - point_tag, box_tag, - Point, Box, - StrategyLess, StrategyGreater - > - : detail::envelope::envelope_expand_one<Point, Box> +template <typename Point> +struct envelope<Point, point_tag> + : detail::envelope::envelope_expand_one {}; -template -< - typename BoxIn, typename BoxOut, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - box_tag, box_tag, - BoxIn, BoxOut, - StrategyLess, StrategyGreater - > - : detail::envelope::envelope_expand_one<BoxIn, BoxOut> +template <typename Box> +struct envelope<Box, box_tag> + : detail::envelope::envelope_expand_one {}; -template -< - typename Segment, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - segment_tag, box_tag, - Segment, Box, - StrategyLess, StrategyGreater - > - : detail::envelope::envelope_expand_one<Segment, Box> +template <typename Segment> +struct envelope<Segment, segment_tag> + : detail::envelope::envelope_expand_one {}; -template -< - typename Linestring, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - linestring_tag, box_tag, - Linestring, Box, - StrategyLess, StrategyGreater - > - : detail::envelope::envelope_range<Linestring, Box> +template <typename Linestring> +struct envelope<Linestring, linestring_tag> + : detail::envelope::envelope_range {}; -template -< - typename Ring, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - ring_tag, box_tag, - Ring, Box, - StrategyLess, StrategyGreater - > - : detail::envelope::envelope_range<Ring, Box> +template <typename Ring> +struct envelope<Ring, ring_tag> + : detail::envelope::envelope_range {}; -template -< - typename Polygon, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope - < - polygon_tag, box_tag, - Polygon, Box, - StrategyLess, StrategyGreater - > +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 - < - typename ring_type<Polygon>::type, - Box - >::apply(exterior_ring(poly), mbr); + detail::envelope::envelope_range::apply(exterior_ring(poly), mbr); } }; +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 resolve_variant { + +template <typename Geometry> +struct envelope +{ + template <typename Box> + static inline void apply(Geometry const& geometry, Box& box) + { + concept::check<Geometry const>(); + concept::check<Box>(); + + dispatch::envelope<Geometry>::apply(geometry, box); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Box> + struct visitor: boost::static_visitor<void> + { + Box& m_box; + + visitor(Box& box): m_box(box) {} + + template <typename Geometry> + void operator()(Geometry const& geometry) const + { + envelope<Geometry>::apply(geometry, m_box); + } + }; + + template <typename Box> + static inline void + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Box& box) + { + boost::apply_visitor(visitor<Box>(box), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc{envelope} \ingroup envelope @@ -225,15 +262,7 @@ struct envelope template<typename Geometry, typename Box> inline void envelope(Geometry const& geometry, Box& mbr) { - concept::check<Geometry const>(); - concept::check<Box>(); - - dispatch::envelope - < - typename tag<Geometry>::type, typename tag<Box>::type, - Geometry, Box, - void, void - >::apply(geometry, mbr); + resolve_variant::envelope<Geometry>::apply(geometry, mbr); } @@ -255,16 +284,8 @@ inline void envelope(Geometry const& geometry, Box& mbr) template<typename Box, typename Geometry> inline Box return_envelope(Geometry const& geometry) { - concept::check<Geometry const>(); - concept::check<Box>(); - Box mbr; - dispatch::envelope - < - typename tag<Geometry>::type, typename tag<Box>::type, - Geometry, Box, - void, void - >::apply(geometry, mbr); + resolve_variant::envelope<Geometry>::apply(geometry, mbr); return mbr; } diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp index 6b094f76d0..c6b718da1b 100644 --- a/boost/geometry/algorithms/equals.hpp +++ b/boost/geometry/algorithms/equals.hpp @@ -3,6 +3,12 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,18 +24,19 @@ #include <cstddef> #include <vector> -#include <boost/mpl/if.hpp> -#include <boost/static_assert.hpp> #include <boost/range.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/geometry_id.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/algorithms/detail/disjoint.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/not.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> // For trivial checks #include <boost/geometry/algorithms/area.hpp> @@ -39,7 +46,12 @@ #include <boost/geometry/util/select_most_precise.hpp> #include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp> +#include <boost/geometry/algorithms/detail/relate/relate.hpp> +#include <boost/geometry/views/detail/indexed_point_view.hpp> + +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> namespace boost { namespace geometry { @@ -51,13 +63,12 @@ namespace detail { namespace equals template < - typename Box1, - typename Box2, 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)) @@ -65,13 +76,14 @@ struct box_box { return false; } - return box_box<Box1, Box2, Dimension + 1, DimensionCount>::apply(box1, box2); + return box_box<Dimension + 1, DimensionCount>::apply(box1, box2); } }; -template <typename Box1, typename Box2, std::size_t DimensionCount> -struct box_box<Box1, Box2, DimensionCount, DimensionCount> +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; @@ -79,6 +91,28 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount> }; +struct segment_segment +{ + template <typename Segment1, typename Segment2> + static inline bool apply(Segment1 const& segment1, Segment2 const& segment2) + { + return equals::equals_point_point( + indexed_point_view<Segment1 const, 0>(segment1), + indexed_point_view<Segment2 const, 0>(segment2) ) + ? equals::equals_point_point( + indexed_point_view<Segment1 const, 1>(segment1), + indexed_point_view<Segment2 const, 1>(segment2) ) + : ( equals::equals_point_point( + indexed_point_view<Segment1 const, 0>(segment1), + indexed_point_view<Segment2 const, 1>(segment2) ) + && equals::equals_point_point( + indexed_point_view<Segment1 const, 1>(segment1), + indexed_point_view<Segment2 const, 0>(segment2) ) + ); + } +}; + + struct area_check { template <typename Geometry1, typename Geometry2> @@ -103,9 +137,10 @@ struct length_check }; -template <typename Geometry1, typename Geometry2, typename TrivialCheck> +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)) @@ -141,6 +176,15 @@ struct equals_by_collection } }; +template<typename Geometry1, typename Geometry2> +struct equals_by_relate + : detail::relate::relate_base + < + detail::relate::static_mask_equals_type, + Geometry1, + Geometry2 + > +{}; }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL @@ -152,17 +196,42 @@ namespace dispatch template < - typename Tag1, typename Tag2, typename Geometry1, typename Geometry2, - std::size_t DimensionCount + 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 +struct equals: not_implemented<Tag1, Tag2> {}; -template <typename P1, typename P2, std::size_t DimensionCount> -struct equals<point_tag, point_tag, P1, P2, DimensionCount> +// 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, @@ -172,104 +241,208 @@ struct equals<point_tag, point_tag, P1, P2, DimensionCount> {}; -template <typename Box1, typename Box2, std::size_t DimensionCount> -struct equals<box_tag, box_tag, Box1, Box2, DimensionCount> - : detail::equals::box_box<Box1, Box2, 0, DimensionCount> +template <typename 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> -struct equals<ring_tag, ring_tag, Ring1, Ring2, 2> - : detail::equals::equals_by_collection - < - Ring1, Ring2, - detail::equals::area_check - > +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> -struct equals<polygon_tag, polygon_tag, Polygon1, Polygon2, 2> - : detail::equals::equals_by_collection - < - Polygon1, Polygon2, - 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> -struct equals<linestring_tag, linestring_tag, LineString1, LineString2, 2> - : detail::equals::equals_by_collection - < - LineString1, LineString2, - detail::equals::length_check - > +template <typename Polygon, typename Ring, bool Reverse> +struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> {}; -template <typename Polygon, typename Ring> -struct equals<polygon_tag, ring_tag, Polygon, Ring, 2> - : detail::equals::equals_by_collection - < - Polygon, Ring, - detail::equals::area_check - > +template <typename Ring, typename Box, bool Reverse> +struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> {}; -template <typename Ring, typename Box> -struct equals<ring_tag, box_tag, Ring, Box, 2> - : detail::equals::equals_by_collection - < - Ring, Box, - detail::equals::area_check - > +template <typename Polygon, typename Box, bool Reverse> +struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse> + : detail::equals::equals_by_collection<detail::equals::area_check> {}; +template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse> +struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse> + : detail::equals::segment_segment +{}; -template <typename Polygon, typename Box> -struct equals<polygon_tag, box_tag, Polygon, Box, 2> - : detail::equals::equals_by_collection - < - Polygon, Box, - detail::equals::area_check - > +template <typename LineString1, typename LineString2, bool Reverse> +struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse> + //: detail::equals::equals_by_collection<detail::equals::length_check> + : detail::equals::equals_by_relate<LineString1, LineString2> {}; +template <typename LineString, typename MultiLineString, bool Reverse> +struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse> + : detail::equals::equals_by_relate<LineString, MultiLineString> +{}; -template -< - typename Tag1, typename Tag2, - typename Geometry1, - typename Geometry2, - std::size_t DimensionCount -> -struct equals_reversed +template <typename MultiLineString1, typename MultiLineString2, bool Reverse> +struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse> + : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2> +{}; + + +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 resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct equals { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2) { - return equals - < - Tag2, Tag1, - Geometry2, Geometry1, - DimensionCount - >::apply(g2, g1); + concept::check_concepts_and_equal_dimensions + < + Geometry1 const, + Geometry2 const + >(); + + return dispatch::equals<Geometry1, Geometry2> + ::apply(geometry1, geometry2); } }; +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct 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) + {} -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH + template <typename Geometry1> + inline bool operator()(Geometry1 const& geometry1) const + { + return 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 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 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 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 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 resolve_variant /*! \brief \brief_check{are spatially equal} -\details \details_check12{equals, is spatially equal}. Spatially equal means +\details \details_check12{equals, is spatially equal}. Spatially equal means that the same point set is included. A box can therefore be spatially equal - to a ring or a polygon, or a linestring can be spatially equal to a - multi-linestring or a segment. This only theoretically, not all combinations - are implemented yet. + 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 @@ -283,32 +456,8 @@ struct equals_reversed template <typename Geometry1, typename Geometry2> inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check_concepts_and_equal_dimensions - < - Geometry1 const, - Geometry2 const - >(); - - return boost::mpl::if_c - < - reverse_dispatch<Geometry1, Geometry2>::type::value, - dispatch::equals_reversed - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - Geometry1, - Geometry2, - dimension<Geometry1>::type::value - >, - dispatch::equals - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - Geometry1, - Geometry2, - dimension<Geometry1>::type::value - > - >::type::apply(geometry1, geometry2); + return resolve_variant::equals<Geometry1, Geometry2> + ::apply(geometry1, geometry2); } diff --git a/boost/geometry/algorithms/expand.hpp b/boost/geometry/algorithms/expand.hpp index da7442b593..19e40aa2d0 100644 --- a/boost/geometry/algorithms/expand.hpp +++ b/boost/geometry/algorithms/expand.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -19,6 +20,7 @@ #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> @@ -27,6 +29,9 @@ #include <boost/geometry/strategies/compare.hpp> #include <boost/geometry/policies/compare.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> + namespace boost { namespace geometry { @@ -38,26 +43,26 @@ namespace detail { namespace expand template < - typename Box, typename Point, typename StrategyLess, typename StrategyGreater, std::size_t Dimension, std::size_t DimensionCount > struct point_loop { - typedef typename strategy::compare::detail::select_strategy - < - StrategyLess, 1, Point, Dimension - >::type less_type; + 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 strategy::compare::detail::select_strategy + < + StrategyGreater, -1, Point, Dimension + >::type greater_type; - typedef typename select_coordinate_type<Point, Box>::type coordinate_type; + typedef typename select_coordinate_type<Point, Box>::type coordinate_type; - static inline void apply(Box& box, Point const& source) - { less_type less; greater_type greater; @@ -75,7 +80,6 @@ struct point_loop point_loop < - Box, Point, StrategyLess, StrategyGreater, Dimension + 1, DimensionCount >::apply(box, source); @@ -85,49 +89,47 @@ struct point_loop template < - typename Box, typename Point, typename StrategyLess, typename StrategyGreater, std::size_t DimensionCount > struct point_loop < - Box, Point, StrategyLess, StrategyGreater, DimensionCount, DimensionCount > { + template <typename Box, typename Point> static inline void apply(Box&, Point const&) {} }; template < - typename Box, typename Geometry, typename StrategyLess, typename StrategyGreater, std::size_t Index, std::size_t Dimension, std::size_t DimensionCount > struct indexed_loop { - typedef typename strategy::compare::detail::select_strategy - < - StrategyLess, 1, Box, Dimension - >::type less_type; - - typedef typename strategy::compare::detail::select_strategy - < - StrategyGreater, -1, Box, Dimension - >::type greater_type; + 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 select_coordinate_type + typedef typename strategy::compare::detail::select_strategy < - Box, - Geometry - >::type coordinate_type; + StrategyGreater, -1, Box, Dimension + >::type greater_type; + typedef typename select_coordinate_type + < + Box, + Geometry + >::type coordinate_type; - static inline void apply(Box& box, Geometry const& source) - { less_type less; greater_type greater; @@ -145,7 +147,6 @@ struct indexed_loop indexed_loop < - Box, Geometry, StrategyLess, StrategyGreater, Index, Dimension + 1, DimensionCount >::apply(box, source); @@ -155,17 +156,16 @@ struct indexed_loop template < - typename Box, typename Geometry, typename StrategyLess, typename StrategyGreater, std::size_t Index, std::size_t DimensionCount > struct indexed_loop < - Box, Geometry, StrategyLess, StrategyGreater, Index, DimensionCount, DimensionCount > { + template <typename Box, typename Geometry> static inline void apply(Box&, Geometry const&) {} }; @@ -174,23 +174,21 @@ struct indexed_loop // Changes a box such that the other box is also contained by the box template < - typename Box, typename Geometry, typename StrategyLess, typename StrategyGreater > struct expand_indexed { + template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& geometry) { indexed_loop < - Box, Geometry, StrategyLess, StrategyGreater, 0, 0, dimension<Geometry>::type::value >::apply(box, geometry); indexed_loop < - Box, Geometry, StrategyLess, StrategyGreater, 1, 0, dimension<Geometry>::type::value >::apply(box, geometry); @@ -206,11 +204,13 @@ namespace dispatch template < - typename Tag, - typename BoxOut, typename Geometry, - typename StrategyLess, typename StrategyGreater + 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 +struct expand: not_implemented<TagOut, Tag> {}; @@ -220,10 +220,9 @@ template typename BoxOut, typename Point, typename StrategyLess, typename StrategyGreater > -struct expand<point_tag, BoxOut, Point, StrategyLess, StrategyGreater> +struct expand<BoxOut, Point, StrategyLess, StrategyGreater, box_tag, point_tag> : detail::expand::point_loop < - BoxOut, Point, StrategyLess, StrategyGreater, 0, dimension<Point>::type::value > @@ -236,9 +235,8 @@ template typename BoxOut, typename BoxIn, typename StrategyLess, typename StrategyGreater > -struct expand<box_tag, BoxOut, BoxIn, StrategyLess, StrategyGreater> - : detail::expand::expand_indexed - <BoxOut, BoxIn, StrategyLess, StrategyGreater> +struct expand<BoxOut, BoxIn, StrategyLess, StrategyGreater, box_tag, box_tag> + : detail::expand::expand_indexed<StrategyLess, StrategyGreater> {}; template @@ -246,9 +244,8 @@ template typename Box, typename Segment, typename StrategyLess, typename StrategyGreater > -struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater> - : detail::expand::expand_indexed - <Box, Segment, StrategyLess, StrategyGreater> +struct expand<Box, Segment, StrategyLess, StrategyGreater, box_tag, segment_tag> + : detail::expand::expand_indexed<StrategyLess, StrategyGreater> {}; @@ -256,6 +253,51 @@ struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater> #endif // DOXYGEN_NO_DISPATCH +namespace resolve_variant { + +template <typename Geometry> +struct expand +{ + template <typename Box> + static inline void apply(Box& box, Geometry const& geometry) + { + concept::check<Box>(); + concept::check<Geometry const>(); + concept::check_concepts_and_equal_dimensions<Box, Geometry const>(); + + dispatch::expand<Box, Geometry>::apply(box, geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Box> + struct visitor: boost::static_visitor<void> + { + Box& m_box; + + visitor(Box& box) : m_box(box) {} + + template <typename Geometry> + void operator()(Geometry const& geometry) const + { + return expand<Geometry>::apply(m_box, geometry); + } + }; + + template <class Box> + static inline void + apply(Box& box, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor<Box>(box), geometry); + } +}; + +} // namespace resolve_variant + + /*** *! \brief Expands a box using the extend (envelope) of another geometry (box, point) @@ -279,13 +321,7 @@ inline void expand(Box& box, Geometry const& geometry, { concept::check_concepts_and_equal_dimensions<Box, Geometry const>(); - dispatch::expand - < - typename tag<Geometry>::type, - Box, - Geometry, - StrategyLess, StrategyGreater - >::apply(box, geometry); + dispatch::expand<Box, Geometry>::apply(box, geometry); } ***/ @@ -303,15 +339,7 @@ inline void expand(Box& box, Geometry const& geometry, template <typename Box, typename Geometry> inline void expand(Box& box, Geometry const& geometry) { - concept::check_concepts_and_equal_dimensions<Box, Geometry const>(); - - dispatch::expand - < - typename tag<Geometry>::type, - Box, Geometry, - strategy::compare::default_strategy, - strategy::compare::default_strategy - >::apply(box, geometry); + resolve_variant::expand<Geometry>::apply(box, geometry); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/for_each.hpp b/boost/geometry/algorithms/for_each.hpp index 671f26a70d..c5c099b1ad 100644 --- a/boost/geometry/algorithms/for_each.hpp +++ b/boost/geometry/algorithms/for_each.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,17 +24,24 @@ #include <algorithm> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> +#include <boost/geometry/algorithms/not_implemented.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_type.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/util/add_const_if_c.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -39,127 +52,162 @@ namespace detail { namespace for_each { -template <typename Point, typename Functor, bool IsConst> struct fe_point_per_point { - static inline Functor apply( - typename add_const_if_c<IsConst, Point>::type& point, Functor f) + template <typename Point, typename Functor> + static inline void apply(Point& point, Functor& f) { f(point); - return f; } }; -template <typename Point, typename Functor, bool IsConst> struct fe_point_per_segment { - static inline Functor apply( - typename add_const_if_c<IsConst, Point>::type& , Functor f) + 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 - return f; } }; -template <typename Range, typename Functor, bool IsConst> struct fe_range_per_point { - static inline Functor apply( - typename add_const_if_c<IsConst, Range>::type& range, - Functor f) + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) { - return (std::for_each(boost::begin(range), boost::end(range), 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); + } } }; -template <typename Range, typename Functor, bool IsConst> -struct fe_range_per_segment +template <closure_selector Closure> +struct fe_range_per_segment_with_closure { - static inline Functor apply( - typename add_const_if_c<IsConst, Range>::type& range, - Functor f) + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) { typedef typename add_const_if_c < - IsConst, + is_const<Range>::value, typename point_type<Range>::type >::type point_type; - BOOST_AUTO_TPL(it, boost::begin(range)); - BOOST_AUTO_TPL(previous, it++); + typedef typename boost::range_iterator<Range>::type iterator_type; + + iterator_type it = boost::begin(range); + iterator_type previous = it++; while(it != boost::end(range)) { model::referring_segment<point_type> s(*previous, *it); f(s); previous = it++; } + } +}; + - return f; +template <> +struct fe_range_per_segment_with_closure<open> +{ + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) + { + fe_range_per_segment_with_closure<closed>::apply(range, f); + + model::referring_segment + < + typename add_const_if_c + < + is_const<Range>::value, + typename point_type<Range>::type + >::type + > s(range::back(range), range::front(range)); + + f(s); } }; -template <typename Polygon, typename Functor, bool IsConst> -struct fe_polygon_per_point +struct fe_range_per_segment { - typedef typename add_const_if_c<IsConst, Polygon>::type poly_type; + template <typename Range, typename Functor> + static inline void apply(Range& range, Functor& f) + { + fe_range_per_segment_with_closure + < + closure<Range>::value + >::apply(range, f); + } +}; + - static inline Functor apply(poly_type& poly, Functor f) +struct fe_polygon_per_point +{ + template <typename Polygon, typename Functor> + static inline void apply(Polygon& poly, Functor& f) { - typedef fe_range_per_point - < - typename ring_type<Polygon>::type, - Functor, - IsConst - > per_ring; + fe_range_per_point::apply(exterior_ring(poly), f); - f = per_ring::apply(exterior_ring(poly), f); + typename interior_return_type<Polygon>::type + rings = interior_rings(poly); - typename interior_return_type<poly_type>::type rings - = interior_rings(poly); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { - f = per_ring::apply(*it, f); + fe_range_per_point::apply(*it, f); } - - return f; } }; - -template <typename Polygon, typename Functor, bool IsConst> struct fe_polygon_per_segment { - typedef typename add_const_if_c<IsConst, Polygon>::type poly_type; - - static inline Functor apply(poly_type& poly, Functor f) + template <typename Polygon, typename Functor> + static inline void apply(Polygon& poly, Functor& f) { - typedef fe_range_per_segment - < - typename ring_type<Polygon>::type, - Functor, - IsConst - > per_ring; + fe_range_per_segment::apply(exterior_ring(poly), f); - f = per_ring::apply(exterior_ring(poly), f); + typename interior_return_type<Polygon>::type + rings = interior_rings(poly); - typename interior_return_type<poly_type>::type rings - = interior_rings(poly); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { - f = per_ring::apply(*it, f); + fe_range_per_segment::apply(*it, f); } - - return f; } }; +// 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 (typename boost::range_iterator<MultiGeometry>::type + it = boost::begin(multi); it != boost::end(multi); ++it) + { + Policy::apply(*it, f); + } + } +}; }} // namespace detail::for_each #endif // DOXYGEN_NO_DETAIL @@ -171,102 +219,105 @@ namespace dispatch template < - typename Tag, typename Geometry, - typename Functor, - bool IsConst + typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type > -struct for_each_point {}; +struct for_each_point: not_implemented<Tag> +{}; -template <typename Point, typename Functor, bool IsConst> -struct for_each_point<point_tag, Point, Functor, IsConst> - : detail::for_each::fe_point_per_point<Point, Functor, IsConst> +template <typename Point> +struct for_each_point<Point, point_tag> + : detail::for_each::fe_point_per_point {}; -template <typename Linestring, typename Functor, bool IsConst> -struct for_each_point<linestring_tag, Linestring, Functor, IsConst> - : detail::for_each::fe_range_per_point<Linestring, Functor, IsConst> +template <typename Linestring> +struct for_each_point<Linestring, linestring_tag> + : detail::for_each::fe_range_per_point {}; -template <typename Ring, typename Functor, bool IsConst> -struct for_each_point<ring_tag, Ring, Functor, IsConst> - : detail::for_each::fe_range_per_point<Ring, Functor, IsConst> +template <typename Ring> +struct for_each_point<Ring, ring_tag> + : detail::for_each::fe_range_per_point {}; -template <typename Polygon, typename Functor, bool IsConst> -struct for_each_point<polygon_tag, Polygon, Functor, IsConst> - : detail::for_each::fe_polygon_per_point<Polygon, Functor, IsConst> +template <typename Polygon> +struct for_each_point<Polygon, polygon_tag> + : detail::for_each::fe_polygon_per_point {}; template < - typename Tag, typename Geometry, - typename Functor, - bool IsConst + typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type > -struct for_each_segment {}; +struct for_each_segment: not_implemented<Tag> +{}; -template <typename Point, typename Functor, bool IsConst> -struct for_each_segment<point_tag, Point, Functor, IsConst> - : detail::for_each::fe_point_per_segment<Point, Functor, IsConst> +template <typename Point> +struct for_each_segment<Point, point_tag> + : detail::for_each::fe_point_per_segment {}; -template <typename Linestring, typename Functor, bool IsConst> -struct for_each_segment<linestring_tag, Linestring, Functor, IsConst> - : detail::for_each::fe_range_per_segment<Linestring, Functor, IsConst> +template <typename Linestring> +struct for_each_segment<Linestring, linestring_tag> + : detail::for_each::fe_range_per_segment {}; -template <typename Ring, typename Functor, bool IsConst> -struct for_each_segment<ring_tag, Ring, Functor, IsConst> - : detail::for_each::fe_range_per_segment<Ring, Functor, IsConst> +template <typename Ring> +struct for_each_segment<Ring, ring_tag> + : detail::for_each::fe_range_per_segment {}; -template <typename Polygon, typename Functor, bool IsConst> -struct for_each_segment<polygon_tag, Polygon, Functor, IsConst> - : detail::for_each::fe_polygon_per_segment<Polygon, Functor, IsConst> +template <typename Polygon> +struct for_each_segment<Polygon, polygon_tag> + : detail::for_each::fe_polygon_per_segment {}; -} // namespace dispatch -#endif // DOXYGEN_NO_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 + > + > +{}; -/*! -\brief \brf_for_each{point} -\details \det_for_each{point} -\ingroup for_each -\param geometry \param_geometry -\param f \par_for_each_f{const point} -\tparam Geometry \tparam_geometry -\tparam Functor \tparam_functor +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 + > + > +{}; -\qbk{distinguish,const version} -\qbk{[include reference/algorithms/for_each_point.qbk]} -\qbk{[heading Example]} -\qbk{[for_each_point_const] [for_each_point_const_output]} -*/ -template<typename Geometry, typename Functor> -inline Functor for_each_point(Geometry const& geometry, Functor f) -{ - concept::check<Geometry const>(); - return dispatch::for_each_point - < - typename tag_cast<typename tag<Geometry>::type, multi_tag>::type, - Geometry, - Functor, - true - >::apply(geometry, f); -} +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH /*! @@ -281,19 +332,15 @@ inline Functor for_each_point(Geometry const& geometry, Functor f) \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>(); - return dispatch::for_each_point - < - typename tag_cast<typename tag<Geometry>::type, multi_tag>::type, - Geometry, - Functor, - false - >::apply(geometry, f); + dispatch::for_each_point<Geometry>::apply(geometry, f); + return f; } @@ -302,53 +349,21 @@ inline Functor for_each_point(Geometry& geometry, Functor f) \details \det_for_each{segment} \ingroup for_each \param geometry \param_geometry -\param f \par_for_each_f{const segment} +\param f \par_for_each_f{segment} \tparam Geometry \tparam_geometry \tparam Functor \tparam_functor -\qbk{distinguish,const version} \qbk{[include reference/algorithms/for_each_segment.qbk]} \qbk{[heading Example]} \qbk{[for_each_segment_const] [for_each_segment_const_output]} */ template<typename Geometry, typename Functor> -inline Functor for_each_segment(Geometry const& geometry, Functor f) -{ - concept::check<Geometry const>(); - - return dispatch::for_each_segment - < - typename tag_cast<typename tag<Geometry>::type, multi_tag>::type, - Geometry, - Functor, - true - >::apply(geometry, f); -} - - -/*! -\brief \brf_for_each{segment} -\details \det_for_each{segment} -\ingroup for_each -\param geometry \param_geometry -\param f \par_for_each_f{segment} -\tparam Geometry \tparam_geometry -\tparam Functor \tparam_functor - -\qbk{[include reference/algorithms/for_each_segment.qbk]} -*/ -template<typename Geometry, typename Functor> inline Functor for_each_segment(Geometry& geometry, Functor f) { concept::check<Geometry>(); - return dispatch::for_each_segment - < - typename tag_cast<typename tag<Geometry>::type, multi_tag>::type, - Geometry, - Functor, - false - >::apply(geometry, f); + dispatch::for_each_segment<Geometry>::apply(geometry, f); + return f; } diff --git a/boost/geometry/algorithms/intersection.hpp b/boost/geometry/algorithms/intersection.hpp index 8d3dd68b3a..0169f12db1 100644 --- a/boost/geometry/algorithms/intersection.hpp +++ b/boost/geometry/algorithms/intersection.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -10,228 +15,8 @@ #define BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> -#include <boost/geometry/algorithms/intersects.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace intersection -{ - -template -< - typename Box1, typename Box2, - typename BoxOut, - typename Strategy, - std::size_t Dimension, std::size_t DimensionCount -> -struct intersection_box_box -{ - static inline bool apply(Box1 const& box1, - Box2 const& box2, BoxOut& box_out, - Strategy const& strategy) - { - typedef typename coordinate_type<BoxOut>::type ct; - - ct min1 = get<min_corner, Dimension>(box1); - ct min2 = get<min_corner, Dimension>(box2); - ct max1 = get<max_corner, Dimension>(box1); - ct max2 = get<max_corner, Dimension>(box2); - - if (max1 < min2 || max2 < min1) - { - return false; - } - // Set dimensions of output coordinate - set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1); - set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1); - - return intersection_box_box - < - Box1, Box2, BoxOut, Strategy, - Dimension + 1, DimensionCount - >::apply(box1, box2, box_out, strategy); - } -}; - -template -< - typename Box1, typename Box2, - typename BoxOut, - typename Strategy, - std::size_t DimensionCount -> -struct intersection_box_box<Box1, Box2, BoxOut, Strategy, DimensionCount, DimensionCount> -{ - static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&) - { - return true; - } -}; - - -}} // namespace detail::intersection -#endif // DOXYGEN_NO_DETAIL - - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -// By default, all is forwarded to the intersection_insert-dispatcher -template -< - typename Tag1, typename Tag2, typename TagOut, - typename Geometry1, typename Geometry2, - typename GeometryOut, - typename Strategy -> -struct intersection -{ - typedef std::back_insert_iterator<GeometryOut> output_iterator; - - static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - { - typedef typename boost::range_value<GeometryOut>::type OneOut; - - intersection_insert - < - Tag1, Tag2, typename geometry::tag<OneOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<OneOut>::value, - Geometry1, Geometry2, - detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, false>::value, - detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, false>::value, - detail::overlay::do_reverse<geometry::point_order<OneOut>::value>::value, - output_iterator, OneOut, - overlay_intersection, - Strategy - >::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy); - - return true; - } - -}; - - -template -< - typename Box1, typename Box2, - typename BoxOut, - typename Strategy -> -struct intersection - < - box_tag, box_tag, box_tag, - Box1, Box2, BoxOut, - Strategy - > : public detail::intersection::intersection_box_box - < - Box1, Box2, BoxOut, - Strategy, - 0, geometry::dimension<Box1>::value - > -{}; - - -template -< - typename Tag1, typename Tag2, typename TagOut, - typename Geometry1, typename Geometry2, - typename GeometryOut, - typename Strategy -> -struct intersection_reversed -{ - static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - { - return intersection - < - Tag2, Tag1, TagOut, - Geometry2, Geometry1, - GeometryOut, Strategy - >::apply(geometry2, geometry1, geometry_out, strategy); - } -}; - - - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -/*! -\brief \brief_calc2{intersection} -\ingroup intersection -\details \details_calc2{intersection, spatial set theoretic intersection}. -\tparam Geometry1 \tparam_geometry -\tparam Geometry2 \tparam_geometry -\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which - the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box) -\param geometry1 \param_geometry -\param geometry2 \param_geometry -\param geometry_out The output geometry, either a multi_point, multi_polygon, - multi_linestring, or a box (for intersection of two boxes) - -\qbk{[include reference/algorithms/intersection.qbk]} -*/ -template -< - typename Geometry1, - typename Geometry2, - typename GeometryOut -> -inline bool intersection(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out) -{ - concept::check<Geometry1 const>(); - concept::check<Geometry2 const>(); - - typedef strategy_intersection - < - typename cs_tag<Geometry1>::type, - Geometry1, - Geometry2, - typename geometry::point_type<Geometry1>::type - > strategy; - - - return boost::mpl::if_c - < - geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, - dispatch::intersection_reversed - < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - Geometry1, Geometry2, GeometryOut, strategy - >, - dispatch::intersection - < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - Geometry1, Geometry2, GeometryOut, strategy - > - >::type::apply(geometry1, geometry2, geometry_out, strategy()); -} - - -}} // namespace boost::geometry +#include <boost/geometry/algorithms/detail/intersection/interface.hpp> +#include <boost/geometry/algorithms/detail/intersection/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp index f367f2e258..1bb85aa3bb 100644 --- a/boost/geometry/algorithms/intersects.hpp +++ b/boost/geometry/algorithms/intersects.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -21,6 +26,9 @@ #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> + namespace boost { namespace geometry { @@ -43,37 +51,29 @@ inline bool intersects(Geometry const& geometry) { concept::check<Geometry const>(); + typedef typename geometry::point_type<Geometry>::type point_type; + typedef detail::no_rescale_policy rescale_policy_type; typedef detail::overlay::turn_info < - typename geometry::point_type<Geometry>::type + point_type, + typename segment_ratio_type<point_type, rescale_policy_type>::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; + std::deque<turn_info> turns; typedef detail::overlay::get_turn_info < - typename point_type<Geometry>::type, - typename point_type<Geometry>::type, - turn_info, detail::overlay::assign_null_policy - > TurnPolicy; + > turn_policy; + + rescale_policy_type robust_policy; 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); + < + turn_policy + >::apply(geometry, robust_policy, turns, policy); return policy.has_intersections; } diff --git a/boost/geometry/algorithms/is_simple.hpp b/boost/geometry/algorithms/is_simple.hpp new file mode 100644 index 0000000000..f48c957dfc --- /dev/null +++ b/boost/geometry/algorithms/is_simple.hpp @@ -0,0 +1,16 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP + +#include <boost/geometry/algorithms/detail/is_simple/interface.hpp> +#include <boost/geometry/algorithms/detail/is_simple/implementation.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP diff --git a/boost/geometry/algorithms/is_valid.hpp b/boost/geometry/algorithms/is_valid.hpp new file mode 100644 index 0000000000..24dc5f7737 --- /dev/null +++ b/boost/geometry/algorithms/is_valid.hpp @@ -0,0 +1,16 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP +#define BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP + +#include <boost/geometry/algorithms/detail/is_valid/interface.hpp> +#include <boost/geometry/algorithms/detail/is_valid/implementation.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP diff --git a/boost/geometry/algorithms/length.hpp b/boost/geometry/algorithms/length.hpp index de53a39e8f..6cbec5303e 100644 --- a/boost/geometry/algorithms/length.hpp +++ b/boost/geometry/algorithms/length.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,18 +21,32 @@ #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/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/tags.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/multi_sum.hpp> // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/strategies/distance.hpp> @@ -43,9 +62,10 @@ namespace detail { namespace length { -template<typename Segment, typename Strategy> +template<typename Segment> struct segment_length { + template <typename Strategy> static inline typename default_length_result<Segment>::type apply( Segment const& segment, Strategy const& strategy) { @@ -63,14 +83,16 @@ struct segment_length \note for_each could be used here, now that point_type is changed by boost range iterator */ -template<typename Range, typename Strategy, closure_selector Closure> +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 < @@ -106,35 +128,111 @@ namespace dispatch { -template <typename Tag, typename Geometry, typename Strategy> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct length : detail::calculate_null - < - typename default_length_result<Geometry>::type, - Geometry, - Strategy - > -{}; +{ + 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, typename Strategy> -struct length<linestring_tag, Geometry, Strategy> - : detail::length::range_length<Geometry, Strategy, closed> + +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, typename Strategy> -struct length<segment_tag, Geometry, Strategy> - : detail::length::segment_length<Geometry, Strategy> +template <typename Geometry> +struct length<Geometry, segment_tag> + : detail::length::segment_length<Geometry> {}; +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 // DOXYGEN_NO_DISPATCH +namespace resolve_variant { + +template <typename Geometry> +struct length +{ + template <typename Strategy> + static inline typename default_length_result<Geometry>::type + apply(Geometry const& geometry, Strategy const& strategy) + { + return dispatch::length<Geometry>::apply(geometry, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct length<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + typedef typename default_length_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> + >::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 default_length_result<Geometry>::type + operator()(Geometry const& geometry) const + { + return 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 resolve_variant + + /*! \brief \brief_calc{length} \ingroup length @@ -147,24 +245,20 @@ struct length<segment_tag, Geometry, Strategy> \qbk{[length] [length_output]} */ template<typename Geometry> -inline typename default_length_result<Geometry>::type length( - Geometry const& geometry) +inline typename default_length_result<Geometry>::type +length(Geometry const& geometry) { concept::check<Geometry const>(); // detail::throw_on_empty_input(geometry); + // TODO put this into a resolve_strategy stage typedef typename strategy::distance::services::default_strategy < - point_tag, typename point_type<Geometry>::type + point_tag, point_tag, typename point_type<Geometry>::type >::type strategy_type; - return dispatch::length - < - typename tag<Geometry>::type, - Geometry, - strategy_type - >::apply(geometry, strategy_type()); + return resolve_variant::length<Geometry>::apply(geometry, strategy_type()); } @@ -183,19 +277,14 @@ inline typename default_length_result<Geometry>::type length( \qbk{[length_with_strategy] [length_with_strategy_output]} */ template<typename Geometry, typename Strategy> -inline typename default_length_result<Geometry>::type length( - Geometry const& geometry, Strategy const& strategy) +inline typename default_length_result<Geometry>::type +length(Geometry const& geometry, Strategy const& strategy) { concept::check<Geometry const>(); // detail::throw_on_empty_input(geometry); - - return dispatch::length - < - typename tag<Geometry>::type, - Geometry, - Strategy - >::apply(geometry, strategy); + + return resolve_variant::length<Geometry>::apply(geometry, strategy); } diff --git a/boost/geometry/algorithms/not_implemented.hpp b/boost/geometry/algorithms/not_implemented.hpp index 008f111cc8..cd40a2772f 100644 --- a/boost/geometry/algorithms/not_implemented.hpp +++ b/boost/geometry/algorithms/not_implemented.hpp @@ -18,7 +18,6 @@ #include <boost/mpl/assert.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/multi/core/tags.hpp> namespace boost { namespace geometry diff --git a/boost/geometry/algorithms/num_geometries.hpp b/boost/geometry/algorithms/num_geometries.hpp index 20f35e90d2..d37d0bfabe 100644 --- a/boost/geometry/algorithms/num_geometries.hpp +++ b/boost/geometry/algorithms/num_geometries.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -17,7 +22,12 @@ #include <cstddef> -#include <boost/mpl/assert.hpp> +#include <boost/range.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> @@ -25,6 +35,8 @@ #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/counting.hpp> + namespace boost { namespace geometry { @@ -35,30 +47,74 @@ namespace dispatch { -template <typename Tag, typename Geometry> -struct num_geometries +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> + : detail::counting::other_count<1> +{}; + + +template <typename MultiGeometry> +struct num_geometries<MultiGeometry, multi_tag> { - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry>) - ); + static inline std::size_t apply(MultiGeometry const& multi_geometry) + { + return boost::size(multi_geometry); + } }; +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant +{ + template <typename Geometry> -struct num_geometries<single_tag, Geometry> +struct num_geometries { - static inline std::size_t apply(Geometry const&) + static inline std::size_t apply(Geometry const& geometry) { - return 1; + concept::check<Geometry const>(); + + return dispatch::num_geometries<Geometry>::apply(geometry); } }; +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct num_geometries<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<std::size_t> + { + template <typename Geometry> + inline std::size_t operator()(Geometry const& geometry) const + { + return num_geometries<Geometry>::apply(geometry); + } + }; + + static inline std::size_t + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; - -} // namespace dispatch -#endif +} // namespace resolve_variant /*! @@ -74,18 +130,7 @@ struct num_geometries<single_tag, Geometry> template <typename Geometry> inline std::size_t num_geometries(Geometry const& geometry) { - concept::check<Geometry const>(); - - return dispatch::num_geometries - < - typename tag_cast - < - typename tag<Geometry>::type, - single_tag, - multi_tag - >::type, - Geometry - >::apply(geometry); + return resolve_variant::num_geometries<Geometry>::apply(geometry); } diff --git a/boost/geometry/algorithms/num_interior_rings.hpp b/boost/geometry/algorithms/num_interior_rings.hpp index 2149f46576..e198b37a75 100644 --- a/boost/geometry/algorithms/num_interior_rings.hpp +++ b/boost/geometry/algorithms/num_interior_rings.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,11 +24,19 @@ #include <boost/range.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/algorithms/detail/counting.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + namespace boost { namespace geometry { @@ -32,19 +46,15 @@ namespace dispatch { -template <typename Tag, typename Geometry> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct num_interior_rings -{ - static inline std::size_t apply(Geometry const& ) - { - return 0; - } -}; + : detail::counting::other_count<0> +{}; template <typename Polygon> -struct num_interior_rings<polygon_tag, Polygon> +struct num_interior_rings<Polygon, polygon_tag> { static inline std::size_t apply(Polygon const& polygon) { @@ -54,8 +64,56 @@ struct num_interior_rings<polygon_tag, Polygon> }; +template <typename MultiPolygon> +struct num_interior_rings<MultiPolygon, multi_polygon_tag> + : detail::counting::multi_count + < + num_interior_rings + < + typename boost::range_value<MultiPolygon const>::type + > + > +{}; + + } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant +{ + +template <typename Geometry> +struct num_interior_rings +{ + static inline std::size_t apply(Geometry const& geometry) + { + concept::check<Geometry const>(); + + return dispatch::num_interior_rings<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct num_interior_rings<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<std::size_t> + { + template <typename Geometry> + inline std::size_t operator()(Geometry const& geometry) const + { + return num_interior_rings<Geometry>::apply(geometry); + } + }; + + static inline std::size_t + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant /*! @@ -74,11 +132,7 @@ struct num_interior_rings<polygon_tag, Polygon> template <typename Geometry> inline std::size_t num_interior_rings(Geometry const& geometry) { - return dispatch::num_interior_rings - < - typename tag<Geometry>::type, - Geometry - >::apply(geometry); + return resolve_variant::num_interior_rings<Geometry>::apply(geometry); } diff --git a/boost/geometry/algorithms/num_points.hpp b/boost/geometry/algorithms/num_points.hpp index c480068f43..4c2ad3b08c 100644 --- a/boost/geometry/algorithms/num_points.hpp +++ b/boost/geometry/algorithms/num_points.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,76 +22,55 @@ #include <cstddef> -#include <boost/mpl/assert.hpp> +#include <boost/mpl/size_t.hpp> + #include <boost/range.hpp> -#include <boost/typeof/typeof.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/ring_type.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/algorithms/detail/counting.hpp> -#include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/geometries/concepts/check.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 { -template <typename Range> +template <bool AddForOpen> struct range_count { - static inline std::size_t apply(Range const& range, bool add_for_open) + template <typename Range> + static inline std::size_t apply(Range const& range) { std::size_t n = boost::size(range); - if (add_for_open && n > 0) - { - closure_selector const s = geometry::closure<Range>::value; - - if (s == open) - { - if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1))) - { - return n + 1; - } - } - } - return n; - } -}; - -template <typename Geometry, std::size_t D> -struct other_count -{ - static inline std::size_t apply(Geometry const&, bool) - { - return D; - } -}; - -template <typename Polygon> -struct polygon_count -{ - static inline std::size_t apply(Polygon const& poly, bool add_for_open) - { - typedef typename geometry::ring_type<Polygon>::type ring_type; - - std::size_t n = range_count<ring_type>::apply( - exterior_ring(poly), add_for_open); - - typename interior_return_type<Polygon const>::type rings - = interior_rings(poly); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + if (AddForOpen + && n > 0 + && geometry::closure<Range>::value == open + ) { - n += range_count<ring_type>::apply(*it, add_for_open); + return n + 1; } - return n; } }; @@ -98,50 +83,107 @@ struct polygon_count namespace dispatch { -template <typename GeometryTag, typename Geometry> -struct num_points -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry>) - ); -}; +template +< + typename Geometry, + bool AddForOpen, + typename Tag = typename tag_cast + < + typename tag<Geometry>::type, multi_tag + >::type +> +struct num_points: not_implemented<Tag> +{}; -template <typename Geometry> -struct num_points<point_tag, Geometry> - : detail::num_points::other_count<Geometry, 1> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, point_tag> + : detail::counting::other_count<1> {}; -template <typename Geometry> -struct num_points<box_tag, Geometry> - : detail::num_points::other_count<Geometry, 4> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, box_tag> + : detail::counting::other_count<(1 << geometry::dimension<Geometry>::value)> {}; -template <typename Geometry> -struct num_points<segment_tag, Geometry> - : detail::num_points::other_count<Geometry, 2> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, segment_tag> + : detail::counting::other_count<2> {}; -template <typename Geometry> -struct num_points<linestring_tag, Geometry> - : detail::num_points::range_count<Geometry> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, linestring_tag> + : detail::num_points::range_count<AddForOpen> {}; -template <typename Geometry> -struct num_points<ring_tag, Geometry> - : detail::num_points::range_count<Geometry> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, ring_tag> + : detail::num_points::range_count<AddForOpen> {}; -template <typename Geometry> -struct num_points<polygon_tag, Geometry> - : detail::num_points::polygon_count<Geometry> +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, polygon_tag> + : detail::counting::polygon_count + < + detail::num_points::range_count<AddForOpen> + > +{}; + +template <typename Geometry, bool AddForOpen> +struct num_points<Geometry, AddForOpen, multi_tag> + : detail::counting::multi_count + < + num_points<typename boost::range_value<Geometry>::type, AddForOpen> + > {}; } // namespace dispatch #endif +namespace resolve_variant +{ + +template <typename Geometry> +struct num_points +{ + static inline std::size_t apply(Geometry const& geometry, + bool add_for_open) + { + concept::check<Geometry const>(); + + return add_for_open + ? dispatch::num_points<Geometry, true>::apply(geometry) + : dispatch::num_points<Geometry, false>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct 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> + inline std::size_t operator()(Geometry const& geometry) const + { + return 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 resolve_variant + + /*! \brief \brief_calc{number of points} \ingroup num_points @@ -156,15 +198,13 @@ struct num_points<polygon_tag, Geometry> template <typename Geometry> inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false) { - concept::check<Geometry const>(); - - return dispatch::num_points - < - typename tag_cast<typename tag<Geometry>::type, multi_tag>::type, - Geometry - >::apply(geometry, add_for_open); + return resolve_variant::num_points<Geometry>::apply(geometry, add_for_open); } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/num_segments.hpp b/boost/geometry/algorithms/num_segments.hpp new file mode 100644 index 0000000000..cbb5685967 --- /dev/null +++ b/boost/geometry/algorithms/num_segments.hpp @@ -0,0 +1,204 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP + +#include <cstddef> + +#include <boost/mpl/size_t.hpp> +#include <boost/mpl/times.hpp> + +#include <boost/range.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/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/range.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/algorithms/detail/counting.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace num_segments +{ + + +struct range_count +{ + template <typename Range> + static inline std::size_t apply(Range const& range) + { + std::size_t n = boost::size(range); + if ( n <= 1 ) + { + return 0; + } + + return + geometry::closure<Range>::value == open + ? + n + : + static_cast<std::size_t>(n - 1); + } +}; + +}} // namespace detail::num_segments +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct num_segments + : not_implemented<Tag> +{}; + +template <typename Geometry> +struct num_segments<Geometry, point_tag> + : detail::counting::other_count<0> +{}; + +// the number of segments (1-dimensional faces) of the hypercube is +// given by the formula: d * 2^(d-1), where d is the dimension of the +// hypercube; see also: +// http://en.wikipedia.org/wiki/Hypercube +template <typename Geometry> +struct num_segments<Geometry, box_tag> + : detail::counting::other_count + < + geometry::dimension<Geometry>::value + * (1 << (geometry::dimension<Geometry>::value - 1)) + > +{}; + +template <typename Geometry> +struct num_segments<Geometry, segment_tag> + : detail::counting::other_count<1> +{}; + +template <typename Geometry> +struct num_segments<Geometry, linestring_tag> + : detail::num_segments::range_count +{}; + +template <typename Geometry> +struct num_segments<Geometry, ring_tag> + : detail::num_segments::range_count +{}; + +template <typename Geometry> +struct num_segments<Geometry, polygon_tag> + : detail::counting::polygon_count<detail::num_segments::range_count> +{}; + +template <typename Geometry> +struct num_segments<Geometry, multi_point_tag> + : detail::counting::other_count<0> +{}; + +template <typename Geometry> +struct num_segments<Geometry, multi_linestring_tag> + : detail::counting::multi_count + < + num_segments< typename boost::range_value<Geometry>::type> + > +{}; + +template <typename Geometry> +struct num_segments<Geometry, multi_polygon_tag> + : detail::counting::multi_count + < + num_segments< typename boost::range_value<Geometry>::type> + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +namespace resolve_variant +{ + + +template <typename Geometry> +struct num_segments +{ + static inline std::size_t apply(Geometry const& geometry) + { + concept::check<Geometry const>(); + + return dispatch::num_segments<Geometry>::apply(geometry); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<std::size_t> + { + template <typename Geometry> + inline std::size_t operator()(Geometry const& geometry) const + { + return num_segments<Geometry>::apply(geometry); + } + }; + + static inline std::size_t + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; + + +} // namespace resolve_variant + + + +/*! +\brief \brief_calc{number of segments} +\ingroup num_segments +\details \details_calc{num_segments, number of segments}. +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\return \return_calc{number of segments} + +\qbk{[include reference/algorithms/num_segments.qbk]} +*/ +template <typename Geometry> +inline std::size_t num_segments(Geometry const& geometry) +{ + return resolve_variant::num_segments<Geometry>::apply(geometry); +} + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp index 2f854b4fdd..f724a544fd 100644 --- a/boost/geometry/algorithms/overlaps.hpp +++ b/boost/geometry/algorithms/overlaps.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,18 +14,22 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP #define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP #include <cstddef> -#include <boost/mpl/assert.hpp> - #include <boost/geometry/core/access.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/relate/relate.hpp> + namespace boost { namespace geometry { @@ -32,13 +39,12 @@ namespace detail { namespace overlaps template < - typename Box1, - typename Box2, 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) { @@ -84,8 +90,6 @@ struct box_box_loop box_box_loop < - Box1, - Box2, Dimension + 1, DimensionCount >::apply(b1, b2, overlaps, one_in_two, two_in_one); @@ -94,24 +98,19 @@ struct box_box_loop template < - typename Box1, - typename Box2, std::size_t DimensionCount > -struct box_box_loop<Box1, Box2, DimensionCount, DimensionCount> +struct box_box_loop<DimensionCount, DimensionCount> { + template <typename Box1, typename Box2> static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&) { } }; -template -< - typename Box1, - typename Box2 -> struct box_box { + template <typename Box1, typename Box2> static inline bool apply(Box1 const& b1, Box2 const& b2) { bool overlaps = true; @@ -119,8 +118,6 @@ struct box_box bool within2 = true; box_box_loop < - Box1, - Box2, 0, dimension<Box1>::type::value >::apply(b1, b2, overlaps, within1, within2); @@ -134,8 +131,6 @@ struct box_box } }; - - }} // namespace detail::overlaps #endif // DOXYGEN_NO_DETAIL @@ -148,29 +143,26 @@ namespace dispatch template < - typename Tag1, - typename Tag2, typename Geometry1, - typename Geometry2 + typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type > struct overlaps -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry1, Geometry2>) - ); -}; + : detail::relate::relate_base + < + detail::relate::static_mask_overlaps_type, + Geometry1, + Geometry2 + > +{}; template <typename Box1, typename Box2> -struct overlaps<box_tag, box_tag, Box1, Box2> - : detail::overlaps::box_box<Box1, Box2> +struct overlaps<Box1, Box2, box_tag, box_tag> + : detail::overlaps::box_box {}; - - - } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -178,6 +170,10 @@ struct overlaps<box_tag, box_tag, Box1, Box2> /*! \brief \brief_check2{overlap} \ingroup overlaps +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry \return \return_check2{overlap} \qbk{[include reference/algorithms/overlaps.qbk]} @@ -190,8 +186,6 @@ inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2) return dispatch::overlaps < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, Geometry1, Geometry2 >::apply(geometry1, geometry2); diff --git a/boost/geometry/algorithms/perimeter.hpp b/boost/geometry/algorithms/perimeter.hpp index adeb0b05b0..0ec153c1f4 100644 --- a/boost/geometry/algorithms/perimeter.hpp +++ b/boost/geometry/algorithms/perimeter.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,16 +19,22 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP #define BOOST_GEOMETRY_ALGORITHMS_PERIMETER_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/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/multi_sum.hpp> // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> - +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/default_length_result.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> namespace boost { namespace geometry { @@ -33,40 +44,59 @@ namespace dispatch { // Default perimeter is 0.0, specializations implement calculated values -template <typename Tag, typename Geometry, typename Strategy> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct perimeter : detail::calculate_null - < - typename default_length_result<Geometry>::type, - Geometry, - Strategy - > -{}; +{ + 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, typename Strategy> -struct perimeter<ring_tag, Geometry, Strategy> +template <typename Geometry> +struct perimeter<Geometry, ring_tag> : detail::length::range_length < Geometry, - Strategy, closure<Geometry>::value > {}; -template <typename Polygon, typename Strategy> -struct perimeter<polygon_tag, Polygon, Strategy> - : detail::calculate_polygon_sum - < - typename default_length_result<Polygon>::type, - Polygon, - Strategy, - detail::length::range_length +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, - Strategy, 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); + } +}; + +template <typename MultiPolygon> +struct perimeter<MultiPolygon, multi_polygon_tag> : detail::multi_sum +{ + typedef typename default_length_result<MultiPolygon>::type return_type; + + template <typename Strategy> + static inline return_type apply(MultiPolygon const& multi, Strategy const& strategy) + { + return multi_sum::apply + < + return_type, + perimeter<typename boost::range_value<MultiPolygon>::type> + >(multi, strategy); + } +}; // box,n-sphere: to be implemented @@ -75,6 +105,82 @@ struct perimeter<polygon_tag, Polygon, Strategy> #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy { + +struct perimeter +{ + template <typename Geometry, typename Strategy> + static inline typename default_length_result<Geometry>::type + apply(Geometry const& geometry, Strategy const& strategy) + { + return dispatch::perimeter<Geometry>::apply(geometry, strategy); + } + + template <typename Geometry> + static inline typename default_length_result<Geometry>::type + apply(Geometry const& geometry, default_strategy) + { + typedef typename strategy::distance::services::default_strategy + < + point_tag, point_tag, typename point_type<Geometry>::type + >::type strategy_type; + + return dispatch::perimeter<Geometry>::apply(geometry, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry> +struct perimeter +{ + template <typename Strategy> + static inline typename default_length_result<Geometry>::type + apply(Geometry const& geometry, Strategy const& strategy) + { + concept::check<Geometry const>(); + return resolve_strategy::perimeter::apply(geometry, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct perimeter<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + typedef typename default_length_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> + >::type result_type; + + template <typename Strategy> + struct visitor: boost::static_visitor<result_type> + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy): m_strategy(strategy) {} + + template <typename Geometry> + typename default_length_result<Geometry>::type + operator()(Geometry const& geometry) const + { + return perimeter<Geometry>::apply(geometry, m_strategy); + } + }; + + template <typename Strategy> + static inline result_type + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Strategy const& strategy) + { + return boost::apply_visitor(visitor<Strategy>(strategy), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc{perimeter} \ingroup perimeter @@ -90,22 +196,8 @@ template<typename Geometry> inline typename default_length_result<Geometry>::type perimeter( Geometry const& geometry) { - concept::check<Geometry const>(); - - typedef typename point_type<Geometry>::type point_type; - typedef typename strategy::distance::services::default_strategy - < - point_tag, point_type - >::type strategy_type; - // detail::throw_on_empty_input(geometry); - - return dispatch::perimeter - < - typename tag<Geometry>::type, - Geometry, - strategy_type - >::apply(geometry, strategy_type()); + return resolve_variant::perimeter<Geometry>::apply(geometry, default_strategy()); } /*! @@ -126,16 +218,8 @@ template<typename Geometry, typename Strategy> inline typename default_length_result<Geometry>::type perimeter( Geometry const& geometry, Strategy const& strategy) { - concept::check<Geometry const>(); - // detail::throw_on_empty_input(geometry); - - return dispatch::perimeter - < - typename tag<Geometry>::type, - Geometry, - Strategy - >::apply(geometry, strategy); + return resolve_variant::perimeter<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/point_on_surface.hpp b/boost/geometry/algorithms/point_on_surface.hpp new file mode 100644 index 0000000000..3fa83bfe6f --- /dev/null +++ b/boost/geometry/algorithms/point_on_surface.hpp @@ -0,0 +1,327 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP + + +#include <cstddef> + +#include <numeric> + +#include <boost/concept_check.hpp> +#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/detail/extreme_points.hpp> + +#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_on_surface +{ + +template <typename CoordinateType, int Dimension> +struct specific_coordinate_first +{ + CoordinateType const m_value_to_be_first; + + inline specific_coordinate_first(CoordinateType value_to_be_skipped) + : m_value_to_be_first(value_to_be_skipped) + {} + + template <typename Point> + inline bool operator()(Point const& lhs, Point const& rhs) + { + CoordinateType const lh = geometry::get<Dimension>(lhs); + CoordinateType const rh = geometry::get<Dimension>(rhs); + + // If both lhs and rhs equal m_value_to_be_first, + // we should handle conform if lh < rh = FALSE + // The first condition meets that, keep it first + if (geometry::math::equals(rh, m_value_to_be_first)) + { + // Handle conform lh < -INF, which is always false + return false; + } + + if (geometry::math::equals(lh, m_value_to_be_first)) + { + // Handle conform -INF < rh, which is always true + return true; + } + + return lh < rh; + } +}; + +template <int Dimension, typename Collection, typename Value, typename Predicate> +inline bool max_value(Collection const& collection, Value& the_max, Predicate const& predicate) +{ + bool first = true; + for (typename Collection::const_iterator it = collection.begin(); it != collection.end(); ++it) + { + if (! it->empty()) + { + Value the_value = geometry::get<Dimension>(*std::max_element(it->begin(), it->end(), predicate)); + if (first || the_value > the_max) + { + the_max = the_value; + first = false; + } + } + } + return ! first; +} + + +template <int Dimension, typename Value> +struct select_below +{ + Value m_value; + inline select_below(Value const& v) + : m_value(v) + {} + + template <typename Intruder> + inline bool operator()(Intruder const& intruder) const + { + if (intruder.empty()) + { + return true; + } + Value max = geometry::get<Dimension>(*std::max_element(intruder.begin(), intruder.end(), detail::extreme_points::compare<Dimension>())); + return geometry::math::equals(max, m_value) || max < m_value; + } +}; + +template <int Dimension, typename Value> +struct adapt_base +{ + Value m_value; + inline adapt_base(Value const& v) + : m_value(v) + {} + + template <typename Intruder> + inline void operator()(Intruder& intruder) const + { + if (intruder.size() >= 3) + { + detail::extreme_points::move_along_vector<Dimension>(intruder, m_value); + } + } +}; + +template <int Dimension, typename Value> +struct min_of_intruder +{ + template <typename Intruder> + inline bool operator()(Intruder const& lhs, Intruder const& rhs) const + { + Value lhs_min = geometry::get<Dimension>(*std::min_element(lhs.begin(), lhs.end(), detail::extreme_points::compare<Dimension>())); + Value rhs_min = geometry::get<Dimension>(*std::min_element(rhs.begin(), rhs.end(), detail::extreme_points::compare<Dimension>())); + return lhs_min < rhs_min; + } +}; + + +template <typename Point, typename P> +inline void calculate_average(Point& point, std::vector<P> const& points) +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + typedef typename std::vector<P>::const_iterator iterator_type; + typedef typename std::vector<P>::size_type size_type; + + coordinate_type x = 0; + coordinate_type y = 0; + + iterator_type end = points.end(); + for ( iterator_type it = points.begin() ; it != end ; ++it) + { + x += geometry::get<0>(*it); + y += geometry::get<1>(*it); + } + + size_type const count = points.size(); + geometry::set<0>(point, x / count); + geometry::set<1>(point, y / count); +} + + +template <int Dimension, typename Extremes, typename Intruders, typename CoordinateType> +inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders& intruders, CoordinateType const& max_intruder) +{ + // This function handles self-tangencies. + // Self-tangencies use, as usual, the major part of code... + + // ___ e + // /|\ \ . + // / | \ \ . + // / | \ \ . + // / | \ \ . + // / /\ | \ \ . + // i2 i1 + + // The picture above shows the extreme (outside, "e") and two intruders ("i1","i2") + // Assume that "i1" is self-tangent with the extreme, in one point at the top + // Now the "penultimate" value is searched, this is is the top of i2 + // Then everything including and below (this is "i2" here) is removed + // Then the base of "i1" and of "e" is adapted to this penultimate value + // It then looks like: + + // b ___ e + // /|\ \ . + // / | \ \ . + // / | \ \ . + // / | \ \ . + // a c i1 + + // Then intruders (here "i1" but there may be more) are sorted from left to right + // Finally points "a","b" and "c" (in this order) are selected as a new triangle. + // This triangle will have a centroid which is inside (assumed that intruders left segment + // is not equal to extremes left segment, but that polygon would be invalid) + + // Find highest non-self tangent intrusion, if any + CoordinateType penultimate_value; + specific_coordinate_first<CoordinateType, Dimension> pu_compare(max_intruder); + if (max_value<Dimension>(intruders, penultimate_value, pu_compare)) + { + // Throw away all intrusions <= this value, and of the kept one set this as base. + select_below<Dimension, CoordinateType> predicate(penultimate_value); + intruders.erase + ( + std::remove_if(boost::begin(intruders), boost::end(intruders), predicate), + boost::end(intruders) + ); + adapt_base<Dimension, CoordinateType> fe_predicate(penultimate_value); + // Sort from left to right (or bottom to top if Dimension=0) + std::for_each(boost::begin(intruders), boost::end(intruders), fe_predicate); + + // Also adapt base of extremes + detail::extreme_points::move_along_vector<Dimension>(extremes, penultimate_value); + } + // Then sort in 1-Dim. Take first to calc centroid. + std::sort(boost::begin(intruders), boost::end(intruders), min_of_intruder<1 - Dimension, CoordinateType>()); + + Extremes triangle; + triangle.reserve(3); + + // Make a triangle of first two points of extremes (the ramp, from left to right), and last point of first intruder (which goes from right to left) + std::copy(extremes.begin(), extremes.begin() + 2, std::back_inserter(triangle)); + triangle.push_back(intruders.front().back()); + + // (alternatively we could use the last two points of extremes, and first point of last intruder...): + //// ALTERNATIVE: std::copy(extremes.rbegin(), extremes.rbegin() + 2, std::back_inserter(triangle)); + //// ALTERNATIVE: triangle.push_back(intruders.back().front()); + + // Now replace extremes with this smaller subset, a triangle, such that centroid calculation will result in a point inside + extremes = triangle; +} + +template <int Dimension, typename Geometry, typename Point> +inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) +{ + typedef typename geometry::point_type<Geometry>::type point_type; + typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; + std::vector<point_type> extremes; + + typedef std::vector<std::vector<point_type> > intruders_type; + intruders_type intruders; + geometry::extreme_points<Dimension>(geometry, extremes, intruders); + + if (extremes.size() < 3) + { + return false; + } + + // If there are intruders, find the max. + if (! intruders.empty()) + { + coordinate_type max_intruder; + detail::extreme_points::compare<Dimension> compare; + if (max_value<Dimension>(intruders, max_intruder, compare)) + { + coordinate_type max_extreme = geometry::get<Dimension>(*std::max_element(extremes.begin(), extremes.end(), detail::extreme_points::compare<Dimension>())); + if (max_extreme > max_intruder) + { + detail::extreme_points::move_along_vector<Dimension>(extremes, max_intruder); + } + else + { + replace_extremes_for_self_tangencies<Dimension>(extremes, intruders, max_intruder); + } + } + } + + // Now calculate the average/centroid of the (possibly adapted) extremes + calculate_average(point, extremes); + + return true; +} + +}} // namespace detail::point_on_surface +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Assigns a Point guaranteed to lie on the surface of the Geometry +\tparam Geometry geometry type. This also defines the type of the output point +\param geometry Geometry to take point from +\param point Point to assign + */ +template <typename Geometry, typename Point> +inline void point_on_surface(Geometry const& geometry, Point & point) +{ + concept::check<Point>(); + concept::check<Geometry const>(); + + // First try in Y-direction (which should always succeed for valid polygons) + if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point)) + { + // For invalid polygons, we might try X-direction + detail::point_on_surface::calculate_point_on_surface<0>(geometry, point); + } +} + +/*! +\brief Returns point guaranteed to lie on the surface of the Geometry +\tparam Geometry geometry type. This also defines the type of the output point +\param geometry Geometry to take point from +\return The Point guaranteed to lie on the surface of the Geometry + */ +template<typename Geometry> +inline typename geometry::point_type<Geometry>::type +return_point_on_surface(Geometry const& geometry) +{ + typename geometry::point_type<Geometry>::type result; + geometry::point_on_surface(geometry, result); + return result; +} + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP diff --git a/boost/geometry/algorithms/remove_spikes.hpp b/boost/geometry/algorithms/remove_spikes.hpp new file mode 100644 index 0000000000..e62ea9fe3d --- /dev/null +++ b/boost/geometry/algorithms/remove_spikes.hpp @@ -0,0 +1,280 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 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_ALGORITHMS_REMOVE_SPIKES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP + +#include <deque> + +#include <boost/range.hpp> +#include <boost/type_traits/remove_reference.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/coordinate_type.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> +#include <boost/geometry/algorithms/clear.hpp> + + +/* +Remove spikes from a ring/polygon. +Ring (having 8 vertices, including closing vertex) ++------+ +| | +| +--+ +| | ^this "spike" is removed, can be located outside/inside the ring ++------+ +(the actualy determination if it is removed is done by a strategy) + +*/ + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace remove_spikes +{ + + +template <typename Range> +struct range_remove_spikes +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Range>::type + >::type side_strategy; + + typedef typename coordinate_type<Range>::type coordinate_type; + typedef typename point_type<Range>::type point_type; + + + static inline void apply(Range& range) + { + std::size_t n = boost::size(range); + std::size_t const min_num_points = core_detail::closure::minimum_ring_size + < + geometry::closure<Range>::value + >::value - 1; // subtract one: a polygon with only one spike should result into one point + if (n < min_num_points) + { + return; + } + + std::deque<point_type> cleaned; + for (typename boost::range_iterator<Range const>::type it = boost::begin(range); + it != boost::end(range); ++it) + { + // Add point + cleaned.push_back(*it); + + while(cleaned.size() >= 3 + && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2))) + { + // Remove pen-ultimate point causing the spike (or which was equal) + cleaned.erase(cleaned.end() - 2); + } + } + + // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent + if (geometry::closure<Range>::value == geometry::closed) + { + cleaned.pop_back(); + } + + bool found = false; + do + { + found = false; + // Check for spike in first point + int const penultimate = 2; + while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back())) + { + cleaned.pop_back(); + found = true; + } + // Check for spike in second point + while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front())) + { + cleaned.pop_front(); + found = true; + } + } + while (found); + + if (cleaned.size() == 2) + { + // Ticket #9871: open polygon with only two points. + // the second point forms, by definition, a spike + cleaned.pop_back(); + } + + // Close if necessary + if (geometry::closure<Range>::value == geometry::closed) + { + cleaned.push_back(cleaned.front()); + } + + // Copy output + geometry::clear(range); + std::copy(cleaned.begin(), cleaned.end(), std::back_inserter(range)); + } +}; + + +template <typename Polygon> +struct polygon_remove_spikes +{ + static inline void apply(Polygon& polygon) + { + typedef typename geometry::ring_type<Polygon>::type ring_type; + + typedef range_remove_spikes<ring_type> per_range; + per_range::apply(exterior_ring(polygon)); + + typename interior_return_type<Polygon>::type + rings = interior_rings(polygon); + + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) + { + per_range::apply(*it); + } + } +}; + + +template <typename MultiGeometry, typename SingleVersion> +struct multi_remove_spikes +{ + static inline void apply(MultiGeometry& multi) + { + for (typename boost::range_iterator<MultiGeometry>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + SingleVersion::apply(*it); + } + } +}; + + +}} // namespace detail::remove_spikes +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct remove_spikes +{ + static inline void apply(Geometry&) + {} +}; + + +template <typename Ring> +struct remove_spikes<Ring, ring_tag> + : detail::remove_spikes::range_remove_spikes<Ring> +{}; + + + +template <typename Polygon> +struct remove_spikes<Polygon, polygon_tag> + : detail::remove_spikes::polygon_remove_spikes<Polygon> +{}; + + +template <typename MultiPolygon> +struct remove_spikes<MultiPolygon, multi_polygon_tag> + : detail::remove_spikes::multi_remove_spikes + < + MultiPolygon, + detail::remove_spikes::polygon_remove_spikes + < + typename boost::range_value<MultiPolygon>::type + > + > +{}; + + +} // namespace dispatch +#endif + + +namespace resolve_variant { + +template <typename Geometry> +struct remove_spikes +{ + static void apply(Geometry& geometry) + { + concept::check<Geometry>(); + dispatch::remove_spikes<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<void> + { + template <typename Geometry> + void operator()(Geometry& geometry) const + { + remove_spikes<Geometry>::apply(geometry); + } + }; + + static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) + { + boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + + +/*! + \ingroup remove_spikes + \tparam Geometry geometry type + \param geometry the geometry to make remove_spikes +*/ +template <typename Geometry> +inline void remove_spikes(Geometry& geometry) +{ + resolve_variant::remove_spikes<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP diff --git a/boost/geometry/algorithms/reverse.hpp b/boost/geometry/algorithms/reverse.hpp index bf0ef2d9a9..17b23ffdfb 100644 --- a/boost/geometry/algorithms/reverse.hpp +++ b/boost/geometry/algorithms/reverse.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -17,9 +18,15 @@ #include <algorithm> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> +#include <boost/geometry/algorithms/detail/multi_modify.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -32,9 +39,9 @@ namespace detail { namespace reverse { -template <typename Range> struct range_reverse { + template <typename Range> static inline void apply(Range& range) { std::reverse(boost::begin(range), boost::end(range)); @@ -42,21 +49,20 @@ struct range_reverse }; -template <typename Polygon> -struct polygon_reverse +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)); - typedef range_reverse<ring_type> per_range; - per_range::apply(exterior_ring(polygon)); + typename interior_return_type<Polygon>::type + rings = interior_rings(polygon); - typename interior_return_type<Polygon>::type rings - = interior_rings(polygon); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { - per_range::apply(*it); + range_reverse::apply(*it); } } }; @@ -71,11 +77,7 @@ namespace dispatch { -template -< - typename Tag, - typename Geometry -> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct reverse { static inline void apply(Geometry&) @@ -84,27 +86,82 @@ struct reverse template <typename Ring> -struct reverse<ring_tag, Ring> - : detail::reverse::range_reverse<Ring> +struct reverse<Ring, ring_tag> + : detail::reverse::range_reverse {}; template <typename LineString> -struct reverse<linestring_tag, LineString> - : detail::reverse::range_reverse<LineString> +struct reverse<LineString, linestring_tag> + : detail::reverse::range_reverse {}; template <typename Polygon> -struct reverse<polygon_tag, Polygon> - : detail::reverse::polygon_reverse<Polygon> +struct reverse<Polygon, polygon_tag> + : detail::reverse::polygon_reverse {}; +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 +namespace resolve_variant +{ + +template <typename Geometry> +struct reverse +{ + static void apply(Geometry& geometry) + { + concept::check<Geometry>(); + dispatch::reverse<Geometry>::apply(geometry); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct reverse<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<void> + { + template <typename Geometry> + void operator()(Geometry& geometry) const + { + reverse<Geometry>::apply(geometry); + } + }; + + static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) + { + boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + + /*! \brief Reverses the points within a geometry \details Generic function to reverse a geometry. It resembles the std::reverse @@ -119,13 +176,7 @@ struct reverse<polygon_tag, Polygon> template <typename Geometry> inline void reverse(Geometry& geometry) { - concept::check<Geometry>(); - - dispatch::reverse - < - typename tag<Geometry>::type, - Geometry - >::apply(geometry); + resolve_variant::reverse<Geometry>::apply(geometry); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/simplify.hpp b/boost/geometry/algorithms/simplify.hpp index 225321d303..101b1324e1 100644 --- a/boost/geometry/algorithms/simplify.hpp +++ b/boost/geometry/algorithms/simplify.hpp @@ -14,27 +14,30 @@ #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/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.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/core/tags.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/strategies/default_strategy.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/convert.hpp> -#include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> namespace boost { namespace geometry { @@ -43,12 +46,11 @@ namespace boost { namespace geometry namespace detail { namespace simplify { -template<typename Range, typename Strategy> struct simplify_range_insert { - template <typename OutputIterator, typename Distance> + 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) + Distance const& max_distance, Strategy const& strategy) { if (boost::size(range) <= 2 || max_distance < 0) { @@ -62,12 +64,11 @@ struct simplify_range_insert }; -template<typename Range, typename Strategy> struct simplify_copy { - template <typename Distance> + template <typename Range, typename Strategy, typename Distance> static inline void apply(Range const& range, Range& out, - Distance const& , Strategy const& ) + Distance const& , Strategy const& ) { std::copy ( @@ -77,10 +78,10 @@ struct simplify_copy }; -template<typename Range, typename Strategy, std::size_t Minimum> +template<std::size_t Minimum> struct simplify_range { - template <typename Distance> + template <typename Range, typename Strategy, typename Distance> static inline void apply(Range const& range, Range& out, Distance const& max_distance, Strategy const& strategy) { @@ -101,14 +102,11 @@ struct simplify_range if (boost::size(range) <= int(Minimum) || max_distance < 0.0) { - simplify_copy<Range, Strategy>::apply - ( - range, out, max_distance, strategy - ); + simplify_copy::apply(range, out, max_distance, strategy); } else { - simplify_range_insert<Range, Strategy>::apply + simplify_range_insert::apply ( range, std::back_inserter(out), max_distance, strategy ); @@ -116,16 +114,56 @@ struct simplify_range } }; -template<typename Polygon, typename Strategy> struct simplify_polygon { - template <typename Distance> - static inline void apply(Polygon const& poly_in, Polygon& poly_out, +private: + + template + < + std::size_t Minimum, + typename IteratorIn, + typename IteratorOut, + typename Distance, + typename Strategy + > + static inline void iterate(IteratorIn begin, IteratorIn end, + IteratorOut it_out, + Distance const& max_distance, Strategy const& strategy) + { + for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out) + { + simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy); + } + } + + template + < + std::size_t Minimum, + typename InteriorRingsIn, + typename InteriorRingsOut, + typename Distance, + typename Strategy + > + static inline void apply_interior_rings( + InteriorRingsIn const& interior_rings_in, + InteriorRingsOut& interior_rings_out, Distance const& max_distance, Strategy const& strategy) { - typedef typename ring_type<Polygon>::type ring_type; + traits::resize<InteriorRingsOut>::apply(interior_rings_out, + boost::size(interior_rings_in)); - int const Minimum = core_detail::closure::minimum_ring_size + iterate<Minimum>( + boost::begin(interior_rings_in), boost::end(interior_rings_in), + boost::begin(interior_rings_out), + max_distance, strategy); + } + +public: + 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) + { + std::size_t const minimum = core_detail::closure::minimum_ring_size < geometry::closure<Polygon>::value >::value; @@ -133,29 +171,34 @@ struct simplify_polygon // Note that if there are inner rings, and distance is too large, // they might intersect with the outer ring in the output, // while it didn't in the input. - simplify_range<ring_type, Strategy, Minimum>::apply(exterior_ring(poly_in), - exterior_ring(poly_out), - max_distance, strategy); + 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) + apply_interior_rings<minimum>(interior_rings(poly_in), + interior_rings(poly_out), + max_distance, strategy); + } +}; + + +template<typename Policy> +struct simplify_multi +{ + template <typename MultiGeometry, typename Strategy, typename Distance> + static inline void apply(MultiGeometry const& multi, MultiGeometry& out, + Distance const& 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) { - simplify_range<ring_type, Strategy, Minimum>::apply(*it_in, - *it_out, max_distance, strategy); + Policy::apply(*it_in, *it_out, max_distance, strategy); } } }; @@ -169,15 +212,18 @@ struct simplify_polygon namespace dispatch { -template <typename Tag, typename Geometry, typename Strategy> -struct simplify -{ -}; +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct simplify: not_implemented<Tag> +{}; -template <typename Point, typename Strategy> -struct simplify<point_tag, Point, Strategy> +template <typename Point> +struct simplify<Point, point_tag> { - template <typename Distance> + template <typename Distance, typename Strategy> static inline void apply(Point const& point, Point& out, Distance const& , Strategy const& ) { @@ -186,22 +232,15 @@ struct simplify<point_tag, Point, Strategy> }; -template <typename Linestring, typename Strategy> -struct simplify<linestring_tag, Linestring, Strategy> - : detail::simplify::simplify_range - < - Linestring, - Strategy, - 2 - > +template <typename Linestring> +struct simplify<Linestring, linestring_tag> + : detail::simplify::simplify_range<2> {}; -template <typename Ring, typename Strategy> -struct simplify<ring_tag, Ring, Strategy> +template <typename Ring> +struct simplify<Ring, ring_tag> : detail::simplify::simplify_range < - Ring, - Strategy, core_detail::closure::minimum_ring_size < geometry::closure<Ring>::value @@ -209,38 +248,46 @@ struct simplify<ring_tag, Ring, Strategy> > {}; -template <typename Polygon, typename Strategy> -struct simplify<polygon_tag, Polygon, Strategy> +template <typename Polygon> +struct simplify<Polygon, polygon_tag> : detail::simplify::simplify_polygon - < - Polygon, - Strategy - > {}; -template <typename Tag, typename Geometry, typename Strategy> -struct simplify_insert -{ -}; +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct simplify_insert: not_implemented<Tag> +{}; -template <typename Linestring, typename Strategy> -struct simplify_insert<linestring_tag, Linestring, Strategy> +template <typename Linestring> +struct simplify_insert<Linestring, linestring_tag> : detail::simplify::simplify_range_insert - < - Linestring, - Strategy - > {}; -template <typename Ring, typename Strategy> -struct simplify_insert<ring_tag, Ring, Strategy> +template <typename Ring> +struct simplify_insert<Ring, ring_tag> : detail::simplify::simplify_range_insert - < - Ring, - Strategy - > +{}; + +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> {}; @@ -248,6 +295,146 @@ struct simplify_insert<ring_tag, Ring, Strategy> #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +struct simplify +{ + template <typename Geometry, typename Distance, typename Strategy> + static inline void apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + Strategy const& strategy) + { + dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy); + } + + template <typename Geometry, typename Distance> + static inline void apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + default_strategy) + { + typedef typename point_type<Geometry>::type point_type; + + typedef typename strategy::distance::services::default_strategy + < + point_tag, segment_tag, point_type + >::type ds_strategy_type; + + typedef strategy::simplify::douglas_peucker + < + point_type, ds_strategy_type + > strategy_type; + + BOOST_CONCEPT_ASSERT( + (concept::SimplifyStrategy<strategy_type, point_type>) + ); + + apply(geometry, out, max_distance, strategy_type()); + } +}; + +struct simplify_insert +{ + template + < + typename Geometry, + typename OutputIterator, + typename Distance, + typename Strategy + > + static inline void apply(Geometry const& geometry, + OutputIterator& out, + Distance const& max_distance, + Strategy const& strategy) + { + dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy); + } + + template <typename Geometry, typename OutputIterator, typename Distance> + static inline void apply(Geometry const& geometry, + OutputIterator& out, + Distance const& max_distance, + default_strategy) + { + typedef typename point_type<Geometry>::type point_type; + + typedef typename strategy::distance::services::default_strategy + < + point_tag, segment_tag, point_type + >::type ds_strategy_type; + + typedef strategy::simplify::douglas_peucker + < + point_type, ds_strategy_type + > strategy_type; + + BOOST_CONCEPT_ASSERT( + (concept::SimplifyStrategy<strategy_type, point_type>) + ); + + apply(geometry, out, max_distance, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry> +struct simplify +{ + template <typename Distance, typename Strategy> + static inline void apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + Strategy const& strategy) + { + resolve_strategy::simplify::apply(geometry, out, max_distance, strategy); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Distance, typename Strategy> + struct visitor: boost::static_visitor<void> + { + Distance const& m_max_distance; + Strategy const& m_strategy; + + visitor(Distance const& max_distance, Strategy const& strategy) + : m_max_distance(max_distance) + , m_strategy(strategy) + {} + + template <typename Geometry> + void operator()(Geometry const& geometry, Geometry& out) const + { + simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy); + } + }; + + template <typename Distance, typename Strategy> + static inline void + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out, + Distance const& max_distance, + Strategy const& strategy) + { + boost::apply_visitor( + visitor<Distance, Strategy>(max_distance, strategy), + geometry, + out + ); + } +}; + +} // namespace resolve_variant + + /*! \brief Simplify a geometry using a specified strategy \ingroup simplify @@ -271,16 +458,9 @@ inline void simplify(Geometry const& geometry, Geometry& out, { concept::check<Geometry>(); - BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) ); - geometry::clear(out); - dispatch::simplify - < - typename tag<Geometry>::type, - Geometry, - Strategy - >::apply(geometry, out, max_distance, strategy); + resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy); } @@ -306,18 +486,7 @@ inline void simplify(Geometry const& geometry, Geometry& out, { 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()); + simplify(geometry, out, max_distance, default_strategy()); } @@ -343,17 +512,11 @@ namespace detail { namespace simplify */ 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) + Distance const& max_distance, Strategy const& strategy) { concept::check<Geometry const>(); - BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) ); - dispatch::simplify_insert - < - typename tag<Geometry>::type, - Geometry, - Strategy - >::apply(geometry, out, max_distance, strategy); + resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy); } /*! @@ -369,30 +532,13 @@ inline void simplify_insert(Geometry const& geometry, OutputIterator out, */ template<typename Geometry, typename OutputIterator, typename Distance> inline void simplify_insert(Geometry const& geometry, OutputIterator out, - Distance const& max_distance) + 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>(); + concept::check<typename point_type<Geometry>::type>(); - typedef typename strategy::distance::services::default_strategy - < - segment_tag, point_type - >::type ds_strategy_type; - - typedef strategy::simplify::douglas_peucker - < - point_type, ds_strategy_type - > strategy_type; - - dispatch::simplify_insert - < - typename tag<Geometry>::type, - Geometry, - strategy_type - >::apply(geometry, out, max_distance, strategy_type()); + simplify_insert(geometry, out, max_distance, default_strategy()); } }} // namespace detail::simplify diff --git a/boost/geometry/algorithms/sym_difference.hpp b/boost/geometry/algorithms/sym_difference.hpp index 6394576de4..de34c9c7b0 100644 --- a/boost/geometry/algorithms/sym_difference.hpp +++ b/boost/geometry/algorithms/sym_difference.hpp @@ -46,11 +46,14 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { concept::check<Geometry1 const>(); @@ -59,36 +62,21 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, out = geometry::dispatch::intersection_insert < - typename geometry::tag<Geometry1>::type, - typename geometry::tag<Geometry2>::type, - typename geometry::tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, Geometry1, Geometry2, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value, - geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, + GeometryOut, overlay_difference, - Strategy - >::apply(geometry1, geometry2, out, strategy); + 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, robust_policy, out, strategy); out = geometry::dispatch::intersection_insert < - typename geometry::tag<Geometry2>::type, - typename geometry::tag<Geometry1>::type, - typename geometry::tag<GeometryOut>::type, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<GeometryOut>::value, Geometry2, Geometry1, + 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, - OutputIterator, GeometryOut, - overlay_difference, - Strategy - >::apply(geometry2, geometry1, out, strategy); + geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value + >::apply(geometry2, geometry1, robust_policy, out, strategy); return out; } @@ -112,10 +100,12 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, OutputIterator out) { concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); @@ -126,10 +116,11 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, typename cs_tag<GeometryOut>::type, Geometry1, Geometry2, - typename geometry::point_type<GeometryOut>::type + typename geometry::point_type<GeometryOut>::type, + RobustPolicy > strategy_type; - return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); + return sym_difference_insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy_type()); } }} // namespace detail::sym_difference @@ -165,8 +156,17 @@ inline void sym_difference(Geometry1 const& geometry1, typedef typename boost::range_value<Collection>::type geometry_out; concept::check<geometry_out>(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); + detail::sym_difference::sym_difference_insert<geometry_out>( - geometry1, geometry2, + geometry1, geometry2, robust_policy, std::back_inserter(output_collection)); } diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp index 7d424af428..a06071d428 100644 --- a/boost/geometry/algorithms/touches.hpp +++ b/boost/geometry/algorithms/touches.hpp @@ -3,6 +3,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,6 +15,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP @@ -18,70 +24,511 @@ #include <deque> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay.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> +#include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/algorithms/detail/relate/relate.hpp> namespace boost { namespace geometry { -namespace detail { namespace touches +#ifndef DOXYGEN_NO_DETAIL +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) - ; -} +// Box/Box -template <typename Turns> -inline bool has_only_turns(Turns const& turns) +template +< + std::size_t Dimension, + std::size_t DimensionCount +> +struct box_box_loop { - 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) + template <typename Box1, typename Box2> + static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch) { - if (it->has(detail::overlay::operation_intersection)) + 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); + + // TODO assert or exception? + //BOOST_ASSERT(min1 <= max1 && min2 <= max2); + + if ( max1 < min2 || max2 < min1 ) { return false; } - switch(it->method) + if ( max1 == min2 || max2 == min1 ) + { + touch = true; + } + + return box_box_loop + < + Dimension + 1, + DimensionCount + >::apply(b1, b2, touch); + } +}; + +template +< + std::size_t DimensionCount +> +struct box_box_loop<DimensionCount, DimensionCount> +{ + template <typename Box1, typename Box2> + static inline bool apply(Box1 const& , Box2 const&, bool &) + { + return true; + } +}; + +struct box_box +{ + template <typename Box1, typename Box2> + static inline bool apply(Box1 const& b1, Box2 const& b2) + { + BOOST_STATIC_ASSERT((boost::is_same + < + typename geometry::coordinate_system<Box1>::type, + typename geometry::coordinate_system<Box2>::type + >::value + )); + assert_dimension_equal<Box1, Box2>(); + + bool touches = false; + bool ok = box_box_loop + < + 0, + dimension<Box1>::type::value + >::apply(b1, b2, touches); + + return ok && touches; + } +}; + +// Areal/Areal + +struct areal_interrupt_policy +{ + static bool const enabled = true; + bool found_touch; + bool found_not_touch; + + // dummy variable required by self_get_turn_points::get_turns + static bool const has_intersections = false; + + inline bool result() + { + return found_touch && !found_not_touch; + } + + inline areal_interrupt_policy() + : found_touch(false), found_not_touch(false) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // if already rejected (temp workaround?) + if ( found_not_touch ) + return true; + + typedef typename boost::range_iterator<Range const>::type iterator; + for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it ) + { + if ( it->has(overlay::operation_intersection) ) + { + found_not_touch = true; + return true; + } + + switch(it->method) + { + case overlay::method_crosses: + found_not_touch = true; + return true; + case overlay::method_equal: + // Segment spatially equal means: at the right side + // the polygon internally overlaps. So return false. + found_not_touch = true; + return true; + case overlay::method_touch: + case overlay::method_touch_interior: + case overlay::method_collinear: + if ( ok_for_touch(*it) ) + { + found_touch = true; + } + else + { + found_not_touch = true; + return true; + } + break; + case overlay::method_none : + case overlay::method_disjoint : + case overlay::method_error : + break; + } + } + + return false; + } + + template <typename Turn> + inline bool ok_for_touch(Turn const& turn) + { + return turn.both(overlay::operation_union) + || turn.both(overlay::operation_blocked) + || turn.combination(overlay::operation_union, overlay::operation_blocked) + ; + } +}; + +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 ( !has_within && geometry::within(p, m_geometry) ) { - 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; + has_within = true; } } - return has_touch; +}; + +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; } +template <typename Geometry1, typename Geometry2> +struct areal_areal +{ + static inline + bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + typedef detail::no_rescale_policy rescale_policy_type; + typedef typename geometry::point_type<Geometry1>::type point_type; + typedef detail::overlay::turn_info + < + point_type, + typename segment_ratio_type<point_type, rescale_policy_type>::type + > turn_info; + + std::deque<turn_info> turns; + detail::touches::areal_interrupt_policy policy; + rescale_policy_type robust_policy; + boost::geometry::get_turns + < + detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, + detail::overlay::assign_null_policy + >(geometry1, geometry2, robust_policy, turns, policy); + + return policy.result() + && ! geometry::detail::touches::rings_containing(geometry1, geometry2) + && ! geometry::detail::touches::rings_containing(geometry2, geometry1); + } +}; + +// P/* + +struct use_point_in_geometry +{ + template <typename Point, typename Geometry> + static inline bool apply(Point const& point, Geometry const& geometry) + { + return detail::within::point_in_geometry(point, geometry) == 0; + } +}; + }} +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch { + +// TODO: Since CastedTags are used is Reverse needed? + +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag2 = typename tag<Geometry2>::type, + typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type, + typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type, + bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value +> +struct touches + : not_implemented<Tag1, Tag2> +{}; + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, + typename Tag1, typename Tag2, + typename CastedTag1, typename CastedTag2 +> +struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true> + : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false> +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + return touches<Geometry2, Geometry1>::apply(g2, g1); + } +}; + +// P/P + +template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> +struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false> +{ + static inline bool apply(Geometry1 const& , Geometry2 const& ) + { + return false; + } +}; + +// P/* + +template <typename Point, typename Geometry, typename Tag2, typename CastedTag2> +struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false> + : detail::touches::use_point_in_geometry +{}; + +// TODO: support touches(MPt, Linear/Areal) + +// Box/Box + +template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2> +struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false> + : detail::touches::box_box +{}; + +template <typename Box1, typename Box2> +struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false> + : detail::touches::box_box +{}; + +// L/L + +template <typename Linear1, typename Linear2, typename Tag1, typename Tag2> +struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false> + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Linear1, + Linear2 + > +{}; + +// L/A + +template <typename Linear, typename Areal, typename Tag1, typename Tag2> +struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false> + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Linear, + Areal + > +{}; + +// A/L +template <typename Linear, typename Areal, typename Tag1, typename Tag2> +struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, true> + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Areal, + Linear + > +{}; + +// A/A + +template <typename Areal1, typename Areal2, typename Tag1, typename Tag2> +struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false> + : detail::touches::areal_areal<Areal1, Areal2> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct touches +{ + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + + return dispatch::touches<Geometry1, Geometry2> + ::apply(geometry1, geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + struct visitor: boost::static_visitor<bool> + { + Geometry2 const& m_geometry2; + + visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {} + + template <typename Geometry1> + bool operator()(Geometry1 const& geometry1) const + { + return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2); + } + }; + + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2) + { + return boost::apply_visitor(visitor(geometry2), geometry1); + } +}; + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<bool> + { + Geometry1 const& m_geometry1; + + visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {} + + template <typename Geometry2> + bool operator()(Geometry2 const& geometry2) const + { + return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2); + } + }; + + static inline bool + apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + { + return boost::apply_visitor(visitor(geometry1), geometry2); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +{ + struct visitor: boost::static_visitor<bool> + { + template <typename Geometry1, typename Geometry2> + bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return touches<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 boost::apply_visitor(visitor(), geometry1, geometry2); + } +}; + +template <typename Geometry> +struct self_touches +{ + static bool apply(Geometry const& geometry) + { + concept::check<Geometry const>(); + + typedef detail::no_rescale_policy rescale_policy_type; + typedef typename geometry::point_type<Geometry>::type point_type; + typedef detail::overlay::turn_info + < + point_type, + typename segment_ratio_type<point_type, rescale_policy_type>::type + > turn_info; + + typedef detail::overlay::get_turn_info + < + detail::overlay::assign_null_policy + > policy_type; + + std::deque<turn_info> turns; + detail::touches::areal_interrupt_policy policy; + rescale_policy_type robust_policy; + detail::self_get_turn_points::get_turns + < + policy_type + >::apply(geometry, robust_policy, turns, policy); + + return policy.result(); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + struct visitor: boost::static_visitor<bool> + { + template <typename Geometry> + bool operator()(Geometry const& geometry) const + { + return self_touches<Geometry>::apply(geometry); + } + }; + + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + { + return boost::apply_visitor(visitor(), geometry); + } +}; + +} // namespace resolve_variant + /*! \brief \brief_check{has at least one touching point (self-tangency)} @@ -99,32 +546,7 @@ inline bool has_only_turns(Turns const& turns) 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); + return resolve_variant::self_touches<Geometry>::apply(geometry); } @@ -143,39 +565,10 @@ inline bool touches(Geometry const& geometry) 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) - ; + return resolve_variant::touches<Geometry1, Geometry2>::apply(geometry1, geometry2); } - }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp index 22b45dc77e..1d6e8d0a35 100644 --- a/boost/geometry/algorithms/transform.hpp +++ b/boost/geometry/algorithms/transform.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,10 +19,14 @@ #include <iterator> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/core/cs.hpp> @@ -30,7 +35,9 @@ #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/transform.hpp> @@ -41,9 +48,9 @@ namespace boost { namespace geometry namespace detail { namespace transform { -template <typename Point1, typename Point2, typename Strategy> struct transform_point { + template <typename Point1, typename Point2, typename Strategy> static inline bool apply(Point1 const& p1, Point2& p2, Strategy const& strategy) { @@ -52,9 +59,9 @@ struct transform_point }; -template <typename Box1, typename Box2, typename Strategy> struct transform_box { + template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& b1, Box2& b2, Strategy const& strategy) { @@ -91,9 +98,9 @@ struct transform_box } }; -template <typename Geometry1, typename Geometry2, typename Strategy> struct transform_box_or_segment { + template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& source, Geometry2& target, Strategy const& strategy) { @@ -133,12 +140,7 @@ inline bool transform_range_out(Range const& range, it != boost::end(range); ++it) { - if (! transform_point - < - typename point_type<Range>::type, - PointOut, - Strategy - >::apply(*it, point_out, strategy)) + if (! transform_point::apply(*it, point_out, strategy)) { return false; } @@ -148,14 +150,12 @@ inline bool transform_range_out(Range const& range, } -template <typename Polygon1, typename Polygon2, typename Strategy> 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); @@ -175,16 +175,20 @@ struct transform_polygon >::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) + typename interior_return_type<Polygon1 const>::type + rings1 = interior_rings(poly1); + typename interior_return_type<Polygon2>::type + rings2 = interior_rings(poly2); + + typename detail::interior_iterator<Polygon1 const>::type + it1 = boost::begin(rings1); + typename detail::interior_iterator<Polygon2>::type + it2 = boost::begin(rings2); + for ( ; it1 != boost::end(rings1); ++it1, ++it2) { - if (!transform_range_out<point2_type>(*it1, - std::back_inserter(*it2), strategy)) + if ( ! transform_range_out<point2_type>(*it1, + std::back_inserter(*it2), + strategy) ) { return false; } @@ -211,9 +215,9 @@ struct select_strategy >::type type; }; -template <typename Range1, typename Range2, typename Strategy> struct transform_range { + template <typename Range1, typename Range2, typename Strategy> static inline bool apply(Range1 const& range1, Range2& range2, Strategy const& strategy) { @@ -226,6 +230,36 @@ struct transform_range } }; + +/*! + \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 @@ -236,58 +270,166 @@ namespace dispatch template < - typename Tag1, typename Tag2, typename Geometry1, typename Geometry2, - typename Strategy + 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, typename Strategy> -struct transform<point_tag, point_tag, Point1, Point2, Strategy> - : detail::transform::transform_point<Point1, Point2, Strategy> +template <typename Point1, typename Point2> +struct transform<Point1, Point2, point_tag, point_tag> + : detail::transform::transform_point { }; -template <typename Linestring1, typename Linestring2, typename Strategy> +template <typename Linestring1, typename Linestring2> struct transform < - linestring_tag, linestring_tag, - Linestring1, Linestring2, Strategy + Linestring1, Linestring2, + linestring_tag, linestring_tag > - : detail::transform::transform_range<Linestring1, Linestring2, Strategy> + : detail::transform::transform_range { }; -template <typename Range1, typename Range2, typename Strategy> -struct transform<ring_tag, ring_tag, Range1, Range2, Strategy> - : detail::transform::transform_range<Range1, Range2, Strategy> +template <typename Range1, typename Range2> +struct transform<Range1, Range2, ring_tag, ring_tag> + : detail::transform::transform_range { }; -template <typename Polygon1, typename Polygon2, typename Strategy> -struct transform<polygon_tag, polygon_tag, Polygon1, Polygon2, Strategy> - : detail::transform::transform_polygon<Polygon1, Polygon2, Strategy> +template <typename Polygon1, typename Polygon2> +struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag> + : detail::transform::transform_polygon { }; -template <typename Box1, typename Box2, typename Strategy> -struct transform<box_tag, box_tag, Box1, Box2, Strategy> - : detail::transform::transform_box<Box1, Box2, Strategy> +template <typename Box1, typename Box2> +struct transform<Box1, Box2, box_tag, box_tag> + : detail::transform::transform_box { }; -template <typename Segment1, typename Segment2, typename Strategy> -struct transform<segment_tag, segment_tag, Segment1, Segment2, Strategy> - : detail::transform::transform_box_or_segment<Segment1, Segment2, Strategy> +template <typename Segment1, typename Segment2> +struct transform<Segment1, Segment2, segment_tag, segment_tag> + : detail::transform::transform_box_or_segment { }; +template <typename Multi1, typename Multi2> +struct transform + < + Multi1, Multi2, + multi_tag, multi_tag + > + : detail::transform::transform_multi + < + dispatch::transform + < + typename boost::range_value<Multi1>::type, + typename boost::range_value<Multi2>::type + > + > +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy { + +struct transform +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2& geometry2, + Strategy const& strategy) + { + concept::check<Geometry1 const>(); + concept::check<Geometry2>(); + + return dispatch::transform<Geometry1, Geometry2>::apply( + geometry1, + geometry2, + strategy + ); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2& geometry2, + default_strategy) + { + return apply( + geometry1, + geometry2, + typename detail::transform::select_strategy<Geometry1, Geometry2>::type() + ); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant { + +template <typename Geometry1, typename Geometry2> +struct transform +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2& geometry2, + Strategy const& strategy) + { + return resolve_strategy::transform::apply( + geometry1, + geometry2, + strategy + ); + } +}; + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct transform<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Strategy> + struct visitor: static_visitor<bool> + { + Geometry2& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2& geometry2, Strategy const& strategy) + : m_geometry2(geometry2) + , m_strategy(strategy) + {} + + template <typename Geometry1> + inline bool operator()(Geometry1 const& geometry1) const + { + return transform<Geometry1, Geometry2>::apply( + geometry1, + m_geometry2, + m_strategy + ); + } + }; + + template <typename Strategy> + static inline bool apply( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2& geometry2, + Strategy const& strategy + ) + { + return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + } +}; + +} // namespace resolve_variant + + /*! \brief Transforms from one geometry to another geometry \brief_strategy \ingroup transform @@ -307,19 +449,8 @@ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2, Strategy const& strategy) { - concept::check<Geometry1 const>(); - concept::check<Geometry2>(); - - typedef dispatch::transform - < - typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type, - typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type, - Geometry1, - Geometry2, - Strategy - > transform_type; - - return transform_type::apply(geometry1, geometry2, strategy); + return resolve_variant::transform<Geometry1, Geometry2> + ::apply(geometry1, geometry2, strategy); } @@ -337,11 +468,7 @@ inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2, 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); + return transform(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/union.hpp b/boost/geometry/algorithms/union.hpp index 28d8e5dc0b..ff16c60ea1 100644 --- a/boost/geometry/algorithms/union.hpp +++ b/boost/geometry/algorithms/union.hpp @@ -1,6 +1,11 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,15 +15,18 @@ #define BOOST_GEOMETRY_ALGORITHMS_UNION_HPP -#include <boost/mpl/if.hpp> - #include <boost/range/metafunctions.hpp> #include <boost/geometry/core/is_areal.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> + +#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> namespace boost { namespace geometry @@ -30,170 +38,146 @@ namespace dispatch template < - // tag dispatching: + 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, - // metafunction finetuning helpers: bool Areal1, bool Areal2, bool ArealOut, - // real types - typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, - typename GeometryOut, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct union_insert + < + Geometry1, Geometry2, GeometryOut, + TagIn1, TagIn2, TagOut, + Areal1, Areal2, ArealOut, + Reverse1, Reverse2, ReverseOut, + true + >: union_insert<Geometry2, Geometry1, GeometryOut> { - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES - , (types<Geometry1, Geometry2, GeometryOut>) - ); + template <typename RobustPolicy, typename OutputIterator, typename Strategy> + static inline OutputIterator apply(Geometry1 const& g1, + Geometry2 const& g2, + RobustPolicy const& robust_policy, + OutputIterator out, + Strategy const& strategy) + { + return union_insert + < + Geometry2, Geometry1, GeometryOut + >::apply(g2, g1, robust_policy, out, strategy); + } }; template < + typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1, typename TagIn2, typename TagOut, - typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, - typename GeometryOut, - typename Strategy + bool Reverse1, bool Reverse2, bool ReverseOut > struct union_insert < + Geometry1, Geometry2, GeometryOut, TagIn1, TagIn2, TagOut, true, true, true, - Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - Strategy + false > : detail::overlay::overlay - <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, overlay_union, Strategy> + <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, overlay_union> {}; - +// dispatch for union of non-areal geometries template < - typename GeometryTag1, typename GeometryTag2, typename GeometryTag3, - bool Areal1, bool Areal2, bool ArealOut, - typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - typename Strategy + typename Geometry1, typename Geometry2, typename GeometryOut, + typename TagIn1, typename TagIn2, typename TagOut, + bool Reverse1, bool Reverse2, bool ReverseOut > -struct union_insert_reversed -{ - static inline OutputIterator apply(Geometry1 const& g1, - Geometry2 const& g2, OutputIterator out, - Strategy const& strategy) - { - return union_insert - < - GeometryTag2, GeometryTag1, GeometryTag3, - Areal2, Areal1, ArealOut, - Geometry2, Geometry1, - Reverse2, Reverse1, ReverseOut, - OutputIterator, GeometryOut, - Strategy - >::apply(g2, g1, out, strategy); - } -}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH +struct union_insert + < + Geometry1, Geometry2, GeometryOut, + TagIn1, TagIn2, TagOut, + false, false, false, + Reverse1, Reverse2, ReverseOut, + false + > : union_insert + < + Geometry1, Geometry2, GeometryOut, + typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type, + typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type, + TagOut, + false, false, false, + Reverse1, Reverse2, ReverseOut, + false + > +{}; -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace union_ -{ +// dispatch for union of linear geometries template < - typename GeometryOut, - typename Geometry1, typename Geometry2, - typename OutputIterator, - typename Strategy + typename Linear1, typename Linear2, typename LineStringOut, + bool Reverse1, bool Reverse2, bool ReverseOut > -inline OutputIterator insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, - OutputIterator out, - Strategy const& strategy) -{ - return boost::mpl::if_c +struct union_insert + < + Linear1, Linear2, LineStringOut, + linear_tag, linear_tag, linestring_tag, + false, false, false, + Reverse1, Reverse2, ReverseOut, + false + > : detail::overlay::linear_linear_linestring < - geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, - dispatch::union_insert_reversed - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, - Geometry1, Geometry2, - overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, - overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, - Strategy - >, - dispatch::union_insert - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag<GeometryOut>::type, - geometry::is_areal<Geometry1>::value, - geometry::is_areal<Geometry2>::value, - geometry::is_areal<GeometryOut>::value, - Geometry1, Geometry2, - overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, - overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, - OutputIterator, GeometryOut, - Strategy - > - >::type::apply(geometry1, geometry2, out, strategy); -} + Linear1, Linear2, LineStringOut, overlay_union + > +{}; -/*! -\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} -*/ +// dispatch for point-like geometries template < - typename GeometryOut, - typename Geometry1, - typename Geometry2, - typename OutputIterator, - typename Strategy + typename PointLike1, typename PointLike2, typename PointOut, + bool Reverse1, bool Reverse2, bool ReverseOut > -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>(); +struct union_insert + < + PointLike1, PointLike2, PointOut, + pointlike_tag, pointlike_tag, point_tag, + false, false, false, + Reverse1, Reverse2, ReverseOut, + false + > : detail::overlay::union_pointlike_pointlike_point + < + PointLike1, PointLike2, PointOut + > +{}; - return detail::union_::insert<GeometryOut>(geometry1, geometry2, out, strategy); -} + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace union_ +{ /*! \brief_calc2{union} @@ -224,15 +208,28 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, concept::check<Geometry2 const>(); concept::check<GeometryOut>(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + typedef strategy_intersection < typename cs_tag<GeometryOut>::type, Geometry1, Geometry2, - typename geometry::point_type<GeometryOut>::type + typename geometry::point_type<GeometryOut>::type, + rescale_policy_type > strategy; - return union_insert<GeometryOut>(geometry1, geometry2, out, strategy()); + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); + + return dispatch::union_insert + < + Geometry1, Geometry2, GeometryOut + >::apply(geometry1, geometry2, robust_policy, out, strategy()); } diff --git a/boost/geometry/algorithms/unique.hpp b/boost/geometry/algorithms/unique.hpp index 3bbf479f9b..fed9f8af4b 100644 --- a/boost/geometry/algorithms/unique.hpp +++ b/boost/geometry/algorithms/unique.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -17,10 +18,12 @@ #include <algorithm> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/compare.hpp> @@ -34,9 +37,9 @@ namespace detail { namespace unique { -template <typename Range, typename ComparePolicy> struct range_unique { + template <typename Range, typename ComparePolicy> static inline void apply(Range& range, ComparePolicy const& policy) { typename boost::range_iterator<Range>::type it @@ -52,26 +55,41 @@ struct range_unique }; -template <typename Polygon, typename ComparePolicy> 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); - typedef range_unique<ring_type, ComparePolicy> per_range; - per_range::apply(exterior_ring(polygon), policy); + typename interior_return_type<Polygon>::type + rings = interior_rings(polygon); - typename interior_return_type<Polygon>::type rings - = interior_rings(polygon); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + for (typename detail::interior_iterator<Polygon>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { - per_range::apply(*it, policy); + range_unique::apply(*it, policy); } } }; +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 @@ -85,32 +103,50 @@ namespace dispatch template < - typename Tag, typename Geometry, - typename ComparePolicy + typename Tag = typename tag<Geometry>::type > struct unique { + template <typename ComparePolicy> static inline void apply(Geometry&, ComparePolicy const& ) {} }; -template <typename Ring, typename ComparePolicy> -struct unique<ring_tag, Ring, ComparePolicy> - : detail::unique::range_unique<Ring, ComparePolicy> +template <typename 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 {}; -template <typename LineString, typename ComparePolicy> -struct unique<linestring_tag, LineString, ComparePolicy> - : detail::unique::range_unique<LineString, ComparePolicy> +// 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 Polygon, typename ComparePolicy> -struct unique<polygon_tag, Polygon, ComparePolicy> - : detail::unique::polygon_unique<Polygon, ComparePolicy> +template <typename MultiPolygon> +struct unique<MultiPolygon, multi_polygon_tag> + : detail::unique::multi_unique<detail::unique::polygon_unique> {}; @@ -139,12 +175,7 @@ inline void unique(Geometry& geometry) > policy; - dispatch::unique - < - typename tag<Geometry>::type, - Geometry, - policy - >::apply(geometry, policy()); + dispatch::unique<Geometry>::apply(geometry, policy()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp index f1f0993d77..f66b1ed1c6 100644 --- a/boost/geometry/algorithms/within.hpp +++ b/boost/geometry/algorithms/within.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,14 +14,19 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #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/variant/static_visitor.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/make.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> @@ -34,131 +42,47 @@ #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/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/within.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> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> + +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> +#include <deque> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace within -{ +namespace detail { namespace within { - -template -< - typename Point, - typename Ring, - iterate_direction Direction, - closure_selector Closure, - typename Strategy -> -struct point_in_ring +struct use_point_in_geometry { - BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) ); - - static inline int apply(Point const& point, Ring const& ring, - Strategy const& strategy) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& 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); + return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1; } }; - -// 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 +struct use_relate { - BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) ); - - static inline int apply(Point const& point, Polygon const& poly, - Strategy const& strategy) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, 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; + return Strategy::apply(geometry1, geometry2); } }; }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -170,7 +94,8 @@ template typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > -struct within: not_implemented<Tag1, Tag2> +struct within + : not_implemented<Tag1, Tag2> {}; @@ -180,6 +105,7 @@ 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); } }; @@ -191,48 +117,349 @@ struct within<Box1, Box2, box_tag, box_tag> 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); } }; +// P/P +template <typename Point1, typename Point2> +struct within<Point1, Point2, point_tag, point_tag> + : public detail::within::use_point_in_geometry +{}; + +template <typename Point, typename MultiPoint> +struct within<Point, MultiPoint, point_tag, multi_point_tag> + : public detail::within::use_point_in_geometry +{}; + +// P/L + +template <typename Point, typename Segment> +struct within<Point, Segment, point_tag, segment_tag> + : public detail::within::use_point_in_geometry +{}; + +template <typename Point, typename Linestring> +struct within<Point, Linestring, point_tag, linestring_tag> + : public detail::within::use_point_in_geometry +{}; + +template <typename Point, typename MultiLinestring> +struct within<Point, MultiLinestring, point_tag, multi_linestring_tag> + : public detail::within::use_point_in_geometry +{}; + +// P/A template <typename Point, typename Ring> struct within<Point, Ring, point_tag, ring_tag> + : public detail::within::use_point_in_geometry +{}; + +template <typename Point, typename Polygon> +struct within<Point, Polygon, point_tag, polygon_tag> + : public detail::within::use_point_in_geometry +{}; + +template <typename Point, typename MultiPolygon> +struct within<Point, MultiPolygon, point_tag, multi_polygon_tag> + : public detail::within::use_point_in_geometry +{}; + +// L/L + +template <typename Linestring1, typename Linestring2> +struct within<Linestring1, Linestring2, linestring_tag, linestring_tag> + : public detail::within::use_relate +{}; + +template <typename Linestring, typename MultiLinestring> +struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag> + : public detail::within::use_relate +{}; + +template <typename MultiLinestring, typename Linestring> +struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag> + : public detail::within::use_relate +{}; + +template <typename MultiLinestring1, typename MultiLinestring2> +struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag> + : public detail::within::use_relate +{}; + +// L/A + +template <typename Linestring, typename Ring> +struct within<Linestring, Ring, linestring_tag, ring_tag> + : public detail::within::use_relate +{}; + +template <typename MultiLinestring, typename Ring> +struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag> + : public detail::within::use_relate +{}; + +template <typename Linestring, typename Polygon> +struct within<Linestring, Polygon, linestring_tag, polygon_tag> + : public detail::within::use_relate +{}; + +template <typename MultiLinestring, typename Polygon> +struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag> + : public detail::within::use_relate +{}; + +template <typename Linestring, typename MultiPolygon> +struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag> + : public detail::within::use_relate +{}; + +template <typename MultiLinestring, typename MultiPolygon> +struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag> + : public detail::within::use_relate +{}; + +// A/A + +template <typename Ring1, typename Ring2> +struct within<Ring1, Ring2, ring_tag, ring_tag> + : public detail::within::use_relate +{}; + +template <typename Ring, typename Polygon> +struct within<Ring, Polygon, ring_tag, polygon_tag> + : public detail::within::use_relate +{}; + +template <typename Polygon, typename Ring> +struct within<Polygon, Ring, polygon_tag, ring_tag> + : public detail::within::use_relate +{}; + +template <typename Polygon1, typename Polygon2> +struct within<Polygon1, Polygon2, polygon_tag, polygon_tag> + : public detail::within::use_relate +{}; + +template <typename Ring, typename MultiPolygon> +struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag> + : public detail::within::use_relate +{}; + +template <typename MultiPolygon, typename Ring> +struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag> + : public detail::within::use_relate +{}; + +template <typename Polygon, typename MultiPolygon> +struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag> + : public detail::within::use_relate +{}; + +template <typename MultiPolygon, typename Polygon> +struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag> + : public detail::within::use_relate +{}; + +template <typename MultiPolygon1, typename MultiPolygon2> +struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag> + : public detail::within::use_relate +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_strategy { - template <typename Strategy> - static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy) + +struct within +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return detail::within::point_in_ring + concept::within::check < - Point, - Ring, - order_as_direction<geometry::point_order<Ring>::value>::value, - geometry::closure<Ring>::value, + typename tag<Geometry1>::type, + typename tag<Geometry2>::type, + typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, Strategy - >::apply(point, ring, strategy) == 1; + >(); + + return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + 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 apply(geometry1, geometry2, strategy_type()); } }; -template <typename Point, typename Polygon> -struct within<Point, Polygon, point_tag, polygon_tag> +} // namespace resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct within { template <typename Strategy> - static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy) + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + 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; + concept::check<Geometry1 const>(); + concept::check<Geometry2 const>(); + assert_dimension_equal<Geometry1, Geometry2>(); + + return resolve_strategy::within::apply(geometry1, + geometry2, + strategy); } }; -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, Strategy const& strategy): + m_geometry2(geometry2), + m_strategy(strategy) + {} + + template <typename Geometry1> + bool operator()(Geometry1 const& geometry1) const + { + return within<Geometry1, Geometry2>::apply(geometry1, + m_geometry2, + m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor( + visitor<Strategy>(geometry2, strategy), + geometry1 + ); + } +}; + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Geometry1 const& m_geometry1; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, Strategy const& strategy): + m_geometry1(geometry1), + m_strategy(strategy) + {} + + template <typename Geometry2> + bool operator()(Geometry2 const& geometry2) const + { + return within<Geometry1, Geometry2>::apply(m_geometry1, + geometry2, + m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor( + visitor<Strategy>(geometry1, strategy), + geometry2 + ); + } +}; + +template < + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) +> +struct within< + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> +> +{ + template <typename Strategy> + struct visitor: boost::static_visitor<bool> + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy): m_strategy(strategy) {} + + template <typename Geometry1, typename Geometry2> + bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + return within<Geometry1, Geometry2>::apply(geometry1, + geometry2, + m_strategy); + } + }; + + template <typename Strategy> + static inline bool + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) + { + return boost::apply_visitor( + visitor<Strategy>(strategy), + geometry1, geometry2 + ); + } +}; + +} /*! @@ -259,36 +486,11 @@ struct within<Point, Polygon, point_tag, polygon_tag> 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 + return resolve_variant::within < - 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()); + >::apply(geometry1, geometry2, default_strategy()); } /*! @@ -321,18 +523,7 @@ 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 + return resolve_variant::within < Geometry1, Geometry2 diff --git a/boost/geometry/arithmetic/arithmetic.hpp b/boost/geometry/arithmetic/arithmetic.hpp index 6479ecc4a6..6eb31f488e 100644 --- a/boost/geometry/arithmetic/arithmetic.hpp +++ b/boost/geometry/arithmetic/arithmetic.hpp @@ -117,6 +117,7 @@ struct point_assignment \brief Adds the same value to each coordinate of a point \ingroup arithmetic \details + \tparam Point \tparam_point \param p point \param value value to add */ @@ -133,13 +134,15 @@ inline void add_value(Point& p, typename detail::param<Point>::type value) \ingroup arithmetic \details The coordinates of the second point will be added to those of the first point. The second point is not modified. + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \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::Point<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); for_each_coordinate(p1, detail::point_operation<Point2, std::plus>(p2)); @@ -149,6 +152,7 @@ inline void add_point(Point1& p1, Point2 const& p2) \brief Subtracts the same value to each coordinate of a point \ingroup arithmetic \details + \tparam Point \tparam_point \param p point \param value value to subtract */ @@ -165,13 +169,15 @@ inline void subtract_value(Point& p, typename detail::param<Point>::type value) \ingroup arithmetic \details The coordinates of the second point will be subtracted to those of the first point. The second point is not modified. + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \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::Point<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); for_each_coordinate(p1, detail::point_operation<Point2, std::minus>(p2)); @@ -181,6 +187,7 @@ inline void subtract_point(Point1& p1, Point2 const& p2) \brief Multiplies each coordinate of a point by the same value \ingroup arithmetic \details + \tparam Point \tparam_point \param p point \param value value to multiply by */ @@ -197,6 +204,8 @@ inline void multiply_value(Point& p, typename detail::param<Point>::type value) \ingroup arithmetic \details The coordinates of the first point will be multiplied by those of the second point. The second point is not modified. + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \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. @@ -204,7 +213,7 @@ inline void multiply_value(Point& p, typename detail::param<Point>::type value) template <typename Point1, typename Point2> inline void multiply_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); for_each_coordinate(p1, detail::point_operation<Point2, std::multiplies>(p2)); @@ -214,6 +223,7 @@ inline void multiply_point(Point1& p1, Point2 const& p2) \brief Divides each coordinate of the same point by a value \ingroup arithmetic \details + \tparam Point \tparam_point \param p point \param value value to divide by */ @@ -230,13 +240,15 @@ inline void divide_value(Point& p, typename detail::param<Point>::type value) \ingroup arithmetic \details The coordinates of the first point will be divided by those of the second point. The second point is not modified. + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \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::Point<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); for_each_coordinate(p1, detail::point_operation<Point2, std::divides>(p2)); @@ -246,6 +258,7 @@ inline void divide_point(Point1& p1, Point2 const& p2) \brief Assign each coordinate of a point the same value \ingroup arithmetic \details + \tparam Point \tparam_point \param p point \param value value to assign */ @@ -262,13 +275,15 @@ inline void assign_value(Point& p, typename detail::param<Point>::type value) \ingroup arithmetic \details The coordinates of the first point will be assigned those of the second point. The second point is not modified. + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \param p1 first point \param p2 second point */ template <typename Point1, typename Point2> -inline void assign_point(Point1& p1, const Point2& p2) +inline void assign_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) ); + BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); for_each_coordinate(p1, detail::point_assignment<Point2>(p2)); diff --git a/boost/geometry/arithmetic/determinant.hpp b/boost/geometry/arithmetic/determinant.hpp index db3b867096..14edea7182 100644 --- a/boost/geometry/arithmetic/determinant.hpp +++ b/boost/geometry/arithmetic/determinant.hpp @@ -62,7 +62,7 @@ inline ReturnType determinant(U const& u, V const& v) return calculate_determinant < - ReturnType, + 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)); diff --git a/boost/geometry/arithmetic/dot_product.hpp b/boost/geometry/arithmetic/dot_product.hpp index 13fe968779..fc2b3844e6 100644 --- a/boost/geometry/arithmetic/dot_product.hpp +++ b/boost/geometry/arithmetic/dot_product.hpp @@ -59,21 +59,23 @@ struct dot_product_maker<P1, P2, DimensionCount, DimensionCount> /*! \brief Computes the dot product (or scalar product) of 2 vectors (points). \ingroup arithmetic + \tparam Point1 \tparam_point + \tparam Point2 \tparam_point \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) +template <typename Point1, typename Point2> +inline typename select_coordinate_type<Point1, Point2>::type dot_product( + Point1 const& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P1>) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P2>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point1>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); return detail::dot_product_maker < - P1, P2, - 0, dimension<P1>::type::value - 1 + Point1, Point2, + 0, dimension<Point1>::type::value - 1 >::apply(p1, p2); } diff --git a/boost/geometry/core/access.hpp b/boost/geometry/core/access.hpp index cdc8ff9cff..57f925763d 100644 --- a/boost/geometry/core/access.hpp +++ b/boost/geometry/core/access.hpp @@ -137,8 +137,8 @@ template typename Geometry, typename CoordinateType, - std::size_t Dimension, - typename IsPointer + std::size_t Dimension, + typename IsPointer > struct access { @@ -153,7 +153,7 @@ template typename CoordinateType, std::size_t Index, std::size_t Dimension, - typename IsPointer + typename IsPointer > struct indexed_access { @@ -260,13 +260,15 @@ struct signature_getset_index_dimension {}; \tparam Dimension \tparam_dimension_required \tparam Geometry \tparam_geometry (usually a Point Concept) \param geometry \param_geometry (usually a point) -\param dummy \qbk_skip \return The coordinate value of specified dimension of specified geometry + \qbk{[include reference/core/get_point.qbk]} */ template <std::size_t Dimension, typename Geometry> inline typename coordinate_type<Geometry>::type get(Geometry const& geometry +#ifndef DOXYGEN_SHOULD_SKIP_THIS , detail::signature_getset_dimension* dummy = 0 +#endif ) { boost::ignore_unused_variable_warning(dummy); @@ -277,7 +279,7 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry typename geometry::util::bare_type<Geometry>::type, typename coordinate_type<Geometry>::type, Dimension, - typename boost::is_pointer<Geometry>::type + typename boost::is_pointer<Geometry>::type > coord_access_type; return coord_access_type::get(geometry); @@ -292,7 +294,6 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry \param geometry geometry to assign coordinate to \param geometry \param_geometry (usually a point) \param value The coordinate value to set -\param dummy \qbk_skip \ingroup set \qbk{[include reference/core/set_point.qbk]} @@ -300,7 +301,9 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry 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); @@ -311,7 +314,7 @@ inline void set(Geometry& geometry typename geometry::util::bare_type<Geometry>::type, typename coordinate_type<Geometry>::type, Dimension, - typename boost::is_pointer<Geometry>::type + typename boost::is_pointer<Geometry>::type > coord_access_type; coord_access_type::set(geometry, value); @@ -325,7 +328,6 @@ inline void set(Geometry& geometry \tparam Dimension \tparam_dimension_required \tparam Geometry \tparam_box_or_segment \param geometry \param_geometry -\param dummy \qbk_skip \return coordinate value \ingroup get @@ -334,7 +336,9 @@ inline void set(Geometry& geometry */ 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); @@ -346,7 +350,7 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry typename coordinate_type<Geometry>::type, Index, Dimension, - typename boost::is_pointer<Geometry>::type + typename boost::is_pointer<Geometry>::type > coord_access_type; return coord_access_type::get(geometry); @@ -361,7 +365,6 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry \param geometry geometry to assign coordinate to \param geometry \param_geometry \param value The coordinate value to set -\param dummy \qbk_skip \ingroup set \qbk{distinguish,with index} @@ -370,19 +373,21 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry 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 tag<Geometry>::type, typename geometry::util::bare_type<Geometry>::type, typename coordinate_type<Geometry>::type, Index, Dimension, - typename boost::is_pointer<Geometry>::type + typename boost::is_pointer<Geometry>::type > coord_access_type; coord_access_type::set(geometry, value); diff --git a/boost/geometry/core/closure.hpp b/boost/geometry/core/closure.hpp index aab02e7871..b69dcda140 100644 --- a/boost/geometry/core/closure.hpp +++ b/boost/geometry/core/closure.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,10 +19,9 @@ #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/mpl/size_t.hpp> +#include <boost/range/value_type.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/geometry/core/ring_type.hpp> @@ -32,10 +36,10 @@ 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 + 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 + 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{ @@ -45,12 +49,12 @@ namespace boost { namespace geometry */ enum closure_selector { - /// Rings are open: first point and last point are different, algorithms + /// 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 + /// (Not yet implemented): algorithms first figure out if ring must be /// closed on the fly closure_undertermined = -1 }; @@ -93,10 +97,10 @@ template <closure_selector Closure> struct minimum_ring_size {}; template <> -struct minimum_ring_size<geometry::closed> : boost::mpl::int_<4> {}; +struct minimum_ring_size<geometry::closed> : boost::mpl::size_t<4> {}; template <> -struct minimum_ring_size<geometry::open> : boost::mpl::int_<3> {}; +struct minimum_ring_size<geometry::open> : boost::mpl::size_t<3> {}; }} // namespace detail::point_order @@ -128,18 +132,18 @@ template <typename Box> struct closure<segment_tag, Box> : public core_detail::closure::closed {}; template <typename LineString> -struct closure<linestring_tag, LineString> +struct closure<linestring_tag, LineString> : public core_detail::closure::closed {}; template <typename Ring> struct closure<ring_tag, Ring> { - static const closure_selector value + static const closure_selector value = geometry::traits::closure<Ring>::value; }; -// Specialization for polygon: the closure is the closure of its rings +// Specialization for Polygon: the closure is the closure of its rings template <typename Polygon> struct closure<polygon_tag, Polygon> { @@ -150,13 +154,31 @@ struct closure<polygon_tag, Polygon> >::value ; }; +template <typename MultiPoint> +struct closure<multi_point_tag, MultiPoint> + : public core_detail::closure::closed {}; + +template <typename MultiLinestring> +struct closure<multi_linestring_tag, MultiLinestring> + : public core_detail::closure::closed {}; + +// Specialization for MultiPolygon: the closure is the closure of Polygon's 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 /*! -\brief \brief_meta{value, closure (clockwise\, counterclockwise), +\brief \brief_meta{value, closure (clockwise\, counterclockwise), \meta_geometry_type} \tparam Geometry \tparam_geometry \ingroup core @@ -169,7 +191,7 @@ struct closure static const closure_selector value = core_dispatch::closure < typename tag<Geometry>::type, - typename boost::remove_const<Geometry>::type + typename util::bare_type<Geometry>::type >::value; }; diff --git a/boost/geometry/core/coordinate_dimension.hpp b/boost/geometry/core/coordinate_dimension.hpp index 2f3c914601..85da6b424e 100644 --- a/boost/geometry/core/coordinate_dimension.hpp +++ b/boost/geometry/core/coordinate_dimension.hpp @@ -58,7 +58,15 @@ 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> {}; +struct dimension<point_tag, P> + : traits::dimension<typename geometry::util::bare_type<P>::type> +{ + BOOST_MPL_ASSERT_MSG( + (traits::dimension<typename geometry::util::bare_type<P>::type>::value > 0), + INVALID_DIMENSION_VALUE, + (traits::dimension<typename geometry::util::bare_type<P>::type>) + ); +}; } // namespace core_dispatch #endif @@ -75,7 +83,7 @@ struct dimension : core_dispatch::dimension < typename tag<Geometry>::type, - typename geometry::util::bare_type<Geometry>::type + typename geometry::util::bare_type<Geometry>::type > {}; @@ -89,7 +97,7 @@ inline void assert_dimension() BOOST_STATIC_ASSERT(( boost::mpl::equal_to < - geometry::dimension<Geometry>, + boost::mpl::int_<geometry::dimension<Geometry>::value>, boost::mpl::int_<Dimensions> >::type::value )); @@ -102,13 +110,13 @@ inline void assert_dimension() template <typename Geometry, int Dimensions> inline void assert_dimension_less_equal() { - BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value <= Dimensions )); + BOOST_STATIC_ASSERT(( static_cast<int>(dimension<Geometry>::type::value) <= Dimensions )); } template <typename Geometry, int Dimensions> inline void assert_dimension_greater_equal() { - BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value >= Dimensions )); + BOOST_STATIC_ASSERT(( static_cast<int>(dimension<Geometry>::type::value) >= Dimensions )); } /*! @@ -118,7 +126,7 @@ inline void assert_dimension_greater_equal() template <typename G1, typename G2> inline void assert_dimension_equal() { - BOOST_STATIC_ASSERT(( dimension<G1>::type::value == dimension<G2>::type::value )); + BOOST_STATIC_ASSERT(( static_cast<size_t>(dimension<G1>::type::value) == static_cast<size_t>(dimension<G2>::type::value) )); } }} // namespace boost::geometry diff --git a/boost/geometry/core/coordinate_system.hpp b/boost/geometry/core/coordinate_system.hpp index 01e5ad1dd7..d33353f4b4 100644 --- a/boost/geometry/core/coordinate_system.hpp +++ b/boost/geometry/core/coordinate_system.hpp @@ -66,9 +66,9 @@ namespace core_dispatch struct coordinate_system<point_tag, Point> { typedef typename traits::coordinate_system - < - typename geometry::util::bare_type<Point>::type - >::type type; + < + typename geometry::util::bare_type<Point>::type + >::type type; }; @@ -89,7 +89,7 @@ struct coordinate_system typedef typename core_dispatch::coordinate_system < typename tag<Geometry>::type, - typename geometry::util::bare_type<Geometry>::type + typename geometry::util::bare_type<Geometry>::type >::type type; }; diff --git a/boost/geometry/core/coordinate_type.hpp b/boost/geometry/core/coordinate_type.hpp index d17f66ab73..f138d59c8a 100644 --- a/boost/geometry/core/coordinate_type.hpp +++ b/boost/geometry/core/coordinate_type.hpp @@ -65,9 +65,9 @@ template <typename Point> struct coordinate_type<point_tag, Point> { typedef typename traits::coordinate_type - < + < typename geometry::util::bare_type<Point>::type - >::type type; + >::type type; }; @@ -85,11 +85,11 @@ struct coordinate_type<point_tag, Point> 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; + typedef typename core_dispatch::coordinate_type + < + typename tag<Geometry>::type, + typename geometry::util::bare_type<Geometry>::type + >::type type; }; template <typename Geometry> diff --git a/boost/geometry/core/cs.hpp b/boost/geometry/core/cs.hpp index 3588ed1a86..cf6c56b53c 100644 --- a/boost/geometry/core/cs.hpp +++ b/boost/geometry/core/cs.hpp @@ -28,7 +28,7 @@ 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). + 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]} */ @@ -38,7 +38,7 @@ 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). + 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]} */ @@ -106,7 +106,7 @@ struct spherical /*! \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 + 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) @@ -185,20 +185,22 @@ struct cs_tag<cs::cartesian> /*! \brief Meta-function returning coordinate system tag (cs family) of any geometry +\tparam Geometry \tparam_geometry \ingroup core */ -template <typename G> +template <typename Geometry> struct cs_tag { typedef typename traits::cs_tag < - typename geometry::coordinate_system<G>::type + typename geometry::coordinate_system<Geometry>::type >::type type; }; /*! \brief Meta-function to verify if a coordinate system is radian +\tparam CoordinateSystem Any coordinate system. \ingroup core */ template <typename CoordinateSystem> diff --git a/boost/geometry/core/exterior_ring.hpp b/boost/geometry/core/exterior_ring.hpp index 70012c22db..e5c97dd301 100644 --- a/boost/geometry/core/exterior_ring.hpp +++ b/boost/geometry/core/exterior_ring.hpp @@ -101,7 +101,7 @@ struct exterior_ring<polygon_tag, Polygon> \brief Function to get the exterior_ring ring of a polygon \ingroup exterior_ring \note OGC compliance: instead of ExteriorRing - \tparam P polygon type + \tparam Polygon polygon type \param polygon the polygon to get the exterior ring from \return a reference to the exterior ring */ diff --git a/boost/geometry/core/geometry_id.hpp b/boost/geometry/core/geometry_id.hpp index 369c5cfa1a..5fc5a80050 100644 --- a/boost/geometry/core/geometry_id.hpp +++ b/boost/geometry/core/geometry_id.hpp @@ -18,8 +18,6 @@ #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> @@ -45,28 +43,39 @@ struct geometry_id template <> -struct geometry_id<point_tag> : boost::mpl::int_<1> {}; +struct geometry_id<point_tag> : boost::mpl::int_<1> {}; template <> -struct geometry_id<linestring_tag> : boost::mpl::int_<2> {}; +struct geometry_id<linestring_tag> : boost::mpl::int_<2> {}; template <> -struct geometry_id<polygon_tag> : boost::mpl::int_<3> {}; +struct geometry_id<polygon_tag> : boost::mpl::int_<3> {}; template <> -struct geometry_id<segment_tag> : boost::mpl::int_<92> {}; +struct geometry_id<multi_point_tag> : boost::mpl::int_<4> {}; template <> -struct geometry_id<ring_tag> : boost::mpl::int_<93> {}; +struct geometry_id<multi_linestring_tag> : boost::mpl::int_<5> {}; template <> -struct geometry_id<box_tag> : boost::mpl::int_<94> {}; +struct geometry_id<multi_polygon_tag> : boost::mpl::int_<6> {}; + + +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 @@ -76,9 +85,9 @@ struct geometry_id<box_tag> : boost::mpl::int_<94> {}; /*! \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 +\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 diff --git a/boost/geometry/core/interior_rings.hpp b/boost/geometry/core/interior_rings.hpp index 10af2ae4ee..798f415779 100644 --- a/boost/geometry/core/interior_rings.hpp +++ b/boost/geometry/core/interior_rings.hpp @@ -17,7 +17,7 @@ #include <cstddef> #include <boost/mpl/assert.hpp> -#include <boost/range.hpp> +#include <boost/range/value_type.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/geometry/core/tag.hpp> @@ -85,6 +85,17 @@ struct interior_rings<polygon_tag, Polygon> }; +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 diff --git a/boost/geometry/core/is_areal.hpp b/boost/geometry/core/is_areal.hpp index 5ddfa753bc..23858605f4 100644 --- a/boost/geometry/core/is_areal.hpp +++ b/boost/geometry/core/is_areal.hpp @@ -16,8 +16,7 @@ #define BOOST_GEOMETRY_CORE_IS_AREAL_HPP -#include <boost/type_traits.hpp> - +#include <boost/type_traits/integral_constant.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> @@ -36,7 +35,7 @@ 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 {}; - +template <> struct is_areal<multi_polygon_tag> : boost::true_type {}; } // namespace core_dispatch #endif diff --git a/boost/geometry/core/point_order.hpp b/boost/geometry/core/point_order.hpp index f09086a9d4..d43adbd03a 100644 --- a/boost/geometry/core/point_order.hpp +++ b/boost/geometry/core/point_order.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,7 +21,7 @@ #include <boost/mpl/assert.hpp> -#include <boost/range.hpp> +#include <boost/range/value_type.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/geometry/core/ring_type.hpp> @@ -29,10 +34,10 @@ 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, +\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{ @@ -120,7 +125,7 @@ struct point_order<linestring_tag, LineString> template <typename Ring> struct point_order<ring_tag, Ring> { - static const order_selector value + static const order_selector value = geometry::traits::point_order<Ring>::value; }; @@ -135,12 +140,32 @@ struct point_order<polygon_tag, Polygon> >::value ; }; +template <typename MultiPoint> +struct point_order<multi_point_tag, MultiPoint> + : public detail::point_order::clockwise {}; + +template <typename MultiLinestring> +struct point_order<multi_linestring_tag, MultiLinestring> + : 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 /*! -\brief \brief_meta{value, point order (clockwise\, counterclockwise), +\brief \brief_meta{value, point order (clockwise\, counterclockwise), \meta_geometry_type} \tparam Geometry \tparam_geometry \ingroup core @@ -153,7 +178,7 @@ struct point_order static const order_selector value = core_dispatch::point_order < typename tag<Geometry>::type, - typename boost::remove_const<Geometry>::type + typename util::bare_type<Geometry>::type >::value; }; diff --git a/boost/geometry/core/point_type.hpp b/boost/geometry/core/point_type.hpp index e148c84a57..f70e1fedd5 100644 --- a/boost/geometry/core/point_type.hpp +++ b/boost/geometry/core/point_type.hpp @@ -16,7 +16,7 @@ #include <boost/mpl/assert.hpp> -#include <boost/range.hpp> +#include <boost/range/value_type.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/geometry/core/ring_type.hpp> @@ -102,13 +102,45 @@ struct point_type<polygon_tag, Polygon> }; +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; +}; + + } // namespace core_dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief \brief_meta{type, point_type, \meta_geometry_type} -\tparam Geometry \tparam_geometry +\tparam Geometry \tparam_geometry \ingroup core \qbk{[include reference/core/point_type.qbk]} diff --git a/boost/geometry/core/ring_type.hpp b/boost/geometry/core/ring_type.hpp index 9b984faf3c..fe551f060f 100644 --- a/boost/geometry/core/ring_type.hpp +++ b/boost/geometry/core/ring_type.hpp @@ -18,8 +18,10 @@ #include <boost/mpl/assert.hpp> #include <boost/mpl/if.hpp> +#include <boost/range/value_type.hpp> +#include <boost/type_traits/is_const.hpp> #include <boost/type_traits/remove_const.hpp> - +#include <boost/type_traits/remove_reference.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> @@ -102,6 +104,38 @@ struct ring_return_type<polygon_tag, Polygon> }; +template <typename MultiLinestring> +struct ring_return_type<multi_linestring_tag, MultiLinestring> +{ + typedef typename ring_return_type + < + linestring_tag, + typename mpl::if_ + < + boost::is_const<MultiLinestring>, + typename boost::range_value<MultiLinestring>::type const, + typename boost::range_value<MultiLinestring>::type + >::type + >::type type; +}; + + +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 GeometryTag, typename Geometry> struct ring_type {}; @@ -124,7 +158,24 @@ struct ring_type<polygon_tag, Polygon> }; +template <typename MultiLinestring> +struct ring_type<multi_linestring_tag, MultiLinestring> +{ + typedef typename boost::remove_reference + < + typename ring_return_type<multi_linestring_tag, MultiLinestring>::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 diff --git a/boost/geometry/core/tag.hpp b/boost/geometry/core/tag.hpp index 4c790fdc9e..6bffcb932d 100644 --- a/boost/geometry/core/tag.hpp +++ b/boost/geometry/core/tag.hpp @@ -14,7 +14,6 @@ #ifndef BOOST_GEOMETRY_CORE_TAG_HPP #define BOOST_GEOMETRY_CORE_TAG_HPP - #include <boost/mpl/assert.hpp> #include <boost/geometry/core/tags.hpp> @@ -52,7 +51,7 @@ struct tag \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 +\tparam Geometry \tparam_geometry \ingroup core \qbk{[include reference/core/tag.qbk]} @@ -62,7 +61,7 @@ struct tag { typedef typename traits::tag < - typename geometry::util::bare_type<Geometry>::type + typename geometry::util::bare_type<Geometry>::type >::type type; }; diff --git a/boost/geometry/core/tag_cast.hpp b/boost/geometry/core/tag_cast.hpp index 47a2e834f1..cafd13cba9 100644 --- a/boost/geometry/core/tag_cast.hpp +++ b/boost/geometry/core/tag_cast.hpp @@ -25,10 +25,10 @@ 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 + 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 +\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 diff --git a/boost/geometry/core/tags.hpp b/boost/geometry/core/tags.hpp index 9272858ed2..160477b8c4 100644 --- a/boost/geometry/core/tags.hpp +++ b/boost/geometry/core/tags.hpp @@ -57,7 +57,7 @@ struct linear_tag {}; struct areal_tag {}; // Subset of areal types (polygon, multi_polygon, ring) -struct polygonal_tag : areal_tag {}; +struct polygonal_tag : areal_tag {}; /// For volume types (also box (?), polyhedron) struct volumetric_tag {}; @@ -88,6 +88,49 @@ struct box_tag : single_tag, areal_tag {}; struct segment_tag : single_tag, linear_tag {}; +/// 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 diff --git a/boost/geometry/core/topological_dimension.hpp b/boost/geometry/core/topological_dimension.hpp index 02f1ed341e..22ed676fc6 100644 --- a/boost/geometry/core/topological_dimension.hpp +++ b/boost/geometry/core/topological_dimension.hpp @@ -49,10 +49,12 @@ struct top_dim<segment_tag> : boost::mpl::int_<1> {}; // ring: topological dimension of two, but some people say: 1 !! +// NOTE: This is not OGC LinearRing! template <> struct top_dim<ring_tag> : boost::mpl::int_<2> {}; +// TODO: This is wrong! Boxes may have various topological dimensions template <> struct top_dim<box_tag> : boost::mpl::int_<2> {}; @@ -61,6 +63,17 @@ template <> struct top_dim<polygon_tag> : boost::mpl::int_<2> {}; +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 diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp index 93b21fee94..490fa45fe9 100644 --- a/boost/geometry/geometries/adapted/boost_polygon/ring.hpp +++ b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp @@ -69,7 +69,26 @@ struct push_back<boost::polygon::polygon_data<CoordinateType> > } }; +template <typename CoordinateType> +struct resize<boost::polygon::polygon_data<CoordinateType> > +{ + typedef boost::polygon::point_data<CoordinateType> point_type; + static inline void apply(boost::polygon::polygon_data<CoordinateType>& data, + std::size_t new_size) + { + // Boost.Polygon's polygons are not resizable. So create a temporary vector, + // resize it 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.resize(new_size); + data.set(temporary_vector.begin(), temporary_vector.end()); + } +}; } // namespace traits diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp index 825ef8061f..1616369da1 100644 --- a/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp +++ b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp @@ -150,7 +150,7 @@ public : } } - void resize(std::size_t new_size) + void resize(std::size_t /*new_size*/) { if (m_do_hole) { diff --git a/boost/geometry/geometries/concepts/check.hpp b/boost/geometry/geometries/concepts/check.hpp index f8001f0d12..07ef84f4a4 100644 --- a/boost/geometry/geometries/concepts/check.hpp +++ b/boost/geometry/geometries/concepts/check.hpp @@ -18,17 +18,23 @@ #include <boost/concept_check.hpp> #include <boost/concept/requires.hpp> - #include <boost/type_traits/is_const.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/box_concept.hpp> #include <boost/geometry/geometries/concepts/linestring_concept.hpp> +#include <boost/geometry/geometries/concepts/multi_point_concept.hpp> +#include <boost/geometry/geometries/concepts/multi_linestring_concept.hpp> +#include <boost/geometry/geometries/concepts/multi_polygon_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> namespace boost { namespace geometry { @@ -53,59 +59,122 @@ class check namespace dispatch { -template <typename GeometryTag, typename Geometry, bool IsConst> -struct check +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<point_tag, Geometry, true> +struct check<Geometry, point_tag, true> : detail::concept_check::check<concept::ConstPoint<Geometry> > {}; template <typename Geometry> -struct check<point_tag, Geometry, false> +struct check<Geometry, point_tag, false> : detail::concept_check::check<concept::Point<Geometry> > {}; template <typename Geometry> -struct check<linestring_tag, Geometry, true> +struct check<Geometry, linestring_tag, true> : detail::concept_check::check<concept::ConstLinestring<Geometry> > {}; template <typename Geometry> -struct check<linestring_tag, Geometry, false> +struct check<Geometry, linestring_tag, false> : detail::concept_check::check<concept::Linestring<Geometry> > {}; template <typename Geometry> -struct check<polygon_tag, Geometry, true> +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<polygon_tag, Geometry, false> +struct check<Geometry, polygon_tag, false> : detail::concept_check::check<concept::Polygon<Geometry> > {}; template <typename Geometry> -struct check<box_tag, Geometry, true> +struct check<Geometry, box_tag, true> : detail::concept_check::check<concept::ConstBox<Geometry> > {}; template <typename Geometry> -struct check<box_tag, Geometry, false> +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> > +{}; + + +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 @@ -122,13 +191,16 @@ namespace detail { -template <typename Geometry, bool IsConst> -struct checker : dispatch::check - < - typename tag<Geometry>::type, - Geometry, - IsConst - > +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> {}; @@ -143,7 +215,7 @@ struct checker : dispatch::check template <typename Geometry> inline void check() { - detail::checker<Geometry, boost::is_const<Geometry>::type::value> c; + detail::checker<Geometry> c; boost::ignore_unused_variable_warning(c); } diff --git a/boost/geometry/geometries/concepts/multi_linestring_concept.hpp b/boost/geometry/geometries/concepts/multi_linestring_concept.hpp new file mode 100644 index 0000000000..f13f7ac7e8 --- /dev/null +++ b/boost/geometry/geometries/concepts/multi_linestring_concept.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_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP +#define BOOST_GEOMETRY_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) + { + Geometry* mls = 0; + traits::clear<Geometry>::apply(*mls); + traits::resize<Geometry>::apply(*mls, 0); + linestring_type* ls = 0; + traits::push_back<Geometry>::apply(*mls, *ls); + } +#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_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/multi_point_concept.hpp b/boost/geometry/geometries/concepts/multi_point_concept.hpp new file mode 100644 index 0000000000..81c087166f --- /dev/null +++ b/boost/geometry/geometries/concepts/multi_point_concept.hpp @@ -0,0 +1,90 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP +#define BOOST_GEOMETRY_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) + { + Geometry* mp = 0; + traits::clear<Geometry>::apply(*mp); + traits::resize<Geometry>::apply(*mp, 0); + point_type* point = 0; + traits::push_back<Geometry>::apply(*mp, *point); + } +#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_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP diff --git a/boost/geometry/geometries/concepts/multi_polygon_concept.hpp b/boost/geometry/geometries/concepts/multi_polygon_concept.hpp new file mode 100644 index 0000000000..b13d330f3c --- /dev/null +++ b/boost/geometry/geometries/concepts/multi_polygon_concept.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_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP +#define BOOST_GEOMETRY_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) + { + Geometry* mp = 0; + traits::clear<Geometry>::apply(*mp); + traits::resize<Geometry>::apply(*mp, 0); + polygon_type* poly = 0; + traits::push_back<Geometry>::apply(*mp, *poly); + } +#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_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP diff --git a/boost/geometry/geometries/geometries.hpp b/boost/geometry/geometries/geometries.hpp index cda55c1d28..de9e2b1fd9 100644 --- a/boost/geometry/geometries/geometries.hpp +++ b/boost/geometry/geometries/geometries.hpp @@ -18,6 +18,10 @@ #include <boost/geometry/geometries/linestring.hpp> #include <boost/geometry/geometries/polygon.hpp> +#include <boost/geometry/geometries/multi_point.hpp> +#include <boost/geometry/geometries/multi_linestring.hpp> +#include <boost/geometry/geometries/multi_polygon.hpp> + #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/ring.hpp> #include <boost/geometry/geometries/segment.hpp> diff --git a/boost/geometry/geometries/multi_linestring.hpp b/boost/geometry/geometries/multi_linestring.hpp new file mode 100644 index 0000000000..2ba8e7196b --- /dev/null +++ b/boost/geometry/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_GEOMETRIES_MULTI_LINESTRING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_MULTI_LINESTRING_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/geometries/concepts/linestring_concept.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_GEOMETRIES_MULTI_LINESTRING_HPP diff --git a/boost/geometry/geometries/multi_point.hpp b/boost/geometry/geometries/multi_point.hpp new file mode 100644 index 0000000000..d0a782a1de --- /dev/null +++ b/boost/geometry/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_GEOMETRIES_MULTI_POINT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_MULTI_POINT_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/geometries/concepts/point_concept.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_GEOMETRIES_MULTI_POINT_HPP diff --git a/boost/geometry/geometries/multi_polygon.hpp b/boost/geometry/geometries/multi_polygon.hpp new file mode 100644 index 0000000000..228074cd34 --- /dev/null +++ b/boost/geometry/geometries/multi_polygon.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_GEOMETRIES_MULTI_POLYGON_HPP +#define BOOST_GEOMETRY_GEOMETRIES_MULTI_POLYGON_HPP + +#include <memory> +#include <vector> + +#include <boost/concept/requires.hpp> + +#include <boost/geometry/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_GEOMETRIES_MULTI_POLYGON_HPP diff --git a/boost/geometry/geometries/point.hpp b/boost/geometry/geometries/point.hpp index b40a47355d..a25340c463 100644 --- a/boost/geometry/geometries/point.hpp +++ b/boost/geometry/geometries/point.hpp @@ -28,6 +28,12 @@ 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 { @@ -65,7 +71,7 @@ public: {} /// @brief Constructor to set one, two or three values - inline point(CoordinateType const& v0, CoordinateType const& v1 = 0, CoordinateType const& v2 = 0) + explicit 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; @@ -173,6 +179,10 @@ struct access<model::point<CoordinateType, DimensionCount, CoordinateSystem>, Di } // 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/pointing_segment.hpp b/boost/geometry/geometries/pointing_segment.hpp new file mode 100644 index 0000000000..681752ef2d --- /dev/null +++ b/boost/geometry/geometries/pointing_segment.hpp @@ -0,0 +1,143 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP + +#include <cstddef> + +#include <boost/assert.hpp> +#include <boost/concept/assert.hpp> +#include <boost/core/addressof.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_const.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace model +{ + +// const or non-const segment type that is meant to be +// * default constructible +// * copy constructible +// * assignable +// referring_segment does not fit these requirements, hence the +// pointing_segment class +// +// this class is used by the segment_iterator as its value type +template <typename ConstOrNonConstPoint> +class pointing_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 pointing_segment() + : first(NULL) + , second(NULL) + {} + + inline pointing_segment(point_type const& p1, point_type const& p2) + : first(boost::addressof(p1)) + , second(boost::addressof(p2)) + {} +}; + + +} // namespace model + + +// Traits specializations for segment above +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename Point> +struct tag<model::pointing_segment<Point> > +{ + typedef segment_tag type; +}; + +template <typename Point> +struct point_type<model::pointing_segment<Point> > +{ + typedef Point type; +}; + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::pointing_segment<Point>, 0, Dimension> +{ + typedef model::pointing_segment<Point> segment_type; + typedef typename geometry::coordinate_type + < + segment_type + >::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + BOOST_ASSERT( s.first != NULL ); + return geometry::get<Dimension>(*s.first); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + BOOST_ASSERT( s.first != NULL ); + geometry::set<Dimension>(*s.first, value); + } +}; + + +template <typename Point, std::size_t Dimension> +struct indexed_access<model::pointing_segment<Point>, 1, Dimension> +{ + typedef model::pointing_segment<Point> segment_type; + typedef typename geometry::coordinate_type + < + segment_type + >::type coordinate_type; + + static inline coordinate_type get(segment_type const& s) + { + BOOST_ASSERT( s.second != NULL ); + return geometry::get<Dimension>(*s.second); + } + + static inline void set(segment_type& s, coordinate_type const& value) + { + BOOST_ASSERT( s.second != NULL ); + geometry::set<Dimension>(*s.second, value); + } +}; + + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP diff --git a/boost/geometry/geometries/register/box.hpp b/boost/geometry/geometries/register/box.hpp index 838c2bb5fc..71a7077a66 100644 --- a/boost/geometry/geometries/register/box.hpp +++ b/boost/geometry/geometries/register/box.hpp @@ -105,7 +105,7 @@ template <> struct indexed_access<Box, max_corner, 1> \ /*! \brief \brief_macro{box} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX, box} The +\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 @@ -128,7 +128,7 @@ namespace boost { namespace geometry { namespace traits { \ /*! \brief \brief_macro{box} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED, box} +\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) @@ -149,10 +149,10 @@ namespace boost { namespace geometry { namespace traits { \ /*! \brief \brief_macro{box} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_2D_4VALUES, box} +\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 + 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) diff --git a/boost/geometry/geometries/register/linestring.hpp b/boost/geometry/geometries/register/linestring.hpp index b064398746..cfc7dcaed2 100644 --- a/boost/geometry/geometries/register/linestring.hpp +++ b/boost/geometry/geometries/register/linestring.hpp @@ -22,7 +22,7 @@ /*! \brief \brief_macro{linestring} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING, linestring} The +\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} @@ -41,7 +41,7 @@ namespace boost { namespace geometry { namespace traits { \ /*! \brief \brief_macro{templated linestring} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED, templated linestring} +\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED, templated linestring} \details_macro_templated{linestring, point} \param Linestring \param_macro_type{linestring (without template parameters)} diff --git a/boost/geometry/geometries/register/multi_linestring.hpp b/boost/geometry/geometries/register/multi_linestring.hpp new file mode 100644 index 0000000000..ad11289d11 --- /dev/null +++ b/boost/geometry/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_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/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_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP diff --git a/boost/geometry/geometries/register/multi_point.hpp b/boost/geometry/geometries/register/multi_point.hpp new file mode 100644 index 0000000000..4e875ae0cd --- /dev/null +++ b/boost/geometry/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_GEOMETRIES_REGISTER_MULTI_POINT_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POINT_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/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_GEOMETRIES_REGISTER_MULTI_POINT_HPP diff --git a/boost/geometry/geometries/register/multi_polygon.hpp b/boost/geometry/geometries/register/multi_polygon.hpp new file mode 100644 index 0000000000..1c3818b551 --- /dev/null +++ b/boost/geometry/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_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP +#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/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_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP diff --git a/boost/geometry/geometries/register/ring.hpp b/boost/geometry/geometries/register/ring.hpp index fb6cb67200..761e46fbc4 100644 --- a/boost/geometry/geometries/register/ring.hpp +++ b/boost/geometry/geometries/register/ring.hpp @@ -22,7 +22,7 @@ /*! \brief \brief_macro{ring} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_RING, ring} The +\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} @@ -41,7 +41,7 @@ namespace boost { namespace geometry { namespace traits { \ /*! \brief \brief_macro{templated ring} \ingroup register -\details \details_macro{BOOST_GEOMETRY_REGISTER_RING_TEMPLATED, templated ring} +\details \details_macro{BOOST_GEOMETRY_REGISTER_RING_TEMPLATED, templated ring} \details_macro_templated{ring, point} \param Ring \param_macro_type{ring (without template parameters)} diff --git a/boost/geometry/geometries/variant.hpp b/boost/geometry/geometries/variant.hpp new file mode 100644 index 0000000000..9db11d5a82 --- /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 index b696b652cf..110f0e60ff 100644 --- a/boost/geometry/geometry.hpp +++ b/boost/geometry/geometry.hpp @@ -16,7 +16,15 @@ // Shortcut to include all header files +#include <boost/geometry/core/closure.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/cs.hpp> +#include <boost/geometry/core/interior_type.hpp> +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> @@ -45,6 +53,7 @@ #include <boost/geometry/algorithms/convex_hull.hpp> #include <boost/geometry/algorithms/correct.hpp> #include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/crosses.hpp> #include <boost/geometry/algorithms/difference.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/distance.hpp> @@ -54,13 +63,17 @@ #include <boost/geometry/algorithms/for_each.hpp> #include <boost/geometry/algorithms/intersection.hpp> #include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/is_simple.hpp> +#include <boost/geometry/algorithms/is_valid.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/num_segments.hpp> #include <boost/geometry/algorithms/overlaps.hpp> #include <boost/geometry/algorithms/perimeter.hpp> +#include <boost/geometry/algorithms/remove_spikes.hpp> #include <boost/geometry/algorithms/reverse.hpp> #include <boost/geometry/algorithms/simplify.hpp> #include <boost/geometry/algorithms/sym_difference.hpp> @@ -79,13 +92,20 @@ #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/util/select_most_precise.hpp> #include <boost/geometry/views/box_view.hpp> +#include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/views/identity_view.hpp> +#include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/views/segment_view.hpp> #include <boost/geometry/io/io.hpp> +#include <boost/geometry/io/dsv/write.hpp> +#include <boost/geometry/io/svg/svg_mapper.hpp> +#include <boost/geometry/io/svg/write_svg.hpp> +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/io/wkt/write.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 0000000000..472b3693b1 --- /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 0000000000..4d2416e98d --- /dev/null +++ b/boost/geometry/index/detail/algorithms/bounds.hpp @@ -0,0 +1,90 @@ +// Boost.Geometry Index +// +// n-dimensional bounds +// +// Copyright (c) 2011-2014 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 + +#include <boost/geometry/index/detail/bounded_view.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); + } +}; + +template <typename Geometry, typename Bounds> +struct bounds<Geometry, Bounds, segment_tag, box_tag> +{ + static inline void apply(Geometry const& g, Bounds & b) + { + index::detail::bounded_view<Geometry, Bounds> v(g); + geometry::convert(v, 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 dispatch { + +template <typename Geometry, + typename TagGeometry = typename geometry::tag<Geometry>::type> +struct return_ref_or_bounds +{ + typedef Geometry const& result_type; + + static inline result_type apply(Geometry const& g) + { + return g; + } +}; + +template <typename Geometry> +struct return_ref_or_bounds<Geometry, segment_tag> +{ + typedef typename point_type<Geometry>::type point_type; + typedef geometry::model::box<point_type> bounds_type; + typedef index::detail::bounded_view<Geometry, bounds_type> result_type; + + static inline result_type apply(Geometry const& g) + { + return result_type(g); + } +}; + +} // namespace dispatch + +template <typename Geometry> +inline +typename dispatch::return_ref_or_bounds<Geometry>::result_type +return_ref_or_bounds(Geometry const& g) +{ + return dispatch::return_ref_or_bounds<Geometry>::apply(g); +} + +}}}} // 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 0000000000..c4e44cae18 --- /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-2014 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_comparable_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_comparable_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_comparable_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 0000000000..214fbf6aaf --- /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-2014 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_comparable_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_comparable_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 0000000000..15368a7d24 --- /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-2014 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_comparable_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_comparable_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_comparable_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 0000000000..028113e0ef --- /dev/null +++ b/boost/geometry/index/detail/algorithms/content.hpp @@ -0,0 +1,87 @@ +// Boost.Geometry Index +// +// n-dimensional content (hypervolume) - 2d area, 3d volume, ... +// +// Copyright (c) 2011-2014 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, + std::size_t CurrentDimension = dimension<Box>::value> +struct content_box +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + + 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>::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 0000000000..ec63bd9a5d --- /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 0000000000..4afb40479c --- /dev/null +++ b/boost/geometry/index/detail/algorithms/intersection_content.hpp @@ -0,0 +1,37 @@ +// Boost.Geometry Index +// +// boxes union/intersection area/volume +// +// Copyright (c) 2011-2014 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/strategies/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; + if ( 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 0000000000..d85ac56d69 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/is_valid.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry Index +// +// n-dimensional Indexable validity check +// +// Copyright (c) 2011-2014 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 + +#include <cstddef> +#include <boost/geometry/core/access.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template <typename Box, + std::size_t Dimension = geometry::dimension<Box>::value> +struct 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 = typename geometry::tag<Indexable>::type> +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>::apply(b); + } +}; + +template <typename Indexable> +struct is_valid<Indexable, segment_tag> +{ + static inline bool apply(Indexable const&) + { + return true; + } +}; + +} // namespace dispatch + +template <typename Indexable> +inline bool is_valid(Indexable const& b) +{ + return dispatch::is_valid<Indexable>::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 0000000000..d4876600ac --- /dev/null +++ b/boost/geometry/index/detail/algorithms/margin.hpp @@ -0,0 +1,169 @@ +// Boost.Geometry Index +// +// n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc... +// +// Copyright (c) 2011-2014 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, +// std::size_t CurrentDimension, +// std::size_t EdgeDimension = dimension<Box>::value> +//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, std::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, std::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, +// std::size_t CurrentDimension = dimension<Box>::value> +//struct margin_for_each_dimension +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// +// 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>::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>::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, + std::size_t CurrentDimension = dimension<Box>::value> +struct simple_margin_for_each_dimension +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + + 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>::apply(g); + return detail::simple_margin_for_each_dimension<Box>::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>::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 0000000000..ab6291504f --- /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-2014 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_comparable_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_comparable_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_comparable_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_comparable_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 0000000000..fe92596ba2 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/path_intersection.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry Index +// +// n-dimensional box-linestring intersection +// +// Copyright (c) 2011-2014 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)); +}; + +// TODO: FP type must be used as a relative distance type! +// and default_distance_result can be some user-defined int type +// BUT! This code is experimental and probably won't be released at all +// since more flexible user-defined-nearest predicate should be added instead + +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 0000000000..ec7a88f490 --- /dev/null +++ b/boost/geometry/index/detail/algorithms/segment_intersection.hpp @@ -0,0 +1,146 @@ +// Boost.Geometry Index +// +// n-dimensional box-segment intersection +// +// Copyright (c) 2011-2014 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(0 <= dimension<Box>::value); + BOOST_STATIC_ASSERT(0 <= dimension<Point>::value); + BOOST_STATIC_ASSERT(I < size_t(dimension<Box>::value)); + BOOST_STATIC_ASSERT(I < size_t(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) + { + +// TODO: this ASSERT CHECK is wrong for user-defined CoordinateTypes! + + 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 0000000000..3ca335d5a7 --- /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 0000000000..4aef36352e --- /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 0000000000..3acdc3d198 --- /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 0000000000..22af315bc8 --- /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/bounded_view.hpp b/boost/geometry/index/detail/bounded_view.hpp new file mode 100644 index 0000000000..572368e273 --- /dev/null +++ b/boost/geometry/index/detail/bounded_view.hpp @@ -0,0 +1,185 @@ +// Boost.Geometry Index +// +// This view makes possible to treat some simple primitives as its bounding geometry +// e.g. box, nsphere, etc. +// +// Copyright (c) 2014 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_BOUNDED_VIEW_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP + +namespace boost { namespace geometry { + +namespace index { namespace detail { + +template <typename Geometry, + typename BoundingGeometry, + typename Tag = typename geometry::tag<Geometry>::type, + typename BoundingTag = typename geometry::tag<BoundingGeometry>::type> +struct bounded_view +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THOSE_GEOMETRIES, + (BoundingTag, Tag)); +}; + + +// Segment -> Box + +template <typename Segment, typename Box> +struct bounded_view<Segment, Box, segment_tag, box_tag> +{ +public: + typedef typename geometry::coordinate_type<Box>::type coordinate_type; + + explicit bounded_view(Segment const& segment) + : m_segment(segment) + {} + + template <std::size_t Dimension> + inline coordinate_type get_min() const + { + return boost::numeric_cast<coordinate_type>( + (std::min)( geometry::get<0, Dimension>(m_segment), + geometry::get<1, Dimension>(m_segment) ) ); + } + + template <std::size_t Dimension> + inline coordinate_type get_max() const + { + return boost::numeric_cast<coordinate_type>( + (std::max)( geometry::get<0, Dimension>(m_segment), + geometry::get<1, Dimension>(m_segment) ) ); + } + +private: + Segment const& m_segment; +}; + +// Box -> Box + +template <typename BoxIn, typename Box> +struct bounded_view<BoxIn, Box, box_tag, box_tag> +{ +public: + typedef typename geometry::coordinate_type<Box>::type coordinate_type; + + explicit bounded_view(BoxIn const& box) + : m_box(box) + {} + + template <std::size_t Dimension> + inline coordinate_type get_min() const + { + return boost::numeric_cast<coordinate_type>( + geometry::get<min_corner, Dimension>(m_box) ); + } + + template <std::size_t Dimension> + inline coordinate_type get_max() const + { + return boost::numeric_cast<coordinate_type>( + geometry::get<max_corner, Dimension>(m_box) ); + } + +private: + BoxIn const& m_box; +}; + +// Point -> Box + +template <typename Point, typename Box> +struct bounded_view<Point, Box, point_tag, box_tag> +{ +public: + typedef typename geometry::coordinate_type<Box>::type coordinate_type; + + explicit bounded_view(Point const& point) + : m_point(point) + {} + + template <std::size_t Dimension> + inline coordinate_type get_min() const + { + return boost::numeric_cast<coordinate_type>( + geometry::get<Dimension>(m_point) ); + } + + template <std::size_t Dimension> + inline coordinate_type get_max() const + { + return boost::numeric_cast<coordinate_type>( + geometry::get<Dimension>(m_point) ); + } + +private: + Point const& m_point; +}; + +}} // namespace index::detail + +// XXX -> Box + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename Geometry, typename Box, typename Tag> +struct tag< index::detail::bounded_view<Geometry, Box, Tag, box_tag> > +{ + typedef box_tag type; +}; + +template <typename Segment, typename Box, typename Tag> +struct point_type< index::detail::bounded_view<Segment, Box, Tag, box_tag> > +{ + typedef typename point_type<Box>::type type; +}; + +template <typename Segment, typename Box, typename Tag, std::size_t Dimension> +struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>, + min_corner, Dimension> +{ + typedef index::detail::bounded_view<Segment, Box, Tag, box_tag> box_type; + typedef typename geometry::coordinate_type<Box>::type coordinate_type; + + static inline coordinate_type get(box_type const& b) + { + return b.template get_min<Dimension>(); + } + + //static inline void set(box_type & b, coordinate_type const& value) + //{ + // BOOST_ASSERT(false); + //} +}; + +template <typename Segment, typename Box, typename Tag, std::size_t Dimension> +struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>, + max_corner, Dimension> +{ + typedef index::detail::bounded_view<Segment, Box, Tag, box_tag> box_type; + typedef typename geometry::coordinate_type<Box>::type coordinate_type; + + static inline coordinate_type get(box_type const& b) + { + return b.template get_max<Dimension>(); + } + + //static inline void set(box_type & b, coordinate_type const& value) + //{ + // BOOST_ASSERT(false); + //} +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP diff --git a/boost/geometry/index/detail/config_begin.hpp b/boost/geometry/index/detail/config_begin.hpp new file mode 100644 index 0000000000..21c346012b --- /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 0000000000..d144c33698 --- /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 0000000000..3e057290a6 --- /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-2014 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_comparable_distance_result<point_type, Indexable>::type result_type; + + static inline bool apply(nearest<PointRelation> const& p, Indexable const& i, result_type & result) + { + result = geometry::comparable_distance(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_comparable_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_comparable_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 0000000000..c3ea0e1923 --- /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 0000000000..bec1380b06 --- /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 0000000000..b92256649a --- /dev/null +++ b/boost/geometry/index/detail/predicates.hpp @@ -0,0 +1,813 @@ +// 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; +}; + +// ------------------------------------------------------------------ // + +// CONSIDER: separated nearest<> and path<> may be replaced by +// nearest_predicate<Geometry, Tag> +// where Tag = point_tag | path_tag +// IMPROVEMENT: user-defined nearest predicate allowing to define +// all or only geometrical aspects of the search + +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/rtree/adaptors.hpp b/boost/geometry/index/detail/rtree/adaptors.hpp new file mode 100644 index 0000000000..4e0eb9ba0a --- /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 0000000000..3f61482b27 --- /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 0000000000..f19654972e --- /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 0000000000..1461692a1e --- /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 0000000000..05a64c7b72 --- /dev/null +++ b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp @@ -0,0 +1,446 @@ +// Boost.Geometry Index +// +// R-tree linear split algorithm implementation +// +// Copyright (c) 2008 Federico J. Fernandez. +// Copyright (c) 2011-2014 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/bounded_view.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 +{ + 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; + + typedef typename geometry::point_type<indexable_type>::type point_type; + typedef geometry::model::box<point_type> bounds_type; + typedef index::detail::bounded_view<indexable_type, bounds_type> bounded_view_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 + bounded_view_type bounded_indexable_0(rtree::element_indexable(elements[0], translator)); + coordinate_type lowest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_0); + coordinate_type highest_high = geometry::get<max_corner, DimensionIndex>(bounded_indexable_0); + + // 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 ) + { + bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator)); + coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable); + coordinate_type max_coord = geometry::get<max_corner, DimensionIndex>(bounded_indexable); + + 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; + bounded_view_type bounded_indexable_hl(rtree::element_indexable(elements[highest_low_index], translator)); + coordinate_type highest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_hl); + for ( size_t i = highest_low_index ; i < elements_count ; ++i ) + { + bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator)); + coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable); + 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 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> +inline void pick_seeds(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + + typedef pick_seeds_impl + < + Elements, Parameters, Translator, + geometry::dimension<indexable_type>::value + > impl; + typedef typename impl::separation_type separation_type; + + separation_type separation = 0; + impl::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 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 - use in-memory storage (std::allocator) + // TODO: move if noexcept + typedef typename rtree::container_from_elements_type<elements_type, element_type>::type + container_type; + container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + linear::pick_seeds(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 0000000000..dd55c6d76c --- /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 0000000000..30fa44d263 --- /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 0000000000..43dff56bcb --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry Index +// +// R-tree nodes weak visitor and nodes base type +// +// Copyright (c) 2011-2014 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_WEAK_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// empty visitor +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst> +struct weak_visitor {}; + +// node + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_node {}; + +// nodes variants forward declarations + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_internal_node; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_leaf; + +// nodes conversion + +template <typename Derived, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline Derived & get(weak_node<Value, Parameters, Box, Allocators, Tag> & n) +{ + return static_cast<Derived&>(n); +} + +// apply visitor + +template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline void apply_visitor(Visitor & v, + raw_node<Value, Parameters, Box, Allocators, Tag> & n, + bool is_internal_node) +{ + BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); + if ( is_internal_node ) + { + typedef raw_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node; + v(get<internal_node>(n)); + } + else + { + typedef raw_leaf<Value, Parameters, Box, Allocators, Tag> leaf; + v(get<leaf>(n)); + } +} + +}} // 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 0000000000..a632ece66a --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node.hpp @@ -0,0 +1,178 @@ +// Boost.Geometry Index +// +// R-tree nodes +// +// Copyright (c) 2011-2014 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/node_elements.hpp> + +//#include <boost/geometry/index/detail/rtree/node/weak_visitor.hpp> +//#include <boost/geometry/index/detail/rtree/node/weak_dynamic.hpp> +//#include <boost/geometry/index/detail/rtree/node/weak_static.hpp> + +#include <boost/geometry/index/detail/rtree/node/variant_visitor.hpp> +#include <boost/geometry/index/detail/rtree/node/variant_dynamic.hpp> +#include <boost/geometry/index/detail/rtree/node/variant_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 +{ + template <typename Range> + inline static void apply(Range & elements, Allocators & allocators) + { + apply(boost::begin(elements), boost::end(elements), allocators); + } + + template <typename It> + inline static void apply(It first, It last, Allocators & allocators) + { + typedef boost::mpl::bool_< + boost::is_same< + Value, typename std::iterator_traits<It>::value_type + >::value + > is_range_of_values; + + apply_dispatch(first, last, allocators, is_range_of_values()); + } + +private: + template <typename It> + inline static void apply_dispatch(It first, It last, Allocators & allocators, + boost::mpl::bool_<false> const& /*is_range_of_values*/) + { + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + + for ( ; first != last ; ++first ) + { + node_auto_ptr dummy(first->second, allocators); + first->second = 0; + } + } + + template <typename It> + inline static void apply_dispatch(It /*first*/, It /*last*/, Allocators & /*allocators*/, + boost::mpl::bool_<true> const& /*is_range_of_values*/) + {} +}; + +// 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 0000000000..c19e123b62 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp @@ -0,0 +1,81 @@ +// 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 { + +// TODO - change the name to node_scoped_ptr + +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_elements.hpp b/boost/geometry/index/detail/rtree/node/node_elements.hpp new file mode 100644 index 0000000000..e3bfb701f8 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/node_elements.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry Index +// +// R-tree node elements access +// +// Copyright (c) 2011-2014 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_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP + +#include <boost/container/vector.hpp> +#include <boost/geometry/index/detail/varray.hpp> +#include <boost/geometry/index/detail/rtree/node/pairs.hpp> + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// 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; +}; + +template <typename OldValue, size_t N, typename NewValue> +struct container_from_elements_type<detail::varray<OldValue, N>, NewValue> +{ + typedef detail::varray<NewValue, N> type; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_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 0000000000..dc088ec29b --- /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/variant_dynamic.hpp b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp new file mode 100644 index 0000000000..f13dd10360 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp @@ -0,0 +1,275 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing dynamic-size containers +// +// Copyright (c) 2011-2014 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_VARIANT_DYNAMIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_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 variant_internal_node +{ + typedef boost::container::vector + < + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + typename Allocators::node_allocator_type::template rebind + < + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other + > elements_type; + + template <typename Al> + inline variant_internal_node(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct variant_leaf +{ + typedef boost::container::vector + < + Value, + typename Allocators::node_allocator_type::template rebind + < + Value + >::other + > elements_type; + + template <typename Al> + inline variant_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_variant_dynamic_tag> +{ + typedef boost::variant< + variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>, + variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> + > type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> +{ + typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> +{ + typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_variant_dynamic_tag, IsVisitableConst> +{ + typedef static_visitor<> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag> + : public Allocator::template rebind< + typename node< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>, + node_variant_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_variant_dynamic_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_variant_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_variant_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_variant_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, + variant_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_variant_node< + typename Allocators::node_pointer, + variant_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, + variant_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_variant_node< + typename Allocators::node_pointer, + variant_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, + variant_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_variant_node< + variant_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, + variant_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_variant_node< + variant_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_VARIANT_DYNAMIC_HPP diff --git a/boost/geometry/index/detail/rtree/node/variant_static.hpp b/boost/geometry/index/detail/rtree/node/variant_static.hpp new file mode 100644 index 0000000000..f6e9761b2d --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/variant_static.hpp @@ -0,0 +1,194 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing static-size containers +// +// Copyright (c) 2011-2014 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_VARIANT_STATIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes default types + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> +{ + typedef detail::varray< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline variant_internal_node(Alloc const&) {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> +{ + typedef detail::varray< + Value, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline variant_leaf(Alloc const&) {} + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_variant_static_tag> +{ + typedef boost::variant< + variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>, + variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> + > type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> +{ + typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> +{ + typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_variant_static_tag, IsVisitableConst> +{ + typedef static_visitor<> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +struct allocators<Allocator, Value, Parameters, Box, node_variant_static_tag> + : public Allocator::template rebind< + typename node< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_variant_static_tag>, + node_variant_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_variant_static_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename node<Value, Parameters, Box, allocators, node_variant_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, + variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_variant_node< + typename Allocators::node_pointer, + variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> + >::apply(allocators.node_allocator()); + } +}; + +template <typename Allocators, typename Value, typename Parameters, typename Box> +struct create_node< + Allocators, + variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_variant_node< + typename Allocators::node_pointer, + variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> + >::apply(allocators.node_allocator()); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP diff --git a/boost/geometry/index/detail/rtree/node/variant_visitor.hpp b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp new file mode 100644 index 0000000000..ffd67039d2 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry Index +// +// R-tree nodes static visitor related code +// +// Copyright (c) 2011-2014 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_VARIANT_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_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 variant_internal_node; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct variant_leaf; + +// nodes conversion + +template <typename V, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline V & get( + boost::variant< + variant_leaf<Value, Parameters, Box, Allocators, Tag>, + variant_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< + variant_leaf<Value, Parameters, Box, Allocators, Tag>, + variant_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< + variant_leaf<Value, Parameters, Box, Allocators, Tag>, + variant_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_VARIANT_VISITOR_HPP diff --git a/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp new file mode 100644 index 0000000000..b828b35f45 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp @@ -0,0 +1,294 @@ +// Boost.Geometry Index +// +// R-tree nodes based on static conversion, storing dynamic-size containers +// +// Copyright (c) 2011-2014 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_WEAK_DYNAMIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_internal_node + : public weak_node<Value, Parameters, Box, Allocators, Tag> +{ + typedef boost::container::vector + < + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + typename Allocators::internal_node_allocator_type::template rebind + < + rtree::ptr_pair<Box, typename Allocators::node_pointer> + >::other + > elements_type; + + template <typename Al> + inline weak_internal_node(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_leaf + : public weak_node<Value, Parameters, Box, Allocators, Tag> +{ + typedef boost::container::vector + < + Value, + typename Allocators::leaf_allocator_type::template rebind + < + Value + >::other + > elements_type; + + template <typename Al> + inline weak_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_weak_dynamic_tag> +{ + typedef weak_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> +{ + typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> +{ + typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type; +}; + +// visitor traits + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst> +{ + typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag> + : public Allocator::template rebind< + typename internal_node< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>, + node_weak_dynamic_tag + >::type + >::other + , public Allocator::template rebind< + typename leaf< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>, + node_weak_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_weak_dynamic_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf<Value, Parameters, Box, allocators, node_weak_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_weak_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_weak_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, + weak_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_weak_node< + typename Allocators::node_pointer, + weak_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, + weak_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_weak_node< + typename Allocators::node_pointer, + weak_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, + weak_internal_node<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_weak_node< + weak_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, + weak_leaf<Value, Parameters, Box, Allocators, Tag> +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_weak_node< + weak_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_WEAK_DYNAMIC_HPP diff --git a/boost/geometry/index/detail/rtree/node/weak_static.hpp b/boost/geometry/index/detail/rtree/node/weak_static.hpp new file mode 100644 index 0000000000..632e35678a --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/weak_static.hpp @@ -0,0 +1,174 @@ +// Boost.Geometry Index +// +// R-tree nodes based on static conversion, storing static-size containers +// +// Copyright (c) 2011-2014 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_WEAK_STATIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag> + : public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag> +{ + typedef detail::varray< + rtree::ptr_pair<Box, typename Allocators::node_pointer>, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline weak_internal_node(Alloc const&) {} + + elements_type elements; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag> + : public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag> +{ + typedef detail::varray< + Value, + Parameters::max_elements + 1 + > elements_type; + + template <typename Alloc> + inline weak_leaf(Alloc const&) {} + + elements_type elements; +}; + +// nodes traits + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct node<Value, Parameters, Box, Allocators, node_weak_static_tag> +{ + typedef weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag> +{ + typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators> +struct leaf<Value, Parameters, Box, Allocators, node_weak_static_tag> +{ + typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag> type; +}; + +template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst> +struct visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst> +{ + typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst> type; +}; + +// allocators + +template <typename Allocator, typename Value, typename Parameters, typename Box> +class allocators<Allocator, Value, Parameters, Box, node_weak_static_tag> + : public Allocator::template rebind< + typename internal_node< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>, + node_weak_static_tag + >::type + >::other + , public Allocator::template rebind< + typename leaf< + Value, Parameters, Box, + allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>, + node_weak_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_weak_static_tag>::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node<Value, Parameters, Box, allocators, node_weak_static_tag>::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf<Value, Parameters, Box, allocators, node_weak_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_WEAK_STATIC_HPP diff --git a/boost/geometry/index/detail/rtree/node/weak_visitor.hpp b/boost/geometry/index/detail/rtree/node/weak_visitor.hpp new file mode 100644 index 0000000000..08d84778e6 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/weak_visitor.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry Index +// +// R-tree nodes weak visitor and nodes base type +// +// Copyright (c) 2011-2014 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_WEAK_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// empty visitor +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst> +struct weak_visitor {}; + +// node + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_node {}; + +// nodes variants forward declarations + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_internal_node; + +template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +struct weak_leaf; + +// nodes conversion + +template <typename Derived, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline Derived & get(weak_node<Value, Parameters, Box, Allocators, Tag> & n) +{ + return static_cast<Derived&>(n); +} + +// apply visitor + +template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag> +inline void apply_visitor(Visitor & v, + weak_node<Value, Parameters, Box, Allocators, Tag> & n, + bool is_internal_node) +{ + BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); + if ( is_internal_node ) + { + typedef weak_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node; + v(get<internal_node>(n)); + } + else + { + typedef weak_leaf<Value, Parameters, Box, Allocators, Tag> leaf; + v(get<leaf>(n)); + } +} + +}} // 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/options.hpp b/boost/geometry/index/detail/rtree/options.hpp new file mode 100644 index 0000000000..ff772834d7 --- /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-2014 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_variant_dynamic_tag {}; +struct node_variant_static_tag {}; +//struct node_weak_dynamic_tag {}; +//struct node_weak_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_variant_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_variant_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_variant_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_variant_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_variant_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_variant_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_variant_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 0000000000..46bf357fc4 --- /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-2014 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 nth_element_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::nth_element(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 + nth_element_and_half_boxes<I+1, Dimension>::apply(first, median, last, box, left, right, dim_index); + } +}; + +template <std::size_t Dimension> +struct nth_element_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 geometry::point_type<Box>::type point_type; + typedef typename geometry::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 = geometry::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::nth_element_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) + { + boost::ignore_unused_variable_warning(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 0000000000..837ddbeecb --- /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 0000000000..634d879864 --- /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-2014 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/bounded_view.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 Box, typename Elements, typename Parameters, typename Translator> +inline void pick_seeds(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; + typedef Box box_type; + typedef typename index::detail::default_content_result<box_type>::type content_type; + typedef index::detail::bounded_view<indexable_type, box_type> bounded_indexable_view; + + 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); + + bounded_indexable_view bounded_ind1(ind1); + bounded_indexable_view bounded_ind2(ind2); + content_type free_content = ( index::detail::content(enlarged_box) + - index::detail::content(bounded_ind1) ) + - index::detail::content(bounded_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; + + 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 - use in-memory storage (std::allocator) + // TODO: move if noexcept + typedef typename rtree::container_from_elements_type<elements_type, element_type>::type + container_type; + container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy) + container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + quadratic::pick_seeds<Box>(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 container_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 container_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 0000000000..8366fca191 --- /dev/null +++ b/boost/geometry/index/detail/rtree/query_iterators.hpp @@ -0,0 +1,599 @@ +// 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 + +#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL +//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION +//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE +//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { + +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 const& /*l*/, end_query_iterator const& /*r*/) + { + return true; + } +}; + +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) + { + m_visitor.initialize(root); + } + + 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> const& /*r*/) + { + return l.m_visitor.is_end(); + } + + friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, 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) + { + m_visitor.initialize(root); + } + + 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> const& /*r*/) + { + return l.m_visitor.is_end(); + } + + friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, distance_query_iterator const& r) + { + return r.m_visitor.is_end(); + } + +private: + visitor_type m_visitor; +}; + +template <typename L, typename R> +inline bool operator!=(L const& l, R const& r) +{ + return !(l == r); +} + +}}}}}} // namespace boost::geometry::index::detail::rtree::iterators + +#if defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL) || defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION) + +#if defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL) + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { + +template <typename Value, typename Allocators> +class query_iterator_base +{ +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; + + virtual ~query_iterator_base() {} + + virtual query_iterator_base * clone() const = 0; + + virtual bool is_end() const = 0; + virtual reference dereference() const = 0; + virtual void increment() = 0; + virtual bool equals(query_iterator_base const&) const = 0; +}; + +template <typename Value, typename Allocators, typename Iterator> +class query_iterator_wrapper + : public query_iterator_base<Value, Allocators> +{ + typedef query_iterator_base<Value, Allocators> base_t; + +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; + + explicit query_iterator_wrapper(Iterator const& it) : m_iterator(it) {} + + virtual base_t * clone() const { return new query_iterator_wrapper(m_iterator); } + + virtual bool is_end() const { return m_iterator == end_query_iterator<Value, Allocators>(); } + virtual reference dereference() const { return *m_iterator; } + virtual void increment() { ++m_iterator; } + virtual bool equals(base_t const& r) const + { + const query_iterator_wrapper * p = dynamic_cast<const query_iterator_wrapper *>(boost::addressof(r)); + BOOST_ASSERT_MSG(p, "those iterators can't be compared"); + return m_iterator == p->m_iterator; + } + +private: + Iterator m_iterator; +}; + +#elif defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION) + +#include <boost/function.hpp> +#include <boost/bind.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { + +template <typename Value, typename Allocators> +class query_iterator_base +{ +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; + + virtual ~query_iterator_base() {} + + boost::function<query_iterator_base*()> clone; + boost::function<bool()> is_end; + boost::function<reference()> dereference; + boost::function<void()> increment; + boost::function<bool(query_iterator_base const&)> equals; +}; + +template <typename Value, typename Allocators, typename Iterator> +class query_iterator_wrapper + : public query_iterator_base<Value, Allocators> +{ + typedef query_iterator_base<Value, Allocators> base_t; + +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; + + explicit query_iterator_wrapper(Iterator const& it) + : m_iterator(it) + { + base_t::clone = boost::bind(&query_iterator_wrapper::clone_, this); + base_t::is_end = boost::bind(&query_iterator_wrapper::is_end_, this); + base_t::dereference = boost::bind(&query_iterator_wrapper::dereference_, this); + base_t::increment = boost::bind(&query_iterator_wrapper::increment_, this); + base_t::equals = boost::bind(&query_iterator_wrapper::equals_, this, _1); + } + +private: + base_t * clone_() const { return new query_iterator_wrapper(m_iterator); } + + bool is_end_() const { return m_iterator == end_query_iterator<Value, Allocators>(); } + reference dereference_() const { return *m_iterator; } + void increment_() { ++m_iterator; } + bool equals_(base_t const& r) const + { + const query_iterator_wrapper * p = dynamic_cast<const query_iterator_wrapper *>(boost::addressof(r)); + BOOST_ASSERT_MSG(p, "those iterators can't be compared"); + return m_iterator == p->m_iterator; + } + +private: + Iterator m_iterator; +}; + +#endif + +template <typename Value, typename Allocators> +class query_iterator +{ + typedef query_iterator_base<Value, Allocators> iterator_base; + typedef std::auto_ptr<iterator_base> iterator_ptr; + +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; + + query_iterator() {} + + template <typename It> + query_iterator(It const& it) + : m_ptr(static_cast<iterator_base*>( + new query_iterator_wrapper<Value, Allocators, It>(it) )) + {} + + query_iterator(end_query_iterator<Value, Allocators> const& /*it*/) + {} + + query_iterator(query_iterator const& o) + : m_ptr(o.m_ptr.get() ? o.m_ptr->clone() : 0) + {} + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE + query_iterator & operator=(query_iterator const& o) + { + m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0); + return *this; + } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + query_iterator(query_iterator && o) + : m_ptr(o.m_ptr.get()) + { + o.m_ptr.release(); + } + query_iterator & operator=(query_iterator && o) + { + if ( this != boost::addressof(o) ) + { + m_ptr.reset(o.m_ptr.get()); + o.m_ptr.release(); + } + return *this; + } +#endif +#else // !BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE +private: + BOOST_COPYABLE_AND_MOVABLE(query_iterator) +public: + query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o) + { + m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0); + return *this; + } + query_iterator(BOOST_RV_REF(query_iterator) o) + : m_ptr(o.m_ptr.get()) + { + o.m_ptr.release(); + } + query_iterator & operator=(BOOST_RV_REF(query_iterator) o) + { + if ( this != boost::addressof(o) ) + { + m_ptr.reset(o.m_ptr.get()); + o.m_ptr.release(); + } + return *this; + } +#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE + + reference operator*() const + { + return m_ptr->dereference(); + } + + const value_type * operator->() const + { + return boost::addressof(m_ptr->dereference()); + } + + query_iterator & operator++() + { + m_ptr->increment(); + return *this; + } + + query_iterator operator++(int) + { + query_iterator temp = *this; + this->operator++(); + return temp; + } + + friend bool operator==(query_iterator const& l, query_iterator const& r) + { + if ( l.m_ptr.get() ) + { + if ( r.m_ptr.get() ) + return l.m_ptr->equals(*r.m_ptr); + else + return l.m_ptr->is_end(); + } + else + { + if ( r.m_ptr.get() ) + return r.m_ptr->is_end(); + else + return true; + } + } + +private: + iterator_ptr m_ptr; +}; + +}}}}}} // namespace boost::geometry::index::detail::rtree::iterators + +#elif defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE) + +#include <boost/type_erasure/any.hpp> +#include <boost/type_erasure/operators.hpp> +#include <boost/type_erasure/is_empty.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { + +template<typename T, typename Value, typename Allocators> +struct single_pass_iterator_concept : + ::boost::mpl::vector< + ::boost::type_erasure::copy_constructible<T>, + ::boost::type_erasure::equality_comparable<T>, + ::boost::type_erasure::dereferenceable<typename Allocators::const_reference, T>, + ::boost::type_erasure::assignable<T>, + ::boost::type_erasure::incrementable<T>, + ::boost::type_erasure::equality_comparable<T, end_query_iterator<Value, Allocators> >, + ::boost::type_erasure::relaxed // default ctor + > +{}; + +template <typename Value, typename Allocators> +struct single_pass_iterator_type +{ + typedef ::boost::type_erasure::any< + single_pass_iterator_concept< + ::boost::type_erasure::_self, Value, Allocators + > + > type; +}; + +}}}}}} // namespace boost::geometry::index::detail::rtree::iterators + +namespace boost { namespace type_erasure { + +template<typename T, typename Value, typename Allocators, typename Base> +struct concept_interface< + ::boost::geometry::index::detail::rtree::single_pass_iterator_concept< + T, Value, Allocators + >, Base, T> + : Base +{ + typedef Value value_type; + typedef typename Allocators::const_reference reference; + typedef typename Allocators::const_pointer pointer; + typedef typename Allocators::difference_type difference_type; + typedef ::std::input_iterator_tag iterator_category; +}; + +}} // boost::type_erasure + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { + +template <typename Value, typename Allocators> +class query_iterator +{ +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; + +private: + typedef typename rtree::single_pass_iterator_type<Value, Allocators>::type iterator_type; + +public: + + query_iterator() {} + + template <typename It> + query_iterator(It const& it) + : m_iterator(it) + {} + + query_iterator(end_query_iterator<Value, Allocators> const& /*it*/) + {} + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE +private: + BOOST_COPYABLE_AND_MOVABLE(query_iterator) +public: + query_iterator(query_iterator const& o) + : m_iterator(o.m_iterator) + {} + query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o) + { + m_iterator = o.m_iterator; + return *this; + } + query_iterator(BOOST_RV_REF(query_iterator) o) + : m_iterator(boost::move(o.m_iterator)) + {} + query_iterator & operator=(BOOST_RV_REF(query_iterator) o) + { + if ( this != boost::addressof(o) ) + { + m_iterator = boost::move(o.m_iterator); + } + return *this; + } +#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE + + reference operator*() const + { + return *m_iterator; + } + + const value_type * operator->() const + { + return boost::addressof(*m_iterator); + } + + query_iterator & operator++() + { + ++m_iterator; + return *this; + } + + query_iterator operator++(int) + { + query_iterator temp = *this; + ++m_iterator; + return temp; + } + + friend bool operator==(query_iterator const& l, query_iterator const& r) + { + if ( !::boost::type_erasure::is_empty(l.m_iterator) ) + { + if ( !::boost::type_erasure::is_empty(r.m_iterator) ) + return l.m_iterator == r.m_iterator; + else + return l.m_iterator == end_query_iterator<Value, Allocators>(); + } + else + { + if ( !::boost::type_erasure::is_empty(r.m_iterator) ) + return r.m_iterator == end_query_iterator<Value, Allocators>(); + else + return true; + } + } + +private: + iterator_type m_iterator; +}; + +}}}}}} // namespace boost::geometry::index::detail::rtree::iterators + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE + +#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 0000000000..7a96986a27 --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp @@ -0,0 +1,233 @@ +// Boost.Geometry Index +// +// R-tree R*-tree next node choosing algorithm implementation +// +// Copyright (c) 2011-2014 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 ) + { + 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 ) + { + size_t first_n_children_count = children_count; + if ( 0 < overlap_cost_threshold && overlap_cost_threshold < children.size() ) + { + first_n_children_count = overlap_cost_threshold; + // rearrange by content_diff + // in order to calculate nearly minimum overlap cost + std::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less); + } + + // calculate minimum or nearly minimum overlap cost + choosen_index = choose_by_minimum_overlap_cost_first_n(children, indexable, first_n_children_count, children_count, children_contents); + } + + 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, typename ChildrenContents> + static inline size_t choose_by_minimum_overlap_cost_first_n(children_type const& children, + Indexable const& indexable, + size_t const first_n_children_count, + size_t const children_count, + ChildrenContents const& children_contents) + { + BOOST_GEOMETRY_INDEX_ASSERT(first_n_children_count <= children_count, "unexpected value"); + 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 < first_n_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> + 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 0000000000..e544d6dd1e --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/insert.hpp @@ -0,0 +1,577 @@ +// Boost.Geometry Index +// +// R-tree R*-tree insert algorithm implementation +// +// Copyright (c) 2011-2014 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; + typedef internal_node * 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_comparable_distance_result<point_type>::type + comparable_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<comparable_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<comparable_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; + typedef typename Allocators::size_type size_type; + + inline level_insert_base(node_pointer & root, + size_type & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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_type 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; + typedef typename Allocators::size_type size_type; + + inline level_insert(node_pointer & root, + size_type & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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; + typedef typename Allocators::size_type size_type; + + inline level_insert(node_pointer & root, + size_type & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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; + typedef typename Allocators::size_type size_type; + + inline level_insert(node_pointer & root, + size_type & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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; + typedef typename Allocators::size_type size_type; + +public: + inline insert(node_pointer & root, + size_type & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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_type & m_leafs_level; + Element const& m_element; + + parameters_type const& m_parameters; + Translator const& m_translator; + + size_type 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 0000000000..8f270537fb --- /dev/null +++ b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp @@ -0,0 +1,468 @@ +// Boost.Geometry Index +// +// R-tree R*-tree split algorithm implementation +// +// Copyright (c) 2011-2014 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/bounded_view.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 +{ + typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type; + typedef typename geometry::point_type<indexable_type>::type point_type; + typedef geometry::model::box<point_type> bounds_type; + typedef index::detail::bounded_view<indexable_type, bounds_type> bounded_view_type; + +public: + element_axis_corner_less(Translator const& tr) + : m_tr(tr) + {} + + bool operator()(Element const& e1, Element const& e2) const + { + bounded_view_type bounded_ind1(rtree::element_indexable(e1, m_tr)); + bounded_view_type bounded_ind2(rtree::element_indexable(e2, m_tr)); + + return geometry::get<Corner, AxisIndex>(bounded_ind1) + < geometry::get<Corner, AxisIndex>(bounded_ind2); + } + +private: + Translator const& m_tr; +}; + +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 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 Parameters, 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) + + size_t const index_first = parameters.get_min_elements(); + size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2; + + // 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) +// { +// typename Elements::iterator f = elements_copy.begin() + index_first; +// typename Elements::iterator l = elements_copy.begin() + index_last; +// std::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) +// std::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) +// std::sort(f, l, elements_less); // MAY THROW, BASIC (copy) +// } + + // init outputs + choosen_index = index_first; + 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 + for ( size_t i = index_first ; 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 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 Box, size_t AxisIndex, typename ElementIndexableTag> +struct choose_split_axis_and_index_for_axis +{ + 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 Parameters, 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<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<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 Box, size_t AxisIndex> +struct choose_split_axis_and_index_for_axis<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 Parameters, 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<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 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 Parameters, 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<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< + 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 Box> +struct choose_split_axis_and_index<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 Parameters, 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< + 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, size_t I = 0> +struct nth_element +{ + BOOST_STATIC_ASSERT(0 < Dimension); + BOOST_STATIC_ASSERT(I < Dimension); + + template <typename Elements, typename Translator> + static inline void apply(Elements & elements, const size_t axis, const size_t index, Translator const& tr) + { + //BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value"); + + if ( axis != I ) + { + nth_element<Corner, Dimension, I + 1>::apply(elements, axis, index, tr); // MAY THROW, BASIC (copy) + } + else + { + 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, I> less(tr); + std::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + } + } +}; + +template <size_t Corner, size_t Dimension> +struct nth_element<Corner, Dimension, Dimension> +{ + template <typename Elements, typename Translator> + static inline void apply(Elements & /*elements*/, const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/) + {} +}; + +} // 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; + typedef typename elements_type::value_type element_type; + + elements_type & elements1 = rtree::elements(n); + elements_type & elements2 = rtree::elements(second_node); + + // copy original elements - use in-memory storage (std::allocator) + // TODO: move if noexcept + typedef typename rtree::container_from_elements_type<elements_type, element_type>::type + container_type; + container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG + container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG + + 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)(); + + // NOTE: this function internally copies passed elements + // why not pass mutable elements and use the same container for all axes/corners + // and again, the same below calling partial_sort/nth_element + // It would be even possible to not re-sort/find nth_element if the axis/corner + // was found for the last sorting - last combination of axis/corner + rstar::choose_split_axis_and_index<Box, dimension> + ::apply(elements_copy, + 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"); + + // TODO: consider using nth_element + if ( split_corner == static_cast<size_t>(min_corner) ) + { + rstar::nth_element<min_corner, dimension> + ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy) + } + else + { + rstar::nth_element<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 0000000000..ed3959c89d --- /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 0000000000..d2caa36707 --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp @@ -0,0 +1,142 @@ +// Boost.Geometry Index +// +// R-tree boxes validating visitor implementation +// +// Copyright (c) 2011-2014 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( + index::detail::return_ref_or_bounds(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 0000000000..4860dbcb9b --- /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 0000000000..84201b6afe --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp @@ -0,0 +1,243 @@ +// 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 + +#include <boost/mpl/assert.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) + { + typename coordinate_type<Point>::type const& x = geometry::get<0>(p); + typename coordinate_type<Point>::type const& y = geometry::get<1>(p); + /*glBegin(GL_POINT); + glVertex3f(x, y, z); + glEnd();*/ + glBegin(GL_QUADS); + glVertex3f(x+1, y, z); + glVertex3f(x, y+1, z); + glVertex3f(x-1, y, z); + glVertex3f(x, y-1, 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 Segment, size_t Dimension> +struct gl_draw_segment +{}; + +template <typename Segment> +struct gl_draw_segment<Segment, 2> +{ + static inline void apply(Segment const& s, typename coordinate_type<Segment>::type z) + { + glBegin(GL_LINES); + glVertex3f(geometry::get<0, 0>(s), geometry::get<0, 1>(s), z); + glVertex3f(geometry::get<1, 0>(s), geometry::get<1, 1>(s), z); + glEnd(); + } +}; + +template <typename Indexable, typename Tag> +struct gl_draw_indexable +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag)); +}; + +template <typename Box> +struct gl_draw_indexable<Box, box_tag> + : gl_draw_box<Box, geometry::dimension<Box>::value> +{}; + +template <typename Point> +struct gl_draw_indexable<Point, point_tag> + : gl_draw_point<Point, geometry::dimension<Point>::value> +{}; + +template <typename Segment> +struct gl_draw_indexable<Segment, segment_tag> + : gl_draw_segment<Segment, geometry::dimension<Segment>::value> +{}; + +} // 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 0000000000..4c42659c64 --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/print.hpp @@ -0,0 +1,219 @@ +// 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 +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag)); +}; + +template <typename Indexable> +struct print_indexable<Indexable, box_tag> +{ + static const size_t dimension = geometry::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 = geometry::dimension<Indexable>::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_point<Indexable, dimension>::apply(os, i); + os << ')'; + } +}; + +template <typename Indexable> +struct print_indexable<Indexable, segment_tag> +{ + static const size_t dimension = geometry::dimension<Indexable>::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_corner<Indexable, 0, dimension>::apply(os, i); + os << ")-("; + print_corner<Indexable, 1, 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 0000000000..bbaed8100e --- /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 <boost/tuple/tuple.hpp> + +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 0000000000..6dbbd07bfe --- /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 0000000000..93726063b4 --- /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 0000000000..8fc25ac803 --- /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 0000000000..7efd5b7028 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/count.hpp @@ -0,0 +1,107 @@ +// Boost.Geometry Index +// +// R-tree count visitor implementation +// +// Copyright (c) 2011-2014 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> +struct count_helper +{ + template <typename Translator> + static inline typename Translator::result_type indexable(Indexable const& i, Translator const&) + { + return i; + } + template <typename Translator> + static inline bool equals(Indexable const& i, Value const& v, Translator const& tr) + { + return geometry::equals(i, tr(v)); + } +}; + +template <typename Value> +struct count_helper<Value, Value> +{ + template <typename Translator> + static inline typename Translator::result_type indexable(Value const& v, Translator const& tr) + { + return tr(v); + } + template <typename Translator> + static inline bool equals(Value const& v1, Value const& v2, Translator const& tr) + { + return tr.equals(v1, v2); + } +}; + +template <typename ValueOrIndexable, 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; + + typedef count_helper<ValueOrIndexable, Value> count_help; + + inline count(ValueOrIndexable const& vori, Translator const& t) + : value_or_indexable(vori), 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( + return_ref_or_bounds( + count_help::indexable(value_or_indexable, tr)), + 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 ( count_help::equals(value_or_indexable, *it, tr) ) + { + ++found_count; + } + } + } + + ValueOrIndexable const& value_or_indexable; + 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 0000000000..62722b97a8 --- /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 0000000000..342cc4bbc3 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -0,0 +1,580 @@ +// Boost.Geometry Index +// +// R-tree distance (knn, path, etc. ) query visitor implementation +// +// Copyright (c) 2011-2014 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)); + } + + // ALTERNATIVE VERSION - use heap instead of sorted container + // It seems to be faster for greater MaxElements and slower otherwise + // CONSIDER: using one global container/heap for active branches + // instead of a sorted container per level + // This would also change the way how branches are traversed! + // The same may be applied to the iterative version which btw suffers + // from the copying of the whole containers on resize of the ABLs container + + //// make a heap + //std::make_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater); + + //// recursively visit nodes + //while ( !active_branch_list.empty() ) + //{ + // //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(), active_branch_list.front().first) ) + // { + // break; + // } + + // rtree::apply_visitor(*this, *(active_branch_list.front().second)); + + // std::pop_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater); + // active_branch_list.pop_back(); + //} + } + + 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; + } + + //static inline bool abl_greater( + // 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 initialize(node_pointer root) + { + rtree::apply_visitor(*this, *root); + increment(); + } + + 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 0000000000..388b3193f6 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/insert.hpp @@ -0,0 +1,527 @@ +// 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, typename SizeType> +struct insert_traverse_data +{ + typedef typename rtree::elements_type<InternalNode>::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename elements_type::size_type elements_size_type; + typedef SizeType size_type; + + insert_traverse_data() + : parent(0), current_child_index(0), current_level(0) + {} + + void move_to_next_level(InternalNodePtr new_parent, + elements_size_type 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; + elements_size_type current_child_index; + size_type 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::size_type size_type; + + //typedef typename Allocators::internal_node_pointer internal_node_pointer; + typedef internal_node * internal_node_pointer; + + inline insert(node_pointer & root, + size_type & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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() ) + { + // NOTE: If the exception is thrown current node may contain more than MAX elements or be empty. + // Furthermore it may be empty root - internal node. + 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, size_type> + 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; + size_type const m_relative_level; + size_type const m_level; + + node_pointer & m_root_node; + size_type & m_leafs_level; + + // traversing input parameters + insert_traverse_data<internal_node, internal_node_pointer, size_type> 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; + typedef typename base::size_type size_type; + + inline insert(node_pointer & root, + size_type & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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; + typedef typename base::size_type size_type; + + inline insert(node_pointer & root, + size_type & leafs_level, + Value const& value, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_type 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 0000000000..6d21afd99e --- /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 0000000000..d4890a368b --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/remove.hpp @@ -0,0 +1,326 @@ +// Boost.Geometry Index +// +// R-tree removing visitor implementation +// +// Copyright (c) 2011-2014 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::size_type size_type; + + typedef typename rtree::elements_type<internal_node>::type::size_type internal_size_type; + + //typedef typename Allocators::internal_node_pointer internal_node_pointer; + typedef internal_node * internal_node_pointer; + +public: + inline remove(node_pointer & root, + size_type & 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 + internal_size_type child_node_index = 0; + for ( ; child_node_index < children.size() ; ++child_node_index ) + { + if ( geometry::covered_by( + return_ref_or_bounds(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_type 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_type, node_pointer> > UnderflowNodes; + + void traverse_apply_visitor(internal_node &n, internal_size_type choosen_node_index) + { + // save previous traverse inputs and set new ones + internal_node_pointer parent_bckup = m_parent; + internal_size_type current_child_index_bckup = m_current_child_index; + size_type 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_type 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 + { + // NOTE: those are elements of the internal node which means that copy/move shouldn't throw + // Though it's safer in case if the pointer type could throw in copy ctor. + // In the future this try-catch block could be removed. + 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_type 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_type & m_leafs_level; + + bool m_is_value_removed; + UnderflowNodes m_underflowed_nodes; + + // traversing input parameters + internal_node_pointer m_parent; + internal_size_type m_current_child_index; + size_type 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 0000000000..0a43111ac4 --- /dev/null +++ b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -0,0 +1,206 @@ +// 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(); + } + + const_reference dereference() const + { + BOOST_ASSERT_MSG(m_values, "not dereferencable"); + return *m_current; + } + + void initialize(node_pointer root) + { + rtree::apply_visitor(*this, *root); + search_value(); + } + + void increment() + { + ++m_current; + search_value(); + } + + void search_value() + { + for (;;) + { + // if leaf is choosen, move to the next value in leaf + if ( m_values ) + { + if ( m_current != m_values->end() ) + { + // 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; +}; + +}}} // 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/serialization.hpp b/boost/geometry/index/detail/serialization.hpp new file mode 100644 index 0000000000..34036e3904 --- /dev/null +++ b/boost/geometry/index/detail/serialization.hpp @@ -0,0 +1,585 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2014 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_SERIALIZATION_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP + +//#include <boost/serialization/serialization.hpp> +#include <boost/serialization/split_member.hpp> +#include <boost/serialization/version.hpp> +//#include <boost/serialization/nvp.hpp> + +// TODO +// how about using the unsigned type capable of storing Max in compile-time versions? + +// TODO +// - add wrappers for Point and Box and implement serialize for those wrappers instead of +// raw geometries +// PROBLEM: after implementing this, how Values would be set? +// - store the name of the parameters to know how to load and detect errors +// - in the header, once store info about the Indexable and Bounds types (geometry type, point CS, Dim, etc.) +// each geometry save without this info + +// TODO - move to index/detail/serialization.hpp +namespace boost { namespace geometry { namespace index { namespace detail { + +// TODO - use boost::move? +template<typename T> +class serialization_storage +{ +public: + template <typename Archive> + serialization_storage(Archive & ar, unsigned int version) + { + boost::serialization::load_construct_data_adl(ar, this->address(), version); + } + ~serialization_storage() + { + this->address()->~T(); + } + T * address() + { + return static_cast<T*>(m_storage.address()); + } +private: + boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value> m_storage; +}; + +// TODO - save and load item_version? see: collections_load_imp and collections_save_imp +// this should be done once for the whole container +// versions of all used types should be stored + +template <typename T, typename Archive> inline +T serialization_load(const char * name, Archive & ar) +{ + namespace bs = boost::serialization; + serialization_storage<T> storage(ar, bs::version<T>::value); // load_construct_data + ar >> boost::serialization::make_nvp(name, *storage.address()); // serialize + //ar >> *storage.address(); // serialize + return *storage.address(); +} + +template <typename T, typename Archive> inline +void serialization_save(T const& t, const char * name, Archive & ar) +{ + namespace bs = boost::serialization; + bs::save_construct_data_adl(ar, boost::addressof(t), bs::version<T>::value); // save_construct_data + ar << boost::serialization::make_nvp(name, t); // serialize + //ar << t; // serialize +} + +}}}} + +// TODO - move to index/serialization/rtree.hpp +namespace boost { namespace serialization { + +// boost::geometry::index::linear + +template<class Archive, size_t Max, size_t Min> +void save_construct_data(Archive & ar, const boost::geometry::index::linear<Max, Min> * params, unsigned int ) +{ + size_t max = params->get_max_elements(), min = params->get_min_elements(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); +} +template<class Archive, size_t Max, size_t Min> +void load_construct_data(Archive & ar, boost::geometry::index::linear<Max, Min> * params, unsigned int ) +{ + size_t max, min; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + if ( max != params->get_max_elements() || min != params->get_min_elements() ) + // TODO change exception type + BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); + // the constructor musn't be called for this type + //::new(params)boost::geometry::index::linear<Max, Min>(); +} +template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::linear<Max, Min> &, unsigned int) {} + +// boost::geometry::index::quadratic + +template<class Archive, size_t Max, size_t Min> +void save_construct_data(Archive & ar, const boost::geometry::index::quadratic<Max, Min> * params, unsigned int ) +{ + size_t max = params->get_max_elements(), min = params->get_min_elements(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); +} +template<class Archive, size_t Max, size_t Min> +void load_construct_data(Archive & ar, boost::geometry::index::quadratic<Max, Min> * params, unsigned int ) +{ + size_t max, min; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + if ( max != params->get_max_elements() || min != params->get_min_elements() ) + // TODO change exception type + BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); + // the constructor musn't be called for this type + //::new(params)boost::geometry::index::quadratic<Max, Min>(); +} +template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::quadratic<Max, Min> &, unsigned int) {} + +// boost::geometry::index::rstar + +template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT> +void save_construct_data(Archive & ar, const boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int ) +{ + size_t max = params->get_max_elements() + , min = params->get_min_elements() + , re = params->get_reinserted_elements() + , oct = params->get_overlap_cost_threshold(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); + ar << boost::serialization::make_nvp("re", re); + ar << boost::serialization::make_nvp("oct", oct); +} +template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT> +void load_construct_data(Archive & ar, boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int ) +{ + size_t max, min, re, oct; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + ar >> boost::serialization::make_nvp("re", re); + ar >> boost::serialization::make_nvp("oct", oct); + if ( max != params->get_max_elements() || min != params->get_min_elements() || + re != params->get_reinserted_elements() || oct != params->get_overlap_cost_threshold() ) + // TODO change exception type + BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); + // the constructor musn't be called for this type + //::new(params)boost::geometry::index::rstar<Max, Min, RE, OCT>(); +} +template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT> +void serialize(Archive &, boost::geometry::index::rstar<Max, Min, RE, OCT> &, unsigned int) {} + +// boost::geometry::index::dynamic_linear + +template<class Archive> +inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_linear * params, unsigned int ) +{ + size_t max = params->get_max_elements(), min = params->get_min_elements(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); +} +template<class Archive> +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int ) +{ + size_t max, min; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + ::new(params)boost::geometry::index::dynamic_linear(max, min); +} +template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_linear &, unsigned int) {} + +// boost::geometry::index::dynamic_quadratic + +template<class Archive> +inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_quadratic * params, unsigned int ) +{ + size_t max = params->get_max_elements(), min = params->get_min_elements(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); +} +template<class Archive> +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int ) +{ + size_t max, min; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + ::new(params)boost::geometry::index::dynamic_quadratic(max, min); +} +template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_quadratic &, unsigned int) {} + +// boost::geometry::index::dynamic_rstar + +template<class Archive> +inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_rstar * params, unsigned int ) +{ + size_t max = params->get_max_elements() + , min = params->get_min_elements() + , re = params->get_reinserted_elements() + , oct = params->get_overlap_cost_threshold(); + ar << boost::serialization::make_nvp("max", max); + ar << boost::serialization::make_nvp("min", min); + ar << boost::serialization::make_nvp("re", re); + ar << boost::serialization::make_nvp("oct", oct); +} +template<class Archive> +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int ) +{ + size_t max, min, re, oct; + ar >> boost::serialization::make_nvp("max", max); + ar >> boost::serialization::make_nvp("min", min); + ar >> boost::serialization::make_nvp("re", re); + ar >> boost::serialization::make_nvp("oct", oct); + ::new(params)boost::geometry::index::dynamic_rstar(max, min, re, oct); +} +template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_rstar &, unsigned int) {} + +}} // boost::serialization + +// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename P, size_t I = 0, size_t D = geometry::dimension<P>::value> +struct serialize_point +{ + template <typename Archive> + static inline void save(Archive & ar, P const& p, unsigned int version) + { + typename coordinate_type<P>::type c = get<I>(p); + ar << boost::serialization::make_nvp("c", c); + serialize_point<P, I+1, D>::save(ar, p, version); + } + + template <typename Archive> + static inline void load(Archive & ar, P & p, unsigned int version) + { + typename geometry::coordinate_type<P>::type c; + ar >> boost::serialization::make_nvp("c", c); + set<I>(p, c); + serialize_point<P, I+1, D>::load(ar, p, version); + } +}; + +template <typename P, size_t D> +struct serialize_point<P, D, D> +{ + template <typename Archive> static inline void save(Archive &, P const&, unsigned int) {} + template <typename Archive> static inline void load(Archive &, P &, unsigned int) {} +}; + +}}}} + +// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp +namespace boost { namespace serialization { + +template<class Archive, typename T, size_t D, typename C> +void save(Archive & ar, boost::geometry::model::point<T, D, C> const& p, unsigned int version) +{ + boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::save(ar, p, version); +} +template<class Archive, typename T, size_t D, typename C> +void load(Archive & ar, boost::geometry::model::point<T, D, C> & p, unsigned int version) +{ + boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::load(ar, p, version); +} +template<class Archive, typename T, size_t D, typename C> +inline void serialize(Archive & ar, boost::geometry::model::point<T, D, C> & o, const unsigned int version) { split_free(ar, o, version); } + +template<class Archive, typename P> +inline void serialize(Archive & ar, boost::geometry::model::box<P> & b, const unsigned int) +{ + ar & boost::serialization::make_nvp("min", b.min_corner()); + ar & boost::serialization::make_nvp("max", b.max_corner()); +} + +}} // boost::serialization + +// TODO - move to index/detail/rtree/visitors/save.hpp +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { + +// TODO move saving and loading of the rtree outside the rtree, this will require adding some kind of members_view + +template <typename Archive, typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class save + : 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; + + save(Archive & archive, unsigned int version) + : m_archive(archive), m_version(version) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // CONSIDER: change to elements_type::size_type or size_type + // or use fixed-size type like uint32 or even uint16? + size_t s = elements.size(); + m_archive << boost::serialization::make_nvp("s", s); + + for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + { + serialization_save(it->first, "b", m_archive); + + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& l) + { + typedef typename rtree::elements_type<leaf>::type elements_type; + //typedef typename elements_type::size_type elements_size; + elements_type const& elements = rtree::elements(l); + + // CONSIDER: change to elements_type::size_type or size_type + // or use fixed-size type like uint32 or even uint16? + size_t s = elements.size(); + m_archive << boost::serialization::make_nvp("s", s); + + for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + { + serialization_save(*it, "v", m_archive); + } + } + +private: + Archive & m_archive; + unsigned int m_version; +}; + +}}}}}} // boost::geometry::index::detail::rtree::visitors + +// TODO - move to index/detail/rtree/load.hpp +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +template <typename Value, typename Options, typename Translator, typename Box, typename Allocators> +class load +{ + 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::node_pointer node_pointer; + typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr; + typedef typename Allocators::size_type size_type; + +public: + template <typename Archive> inline static + node_pointer apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators) + { + values_count = 0; + return raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators); + } + +private: + template <typename Archive> inline static + node_pointer raw_apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators, size_type current_level = 0) + { + //BOOST_GEOMETRY_INDEX_ASSERT(current_level <= leafs_level, "invalid parameter"); + + typedef typename rtree::elements_type<internal_node>::type elements_type; + typedef typename elements_type::value_type element_type; + //typedef typename elements_type::size_type elements_size; + + // CONSIDER: change to elements_type::size_type or size_type + // or use fixed-size type like uint32 or even uint16? + size_t elements_count; + ar >> boost::serialization::make_nvp("s", elements_count); + + if ( elements_count < parameters.get_min_elements() || parameters.get_max_elements() < elements_count ) + BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error")); + + if ( current_level < leafs_level ) + { + 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); + + elements_type & elements = rtree::elements(in); + + elements.reserve(elements_count); // MAY THROW (A) + + for ( size_t i = 0 ; i < elements_count ; ++i ) + { + typedef typename elements_type::value_type::first_type box_type; + box_type b = serialization_load<box_type>("b", ar); + node_pointer n = raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators, current_level+1); // recursive call + elements.push_back(element_type(b, n)); + } + + auto_remover.release(); + return n; + } + else + { + BOOST_GEOMETRY_INDEX_ASSERT(current_level == leafs_level, "unexpected value"); + + 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); + + typedef typename rtree::elements_type<leaf>::type elements_type; + typedef typename elements_type::value_type element_type; + elements_type & elements = rtree::elements(l); + + values_count += elements_count; + + elements.reserve(elements_count); // MAY THROW (A) + + for ( size_t i = 0 ; i < elements_count ; ++i ) + { + element_type el = serialization_load<element_type>("v", ar); // MAY THROW (C) + elements.push_back(el); // MAY THROW (C) + } + + auto_remover.release(); + return n; + } + } +}; + +}}}}} // boost::geometry::index::detail::rtree + +// TODO - move to index/detail/rtree/private_view.hpp +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +template <typename Rtree> +class const_private_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; + + const_private_view(Rtree const& rt) : m_rtree(rt) {} + + typedef typename Rtree::members_holder members_holder; + + members_holder const& members() const { return m_rtree.m_members; } + +private: + const_private_view(const_private_view const&); + const_private_view & operator=(const_private_view const&); + + Rtree const& m_rtree; +}; + +template <typename Rtree> +class private_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; + + private_view(Rtree & rt) : m_rtree(rt) {} + + typedef typename Rtree::members_holder members_holder; + + members_holder & members() { return m_rtree.m_members; } + members_holder const& members() const { return m_rtree.m_members; } + +private: + private_view(private_view const&); + private_view & operator=(private_view const&); + + Rtree & m_rtree; +}; + +}}}}} // namespace boost::geometry::index::detail::rtree + +// TODO - move to index/serialization/rtree.hpp +namespace boost { namespace serialization { + +template<class Archive, typename V, typename P, typename I, typename E, typename A> +void save(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version) +{ + namespace detail = boost::geometry::index::detail; + + typedef boost::geometry::index::rtree<V, P, I, E, A> rtree; + typedef detail::rtree::const_private_view<rtree> view; + typedef typename view::translator_type translator_type; + typedef typename view::value_type value_type; + typedef typename view::options_type options_type; + typedef typename view::box_type box_type; + typedef typename view::allocators_type allocators_type; + + view tree(rt); + + detail::serialization_save(tree.members().parameters(), "parameters", ar); + + ar << boost::serialization::make_nvp("values_count", tree.members().values_count); + ar << boost::serialization::make_nvp("leafs_level", tree.members().leafs_level); + + if ( tree.members().values_count ) + { + BOOST_GEOMETRY_INDEX_ASSERT(tree.members().root, "root shouldn't be null_ptr"); + + detail::rtree::visitors::save<Archive, value_type, options_type, translator_type, box_type, allocators_type> save_v(ar, version); + detail::rtree::apply_visitor(save_v, *tree.members().root); + } +} + +template<class Archive, typename V, typename P, typename I, typename E, typename A> +void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version) +{ + namespace detail = boost::geometry::index::detail; + + typedef boost::geometry::index::rtree<V, P, I, E, A> rtree; + typedef detail::rtree::private_view<rtree> view; + typedef typename view::size_type size_type; + typedef typename view::translator_type translator_type; + typedef typename view::value_type value_type; + typedef typename view::options_type options_type; + typedef typename view::box_type box_type; + typedef typename view::allocators_type allocators_type; + + typedef typename options_type::parameters_type parameters_type; + typedef typename allocators_type::node_pointer node_pointer; + typedef detail::rtree::node_auto_ptr<value_type, options_type, translator_type, box_type, allocators_type> node_auto_ptr; + + view tree(rt); + + parameters_type params = detail::serialization_load<parameters_type>("parameters", ar); + + size_type values_count, leafs_level; + ar >> boost::serialization::make_nvp("values_count", values_count); + ar >> boost::serialization::make_nvp("leafs_level", leafs_level); + + node_pointer n(0); + if ( 0 < values_count ) + { + size_type loaded_values_count = 0; + n = detail::rtree::load<value_type, options_type, translator_type, box_type, allocators_type> + ::apply(ar, version, leafs_level, loaded_values_count, params, tree.members().translator(), tree.members().allocators()); // MAY THROW + + node_auto_ptr remover(n, tree.members().allocators()); + if ( loaded_values_count != values_count ) + BOOST_THROW_EXCEPTION(std::runtime_error("unexpected number of values")); // TODO change exception type + remover.release(); + } + + tree.members().parameters() = params; + tree.members().values_count = values_count; + tree.members().leafs_level = leafs_level; + + node_auto_ptr remover(tree.members().root, tree.members().allocators()); + tree.members().root = n; +} + +template<class Archive, typename V, typename P, typename I, typename E, typename A> inline +void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version) +{ + split_free(ar, rt, version); +} + +template<class Archive, typename V, typename P, typename I, typename E, typename A> inline +void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version) +{ + split_free(ar, rt, version); +} + +}} // boost::serialization + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP diff --git a/boost/geometry/index/detail/tags.hpp b/boost/geometry/index/detail/tags.hpp new file mode 100644 index 0000000000..e1a1716bed --- /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 0000000000..f377c720aa --- /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 0000000000..e7f6d22357 --- /dev/null +++ b/boost/geometry/index/detail/tuples.hpp @@ -0,0 +1,204 @@ +// 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 = 0, + size_t N = boost::tuples::length<Tuple>::value> +struct push_back +{ + typedef + boost::tuples::cons< + typename boost::tuples::element<I, Tuple>::type, + typename push_back<Tuple, T, I+1, N>::type + > type; + + static type apply(Tuple const& tup, T const& t) + { + return + type( + boost::get<I>(tup), + push_back<Tuple, T, I+1, N>::apply(tup, t) + ); + } +}; + +template <typename Tuple, typename T, size_t N> +struct push_back<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/utilities.hpp b/boost/geometry/index/detail/utilities.hpp new file mode 100644 index 0000000000..26f0780016 --- /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 0000000000..63577e64a7 --- /dev/null +++ b/boost/geometry/index/detail/varray.hpp @@ -0,0 +1,2203 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2014 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> +#include <boost/throw_exception.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_CXX11_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> + varray & operator=(BOOST_COPY_ASSIGN_REF_2_TEMPL_ARGS(varray, value_type, C) other) + { + 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 const_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 const_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 const_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 const_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 + 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 + 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 0000000000..962d4d8288 --- /dev/null +++ b/boost/geometry/index/detail/varray_detail.hpp @@ -0,0 +1,756 @@ +// 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_trivial_move_constructor.hpp> +#include <boost/type_traits/has_trivial_move_assign.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 varray_detail::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 varray_detail::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_copy_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_copy_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_copy_dispatch(pos, p, use_memcpy()); // may throw +} + +// Needed by push_back(V &&) + +template <typename I, typename V> +inline +void construct_move_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_move_dispatch(I pos, BOOST_RV_REF(P) p, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value<I>::type V; + new (static_cast<void*>(boost::addressof(*pos))) V(::boost::move(p)); // may throw +} + +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_move_constructor<P> + >::type + use_memcpy; + + construct_move_dispatch(pos, ::boost::move(p), use_memcpy()); // may throw +} + +// Needed by emplace_back() and emplace() + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if !defined(BOOST_NO_CXX11_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_CXX11_VARIADIC_TEMPLATES + +// BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 const& p0 +// !BOOST_NO_CXX11_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_CXX11_VARIADIC_TEMPLATES +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + +// assign(I, V) + +template <typename I, typename V> +inline +void assign_copy_dispatch(I pos, V const& v, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ +// TODO - use memmove here? + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template <typename I, typename V> +inline +void assign_copy_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_copy_dispatch(pos, v, use_memcpy()); // may throw +} + +template <typename I, typename V> +inline +void assign_move_dispatch(I pos, V const& v, + boost::mpl::bool_<true> const& /*use_memcpy*/) +{ +// TODO - use memmove here? + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template <typename I, typename V> +inline +void assign_move_dispatch(I pos, BOOST_RV_REF(V) v, + boost::mpl::bool_<false> const& /*use_memcpy*/) +{ + *pos = boost::move(v); // may throw +} + +template <typename I, typename V> +inline +void assign(I pos, BOOST_RV_REF(V) v) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value<I, V>, + ::boost::has_trivial_move_assign<V> + >::type + use_memcpy; + + assign_move_dispatch(pos, ::boost::move(v), use_memcpy()); +} + +// 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 0000000000..59b32af475 --- /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 0000000000..5fbaa8209f --- /dev/null +++ b/boost/geometry/index/equal_to.hpp @@ -0,0 +1,249 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2014 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> +#include <boost/geometry/index/indexable.hpp> + +namespace boost { namespace geometry { namespace index { namespace detail { + +template <typename Geometry, + typename Tag = typename geometry::tag<Geometry>::type> +struct equals +{ + inline static bool apply(Geometry const& g1, Geometry const& g2) + { + return geometry::equals(g1, g2); + } +}; + +template <typename T> +struct equals<T, void> +{ + inline 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>::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; + } +}; + +// TODO: Consider this: Since equal_to<> is using geometry::equals() it's possible that +// two compared Indexables are not exactly the same! They will be spatially equal +// but not strictly equal. Consider 2 Segments with reversed order of points. +// Therefore it's possible that during the Value removal different value will be +// removed than the one that was passed. + +/*! +\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. +\tparam IsIndexable If true, Values are compared using boost::geometry::equals() functions. +*/ +template <typename Value, + bool IsIndexable = is_indexable<Value>::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. + */ + inline bool operator()(Value const& l, Value const& r) const + { + return detail::equals<Value>::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>, false> +{ + /*! \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. + */ + inline bool operator()(std::pair<T1, T2> const& l, std::pair<T1, T2> const& r) const + { + return detail::equals<T1>::apply(l.first, r.first) + && detail::equals<T2>::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>, false> +{ + 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. + */ + inline 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::detail + +#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>::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; + } +}; + +/*! +\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...>, false> +{ + 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::detail + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +namespace boost { namespace geometry { namespace index { + +/*! +\brief The function object comparing Values. + +The default version handles Values which are Indexables, std::pair<T1, T2>, boost::tuple<...> +and std::tuple<...> if STD tuples and variadic templates are supported. +All members are compared from left to right, Geometries using boost::geometry::equals() function, +other types using operator==. + +\tparam Value The type of objects which are compared by this function object. +*/ +template <typename Value> +struct equal_to + : detail::equal_to<Value> +{ + /*! \brief The type of result returned by function object. */ + typedef typename detail::equal_to<Value>::result_type result_type; + + /*! + \brief Compare Values. + + \param l First value. + \param r Second value. + \return true if Values are equal. + */ + inline bool operator()(Value const& l, Value const& r) const + { + return detail::equal_to<Value>::operator()(l ,r); + } +}; + +}}} // namespace boost::geometry::index + +#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 0000000000..391b544f37 --- /dev/null +++ b/boost/geometry/index/indexable.hpp @@ -0,0 +1,217 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2014 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 Segment> +struct is_indexable_impl<Segment, geometry::segment_tag> { static const bool value = true; }; + +template <typename Indexable> +struct is_indexable +{ + static const bool value = + is_indexable_impl + < + Indexable, + typename geometry::tag<Indexable>::type + >::value; +}; + +/*! +\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>, boost::tuple<Indexable, ...> +and std::tuple<Indexable, ...>. + +\tparam Value The Value type which may be translated directly to the Indexable. +\tparam IsIndexable If true, the const reference to Value is returned. +*/ +template <typename Value, bool IsIndexable = is_indexable<Value>::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. + */ + inline 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>, false> +{ + 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. + */ + inline 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>, false> +{ + 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. + */ + inline result_type operator()(value_type const& v) const + { + return boost::get<0>(v); + } +}; + +}}}} // namespace boost::geometry::index::detail + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include <tuple> + +namespace boost { namespace geometry { namespace index { namespace detail { + +/*! +\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...>, false> +{ + 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::detail + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +namespace boost { namespace geometry { namespace index { + +/*! +\brief The function object extracting Indexable from Value. + +It translates Value object to Indexable object. By default, it can handle Values which are Indexables, +std::pair<Indexable, T2>, boost::tuple<Indexable, ...> and std::tuple<Indexable, ...> if STD tuples +and variadic templates are supported. + +\tparam Value The Value type which may be translated directly to the Indexable. +*/ +template <typename Value> +struct indexable + : detail::indexable<Value> +{ + /*! \brief The type of result returned by function object. It should be const Indexable reference. */ + typedef typename detail::indexable<Value>::result_type result_type; + + /*! + \brief Return indexable extracted from the value. + + \param v The value. + \return The indexable. + */ + inline result_type operator()(Value const& v) const + { + return detail::indexable<Value>::operator()(v); + } +}; + +}}} // namespace boost::geometry::index + +#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 0000000000..7c489bc3f1 --- /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 0000000000..fd6df716ee --- /dev/null +++ b/boost/geometry/index/parameters.hpp @@ -0,0 +1,253 @@ +// 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 +{ + 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 ) + { + 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 +{ + 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 ) + { + 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 0000000000..10033abff8 --- /dev/null +++ b/boost/geometry/index/predicates.hpp @@ -0,0 +1,385 @@ +// Boost.Geometry Index +// +// Spatial query predicates +// +// Copyright (c) 2011-2014 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 { + +/*! +\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); +} + +/*! +\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); +} + +/*! +\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); +} + +/*! +\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 Geometry from which distances to \c Values are calculated +and the maximum number of \c Values that should be returned. Internally +boost::geometry::comparable_distance() is used to perform the calculation. + +\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)); +bgi::query(spatial_index, bgi::nearest(box, 5), std::back_inserter(result)); +\endverbatim + +\warning +Only one \c nearest() predicate may be used in a query. + +\ingroup predicates + +\param geometry The geometry from which distance is calculated. +\param k The maximum number of values to return. +*/ +template <typename Geometry> inline +detail::nearest<Geometry> +nearest(Geometry const& geometry, unsigned k) +{ + return detail::nearest<Geometry>(geometry, 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< + boost::tuples::cons<Head, Tail>, Pred +>::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< + bt::cons<Head, Tail>, Pred + >::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 0000000000..503f47b89f --- /dev/null +++ b/boost/geometry/index/rtree.hpp @@ -0,0 +1,1919 @@ +// Boost.Geometry Index +// +// R-tree implementation +// +// Copyright (c) 2008 Federico J. Fernandez. +// Copyright (c) 2011-2014 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 + +// STD +#include <algorithm> + +// Boost +#include <boost/tuple/tuple.hpp> +#include <boost/move/move.hpp> + +// Boost.Geometry +#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp> +#include <boost/geometry/algorithms/centroid.hpp> +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/disjoint.hpp> +#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/overlaps.hpp> +#include <boost/geometry/algorithms/touches.hpp> +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/geometries/point.hpp> +#include <boost/geometry/geometries/box.hpp> + +#include <boost/geometry/strategies/strategies.hpp> + +// Boost.Geometry.Index +#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> + +#include <boost/geometry/index/detail/rtree/query_iterators.hpp> + +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL +// serialization +#include <boost/geometry/index/detail/serialization.hpp> +#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 IndexableGetter +The object of IndexableGetter type translates from Value to Indexable each time r-tree requires it. Which means that this +operation is done for each Value access. Therefore the IndexableGetter should return the Indexable by +const reference instead of a value. Default one can translate all types adapted to Point, Box or Segment +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 IndexableGetter translates from <tt>std::pair<Box, int> const&</tt> to <tt>Box const&</tt>. + +\par EqualTo +The object of EqualTo type compares Values and returns <tt>true</tt> if they're equal. It's similar to <tt>std::equal_to<></tt>. +The default EqualTo returns the result of <tt>boost::geometry::equals()</tt> for types adapted to some Geometry concept +defined in Boost.Geometry and the result of operator= for other types. Components of Pairs and Tuples are compared left-to-right. + +\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; + typedef detail::rtree::node_auto_ptr<value_type, options_type, translator_type, box_type, allocators_type> node_auto_ptr; + + friend class detail::rtree::utilities::view<rtree>; +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + friend class detail::rtree::private_view<rtree>; + friend class detail::rtree::const_private_view<rtree>; +#endif + +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; + + /*! \brief Type of const query iterator. */ + typedef index::detail::rtree::iterators::query_iterator<value_type, allocators_type> const_query_iterator; + +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. + + The tree is created using packing algorithm. + + \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. + + The tree is created using packing algorithm. + + \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 value created using convertible object or a range of values to the index. + + \param conv_or_rng An object of type convertible to value_type or a 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 ConvertibleOrRange> + inline void insert(ConvertibleOrRange const& conv_or_rng) + { + typedef boost::mpl::bool_ + < + boost::is_convertible<ConvertibleOrRange, value_type>::value + > is_conv_t; + + this->insert_dispatch(conv_or_rng, is_conv_t()); + } + + /*! + \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 value corresponding to an object convertible to it or 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 conv_or_rng The object of type convertible to value_type or a 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 ConvertibleOrRange> + inline size_type remove(ConvertibleOrRange const& conv_or_rng) + { + typedef boost::mpl::bool_ + < + boost::is_convertible<ConvertibleOrRange, value_type>::value + > is_conv_t; + + return this->remove_dispatch(conv_or_rng, is_conv_t()); + } + + /*! + \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::contains(), + \li \c boost::geometry::index::covered_by(), + \li \c boost::geometry::index::covers(), + \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::contains()</tt>, + \li <tt>! boost::geometry::index::covered_by()</tt>, + \li <tt>! boost::geometry::index::covers()</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. + If predicates copy 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>()); + } + + /*! + \brief Returns the query iterator pointing at the begin of the query range. + + This method returns the iterator which may be used to perform iterative queries. For the information + about the predicates which may be passed to this method see query(). + + \par Example + \verbatim + for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ; + it != tree.qend() ; ++it ) + { + // do something with value + if ( has_enough_nearest_values() ) + break; + } + \endverbatim + + \par Throws + If predicates copy throws. + If allocation throws. + + \param predicates Predicates. + + \return The iterator pointing at the begin of the query range. + */ + template <typename Predicates> + const_query_iterator qbegin(Predicates const& predicates) const + { + return const_query_iterator(qbegin_(predicates)); + } + + /*! + \brief Returns the query iterator pointing at the end of the query range. + + This method returns the iterator which may be used to check if the query has ended. + + \par Example + \verbatim + for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ; + it != tree.qend() ; ++it ) + { + // do something with value + if ( has_enough_nearest_values() ) + break; + } + \endverbatim + + \par Throws + Nothing + + \return The iterator pointing at the end of the query range. + */ + const_query_iterator qend() const + { + return const_query_iterator(); + } + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL +private: +#endif + /*! + \brief Returns the query iterator pointing at the begin of the query range. + + This method returns the iterator which may be used to perform iterative queries. For the information + about the predicates which may be passed to this method see query(). + + The type of the returned iterator depends on the type of passed Predicates but the iterator of this type + may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator + returned by this method you may get the type e.g. by using C++11 decltype or Boost.Typeof library. + This iterator may be compared with iterators returned by both versions of qend() method. + + \par Example + \verbatim + // Store the result in the container using std::copy() - it requires both iterators of the same type + std::copy(tree.qbegin(bgi::intersects(box)), tree.qend(bgi::intersects(box)), std::back_inserter(result)); + + // Store the result in the container using std::copy() and type-erased iterators + Rtree::const_query_iterator first = tree.qbegin(bgi::intersects(box)); + Rtree::const_query_iterator last = tree.qend(); + std::copy(first, last, std::back_inserter(result)); + + // Boost.Typeof + typedef BOOST_TYPEOF(tree.qbegin(bgi::nearest(pt, 10000))) Iter; + for ( Iter it = tree.qbegin(bgi::nearest(pt, 10000)) ; it != tree.qend() ; ++it ) + { + // do something with value + if ( has_enough_nearest_values() ) + break; + } + \endverbatim + + \par Throws + If predicates copy throws. + If allocation throws. + + \param predicates Predicates. + + \return The iterator pointing at the begin of the query range. + */ + template <typename Predicates> + typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::iterators::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::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::iterators::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); + } + + /*! + \brief Returns the query iterator pointing at the end of the query range. + + This method returns the iterator which may be used to perform iterative queries. For the information + about the predicates which may be passed to this method see query(). + + The type of the returned iterator depends on the type of passed Predicates but the iterator of this type + may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator + returned by this method you may get the type e.g. by using C++11 decltype or Boost.Typeof library. + + The type of the iterator returned by this method is the same as the one returned by qbegin() to which + the same predicates were passed. + + \par Example + \verbatim + // Store the result in the container using std::copy() - it requires both iterators of the same type + std::copy(tree.qbegin(bgi::intersects(box)), tree.qend(bgi::intersects(box)), std::back_inserter(result)); + \endverbatim + + \par Throws + If predicates copy throws. + + \param predicates Predicates. + + \return The iterator pointing at the end of the query range. + */ + template <typename Predicates> + typename boost::mpl::if_c< + detail::predicates_count_distance<Predicates>::value == 0, + detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::iterators::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::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>, + detail::rtree::iterators::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); + } + + /*! + \brief Returns the query iterator pointing at the end of the query range. + + This method returns the iterator which may be compared with the iterator returned by qbegin() in order to + check if the query has ended. + + The type of the returned iterator is different than the type returned by qbegin() but the iterator of this type + may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator returned by this + method, which most certainly will be faster than the type-erased iterator, you may get the type + e.g. by using C++11 decltype or Boost.Typeof library. + + The type of the iterator returned by this method is dfferent than the type returned by qbegin(). + + \par Example + \verbatim + // Store the result in the container using std::copy() and type-erased iterators + Rtree::const_query_iterator first = tree.qbegin(bgi::intersects(box)); + Rtree::const_query_iterator last = tree.qend(); + std::copy(first, last, std::back_inserter(result)); + + // Boost.Typeof + typedef BOOST_TYPEOF(tree.qbegin(bgi::nearest(pt, 10000))) Iter; + for ( Iter it = tree.qbegin(bgi::nearest(pt, 10000)) ; it != tree.qend() ; ++it ) + { + // do something with value + if ( has_enough_nearest_values() ) + break; + } + \endverbatim + + \par Throws + Nothing + + \return The iterator pointing at the end of the query range. + */ + detail::rtree::iterators::end_query_iterator<value_type, allocators_type> + qend_() const + { + return detail::rtree::iterators::end_query_iterator<value_type, allocators_type>(); + } + +public: + + /*! + \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 + { + enum { as_val = 0, as_ind, dont_know }; + typedef boost::mpl::int_ + < + boost::is_same<ValueOrIndexable, value_type>::value ? + as_val : + boost::is_same<ValueOrIndexable, indexable_type>::value ? + as_ind : + boost::is_convertible<ValueOrIndexable, indexable_type>::value ? + as_ind : + boost::is_convertible<ValueOrIndexable, value_type>::value ? + as_val : + dont_know + > variant; + + BOOST_MPL_ASSERT_MSG((variant::value != dont_know), + PASSED_OBJECT_NOT_CONVERTIBLE_TO_VALUE_NOR_INDEXABLE_TYPE, + (ValueOrIndexable)); + + typedef typename boost::mpl::if_c + < + variant::value == as_val, + value_type, + indexable_type + >::type value_or_indexable; + + if ( !m_members.root ) + return 0; + + detail::rtree::visitors::count<value_or_indexable, 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(); + } + + // TODO use node_auto_ptr + 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 Insert a value corresponding to convertible object into the index. + + \param val_conv The object convertible to value. + + \par Exception-safety + basic + */ + template <typename ValueConvertible> + inline void insert_dispatch(ValueConvertible const& val_conv, + boost::mpl::bool_<true> const& /*is_convertible*/) + { + if ( !m_members.root ) + this->raw_create(); + + this->raw_insert(val_conv); + } + + /*! + \brief Insert a range of values into the index. + + \param rng The range of values. + + \par Exception-safety + basic + */ + template <typename Range> + inline void insert_dispatch(Range const& rng, + boost::mpl::bool_<false> const& /*is_convertible*/) + { + BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value), + PASSED_OBJECT_IS_NOT_CONVERTIBLE_TO_VALUE_NOR_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 corresponding to convertible object from the index. + + \param val_conv The object convertible to value. + + \par Exception-safety + basic + */ + template <typename ValueConvertible> + inline size_type remove_dispatch(ValueConvertible const& val_conv, + boost::mpl::bool_<true> const& /*is_convertible*/) + { + return this->raw_remove(val_conv); + } + + /*! + \brief Remove a range of values from the index. + + \param rng The range of values which will be removed from the container. + + \par Exception-safety + basic + */ + template <typename Range> + inline size_type remove_dispatch(Range const& rng, + boost::mpl::bool_<false> const& /*is_convertible*/) + { + BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value), + PASSED_OBJECT_IS_NOT_CONVERTIBLE_TO_VALUE_NOR_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 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 value created using convertible object or a range of values to the index. + +It calls <tt>rtree::insert(ConvertibleOrRange const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param conv_or_rng The object of type convertible to value_type or a range of values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, + typename ConvertibleOrRange> +inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, + ConvertibleOrRange const& conv_or_rng) +{ + tree.insert(conv_or_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 value corresponding to an object convertible to it or a range of values from the container. + +Remove a value corresponding to an object convertible to it or 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(ConvertibleOrRange const&)</tt>. + +\ingroup rtree_functions + +\param tree The spatial index. +\param conv_or_rng The object of type convertible to value_type or the range of values. + +\return The number of removed values. +*/ +template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, + typename ConvertibleOrRange> +inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type +remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree, + ConvertibleOrRange const& conv_or_rng) +{ + return tree.remove(conv_or_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::contains(), +\li \c boost::geometry::index::covered_by(), +\li \c boost::geometry::index::covers(), +\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::contains()</tt>, +\li <tt>! boost::geometry::index::covered_by()</tt>, +\li <tt>! boost::geometry::index::covers()</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 Returns the query iterator pointing at the begin of the query range. + +This method returns the iterator which may be used to perform iterative queries. For the information +about the predicates which may be passed to this method see query(). + +\par Example +\verbatim + +for ( Rtree::const_query_iterator it = qbegin(tree, bgi::nearest(pt, 10000)) ; + it != qend(tree) ; ++it ) +{ + // do something with value + if ( has_enough_nearest_values() ) + break; +} +\endverbatim + +\par Throws +If predicates copy throws. +If allocation throws. + +\ingroup rtree_functions + +\param tree The rtree. +\param predicates Predicates. + +\return The iterator pointing at the begin of the query range. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator, + typename Predicates> inline +typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::const_query_iterator +qbegin(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree, + Predicates const& predicates) +{ + return tree.qbegin(predicates); +} + +/*! +\brief Returns the query iterator pointing at the end of the query range. + +This method returns the iterator which may be used to check if the query has ended. + +\par Example +\verbatim + +for ( Rtree::const_query_iterator it = qbegin(tree, bgi::nearest(pt, 10000)) ; + it != qend(tree) ; ++it ) +{ + // do something with value + if ( has_enough_nearest_values() ) + break; +} +\endverbatim + +\par Throws +Nothing + +\ingroup rtree_functions + +\return The iterator pointing at the end of the query range. +*/ +template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> inline +typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::const_query_iterator +qend(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree) +{ + return tree.qend(); +} + +/*! +\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 + +// TODO: don't include the implementation at the end of the file +#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp> + +#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 index 62929f8073..f39a2489ad 100644 --- a/boost/geometry/io/dsv/write.hpp +++ b/boost/geometry/io/dsv/write.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -20,12 +21,14 @@ #include <boost/concept_check.hpp> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/detail/interior_iterator.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/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -209,9 +212,10 @@ struct dsv_poly 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) + typename interior_return_type<Polygon const>::type + rings = interior_rings(poly); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { os << settings.list_separator; dsv_range<ring>::apply(os, *it, settings); @@ -339,9 +343,61 @@ private: dsv_settings m_settings; }; + +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 +// TODO: The alternative to this could be a forward declaration of dispatch::dsv<> +// or braking the code into the interface and implementation part +#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 + /*! \brief Main DSV-streaming function \details DSV stands for Delimiter Separated Values. Geometries can be streamed diff --git a/boost/geometry/io/svg/svg_mapper.hpp b/boost/geometry/io/svg/svg_mapper.hpp new file mode 100644 index 0000000000..b53fef2ceb --- /dev/null +++ b/boost/geometry/io/svg/svg_mapper.hpp @@ -0,0 +1,390 @@ +// 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/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 typename geometry::select_most_precise + < + typename coordinate_type<Point>::type, + double + >::type calculation_type; + + typedef strategy::transform::map_transformer + < + calculation_type, + geometry::dimension<Point>::type::value, + geometry::dimension<Point>::type::value, + 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 + << "xmlns:xlink=\"http://www.w3.org/1999/xlink\"" + << ">" + << 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) + { + 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 0000000000..fba3cbebaf --- /dev/null +++ b/boost/geometry/io/svg/write_svg.hpp @@ -0,0 +1,279 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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/geometry/algorithms/detail/interior_iterator.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 (typename detail::interior_iterator<Polygon const>::type + rit = boost::begin(rings); rit != boost::end(rings); ++rit) + { + first = true; + for (typename detail::interior_ring_iterator<Polygon const>::type + 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 0000000000..a794120c06 --- /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 index 45e43b88d4..b566e02aa6 100644 --- a/boost/geometry/io/wkt/detail/prefix.hpp +++ b/boost/geometry/io/wkt/detail/prefix.hpp @@ -17,10 +17,16 @@ namespace boost { namespace geometry { + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace wkt { +struct prefix_null +{ + static inline const char* apply() { return ""; } +}; + struct prefix_point { static inline const char* apply() { return "POINT"; } @@ -36,6 +42,21 @@ struct prefix_linestring static inline const char* apply() { return "LINESTRING"; } }; +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 diff --git a/boost/geometry/io/wkt/detail/wkt_multi.hpp b/boost/geometry/io/wkt/detail/wkt_multi.hpp index 0e5abbca81..2b2d1946ad 100644 --- a/boost/geometry/io/wkt/detail/wkt_multi.hpp +++ b/boost/geometry/io/wkt/detail/wkt_multi.hpp @@ -14,9 +14,8 @@ #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/core/tags.hpp> #include <boost/geometry/domains/gis/io/wkt/write.hpp> -#include <boost/geometry/multi/core/tags.hpp> namespace boost { namespace geometry diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp index e926939d51..748eecdbe6 100644 --- a/boost/geometry/io/wkt/read.hpp +++ b/boost/geometry/io/wkt/read.hpp @@ -14,6 +14,7 @@ #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP #define BOOST_GEOMETRY_IO_WKT_READ_HPP +#include <cstddef> #include <string> #include <boost/lexical_cast.hpp> @@ -36,6 +37,8 @@ #include <boost/geometry/core/geometry_id.hpp> #include <boost/geometry/core/interior_rings.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> @@ -306,8 +309,6 @@ struct ring_parser }; - - /*! \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 @@ -358,6 +359,7 @@ struct polygon_parser } }; + inline bool one_of(tokenizer::iterator const& it, std::string const& value, bool& is_present) { @@ -423,10 +425,21 @@ inline bool initialize(tokenizer const& tokens, 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); @@ -458,7 +471,101 @@ struct geometry_parser }; +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, *(boost::end(geometry) - 1)); + 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, *(boost::end(geometry) - 1)); + } + else + { + noparenthesis_point_parser + < + typename boost::range_value<MultiGeometry>::type + >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1)); + } + + if (it != tokens.end() && *it == ",") + { + // Skip "," after point is parsed + ++it; + } + } + + handle_close_parenthesis(it, tokens.end(), wkt); + } + + check_end(it, tokens.end(), wkt); + } +}; /*! @@ -511,7 +618,7 @@ struct box_parser check_end(it, end, wkt); int index = 0; - int n = boost::size(points); + std::size_t n = boost::size(points); if (n == 2) { index = 1; @@ -578,7 +685,6 @@ struct segment_parser }; - }} // namespace detail::wkt #endif // DOXYGEN_NO_DETAIL @@ -632,6 +738,36 @@ struct read_wkt<polygon_tag, Geometry> {}; +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 + > +{}; + + // Box (Non-OGC) template <typename Box> struct read_wkt<box_tag, Box> @@ -651,28 +787,11 @@ struct read_wkt<segment_tag, Segment> /*! \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry) \ingroup wkt +\tparam Geometry \tparam_geometry \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 } +\param geometry \param_geometry output geometry +\ingroup wkt +\qbk{[include reference/io/read_wkt.qbk]} */ template <typename Geometry> inline void read_wkt(std::string const& wkt, Geometry& geometry) diff --git a/boost/geometry/io/wkt/stream.hpp b/boost/geometry/io/wkt/stream.hpp index 86e49fdaf1..3849dda594 100644 --- a/boost/geometry/io/wkt/stream.hpp +++ b/boost/geometry/io/wkt/stream.hpp @@ -22,10 +22,8 @@ // 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 -*/ +// This is currently not documented on purpose: the Doxygen 2 QBK generator +// should be updated w.r.t. << which in the end ruins the DocBook XML template<typename Char, typename Traits, typename Geometry> inline std::basic_ostream<Char, Traits>& operator<< ( diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp index a3e3173d05..6c1a2e153e 100644 --- a/boost/geometry/io/wkt/write.hpp +++ b/boost/geometry/io/wkt/write.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,24 +19,36 @@ #include <string> #include <boost/array.hpp> -#include <boost/concept/assert.hpp> #include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/disjoint.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/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/ring.hpp> #include <boost/geometry/io/wkt/detail/prefix.hpp> + namespace boost { namespace geometry { +// 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 { @@ -109,31 +122,49 @@ struct wkt_range { template <typename Char, typename Traits> static inline void apply(std::basic_ostream<Char, Traits>& os, - Range const& range) + Range const& range, bool force_closed) { typedef typename boost::range_iterator<Range const>::type iterator_type; + typedef stream_coordinate + < + point_type, 0, dimension<point_type>::type::value + > stream_type; + bool first = true; os << PrefixPolicy::apply(); // TODO: check EMPTY here - for (iterator_type it = boost::begin(range); - it != boost::end(range); - ++it) + iterator_type begin = boost::begin(range); + iterator_type end = boost::end(range); + for (iterator_type it = begin; it != end; ++it) { os << (first ? "" : ","); - stream_coordinate - < - point_type, 0, dimension<point_type>::type::value - >::apply(os, *it); + stream_type::apply(os, *it); first = false; } + // optionally, close range to ring by repeating the first point + if (force_closed + && boost::size(range) > 1 + && geometry::disjoint(*begin, *(end - 1))) + { + os << ","; + stream_type::apply(os, *begin); + } + os << SuffixPolicy::apply(); } + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range) + { + apply(os, range, false); + } + private: typedef typename boost::range_value<Range>::type point_type; }; @@ -160,23 +191,52 @@ struct wkt_poly Polygon const& poly) { typedef typename ring_type<Polygon const>::type ring; + bool const force_closed = true; os << PrefixPolicy::apply(); // TODO: check EMPTY here os << "("; - wkt_sequence<ring>::apply(os, exterior_ring(poly)); + wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed); - typename interior_return_type<Polygon const>::type rings - = interior_rings(poly); - for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + typename interior_return_type<Polygon const>::type + rings = interior_rings(poly); + for (typename detail::interior_iterator<Polygon const>::type + it = boost::begin(rings); it != boost::end(rings); ++it) { os << ","; - wkt_sequence<ring>::apply(os, *it); + wkt_sequence<ring>::apply(os, *it, force_closed); } os << ")"; } }; +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 << ")"; + } +}; + template <typename Box> struct wkt_box { @@ -240,18 +300,12 @@ struct wkt_segment namespace dispatch { -template <typename Tag, typename Geometry> -struct wkt -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types<Geometry>) - ); -}; +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct wkt: not_implemented<Tag> +{}; template <typename Point> -struct wkt<point_tag, Point> +struct wkt<Point, point_tag> : detail::wkt::wkt_point < Point, @@ -260,7 +314,7 @@ struct wkt<point_tag, Point> {}; template <typename Linestring> -struct wkt<linestring_tag, Linestring> +struct wkt<Linestring, linestring_tag> : detail::wkt::wkt_range < Linestring, @@ -275,12 +329,12 @@ struct wkt<linestring_tag, Linestring> It is therefore streamed as a polygon */ template <typename Box> -struct wkt<box_tag, Box> +struct wkt<Box, box_tag> : detail::wkt::wkt_box<Box> {}; template <typename Segment> -struct wkt<segment_tag, Segment> +struct wkt<Segment, segment_tag> : detail::wkt::wkt_segment<Segment> {}; @@ -291,7 +345,7 @@ A ring is equivalent to a polygon without inner rings It is therefore streamed as a polygon */ template <typename Ring> -struct wkt<ring_tag, Ring> +struct wkt<Ring, ring_tag> : detail::wkt::wkt_range < Ring, @@ -304,7 +358,7 @@ struct wkt<ring_tag, Ring> \brief Specialization to stream polygon as WKT */ template <typename Polygon> -struct wkt<polygon_tag, Polygon> +struct wkt<Polygon, polygon_tag> : detail::wkt::wkt_poly < Polygon, @@ -312,6 +366,88 @@ struct wkt<polygon_tag, Polygon> > {}; +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 + > +{}; + + +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 @@ -340,11 +476,7 @@ public: std::basic_ostream<Char, Traits>& os, wkt_manipulator const& m) { - dispatch::wkt - < - typename tag<Geometry>::type, - Geometry - >::apply(os, m.m_geometry); + dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry); os.flush(); return os; } @@ -355,13 +487,10 @@ private: /*! \brief Main WKT-streaming function +\tparam Geometry \tparam_geometry +\param geometry \param_geometry \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 } +\qbk{[include reference/io/wkt.qbk]} */ template <typename Geometry> inline wkt_manipulator<Geometry> wkt(Geometry const& geometry) @@ -371,6 +500,10 @@ inline wkt_manipulator<Geometry> wkt(Geometry const& geometry) 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/closing_iterator.hpp b/boost/geometry/iterators/closing_iterator.hpp index 7cd8fa0150..a9f67d4788 100644 --- a/boost/geometry/iterators/closing_iterator.hpp +++ b/boost/geometry/iterators/closing_iterator.hpp @@ -28,8 +28,9 @@ 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 It's const iterator treating the Range as one containing non-mutable elements. + For both "closing_iterator<Range> and "closing_iterator<Range const> + const reference is always returned when dereferenced. \note This class is normally used from "closeable_view" if Close==true */ template <typename Range> diff --git a/boost/geometry/iterators/concatenate_iterator.hpp b/boost/geometry/iterators/concatenate_iterator.hpp new file mode 100644 index 0000000000..20112b4c4c --- /dev/null +++ b/boost/geometry/iterators/concatenate_iterator.hpp @@ -0,0 +1,184 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/iterator_categories.hpp> + + +namespace boost { namespace geometry +{ + + + +template +< + typename Iterator1, + typename Iterator2, + typename Value, + typename Reference = Value& +> +class concatenate_iterator + : public boost::iterator_facade + < + concatenate_iterator<Iterator1, Iterator2, Value, Reference>, + Value, + boost::bidirectional_traversal_tag, + Reference + > +{ +private: + Iterator1 m_it1, m_end1; + Iterator2 m_begin2, m_it2; + +public: + typedef Iterator1 first_iterator_type; + typedef Iterator2 second_iterator_type; + + // default constructor + concatenate_iterator() {} + + // for begin + concatenate_iterator(Iterator1 it1, Iterator1 end1, + Iterator2 begin2, Iterator2 it2) + : m_it1(it1), m_end1(end1), m_begin2(begin2), m_it2(it2) + {} + + // for end + concatenate_iterator(Iterator1 end1, Iterator2 begin2, Iterator2 end2) + : m_it1(end1), m_end1(end1), m_begin2(begin2), m_it2(end2) + {} + + template + < + typename OtherIt1, + typename OtherIt2, + typename OtherValue, + typename OtherReference + > + concatenate_iterator(concatenate_iterator + < + OtherIt1, + OtherIt2, + OtherValue, + OtherReference + > const& other) + : m_it1(other.m_it1) + , m_end1(other.m_end1) + , m_begin2(other.m_begin2) + , m_it2(other.m_it2) + { + static const bool are_conv + = boost::is_convertible<OtherIt1, Iterator1>::value + && boost::is_convertible<OtherIt2, Iterator2>::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types<OtherIt1, OtherIt2>)); + } + + template + < + typename OtherIt1, + typename OtherIt2, + typename OtherValue, + typename OtherReference + > + concatenate_iterator operator=(concatenate_iterator + < + OtherIt1, + OtherIt2, + OtherValue, + OtherReference + > const& other) + { + static const bool are_conv + = boost::is_convertible<OtherIt1, Iterator1>::value + && boost::is_convertible<OtherIt2, Iterator2>::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types<OtherIt1, OtherIt2>)); + + m_it1 = other.m_it1; + m_end1 = other.m_end1; + m_begin2 = other.m_begin2; + m_it2 = other.m_it2; + return *this; + } + +private: + friend class boost::iterator_core_access; + + template <typename It1, typename It2, typename V, typename R> + friend class concatenate_iterator; + + inline Reference dereference() const + { + if ( m_it1 == m_end1 ) + { + return *m_it2; + } + return *m_it1; + } + + template + < + typename OtherIt1, + typename OtherIt2, + typename OtherValue, + typename OtherReference + > + inline bool equal(concatenate_iterator + < + OtherIt1, + OtherIt2, + OtherValue, + OtherReference + > const& other) const + { + return m_it1 == other.m_it1 && m_it2 == other.m_it2; + } + + inline void increment() + { + if ( m_it1 == m_end1 ) + { + ++m_it2; + } + else + { + ++m_it1; + } + } + + inline void decrement() + { + if ( m_it2 == m_begin2 ) + { + --m_it1; + } + else + { + --m_it2; + } + } +}; + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP diff --git a/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp b/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp new file mode 100644 index 0000000000..b2239fb8dd --- /dev/null +++ b/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP + +#include <boost/range.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/mpl/if.hpp> + +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_iterator +{ + + +template +< + typename Geometry, + typename Tag = typename tag<Geometry>::type +> +struct inner_range_type +{ + typedef typename boost::mpl::if_c + < + !boost::is_const<Geometry>::type::value, + typename boost::range_value<Geometry>::type, + typename boost::range_value<Geometry>::type const + >::type type; +}; + + +template <typename Polygon> +struct inner_range_type<Polygon, polygon_tag> +{ + typedef typename boost::mpl::if_c + < + !boost::is_const<Polygon>::type::value, + typename geometry::ring_type<Polygon>::type, + typename geometry::ring_type<Polygon>::type const + >::type type; +}; + + +}} // namespace detail::point_iterator +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP diff --git a/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp b/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp new file mode 100644 index 0000000000..a7805b127b --- /dev/null +++ b/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp @@ -0,0 +1,136 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/iterators/flatten_iterator.hpp> +#include <boost/geometry/iterators/concatenate_iterator.hpp> + +#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp> +#include <boost/geometry/iterators/detail/point_iterator/value_type.hpp> + +#include <boost/geometry/iterators/dispatch/point_iterator.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_iterator +{ + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct iterator_type + : not_implemented<Geometry> +{}; + + + + +template <typename Linestring> +struct iterator_type<Linestring, linestring_tag> +{ + typedef typename boost::range_iterator<Linestring>::type type; +}; + + +template <typename Ring> +struct iterator_type<Ring, ring_tag> +{ + typedef typename boost::range_iterator<Ring>::type type; +}; + + +template <typename Polygon> +class iterator_type<Polygon, polygon_tag> +{ +private: + typedef typename inner_range_type<Polygon>::type inner_range; + +public: + typedef concatenate_iterator + < + typename boost::range_iterator<inner_range>::type, + flatten_iterator + < + typename boost::range_iterator + < + typename geometry::interior_type<Polygon>::type + >::type, + typename iterator_type<inner_range>::type, + typename value_type<Polygon>::type, + dispatch::points_begin<inner_range>, + dispatch::points_end<inner_range> + >, + typename value_type<Polygon>::type + > type; +}; + + +template <typename MultiPoint> +struct iterator_type<MultiPoint, multi_point_tag> +{ + typedef typename boost::range_iterator<MultiPoint>::type type; +}; + + +template <typename MultiLinestring> +class iterator_type<MultiLinestring, multi_linestring_tag> +{ +private: + typedef typename inner_range_type<MultiLinestring>::type inner_range; + +public: + typedef flatten_iterator + < + typename boost::range_iterator<MultiLinestring>::type, + typename iterator_type<inner_range>::type, + typename value_type<MultiLinestring>::type, + dispatch::points_begin<inner_range>, + dispatch::points_end<inner_range> + > type; +}; + + +template <typename MultiPolygon> +class iterator_type<MultiPolygon, multi_polygon_tag> +{ +private: + typedef typename inner_range_type<MultiPolygon>::type inner_range; + +public: + typedef flatten_iterator + < + typename boost::range_iterator<MultiPolygon>::type, + typename iterator_type<inner_range>::type, + typename value_type<MultiPolygon>::type, + dispatch::points_begin<inner_range>, + dispatch::points_end<inner_range> + > type; +}; + + +}} // namespace detail::point_iterator +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP diff --git a/boost/geometry/iterators/detail/point_iterator/value_type.hpp b/boost/geometry/iterators/detail/point_iterator/value_type.hpp new file mode 100644 index 0000000000..7cdf366391 --- /dev/null +++ b/boost/geometry/iterators/detail/point_iterator/value_type.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP + +#include <boost/type_traits/is_const.hpp> +#include <boost/mpl/if.hpp> + +#include <boost/geometry/core/point_type.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace point_iterator +{ + + +template <typename Geometry> +struct value_type +{ + typedef typename boost::mpl::if_c + < + !boost::is_const<Geometry>::type::value, + typename geometry::point_type<Geometry>::type, + typename geometry::point_type<Geometry>::type const + >::type type; +}; + + +}} // namespace detail::point_iterator +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP diff --git a/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp b/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp new file mode 100644 index 0000000000..57a524e7e4 --- /dev/null +++ b/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp @@ -0,0 +1,153 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/core/interior_type.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/iterators/concatenate_iterator.hpp> +#include <boost/geometry/iterators/flatten_iterator.hpp> +#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp> + +#include <boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp> +#include <boost/geometry/iterators/detail/segment_iterator/value_type.hpp> + +#include <boost/geometry/iterators/dispatch/segment_iterator.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace segment_iterator +{ + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct iterator_type + : not_implemented<Geometry> +{}; + + +template <typename Linestring> +struct iterator_type<Linestring, linestring_tag> +{ + typedef range_segment_iterator + < + Linestring, typename value_type<Linestring>::type + > type; +}; + + +template <typename Ring> +struct iterator_type<Ring, ring_tag> +{ + typedef range_segment_iterator + < + Ring, typename value_type<Ring>::type + > type; +}; + + +template <typename Polygon> +class iterator_type<Polygon, polygon_tag> +{ +private: + typedef typename detail::point_iterator::inner_range_type + < + Polygon + >::type inner_range; + +public: + typedef concatenate_iterator + < + range_segment_iterator + < + inner_range, + typename value_type<Polygon>::type + >, + flatten_iterator + < + typename boost::range_iterator + < + typename geometry::interior_type<Polygon>::type + >::type, + typename iterator_type<inner_range>::type, + typename value_type<Polygon>::type, + dispatch::segments_begin<inner_range>, + dispatch::segments_end<inner_range>, + typename value_type<Polygon>::type + >, + typename value_type<Polygon>::type, + typename value_type<Polygon>::type + > type; +}; + + +template <typename MultiLinestring> +class iterator_type<MultiLinestring, multi_linestring_tag> +{ +private: + typedef typename detail::point_iterator::inner_range_type + < + MultiLinestring + >::type inner_range; + +public: + typedef flatten_iterator + < + typename boost::range_iterator<MultiLinestring>::type, + typename iterator_type<inner_range>::type, + typename value_type<MultiLinestring>::type, + dispatch::segments_begin<inner_range>, + dispatch::segments_end<inner_range>, + typename value_type<MultiLinestring>::type + > type; +}; + + +template <typename MultiPolygon> +class iterator_type<MultiPolygon, multi_polygon_tag> +{ +private: + typedef typename detail::point_iterator::inner_range_type + < + MultiPolygon + >::type inner_range; +public: + typedef flatten_iterator + < + typename boost::range_iterator<MultiPolygon>::type, + typename iterator_type<inner_range>::type, + typename value_type<MultiPolygon>::type, + dispatch::segments_begin<inner_range>, + dispatch::segments_end<inner_range>, + typename value_type<MultiPolygon>::type + > type; +}; + + + +}} // namespace detail::segment_iterator +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP diff --git a/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp new file mode 100644 index 0000000000..d79fda84d9 --- /dev/null +++ b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp @@ -0,0 +1,223 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/iterator_categories.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/iterators/closing_iterator.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace segment_iterator +{ + + +template <typename Range, closure_selector Closure = closure<Range>::value> +struct range_iterator_type +{ + typedef typename boost::range_iterator<Range>::type type; +}; + +template <typename Range> +struct range_iterator_type<Range, open> +{ + typedef closing_iterator<Range> type; +}; + + + +template <typename Range, closure_selector Closure = closure<Range>::value> +struct range_iterator_begin +{ + static inline typename range_iterator_type<Range, Closure>::type + apply(Range& range) + { + return boost::begin(range); + } +}; + +template <typename Range> +struct range_iterator_begin<Range, open> +{ + static inline typename range_iterator_type<Range, open>::type + apply(Range& range) + { + return closing_iterator<Range>(range); + } +}; + + + +template <typename Range, closure_selector Closure = closure<Range>::value> +struct range_iterator_end +{ + static inline typename range_iterator_type<Range, Closure>::type + apply(Range& range) + { + return boost::end(range); + } +}; + +template <typename Range> +struct range_iterator_end<Range, open> +{ + static inline typename range_iterator_type<Range, open>::type + apply(Range& range) + { + return closing_iterator<Range>(range, true); + } +}; + + + + + + +template <typename Range, typename Value, typename Reference = Value> +class range_segment_iterator + : public boost::iterator_facade + < + range_segment_iterator<Range, Value, Reference>, + Value, + boost::bidirectional_traversal_tag, + Reference + > +{ +public: + typedef typename range_iterator_type<Range>::type iterator_type; + + // default constructor + range_segment_iterator() + : m_it() + {} + + // for begin + range_segment_iterator(Range& r) + : m_it(range_iterator_begin<Range>::apply(r)) + {} + + // for end + range_segment_iterator(Range& r, bool) + : m_it(--range_iterator_end<Range>::apply(r)) + {} + + template + < + typename OtherRange, + typename OtherValue, + typename OtherReference + > + range_segment_iterator(range_segment_iterator + < + OtherRange, + OtherValue, + OtherReference + > const& other) + : m_it(other.m_it) + { + typedef typename range_segment_iterator + < + OtherRange, OtherValue, OtherReference + >::iterator_type other_iterator_type; + + static const bool are_conv + = boost::is_convertible<other_iterator_type, iterator_type>::value; + + BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>)); + } + + template + < + typename OtherRange, + typename OtherValue, + typename OtherReference + > + range_segment_iterator operator=(range_segment_iterator + < + OtherRange, + OtherValue, + OtherReference + > const& other) + { + typedef typename range_segment_iterator + < + OtherRange, OtherValue, OtherReference + >::iterator_type other_iterator_type; + + static const bool are_conv + = boost::is_convertible<other_iterator_type, iterator_type>::value; + + BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>)); + + m_it = other.m_it; + return *this; + } + +private: + friend class boost::iterator_core_access; + + template <typename Rng, typename V, typename R> + friend class range_segment_iterator; + + inline Reference dereference() const + { + iterator_type next(m_it); + ++next; + return Reference(*m_it, *next); + } + + template + < + typename OtherRange, + typename OtherValue, + typename OtherReference + > + inline bool equal(range_segment_iterator + < + OtherRange, + OtherValue, + OtherReference + > const& other) const + { + return m_it == other.m_it; + } + + inline void increment() + { + ++m_it; + } + + inline void decrement() + { + --m_it; + } + +private: + iterator_type m_it; +}; + + +}} // namespace detail::segment_iterator +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP diff --git a/boost/geometry/iterators/detail/segment_iterator/value_type.hpp b/boost/geometry/iterators/detail/segment_iterator/value_type.hpp new file mode 100644 index 0000000000..0b3c66670c --- /dev/null +++ b/boost/geometry/iterators/detail/segment_iterator/value_type.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP + +#include <boost/geometry/iterators/detail/point_iterator/value_type.hpp> +#include <boost/geometry/geometries/pointing_segment.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace segment_iterator +{ + +template <typename Geometry> +struct value_type +{ + typedef typename detail::point_iterator::value_type + < + Geometry + >::type point_iterator_value_type; + + typedef geometry::model::pointing_segment + < + point_iterator_value_type + > type; +}; + +}} // namespace detail::segment_iterator +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP diff --git a/boost/geometry/iterators/dispatch/point_iterator.hpp b/boost/geometry/iterators/dispatch/point_iterator.hpp new file mode 100644 index 0000000000..938dfd8ebc --- /dev/null +++ b/boost/geometry/iterators/dispatch/point_iterator.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// dispatch for points_begin +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct points_begin + : not_implemented<Geometry> +{}; + + + +// dispatch for points_end +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct points_end + : not_implemented<Geometry> +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP diff --git a/boost/geometry/iterators/dispatch/segment_iterator.hpp b/boost/geometry/iterators/dispatch/segment_iterator.hpp new file mode 100644 index 0000000000..0c0a1b09a7 --- /dev/null +++ b/boost/geometry/iterators/dispatch/segment_iterator.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// dispatch for segments_begin +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct segments_begin + : not_implemented<Geometry> +{}; + + + +// dispatch for segments_end +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct segments_end + : not_implemented<Geometry> +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP diff --git a/boost/geometry/iterators/ever_circling_iterator.hpp b/boost/geometry/iterators/ever_circling_iterator.hpp index 566669e26d..50b20480cd 100644 --- a/boost/geometry/iterators/ever_circling_iterator.hpp +++ b/boost/geometry/iterators/ever_circling_iterator.hpp @@ -177,7 +177,7 @@ private: inline void advance(difference_type n) { - if (m_index >= 0 && m_index < m_size + if (m_index >= 0 && m_index < m_size && m_index + n >= 0 && m_index + n < m_size) { m_index += n; @@ -196,7 +196,7 @@ private: { m_index += m_size; } - m_index = m_index % m_size; + m_index = m_index % m_size; this->m_iterator = boost::begin(*m_range) + m_index; } diff --git a/boost/geometry/iterators/flatten_iterator.hpp b/boost/geometry/iterators/flatten_iterator.hpp new file mode 100644 index 0000000000..078079dc2c --- /dev/null +++ b/boost/geometry/iterators/flatten_iterator.hpp @@ -0,0 +1,259 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/iterator.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/iterator_categories.hpp> + + +namespace boost { namespace geometry +{ + + + +template +< + typename OuterIterator, + typename InnerIterator, + typename Value, + typename AccessInnerBegin, + typename AccessInnerEnd, + typename Reference = Value& +> +class flatten_iterator + : public boost::iterator_facade + < + flatten_iterator + < + OuterIterator, + InnerIterator, + Value, + AccessInnerBegin, + AccessInnerEnd, + Reference + >, + Value, + boost::bidirectional_traversal_tag, + Reference + > +{ +private: + OuterIterator m_outer_it, m_outer_end; + InnerIterator m_inner_it; + +public: + typedef OuterIterator outer_iterator_type; + typedef InnerIterator inner_iterator_type; + + // default constructor + flatten_iterator() {} + + // for begin + flatten_iterator(OuterIterator outer_it, OuterIterator outer_end) + : m_outer_it(outer_it), m_outer_end(outer_end) + { + advance_through_empty(); + } + + // for end + flatten_iterator(OuterIterator outer_end) + : m_outer_it(outer_end), m_outer_end(outer_end) + {} + + template + < + typename OtherOuterIterator, typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, typename OtherAccessInnerEnd, + typename OtherReference + > + flatten_iterator(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd, + OtherReference + > const& other) + : m_outer_it(other.m_outer_it), + m_outer_end(other.m_outer_end), + m_inner_it(other.m_inner_it) + { + static const bool are_conv + = boost::is_convertible + < + OtherOuterIterator, OuterIterator + >::value + && boost::is_convertible + < + OtherInnerIterator, InnerIterator + >::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types<OtherOuterIterator, OtherInnerIterator>)); + } + + template + < + typename OtherOuterIterator, + typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, + typename OtherAccessInnerEnd, + typename OtherReference + > + flatten_iterator operator=(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd, + OtherReference + > const& other) + { + static const bool are_conv + = boost::is_convertible + < + OtherOuterIterator, OuterIterator + >::value + && boost::is_convertible + < + OtherInnerIterator, InnerIterator + >::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types<OtherOuterIterator, OtherInnerIterator>)); + + m_outer_it = other.m_outer_it; + m_outer_end = other.m_outer_end; + m_inner_it = other.m_inner_it; + return *this; + } + +private: + friend class boost::iterator_core_access; + + template + < + typename Outer, + typename Inner, + typename V, + typename InnerBegin, + typename InnerEnd, + typename R + > + friend class flatten_iterator; + + static inline bool empty(OuterIterator outer_it) + { + return + AccessInnerBegin::apply(*outer_it) == AccessInnerEnd::apply(*outer_it); + } + + inline void advance_through_empty() + { + while ( m_outer_it != m_outer_end && empty(m_outer_it) ) + { + ++m_outer_it; + } + + if ( m_outer_it != m_outer_end ) + { + m_inner_it = AccessInnerBegin::apply(*m_outer_it); + } + } + + inline Reference dereference() const + { + BOOST_ASSERT( m_outer_it != m_outer_end ); + BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); + return *m_inner_it; + } + + + template + < + typename OtherOuterIterator, + typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, + typename OtherAccessInnerEnd, + typename OtherReference + > + inline bool equal(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd, + OtherReference + > const& other) const + { + if ( m_outer_it != other.m_outer_it ) + { + return false; + } + + if ( m_outer_it == m_outer_end ) + { + return true; + } + + return m_inner_it == other.m_inner_it; + } + + inline void increment() + { + BOOST_ASSERT( m_outer_it != m_outer_end ); + BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); + + ++m_inner_it; + if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) ) + { + ++m_outer_it; + advance_through_empty(); + } + } + + inline void decrement() + { + if ( m_outer_it == m_outer_end + || m_inner_it == AccessInnerBegin::apply(*m_outer_it) ) + { + do + { + --m_outer_it; + } + while ( empty(m_outer_it) ); + m_inner_it = --AccessInnerEnd::apply(*m_outer_it); + } + else + { + --m_inner_it; + } + } +}; + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP diff --git a/boost/geometry/iterators/has_one_element.hpp b/boost/geometry/iterators/has_one_element.hpp new file mode 100644 index 0000000000..2f9acefc1e --- /dev/null +++ b/boost/geometry/iterators/has_one_element.hpp @@ -0,0 +1,29 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP +#define BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP + + +namespace boost { namespace geometry +{ + + +// free function to test if an iterator range has a single element +template <typename Iterator> +inline bool has_one_element(Iterator first, Iterator beyond) +{ + return first != beyond && ++first == beyond; +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP diff --git a/boost/geometry/iterators/point_iterator.hpp b/boost/geometry/iterators/point_iterator.hpp new file mode 100644 index 0000000000..075339aa58 --- /dev/null +++ b/boost/geometry/iterators/point_iterator.hpp @@ -0,0 +1,315 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/iterators/dispatch/point_iterator.hpp> +#include <boost/geometry/iterators/detail/point_iterator/iterator_type.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for points_begin + + +template <typename Linestring> +struct points_begin<Linestring, linestring_tag> +{ + static inline typename detail::point_iterator::iterator_type + < + Linestring + >::type + apply(Linestring& linestring) + { + return boost::begin(linestring); + } +}; + + +template <typename Ring> +struct points_begin<Ring, ring_tag> +{ + static inline typename detail::point_iterator::iterator_type<Ring>::type + apply(Ring& ring) + { + return boost::begin(ring); + } +}; + + +template <typename Polygon> +struct points_begin<Polygon, polygon_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + Polygon + >::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (boost::begin(geometry::exterior_ring(polygon)), + boost::end(geometry::exterior_ring(polygon)), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ) + ); + } +}; + + +template <typename MultiPoint> +struct points_begin<MultiPoint, multi_point_tag> +{ + static inline typename detail::point_iterator::iterator_type + < + MultiPoint + >::type + apply(MultiPoint& multipoint) + { + return boost::begin(multipoint); + } +}; + + +template <typename MultiLinestring> +struct points_begin<MultiLinestring, multi_linestring_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + MultiLinestring + >::type return_type; + + static inline return_type apply(MultiLinestring& multilinestring) + { + return return_type(boost::begin(multilinestring), + boost::end(multilinestring)); + } +}; + + +template <typename MultiPolygon> +struct points_begin<MultiPolygon, multi_polygon_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + MultiPolygon + >::type return_type; + + static inline return_type apply(MultiPolygon& multipolygon) + { + return return_type(boost::begin(multipolygon), + boost::end(multipolygon)); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for points_end + + +template <typename Linestring> +struct points_end<Linestring, linestring_tag> +{ + static inline typename detail::point_iterator::iterator_type + < + Linestring + >::type + apply(Linestring& linestring) + { + return boost::end(linestring); + } +}; + + +template <typename Ring> +struct points_end<Ring, ring_tag> +{ + static inline typename detail::point_iterator::iterator_type<Ring>::type + apply(Ring& ring) + { + return boost::end(ring); + } +}; + + +template <typename Polygon> +struct points_end<Polygon, polygon_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + Polygon + >::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (boost::end(geometry::exterior_ring(polygon)), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ), + flatten_iterator( boost::end(geometry::interior_rings(polygon)) ) + ); + } +}; + + +template <typename MultiPoint> +struct points_end<MultiPoint, multi_point_tag> +{ + static inline typename detail::point_iterator::iterator_type + < + MultiPoint + >::type + apply(MultiPoint& multipoint) + { + return boost::end(multipoint); + } +}; + + +template <typename MultiLinestring> +struct points_end<MultiLinestring, multi_linestring_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + MultiLinestring + >::type return_type; + + static inline return_type apply(MultiLinestring& multilinestring) + { + return return_type(boost::end(multilinestring)); + } +}; + + +template <typename MultiPolygon> +struct points_end<MultiPolygon, multi_polygon_tag> +{ + typedef typename detail::point_iterator::iterator_type + < + MultiPolygon + >::type return_type; + + static inline return_type apply(MultiPolygon& multipolygon) + { + return return_type(boost::end(multipolygon)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +// MK:: need to add doc here +template <typename Geometry> +class point_iterator + : public detail::point_iterator::iterator_type<Geometry>::type +{ +private: + typedef typename detail::point_iterator::iterator_type<Geometry>::type base; + + inline base* base_ptr() + { + return this; + } + + inline base const* base_ptr() const + { + return this; + } + + template <typename OtherGeometry> friend class point_iterator; + template <typename G> friend inline point_iterator<G> points_begin(G&); + template <typename G> friend inline point_iterator<G> points_end(G&); + + inline point_iterator(base const& base_it) : base(base_it) {} + +public: + inline point_iterator() {} + + template <typename OtherGeometry> + inline point_iterator(point_iterator<OtherGeometry> const& other) + : base(*other.base_ptr()) + { + static const bool is_conv + = boost::is_convertible< + typename detail::point_iterator::iterator_type + < + OtherGeometry + >::type, + typename detail::point_iterator::iterator_type + < + Geometry + >::type + >::value; + + BOOST_MPL_ASSERT_MSG((is_conv), + NOT_CONVERTIBLE, + (point_iterator<OtherGeometry>)); + } +}; + + +// MK:: need to add doc here +template <typename Geometry> +inline point_iterator<Geometry> +points_begin(Geometry& geometry) +{ + return dispatch::points_begin<Geometry>::apply(geometry); +} + + +// MK:: need to add doc here +template <typename Geometry> +inline point_iterator<Geometry> +points_end(Geometry& geometry) +{ + return dispatch::points_end<Geometry>::apply(geometry); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP diff --git a/boost/geometry/iterators/point_reverse_iterator.hpp b/boost/geometry/iterators/point_reverse_iterator.hpp new file mode 100644 index 0000000000..1c2ac0169d --- /dev/null +++ b/boost/geometry/iterators/point_reverse_iterator.hpp @@ -0,0 +1,98 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP + +#include <iterator> + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> + +namespace boost { namespace geometry +{ + + +// MK:: need to add doc here +template <typename Geometry> +class point_reverse_iterator + : public std::reverse_iterator<point_iterator<Geometry> > +{ +private: + typedef std::reverse_iterator<point_iterator<Geometry> > base; + + inline base* base_ptr() + { + return this; + } + + inline base const* base_ptr() const + { + return this; + } + + template <typename OtherGeometry> friend class point_reverse_iterator; + template <typename G> + friend inline point_reverse_iterator<G> points_rbegin(G&); + + template <typename G> + friend inline point_reverse_iterator<G> points_rend(G&); + + inline point_reverse_iterator(base const& base_it) : base(base_it) {} + +public: + inline point_reverse_iterator() {} + + template <typename OtherGeometry> + inline + point_reverse_iterator(point_reverse_iterator<OtherGeometry> const& other) + : base(*other.base_ptr()) + { + static const bool is_conv = boost::is_convertible + < + std::reverse_iterator<point_iterator<Geometry> >, + std::reverse_iterator<point_iterator<OtherGeometry> > + >::value; + + BOOST_MPL_ASSERT_MSG((is_conv), + NOT_CONVERTIBLE, + (point_reverse_iterator<OtherGeometry>)); + } +}; + + +// MK:: need to add doc here +template <typename Geometry> +inline point_reverse_iterator<Geometry> +points_rbegin(Geometry& geometry) +{ + return std::reverse_iterator + < + point_iterator<Geometry> + >(points_end(geometry)); +} + + +// MK:: need to add doc here +template <typename Geometry> +inline point_reverse_iterator<Geometry> +points_rend(Geometry& geometry) +{ + return std::reverse_iterator + < + point_iterator<Geometry> + >(points_begin(geometry)); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP diff --git a/boost/geometry/iterators/segment_iterator.hpp b/boost/geometry/iterators/segment_iterator.hpp new file mode 100644 index 0000000000..206d7fc503 --- /dev/null +++ b/boost/geometry/iterators/segment_iterator.hpp @@ -0,0 +1,317 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp> +#include <boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp> + +#include <boost/geometry/iterators/dispatch/segment_iterator.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for segments_begin + + +template <typename Linestring> +struct segments_begin<Linestring, linestring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + Linestring + >::type return_type; + + static inline return_type apply(Linestring& linestring) + { + return return_type(linestring); + } +}; + + +template <typename Ring> +struct segments_begin<Ring, ring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + Ring + >::type return_type; + + static inline return_type apply(Ring& ring) + { + return return_type(ring); + } +}; + + +template <typename Polygon> +struct segments_begin<Polygon, polygon_tag> +{ + typedef typename detail::point_iterator::inner_range_type + < + Polygon + >::type inner_range; + + typedef typename detail::segment_iterator::iterator_type + < + Polygon + >::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (segments_begin + < + inner_range + >::apply(geometry::exterior_ring(polygon)), + segments_end + < + inner_range + >::apply(geometry::exterior_ring(polygon)), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ) + ); + } +}; + + +template <typename MultiLinestring> +struct segments_begin<MultiLinestring, multi_linestring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + MultiLinestring + >::type return_type; + + static inline return_type apply(MultiLinestring& multilinestring) + { + return return_type(boost::begin(multilinestring), + boost::end(multilinestring)); + } +}; + + +template <typename MultiPolygon> +struct segments_begin<MultiPolygon, multi_polygon_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + MultiPolygon + >::type return_type; + + static inline return_type apply(MultiPolygon& multipolygon) + { + return return_type(boost::begin(multipolygon), + boost::end(multipolygon)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for segments_end + + +template <typename Linestring> +struct segments_end<Linestring, linestring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + Linestring + >::type return_type; + + static inline return_type apply(Linestring& linestring) + { + return return_type(linestring, true); + } +}; + + +template <typename Ring> +struct segments_end<Ring, ring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + Ring + >::type return_type; + + static inline return_type apply(Ring& ring) + { + return return_type(ring, true); + } +}; + + +template <typename Polygon> +struct segments_end<Polygon, polygon_tag> +{ + typedef typename detail::point_iterator::inner_range_type + < + Polygon + >::type inner_range; + + typedef typename detail::segment_iterator::iterator_type + < + Polygon + >::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (segments_end + < + inner_range + >::apply(geometry::exterior_ring(polygon)), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ), + flatten_iterator( boost::end(geometry::interior_rings(polygon)) ) + ); + } +}; + + +template <typename MultiLinestring> +struct segments_end<MultiLinestring, multi_linestring_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + MultiLinestring + >::type return_type; + + static inline return_type apply(MultiLinestring& multilinestring) + { + return return_type(boost::end(multilinestring)); + } +}; + + +template <typename MultiPolygon> +struct segments_end<MultiPolygon, multi_polygon_tag> +{ + typedef typename detail::segment_iterator::iterator_type + < + MultiPolygon + >::type return_type; + + static inline return_type apply(MultiPolygon& multipolygon) + { + return return_type(boost::end(multipolygon)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +// MK:: need to add doc here +template <typename Geometry> +class segment_iterator + : public detail::segment_iterator::iterator_type<Geometry>::type +{ +private: + typedef typename detail::segment_iterator::iterator_type + < + Geometry + >::type base; + + inline base const* base_ptr() const + { + return this; + } + + template <typename OtherGeometry> friend class segment_iterator; + + template <typename G> + friend inline segment_iterator<G const> segments_begin(G const&); + + template <typename G> + friend inline segment_iterator<G const> segments_end(G const&); + + inline segment_iterator(base const& base_it) : base(base_it) {} + +public: + inline segment_iterator() {} + + template <typename OtherGeometry> + inline segment_iterator(segment_iterator<OtherGeometry> const& other) + : base(*other.base_ptr()) + { + static const bool is_conv + = boost::is_convertible< + typename detail::segment_iterator::iterator_type + < + OtherGeometry + >::type, + typename detail::segment_iterator::iterator_type<Geometry>::type + >::value; + + BOOST_MPL_ASSERT_MSG((is_conv), + NOT_CONVERTIBLE, + (segment_iterator<OtherGeometry>)); + } +}; + + +// MK:: need to add doc here +template <typename Geometry> +inline segment_iterator<Geometry const> +segments_begin(Geometry const& geometry) +{ + return dispatch::segments_begin<Geometry const>::apply(geometry); +} + + +// MK:: need to add doc here +template <typename Geometry> +inline segment_iterator<Geometry const> +segments_end(Geometry const& geometry) +{ + return dispatch::segments_end<Geometry const>::apply(geometry); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP diff --git a/boost/geometry/multi/algorithms/append.hpp b/boost/geometry/multi/algorithms/append.hpp index e72be036ae..d1589aca84 100644 --- a/boost/geometry/multi/algorithms/append.hpp +++ b/boost/geometry/multi/algorithms/append.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,39 +20,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP -#include <boost/geometry/algorithms/append.hpp> - -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -namespace splitted_dispatch -{ -template <typename Geometry, typename Point> -struct append_point<multi_point_tag, Geometry, Point> - : detail::append::append_point<Geometry, Point> -{}; - -template <typename Geometry, typename Range> -struct append_range<multi_point_tag, Geometry, Range> - : detail::append::append_range<Geometry, Range> -{}; - -} - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry +#include <boost/geometry/algorithms/append.hpp> #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP diff --git a/boost/geometry/multi/algorithms/area.hpp b/boost/geometry/multi/algorithms/area.hpp index 6695686358..0e25ffc64e 100644 --- a/boost/geometry/multi/algorithms/area.hpp +++ b/boost/geometry/multi/algorithms/area.hpp @@ -15,43 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/area.hpp> -#include <boost/geometry/multi/core/point_type.hpp> -#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ -template <typename MultiGeometry, typename Strategy> -struct area<MultiGeometry, Strategy, multi_polygon_tag> - : detail::multi_sum - < - typename Strategy::return_type, - MultiGeometry, - Strategy, - area - < - typename boost::range_value<MultiGeometry>::type, - Strategy, - polygon_tag - > - > -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP diff --git a/boost/geometry/multi/algorithms/centroid.hpp b/boost/geometry/multi/algorithms/centroid.hpp index 855ed22fda..1c9902f2bf 100644 --- a/boost/geometry/multi/algorithms/centroid.hpp +++ b/boost/geometry/multi/algorithms/centroid.hpp @@ -15,163 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP -#include <boost/range.hpp> - #include <boost/geometry/algorithms/centroid.hpp> -#include <boost/geometry/multi/core/point_type.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace centroid -{ - - -/*! - \brief Building block of a multi-point, to be used as Policy in the - more generec centroid_multi -*/ -template -< - typename Point, - typename Strategy -> -struct centroid_multi_point_state -{ - static inline void apply(Point const& point, - Strategy const& strategy, typename Strategy::state_type& state) - { - strategy.apply(point, state); - } -}; - - - -/*! - \brief Generic implementation which calls a policy to calculate the - centroid of the total of its single-geometries - \details The Policy is, in general, the single-version, with state. So - detail::centroid::centroid_polygon_state is used as a policy for this - detail::centroid::centroid_multi - -*/ -template -< - typename Multi, - typename Point, - typename Strategy, - typename Policy -> -struct centroid_multi -{ - static inline void apply(Multi const& multi, Point& centroid, - Strategy const& strategy) - { -#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) - // If there is nothing in any of the ranges, it is not possible - // to calculate the centroid - if (geometry::num_points(multi) == 0) - { - throw centroid_exception(); - } -#endif - - typename Strategy::state_type state; - - for (typename boost::range_iterator<Multi const>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it) - { - Policy::apply(*it, strategy, state); - } - Strategy::result(state, centroid); - } -}; - - - -}} // namespace detail::centroid -#endif // DOXYGEN_NO_DETAIL - - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -< - typename MultiLinestring, - typename Point, - typename Strategy -> -struct centroid<multi_linestring_tag, MultiLinestring, Point, Strategy> - : detail::centroid::centroid_multi - < - MultiLinestring, - Point, - Strategy, - detail::centroid::centroid_range_state - < - typename boost::range_value<MultiLinestring>::type, - closed, - Strategy - > - > -{}; - -template -< - typename MultiPolygon, - typename Point, - typename Strategy -> -struct centroid<multi_polygon_tag, MultiPolygon, Point, Strategy> - : detail::centroid::centroid_multi - < - MultiPolygon, - Point, - Strategy, - detail::centroid::centroid_polygon_state - < - typename boost::range_value<MultiPolygon>::type, - Strategy - > - > -{}; - - -template -< - typename MultiPoint, - typename Point, - typename Strategy -> -struct centroid<multi_point_tag, MultiPoint, Point, Strategy> - : detail::centroid::centroid_multi - < - MultiPoint, - Point, - Strategy, - detail::centroid::centroid_multi_point_state - < - typename boost::range_value<MultiPoint>::type, - Strategy - > - > -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP diff --git a/boost/geometry/multi/algorithms/clear.hpp b/boost/geometry/multi/algorithms/clear.hpp index 0b14b6ce9c..6d9e284d0a 100644 --- a/boost/geometry/multi/algorithms/clear.hpp +++ b/boost/geometry/multi/algorithms/clear.hpp @@ -15,29 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/clear.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Geometry> -struct clear<Geometry, multi_tag> - : detail::clear::collection_clear<Geometry> -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP diff --git a/boost/geometry/multi/algorithms/convert.hpp b/boost/geometry/multi/algorithms/convert.hpp index 4745791135..0e7b2946d4 100644 --- a/boost/geometry/multi/algorithms/convert.hpp +++ b/boost/geometry/multi/algorithms/convert.hpp @@ -15,114 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/convert.hpp> -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace conversion -{ - -template <typename Single, typename Multi, typename Policy> -struct single_to_multi: private Policy -{ - static inline void apply(Single const& single, Multi& multi) - { - traits::resize<Multi>::apply(multi, 1); - Policy::apply(single, *boost::begin(multi)); - } -}; - - - -template <typename Multi1, typename Multi2, typename Policy> -struct multi_to_multi: private Policy -{ - static inline void apply(Multi1 const& multi1, Multi2& multi2) - { - traits::resize<Multi2>::apply(multi2, boost::size(multi1)); - - typename boost::range_iterator<Multi1 const>::type it1 - = boost::begin(multi1); - typename boost::range_iterator<Multi2>::type it2 - = boost::begin(multi2); - - for (; it1 != boost::end(multi1); ++it1, ++it2) - { - Policy::apply(*it1, *it2); - } - } -}; - - -}} // namespace detail::convert -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -// Dispatch for multi <-> multi, specifying their single-version as policy. -// Note that, even if the multi-types are mutually different, their single -// version types might be the same and therefore we call boost::is_same again - -template <typename Multi1, typename Multi2, std::size_t DimensionCount> -struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false> - : detail::conversion::multi_to_multi - < - Multi1, - Multi2, - convert - < - typename boost::range_value<Multi1>::type, - typename boost::range_value<Multi2>::type, - typename single_tag_of - < - typename tag<Multi1>::type - >::type, - typename single_tag_of - < - typename tag<Multi2>::type - >::type, - DimensionCount - > - > -{}; - -template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount> -struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false> - : detail::conversion::single_to_multi - < - Single, - Multi, - convert - < - Single, - typename boost::range_value<Multi>::type, - typename tag<Single>::type, - typename single_tag_of - < - typename tag<Multi>::type - >::type, - DimensionCount, - false - > - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP diff --git a/boost/geometry/multi/algorithms/correct.hpp b/boost/geometry/multi/algorithms/correct.hpp index d0c3e10753..83d26ca60c 100644 --- a/boost/geometry/multi/algorithms/correct.hpp +++ b/boost/geometry/multi/algorithms/correct.hpp @@ -15,52 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/correct.hpp> -#include <boost/geometry/multi/algorithms/detail/modify.hpp> - -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename MultiPoint> -struct correct<MultiPoint, multi_point_tag> - : detail::correct::correct_nop<MultiPoint> -{}; - - -template <typename MultiLineString> -struct correct<MultiLineString, multi_linestring_tag> - : detail::correct::correct_nop<MultiLineString> -{}; - - -template <typename Geometry> -struct correct<Geometry, multi_polygon_tag> - : detail::multi_modify - < - Geometry, - detail::correct::correct_polygon - < - typename boost::range_value<Geometry>::type - > - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP diff --git a/boost/geometry/multi/algorithms/covered_by.hpp b/boost/geometry/multi/algorithms/covered_by.hpp index ba398c0f42..706bc78475 100644 --- a/boost/geometry/multi/algorithms/covered_by.hpp +++ b/boost/geometry/multi/algorithms/covered_by.hpp @@ -3,6 +3,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,60 +15,13 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP #include <boost/geometry/algorithms/covered_by.hpp> -#include <boost/geometry/multi/core/closure.hpp> -#include <boost/geometry/multi/core/point_order.hpp> -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/algorithms/within.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Point, typename MultiPolygon> -struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag> -{ - template <typename Strategy> - static inline bool apply(Point const& point, - MultiPolygon const& multi_polygon, Strategy const& strategy) - { - return detail::within::geometry_multi_within_code - < - Point, - MultiPolygon, - Strategy, - detail::within::point_in_polygon - < - Point, - typename boost::range_value<MultiPolygon>::type, - order_as_direction - < - geometry::point_order<MultiPolygon>::value - >::value, - geometry::closure<MultiPolygon>::value, - Strategy - > - >::apply(point, multi_polygon, strategy) >= 0; - } -}; - - -} // namespace dispatch - - -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP diff --git a/boost/geometry/multi/algorithms/detail/extreme_points.hpp b/boost/geometry/multi/algorithms/detail/extreme_points.hpp new file mode 100644 index 0000000000..da2ac5e9fa --- /dev/null +++ b/boost/geometry/multi/algorithms/detail/extreme_points.hpp @@ -0,0 +1,19 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP + + +#include <boost/geometry/algorithms/detail/extreme_points.hpp> + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP diff --git a/boost/geometry/multi/algorithms/detail/for_each_range.hpp b/boost/geometry/multi/algorithms/detail/for_each_range.hpp index 08ab14bd69..2fe475ed58 100644 --- a/boost/geometry/multi/algorithms/detail/for_each_range.hpp +++ b/boost/geometry/multi/algorithms/detail/for_each_range.hpp @@ -15,72 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP -#include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> - #include <boost/geometry/algorithms/detail/for_each_range.hpp> -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace for_each -{ - - -template <typename Multi, typename Actor, bool IsConst> -struct fe_range_multi -{ - static inline void apply( - typename add_const_if_c<IsConst, Multi>::type& multi, - Actor& actor) - { - for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it) - { - geometry::detail::for_each_range(*it, actor); - } - } -}; - - - -}} // namespace detail::for_each -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename MultiPoint, typename Actor, bool IsConst> -struct for_each_range<multi_point_tag, MultiPoint, Actor, IsConst> - : detail::for_each::fe_range_range<MultiPoint, Actor, IsConst> -{}; - -template <typename Geometry, typename Actor, bool IsConst> -struct for_each_range<multi_linestring_tag, Geometry, Actor, IsConst> - : - detail::for_each::fe_range_multi<Geometry, Actor, IsConst> -{}; - -template <typename Geometry, typename Actor, bool IsConst> -struct for_each_range<multi_polygon_tag, Geometry, Actor, IsConst> - : - detail::for_each::fe_range_multi<Geometry, Actor, IsConst> -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - - -}} // namespace boost::geometry - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP diff --git a/boost/geometry/multi/algorithms/detail/modify.hpp b/boost/geometry/multi/algorithms/detail/modify.hpp index b52efd2512..ae52e002f0 100644 --- a/boost/geometry/multi/algorithms/detail/modify.hpp +++ b/boost/geometry/multi/algorithms/detail/modify.hpp @@ -15,39 +15,7 @@ #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 +#include <boost/geometry/algorithms/detail/multi_modify.hpp> #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 index 4ae79058da..1a82a67142 100644 --- a/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp +++ b/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp @@ -15,38 +15,7 @@ #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 +#include <boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp> #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 index a47685ceb1..b91970a164 100644 --- a/boost/geometry/multi/algorithms/detail/multi_sum.hpp +++ b/boost/geometry/multi/algorithms/detail/multi_sum.hpp @@ -11,48 +11,11 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_MULTI_SUM_HPP -#define BOOST_GEOMETRY_MULTI_SUM_HPP - -#include <boost/range.hpp> - - -namespace boost { namespace geometry -{ -#ifndef DOXYGEN_NO_DETAIL -namespace detail -{ - -template -< - typename ReturnType, - typename MultiGeometry, - typename Strategy, - typename Policy -> -struct multi_sum -{ - static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy) - { - ReturnType sum = ReturnType(); - for (typename boost::range_iterator - < - MultiGeometry const - >::type it = boost::begin(geometry); - it != boost::end(geometry); - ++it) - { - sum += Policy::apply(*it, strategy); - } - return sum; - } -}; - - -} // namespace detail -#endif - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_MULTI_SUM_HPP +#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MULTI_SUM_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MULTI_SUM_HPP + + +#include <boost/geometry/algorithms/detail/multi_sum.hpp> + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_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 index 72be5ddbf4..5e23cf4bad 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -10,92 +13,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP -#include <boost/range.hpp> - -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace copy_segments -{ - - -template -< - typename MultiGeometry, - typename SegmentIdentifier, - typename PointOut, - typename Policy -> -struct copy_segment_point_multi -{ - static inline bool apply(MultiGeometry const& multi, - SegmentIdentifier const& seg_id, bool second, - PointOut& point) - { - - BOOST_ASSERT - ( - seg_id.multi_index >= 0 - && seg_id.multi_index < 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 index f474b12fdf..54114bfae4 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp @@ -10,95 +10,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP -#include <boost/assert.hpp> -#include <boost/range.hpp> - #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> -#include <boost/geometry/multi/core/ring_type.hpp> -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace copy_segments -{ - - -template -< - typename MultiGeometry, - typename SegmentIdentifier, - typename RangeOut, - typename Policy -> -struct copy_segments_multi -{ - static inline void apply(MultiGeometry const& multi_geometry, - SegmentIdentifier const& seg_id, int to_index, - RangeOut& current_output) - { - - BOOST_ASSERT - ( - seg_id.multi_index >= 0 - && seg_id.multi_index < 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 index e23acf99b3..65e00d064b 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp @@ -10,45 +10,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP -#include <boost/assert.hpp> -#include <boost/range.hpp> - #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> -#include <boost/geometry/multi/core/ring_type.hpp> - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - -template<> -struct get_ring<multi_polygon_tag> -{ - template<typename MultiPolygon> - static inline typename ring_type<MultiPolygon>::type const& apply( - ring_identifier const& id, - MultiPolygon const& multi_polygon) - { - BOOST_ASSERT - ( - id.multi_index >= 0 - && id.multi_index < 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 index 1ee03cc4d0..a83fb77393 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp @@ -10,102 +10,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP -#include <boost/geometry/multi/core/ring_type.hpp> - #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> -#include <boost/geometry/multi/algorithms/distance.hpp> -#include <boost/geometry/multi/views/detail/range_type.hpp> - -#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> -#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace get_turns -{ - -template -< - typename Multi, typename Box, - bool Reverse, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy -> -struct get_turns_multi_polygon_cs -{ - static inline void apply( - int source_id1, Multi const& multi, - int source_id2, Box const& box, - Turns& turns, InterruptPolicy& interrupt_policy) - { - typedef typename boost::range_iterator - < - Multi const - >::type iterator_type; - - int i = 0; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it, ++i) - { - // Call its single version - get_turns_polygon_cs - < - typename boost::range_value<Multi>::type, Box, - Reverse, ReverseBox, - Turns, TurnPolicy, InterruptPolicy - >::apply(source_id1, *it, source_id2, box, - turns, interrupt_policy, i); - } - } -}; - -}} // namespace detail::get_turns -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template -< - typename MultiPolygon, - typename Box, - bool ReverseMultiPolygon, bool ReverseBox, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy -> -struct get_turns - < - multi_polygon_tag, box_tag, - MultiPolygon, Box, - ReverseMultiPolygon, ReverseBox, - Turns, - TurnPolicy, InterruptPolicy - > - : detail::get_turns::get_turns_multi_polygon_cs - < - MultiPolygon, Box, - ReverseMultiPolygon, ReverseBox, - Turns, - TurnPolicy, InterruptPolicy - > -{}; - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp index 4636187880..c780c4cd9a 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp @@ -10,53 +10,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP -#include <boost/range.hpp> - #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - -namespace dispatch -{ - - template <typename Multi> - struct select_rings<multi_polygon_tag, Multi> - { - template <typename Geometry, typename Map> - static inline void apply(Multi const& multi, Geometry const& geometry, - ring_identifier id, Map& map, bool midpoint) - { - typedef typename boost::range_iterator - < - Multi const - >::type iterator_type; - - typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon; - - id.multi_index = 0; - for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) - { - id.ring_index = -1; - per_polygon::apply(*it, geometry, id, map, midpoint); - id.multi_index++; - } - } - }; -} - - -}} // namespace detail::overlay -#endif // DOXYGEN_NO_DETAIL - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP diff --git a/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp index 57d5ff92ca..39bfea2fb3 100644 --- a/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp @@ -10,47 +10,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template -< - typename MultiPolygon, - typename Turns, - typename TurnPolicy, - typename InterruptPolicy -> -struct self_get_turn_points - < - multi_polygon_tag, MultiPolygon, - Turns, - TurnPolicy, InterruptPolicy - > - : detail::self_get_turn_points::get_turns - < - MultiPolygon, - Turns, - TurnPolicy, - InterruptPolicy - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP diff --git a/boost/geometry/multi/algorithms/detail/point_on_border.hpp b/boost/geometry/multi/algorithms/detail/point_on_border.hpp index ac462ed4c5..2ee789c5da 100644 --- a/boost/geometry/multi/algorithms/detail/point_on_border.hpp +++ b/boost/geometry/multi/algorithms/detail/point_on_border.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,82 +17,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP -#include <boost/range.hpp> -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace point_on_border -{ - - -template -< - typename 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 index 28a4805ed1..5604d9d74f 100644 --- a/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp +++ b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,80 +14,13 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP -#include <boost/assert.hpp> -#include <boost/range.hpp> - -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/core/ring_type.hpp> #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace section -{ - - -template -< - typename MultiGeometry, - typename Section, - typename Policy -> -struct full_section_multi -{ - static inline typename ring_return_type<MultiGeometry const>::type apply( - MultiGeometry const& multi, Section const& section) - { - BOOST_ASSERT - ( - section.ring_id.multi_index >= 0 - && section.ring_id.multi_index < 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 index 16f70c193d..ef98021237 100644 --- a/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp +++ b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,82 +17,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP -#include <cstddef> -#include <vector> - -#include <boost/concept/requires.hpp> -#include <boost/range.hpp> #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace sectionalize -{ - - -template <typename MultiGeometry, typename Sections, std::size_t DimensionCount, typename Policy> -struct sectionalize_multi -{ - static inline void apply(MultiGeometry const& multi, Sections& sections, ring_identifier ring_id) - { - ring_id.multi_index = 0; - for (typename boost::range_iterator<MultiGeometry const>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it, ++ring_id.multi_index) - { - Policy::apply(*it, sections, ring_id); - } - } -}; - - -}} // namespace detail::sectionalize -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template -< - typename MultiPolygon, - bool Reverse, - typename Sections, - std::size_t DimensionCount, - std::size_t MaxCount -> -struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, Sections, DimensionCount, MaxCount> - : detail::sectionalize::sectionalize_multi - < - MultiPolygon, - Sections, - DimensionCount, - detail::sectionalize::sectionalize_polygon - < - typename boost::range_value<MultiPolygon>::type, - Reverse, - Sections, - DimensionCount, - MaxCount - > - > - -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP diff --git a/boost/geometry/multi/algorithms/disjoint.hpp b/boost/geometry/multi/algorithms/disjoint.hpp new file mode 100644 index 0000000000..55f0f01cd6 --- /dev/null +++ b/boost/geometry/multi/algorithms/disjoint.hpp @@ -0,0 +1,21 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2012-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// 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> + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP diff --git a/boost/geometry/multi/algorithms/distance.hpp b/boost/geometry/multi/algorithms/distance.hpp index 8acb3f9006..4946b6f3e1 100644 --- a/boost/geometry/multi/algorithms/distance.hpp +++ b/boost/geometry/multi/algorithms/distance.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,144 +19,9 @@ #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> +// this file is intentionally empty (with the exception of the #include below) +// it is used for backward compatinility and may be removed in the future #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 index 1876b5f91e..457dfaf3bc 100644 --- a/boost/geometry/multi/algorithms/envelope.hpp +++ b/boost/geometry/multi/algorithms/envelope.hpp @@ -14,104 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP -#include <vector> -#include <boost/range/metafunctions.hpp> - - -#include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/algorithms/envelope.hpp> -#include <boost/geometry/multi/core/point_type.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL - -namespace detail { namespace envelope -{ - - -template<typename MultiLinestring, typename Box> -struct envelope_multi_linestring -{ - static inline void apply(MultiLinestring const& mp, Box& mbr) - { - assign_inverse(mbr); - for (typename boost::range_iterator<MultiLinestring const>::type - it = mp.begin(); - it != mp.end(); - ++it) - { - envelope_range_additional(*it, mbr); - } - } -}; - - -// version for multi_polygon: outer ring's of all polygons -template<typename MultiPolygon, typename Box> -struct envelope_multi_polygon -{ - static inline void apply(MultiPolygon const& mp, Box& mbr) - { - assign_inverse(mbr); - for (typename boost::range_const_iterator<MultiPolygon>::type - it = mp.begin(); - it != mp.end(); - ++it) - { - envelope_range_additional(exterior_ring(*it), mbr); - } - } -}; - - -}} // namespace detail::envelope - -#endif - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -< - typename Multi, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope<multi_point_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> - : detail::envelope::envelope_range<Multi, Box> -{}; - -template -< - typename Multi, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope<multi_linestring_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> - : detail::envelope::envelope_multi_linestring<Multi, Box> -{}; - - -template -< - typename Multi, typename Box, - typename StrategyLess, typename StrategyGreater -> -struct envelope<multi_polygon_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater> - : detail::envelope::envelope_multi_polygon<Multi, Box> -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP diff --git a/boost/geometry/multi/algorithms/equals.hpp b/boost/geometry/multi/algorithms/equals.hpp index a307ebae8b..0f045fff90 100644 --- a/boost/geometry/multi/algorithms/equals.hpp +++ b/boost/geometry/multi/algorithms/equals.hpp @@ -15,56 +15,8 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/core/geometry_id.hpp> - #include <boost/geometry/algorithms/equals.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename MultiPolygon1, typename MultiPolygon2> -struct equals - < - multi_polygon_tag, multi_polygon_tag, - MultiPolygon1, MultiPolygon2, - 2 - > - : detail::equals::equals_by_collection - < - MultiPolygon1, MultiPolygon2, - detail::equals::area_check - > -{}; - - -template <typename Polygon, typename MultiPolygon> -struct equals - < - polygon_tag, multi_polygon_tag, - Polygon, MultiPolygon, - 2 - > - : detail::equals::equals_by_collection - < - Polygon, MultiPolygon, - detail::equals::area_check - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP diff --git a/boost/geometry/multi/algorithms/for_each.hpp b/boost/geometry/multi/algorithms/for_each.hpp index 1be38e0a7e..d8b3af1ff2 100644 --- a/boost/geometry/multi/algorithms/for_each.hpp +++ b/boost/geometry/multi/algorithms/for_each.hpp @@ -15,115 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP -#include <boost/range.hpp> -#include <boost/typeof/typeof.hpp> - -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/core/point_type.hpp> - - #include <boost/geometry/algorithms/for_each.hpp> - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace for_each -{ - -// Implementation of multi, for both point and segment, -// just calling the single version. -template -< - typename MultiGeometry, - typename Functor, - bool IsConst, - typename Policy -> -struct for_each_multi -{ - static inline Functor apply( - typename add_const_if_c<IsConst, MultiGeometry>::type& multi, - Functor f) - { - for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it) - { - f = Policy::apply(*it, f); - } - return f; - } -}; - - -}} // namespace detail::for_each -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -< - typename MultiGeometry, - typename Functor, - bool IsConst -> -struct for_each_point<multi_tag, MultiGeometry, Functor, IsConst> - : detail::for_each::for_each_multi - < - MultiGeometry, - Functor, - IsConst, - // Specify the dispatch of the single-version as policy - for_each_point - < - typename single_tag_of - < - typename tag<MultiGeometry>::type - >::type, - typename boost::range_value<MultiGeometry>::type, - Functor, - IsConst - > - > -{}; - - -template -< - typename MultiGeometry, - typename Functor, - bool IsConst -> -struct for_each_segment<multi_tag, MultiGeometry, Functor, IsConst> - : detail::for_each::for_each_multi - < - MultiGeometry, - Functor, - IsConst, - // Specify the dispatch of the single-version as policy - for_each_segment - < - typename single_tag_of - < - typename tag<MultiGeometry>::type - >::type, - typename boost::range_value<MultiGeometry>::type, - Functor, - IsConst - > - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP diff --git a/boost/geometry/multi/algorithms/intersection.hpp b/boost/geometry/multi/algorithms/intersection.hpp index 31e74a79ba..f434463253 100644 --- a/boost/geometry/multi/algorithms/intersection.hpp +++ b/boost/geometry/multi/algorithms/intersection.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -10,429 +15,8 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP -#include <boost/geometry/multi/core/closure.hpp> -#include <boost/geometry/multi/core/geometry_id.hpp> -#include <boost/geometry/multi/core/is_areal.hpp> -#include <boost/geometry/multi/core/point_order.hpp> -#include <boost/geometry/multi/algorithms/covered_by.hpp> -#include <boost/geometry/multi/algorithms/envelope.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp> -#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> -#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> - #include <boost/geometry/algorithms/intersection.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace intersection -{ - - -template -< - typename MultiLinestring1, typename MultiLinestring2, - typename OutputIterator, typename PointOut, - typename Strategy -> -struct intersection_multi_linestring_multi_linestring_point -{ - static inline OutputIterator apply(MultiLinestring1 const& ml1, - MultiLinestring2 const& ml2, OutputIterator out, - Strategy const& strategy) - { - // Note, this loop is quadratic w.r.t. number of linestrings per input. - // Future Enhancement: first do the sections of each, then intersect. - for (typename boost::range_iterator - < - MultiLinestring1 const - >::type it1 = boost::begin(ml1); - it1 != boost::end(ml1); - ++it1) - { - for (typename boost::range_iterator - < - MultiLinestring2 const - >::type it2 = boost::begin(ml2); - it2 != boost::end(ml2); - ++it2) - { - out = intersection_linestring_linestring_point - < - typename boost::range_value<MultiLinestring1>::type, - typename boost::range_value<MultiLinestring2>::type, - OutputIterator, PointOut, Strategy - >::apply(*it1, *it2, out, strategy); - } - } - - return out; - } -}; - - -template -< - typename Linestring, typename MultiLinestring, - typename OutputIterator, typename PointOut, - typename Strategy -> -struct intersection_linestring_multi_linestring_point -{ - static inline OutputIterator apply(Linestring const& linestring, - MultiLinestring const& ml, OutputIterator out, - Strategy const& strategy) - { - for (typename boost::range_iterator - < - MultiLinestring const - >::type it = boost::begin(ml); - it != boost::end(ml); - ++it) - { - out = intersection_linestring_linestring_point - < - Linestring, - typename boost::range_value<MultiLinestring>::type, - OutputIterator, PointOut, Strategy - >::apply(linestring, *it, out, strategy); - } - - return out; - } -}; - - -// This loop is quite similar to the loop above, but beacuse the iterator -// is second (above) or first (below) argument, it is not trivial to merge them. -template -< - typename MultiLinestring, typename Areal, - bool ReverseAreal, - typename OutputIterator, typename LineStringOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_of_multi_linestring_with_areal -{ - static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal, - OutputIterator out, - Strategy const& strategy) - { - for (typename boost::range_iterator - < - MultiLinestring const - >::type it = boost::begin(ml); - it != boost::end(ml); - ++it) - { - out = intersection_of_linestring_with_areal - < - typename boost::range_value<MultiLinestring>::type, - Areal, ReverseAreal, - OutputIterator, LineStringOut, OverlayType, Strategy - >::apply(*it, areal, out, strategy); - } - - return out; - - } -}; - -// This one calls the one above with reversed arguments -template -< - typename Areal, typename MultiLinestring, - bool ReverseAreal, - typename OutputIterator, typename LineStringOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_of_areal_with_multi_linestring -{ - static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, - OutputIterator out, - Strategy const& strategy) - { - return intersection_of_multi_linestring_with_areal - < - MultiLinestring, Areal, ReverseAreal, - OutputIterator, LineStringOut, - OverlayType, - Strategy - >::apply(ml, areal, out, strategy); - } -}; - - - -template -< - typename MultiLinestring, typename Box, - typename OutputIterator, typename LinestringOut, - typename Strategy -> -struct clip_multi_linestring -{ - static inline OutputIterator apply(MultiLinestring const& multi_linestring, - Box const& box, OutputIterator out, Strategy const& ) - { - typedef typename point_type<LinestringOut>::type point_type; - strategy::intersection::liang_barsky<Box, point_type> lb_strategy; - for (typename boost::range_iterator<MultiLinestring const>::type it - = boost::begin(multi_linestring); - it != boost::end(multi_linestring); ++it) - { - out = detail::intersection::clip_range_with_box - <LinestringOut>(box, *it, out, lb_strategy); - } - return out; - } -}; - - -}} // namespace detail::intersection -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -// Linear -template -< - typename MultiLinestring1, typename MultiLinestring2, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - multi_linestring_tag, multi_linestring_tag, point_tag, - false, false, false, - MultiLinestring1, MultiLinestring2, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_multi_linestring_multi_linestring_point - < - MultiLinestring1, MultiLinestring2, - OutputIterator, GeometryOut, - Strategy - > -{}; - - -template -< - typename Linestring, typename MultiLinestring, - typename OutputIterator, typename GeometryOut, - bool Reverse1, bool Reverse2, bool ReverseOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - linestring_tag, multi_linestring_tag, point_tag, - false, false, false, - Linestring, MultiLinestring, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_linestring_multi_linestring_point - < - Linestring, MultiLinestring, - OutputIterator, GeometryOut, - Strategy - > -{}; - - -template -< - typename MultiLinestring, typename Box, - bool Reverse1, bool Reverse2, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - multi_linestring_tag, box_tag, linestring_tag, - false, true, false, - MultiLinestring, Box, - Reverse1, Reverse2, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::clip_multi_linestring - < - MultiLinestring, Box, - OutputIterator, GeometryOut, - Strategy - > -{}; - - -template -< - typename Linestring, typename MultiPolygon, - bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - linestring_tag, multi_polygon_tag, linestring_tag, - false, true, false, - Linestring, MultiPolygon, - ReverseLinestring, ReverseMultiPolygon, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_of_linestring_with_areal - < - Linestring, MultiPolygon, - ReverseMultiPolygon, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > -{}; - - -// Derives from areal/mls because runtime arguments are in that order. -// areal/mls reverses it itself to mls/areal -template -< - typename Polygon, typename MultiLinestring, - bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - polygon_tag, multi_linestring_tag, linestring_tag, - true, false, false, - Polygon, MultiLinestring, - ReversePolygon, ReverseMultiLinestring, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_of_areal_with_multi_linestring - < - Polygon, MultiLinestring, - ReversePolygon, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > -{}; - - -template -< - typename MultiLinestring, typename Ring, - bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - multi_linestring_tag, ring_tag, linestring_tag, - false, true, false, - MultiLinestring, Ring, - ReverseMultiLinestring, ReverseRing, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_of_multi_linestring_with_areal - < - MultiLinestring, Ring, - ReverseRing, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > -{}; - -template -< - typename MultiLinestring, typename Polygon, - bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - multi_linestring_tag, polygon_tag, linestring_tag, - false, true, false, - MultiLinestring, Polygon, - ReverseMultiLinestring, ReverseRing, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_of_multi_linestring_with_areal - < - MultiLinestring, Polygon, - ReverseRing, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > -{}; - - - -template -< - typename MultiLinestring, typename MultiPolygon, - bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut, - typename OutputIterator, typename GeometryOut, - overlay_type OverlayType, - typename Strategy -> -struct intersection_insert - < - multi_linestring_tag, multi_polygon_tag, linestring_tag, - false, true, false, - MultiLinestring, MultiPolygon, - ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > : detail::intersection::intersection_of_multi_linestring_with_areal - < - MultiLinestring, MultiPolygon, - ReverseMultiPolygon, - OutputIterator, GeometryOut, - OverlayType, - Strategy - > -{}; - - -} // namespace dispatch -#endif - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP diff --git a/boost/geometry/multi/algorithms/length.hpp b/boost/geometry/multi/algorithms/length.hpp index 51ff9ef3c2..168e6a732f 100644 --- a/boost/geometry/multi/algorithms/length.hpp +++ b/boost/geometry/multi/algorithms/length.hpp @@ -15,43 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/length.hpp> -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename MultiLinestring, typename Strategy> -struct length<multi_linestring_tag, MultiLinestring, Strategy> - : detail::multi_sum - < - typename default_length_result<MultiLinestring>::type, - MultiLinestring, - Strategy, - detail::length::range_length - < - typename boost::range_value<MultiLinestring>::type, - Strategy, - closed // no need to close it explicitly - > - > -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP diff --git a/boost/geometry/multi/algorithms/num_geometries.hpp b/boost/geometry/multi/algorithms/num_geometries.hpp index 213339a18c..3a85f4e4bf 100644 --- a/boost/geometry/multi/algorithms/num_geometries.hpp +++ b/boost/geometry/multi/algorithms/num_geometries.hpp @@ -16,36 +16,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP -#include <cstddef> - -#include <boost/range.hpp> - #include <boost/geometry/algorithms/num_geometries.hpp> -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename MultiGeometry> -struct num_geometries<multi_tag, MultiGeometry> -{ - static inline std::size_t apply(MultiGeometry const& multi_geometry) - { - return boost::size(multi_geometry); - } -}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP diff --git a/boost/geometry/multi/algorithms/num_interior_rings.hpp b/boost/geometry/multi/algorithms/num_interior_rings.hpp index 87b0bdea91..fbaa113aff 100644 --- a/boost/geometry/multi/algorithms/num_interior_rings.hpp +++ b/boost/geometry/multi/algorithms/num_interior_rings.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,48 +19,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP -#include <cstddef> - -#include <boost/range.hpp> - -#include <boost/geometry/core/tag.hpp> -#include <boost/geometry/core/tags.hpp> -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename MultiPolygon> -struct num_interior_rings<multi_polygon_tag, MultiPolygon> -{ - static inline std::size_t apply(MultiPolygon const& multi_polygon) - { - std::size_t n = 0; - for (typename boost::range_iterator<MultiPolygon const>::type - it = boost::begin(multi_polygon); - it != boost::end(multi_polygon); - ++it) - { - n += geometry::num_interior_rings(*it); - } - return n; - } - -}; - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP diff --git a/boost/geometry/multi/algorithms/num_points.hpp b/boost/geometry/multi/algorithms/num_points.hpp index 5ea53854eb..a736f4254b 100644 --- a/boost/geometry/multi/algorithms/num_points.hpp +++ b/boost/geometry/multi/algorithms/num_points.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,66 +21,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP -#include <boost/range.hpp> - -#include <boost/geometry/multi/core/tags.hpp> #include <boost/geometry/algorithms/num_points.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace num_points -{ - - -template <typename MultiGeometry> -struct multi_count -{ - static inline size_t apply(MultiGeometry const& geometry, bool add_for_open) - { - typedef typename boost::range_value<MultiGeometry>::type geometry_type; - typedef typename boost::range_iterator - < - MultiGeometry const - >::type iterator_type; - - std::size_t n = 0; - for (iterator_type it = boost::begin(geometry); - it != boost::end(geometry); - ++it) - { - n += dispatch::num_points - < - typename tag<geometry_type>::type, - geometry_type - >::apply(*it, add_for_open); - } - return n; - } -}; - - -}} // namespace detail::num_points -#endif - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename Geometry> -struct num_points<multi_tag, Geometry> - : detail::num_points::multi_count<Geometry> {}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP diff --git a/boost/geometry/multi/algorithms/perimeter.hpp b/boost/geometry/multi/algorithms/perimeter.hpp index 147f6fcc30..4820111f1f 100644 --- a/boost/geometry/multi/algorithms/perimeter.hpp +++ b/boost/geometry/multi/algorithms/perimeter.hpp @@ -15,42 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/perimeter.hpp> -#include <boost/geometry/multi/core/tags.hpp> - -#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ -template <typename MultiPolygon, typename Strategy> -struct perimeter<multi_polygon_tag, MultiPolygon, Strategy> - : detail::multi_sum - < - typename default_length_result<MultiPolygon>::type, - MultiPolygon, - Strategy, - perimeter - < - polygon_tag, - typename boost::range_value<MultiPolygon>::type, - Strategy - > - > -{}; - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP diff --git a/boost/geometry/multi/algorithms/remove_spikes.hpp b/boost/geometry/multi/algorithms/remove_spikes.hpp new file mode 100644 index 0000000000..af224ec478 --- /dev/null +++ b/boost/geometry/multi/algorithms/remove_spikes.hpp @@ -0,0 +1,19 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP + + +#include <boost/geometry/algorithms/remove_spikes.hpp> + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP diff --git a/boost/geometry/multi/algorithms/reverse.hpp b/boost/geometry/multi/algorithms/reverse.hpp index f8a9442ac0..a7872bdd2a 100644 --- a/boost/geometry/multi/algorithms/reverse.hpp +++ b/boost/geometry/multi/algorithms/reverse.hpp @@ -15,55 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP -#include <boost/range/metafunctions.hpp> - #include <boost/geometry/algorithms/reverse.hpp> -#include <boost/geometry/multi/algorithms/detail/modify.hpp> - -#include <boost/geometry/multi/core/tags.hpp> - - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename Geometry> -struct reverse<multi_linestring_tag, Geometry> - : detail::multi_modify - < - Geometry, - detail::reverse::range_reverse - < - typename boost::range_value<Geometry>::type - > - > -{}; - - -template <typename Geometry> -struct reverse<multi_polygon_tag, Geometry> - : detail::multi_modify - < - Geometry, - detail::reverse::polygon_reverse - < - typename boost::range_value<Geometry>::type - > - > -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP diff --git a/boost/geometry/multi/algorithms/simplify.hpp b/boost/geometry/multi/algorithms/simplify.hpp index dc3c7b5937..8648d366d1 100644 --- a/boost/geometry/multi/algorithms/simplify.hpp +++ b/boost/geometry/multi/algorithms/simplify.hpp @@ -14,104 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP -#include <boost/range.hpp> -#include <boost/geometry/core/mutable_range.hpp> -#include <boost/geometry/multi/core/tags.hpp> - - -#include <boost/geometry/multi/algorithms/clear.hpp> #include <boost/geometry/algorithms/simplify.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace simplify -{ - -template<typename MultiGeometry, typename Strategy, typename Policy> -struct simplify_multi -{ - static inline void apply(MultiGeometry const& multi, MultiGeometry& out, - double max_distance, Strategy const& strategy) - { - traits::resize<MultiGeometry>::apply(out, boost::size(multi)); - - typename boost::range_iterator<MultiGeometry>::type it_out - = boost::begin(out); - for (typename boost::range_iterator<MultiGeometry const>::type it_in - = boost::begin(multi); - it_in != boost::end(multi); - ++it_in, ++it_out) - { - Policy::apply(*it_in, *it_out, max_distance, strategy); - } - } -}; - - - -}} // namespace detail::simplify -#endif // DOXYGEN_NO_DETAIL - - - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename MultiPoint, typename Strategy> -struct simplify<multi_point_tag, MultiPoint, Strategy> - : detail::simplify::simplify_copy - < - MultiPoint, - Strategy - > - -{}; - - -template <typename MultiLinestring, typename Strategy> -struct simplify<multi_linestring_tag, MultiLinestring, Strategy> - : detail::simplify::simplify_multi - < - MultiLinestring, - Strategy, - detail::simplify::simplify_range - < - typename boost::range_value<MultiLinestring>::type, - Strategy, - 2 - > - > - -{}; - - -template <typename MultiPolygon, typename Strategy> -struct simplify<multi_polygon_tag, MultiPolygon, Strategy> - : detail::simplify::simplify_multi - < - MultiPolygon, - Strategy, - detail::simplify::simplify_polygon - < - typename boost::range_value<MultiPolygon>::type, - Strategy - > - > - -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry - - #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP diff --git a/boost/geometry/multi/algorithms/transform.hpp b/boost/geometry/multi/algorithms/transform.hpp index 09926778f9..7aa691ec4a 100644 --- a/boost/geometry/multi/algorithms/transform.hpp +++ b/boost/geometry/multi/algorithms/transform.hpp @@ -14,89 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP -#include <boost/range.hpp> -#include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/algorithms/transform.hpp> -#include <boost/geometry/multi/core/tags.hpp> - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace transform -{ - -/*! - \brief Is able to transform any multi-geometry, calling the single-version as policy -*/ -template <typename Multi1, typename Multi2, typename Policy> -struct transform_multi -{ - template <typename S> - static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy) - { - traits::resize<Multi2>::apply(multi2, boost::size(multi1)); - - typename boost::range_iterator<Multi1 const>::type it1 - = boost::begin(multi1); - typename boost::range_iterator<Multi2>::type it2 - = boost::begin(multi2); - - for (; it1 != boost::end(multi1); ++it1, ++it2) - { - if (! Policy::apply(*it1, *it2, strategy)) - { - return false; - } - } - - return true; - } -}; - - -}} // namespace detail::transform -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Multi1, typename Multi2, typename Strategy> -struct transform - < - multi_tag, multi_tag, - Multi1, Multi2, - Strategy - > - : detail::transform::transform_multi - < - Multi1, - Multi2, - transform - < - typename single_tag_of - < - typename tag<Multi1>::type - >::type, - typename single_tag_of - < - typename tag<Multi2>::type - >::type, - typename boost::range_value<Multi1>::type, - typename boost::range_value<Multi2>::type, - Strategy - > - > -{}; - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP diff --git a/boost/geometry/multi/algorithms/unique.hpp b/boost/geometry/multi/algorithms/unique.hpp index 5067e71f3f..fa063a312d 100644 --- a/boost/geometry/multi/algorithms/unique.hpp +++ b/boost/geometry/multi/algorithms/unique.hpp @@ -15,88 +15,7 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP -#include <boost/range.hpp> - #include <boost/geometry/algorithms/unique.hpp> -#include <boost/geometry/multi/core/tags.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace unique -{ - - -template <typename MultiGeometry, typename ComparePolicy, typename Policy> -struct multi_unique -{ - static inline void apply(MultiGeometry& multi, ComparePolicy const& compare) - { - for (typename boost::range_iterator<MultiGeometry>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it) - { - Policy::apply(*it, compare); - } - } -}; - - -}} // namespace detail::unique -#endif // DOXYGEN_NO_DETAIL - - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -// For points, unique is not applicable and does nothing -// (Note that it is not "spatially unique" but that it removes duplicate coordinates, -// like std::unique does). Spatially unique is "dissolve" which can (or will be) -// possible for multi-points as well, removing points at the same location. - - -template <typename MultiLineString, typename ComparePolicy> -struct unique<multi_linestring_tag, MultiLineString, ComparePolicy> - : detail::unique::multi_unique - < - MultiLineString, - ComparePolicy, - detail::unique::range_unique - < - typename boost::range_value<MultiLineString>::type, - ComparePolicy - > - > -{}; - - -template <typename MultiPolygon, typename ComparePolicy> -struct unique<multi_polygon_tag, MultiPolygon, ComparePolicy> - : detail::unique::multi_unique - < - MultiPolygon, - ComparePolicy, - detail::unique::polygon_unique - < - typename boost::range_value<MultiPolygon>::type, - ComparePolicy - > - > -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP diff --git a/boost/geometry/multi/algorithms/within.hpp b/boost/geometry/multi/algorithms/within.hpp index a3ec7514b7..9fdc5dd39a 100644 --- a/boost/geometry/multi/algorithms/within.hpp +++ b/boost/geometry/multi/algorithms/within.hpp @@ -3,6 +3,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,94 +15,11 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP #define BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP - -#include <boost/range.hpp> - #include <boost/geometry/algorithms/within.hpp> -#include <boost/geometry/multi/core/closure.hpp> -#include <boost/geometry/multi/core/point_order.hpp> -#include <boost/geometry/multi/core/tags.hpp> - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace within -{ - - -template -< - typename Geometry, - typename MultiGeometry, - typename Strategy, - typename Policy -> -struct geometry_multi_within_code -{ - static inline int apply(Geometry const& geometry, - MultiGeometry const& multi, - Strategy const& strategy) - { - for (typename boost::range_iterator<MultiGeometry const>::type it - = boost::begin(multi); - it != boost::end(multi); - ++it) - { - // Geometry coding on multi: 1 (within) if within one of them; - // 0 (touch) if on border of one of them - int const code = Policy::apply(geometry, *it, strategy); - if (code != -1) - { - return code; - } - } - return -1; - } -}; - - -}} // namespace detail::within -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Point, typename MultiPolygon> -struct within<Point, MultiPolygon, point_tag, multi_polygon_tag> -{ - template <typename Strategy> - static inline bool apply(Point const& point, - MultiPolygon const& multi_polygon, Strategy const& strategy) - { - return detail::within::geometry_multi_within_code - < - Point, - MultiPolygon, - Strategy, - detail::within::point_in_polygon - < - Point, - typename boost::range_value<MultiPolygon>::type, - order_as_direction - < - geometry::point_order<MultiPolygon>::value - >::value, - geometry::closure<MultiPolygon>::value, - Strategy - > - >::apply(point, multi_polygon, strategy) == 1; - } -}; - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP diff --git a/boost/geometry/multi/core/closure.hpp b/boost/geometry/multi/core/closure.hpp index 3964db256c..9e7cf3c248 100644 --- a/boost/geometry/multi/core/closure.hpp +++ b/boost/geometry/multi/core/closure.hpp @@ -14,45 +14,6 @@ #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 index 9d69cb20d9..7d5e888bab 100644 --- a/boost/geometry/multi/core/geometry_id.hpp +++ b/boost/geometry/multi/core/geometry_id.hpp @@ -15,42 +15,6 @@ #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 index 5a200d486c..deeeff81d0 100644 --- a/boost/geometry/multi/core/interior_rings.hpp +++ b/boost/geometry/multi/core/interior_rings.hpp @@ -16,40 +16,7 @@ #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 index ad8daeb497..30f98527ab 100644 --- a/boost/geometry/multi/core/is_areal.hpp +++ b/boost/geometry/multi/core/is_areal.hpp @@ -16,28 +16,7 @@ #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 index 6b08468e8c..119e55c3ba 100644 --- a/boost/geometry/multi/core/point_order.hpp +++ b/boost/geometry/multi/core/point_order.hpp @@ -15,43 +15,7 @@ #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 index 3c77e973b8..a7277d09a9 100644 --- a/boost/geometry/multi/core/point_type.hpp +++ b/boost/geometry/multi/core/point_type.hpp @@ -16,49 +16,7 @@ #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 index faafaed021..b27b5527c2 100644 --- a/boost/geometry/multi/core/ring_type.hpp +++ b/boost/geometry/multi/core/ring_type.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,51 +19,7 @@ #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 index dcfca65b2f..fb0758d95f 100644 --- a/boost/geometry/multi/core/tags.hpp +++ b/boost/geometry/multi/core/tags.hpp @@ -15,57 +15,8 @@ #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 +#include <boost/geometry/core/tags.hpp> -}} // 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 index 55118f1c73..b4f1e89ae8 100644 --- a/boost/geometry/multi/core/topological_dimension.hpp +++ b/boost/geometry/multi/core/topological_dimension.hpp @@ -16,37 +16,7 @@ #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 index 18f4ff0c25..c741afd794 100644 --- a/boost/geometry/multi/geometries/concepts/check.hpp +++ b/boost/geometry/multi/geometries/concepts/check.hpp @@ -16,68 +16,7 @@ #define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP - -#include <boost/type_traits/is_const.hpp> - -#include <boost/geometry/multi/core/tags.hpp> - #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp> - - -namespace boost { namespace geometry -{ - - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename Geometry> -struct check<multi_point_tag, Geometry, true> - : detail::concept_check::check<concept::ConstMultiPoint<Geometry> > -{}; - - -template <typename Geometry> -struct check<multi_point_tag, Geometry, false> - : detail::concept_check::check<concept::MultiPoint<Geometry> > -{}; - - -template <typename Geometry> -struct check<multi_linestring_tag, Geometry, true> - : detail::concept_check::check<concept::ConstMultiLinestring<Geometry> > -{}; - - -template <typename Geometry> -struct check<multi_linestring_tag, Geometry, false> - : detail::concept_check::check<concept::MultiLinestring<Geometry> > -{}; - - -template <typename Geometry> -struct check<multi_polygon_tag, Geometry, true> - : detail::concept_check::check<concept::ConstMultiPolygon<Geometry> > -{}; - - -template <typename Geometry> -struct check<multi_polygon_tag, Geometry, false> - : detail::concept_check::check<concept::MultiPolygon<Geometry> > -{}; - - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP diff --git a/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp index b0519f07ee..9a9438efcc 100644 --- a/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp +++ b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp @@ -16,71 +16,7 @@ #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 +#include <boost/geometry/geometries/concepts/multi_linestring_concept.hpp> #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 index f5942df070..14c1d25e57 100644 --- a/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp +++ b/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp @@ -16,70 +16,7 @@ #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 +#include <boost/geometry/geometries/concepts/multi_point_concept.hpp> #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 index ca730d4f6b..5e46fb7539 100644 --- a/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp +++ b/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp @@ -16,71 +16,7 @@ #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 +#include <boost/geometry/geometries/concepts/multi_polygon_concept.hpp> #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 index 90cf85a0f6..53042091bd 100644 --- a/boost/geometry/multi/geometries/multi_geometries.hpp +++ b/boost/geometry/multi/geometries/multi_geometries.hpp @@ -14,8 +14,8 @@ #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> +#include <boost/geometry/geometries/multi_point.hpp> +#include <boost/geometry/geometries/multi_linestring.hpp> +#include <boost/geometry/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 index 67d4da06b7..696d907dcc 100644 --- a/boost/geometry/multi/geometries/multi_linestring.hpp +++ b/boost/geometry/multi/geometries/multi_linestring.hpp @@ -11,70 +11,11 @@ // 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 +#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP +#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP -#include <memory> -#include <vector> -#include <boost/concept/requires.hpp> +#include <boost/geometry/geometries/multi_linestring.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 +#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP diff --git a/boost/geometry/multi/geometries/multi_point.hpp b/boost/geometry/multi/geometries/multi_point.hpp index 002d8f8a4b..750ad7802a 100644 --- a/boost/geometry/multi/geometries/multi_point.hpp +++ b/boost/geometry/multi/geometries/multi_point.hpp @@ -14,81 +14,8 @@ #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/multi_point.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 index af8d042873..06fefc7856 100644 --- a/boost/geometry/multi/geometries/multi_polygon.hpp +++ b/boost/geometry/multi/geometries/multi_polygon.hpp @@ -14,65 +14,8 @@ #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/geometries/multi_polygon.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 index 5ececdb8e8..2783a8455b 100644 --- a/boost/geometry/multi/geometries/register/multi_linestring.hpp +++ b/boost/geometry/multi/geometries/register/multi_linestring.hpp @@ -15,45 +15,8 @@ #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; }; \ -}}} + +#include <boost/geometry/geometries/register/multi_linestring.hpp> #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 index 813f54733d..6063492c2b 100644 --- a/boost/geometry/multi/geometries/register/multi_point.hpp +++ b/boost/geometry/multi/geometries/register/multi_point.hpp @@ -15,45 +15,8 @@ #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; }; \ -}}} + +#include <boost/geometry/geometries/register/multi_point.hpp> #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 index 801b98cf24..6a3e47e3da 100644 --- a/boost/geometry/multi/geometries/register/multi_polygon.hpp +++ b/boost/geometry/multi/geometries/register/multi_polygon.hpp @@ -15,45 +15,8 @@ #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; }; \ -}}} + +#include <boost/geometry/geometries/register/multi_polygon.hpp> #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 index be40b5da5a..092869f56c 100644 --- a/boost/geometry/multi/io/dsv/write.hpp +++ b/boost/geometry/multi/io/dsv/write.hpp @@ -14,70 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP #define BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP -#include <boost/range.hpp> #include <boost/geometry/io/dsv/write.hpp> -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace dsv -{ - -template <typename MultiGeometry> -struct dsv_multi -{ - typedef dispatch::dsv - < - typename single_tag_of - < - typename tag<MultiGeometry>::type - >::type, - typename boost::range_value<MultiGeometry>::type - > dispatch_one; - - typedef typename boost::range_iterator - < - MultiGeometry const - >::type iterator; - - - template <typename Char, typename Traits> - static inline void apply(std::basic_ostream<Char, Traits>& os, - MultiGeometry const& multi, - dsv_settings const& settings) - { - os << settings.list_open; - - bool first = true; - for(iterator it = boost::begin(multi); - it != boost::end(multi); - ++it, first = false) - { - os << (first ? "" : settings.list_separator); - dispatch_one::apply(os, *it, settings); - } - os << settings.list_close; - } -}; - -}} // namespace detail::dsv -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Geometry> -struct dsv<multi_tag, Geometry> - : detail::dsv::dsv_multi<Geometry> -{}; - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - -}} // namespace boost::geometry #endif // BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP diff --git a/boost/geometry/multi/io/wkt/detail/prefix.hpp b/boost/geometry/multi/io/wkt/detail/prefix.hpp index 37b07979ba..34e2b241d0 100644 --- a/boost/geometry/multi/io/wkt/detail/prefix.hpp +++ b/boost/geometry/multi/io/wkt/detail/prefix.hpp @@ -14,38 +14,8 @@ #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 -{ +#include <boost/geometry/io/wkt/detail/prefix.hpp> -#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 index 218ddf9999..37e5f9e72e 100644 --- a/boost/geometry/multi/io/wkt/read.hpp +++ b/boost/geometry/multi/io/wkt/read.hpp @@ -14,154 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP #define BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP -#include <string> -#include <boost/geometry/core/mutable_range.hpp> -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/core/point_type.hpp> -#include <boost/geometry/multi/io/wkt/detail/prefix.hpp> #include <boost/geometry/io/wkt/read.hpp> -namespace boost { namespace geometry -{ - -namespace detail { namespace wkt -{ - -template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy> -struct multi_parser -{ - static inline void apply(std::string const& wkt, MultiGeometry& geometry) - { - traits::clear<MultiGeometry>::apply(geometry); - - tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); - tokenizer::iterator it; - if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it)) - { - handle_open_parenthesis(it, tokens.end(), wkt); - - // Parse sub-geometries - while(it != tokens.end() && *it != ")") - { - traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1); - Parser - < - typename boost::range_value<MultiGeometry>::type - >::apply(it, tokens.end(), wkt, geometry.back()); - if (it != tokens.end() && *it == ",") - { - // Skip "," after multi-element is parsed - ++it; - } - } - - handle_close_parenthesis(it, tokens.end(), wkt); - } - - 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 index 55f1713d4d..a6159e1409 100644 --- a/boost/geometry/multi/io/wkt/wkt.hpp +++ b/boost/geometry/multi/io/wkt/wkt.hpp @@ -14,7 +14,7 @@ #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> +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/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 index 374da28b53..2c26d3d2e4 100644 --- a/boost/geometry/multi/io/wkt/write.hpp +++ b/boost/geometry/multi/io/wkt/write.hpp @@ -14,95 +14,8 @@ #ifndef BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP #define BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/io/wkt/detail/prefix.hpp> -#include <boost/geometry/io/wkt/write.hpp> - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace wkt -{ - -template <typename Multi, typename StreamPolicy, typename PrefixPolicy> -struct wkt_multi -{ - template <typename Char, typename Traits> - static inline void apply(std::basic_ostream<Char, Traits>& os, - Multi const& geometry) - { - os << PrefixPolicy::apply(); - // TODO: check EMPTY here - os << "("; - - for (typename boost::range_iterator<Multi const>::type - it = boost::begin(geometry); - it != boost::end(geometry); - ++it) - { - if (it != boost::begin(geometry)) - { - os << ","; - } - StreamPolicy::apply(os, *it); - } - - os << ")"; - } -}; -}} // namespace wkt::impl -#endif - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Multi> -struct wkt<multi_point_tag, Multi> - : detail::wkt::wkt_multi - < - Multi, - detail::wkt::wkt_point - < - typename boost::range_value<Multi>::type, - detail::wkt::prefix_null - >, - detail::wkt::prefix_multipoint - > -{}; - -template <typename Multi> -struct wkt<multi_linestring_tag, Multi> - : detail::wkt::wkt_multi - < - Multi, - detail::wkt::wkt_sequence - < - typename boost::range_value<Multi>::type - >, - detail::wkt::prefix_multilinestring - > -{}; - -template <typename Multi> -struct wkt<multi_polygon_tag, Multi> - : detail::wkt::wkt_multi - < - Multi, - detail::wkt::wkt_poly - < - typename boost::range_value<Multi>::type, - detail::wkt::prefix_null - >, - detail::wkt::prefix_multipolygon - > -{}; - -} // namespace dispatch -#endif +#include <boost/geometry/io/wkt/write.hpp> -}} // 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 index db33a9dd03..4b3063e520 100644 --- a/boost/geometry/multi/multi.hpp +++ b/boost/geometry/multi/multi.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2013. +// Modifications copyright (c) 2013, Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -15,63 +18,64 @@ #define BOOST_GEOMETRY_MULTI_HPP -#include <boost/geometry/multi/core/closure.hpp> -#include <boost/geometry/multi/core/geometry_id.hpp> -#include <boost/geometry/multi/core/interior_rings.hpp> -#include <boost/geometry/multi/core/is_areal.hpp> -#include <boost/geometry/multi/core/point_order.hpp> -#include <boost/geometry/multi/core/point_type.hpp> -#include <boost/geometry/multi/core/ring_type.hpp> -#include <boost/geometry/multi/core/tags.hpp> -#include <boost/geometry/multi/core/topological_dimension.hpp> - -#include <boost/geometry/multi/algorithms/append.hpp> -#include <boost/geometry/multi/algorithms/area.hpp> -#include <boost/geometry/multi/algorithms/centroid.hpp> -#include <boost/geometry/multi/algorithms/clear.hpp> -#include <boost/geometry/multi/algorithms/convert.hpp> -#include <boost/geometry/multi/algorithms/correct.hpp> -#include <boost/geometry/multi/algorithms/covered_by.hpp> -#include <boost/geometry/multi/algorithms/distance.hpp> -#include <boost/geometry/multi/algorithms/envelope.hpp> -#include <boost/geometry/multi/algorithms/equals.hpp> -#include <boost/geometry/multi/algorithms/for_each.hpp> -#include <boost/geometry/multi/algorithms/intersection.hpp> -#include <boost/geometry/multi/algorithms/length.hpp> -#include <boost/geometry/multi/algorithms/num_geometries.hpp> -#include <boost/geometry/multi/algorithms/num_interior_rings.hpp> -#include <boost/geometry/multi/algorithms/num_points.hpp> -#include <boost/geometry/multi/algorithms/perimeter.hpp> -#include <boost/geometry/multi/algorithms/reverse.hpp> -#include <boost/geometry/multi/algorithms/simplify.hpp> -#include <boost/geometry/multi/algorithms/transform.hpp> -#include <boost/geometry/multi/algorithms/unique.hpp> -#include <boost/geometry/multi/algorithms/within.hpp> - -#include <boost/geometry/multi/algorithms/detail/for_each_range.hpp> -#include <boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp> -#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp> - -#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp> -#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp> - -#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp> -#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp> - -#include <boost/geometry/multi/geometries/concepts/check.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp> -#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp> - -#include <boost/geometry/multi/views/detail/range_type.hpp> -#include <boost/geometry/multi/strategies/cartesian/centroid_average.hpp> - -#include <boost/geometry/multi/io/dsv/write.hpp> -#include <boost/geometry/multi/io/wkt/wkt.hpp> +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/geometry_id.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/is_areal.hpp> +#include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/topological_dimension.hpp> + +#include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/area.hpp> +#include <boost/geometry/algorithms/centroid.hpp> +#include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/correct.hpp> +#include <boost/geometry/algorithms/covered_by.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/for_each.hpp> +#include <boost/geometry/algorithms/intersection.hpp> +#include <boost/geometry/algorithms/length.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/perimeter.hpp> +#include <boost/geometry/algorithms/remove_spikes.hpp> +#include <boost/geometry/algorithms/reverse.hpp> +#include <boost/geometry/algorithms/simplify.hpp> +#include <boost/geometry/algorithms/transform.hpp> +#include <boost/geometry/algorithms/unique.hpp> +#include <boost/geometry/algorithms/within.hpp> + +#include <boost/geometry/algorithms/detail/point_on_border.hpp> + +#include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp> +#include <boost/geometry/algorithms/detail/multi_sum.hpp> + +#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> +#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> + +#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> +#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> +#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/views/detail/range_type.hpp> +#include <boost/geometry/strategies/cartesian/centroid_average.hpp> + +#include <boost/geometry/io/dsv/write.hpp> +#include <boost/geometry/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 index f28daf20bb..ce614e2e76 100644 --- a/boost/geometry/multi/strategies/cartesian/centroid_average.hpp +++ b/boost/geometry/multi/strategies/cartesian/centroid_average.hpp @@ -15,102 +15,7 @@ #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 +#include <boost/geometry/strategies/cartesian/centroid_average.hpp> #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 index 172feb251f..f8cb0e6e53 100644 --- a/boost/geometry/multi/views/detail/range_type.hpp +++ b/boost/geometry/multi/views/detail/range_type.hpp @@ -15,48 +15,7 @@ #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/disjoint_interrupt_policy.hpp b/boost/geometry/policies/disjoint_interrupt_policy.hpp new file mode 100644 index 0000000000..2a6e54b079 --- /dev/null +++ b/boost/geometry/policies/disjoint_interrupt_policy.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP + +#include <boost/range.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; + } +}; + + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP diff --git a/boost/geometry/policies/predicate_based_interrupt_policy.hpp b/boost/geometry/policies/predicate_based_interrupt_policy.hpp new file mode 100644 index 0000000000..0021b12dc6 --- /dev/null +++ b/boost/geometry/policies/predicate_based_interrupt_policy.hpp @@ -0,0 +1,101 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct stateless_predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + + inline stateless_predicate_based_interrupt_policy() + : has_intersections(false) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range)); + + return has_intersections; + } +}; + + + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + IsAcceptableTurnPredicate const& m_predicate; + + inline + predicate_based_interrupt_policy(IsAcceptableTurnPredicate const& predicate) + : has_intersections(false) + , m_predicate(predicate) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range), m_predicate); + + return has_intersections; + } +}; + + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP diff --git a/boost/geometry/policies/relate/de9im.hpp b/boost/geometry/policies/relate/de9im.hpp index 766d80b220..e2d6b5111c 100644 --- a/boost/geometry/policies/relate/de9im.hpp +++ b/boost/geometry/policies/relate/de9im.hpp @@ -158,15 +158,6 @@ struct segments_de9im 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); - } - }; diff --git a/boost/geometry/policies/relate/direction.hpp b/boost/geometry/policies/relate/direction.hpp index cfbaf7dd15..02fed94b10 100644 --- a/boost/geometry/policies/relate/direction.hpp +++ b/boost/geometry/policies/relate/direction.hpp @@ -88,7 +88,8 @@ struct direction_type // New information side_info sides; - int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b + // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions + int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases @@ -110,28 +111,19 @@ struct direction_type }; - -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) + + template + < + typename Segment1, + typename Segment2, + typename SegmentIntersectionInfo + > + static inline return_type segments_crosses(side_info const& sides, + SegmentIntersectionInfo const& , + Segment1 const& , Segment2 const& ) { bool const ra0 = sides.get<0,0>() == 0; bool const ra1 = sides.get<0,1>() == 0; @@ -140,95 +132,153 @@ struct segments_direction return // opposite and same starting point (FROM) - ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1) + ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1) // opposite and point to each other (TO) - : ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1) + : ra1 && rb1 ? calculate_side<0>(sides, '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) + : ra1 && rb0 ? angle<1>(sides, '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) + : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1) // b starts from interior of a - : rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1) + : rb0 ? starts_from_middle(sides, 'B', 0, -1) // a starts from interior of b (#39) - : ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0) + : ra0 ? starts_from_middle(sides, '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) + : rb1 ? b_ends_at_middle(sides) // a ends at interior of b - : ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2) + : ra1 ? a_ends_at_middle(sides) // normal intersection - : calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1) + : calculate_side<1>(sides, 'i', -1, -1) ; } - static inline return_type collinear_touch( - coordinate_type const& , - coordinate_type const& , int arrival_a, int arrival_b) + template <typename Ratio> + static inline int arrival_value(Ratio const& r_from, Ratio const& r_to) { - // 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); + // a1--------->a2 + // b1----->b2 + // a departs: -1 + + // a1--------->a2 + // b1----->b2 + // a arrives: 1 + + // a1--------->a2 + // b1----->b2 + // both arrive there -> r-to = 1/1, or 0/1 (on_segment) + + // First check the TO (for arrival), then FROM (for departure) + return r_to.in_segment() ? 1 + : r_to.on_segment() ? 0 + : r_from.on_segment() ? -1 + : -1 + ; } - template <typename S> - static inline return_type collinear_interior_boundary_intersect(S const& , bool, - int arrival_a, int arrival_b, bool opposite) + template <typename Ratio> + static inline void analyze(Ratio const& r, + int& in_segment_count, + int& on_end_count, + int& outside_segment_count) { - return_type r('c', opposite); - r.arrival[0] = arrival_a; - r.arrival[1] = arrival_b; - return r; + if (r.on_end()) + { + on_end_count++; + } + else if (r.in_segment()) + { + in_segment_count++; + } + else + { + outside_segment_count++; + } } - 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) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& , Segment2 const&, + Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b, + Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a) { - return_type r('c', opposite); - r.arrival[0] = -1; - r.arrival[1] = 1; - return r; - } + // If segments are opposite, the ratio of the FROM w.r.t. the other + // is larger than the ratio of the TO w.r.t. the other + bool const opposite = ra_to_wrt_b < ra_from_wrt_b; - 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; + + // IMPORTANT: the order of conditions is different as in intersection_points.hpp + // We assign A in 0 and B in 1 + r.arrival[0] = arrival_value(ra_from_wrt_b, ra_to_wrt_b); + r.arrival[1] = arrival_value(rb_from_wrt_a, rb_to_wrt_a); + + // Analyse them + int a_in_segment_count = 0; + int a_on_end_count = 0; + int a_outside_segment_count = 0; + int b_in_segment_count = 0; + int b_on_end_count = 0; + int b_outside_segment_count = 0; + analyze(ra_from_wrt_b, + a_in_segment_count, a_on_end_count, a_outside_segment_count); + analyze(ra_to_wrt_b, + a_in_segment_count, a_on_end_count, a_outside_segment_count); + analyze(rb_from_wrt_a, + b_in_segment_count, b_on_end_count, b_outside_segment_count); + analyze(rb_to_wrt_a, + b_in_segment_count, b_on_end_count, b_outside_segment_count); + + if (a_on_end_count == 1 + && b_on_end_count == 1 + && a_outside_segment_count == 1 + && b_outside_segment_count == 1) + { + // This is a collinear touch + // --------> A (or B) + // <---------- B (or A) + // We adapt the "how" + // TODO: how was to be refactored anyway, + if (! opposite) + { + r.how = 'a'; + } + else + { + r.how = r.arrival[0] == 0 ? 't' : 'f'; + } + } + else if (a_on_end_count == 2 + && b_on_end_count == 2) + { + r.how = 'e'; + } + return r; } - static inline return_type segment_equal(S1 const& , bool opposite) + template <typename Segment> + static inline return_type degenerate(Segment const& , bool) { - return return_type('e', opposite); + return return_type('0', false); } - static inline return_type degenerate(S1 const& , bool) + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& , + Ratio const& , + bool) { + // To be decided return return_type('0', false); } @@ -237,11 +287,6 @@ struct segments_direction 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 @@ -252,62 +297,29 @@ struct segments_direction 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); + int const dir = sides.get<1, I>() == 1 ? 1 : -1; + return return_type(sides, how, how_a, how_b, -dir, dir); } 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); + int const dir = sides.get<1, I>() == 1 ? 1 : -1; + return return_type(sides, how, how_a, how_b, dir, dir); } 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; + int dir = sides.get<1, 1>() == 1 ? 1 : -1; // From other perspective, then reverse bool const is_a = which == 'A'; @@ -326,31 +338,19 @@ private : // 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) + static inline return_type a_ends_at_middle(side_info const& sides) { - 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); + // (because it both "arrives" and "departs" there) + int const dir = sides.get<1, 1>() == 1 ? 1 : -1; + return return_type(sides, 'm', 1, 0, dir, dir); } - 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) + static inline return_type b_ends_at_middle(side_info const& sides) { - 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); + int const dir = sides.get<0, 1>() == 1 ? 1 : -1; + return return_type(sides, 'm', 0, 1, dir, dir); } }; diff --git a/boost/geometry/policies/relate/intersection_points.hpp b/boost/geometry/policies/relate/intersection_points.hpp index d7d5199051..aa2f697a2a 100644 --- a/boost/geometry/policies/relate/intersection_points.hpp +++ b/boost/geometry/policies/relate/intersection_points.hpp @@ -16,12 +16,12 @@ #include <boost/concept_check.hpp> #include <boost/numeric/conversion/cast.hpp> -#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.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> - +#include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { @@ -30,106 +30,153 @@ namespace policies { namespace relate { -template <typename S1, typename S2, typename ReturnType, typename CalculationType = void> +/*! +\brief Policy calculating the intersection points themselves + */ +template +< + typename ReturnType +> 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& dx2, coordinate_type const& dy2, - S1 const& s1, S2 const& s2) - { - 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) + template + < + typename Point, + typename Segment, + typename SegmentRatio, + typename T + > + static inline void assign(Point& point, + Segment const& segment, + SegmentRatio const& ratio, + T const& dx, T const& dy) { - return_type result; - result.count = 1; - set<0>(result.intersections[0], x); - set<1>(result.intersections[0], y); - return result; + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + // Calculate the intersection point based on segment_ratio + // Up to now, division was postponed. Here we divide using numerator/ + // denominator. In case of integer this results in an integer + // division. + BOOST_ASSERT(ratio.denominator() != 0); + set<0>(point, boost::numeric_cast<coordinate_type>( + get<0, 0>(segment) + + ratio.numerator() * dx / ratio.denominator())); + set<1>(point, boost::numeric_cast<coordinate_type>( + get<0, 1>(segment) + + ratio.numerator() * dy / ratio.denominator())); } - template <typename S> - static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1) + + template + < + typename Segment1, + typename Segment2, + typename SegmentIntersectionInfo + > + static inline return_type segments_crosses(side_info const&, + SegmentIntersectionInfo const& sinfo, + Segment1 const& s1, Segment2 const& s2) { 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; - } + result.count = 1; - 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); - } + if (sinfo.robust_ra < sinfo.robust_rb) + { + assign(result.intersections[0], s1, sinfo.robust_ra, + sinfo.dx_a, sinfo.dy_a); + } + else + { + assign(result.intersections[0], s2, sinfo.robust_rb, + sinfo.dx_b, sinfo.dy_b); + } - 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); - } + result.fractions[0].assign(sinfo); - 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) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& a, Segment2 const& b, + Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b, + Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a) { 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)); + int index = 0, count_a = 0, count_b = 0; + Ratio on_a[2]; + + // The conditions "index < 2" are necessary for non-robust handling, + // if index would be 2 this indicate an (currently uncatched) error + + // IMPORTANT: the order of conditions is different as in direction.hpp + if (ra_from_wrt_b.on_segment() + && index < 2) + { + // a1--------->a2 + // b1----->b2 + // + // ra1 (relative to b) is between 0/1: + // -> First point of A is intersection point + detail::assign_point_from_index<0>(a, result.intersections[index]); + result.fractions[index].assign(Ratio::zero(), ra_from_wrt_b); + on_a[index] = Ratio::zero(); + index++; + count_a++; + } + if (rb_from_wrt_a.in_segment() + && index < 2) + { + // We take the first intersection point of B + // a1--------->a2 + // b1----->b2 + // But only if it is not located on A + // a1--------->a2 + // b1----->b2 rb_from_wrt_a == 0/1 -> a already taken + + detail::assign_point_from_index<0>(b, result.intersections[index]); + result.fractions[index].assign(rb_from_wrt_a, Ratio::zero()); + on_a[index] = rb_from_wrt_a; + index++; + count_b++; + } + + if (ra_to_wrt_b.on_segment() + && index < 2) + { + // Similarly, second IP (here a2) + // a1--------->a2 + // b1----->b2 + detail::assign_point_from_index<1>(a, result.intersections[index]); + result.fractions[index].assign(Ratio::one(), ra_to_wrt_b); + on_a[index] = Ratio::one(); + index++; + count_a++; + } + if (rb_to_wrt_a.in_segment() + && index < 2) + { + detail::assign_point_from_index<1>(b, result.intersections[index]); + result.fractions[index].assign(rb_to_wrt_a, Ratio::one()); + on_a[index] = rb_to_wrt_a; + index++; + count_b++; + } + + // TEMPORARY + // If both are from b, and b is reversed w.r.t. a, we swap IP's + // to align them w.r.t. a + // get_turn_info still relies on some order (in some collinear cases) + if (index == 2 && on_a[1] < on_a[0]) + { + std::swap(result.fractions[0], result.fractions[1]); + std::swap(result.intersections[0], result.intersections[1]); + } + + result.count = index; + return result; } @@ -142,17 +189,35 @@ struct segments_intersection_points return return_type(); } - static inline return_type collinear_disjoint() + // Both degenerate + template <typename Segment> + static inline return_type degenerate(Segment const& segment, bool) { - return return_type(); + return_type result; + result.count = 1; + set<0>(result.intersections[0], get<0, 0>(segment)); + set<1>(result.intersections[0], get<0, 1>(segment)); + return result; } - static inline return_type degenerate(S1 const& s, bool) + // One degenerate + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& degenerate_segment, + Ratio const& ratio, bool a_degenerate) { return_type result; result.count = 1; - set<0>(result.intersections[0], get<0, 0>(s)); - set<1>(result.intersections[0], get<0, 1>(s)); + set<0>(result.intersections[0], get<0, 0>(degenerate_segment)); + set<1>(result.intersections[0], get<0, 1>(degenerate_segment)); + if (a_degenerate) + { + // IP lies on ratio w.r.t. segment b + result.fractions[0].assign(Ratio::zero(), ratio); + } + else + { + result.fractions[0].assign(ratio, Ratio::zero()); + } return result; } }; diff --git a/boost/geometry/policies/relate/intersection_ratios.hpp b/boost/geometry/policies/relate/intersection_ratios.hpp new file mode 100644 index 0000000000..81ecba0b54 --- /dev/null +++ b/boost/geometry/policies/relate/intersection_ratios.hpp @@ -0,0 +1,127 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_RATIOS_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP + + +#include <algorithm> +#include <string> + +#include <boost/concept_check.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/strategies/side_info.hpp> + + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +/*! +\brief Policy returning segment ratios +\note Template argument FractionType should be a fraction_type<SegmentRatio> + */ +template +< + typename FractionType +> +struct segments_intersection_ratios +{ + typedef FractionType return_type; + + template + < + typename Segment1, + typename Segment2, + typename SegmentIntersectionInfo + > + static inline return_type segments_crosses(side_info const&, + SegmentIntersectionInfo const& sinfo, + Segment1 const& , Segment2 const& ) + { + return_type result; + result.assign(sinfo); + return result; + } + + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& , Segment2 const& , + Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b, + Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a) + { + // We have only one result, for (potentially) two IP's, + // so we take a first one + return_type result; + + if (ra_from_wrt_b.on_segment()) + { + result.assign(Ratio::zero(), ra_from_wrt_b); + } + else if (rb_from_wrt_a.in_segment()) + { + result.assign(rb_from_wrt_a, Ratio::zero()); + } + else if (ra_to_wrt_b.on_segment()) + { + result.assign(Ratio::one(), ra_to_wrt_b); + } + else if (rb_to_wrt_a.in_segment()) + { + result.assign(rb_to_wrt_a, Ratio::one()); + } + + return result; + } + + static inline return_type disjoint() + { + return return_type(); + } + static inline return_type error(std::string const&) + { + return return_type(); + } + + template <typename Segment> + static inline return_type degenerate(Segment const& segment, bool) + { + return return_type(); + } + + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& , + Ratio const& ratio, bool a_degenerate) + { + return_type result; + if (a_degenerate) + { + // IP lies on ratio w.r.t. segment b + result.assign(Ratio::zero(), ratio); + } + else + { + result.assign(ratio, Ratio::zero()); + } + return result; + } + +}; + + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP diff --git a/boost/geometry/policies/relate/tupled.hpp b/boost/geometry/policies/relate/tupled.hpp index f6713c44c9..6da9095c4e 100644 --- a/boost/geometry/policies/relate/tupled.hpp +++ b/boost/geometry/policies/relate/tupled.hpp @@ -14,8 +14,6 @@ #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 { @@ -26,7 +24,7 @@ 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> +template <typename Policy1, typename Policy2> struct segments_tupled { typedef boost::tuple @@ -35,107 +33,50 @@ struct segments_tupled 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) + template <typename Segment1, typename Segment2, typename SegmentIntersectionInfo> + static inline return_type segments_crosses(side_info const& sides, + SegmentIntersectionInfo const& sinfo, + Segment1 const& s1, Segment2 const& s2) { return boost::make_tuple ( - Policy1::collinear_b_in_a(segment, opposite), - Policy2::collinear_b_in_a(segment, opposite) + Policy1::segments_crosses(sides, sinfo, s1, s2), + Policy2::segments_crosses(sides, sinfo, s1, s2) ); } - - 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) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& segment1, Segment2 const& segment2, + Ratio const& ra1, Ratio const& ra2, Ratio const& rb1, Ratio const& rb2) { 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) + Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2), + Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2) ); } - static inline return_type segment_equal(segment_type1 const& s, - bool opposite) + template <typename Segment> + static inline return_type degenerate(Segment const& segment, + bool a_degenerate) { return boost::make_tuple ( - Policy1::segment_equal(s, opposite), - Policy2::segment_equal(s, opposite) + Policy1::degenerate(segment, a_degenerate), + Policy2::degenerate(segment, a_degenerate) ); } - static inline return_type degenerate(segment_type1 const& segment, - bool a_degenerate) + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& segment, + Ratio const& ratio, + bool a_degenerate) { return boost::make_tuple ( - Policy1::degenerate(segment, a_degenerate), - Policy2::degenerate(segment, a_degenerate) + Policy1::one_degenerate(segment, ratio, a_degenerate), + Policy2::one_degenerate(segment, ratio, a_degenerate) ); } @@ -157,15 +98,6 @@ struct segments_tupled ); } - static inline return_type collinear_disjoint() - { - return boost::make_tuple - ( - Policy1::collinear_disjoint(), - Policy2::collinear_disjoint() - ); - } - }; }} // namespace policies::relate diff --git a/boost/geometry/policies/robustness/get_rescale_policy.hpp b/boost/geometry/policies/robustness/get_rescale_policy.hpp new file mode 100644 index 0000000000..ed7c1eb94c --- /dev/null +++ b/boost/geometry/policies/robustness/get_rescale_policy.hpp @@ -0,0 +1,290 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 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_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP + + +#include <cstddef> + +#include <boost/type_traits.hpp> +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/core/tag_cast.hpp> + +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/algorithms/detail/get_max_size.hpp> +#include <boost/geometry/policies/robustness/robust_type.hpp> + +#include <boost/geometry/geometries/point.hpp> +#include <boost/geometry/geometries/box.hpp> + +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/rescale_policy.hpp> + +#include <boost/geometry/util/promote_floating_point.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace get_rescale_policy +{ + +template <typename Point, typename RobustPoint, typename Geometry, typename Factor> +static inline void init_rescale_policy(Geometry const& geometry, + Point& min_point, + RobustPoint& min_robust_point, + Factor& factor) +{ + // Get bounding boxes + model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry); + + // Scale this to integer-range + typedef typename promote_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type num_type; + num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env)); + num_type const range = 10000000.0; // Define a large range to get precise integer coordinates + num_type const half = 0.5; + factor = math::equals(diff, num_type()) ? 1 + : boost::numeric_cast<num_type>( + boost::numeric_cast<boost::long_long_type>(half + range / diff)); + + // Assign input/output minimal points + detail::assign_point_from_index<0>(env, min_point); + num_type const two = 2; + boost::long_long_type const min_coordinate + = boost::numeric_cast<boost::long_long_type>(-range / two); + assign_values(min_robust_point, min_coordinate, min_coordinate); +} + +template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor> +static inline void init_rescale_policy(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Point& min_point, + RobustPoint& min_robust_point, + Factor& factor) +{ + // Get bounding boxes + model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry1); + model::box<Point> env2 = geometry::return_envelope<model::box<Point> >(geometry2); + geometry::expand(env, env2); + + // TODO: merge this with implementation above + // Scale this to integer-range + typedef typename promote_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type num_type; + num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env)); + num_type const range = 10000000.0; // Define a large range to get precise integer coordinates + num_type const half = 0.5; + factor = math::equals(diff, num_type()) ? 1 + : boost::numeric_cast<num_type>( + boost::numeric_cast<boost::long_long_type>(half + range / diff)); + + // Assign input/output minimal points + detail::assign_point_from_index<0>(env, min_point); + num_type const two = 2; + boost::long_long_type const min_coordinate + = boost::numeric_cast<boost::long_long_type>(-range / two); + assign_values(min_robust_point, min_coordinate, min_coordinate); +} + + +template +< + typename Point, + bool IsFloatingPoint +> +struct rescale_policy_type +{ + typedef no_rescale_policy type; +}; + +// We rescale only all FP types +template +< + typename Point +> +struct rescale_policy_type<Point, true> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<Point>::value, + typename geometry::coordinate_system<Point>::type + > robust_point_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef detail::robust_policy<Point, robust_point_type, factor_type> type; +}; + +template <typename Policy> +struct get_rescale_policy +{ + template <typename Geometry> + static inline Policy apply(Geometry const& geometry) + { + typedef typename point_type<Geometry>::type point_type; + typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<point_type>::value, + typename geometry::coordinate_system<point_type>::type + > robust_point_type; + + point_type min_point; + robust_point_type min_robust_point; + factor_type factor; + init_rescale_policy(geometry, min_point, min_robust_point, factor); + + return Policy(min_point, min_robust_point, factor); + } + + template <typename Geometry1, typename Geometry2> + static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + typedef typename point_type<Geometry1>::type point_type; + typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<point_type>::value, + typename geometry::coordinate_system<point_type>::type + > robust_point_type; + + point_type min_point; + robust_point_type min_robust_point; + factor_type factor; + init_rescale_policy(geometry1, geometry2, min_point, min_robust_point, factor); + + return Policy(min_point, min_robust_point, factor); + } +}; + +// Specialization for no-rescaling +template <> +struct get_rescale_policy<no_rescale_policy> +{ + template <typename Geometry> + static inline no_rescale_policy apply(Geometry const& ) + { + return no_rescale_policy(); + } + + template <typename Geometry1, typename Geometry2> + static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& ) + { + return no_rescale_policy(); + } +}; + + +}} // namespace detail::get_rescale_policy +#endif // DOXYGEN_NO_DETAIL + +template<typename Point> +struct rescale_policy_type + : public detail::get_rescale_policy::rescale_policy_type + < + Point, +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + false +#else + boost::is_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type::value +#endif + > +{ + static const bool is_point + = boost::is_same + < + typename geometry::tag<Point>::type, + geometry::point_tag + >::type::value; + + BOOST_MPL_ASSERT_MSG((is_point), + INVALID_INPUT_GEOMETRY, + (typename geometry::tag<Point>::type)); +}; + + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1 = typename tag_cast + < + typename tag<Geometry1>::type, + box_tag, + pointlike_tag, + linear_tag, + areal_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag<Geometry2>::type, + box_tag, + pointlike_tag, + linear_tag, + areal_tag + >::type +> +struct rescale_overlay_policy_type + // Default: no rescaling + : public detail::get_rescale_policy::rescale_policy_type + < + typename geometry::point_type<Geometry1>::type, + false + > +{}; + +// Areal/areal: get rescale policy based on coordinate type +template +< + typename Geometry1, + typename Geometry2 +> +struct rescale_overlay_policy_type<Geometry1, Geometry2, areal_tag, areal_tag> + : public rescale_policy_type + < + typename geometry::point_type<Geometry1>::type + > +{}; + + +template <typename Policy, typename Geometry> +inline Policy get_rescale_policy(Geometry const& geometry) +{ + return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry); +} + +template <typename Policy, typename Geometry1, typename Geometry2> +inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry1, geometry2); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/no_rescale_policy.hpp b/boost/geometry/policies/robustness/no_rescale_policy.hpp new file mode 100644 index 0000000000..a7899842c1 --- /dev/null +++ b/boost/geometry/policies/robustness/no_rescale_policy.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP + +#include <stddef.h> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Probably this will be moved out of namespace detail +struct no_rescale_policy +{ + static bool const enabled = false; + + // We don't rescale but return the reference of the input + template <std::size_t Dimension, typename Value> + inline Value const& apply(Value const& value) const + { + return value; + } +}; + +} // namespace detail +#endif + + +// Implement meta-functions for this policy +template <typename Point> +struct robust_point_type<Point, detail::no_rescale_policy> +{ + // The point itself + typedef Point type; +}; + +template <typename Point> +struct segment_ratio_type<Point, detail::no_rescale_policy> +{ + // Define a segment_ratio defined on coordinate type, e.g. + // int/int or float/float + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + typedef segment_ratio<coordinate_type> type; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/rescale_policy.hpp b/boost/geometry/policies/robustness/rescale_policy.hpp new file mode 100644 index 0000000000..5b3b566976 --- /dev/null +++ b/boost/geometry/policies/robustness/rescale_policy.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 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_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP + +#include <cstddef> + +#include <boost/type_traits.hpp> + +#include <boost/geometry/policies/robustness/segment_ratio.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename FpPoint, typename IntPoint, typename CalculationType> +struct robust_policy +{ + static bool const enabled = true; + + typedef typename geometry::coordinate_type<IntPoint>::type output_ct; + + robust_policy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor) + : m_fp_min(fp_min) + , m_int_min(int_min) + , m_multiplier(the_factor) + { + } + + template <std::size_t Dimension, typename Value> + inline output_ct apply(Value const& value) const + { + // a + (v-b)*f + CalculationType const a = static_cast<CalculationType>(get<Dimension>(m_int_min)); + CalculationType const b = static_cast<CalculationType>(get<Dimension>(m_fp_min)); + CalculationType const result = a + (value - b) * m_multiplier; + return static_cast<output_ct>(result); + } + + FpPoint m_fp_min; + IntPoint m_int_min; + CalculationType m_multiplier; +}; + +} // namespace detail +#endif + + +// Implement meta-functions for this policy + +// Define the IntPoint as a robust-point type +template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType> +struct robust_point_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> > +{ + typedef IntPoint type; +}; + +// Meta function for rescaling, if rescaling is done segment_ratio is based on long long +template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType> +struct segment_ratio_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> > +{ + typedef segment_ratio<boost::long_long_type> type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/robust_point_type.hpp b/boost/geometry/policies/robustness/robust_point_type.hpp new file mode 100644 index 0000000000..25639227f0 --- /dev/null +++ b/boost/geometry/policies/robustness/robust_point_type.hpp @@ -0,0 +1,30 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP + +namespace boost { namespace geometry +{ + +// Meta-function to typedef a robust point type for a policy +template <typename Point, typename Policy> +struct robust_point_type +{ + // By default, the point itself is the robust type + typedef Point type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP diff --git a/boost/geometry/policies/robustness/robust_type.hpp b/boost/geometry/policies/robustness/robust_type.hpp new file mode 100644 index 0000000000..4cfb2c4d91 --- /dev/null +++ b/boost/geometry/policies/robustness/robust_type.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 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_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP + + +#include <boost/type_traits.hpp> +#include <boost/config.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail_dispatch +{ + +template <typename CoordinateType, typename IsFloatingPoint> +struct robust_type +{ +}; + +template <typename CoordinateType> +struct robust_type<CoordinateType, boost::false_type> +{ + typedef CoordinateType type; +}; + +template <typename CoordinateType> +struct robust_type<CoordinateType, boost::true_type> +{ + typedef boost::long_long_type type; +}; + +} // namespace detail_dispatch + +namespace detail +{ + +template <typename CoordinateType> +struct robust_type +{ + typedef typename detail_dispatch::robust_type + < + CoordinateType, + typename boost::is_floating_point<CoordinateType>::type + >::type type; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP diff --git a/boost/geometry/policies/robustness/segment_ratio.hpp b/boost/geometry/policies/robustness/segment_ratio.hpp new file mode 100644 index 0000000000..8b55605c7f --- /dev/null +++ b/boost/geometry/policies/robustness/segment_ratio.hpp @@ -0,0 +1,239 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_ROBUSTNESS_SEGMENT_RATIO_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/rational.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> + +namespace boost { namespace geometry +{ + + +namespace detail { namespace segment_ratio +{ + +template +< + typename Type, + bool IsIntegral = boost::is_integral<Type>::type::value +> +struct less {}; + +template <typename Type> +struct less<Type, true> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational<Type>(lhs.numerator(), lhs.denominator()) + < boost::rational<Type>(rhs.numerator(), rhs.denominator()); + } +}; + +template <typename Type> +struct less<Type, false> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + BOOST_ASSERT(lhs.denominator() != 0); + BOOST_ASSERT(rhs.denominator() != 0); + return lhs.numerator() * rhs.denominator() + < rhs.numerator() * lhs.denominator(); + } +}; + +template +< + typename Type, + bool IsIntegral = boost::is_integral<Type>::type::value +> +struct equal {}; + +template <typename Type> +struct equal<Type, true> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational<Type>(lhs.numerator(), lhs.denominator()) + == boost::rational<Type>(rhs.numerator(), rhs.denominator()); + } +}; + +template <typename Type> +struct equal<Type, false> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + BOOST_ASSERT(lhs.denominator() != 0); + BOOST_ASSERT(rhs.denominator() != 0); + return geometry::math::equals + ( + lhs.numerator() * rhs.denominator(), + rhs.numerator() * lhs.denominator() + ); + } +}; + +}} + +//! Small class to keep a ratio (e.g. 1/4) +//! Main purpose is intersections and checking on 0, 1, and smaller/larger +//! The prototype used Boost.Rational. However, we also want to store FP ratios, +//! (so numerator/denominator both in float) +//! and Boost.Rational starts with GCD which we prefer to avoid if not necessary +//! On a segment means: this ratio is between 0 and 1 (both inclusive) +//! +template <typename Type> +class segment_ratio +{ +public : + typedef Type numeric_type; + + // Type-alias for the type itself + typedef segment_ratio<Type> thistype; + + inline segment_ratio() + : m_numerator(0) + , m_denominator(1) + , m_approximation(0) + {} + + inline segment_ratio(const Type& nominator, const Type& denominator) + : m_numerator(nominator) + , m_denominator(denominator) + { + initialize(); + } + + inline Type const& numerator() const { return m_numerator; } + inline Type const& denominator() const { return m_denominator; } + + inline void assign(const Type& nominator, const Type& denominator) + { + m_numerator = nominator; + m_denominator = denominator; + initialize(); + } + + inline void initialize() + { + // Minimal normalization + // 1/-4 => -1/4, -1/-4 => 1/4 + if (m_denominator < 0) + { + m_numerator = -m_numerator; + m_denominator = -m_denominator; + } + + typedef typename promote_floating_point<Type>::type num_type; + static const num_type scale = 1000000.0; + m_approximation = + m_denominator == 0 ? 0 + : boost::numeric_cast<double> + ( + boost::numeric_cast<num_type>(m_numerator) * scale + / boost::numeric_cast<num_type>(m_denominator) + ); + } + + inline bool is_zero() const { return math::equals(m_numerator, 0); } + inline bool is_one() const { return math::equals(m_numerator, m_denominator); } + inline bool on_segment() const + { + // e.g. 0/4 or 4/4 or 2/4 + return m_numerator >= 0 && m_numerator <= m_denominator; + } + inline bool in_segment() const + { + // e.g. 1/4 + return m_numerator > 0 && m_numerator < m_denominator; + } + inline bool on_end() const + { + // e.g. 0/4 or 4/4 + return is_zero() || is_one(); + } + inline bool left() const + { + // e.g. -1/4 + return m_numerator < 0; + } + inline bool right() const + { + // e.g. 5/4 + return m_numerator > m_denominator; + } + + inline bool close_to(thistype const& other) const + { + return geometry::math::abs(m_approximation - other.m_approximation) < 2; + } + + inline bool operator< (thistype const& other) const + { + return close_to(other) + ? detail::segment_ratio::less<Type>::apply(*this, other) + : m_approximation < other.m_approximation; + } + + inline bool operator== (thistype const& other) const + { + return close_to(other) + && detail::segment_ratio::equal<Type>::apply(*this, other); + } + + static inline thistype zero() + { + static thistype result(0, 1); + return result; + } + + static inline thistype one() + { + static thistype result(1, 1); + return result; + } + +#if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO) + friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio) + { + os << ratio.m_numerator << "/" << ratio.m_denominator + << " (" << (static_cast<double>(ratio.m_numerator) + / static_cast<double>(ratio.m_denominator)) + << ")"; + return os; + } +#endif + + + +private : + Type m_numerator; + Type m_denominator; + + // Contains ratio on scale 0..1000000 (for 0..1) + // This is an approximation for fast and rough comparisons + // Boost.Rational is used if the approximations are close. + // Reason: performance, Boost.Rational does a GCD by default and also the + // comparisons contain while-loops. + double m_approximation; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP diff --git a/boost/geometry/policies/robustness/segment_ratio_type.hpp b/boost/geometry/policies/robustness/segment_ratio_type.hpp new file mode 100644 index 0000000000..19e935bbb9 --- /dev/null +++ b/boost/geometry/policies/robustness/segment_ratio_type.hpp @@ -0,0 +1,28 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 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_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP + +#include <boost/geometry/algorithms/not_implemented.hpp> + +namespace boost { namespace geometry +{ + +// Meta-function to access segment-ratio for a policy +template <typename Point, typename Policy> +struct segment_ratio_type {}; // : not_implemented<> {}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP diff --git a/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp new file mode 100644 index 0000000000..7b7cd1890f --- /dev/null +++ b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp @@ -0,0 +1,110 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_DISTANCE_ASYMMETRIC_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP + +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + + +/*! +\brief Let the buffer for linestrings be asymmetric +\ingroup strategies +\tparam NumericType \tparam_numeric +\details This strategy can be used as DistanceStrategy for the buffer algorithm. + It can be applied for (multi)linestrings. It uses a (potentially) different + distances for left and for right. This means the (multi)linestrings are + interpreted having a direction. + +\qbk{ +[heading Example] +[buffer_distance_asymmetric] +[heading Output] +[$img/strategies/buffer_distance_asymmetric.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_distance_symmetric distance_symmetric] +} + */ +template<typename NumericType> +class distance_asymmetric +{ +public : + //! \brief Constructs the strategy, two distances must be specified + //! \param left The distance (or radius) of the buffer on the left side + //! \param right The distance on the right side + distance_asymmetric(NumericType const& left, + NumericType const& right) + : m_left(left) + , m_right(right) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Returns the distance-value for the specified side + template <typename Point> + inline NumericType apply(Point const& , Point const& , + buffer_side_selector side) const + { + NumericType result = side == buffer_side_left ? m_left : m_right; + return negative() ? math::abs(result) : result; + } + + //! Used internally, returns -1 for deflate, 1 for inflate + inline int factor() const + { + return negative() ? -1 : 1; + } + + //! Returns true if both distances are negative + inline bool negative() const + { + return m_left < 0 && m_right < 0; + } + + //! Returns the max distance distance up to the buffer will reach + template <typename JoinStrategy, typename EndStrategy> + inline NumericType max_distance(JoinStrategy const& join_strategy, + EndStrategy const& end_strategy) const + { + NumericType const left = geometry::math::abs(m_left); + NumericType const right = geometry::math::abs(m_right); + NumericType const dist = (std::max)(left, right); + return (std::max)(join_strategy.max_distance(dist), + end_strategy.max_distance(dist)); + } + + //! Returns the distance at which the input is simplified before the buffer process + inline NumericType simplify_distance() const + { + NumericType const left = geometry::math::abs(m_left); + NumericType const right = geometry::math::abs(m_right); + return (std::min)(left, right) / 1000.0; + } + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + NumericType m_left; + NumericType m_right; +}; + + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP diff --git a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp new file mode 100644 index 0000000000..bc0c46f644 --- /dev/null +++ b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp @@ -0,0 +1,102 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_DISTANCE_SYMMETRIC_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP + +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + + +/*! +\brief Let the buffer algorithm create buffers with same distances +\ingroup strategies +\tparam NumericType \tparam_numeric +\details This strategy can be used as DistanceStrategy for the buffer algorithm. + It can be applied for all geometries. It uses one distance for left and + for right. + If the distance is negative and used with a (multi)polygon or ring, the + geometry will shrink (deflate) instead of expand (inflate). + +\qbk{ +[heading Example] +[buffer_distance_symmetric] +[heading Output] +[$img/strategies/buffer_distance_symmetric.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_distance_asymmetric distance_asymmetric] +} + */ +template<typename NumericType> +class distance_symmetric +{ +public : + //! \brief Constructs the strategy, a distance must be specified + //! \param distance The distance (or radius) of the buffer + explicit inline distance_symmetric(NumericType const& distance) + : m_distance(distance) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Returns the distance-value + template <typename Point> + inline NumericType apply(Point const& , Point const& , + buffer_side_selector ) const + { + return negative() ? geometry::math::abs(m_distance) : m_distance; + } + + //! Used internally, returns -1 for deflate, 1 for inflate + inline int factor() const + { + return negative() ? -1 : 1; + } + + //! Returns true if distance is negative + inline bool negative() const + { + return m_distance < 0; + } + + //! Returns the max distance distance up to the buffer will reach + template <typename JoinStrategy, typename EndStrategy> + inline NumericType max_distance(JoinStrategy const& join_strategy, + EndStrategy const& end_strategy) const + { + NumericType const dist = geometry::math::abs(m_distance); + return (std::max)(join_strategy.max_distance(dist), + end_strategy.max_distance(dist)); + } + + + //! Returns the distance at which the input is simplified before the buffer process + inline NumericType simplify_distance() const + { + return geometry::math::abs(m_distance) / 1000.0; + } +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + NumericType m_distance; +}; + + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP diff --git a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp index 747c140754..a960a6f1f9 100644 --- a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp +++ b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -230,7 +235,7 @@ public: // 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), + // 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. @@ -282,17 +287,17 @@ public: template <typename OutputIterator> inline void result(partitions const& state, - OutputIterator out, bool clockwise) const + OutputIterator out, + bool clockwise, + bool closed) const { if (clockwise) { - output_range<iterate_forward>(state.m_upper_hull, out, false); - output_range<iterate_reverse>(state.m_lower_hull, out, true); + output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed); } else { - output_range<iterate_forward>(state.m_lower_hull, out, false); - output_range<iterate_reverse>(state.m_upper_hull, out, true); + output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed); } } @@ -319,11 +324,11 @@ private: typedef typename strategy::side::services::default_strategy<cs_tag>::type side; output.push_back(p); - register std::size_t output_size = output.size(); + std::size_t output_size = output.size(); while (output_size >= 3) { rev_iterator rit = output.rbegin(); - point_type const& last = *rit++; + point_type const last = *rit++; point_type const& last2 = *rit++; if (Factor * side::apply(*rit, last, last2) <= 0) @@ -343,28 +348,28 @@ private: } - template <iterate_direction Direction, typename OutputIterator> - static inline void output_range(container_type const& range, - OutputIterator out, bool skip_first) + template <typename OutputIterator> + static inline void output_ranges(container_type const& first, container_type const& second, + OutputIterator out, bool closed) { - 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) + std::copy(boost::begin(first), boost::end(first), out); + + BOOST_ASSERT(closed ? !boost::empty(second) : boost::size(second) > 1); + std::copy(++boost::rbegin(second), // skip the first Point + closed ? boost::rend(second) : --boost::rend(second), // skip the last Point if open + out); + + typedef typename boost::range_size<container_type>::type size_type; + size_type const count = boost::size(first) + boost::size(second) - 1; + // count describes a closed case but comparison with min size of closed + // gives the result compatible also with open + // here core_detail::closure::minimum_ring_size<closed> could be used + if ( count < 4 ) { - if (first && skip_first) - { - first = false; - } - else - { - *out = *it; - ++out; - } + // there should be only one missing + *out++ = *boost::begin(first); } } - }; }} // namespace strategy::convex_hull diff --git a/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp index 1398ddb687..968f9fecb9 100644 --- a/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp +++ b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp @@ -22,9 +22,9 @@ #include <boost/geometry/strategies/within.hpp> -namespace boost { namespace geometry { namespace strategy +namespace boost { namespace geometry { namespace strategy { - + namespace within { @@ -71,11 +71,11 @@ struct point_in_box_by_side 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]); @@ -84,7 +84,7 @@ struct point_in_box_by_side return result; } } - + return result; } }; @@ -102,9 +102,9 @@ 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_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, Point, Box > { @@ -126,9 +126,9 @@ 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_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, Point, Box > { diff --git a/boost/geometry/strategies/agnostic/point_in_point.hpp b/boost/geometry/strategies/agnostic/point_in_point.hpp new file mode 100644 index 0000000000..e4f9bec4c6 --- /dev/null +++ b/boost/geometry/strategies/agnostic/point_in_point.hpp @@ -0,0 +1,136 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> + +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +template +< + typename Point1, typename Point2 +> +struct point_in_point +{ + static inline bool apply(Point1 const& point1, Point2 const& point2) + { + return detail::equals::equals_point_point(point1, point2); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point, typename MultiPoint> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +template <typename Point, typename MultiPoint> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +} // namespace services + +#endif + + +}} // namespace strategy::within + + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace strategy { namespace covered_by { namespace services +{ + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2> +struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2> +{ + typedef strategy::within::point_in_point<Point1, Point2> type; +}; + +template <typename Point, typename MultiPoint> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +template <typename Point, typename MultiPoint> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2> +struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint> +{ + typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; +}; + +}}} // namespace strategy::covered_by::services +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp index 69188650d8..f4ed7a634f 100644 --- a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -1,6 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -9,10 +13,14 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP #define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP +#include <boost/core/ignore_unused.hpp> + #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_calculation_type.hpp> @@ -27,6 +35,153 @@ namespace boost { namespace geometry namespace strategy { namespace within { + +// Fix for https://svn.boost.org/trac/boost/ticket/9628 +// For floating point coordinates, the <1> coordinate of a point is compared +// with the segment's points using some EPS. If the coordinates are "equal" +// the sides are calculated. Therefore we can treat a segment as a long areal +// geometry having some width. There is a small ~triangular area somewhere +// between the segment's effective area and a segment's line used in sides +// calculation where the segment is on the one side of the line but on the +// other side of a segment (due to the width). +// For the s1 of a segment going NE the real side is RIGHT but the point may +// be detected as LEFT, like this: +// RIGHT +// ___-----> +// ^ O Pt __ __ +// EPS __ __ +// v__ __ BUT DETECTED AS LEFT OF THIS LINE +// _____7 +// _____/ +// _____/ +template <typename CSTag> +struct winding_side_equal +{ + typedef typename strategy::side::services::default_strategy + < + CSTag + >::type strategy_side_type; + + template <size_t D, typename Point, typename PointOfSegment> + static inline int apply(Point const& point, + PointOfSegment const& se, + int count) + { + // Create a vertical segment intersecting the original segment's endpoint + // equal to the point, with the derived direction (UP/DOWN). + // Set only the 2 first coordinates, the other ones are ignored + PointOfSegment ss1, ss2; + set<1-D>(ss1, get<1-D>(se)); + set<1-D>(ss2, get<1-D>(se)); + if ( count > 0 ) // UP + { + set<D>(ss1, 0); + set<D>(ss2, 1); + } + else // DOWN + { + set<D>(ss1, 1); + set<D>(ss2, 0); + } + // Check the side using this vertical segment + return strategy_side_type::apply(ss1, ss2, point); + } +}; + +// The optimization for cartesian +template <> +struct winding_side_equal<cartesian_tag> +{ + template <size_t D, typename Point, typename PointOfSegment> + static inline int apply(Point const& point, + PointOfSegment const& se, + int count) + { + return math::equals(get<1-D>(point), get<1-D>(se)) ? + 0 : + get<1-D>(point) < get<1-D>(se) ? + // assuming count is equal to 1 or -1 + count : // ( count > 0 ? 1 : -1) : + -count; // ( count > 0 ? -1 : 1) ; + } +}; + + +template <typename CSTag> +struct winding_side_between +{ + typedef typename strategy::side::services::default_strategy + < + CSTag + >::type strategy_side_type; + + template <size_t D, typename Point, typename PointOfSegment> + static inline int apply(Point const& point, + PointOfSegment const& s1, PointOfSegment const& s2, + int count) + { + // Create a vertical segment intersecting the original segment's endpoint + // equal to the point, with the derived direction (UP/DOWN). + // Set only the 2 first coordinates, the other ones are ignored + PointOfSegment ss1, ss2; + set<1-D>(ss1, get<1-D>(s1)); + set<1-D>(ss2, get<1-D>(s1)); + + if ( count > 0 ) // UP + { + set<D>(ss1, 0); + set<D>(ss2, 1); + } + else // DOWN + { + set<D>(ss1, 1); + set<D>(ss2, 0); + } + + int const seg_side = strategy_side_type::apply(ss1, ss2, s2); + + if ( seg_side != 0 ) // segment not vertical + { + if ( strategy_side_type::apply(ss1, ss2, point) == -seg_side ) // point on the opposite side than s2 + { + return -seg_side; + } + else + { + set<1-D>(ss1, get<1-D>(s2)); + set<1-D>(ss2, get<1-D>(s2)); + + if ( strategy_side_type::apply(ss1, ss2, point) == seg_side ) // point behind s2 + { + return seg_side; + } + } + } + + // segment is vertical or point is between p1 and p2 + return strategy_side_type::apply(s1, s2, point); + } +}; + +// The specialization for cartesian +template <> +struct winding_side_between<cartesian_tag> +{ + typedef strategy::side::services::default_strategy + < + cartesian_tag + >::type strategy_side_type; + + template <size_t D, typename Point, typename PointOfSegment> + static inline int apply(Point const& point, + PointOfSegment const& s1, PointOfSegment const& s2, + int /*count*/) + { + return strategy_side_type::apply(s1, s2, point); + } +}; + + /*! \brief Within detection using winding rule \ingroup strategies @@ -106,21 +261,21 @@ class winding template <size_t D> static inline int check_segment(Point const& point, PointOfSegment const& seg1, PointOfSegment const& seg2, - counter& state) + counter& state, bool& eq1, bool& eq2) { 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); + eq1 = math::equals(s1, p); + 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 check_touch<1 - D>(point, seg1, seg2, state); } return @@ -132,8 +287,6 @@ class winding } - - public : // Typedefs and static methods to fulfill the concept @@ -145,10 +298,27 @@ public : PointOfSegment const& s1, PointOfSegment const& s2, counter& state) { - int count = check_segment<1>(point, s1, s2, state); + typedef typename cs_tag<Point>::type cs_t; + + bool eq1 = false; + bool eq2 = false; + boost::ignore_unused(eq2); + + int count = check_segment<1>(point, s1, s2, state, eq1, eq2); if (count != 0) { - int side = strategy_side_type::apply(s1, s2, point); + int side = 0; + if ( count == 1 || count == -1 ) + { + side = winding_side_equal<cs_t> + ::template apply<1>(point, eq1 ? s1 : s2, count); + } + else // count == 2 || count == -2 + { + side = winding_side_between<cs_t> + ::template apply<1>(point, s1, s2, count); + } + if (side == 0) { // Point is lying on segment @@ -194,6 +364,19 @@ struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, typedef winding<Point, typename geometry::point_type<Geometry>::type> type; }; +// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used + +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry> +{ + typedef winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry> +{ + typedef winding<Point, typename geometry::point_type<Geometry>::type> type; +}; } // namespace services @@ -221,6 +404,19 @@ struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; }; +// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used + +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry> +{ + typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; +}; + +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry> +{ + typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; +}; }}} // namespace strategy::covered_by::services #endif diff --git a/boost/geometry/strategies/agnostic/relate.hpp b/boost/geometry/strategies/agnostic/relate.hpp new file mode 100644 index 0000000000..318047fadb --- /dev/null +++ b/boost/geometry/strategies/agnostic/relate.hpp @@ -0,0 +1,91 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP + +#include <boost/geometry/algorithms/detail/relate/relate.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace relate +{ + +template <typename StaticMask> +struct relate +{ + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + return detail::relate::relate<StaticMask>(geometry1, geometry2); + } +}; + +} // namespace relate + +namespace within +{ + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> +struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2> +{ + typedef strategy::relate::relate<detail::relate::static_mask_within> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> +struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2> +{ + typedef strategy::relate::relate<detail::relate::static_mask_within> type; +}; + + +} // namespace services + +#endif + + +}} // namespace strategy::within + + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace strategy { namespace covered_by { namespace services +{ + + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> +struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2> +{ + typedef strategy::relate::relate<detail::relate::static_mask_covered_by> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> +struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2> +{ + typedef strategy::relate::relate<detail::relate::static_mask_covered_by> type; +}; + + +}}} // namespace strategy::covered_by::services +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP diff --git a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp index 4a1a22d1cf..8ad3bbc50d 100644 --- a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp +++ b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp @@ -65,163 +65,238 @@ namespace detail return douglas_peucker_point<Point>(*this); } }; -} -#endif // DOXYGEN_NO_DETAIL + template + < + typename Point, + typename PointDistanceStrategy, + typename LessCompare + = std::less + < + typename strategy::distance::services::return_type + < + PointDistanceStrategy, + Point, Point + >::type + > + > + class douglas_peucker + : LessCompare // for empty base optimization + { + public : -/*! -\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; - // 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, + Point, Point + >::type distance_type; - typedef typename strategy::distance::services::return_type<distance_strategy_type>::type return_type; + douglas_peucker() + {} -private : - typedef detail::douglas_peucker_point<Point> dp_point_type; - typedef typename std::vector<dp_point_type>::iterator iterator_type; + douglas_peucker(LessCompare const& less_compare) + : LessCompare(less_compare) + {} + 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) + LessCompare const& less() const { -#ifdef GL_DEBUG_DOUGLAS_PEUCKER - if (begin != end) + return *this; + } + + inline void consider(iterator_type begin, + iterator_type end, + distance_type const& max_dist, + int& n, + distance_strategy_type const& ps_distance_strategy) const + { + 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) { - std::cout << "ignore between " << dsv(begin->p) - << " and " << dsv((end - 1)->p) - << " size=" << size << std::endl; - } - std::cout << "return because size=" << size << std::endl; +#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; - } + return; + } - iterator_type last = end - 1; + 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; + 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); + // Find most far point, compare to the current segment + //geometry::segment<Point const> s(begin->p, last->p); + distance_type md(-1.0); // any value < 0 + iterator_type candidate; + for(iterator_type it = begin + 1; it != last; ++it) + { + distance_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; + 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 ( less()(md, dist) ) + { + md = dist; + candidate = it; + } } - } - // If a point is found, set the include flag - // and handle segments in between recursively - if (md > max_dist) - { + // If a point is found, set the include flag + // and handle segments in between recursively + if ( less()(max_dist, md) ) + { #ifdef GL_DEBUG_DOUGLAS_PEUCKER - std::cout << "use " << dsv(candidate->p) << std::endl; + std::cout << "use " << dsv(candidate->p) << std::endl; #endif - candidate->included = true; - n++; + candidate->included = true; + n++; - consider(begin, candidate + 1, max_dist, n, ps_distance_strategy); - consider(candidate, end, max_dist, n, ps_distance_strategy); + 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> + inline OutputIterator apply(Range const& range, + OutputIterator out, + distance_type max_distance) const + { + 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 + 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; + } + + }; + + +} +#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. +\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 +*/ + +/* +For the algorithm, see for example: + - http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + - http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html +*/ +template +< + typename Point, + typename PointDistanceStrategy +> +class douglas_peucker +{ public : + typedef PointDistanceStrategy distance_strategy_type; + + typedef typename detail::douglas_peucker + < + Point, + PointDistanceStrategy + >::distance_type distance_type; + + typedef distance_type return_type; + template <typename Range, typename OutputIterator> static inline OutputIterator apply(Range const& range, - OutputIterator out, double max_distance) + OutputIterator out, + distance_type max_distance) { - distance_strategy_type strategy; + return detail::douglas_peucker + < + Point, + PointDistanceStrategy + >().apply(range, out, max_distance); + } - // 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; +}} // namespace strategy::simplify - // 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 traits { +template <typename P> +struct point_type<strategy::simplify::detail::douglas_peucker_point<P> > +{ + typedef P type; }; -}} // namespace strategy::simplify +} // namespace traits }} // namespace boost::geometry diff --git a/boost/geometry/strategies/buffer.hpp b/boost/geometry/strategies/buffer.hpp new file mode 100644 index 0000000000..7dbe03b4a9 --- /dev/null +++ b/boost/geometry/strategies/buffer.hpp @@ -0,0 +1,91 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + +/* + + A Buffer-join strategy gets 4 input points. + On the two consecutive segments s1 and s2 (joining at vertex v): + + The lines from parallel at s1, s2 (at buffer-distance) end/start + in two points perpendicular to the segments: p1 and p2. + These parallel lines interesct in point ip + + (s2) + | + | + ^ + | + (p2) |(v) + * +----<--- (s1) + + x(ip) *(p1) + + + So, in clockwise order: + v : vertex point + p1: perpendicular on left side of segment1<1> (perp1) + ip: intersection point + p2: perpendicular on left side of segment2<0> (perp2) +*/ + + + +/*! +\brief Enumerates options for side of buffer (left/right w.r.t. directed + segment) +\ingroup enum +\details Around a linestring, a buffer can be defined left or right. + Around a polygon, assumed clockwise internally, + a buffer is either on the left side (inflates the polygon), or on the + right side (deflates the polygon) +*/ +enum buffer_side_selector { buffer_side_left, buffer_side_right }; + +/*! +\brief Enumerates types of pieces (parts of buffer) around geometries +\ingroup enum +*/ +enum piece_type +{ + buffered_segment, + buffered_join, + buffered_round_end, + buffered_flat_end, + buffered_point, + buffered_concave // always on the inside +}; + + +/*! +\brief Enumerates types of joins +\ingroup enum +*/ +enum join_selector +{ + join_convex, + join_concave, + join_continue, // collinear, next segment touches previous segment + join_spike // collinear, with overlap, next segment goes back +}; + + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP diff --git a/boost/geometry/strategies/cartesian/box_in_box.hpp b/boost/geometry/strategies/cartesian/box_in_box.hpp index 7680b8362c..9889658a13 100644 --- a/boost/geometry/strategies/cartesian/box_in_box.hpp +++ b/boost/geometry/strategies/cartesian/box_in_box.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -21,10 +22,10 @@ #include <boost/geometry/strategies/within.hpp> -namespace boost { namespace geometry { namespace strategy +namespace boost { namespace geometry { namespace strategy { - - + + namespace within { @@ -36,7 +37,8 @@ struct box_within_range , BoxContainingValue const& bing_min , BoxContainingValue const& bing_max) { - return bed_min > bing_min && bed_max < bing_max; + return bing_min <= bed_min && bed_max <= bing_max // contained in containing + && bed_min < bed_max; // interiors overlap } }; @@ -69,9 +71,9 @@ struct relate_box_box_loop 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<min_corner, Dimension>(b_contained), + get<max_corner, Dimension>(b_contained), + get<min_corner, Dimension>(b_containing), get<max_corner, Dimension>(b_containing) ) ) @@ -115,7 +117,7 @@ struct box_in_box { return relate_box_box_loop < - SubStrategy, + SubStrategy, Box1, Box2, 0, dimension<Box1>::type::value >::apply(box1, box2); } @@ -134,9 +136,9 @@ namespace within { namespace services template <typename BoxContained, typename BoxContaining> struct default_strategy < - box_tag, box_tag, - box_tag, areal_tag, - cartesian_tag, cartesian_tag, + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, BoxContained, BoxContaining > { @@ -152,9 +154,9 @@ 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, + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, BoxContained, BoxContaining > { diff --git a/boost/geometry/strategies/cartesian/buffer_end_flat.hpp b/boost/geometry/strategies/cartesian/buffer_end_flat.hpp new file mode 100644 index 0000000000..c01cf4df85 --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_end_flat.hpp @@ -0,0 +1,112 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_END_FLAT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/strategies/tags.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace buffer +{ + + +/*! +\brief Let the buffer create flat ends +\ingroup strategies +\details This strategy can be used as EndStrategy for the buffer algorithm. + It creates a flat end for each linestring-end. It can be applied + for (multi)linestrings. Also it is applicable for spikes in (multi)polygons. + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_end_flat] +[heading Output] +[$img/strategies/buffer_end_flat.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_end_round end_round] +} + */ +class end_flat +{ + +public : + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a flat end + template <typename Point, typename RangeOut, typename DistanceStrategy> + inline void apply(Point const& penultimate_point, + Point const& perp_left_point, + Point const& ultimate_point, + Point const& perp_right_point, + buffer_side_selector side, + DistanceStrategy const& distance, + RangeOut& range_out) const + { + typedef typename coordinate_type<Point>::type coordinate_type; + + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left); + promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right); + + bool reversed = (side == buffer_side_left && dist_right < 0 && -dist_right > dist_left) + || (side == buffer_side_right && dist_left < 0 && -dist_left > dist_right) + ; + if (reversed) + { + range_out.push_back(perp_right_point); + range_out.push_back(perp_left_point); + } + else + { + range_out.push_back(perp_left_point); + range_out.push_back(perp_right_point); + } + // Don't add the ultimate_point (endpoint of the linestring). + // The buffer might be generated completely at one side. + // In other cases it does no harm but is further useless + } + + template <typename NumericType> + static inline NumericType max_distance(NumericType const& distance) + { + return distance; + } + + //! Returns the piece_type (flat end) + static inline piece_type get_piece_type() + { + return buffered_flat_end; + } +#endif // DOXYGEN_SHOULD_SKIP_THIS +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_end_round.hpp b/boost/geometry/strategies/cartesian/buffer_end_round.hpp new file mode 100644 index 0000000000..74780d6165 --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_end_round.hpp @@ -0,0 +1,166 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_END_ROUND_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/strategies/tags.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +#include <boost/geometry/io/wkt/wkt.hpp> + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace buffer +{ + + +/*! +\brief Let the buffer create rounded ends +\ingroup strategies +\details This strategy can be used as EndStrategy for the buffer algorithm. + It creates a rounded end for each linestring-end. It can be applied + for (multi)linestrings. Also it is applicable for spikes in (multi)polygons. + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_end_round] +[heading Output] +[$img/strategies/buffer_end_round.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_end_flat end_flat] +} + */ +class end_round +{ +private : + std::size_t m_points_per_circle; + + template + < + typename Point, + typename PromotedType, + typename DistanceType, + typename RangeOut + > + inline void generate_points(Point const& point, + PromotedType alpha, // by value + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + PromotedType const two = 2.0; + PromotedType const two_pi = two * geometry::math::pi<PromotedType>(); + + std::size_t point_buffer_count = m_points_per_circle; + + PromotedType const diff = two_pi / PromotedType(point_buffer_count); + + // For half circle: + point_buffer_count /= 2; + point_buffer_count++; + + for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff) + { + typename boost::range_value<RangeOut>::type p; + set<0>(p, get<0>(point) + buffer_distance * cos(alpha)); + set<1>(p, get<1>(point) + buffer_distance * sin(alpha)); + range_out.push_back(p); + } + } + + template <typename T, typename P1, typename P2> + static 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)); + } + +public : + + //! \brief Constructs the strategy + //! \param points_per_circle points which would be used for a full circle + explicit inline end_round(std::size_t points_per_circle = 90) + : m_points_per_circle(points_per_circle) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + //! Fills output_range with a flat end + template <typename Point, typename RangeOut, typename DistanceStrategy> + inline void apply(Point const& penultimate_point, + Point const& perp_left_point, + Point const& ultimate_point, + Point const& , + buffer_side_selector side, + DistanceStrategy const& distance, + RangeOut& range_out) const + { + typedef typename coordinate_type<Point>::type coordinate_type; + + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + promoted_type const alpha = calculate_angle<promoted_type>(perp_left_point, ultimate_point); + + promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left); + promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right); + if (geometry::math::equals(dist_left, dist_right)) + { + generate_points(ultimate_point, alpha, dist_left, range_out); + } + else + { + promoted_type const two = 2.0; + promoted_type dist_half_diff = (dist_left - dist_right) / two; + + if (side == buffer_side_right) + { + dist_half_diff = -dist_half_diff; + } + + Point shifted_point; + set<0>(shifted_point, get<0>(ultimate_point) + dist_half_diff * cos(alpha)); + set<1>(shifted_point, get<1>(ultimate_point) + dist_half_diff * sin(alpha)); + generate_points(shifted_point, alpha, (dist_left + dist_right) / two, range_out); + } + } + + template <typename NumericType> + static inline NumericType max_distance(NumericType const& distance) + { + return distance; + } + + //! Returns the piece_type (flat end) + static inline piece_type get_piece_type() + { + return buffered_round_end; + } +#endif // DOXYGEN_SHOULD_SKIP_THIS +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_join_miter.hpp b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp new file mode 100644 index 0000000000..8fcf3b996c --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp @@ -0,0 +1,140 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_JOIN_MITER_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP + +#include <boost/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + +/*! +\brief Let the buffer create sharp corners +\ingroup strategies +\details This strategy can be used as JoinStrategy for the buffer algorithm. + It creates a sharp corners around each convex vertex. It can be applied + for (multi)linestrings and (multi)polygons. + If corners are sharp by themselves, the miters might become very long. Therefore + there is a limit (miter_limit), in terms of the used distance, which limits + their length. The miter is not changed to a bevel form (as done in some + other software), it is just adapted to the specified miter_limit but keeps + its miter form. + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_join_miter] +[heading Output] +[$img/strategies/buffer_join_miter.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_join_round join_round] +} + */ +class join_miter +{ +public: + + //! \brief Constructs the strategy + //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners + explicit inline join_miter(double miter_limit = 5.0) + : m_miter_limit(valid_limit(miter_limit)) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a sharp shape around a vertex + template <typename Point, typename DistanceType, typename RangeOut> + inline bool apply(Point const& ip, Point const& vertex, + Point const& perp1, Point const& perp2, + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + geometry::equal_to<Point> equals; + if (equals(ip, vertex)) + { + return false; + } + if (equals(perp1, perp2)) + { + return false; + } + + typedef typename coordinate_type<Point>::type coordinate_type; + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + Point p = ip; + + // Check the distance ip-vertex (= miter distance) + // (We calculate it manually (not using Pythagoras strategy) to reuse + // dx and dy) + coordinate_type const dx = get<0>(p) - get<0>(vertex); + coordinate_type const dy = get<1>(p) - get<1>(vertex); + + promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy); + + promoted_type const max_distance + = m_miter_limit * geometry::math::abs(buffer_distance); + + if (distance > max_distance) + { + BOOST_ASSERT(distance != 0.0); + + promoted_type const proportion = max_distance / distance; + set<0>(p, get<0>(vertex) + dx * proportion); + set<1>(p, get<1>(vertex) + dy * proportion); + } + + range_out.push_back(perp1); + range_out.push_back(p); + range_out.push_back(perp2); + return true; + } + + template <typename NumericType> + inline NumericType max_distance(NumericType const& distance) const + { + return distance * m_miter_limit; + } + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + double valid_limit(double miter_limit) const + { + if (miter_limit < 1.0) + { + // It should always exceed the buffer distance + miter_limit = 1.0; + } + return miter_limit; + } + + double m_miter_limit; +}; + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_join_round.hpp b/boost/geometry/strategies/cartesian/buffer_join_round.hpp new file mode 100644 index 0000000000..9e467c85a0 --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_join_round.hpp @@ -0,0 +1,177 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_JOIN_ROUND_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP + +#include <boost/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN +#include <boost/geometry/io/wkt/wkt.hpp> +#endif + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace buffer +{ + +/*! +\brief Let the buffer create rounded corners +\ingroup strategies +\details This strategy can be used as JoinStrategy for the buffer algorithm. + It creates a rounded corners around each convex vertex. It can be applied + for (multi)linestrings and (multi)polygons. + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_join_round] +[heading Output] +[$img/strategies/buffer_join_round.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_join_miter join_miter] +} + */ +class join_round +{ +public : + + //! \brief Constructs the strategy + //! \param points_per_circle points which would be used for a full circle + explicit inline join_round(std::size_t points_per_circle = 90) + : m_points_per_circle(points_per_circle) + {} + +private : + template + < + typename PromotedType, + typename Point, + typename DistanceType, + typename RangeOut + > + inline void generate_points(Point const& vertex, + Point const& perp1, Point const& perp2, + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + PromotedType dx1 = get<0>(perp1) - get<0>(vertex); + PromotedType dy1 = get<1>(perp1) - get<1>(vertex); + PromotedType dx2 = get<0>(perp2) - get<0>(vertex); + PromotedType dy2 = get<1>(perp2) - get<1>(vertex); + + BOOST_ASSERT(buffer_distance != 0); + + dx1 /= buffer_distance; + dy1 /= buffer_distance; + dx2 /= buffer_distance; + dy2 /= buffer_distance; + + PromotedType angle_diff = acos(dx1 * dx2 + dy1 * dy2); + + PromotedType two = 2.0; + PromotedType steps = m_points_per_circle; + int n = boost::numeric_cast<int>(steps * angle_diff + / (two * geometry::math::pi<PromotedType>())); + + if (n <= 1) + { + return; + } + + PromotedType const angle1 = atan2(dy1, dx1); + PromotedType diff = angle_diff / PromotedType(n); + PromotedType a = angle1 - diff; + + for (int i = 0; i < n - 1; i++, a -= diff) + { + Point p; + set<0>(p, get<0>(vertex) + buffer_distance * cos(a)); + set<1>(p, get<1>(vertex) + buffer_distance * sin(a)); + range_out.push_back(p); + } + } + +public : + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a rounded shape around a vertex + template <typename Point, typename DistanceType, typename RangeOut> + inline bool apply(Point const& ip, Point const& vertex, + Point const& perp1, Point const& perp2, + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + typedef typename coordinate_type<Point>::type coordinate_type; + typedef typename boost::range_value<RangeOut>::type output_point_type; + + typedef typename geometry::select_most_precise + < + typename geometry::select_most_precise + < + coordinate_type, + typename geometry::coordinate_type<output_point_type>::type + >::type, + double + >::type promoted_type; + + geometry::equal_to<Point> equals; + if (equals(perp1, perp2)) + { +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN + std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl; +#endif + return false; + } + + // Generate 'vectors' + coordinate_type vix = (get<0>(ip) - get<0>(vertex)); + coordinate_type viy = (get<1>(ip) - get<1>(vertex)); + + promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy); + DistanceType const bd = geometry::math::abs(buffer_distance); + promoted_type prop = bd / length_i; + + Point bp; + set<0>(bp, get<0>(vertex) + vix * prop); + set<1>(bp, get<1>(vertex) + viy * prop); + + range_out.push_back(perp1); + generate_points<promoted_type>(vertex, perp1, perp2, bd, range_out); + range_out.push_back(perp2); + return true; + } + + template <typename NumericType> + static inline NumericType max_distance(NumericType const& distance) + { + return distance; + } + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + std::size_t m_points_per_circle; +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp b/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp new file mode 100644 index 0000000000..1444c795af --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp @@ -0,0 +1,155 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP + +#include <boost/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN +#include <boost/geometry/io/wkt/wkt.hpp> +#endif + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace buffer +{ + + +class join_round_by_divide +{ +public : + + inline join_round_by_divide(std::size_t max_level = 4) + : m_max_level(max_level) + {} + + template + < + typename PromotedType, + typename Point, + typename DistanceType, + typename RangeOut + > + inline void mid_points(Point const& vertex, + Point const& p1, Point const& p2, + DistanceType const& buffer_distance, + RangeOut& range_out, + std::size_t level = 1) const + { + typedef typename coordinate_type<Point>::type coordinate_type; + + // Generate 'vectors' + coordinate_type const vp1_x = get<0>(p1) - get<0>(vertex); + coordinate_type const vp1_y = get<1>(p1) - get<1>(vertex); + + coordinate_type const vp2_x = (get<0>(p2) - get<0>(vertex)); + coordinate_type const vp2_y = (get<1>(p2) - get<1>(vertex)); + + // Average them to generate vector in between + coordinate_type const two = 2; + coordinate_type const v_x = (vp1_x + vp2_x) / two; + coordinate_type const v_y = (vp1_y + vp2_y) / two; + + PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y); + + PromotedType prop = buffer_distance / length2; + + Point mid_point; + set<0>(mid_point, get<0>(vertex) + v_x * prop); + set<1>(mid_point, get<1>(vertex) + v_y * prop); + + if (level < m_max_level) + { + mid_points<PromotedType>(vertex, p1, mid_point, buffer_distance, range_out, level + 1); + } + range_out.push_back(mid_point); + if (level < m_max_level) + { + mid_points<PromotedType>(vertex, mid_point, p2, buffer_distance, range_out, level + 1); + } + } + + template <typename Point, typename DistanceType, typename RangeOut> + inline bool apply(Point const& ip, Point const& vertex, + Point const& perp1, Point const& perp2, + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + typedef typename coordinate_type<Point>::type coordinate_type; + + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + geometry::equal_to<Point> equals; + + if (equals(perp1, perp2)) + { +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN + std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl; +#endif + return false; + } + + // Generate 'vectors' + coordinate_type const vix = (get<0>(ip) - get<0>(vertex)); + coordinate_type const viy = (get<1>(ip) - get<1>(vertex)); + + promoted_type const length_i = geometry::math::sqrt(vix * vix + viy * viy); + + promoted_type const bd = geometry::math::abs(buffer_distance); + promoted_type prop = bd / length_i; + + Point bp; + set<0>(bp, get<0>(vertex) + vix * prop); + set<1>(bp, get<1>(vertex) + viy * prop); + + range_out.push_back(perp1); + + if (m_max_level > 1) + { + mid_points<promoted_type>(vertex, perp1, bp, bd, range_out); + range_out.push_back(bp); + mid_points<promoted_type>(vertex, bp, perp2, bd, range_out); + } + else if (m_max_level == 1) + { + range_out.push_back(bp); + } + + range_out.push_back(perp2); + return true; + } + + template <typename NumericType> + static inline NumericType max_distance(NumericType const& distance) + { + return distance; + } + +private : + std::size_t m_max_level; +}; + + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_point_circle.hpp b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp new file mode 100644 index 0000000000..f64a82d8fc --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp @@ -0,0 +1,108 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_POINT_CIRCLE_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + +/*! +\brief Create a circular buffer around a point +\ingroup strategies +\details This strategy can be used as PointStrategy for the buffer algorithm. + It creates a circular buffer around a point. It can be applied + for points and multi_points, but also for a linestring (if it is degenerate, + so consisting of only one point) and for polygons (if it is degenerate). + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_point_circle] +[heading Output] +[$img/strategies/buffer_point_circle.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_point_square point_square] +} + */ +class point_circle +{ +public : + //! \brief Constructs the strategy + //! \param count number of points for the created circle + explicit point_circle(std::size_t count = 90) + : m_count(count) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a circle around point using distance_strategy + template + < + typename Point, + typename OutputRange, + typename DistanceStrategy + > + inline void apply(Point const& point, + DistanceStrategy const& distance_strategy, + OutputRange& output_range) const + { + typedef typename boost::range_value<OutputRange>::type output_point_type; + + typedef typename geometry::select_most_precise + < + typename geometry::select_most_precise + < + typename geometry::coordinate_type<Point>::type, + typename geometry::coordinate_type<output_point_type>::type + >::type, + double + >::type promoted_type; + + promoted_type const buffer_distance = distance_strategy.apply(point, point, + strategy::buffer::buffer_side_left); + + promoted_type const two = 2.0; + promoted_type const two_pi = two * geometry::math::pi<promoted_type>(); + + promoted_type const diff = two_pi / promoted_type(m_count); + promoted_type a = 0; + + for (std::size_t i = 0; i < m_count; i++, a -= diff) + { + output_point_type p; + set<0>(p, get<0>(point) + buffer_distance * cos(a)); + set<1>(p, get<1>(point) + buffer_distance * sin(a)); + output_range.push_back(p); + } + + // Close it: + output_range.push_back(output_range.front()); + } +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + std::size_t m_count; +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_point_square.hpp b/boost/geometry/strategies/cartesian/buffer_point_square.hpp new file mode 100644 index 0000000000..37a90c013f --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_point_square.hpp @@ -0,0 +1,109 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_POINT_SQUARE_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP + +#include <cstddef> + +#include <boost/range.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + +/*! +\brief Create a squared form buffer around a point +\ingroup strategies +\details This strategy can be used as PointStrategy for the buffer algorithm. + It creates a square from each point, where the point lies in the center. + It can be applied for points and multi_points, but also for a linestring (if it is degenerate, + so consisting of only one point) and for polygons (if it is degenerate). + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_point_square] +[heading Output] +[$img/strategies/buffer_point_square.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_point_circle point_circle] +} + */ +class point_square +{ + template + < + typename Point, + typename DistanceType, + typename OutputRange + > + inline void add_point(Point const& point, + DistanceType const& distance, + DistanceType const& x, + DistanceType const& y, + OutputRange& output_range) const + { + typename boost::range_value<OutputRange>::type p; + set<0>(p, get<0>(point) + x * distance); + set<1>(p, get<1>(point) + y * distance); + output_range.push_back(p); + } + + template + < + typename Point, + typename DistanceType, + typename OutputRange + > + inline void add_points(Point const& point, + DistanceType const& distance, + OutputRange& output_range) const + { + add_point(point, distance, -1.0, -1.0, output_range); + add_point(point, distance, -1.0, +1.0, output_range); + add_point(point, distance, +1.0, +1.0, output_range); + add_point(point, distance, +1.0, -1.0, output_range); + + // Close it: + output_range.push_back(output_range.front()); + } + +public : + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a square around point using distance_strategy + template + < + typename Point, + typename DistanceStrategy, + typename OutputRange + > + inline void apply(Point const& point, + DistanceStrategy const& distance_strategy, + OutputRange& output_range) const + { + add_points(point, distance_strategy.apply(point, point, + strategy::buffer::buffer_side_left), output_range); + } +#endif // DOXYGEN_SHOULD_SKIP_THIS + +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP diff --git a/boost/geometry/strategies/cartesian/buffer_side_straight.hpp b/boost/geometry/strategies/cartesian/buffer_side_straight.hpp new file mode 100644 index 0000000000..24655ab3d7 --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_side_straight.hpp @@ -0,0 +1,105 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Use, modification and distribution is subject to the Boost Software License, +// 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_BUFFER_SIDE_STRAIGHT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP + +#include <cstddef> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/strategies/side.hpp> + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + + + +/*! +\brief Let the buffer use straight sides along segments (the default) +\ingroup strategies +\details This strategy can be used as SideStrategy for the buffer algorithm. + It is currently the only provided strategy for this purpose + +\qbk{ +[heading Example] +See the examples for other buffer strategies\, for example +[link geometry.reference.strategies.strategy_buffer_join_round join_round] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +} + */ +class side_straight +{ +public : +#ifndef DOXYGEN_SHOULD_SKIP_THIS + template + < + typename Point, + typename OutputRange, + typename DistanceStrategy + > + static inline void apply( + Point const& input_p1, Point const& input_p2, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance, + OutputRange& output_range) + { + typedef typename coordinate_type<Point>::type coordinate_type; + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + // Generate a block along (left or right of) the segment + + // Simulate a vector d (dx,dy) + coordinate_type const dx = get<0>(input_p2) - get<0>(input_p1); + coordinate_type const dy = get<1>(input_p2) - get<1>(input_p1); + + // For normalization [0,1] (=dot product d.d, sqrt) + promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy); + + if (geometry::math::equals(length, 0)) + { + // Coordinates are simplified and therefore most often not equal. + // But if simplify is skipped, or for lines with two + // equal points, length is 0 and we cannot generate output. + return; + } + + // Generate the normalized perpendicular p, to the left (ccw) + promoted_type const px = -dy / length; + promoted_type const py = dx / length; + + promoted_type const d = distance.apply(input_p1, input_p2, side); + + output_range.resize(2); + + set<0>(output_range.front(), get<0>(input_p1) + px * d); + set<1>(output_range.front(), get<1>(input_p1) + py * d); + set<0>(output_range.back(), get<0>(input_p2) + px * d); + set<1>(output_range.back(), get<1>(input_p2) + py * d); + } +#endif // DOXYGEN_SHOULD_SKIP_THIS +}; + + +}} // namespace strategy::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP diff --git a/boost/geometry/strategies/cartesian/cart_intersect.hpp b/boost/geometry/strategies/cartesian/cart_intersect.hpp index ea92cf37b0..66af2d2e9c 100644 --- a/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 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 @@ -18,6 +19,9 @@ #include <boost/geometry/arithmetic/determinant.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_calculation_type.hpp> @@ -27,59 +31,24 @@ #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> #include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/strategies/intersection_result.hpp> - -namespace boost { namespace geometry -{ +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> -namespace strategy { namespace intersection -{ +#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) +# include <boost/geometry/io/wkt/write.hpp> +#endif -#ifndef DOXYGEN_NO_DETAIL -namespace detail +namespace boost { namespace geometry { -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) +namespace strategy { namespace intersection { - 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 @@ -88,650 +57,307 @@ 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) + template <typename D, typename W, typename ResultType> + static inline void cramers_rule(D const& dx_a, D const& dy_a, + D const& dx_b, D const& dy_b, W const& wx, W const& wy, + // out: + ResultType& d, ResultType& da) { - 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); + // Cramers rule + d = geometry::detail::determinant<ResultType>(dx_a, dy_a, dx_b, dy_b); + da = geometry::detail::determinant<ResultType>(dx_b, dy_b, wx, wy); + // Ratio is da/d , collinear if d == 0, intersecting if 0 <= r <= 1 + // IntersectionPoint = (x1 + r * dx_a, y1 + r * dy_a) } - // 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) + // Relate segments a and b + template <typename Segment1, typename Segment2, typename RobustPolicy> + static inline return_type apply(Segment1 const& a, Segment2 const& b, + RobustPolicy const& robust_policy) { - typedef side::side_by_triangle<coordinate_type> side; - side_info sides; - - 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)) - ); + // type them all as in Segment1 - TODO reconsider this, most precise? + typedef typename geometry::point_type<Segment1>::type point_type; - bool collinear = sides.collinear(); + typedef typename geometry::robust_point_type + < + point_type, RobustPolicy + >::type robust_point_type; - robustness_verify_collinear(a, b, sides, collinear); - robustness_verify_meeting(a, b, sides, collinear, collinear_use_first); + point_type a0, a1, b0, b1; + robust_point_type a0_rob, a1_rob, b0_rob, b1_rob; - 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(); - } - } + detail::assign_point_from_index<0>(a, a0); + detail::assign_point_from_index<1>(a, a1); + detail::assign_point_from_index<0>(b, b0); + detail::assign_point_from_index<1>(b, b1); - // Degenerate cases: segments of single point, lying on other segment, non disjoint - coordinate_type const zero = 0; - if (math::equals(dx_a, zero) && math::equals(dy_a, zero)) - { - return Policy::degenerate(a, true); - } - if (math::equals(dx_b, zero) && math::equals(dy_b, zero)) - { - return Policy::degenerate(b, false); - } + geometry::recalculate(a0_rob, a0, robust_policy); + geometry::recalculate(a1_rob, a1, robust_policy); + geometry::recalculate(b0_rob, b0, robust_policy); + geometry::recalculate(b1_rob, b1, robust_policy); - typedef typename select_most_precise - < - coordinate_type, double - >::type promoted_type; + return apply(a, b, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob); + } - // 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); + // The main entry-routine, calculating intersections of segments a / b + template <typename Segment1, typename Segment2, typename RobustPolicy, typename RobustPoint> + static inline return_type apply(Segment1 const& a, Segment2 const& b, + RobustPolicy const& robust_policy, + RobustPoint const& robust_a1, RobustPoint const& robust_a2, + RobustPoint const& robust_b1, RobustPoint const& robust_b2) + { + BOOST_CONCEPT_ASSERT( (concept::ConstSegment<Segment1>) ); + BOOST_CONCEPT_ASSERT( (concept::ConstSegment<Segment2>) ); - if (! robustness_verify_r(a, b, r)) - { - return Policy::disjoint(); - } + boost::ignore_unused_variable_warning(robust_policy); - robustness_handle_meeting(a, b, sides, dx_a, dy_a, wx, wy, d, r); + typedef typename select_calculation_type + <Segment1, Segment2, CalculationType>::type coordinate_type; - if (robustness_verify_disjoint_at_one_collinear(a, b, sides)) - { - return Policy::disjoint(); - } + using geometry::detail::equals::equals_point_point; + bool const a_is_point = equals_point_point(robust_a1, robust_a2); + bool const b_is_point = equals_point_point(robust_b1, robust_b2); - } - } + typedef side::side_by_triangle<coordinate_type> side; - if(collinear) + if(a_is_point && b_is_point) { - 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 equals_point_point(robust_a1, robust_b2) + ? Policy::degenerate(a, true) + : Policy::disjoint() + ; } - return Policy::segments_intersect(sides, r, - dx_a, dy_a, dx_b, dy_b, - a, b); - } - -private : + side_info sides; + sides.set<0>(side::apply(robust_b1, robust_b2, robust_a1), + side::apply(robust_b1, robust_b2, robust_a2)); + sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1), + side::apply(robust_a1, robust_a2, robust_b2)); + bool collinear = sides.collinear(); - // 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 (sides.same<0>() || sides.same<1>()) { - 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(); + // Both points are at same side of other segment, we can leave + return Policy::disjoint(); + } - // 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) + typedef typename select_most_precise + < + coordinate_type, double + >::type promoted_type; - // 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 + typedef typename geometry::coordinate_type + < + RobustPoint + >::type robust_coordinate_type; - // If segments are touching (two sides zero), of course they should intersect - // This is (only) in case #buffer_rt_i in the unit tests) + typedef typename segment_ratio_type + < + typename geometry::point_type<Segment1>::type, // TODO: most precise point? + RobustPolicy + >::type ratio_type; - // If one touches in the middle, they also should intersect (#buffer_rt_j) + segment_intersection_info + < + coordinate_type, + promoted_type, + ratio_type + > sinfo; - // Note that even for ttmath r is occasionally > 1, e.g. 1.0000000000000000000000036191231203575 + sinfo.dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir + sinfo.dx_b = get<1, 0>(b) - get<0, 0>(b); + sinfo.dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir + sinfo.dy_b = get<1, 1>(b) - get<0, 1>(b); - if (r > one) - { - r = one; - } - else if (r < zero) - { - r = zero; - } - } - return true; - } + robust_coordinate_type const robust_dx_a = get<0>(robust_a2) - get<0>(robust_a1); + robust_coordinate_type const robust_dx_b = get<0>(robust_b2) - get<0>(robust_b1); + robust_coordinate_type const robust_dy_a = get<1>(robust_a2) - get<1>(robust_a1); + robust_coordinate_type const robust_dy_b = get<1>(robust_b2) - get<1>(robust_b1); - static inline void robustness_verify_collinear( - segment_type1 const& a, segment_type2 const& b, - side_info& sides, - bool& collinear) - { - if ((sides.zero<0>() && ! sides.zero<1>()) || (sides.zero<1>() && ! sides.zero<0>())) + // r: ratio 0-1 where intersection divides A/B + // (only calculated for non-collinear segments) + if (! collinear) { - // 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; - } - } + robust_coordinate_type robust_da0, robust_da; + robust_coordinate_type robust_db0, robust_db; - 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) - ) - ) + cramers_rule(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b, + get<0>(robust_a1) - get<0>(robust_b1), + get<1>(robust_a1) - get<1>(robust_b1), + robust_da0, robust_da); + + cramers_rule(robust_dx_b, robust_dy_b, robust_dx_a, robust_dy_a, + get<0>(robust_b1) - get<0>(robust_a1), + get<1>(robust_b1) - get<1>(robust_a1), + robust_db0, robust_db); + + if (robust_da0 == 0) { + // If this is the case, no rescaling is done for FP precision. + // We set it to collinear, but it indicates a robustness issue. 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) - )) + else { - sides.correct_to_zero<1, 1>(); - corrected = 2; + sinfo.robust_ra.assign(robust_da, robust_da0); + sinfo.robust_rb.assign(robust_db, robust_db0); } } - else if (sides.one_touching<1>()) + + if (collinear) { - if (point_equals( - select(sides.zero_index<1>(), b), - select(0, a) - )) + bool const collinear_use_first + = geometry::math::abs(robust_dx_a) + geometry::math::abs(robust_dx_b) + >= geometry::math::abs(robust_dy_a) + geometry::math::abs(robust_dy_b); + + // Degenerate cases: segments of single point, lying on other segment, are not disjoint + // This situation is collinear too + + if (collinear_use_first) { - sides.correct_to_zero<0, 0>(); - corrected = 3; + return relate_collinear<0, ratio_type>(a, b, + robust_a1, robust_a2, robust_b1, robust_b2, + a_is_point, b_is_point); } - if (point_equals - ( - select(sides.zero_index<1>(), b), - select(1, a) - )) + else { - sides.correct_to_zero<0, 1>(); - corrected = 4; + // Y direction contains larger segments (maybe dx is zero) + return relate_collinear<1, ratio_type>(a, b, + robust_a1, robust_a2, robust_b1, robust_b2, + a_is_point, b_is_point); } } - return corrected == 0; + return Policy::segments_crosses(sides, sinfo, a, b); } - static inline bool robustness_verify_disjoint_at_one_collinear( - segment_type1 const& a, segment_type2 const& b, - side_info const& sides) +private: + template + < + std::size_t Dimension, + typename RatioType, + typename Segment1, + typename Segment2, + typename RobustPoint + > + static inline return_type relate_collinear(Segment1 const& a, + Segment2 const& b, + RobustPoint const& robust_a1, RobustPoint const& robust_a2, + RobustPoint const& robust_b1, RobustPoint const& robust_b2, + bool a_is_point, bool b_is_point) { - if (sides.one_of_all_zero()) + if (a_is_point) { - if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b)) - { - return true; - } + return relate_one_degenerate<RatioType>(a, + get<Dimension>(robust_a1), + get<Dimension>(robust_b1), get<Dimension>(robust_b2), + 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)) + if (b_is_point) { - 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 << " "; - } - } + return relate_one_degenerate<RatioType>(b, + get<Dimension>(robust_b1), + get<Dimension>(robust_a1), get<Dimension>(robust_a2), + false); } + return relate_collinear<RatioType>(a, b, + get<Dimension>(robust_a1), + get<Dimension>(robust_a2), + get<Dimension>(robust_b1), + get<Dimension>(robust_b2)); } - 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) + /// Relate segments known collinear + template + < + typename RatioType, + typename Segment1, + typename Segment2, + typename RobustType + > + static inline return_type relate_collinear(Segment1 const& a + , Segment2 const& b + , RobustType oa_1, RobustType oa_2 + , RobustType ob_1, RobustType ob_2 + ) { - 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) + // Calculate the ratios where a starts in b, b starts in a + // a1--------->a2 (2..7) + // b1----->b2 (5..8) + // length_a: 7-2=5 + // length_b: 8-5=3 + // b1 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a) + // b2 is located w.r.t. a at ratio: (8-2)/5=6/5 (right of a) + // a1 is located w.r.t. b at ratio: (2-5)/3=-3/3 (left of b) + // a2 is located w.r.t. b at ratio: (7-5)/3=2/3 (on b) + // A arrives (a2 on b), B departs (b1 on a) + + // If both are reversed: + // a2<---------a1 (7..2) + // b2<-----b1 (8..5) + // length_a: 2-7=-5 + // length_b: 5-8=-3 + // b1 is located w.r.t. a at ratio: (8-7)/-5=-1/5 (before a starts) + // b2 is located w.r.t. a at ratio: (5-7)/-5=2/5 (on a) + // a1 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b) + // a2 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends) + + // If both one is reversed: + // a1--------->a2 (2..7) + // b2<-----b1 (8..5) + // length_a: 7-2=+5 + // length_b: 5-8=-3 + // b1 is located w.r.t. a at ratio: (8-2)/5=6/5 (after a ends) + // b2 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a) + // a1 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends) + // a2 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b) + RobustType const length_a = oa_2 - oa_1; // no abs, see above + RobustType const length_b = ob_2 - ob_1; + + RatioType const ra_from(oa_1 - ob_1, length_b); + RatioType const ra_to(oa_2 - ob_1, length_b); + RatioType const rb_from(ob_1 - oa_1, length_a); + RatioType const rb_to(ob_2 - oa_1, length_a); + + if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right())) { return Policy::disjoint(); } - return relate_collinear(a, b, a_1, a_2, b_1, b_2, a_swapped, b_swapped); + + return Policy::segments_collinear(a, b, ra_from, ra_to, rb_from, rb_to); } - /// 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) + /// Relate segments where one is degenerate + template + < + typename RatioType, + typename DegenerateSegment, + typename RobustType + > + static inline return_type relate_one_degenerate( + DegenerateSegment const& degenerate_segment + , RobustType d + , RobustType s1, RobustType s2 + , bool a_degenerate + ) { - // 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"); + // Calculate the ratios where ds starts in s + // a1--------->a2 (2..6) + // b1/b2 (4..4) + // Ratio: (4-2)/(6-2) + RatioType const ratio(d - s1, s2 - s1); + return Policy::one_degenerate(degenerate_segment, ratio, a_degenerate); } }; }} // namespace strategy::intersection - - }} // namespace boost::geometry diff --git a/boost/geometry/strategies/cartesian/centroid_average.hpp b/boost/geometry/strategies/cartesian/centroid_average.hpp new file mode 100644 index 0000000000..76e2f7144c --- /dev/null +++ b/boost/geometry/strategies/cartesian/centroid_average.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_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP + + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/point_type.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_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP diff --git a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp index 8b42715e0b..f199fb80e5 100644 --- a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp +++ b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp @@ -38,17 +38,26 @@ namespace strategy { namespace centroid /*! -\brief Centroid calculation using algorith Bashein / Detmer +\brief Centroid calculation using algorithm 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 +\tparam CalculationType \tparam_calculation + \author Adapted from "Centroid of a Polygon" by Gerard Bashein and Paul R. Detmer<em>, in "Graphics Gems IV", Academic Press, 1994</em> + + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.centroid.centroid_3_with_strategy centroid (with strategy)] +} +*/ + +/* \par Research notes The algorithm gives the same results as Oracle and PostGIS but differs from MySQL @@ -100,12 +109,6 @@ Statements: , 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 < @@ -151,9 +154,7 @@ private : , sum_a2(calculation_type()) , sum_x(calculation_type()) , sum_y(calculation_type()) - { - typedef calculation_type ct; - } + {} }; public : diff --git a/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp index 48feae51df..b788738d15 100644 --- a/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp +++ b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp @@ -13,7 +13,8 @@ #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/algorithms/detail/distance/interface.hpp> +#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/util/select_most_precise.hpp> #include <boost/geometry/strategies/centroid.hpp> diff --git a/boost/geometry/strategies/cartesian/distance_projected_point.hpp b/boost/geometry/strategies/cartesian/distance_projected_point.hpp index 13d4168445..dff4a77f6f 100644 --- a/boost/geometry/strategies/cartesian/distance_projected_point.hpp +++ b/boost/geometry/strategies/cartesian/distance_projected_point.hpp @@ -1,8 +1,13 @@ // 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. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -44,14 +49,11 @@ 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: @@ -67,10 +69,8 @@ namespace strategy { namespace distance */ template < - typename Point, - typename PointOfSegment = Point, typename CalculationType = void, - typename Strategy = pythagoras<Point, PointOfSegment, CalculationType> + typename Strategy = pythagoras<CalculationType> > class projected_point { @@ -81,47 +81,43 @@ public : // 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; + template <typename Point, typename PointOfSegment> + struct calculation_type + : promote_floating_point + < + typename strategy::distance::services::return_type + < + Strategy, + Point, + PointOfSegment + >::type + > + {}; public : - inline calculation_type apply(Point const& p, - PointOfSegment const& p1, PointOfSegment const& p2) const + template <typename Point, typename PointOfSegment> + inline typename calculation_type<Point, PointOfSegment>::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)] + typedef typename calculation_type<Point, PointOfSegment>::type calculation_type; + + // 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; + + /* + Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)] VECTOR v(x2 - x1, y2 - y1) VECTOR w(px - x1, py - y1) c1 = w . v @@ -132,12 +128,13 @@ public : // 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; + fp_vector_type v, w, projected; geometry::convert(p2, v); geometry::convert(p, w); - subtract_point(v, p1); - subtract_point(w, p1); + geometry::convert(p1, projected); + subtract_point(v, projected); + subtract_point(w, projected); Strategy strategy; boost::ignore_unused_variable_warning(strategy); @@ -157,20 +154,10 @@ public : // 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); - - 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); + return strategy.apply(p, projected); } }; @@ -178,103 +165,59 @@ public : namespace services { -template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> -struct tag<projected_point<Point, PointOfSegment, CalculationType, Strategy> > +template <typename CalculationType, typename Strategy> +struct tag<projected_point<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 CalculationType, typename Strategy, typename P, typename PS> +struct return_type<projected_point<CalculationType, Strategy>, P, PS> + : projected_point<CalculationType, Strategy>::template calculation_type<P, PS> +{}; -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> > +template <typename CalculationType, typename Strategy> +struct comparable_type<projected_point<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> > +template <typename CalculationType, typename Strategy> +struct get_comparable<projected_point<CalculationType, Strategy> > { typedef typename comparable_type < - projected_point<Point, PointOfSegment, CalculationType, Strategy> + projected_point<CalculationType, Strategy> >::type comparable_type; public : - static inline comparable_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& ) + static inline comparable_type apply(projected_point<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> > +template <typename CalculationType, typename Strategy, typename P, typename PS> +struct result_from_distance<projected_point<CalculationType, Strategy>, P, PS> { private : - typedef typename return_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> >::type return_type; + typedef typename return_type<projected_point<CalculationType, Strategy>, P, PS>::type return_type; public : template <typename T> - static inline return_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& , T const& value) + static inline return_type apply(projected_point<CalculationType, Strategy> const& , T const& value) { Strategy s; - return result_from_distance<Strategy>::apply(s, value); + return result_from_distance<Strategy, P, PS>::apply(s, value); } }; @@ -285,19 +228,21 @@ public : // 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> +struct default_strategy + < + point_tag, 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, + point_tag, point_tag, Point, PointOfSegment, cartesian_tag, cartesian_tag >::type, Strategy @@ -305,6 +250,20 @@ struct default_strategy<segment_tag, Point, PointOfSegment, cartesian_tag, carte > type; }; +template <typename PointOfSegment, typename Point, typename Strategy> +struct default_strategy + < + segment_tag, point_tag, PointOfSegment, Point, + cartesian_tag, cartesian_tag, Strategy + > +{ + typedef typename default_strategy + < + point_tag, segment_tag, Point, PointOfSegment, + cartesian_tag, cartesian_tag, Strategy + >::type type; +}; + } // namespace services #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp b/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp new file mode 100644 index 0000000000..c4090044f4 --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp @@ -0,0 +1,316 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_AX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP + + +#include <algorithm> + +#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/strategies/cartesian/distance_projected_point.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 +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename T> +struct projected_point_ax_result +{ + typedef T value_type; + + projected_point_ax_result(T const& c = T(0)) + : atd(c), xtd(c) + {} + + projected_point_ax_result(T const& a, T const& x) + : atd(a), xtd(x) + {} + + friend inline bool operator<(projected_point_ax_result const& left, + projected_point_ax_result const& right) + { + return left.xtd < right.xtd || left.atd < right.atd; + } + + T atd, xtd; +}; + +// This less-comparator may be used as a parameter of detail::douglas_peucker. +// In this simplify strategy distances are compared in 2 places +// 1. to choose the furthest candidate (md < dist) +// 2. to check if the candidate is further than max_distance (max_distance < md) +template <typename Distance> +class projected_point_ax_less +{ +public: + projected_point_ax_less(Distance const& max_distance) + : m_max_distance(max_distance) + {} + + inline bool operator()(Distance const& left, Distance const& right) const + { + //return left.xtd < right.xtd && right.atd < m_max_distance.atd; + + typedef typename Distance::value_type value_type; + + value_type const lx = left.xtd > m_max_distance.xtd ? left.xtd - m_max_distance.xtd : 0; + value_type const rx = right.xtd > m_max_distance.xtd ? right.xtd - m_max_distance.xtd : 0; + value_type const la = left.atd > m_max_distance.atd ? left.atd - m_max_distance.atd : 0; + value_type const ra = right.atd > m_max_distance.atd ? right.atd - m_max_distance.atd : 0; + + value_type const l = (std::max)(lx, la); + value_type const r = (std::max)(rx, ra); + + return l < r; + } +private: + Distance const& m_max_distance; +}; + +// This strategy returns 2-component Point/Segment distance. +// The ATD (along track distance) is parallel to the Segment +// and is a distance between Point projected into a line defined by a Segment and the nearest Segment's endpoint. +// If the projected Point intersects the Segment the ATD is equal to 0. +// The XTD (cross track distance) is perpendicular to the Segment +// and is a distance between input Point and its projection. +// If the Segment has length equal to 0, ATD and XTD has value equal +// to the distance between the input Point and one of the Segment's endpoints. +// +// p3 p4 +// ^ 7 +// | / +// p1<-----e========e----->p2 +// +// p1: atd=D, xtd=0 +// p2: atd=D, xtd=0 +// p3: atd=0, xtd=D +// p4: atd=D/2, xtd=D +template +< + typename CalculationType = void, + typename Strategy = pythagoras<CalculationType> +> +class projected_point_ax +{ +public : + template <typename Point, typename PointOfSegment> + struct calculation_type + : public projected_point<CalculationType, Strategy> + ::template calculation_type<Point, PointOfSegment> + {}; + + template <typename Point, typename PointOfSegment> + struct result_type + { + typedef projected_point_ax_result + < + typename calculation_type<Point, PointOfSegment>::type + > type; + }; + +public : + + template <typename Point, typename PointOfSegment> + inline typename result_type<Point, PointOfSegment>::type + apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const + { + assert_dimension_equal<Point, PointOfSegment>(); + + typedef typename calculation_type<Point, PointOfSegment>::type calculation_type; + + // 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; + + /* + Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)] + 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, projected; + + geometry::convert(p2, v); + geometry::convert(p, w); + geometry::convert(p1, projected); + subtract_point(v, projected); + subtract_point(w, projected); + + Strategy strategy; + boost::ignore_unused_variable_warning(strategy); + + typename result_type<Point, PointOfSegment>::type result; + + calculation_type const zero = calculation_type(); + calculation_type const c2 = dot_product(v, v); + if ( math::equals(c2, zero) ) + { + result.xtd = strategy.apply(p, projected); + // assume that the 0-length segment is perpendicular to the Pt->ProjPt vector + result.atd = 0; + return result; + } + + calculation_type const c1 = dot_product(w, v); + calculation_type const b = c1 / c2; + multiply_value(v, b); + add_point(projected, v); + + result.xtd = strategy.apply(p, projected); + + if (c1 <= zero) + { + result.atd = strategy.apply(p1, projected); + } + else if (c2 <= c1) + { + result.atd = strategy.apply(p2, projected); + } + else + { + result.atd = 0; + } + + return result; + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + + +template <typename CalculationType, typename Strategy> +struct tag<detail::projected_point_ax<CalculationType, Strategy> > +{ + typedef strategy_tag_distance_point_segment type; +}; + + +template <typename CalculationType, typename Strategy, typename P, typename PS> +struct return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS> +{ + typedef typename detail::projected_point_ax<CalculationType, Strategy> + ::template result_type<P, PS>::type type; +}; + + +template <typename CalculationType, typename Strategy> +struct comparable_type<detail::projected_point_ax<CalculationType, Strategy> > +{ + // Define a projected_point strategy with its underlying point-point-strategy + // being comparable + typedef detail::projected_point_ax + < + CalculationType, + typename comparable_type<Strategy>::type + > type; +}; + + +template <typename CalculationType, typename Strategy> +struct get_comparable<detail::projected_point_ax<CalculationType, Strategy> > +{ + typedef typename comparable_type + < + detail::projected_point_ax<CalculationType, Strategy> + >::type comparable_type; +public : + static inline comparable_type apply(detail::projected_point_ax<CalculationType, Strategy> const& ) + { + return comparable_type(); + } +}; + + +template <typename CalculationType, typename Strategy, typename P, typename PS> +struct result_from_distance<detail::projected_point_ax<CalculationType, Strategy>, P, PS> +{ +private : + typedef typename return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS>::type return_type; +public : + template <typename T> + static inline return_type apply(detail::projected_point_ax<CalculationType, Strategy> const& , T const& value) + { + Strategy s; + return_type ret; + ret.atd = result_from_distance<Strategy, P, PS>::apply(s, value.atd); + ret.xtd = result_from_distance<Strategy, P, PS>::apply(s, value.xtd); + return ret; + } +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp index 51d2722663..77bdc966a6 100644 --- a/boost/geometry/strategies/cartesian/distance_pythagoras.hpp +++ b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp @@ -22,6 +22,7 @@ #include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/util/math.hpp> #include <boost/geometry/util/calculation_type.hpp> @@ -37,21 +38,23 @@ namespace strategy { namespace distance namespace detail { -template <typename Point1, typename Point2, size_t I, typename T> +template <size_t I, typename T> struct compute_pythagoras { + template <typename Point1, typename Point2> static inline T apply(Point1 const& p1, Point2 const& p2) { - T const c1 = boost::numeric_cast<T>(get<I-1>(p2)); - T const c2 = boost::numeric_cast<T>(get<I-1>(p1)); + T const 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); + return d * d + compute_pythagoras<I-1, T>::apply(p1, p2); } }; -template <typename Point1, typename Point2, typename T> -struct compute_pythagoras<Point1, Point2, 0, T> +template <typename T> +struct compute_pythagoras<0, T> { + template <typename Point1, typename Point2> static inline T apply(Point1 const&, Point2 const&) { return boost::numeric_cast<T>(0); @@ -72,24 +75,26 @@ namespace comparable \tparam Point2 \tparam_second_point \tparam CalculationType \tparam_calculation */ -template -< - typename Point1, - typename Point2 = Point1, - typename CalculationType = void -> +template <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) + template <typename Point1, typename Point2> + struct calculation_type + : util::calculation_type::geometric::binary + < + Point1, + Point2, + CalculationType, + double, + double + > + {}; + + template <typename Point1, typename Point2> + static inline typename calculation_type<Point1, Point2>::type + apply(Point1 const& p1, Point2 const& p2) { BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point1>) ); BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) ); @@ -101,9 +106,8 @@ public : return detail::compute_pythagoras < - Point1, Point2, dimension<Point1>::value, - calculation_type + typename calculation_type<Point1, Point2>::type >::apply(p1, p2); } }; @@ -114,8 +118,6 @@ public : /*! \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{ @@ -128,22 +130,23 @@ public : */ 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; + + template <typename P1, typename P2> + struct calculation_type + : util::calculation_type::geometric::binary + < + P1, + P2, + CalculationType, + double, + double // promote integer to double + > + {}; /*! \brief applies the distance calculation using pythagoras @@ -151,10 +154,18 @@ public : \param p1 first point \param p2 second point */ - static inline calculation_type apply(Point1 const& p1, Point2 const& p2) + template <typename P1, typename P2> + static inline typename calculation_type<P1, P2>::type + apply(P1 const& p1, P2 const& p2) { - calculation_type const t = comparable_type::apply(p1, p2); - return sqrt(t); + // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call + return math::sqrt + ( + boost::numeric_cast<typename calculation_type<P1, P2>::type> + ( + comparable::pythagoras<CalculationType>::apply(p1, p2) + ) + ); } }; @@ -163,81 +174,46 @@ public : namespace services { -template <typename Point1, typename Point2, typename CalculationType> -struct tag<pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType> +struct tag<pythagoras<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 CalculationType, typename P1, typename P2> +struct return_type<distance::pythagoras<CalculationType>, P1, P2> + : pythagoras<CalculationType>::template calculation_type<P1, P2> +{}; -template <typename Point1, typename Point2, typename CalculationType> -struct comparable_type<pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType> +struct comparable_type<pythagoras<CalculationType> > { - typedef comparable::pythagoras<Point1, Point2, CalculationType> type; + typedef comparable::pythagoras<CalculationType> type; }; -template <typename Point1, typename Point2, typename CalculationType> -struct get_comparable<pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType> +struct get_comparable<pythagoras<CalculationType> > { - typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type; + typedef comparable::pythagoras<CalculationType> comparable_type; public : - static inline comparable_type apply(pythagoras<Point1, Point2, CalculationType> const& ) + static inline comparable_type apply(pythagoras<CalculationType> const& ) { return comparable_type(); } }; -template <typename Point1, typename Point2, typename CalculationType> -struct result_from_distance<pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType, typename Point1, typename Point2> +struct result_from_distance<pythagoras<CalculationType>, Point1, Point2> { private : - typedef typename return_type<pythagoras<Point1, Point2, CalculationType> >::type return_type; + typedef typename return_type<pythagoras<CalculationType>, Point1, Point2>::type return_type; public : template <typename T> - static inline return_type apply(pythagoras<Point1, Point2, CalculationType> const& , T const& value) + static inline return_type apply(pythagoras<CalculationType> const& , T const& value) { return return_type(value); } @@ -245,83 +221,48 @@ public : // Specializations for comparable::pythagoras -template <typename Point1, typename Point2, typename CalculationType> -struct tag<comparable::pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType> +struct tag<comparable::pythagoras<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 CalculationType, typename P1, typename P2> +struct return_type<comparable::pythagoras<CalculationType>, P1, P2> + : comparable::pythagoras<CalculationType>::template calculation_type<P1, P2> +{}; -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> > +template <typename CalculationType> +struct comparable_type<comparable::pythagoras<CalculationType> > { - typedef comparable::pythagoras<Point1, Point2, CalculationType> type; + typedef comparable::pythagoras<CalculationType> type; }; -template <typename Point1, typename Point2, typename CalculationType> -struct get_comparable<comparable::pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType> +struct get_comparable<comparable::pythagoras<CalculationType> > { - typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type; + typedef comparable::pythagoras<CalculationType> comparable_type; public : - static inline comparable_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& ) + static inline comparable_type apply(comparable::pythagoras<CalculationType> const& ) { return comparable_type(); } }; -template <typename Point1, typename Point2, typename CalculationType> -struct result_from_distance<comparable::pythagoras<Point1, Point2, CalculationType> > +template <typename CalculationType, typename Point1, typename Point2> +struct result_from_distance<comparable::pythagoras<CalculationType>, Point1, Point2> { private : - typedef typename return_type<comparable::pythagoras<Point1, Point2, CalculationType> >::type return_type; + typedef typename return_type<comparable::pythagoras<CalculationType>, Point1, Point2>::type return_type; public : template <typename T> - static inline return_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& , T const& value) + static inline return_type apply(comparable::pythagoras<CalculationType> const& , T const& value) { return_type const v = value; return v * v; @@ -330,9 +271,12 @@ public : template <typename Point1, typename Point2> -struct default_strategy<point_tag, Point1, Point2, cartesian_tag, cartesian_tag, void> +struct default_strategy + < + point_tag, point_tag, Point1, Point2, cartesian_tag, cartesian_tag + > { - typedef pythagoras<Point1, Point2> type; + typedef pythagoras<> type; }; diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp new file mode 100644 index 0000000000..8a4234282e --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp @@ -0,0 +1,338 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_BOX_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP + + +#include <boost/geometry/core/access.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/calculation_type.hpp> + + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <std::size_t I> +struct compute_pythagoras_box_box +{ + template <typename Box1, typename Box2, typename T> + static inline void apply(Box1 const& box1, Box2 const& box2, T& result) + { + T const b1_min_coord = + boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box1)); + T const b1_max_coord = + boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box1)); + + T const b2_min_coord = + boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box2)); + T const b2_max_coord = + boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box2)); + + if ( b1_max_coord < b2_min_coord ) + { + T diff = b2_min_coord - b1_max_coord; + result += diff * diff; + } + if ( b1_min_coord > b2_max_coord ) + { + T diff = b1_min_coord - b2_max_coord; + result += diff * diff; + } + + compute_pythagoras_box_box<I-1>::apply(box1, box2, result); + } +}; + +template <> +struct compute_pythagoras_box_box<0> +{ + template <typename Box1, typename Box2, typename T> + static inline void apply(Box1 const&, Box2 const&, T&) + { + } +}; + +} +#endif // DOXYGEN_NO_DETAIL + + +namespace comparable +{ + +/*! +\brief Strategy to calculate comparable distance between two boxes +\ingroup strategies +\tparam Box1 \tparam_first_box +\tparam Box2 \tparam_second_box +\tparam CalculationType \tparam_calculation +*/ +template <typename CalculationType = void> +class pythagoras_box_box +{ +public : + + template <typename Box1, typename Box2> + struct calculation_type + { + typedef typename util::calculation_type::geometric::binary + < + Box1, + Box2, + CalculationType + >::type type; + }; + + template <typename Box1, typename Box2> + static inline typename calculation_type<Box1, Box2>::type + apply(Box1 const& box1, Box2 const& box2) + { + BOOST_CONCEPT_ASSERT + ( (concept::ConstPoint<typename point_type<Box1>::type>) ); + BOOST_CONCEPT_ASSERT + ( (concept::ConstPoint<typename point_type<Box2>::type>) ); + + // Calculate distance using Pythagoras + // (Leave comment above for Doxygen) + + assert_dimension_equal<Box1, Box2>(); + + typename calculation_type<Box1, Box2>::type result(0); + + detail::compute_pythagoras_box_box + < + dimension<Box1>::value + >::apply(box1, box2, result); + + return result; + } +}; + +} // namespace comparable + + +/*! +\brief Strategy to calculate the distance between two boxes +\ingroup strategies +\tparam CalculationType \tparam_calculation + +\qbk{ +[heading Notes] +[note Can be used for boxes with two\, three or more dimensions] +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename CalculationType = void +> +class pythagoras_box_box +{ +public : + + template <typename Box1, typename Box2> + struct calculation_type + : util::calculation_type::geometric::binary + < + Box1, + Box2, + CalculationType, + double, + double // promote integer to double + > + {}; + + /*! + \brief applies the distance calculation using pythagoras_box_box + \return the calculated distance (including taking the square root) + \param box1 first box + \param box2 second box + */ + template <typename Box1, typename Box2> + static inline typename calculation_type<Box1, Box2>::type + apply(Box1 const& box1, Box2 const& box2) + { + // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call + return math::sqrt + ( + boost::numeric_cast<typename calculation_type + < + Box1, Box2 + >::type> + ( + comparable::pythagoras_box_box + < + CalculationType + >::apply(box1, box2) + ) + ); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename CalculationType> +struct tag<pythagoras_box_box<CalculationType> > +{ + typedef strategy_tag_distance_box_box type; +}; + + +template <typename CalculationType, typename Box1, typename Box2> +struct return_type<distance::pythagoras_box_box<CalculationType>, Box1, Box2> + : pythagoras_box_box<CalculationType>::template calculation_type<Box1, Box2> +{}; + + +template <typename CalculationType> +struct comparable_type<pythagoras_box_box<CalculationType> > +{ + typedef comparable::pythagoras_box_box<CalculationType> type; +}; + + +template <typename CalculationType> +struct get_comparable<pythagoras_box_box<CalculationType> > +{ + typedef comparable::pythagoras_box_box<CalculationType> comparable_type; +public : + static inline comparable_type + apply(pythagoras_box_box<CalculationType> const& ) + { + return comparable_type(); + } +}; + + +template <typename CalculationType, typename Box1, typename Box2> +struct result_from_distance<pythagoras_box_box<CalculationType>, Box1, Box2> +{ +private: + typedef typename return_type + < + pythagoras_box_box<CalculationType>, Box1, Box2 + >::type return_type; +public: + template <typename T> + static inline return_type + apply(pythagoras_box_box<CalculationType> const& , T const& value) + { + return return_type(value); + } +}; + + +// Specializations for comparable::pythagoras_box_box +template <typename CalculationType> +struct tag<comparable::pythagoras_box_box<CalculationType> > +{ + typedef strategy_tag_distance_box_box type; +}; + + +template <typename CalculationType, typename Box1, typename Box2> +struct return_type<comparable::pythagoras_box_box<CalculationType>, Box1, Box2> + : comparable::pythagoras_box_box + < + CalculationType + >::template calculation_type<Box1, Box2> +{}; + + + + +template <typename CalculationType> +struct comparable_type<comparable::pythagoras_box_box<CalculationType> > +{ + typedef comparable::pythagoras_box_box<CalculationType> type; +}; + + +template <typename CalculationType> +struct get_comparable<comparable::pythagoras_box_box<CalculationType> > +{ + typedef comparable::pythagoras_box_box<CalculationType> comparable_type; +public : + static inline comparable_type apply(comparable_type const& ) + { + return comparable_type(); + } +}; + + +template <typename CalculationType, typename Box1, typename Box2> +struct result_from_distance + < + comparable::pythagoras_box_box<CalculationType>, Box1, Box2 + > +{ +private : + typedef typename return_type + < + comparable::pythagoras_box_box<CalculationType>, Box1, Box2 + >::type return_type; +public : + template <typename T> + static inline return_type + apply(comparable::pythagoras_box_box<CalculationType> const&, + T const& value) + { + return_type const v = value; + return v * v; + } +}; + + +template <typename BoxPoint1, typename BoxPoint2> +struct default_strategy + < + box_tag, box_tag, BoxPoint1, BoxPoint2, cartesian_tag, cartesian_tag + > +{ + typedef pythagoras_box_box<> type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp new file mode 100644 index 0000000000..0ce1d422ee --- /dev/null +++ b/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp @@ -0,0 +1,349 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_POINT_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP + + +#include <boost/geometry/core/access.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/calculation_type.hpp> + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <size_t I> +struct compute_pythagoras_point_box +{ + template <typename Point, typename Box, typename T> + static inline void apply(Point const& point, Box const& box, T& result) + { + T const p_coord = boost::numeric_cast<T>(geometry::get<I-1>(point)); + T const b_min_coord = + boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box)); + T const b_max_coord = + boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box)); + + if ( p_coord < b_min_coord ) + { + T diff = b_min_coord - p_coord; + result += diff * diff; + } + if ( p_coord > b_max_coord ) + { + T diff = p_coord - b_max_coord; + result += diff * diff; + } + + compute_pythagoras_point_box<I-1>::apply(point, box, result); + } +}; + +template <> +struct compute_pythagoras_point_box<0> +{ + template <typename Point, typename Box, typename T> + static inline void apply(Point const&, Box const&, T&) + { + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +namespace comparable +{ + +/*! + \brief Strategy to calculate comparable distance between a point + and a box + \ingroup strategies + \tparam Point \tparam_first_point + \tparam Box \tparam_second_box + \tparam CalculationType \tparam_calculation +*/ +template <typename CalculationType = void> +class pythagoras_point_box +{ +public : + + template <typename Point, typename Box> + struct calculation_type + { + typedef typename util::calculation_type::geometric::binary + < + Point, Box, CalculationType + >::type type; + }; + + template <typename Point, typename Box> + static inline typename calculation_type<Point, Box>::type + apply(Point const& point, Box const& box) + { + BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point>) ); + BOOST_CONCEPT_ASSERT + ( (concept::ConstPoint<typename point_type<Box>::type>) ); + + // Calculate distance using Pythagoras + // (Leave comment above for Doxygen) + + assert_dimension_equal<Point, Box>(); + + typename calculation_type<Point, Box>::type result(0); + + detail::compute_pythagoras_point_box + < + dimension<Point>::value + >::apply(point, box, result); + + return result; + } +}; + +} // namespace comparable + + +/*! +\brief Strategy to calculate the distance between a point and a box +\ingroup strategies +\tparam CalculationType \tparam_calculation + +\qbk{ +[heading Notes] +[note Can be used for points and boxes with two\, three or more dimensions] +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename CalculationType = void +> +class pythagoras_point_box +{ +public : + + template <typename Point, typename Box> + struct calculation_type + : util::calculation_type::geometric::binary + < + Point, + Box, + CalculationType, + double, + double // promote integer to double + > + {}; + + /*! + \brief applies the distance calculation using pythagoras + \return the calculated distance (including taking the square root) + \param point point + \param box box + */ + template <typename Point, typename Box> + static inline typename calculation_type<Point, Box>::type + apply(Point const& point, Box const& box) + { + // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call + return math::sqrt + ( + boost::numeric_cast<typename calculation_type + < + Point, Box + >::type> + ( + comparable::pythagoras_point_box + < + CalculationType + >::apply(point, box) + ) + ); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename CalculationType> +struct tag<pythagoras_point_box<CalculationType> > +{ + typedef strategy_tag_distance_point_box type; +}; + + +template <typename CalculationType, typename Point, typename Box> +struct return_type<distance::pythagoras_point_box<CalculationType>, Point, Box> + : pythagoras_point_box + < + CalculationType + >::template calculation_type<Point, Box> +{}; + + +template <typename CalculationType> +struct comparable_type<pythagoras_point_box<CalculationType> > +{ + typedef comparable::pythagoras_point_box<CalculationType> type; +}; + + +template <typename CalculationType> +struct get_comparable<pythagoras_point_box<CalculationType> > +{ + typedef comparable::pythagoras_point_box<CalculationType> comparable_type; +public : + static inline comparable_type + apply(pythagoras_point_box<CalculationType> const& ) + { + return comparable_type(); + } +}; + + +template <typename CalculationType, typename Point, typename Box> +struct result_from_distance<pythagoras_point_box<CalculationType>, Point, Box> +{ +private : + typedef typename return_type + < + pythagoras_point_box<CalculationType>, Point, Box + >::type return_type; +public : + template <typename T> + static inline return_type + apply(pythagoras_point_box<CalculationType> const& , T const& value) + { + return return_type(value); + } +}; + + +// Specializations for comparable::pythagoras_point_box +template <typename CalculationType> +struct tag<comparable::pythagoras_point_box<CalculationType> > +{ + typedef strategy_tag_distance_point_box type; +}; + + +template <typename CalculationType, typename Point, typename Box> +struct return_type + < + comparable::pythagoras_point_box<CalculationType>, Point, Box + > : comparable::pythagoras_point_box + < + CalculationType + >::template calculation_type<Point, Box> +{}; + + + + +template <typename CalculationType> +struct comparable_type<comparable::pythagoras_point_box<CalculationType> > +{ + typedef comparable::pythagoras_point_box<CalculationType> type; +}; + + +template <typename CalculationType> +struct get_comparable<comparable::pythagoras_point_box<CalculationType> > +{ + typedef comparable::pythagoras_point_box<CalculationType> comparable_type; +public : + static inline comparable_type apply(comparable_type const& ) + { + return comparable_type(); + } +}; + + +template <typename CalculationType, typename Point, typename Box> +struct result_from_distance + < + comparable::pythagoras_point_box<CalculationType>, Point, Box + > +{ +private : + typedef typename return_type + < + comparable::pythagoras_point_box<CalculationType>, Point, Box + >::type return_type; +public : + template <typename T> + static inline return_type + apply(comparable::pythagoras_point_box<CalculationType> const& , + T const& value) + { + return_type const v = value; + return v * v; + } +}; + + +template <typename Point, typename BoxPoint> +struct default_strategy + < + point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag + > +{ + typedef pythagoras_point_box<> type; +}; + +template <typename BoxPoint, typename Point> +struct default_strategy + < + box_tag, point_tag, BoxPoint, Point, cartesian_tag, cartesian_tag + > +{ + typedef typename default_strategy + < + point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag + >::type type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP diff --git a/boost/geometry/strategies/cartesian/point_in_box.hpp b/boost/geometry/strategies/cartesian/point_in_box.hpp index 275f7550e4..79f094113d 100644 --- a/boost/geometry/strategies/cartesian/point_in_box.hpp +++ b/boost/geometry/strategies/cartesian/point_in_box.hpp @@ -21,9 +21,9 @@ #include <boost/geometry/strategies/within.hpp> -namespace boost { namespace geometry { namespace strategy +namespace boost { namespace geometry { namespace strategy { - + namespace within { @@ -60,14 +60,14 @@ 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), + if (! SubStrategy::apply(get<Dimension>(point), + get<min_corner, Dimension>(box), get<max_corner, Dimension>(box)) ) { return false; } - + return relate_point_box_loop < SubStrategy, @@ -102,12 +102,12 @@ template > struct point_in_box { - static inline bool apply(Point const& point, Box const& box) + static inline bool apply(Point const& point, Box const& box) { return relate_point_box_loop < SubStrategy, - Point, Box, + Point, Box, 0, dimension<Point>::type::value >::apply(point, box); } @@ -126,13 +126,13 @@ 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_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, Point, Box > { - typedef within::point_in_box<Point, Box> type; + typedef within::point_in_box<Point, Box> type; }; @@ -146,9 +146,9 @@ 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_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, Point, Box > { diff --git a/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/boost/geometry/strategies/cartesian/side_by_triangle.hpp index 967090c50a..5d589ffc86 100644 --- a/boost/geometry/strategies/cartesian/side_by_triangle.hpp +++ b/boost/geometry/strategies/cartesian/side_by_triangle.hpp @@ -47,6 +47,30 @@ public : // Types can be all three different. Therefore it is // not implemented (anymore) as "segment" + template <typename coordinate_type, typename promoted_type, typename P1, typename P2, typename P> + static inline promoted_type side_value(P1 const& p1, P2 const& p2, P const& p) + { + 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); + + promoted_type const dx = sx2 - sx1; + promoted_type const dy = sy2 - sy1; + promoted_type const dpx = x - sx1; + promoted_type const dpy = y - sy1; + + return geometry::detail::determinant<promoted_type> + ( + dx, dy, + dpx, dpy + ); + + } + template <typename P1, typename P2, typename P> static inline int apply(P1 const& p1, P2 const& p2, P const& p) { @@ -65,14 +89,6 @@ public : 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 < @@ -80,23 +96,14 @@ public : 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 s = side_value<coordinate_type, promoted_type>(p1, p2, p); promoted_type const zero = promoted_type(); - return math::equals(s, zero) ? 0 - : s > zero ? 1 + + return math::equals(s, zero) ? 0 + : s > zero ? 1 : -1; } + }; diff --git a/boost/geometry/strategies/comparable_distance_result.hpp b/boost/geometry/strategies/comparable_distance_result.hpp new file mode 100644 index 0000000000..a258ddb9b4 --- /dev/null +++ b/boost/geometry/strategies/comparable_distance_result.hpp @@ -0,0 +1,196 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP + +#include <boost/mpl/always.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/vector.hpp> + +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/compress_variant.hpp> +#include <boost/geometry/util/transform_variant.hpp> +#include <boost/geometry/util/combine_if.hpp> + +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> + + +namespace boost { namespace geometry +{ + +namespace resolve_strategy +{ + +template <typename Geometry1, typename Geometry2, typename Strategy> +struct comparable_distance_result + : strategy::distance::services::return_type + < + typename strategy::distance::services::comparable_type + < + Strategy + >::type, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + > +{}; + +template <typename Geometry1, typename Geometry2> +struct comparable_distance_result<Geometry1, Geometry2, default_strategy> + : comparable_distance_result + < + Geometry1, + Geometry2, + typename detail::distance::default_strategy + < + Geometry1, Geometry2 + >::type + > +{}; + +} // namespace resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2, typename Strategy> +struct comparable_distance_result + : resolve_strategy::comparable_distance_result + < + Geometry1, + Geometry2, + Strategy + > +{}; + + +template +< + typename Geometry1, + BOOST_VARIANT_ENUM_PARAMS(typename T), + typename Strategy +> +struct comparable_distance_result + < + Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy + > +{ + // A set of all variant type combinations that are compatible and + // implemented + typedef typename util::combine_if< + typename mpl::vector1<Geometry1>, + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + mpl::always<mpl::true_> + >::type possible_input_types; + + // The (possibly variant) result type resulting from these combinations + typedef typename compress_variant< + typename transform_variant< + possible_input_types, + resolve_strategy::comparable_distance_result< + mpl::first<mpl::_>, + mpl::second<mpl::_>, + Strategy + >, + mpl::back_inserter<mpl::vector0<> > + >::type + >::type type; +}; + + +// Distance arguments are commutative +template +< + BOOST_VARIANT_ENUM_PARAMS(typename T), + typename Geometry2, + typename Strategy +> +struct comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + > : public comparable_distance_result + < + Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy + > +{}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy> +struct comparable_distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + > +{ + // A set of all variant type combinations that are compatible and + // implemented + typedef typename util::combine_if + < + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + mpl::always<mpl::true_> + >::type possible_input_types; + + // The (possibly variant) result type resulting from these combinations + typedef typename compress_variant< + typename transform_variant< + possible_input_types, + resolve_strategy::comparable_distance_result< + mpl::first<mpl::_>, + mpl::second<mpl::_>, + Strategy + >, + mpl::back_inserter<mpl::vector0<> > + >::type + >::type type; +}; + +} // namespace resolve_variant + + + + + +/*! +\brief Meta-function defining return type of comparable_distance function +\ingroup distance +*/ +template +< + typename Geometry1, + typename Geometry2 = Geometry1, + typename Strategy = void +> +struct comparable_distance_result + : resolve_variant::comparable_distance_result + < + Geometry1, Geometry2, Strategy + > +{}; + +template <typename Geometry1, typename Geometry2> +struct comparable_distance_result<Geometry1, Geometry2, void> + : comparable_distance_result<Geometry1, Geometry2, default_strategy> +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP diff --git a/boost/geometry/strategies/concepts/convex_hull_concept.hpp b/boost/geometry/strategies/concepts/convex_hull_concept.hpp index b31f0caa4e..d6e42e95a3 100644 --- a/boost/geometry/strategies/concepts/convex_hull_concept.hpp +++ b/boost/geometry/strategies/concepts/convex_hull_concept.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -46,17 +51,17 @@ class ConvexHullStrategy { static void apply() { - Strategy const* str; + Strategy const* str = 0; - state_type* st; - geometry_type* sp; - std::vector<point_type> *v; + state_type* st = 0; + geometry_type* sp = 0; + std::vector<point_type> *v = 0; // 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); + str->result(*st, std::back_inserter(*v), true, true); } }; diff --git a/boost/geometry/strategies/concepts/distance_concept.hpp b/boost/geometry/strategies/concepts/distance_concept.hpp index ba347d015a..a0cbbd21ed 100644 --- a/boost/geometry/strategies/concepts/distance_concept.hpp +++ b/boost/geometry/strategies/concepts/distance_concept.hpp @@ -18,11 +18,13 @@ #include <iterator> #include <boost/concept_check.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/geometry/util/parameter_type_of.hpp> #include <boost/geometry/geometries/concepts/point_concept.hpp> #include <boost/geometry/geometries/segment.hpp> +#include <boost/geometry/geometries/point.hpp> namespace boost { namespace geometry { namespace concept @@ -33,7 +35,7 @@ namespace boost { namespace geometry { namespace concept \brief Checks strategy for point-segment-distance \ingroup distance */ -template <typename Strategy> +template <typename Strategy, typename Point1, typename Point2> struct PointDistanceStrategy { #ifndef DOXYGEN_NO_CONCEPT_MEMBERS @@ -42,7 +44,7 @@ private : struct checker { template <typename ApplyMethod> - static void apply(ApplyMethod const&) + static void apply(ApplyMethod) { // 1: inspect and define both arguments of apply typedef typename parameter_type_of @@ -55,68 +57,45 @@ private : 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 + // 2) must define meta-function return_type + typedef typename strategy::distance::services::return_type < - Strategy, ptype2, ptype1 - >::type stype; + Strategy, ptype1, ptype2 + >::type rtype; - // 5) must define meta-function "comparable_type" + // 3) must define meta-function "comparable_type" typedef typename strategy::distance::services::comparable_type < Strategy >::type ctype; - // 6) must define meta-function "tag" + // 4) must define meta-function "tag" typedef typename strategy::distance::services::tag < Strategy >::type tag; - // 7) must implement apply with arguments + // 5) 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 + // 6) 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 + // 7) must define (meta)struct "result_from_distance" with apply r = strategy::distance::services::result_from_distance < - Strategy + Strategy, + ptype1, ptype2 >::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); + boost::ignore_unused<tag>(); + boost::ignore_unused(str, c, r); } }; @@ -125,7 +104,7 @@ private : public : BOOST_CONCEPT_USAGE(PointDistanceStrategy) { - checker::apply(&Strategy::apply); + checker::apply(&Strategy::template apply<Point1, Point2>); } #endif }; @@ -135,7 +114,7 @@ public : \brief Checks strategy for point-segment-distance \ingroup strategy_concepts */ -template <typename Strategy> +template <typename Strategy, typename Point, typename PointOfSegment> struct PointSegmentDistanceStrategy { #ifndef DOXYGEN_NO_CONCEPT_MEMBERS @@ -144,7 +123,7 @@ private : struct checker { template <typename ApplyMethod> - static void apply(ApplyMethod const&) + static void apply(ApplyMethod) { typedef typename parameter_type_of < @@ -156,27 +135,8 @@ private : 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>) - ); + // must define meta-function return_type + typedef typename strategy::distance::services::return_type<Strategy, ptype, sptype>::type rtype; Strategy *str = 0; @@ -194,7 +154,7 @@ private : public : BOOST_CONCEPT_USAGE(PointSegmentDistanceStrategy) { - checker::apply(&Strategy::apply); + checker::apply(&Strategy::template apply<Point, PointOfSegment>); } #endif }; diff --git a/boost/geometry/strategies/concepts/simplify_concept.hpp b/boost/geometry/strategies/concepts/simplify_concept.hpp index 92e5156b5a..d7f596cfe7 100644 --- a/boost/geometry/strategies/concepts/simplify_concept.hpp +++ b/boost/geometry/strategies/concepts/simplify_concept.hpp @@ -18,7 +18,9 @@ #include <iterator> #include <boost/concept_check.hpp> +#include <boost/core/ignore_unused.hpp> +#include <boost/geometry/geometries/point.hpp> #include <boost/geometry/strategies/concepts/distance_concept.hpp> @@ -30,7 +32,7 @@ namespace boost { namespace geometry { namespace concept \brief Checks strategy for simplify \ingroup simplify */ -template <typename Strategy> +template <typename Strategy, typename Point> struct SimplifyStrategy { #ifndef DOXYGEN_NO_CONCEPT_MEMBERS @@ -44,7 +46,7 @@ private : struct checker { template <typename ApplyMethod> - static void apply(ApplyMethod const&) + static void apply(ApplyMethod) { namespace ft = boost::function_types; typedef typename ft::parameter_types @@ -59,29 +61,14 @@ private : 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>) + (concept::PointSegmentDistanceStrategy<ds_type, Point, Point>) ); Strategy *str = 0; - std::vector<point_type> const* v1 = 0; - std::vector<point_type> * v2 = 0; + std::vector<Point> const* v1 = 0; + std::vector<Point> * v2 = 0; // 2) must implement method apply with arguments // - Range @@ -89,15 +76,15 @@ private : // - floating point value str->apply(*v1, std::back_inserter(*v2), 1.0); - boost::ignore_unused_variable_warning(str); + boost::ignore_unused<parameter_types, base_index>(); + boost::ignore_unused(str); } }; public : BOOST_CONCEPT_USAGE(SimplifyStrategy) { - checker::apply(&ds_type::apply); - + checker::apply(&ds_type::template apply<Point, Point>); } #endif }; diff --git a/boost/geometry/strategies/concepts/within_concept.hpp b/boost/geometry/strategies/concepts/within_concept.hpp index a9684b98e1..8786403712 100644 --- a/boost/geometry/strategies/concepts/within_concept.hpp +++ b/boost/geometry/strategies/concepts/within_concept.hpp @@ -143,7 +143,7 @@ class WithinStrategyPointBox ( (boost::is_same < - bool, + bool, typename boost::function_types::result_type<ApplyMethod>::type >::type::value), WRONG_RETURN_TYPE @@ -207,7 +207,7 @@ class WithinStrategyBoxBox ( (boost::is_same < - bool, + bool, typename boost::function_types::result_type<ApplyMethod>::type >::type::value), WRONG_RETURN_TYPE @@ -237,8 +237,8 @@ public : }; // So now: boost::geometry::concept::within -namespace within -{ +namespace within +{ #ifndef DOXYGEN_NO_DISPATCH namespace dispatch diff --git a/boost/geometry/strategies/covered_by.hpp b/boost/geometry/strategies/covered_by.hpp index a878b26c86..a5aae7703b 100644 --- a/boost/geometry/strategies/covered_by.hpp +++ b/boost/geometry/strategies/covered_by.hpp @@ -53,7 +53,7 @@ struct default_strategy { BOOST_MPL_ASSERT_MSG ( - false, NOT_IMPLEMENTED_FOR_THIS_TYPES + false, NOT_IMPLEMENTED_FOR_THESE_TYPES , (types<GeometryContained, GeometryContaining>) ); }; diff --git a/boost/geometry/strategies/default_comparable_distance_result.hpp b/boost/geometry/strategies/default_comparable_distance_result.hpp new file mode 100644 index 0000000000..3b4229f106 --- /dev/null +++ b/boost/geometry/strategies/default_comparable_distance_result.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_COMPARABLE_DISTANCE_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP + +#include <boost/geometry/strategies/comparable_distance_result.hpp> + + +namespace boost { namespace geometry +{ + +/*! +\brief Meta-function defining return type of comparable_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_comparable_distance_result + : comparable_distance_result<Geometry1, Geometry2, void> +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP diff --git a/boost/geometry/strategies/default_distance_result.hpp b/boost/geometry/strategies/default_distance_result.hpp index ea5f3ff764..e34a947727 100644 --- a/boost/geometry/strategies/default_distance_result.hpp +++ b/boost/geometry/strategies/default_distance_result.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,10 +19,7 @@ #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> +#include <boost/geometry/strategies/distance_result.hpp> namespace boost { namespace geometry @@ -31,17 +33,8 @@ namespace boost { namespace geometry */ 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; -}; + : distance_result<Geometry1, Geometry2, void> +{}; }} // namespace boost::geometry diff --git a/boost/geometry/strategies/default_length_result.hpp b/boost/geometry/strategies/default_length_result.hpp index 706941b9e4..806e4284ce 100644 --- a/boost/geometry/strategies/default_length_result.hpp +++ b/boost/geometry/strategies/default_length_result.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,22 +19,22 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP #define BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/coordinate_type.hpp> + +#include <boost/geometry/util/compress_variant.hpp> #include <boost/geometry/util/select_most_precise.hpp> +#include <boost/geometry/util/transform_variant.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. - */ +namespace resolve_strategy +{ + template <typename Geometry> struct default_length_result { @@ -40,7 +45,45 @@ struct default_length_result >::type type; }; -}} // namespace boost::geometry +} // namespace resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry> +struct default_length_result + : resolve_strategy::default_length_result<Geometry> +{}; +template <BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct default_length_result<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + typedef typename compress_variant< + typename transform_variant< + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + resolve_strategy::default_length_result<boost::mpl::placeholders::_> + >::type + >::type type; +}; + +} // namespace resolve_variant + + +/*! + \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 + : resolve_variant::default_length_result<Geometry> +{}; + + +}} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP diff --git a/boost/geometry/strategies/default_strategy.hpp b/boost/geometry/strategies/default_strategy.hpp new file mode 100644 index 0000000000..6d05970b42 --- /dev/null +++ b/boost/geometry/strategies/default_strategy.hpp @@ -0,0 +1,34 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2013 Bruno Lalande, Paris, France. +// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2013 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_STRATEGY_HPP +#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP + + +namespace boost { namespace geometry +{ + +// This is a strategy placeholder type, which is passed by the algorithm free +// functions to the multi-stage resolving process. It's resolved into an actual +// strategy type during the resolve_strategy stage, possibly depending on the +// input geometry type(s). This typically happens after the resolve_variant +// stage, as it needs to be based on concrete geometry types - as opposed to +// variant geometry types. + +struct default_strategy {}; + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP diff --git a/boost/geometry/strategies/distance.hpp b/boost/geometry/strategies/distance.hpp index ef9a7ee10d..98ccb8202b 100644 --- a/boost/geometry/strategies/distance.hpp +++ b/boost/geometry/strategies/distance.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -30,47 +35,16 @@ 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 +template <typename Strategy, typename P1, typename P2> +struct return_type { BOOST_MPL_ASSERT_MSG ( - false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY - , (types<Strategy, Point1, Point2>) + false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy, P1, P2>) ); }; -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 { @@ -88,11 +62,10 @@ template <typename Strategy> struct get_comparable ); }; -template <typename Strategy> struct result_from_distance {}; +template <typename Strategy, typename P1, typename P2> +struct result_from_distance {}; -// For point-segment only: -template <typename Strategy> struct strategy_point_point {}; // Default strategy @@ -102,7 +75,8 @@ template <typename Strategy> struct strategy_point_point {}; \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 GeometryTag1 tag (point/segment/box) for which this strategy is the default + \tparam GeometryTag2 tag (point/segment/box) 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 @@ -110,7 +84,8 @@ template <typename Strategy> struct strategy_point_point {}; */ template < - typename GeometryTag, + typename GeometryTag1, + typename GeometryTag2, typename Point1, typename Point2 = Point1, typename CsTag1 = typename cs_tag<Point1>::type, diff --git a/boost/geometry/strategies/distance_result.hpp b/boost/geometry/strategies/distance_result.hpp new file mode 100644 index 0000000000..185a511464 --- /dev/null +++ b/boost/geometry/strategies/distance_result.hpp @@ -0,0 +1,213 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_RESULT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP + +#include <boost/mpl/always.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/vector.hpp> + +#include <boost/variant/variant_fwd.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/compress_variant.hpp> +#include <boost/geometry/util/transform_variant.hpp> +#include <boost/geometry/util/combine_if.hpp> + +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> + + +namespace boost { namespace geometry +{ + + +namespace resolve_strategy +{ + +template <typename Geometry1, typename Geometry2, typename Strategy> +struct distance_result + : strategy::distance::services::return_type + < + Strategy, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + > +{}; + +template <typename Geometry1, typename Geometry2> +struct distance_result<Geometry1, Geometry2, default_strategy> + : distance_result + < + Geometry1, + Geometry2, + typename detail::distance::default_strategy + < + Geometry1, Geometry2 + >::type + > +{}; + +} // namespace resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2, typename Strategy> +struct distance_result + : resolve_strategy::distance_result + < + Geometry1, + Geometry2, + Strategy + > +{}; + + +template +< + typename Geometry1, + BOOST_VARIANT_ENUM_PARAMS(typename T), + typename Strategy +> +struct distance_result + < + Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy + > +{ + // A set of all variant type combinations that are compatible and + // implemented + typedef typename util::combine_if< + typename mpl::vector1<Geometry1>, + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + // Here we want should remove most of the combinations that + // are not valid, mostly to limit the size of the resulting MPL set. + // But is_implementedn is not ready for prime time + // + // util::is_implemented2<mpl::_1, mpl::_2, dispatch::distance<mpl::_1, mpl::_2> > + mpl::always<mpl::true_> + >::type possible_input_types; + + // The (possibly variant) result type resulting from these combinations + typedef typename compress_variant< + typename transform_variant< + possible_input_types, + resolve_strategy::distance_result< + mpl::first<mpl::_>, + mpl::second<mpl::_>, + Strategy + >, + mpl::back_inserter<mpl::vector0<> > + >::type + >::type type; +}; + + +// Distance arguments are commutative +template +< + BOOST_VARIANT_ENUM_PARAMS(typename T), + typename Geometry2, + typename Strategy +> +struct distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Geometry2, + Strategy + > : public distance_result + < + Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy + > +{}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy> +struct distance_result + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, + Strategy + > +{ + // A set of all variant type combinations that are compatible and + // implemented + typedef typename util::combine_if + < + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + // Here we want to try to remove most of the combinations + // that are not valid, mostly to limit the size of the + // resulting MPL vector. + // But is_implemented is not ready for prime time + // + // util::is_implemented2<mpl::_1, mpl::_2, dispatch::distance<mpl::_1, mpl::_2> > + mpl::always<mpl::true_> + >::type possible_input_types; + + // The (possibly variant) result type resulting from these combinations + typedef typename compress_variant< + typename transform_variant< + possible_input_types, + resolve_strategy::distance_result< + mpl::first<mpl::_>, + mpl::second<mpl::_>, + Strategy + >, + mpl::back_inserter<mpl::vector0<> > + >::type + >::type type; +}; + +} // namespace resolve_variant + + +/*! +\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, + typename Strategy = void +> +struct distance_result + : resolve_variant::distance_result<Geometry1, Geometry2, Strategy> +{}; + + +template <typename Geometry1, typename Geometry2> +struct distance_result<Geometry1, Geometry2, void> + : distance_result<Geometry1, Geometry2, default_strategy> +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP diff --git a/boost/geometry/strategies/intersection.hpp b/boost/geometry/strategies/intersection.hpp index fc628c0635..ef1b676fda 100644 --- a/boost/geometry/strategies/intersection.hpp +++ b/boost/geometry/strategies/intersection.hpp @@ -17,42 +17,47 @@ #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> +#include <boost/geometry/policies/robustness/segment_ratio_type.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 -*/ +\brief "compound strategy", containing a segment-intersection-strategy + and a side-strategy + */ template < typename Tag, typename Geometry1, typename Geometry2, typename IntersectionPoint, + typename RobustPolicy, typename CalculationType = void > struct strategy_intersection { private : + // for development BOOST_STATIC_ASSERT((! boost::is_same<RobustPolicy, void>::type::value)); + 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, + typename geometry::segment_ratio_type < - IntersectionPoint - > ip_type; + IntersectionPoint, RobustPolicy + >::type + > ip_type; public: typedef strategy::intersection::relate_cartesian_segments @@ -61,18 +66,9 @@ public: < policies::relate::segments_intersection_points < - segment1_type, - segment2_type, - ip_type, - CalculationType + ip_type > , policies::relate::segments_direction - < - segment1_type, - segment2_type, - CalculationType - >, - CalculationType >, CalculationType > segment_intersection_strategy_type; @@ -82,9 +78,12 @@ public: Tag, CalculationType >::type side_strategy_type; -}; + typedef RobustPolicy rescale_policy_type; +}; +// Version for box_box intersection or other detail calls not needing a strategy +struct strategy_intersection_empty {}; }} // namespace boost::geometry diff --git a/boost/geometry/strategies/intersection_result.hpp b/boost/geometry/strategies/intersection_result.hpp index 15917a9eb5..b467b92a7f 100644 --- a/boost/geometry/strategies/intersection_result.hpp +++ b/boost/geometry/strategies/intersection_result.hpp @@ -16,6 +16,7 @@ #include <cstddef> + namespace boost { namespace geometry { @@ -89,7 +90,7 @@ struct de9im static inline char as_char(int v) { - return v >= 0 && v < 10 ? ('0' + char(v)) : '-'; + return v >= 0 && v < 10 ? static_cast<char>('0' + v) : '-'; } #if defined(HAVE_MATRIX_AS_STRING) @@ -153,13 +154,47 @@ struct de9im_segment : public de9im #endif }; +template <typename SegmentRatio> +struct fraction_type +{ + SegmentRatio robust_ra; // TODO this can be renamed now to "ra" + SegmentRatio robust_rb; + + bool initialized; + inline fraction_type() + : initialized(false) + {} + + template <typename Info> + inline void assign(Info const& info) + { + initialized = true; + robust_ra = info.robust_ra; + robust_rb = info.robust_rb; + } + + inline void assign(SegmentRatio const& a, SegmentRatio const& b) + { + initialized = true; + robust_ra = a; + robust_rb = b; + } +}; -template <typename Point> +// +/*! +\brief return-type for segment-intersection +\note Set in intersection_points.hpp, from segment_intersection_info +*/ +template <typename Point, typename SegmentRatio> struct segment_intersection_points { - std::size_t count; + std::size_t count; // The number of intersection points + + // TODO: combine intersections and fractions in one struct Point intersections[2]; + fraction_type<SegmentRatio> fractions[2]; typedef Point point_type; segment_intersection_points() @@ -167,6 +202,18 @@ struct segment_intersection_points {} }; +// All assigned in cart_intersect, passed to intersection_points +template <typename CoordinateType, typename PromotedType, typename SegmentRatio> +struct segment_intersection_info +{ + typedef PromotedType promoted_type; + + CoordinateType dx_a, dy_a; + CoordinateType dx_b, dy_b; // TODO b can be removed + SegmentRatio robust_ra; + SegmentRatio robust_rb; +}; + }} // namespace boost::geometry diff --git a/boost/geometry/strategies/side_info.hpp b/boost/geometry/strategies/side_info.hpp index f3a9da0df0..d113eaa8ff 100644 --- a/boost/geometry/strategies/side_info.hpp +++ b/boost/geometry/strategies/side_info.hpp @@ -14,13 +14,21 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP #define BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP - +#include <cmath> #include <utility> +#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) +# 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) @@ -138,16 +146,16 @@ public : return sides[Which].first == 0 ? 0 : 1; } - +#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) inline void debug() const { std::cout << sides[0].first << " " << sides[0].second << " " << sides[1].first << " " - << sides[1].second - << std::endl; + << sides[1].second + << std::endl; } - +#endif inline void reverse() { @@ -159,6 +167,9 @@ public : }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/strategies/spherical/area_huiller.hpp b/boost/geometry/strategies/spherical/area_huiller.hpp index 1bef9b5f2f..e55fdb2b0e 100644 --- a/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/boost/geometry/strategies/spherical/area_huiller.hpp @@ -82,8 +82,7 @@ protected : calculation_type sum; // Distances are calculated on unit sphere here - strategy::distance::haversine<PointOfSegment, PointOfSegment> - distance_over_unit_sphere; + strategy::distance::haversine<calculation_type> distance_over_unit_sphere; inline excess_sum() @@ -129,7 +128,8 @@ public : // 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) + calculation_type E = four + * atan(geometry::math::sqrt(geometry::math::abs(tan(s / two) * tan((s - a) / two) * tan((s - b) / two) * tan((s - c) / two)))); diff --git a/boost/geometry/strategies/spherical/distance_cross_track.hpp b/boost/geometry/strategies/spherical/distance_cross_track.hpp index 7b353020eb..a40f03dbaf 100644 --- a/boost/geometry/strategies/spherical/distance_cross_track.hpp +++ b/boost/geometry/strategies/spherical/distance_cross_track.hpp @@ -10,6 +10,7 @@ #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP +#include <boost/config.hpp> #include <boost/concept_check.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits.hpp> @@ -18,9 +19,11 @@ #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/algorithms/detail/course.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/concepts/distance_concept.hpp> +#include <boost/geometry/strategies/spherical/distance_haversine.hpp> #include <boost/geometry/util/promote_floating_point.hpp> #include <boost/geometry/util/math.hpp> @@ -40,10 +43,8 @@ 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 +\details Class which calculates the distance of a point to a segment, for points on a sphere or globe \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 @@ -55,40 +56,35 @@ namespace strategy { namespace distance */ template < - typename Point, - typename PointOfSegment = Point, typename CalculationType = void, - typename Strategy = typename services::default_strategy<point_tag, Point>::type + typename Strategy = haversine<double, CalculationType> > class cross_track { public : - typedef typename promote_floating_point - < - typename select_calculation_type - < - Point, - PointOfSegment, - CalculationType - >::type - >::type return_type; + template <typename Point, typename PointOfSegment> + struct return_type + : promote_floating_point + < + typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::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) + explicit inline cross_track(typename Strategy::radius_type const& 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 @@ -96,9 +92,20 @@ public : // crosstrack(...) {} - inline return_type apply(Point const& p, - PointOfSegment const& sp1, PointOfSegment const& sp2) const + template <typename Point, typename PointOfSegment> + inline typename return_type<Point, PointOfSegment>::type + apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const { + +#if !defined(BOOST_MSVC) + BOOST_CONCEPT_ASSERT + ( + (concept::PointDistanceStrategy<Strategy, Point, PointOfSegment>) + ); +#endif + + typedef typename return_type<Point, PointOfSegment>::type return_type; + // http://williams.best.vwh.net/avform.htm#XTE return_type d1 = m_strategy.apply(sp1, p); return_type d3 = m_strategy.apply(sp1, sp2); @@ -111,10 +118,10 @@ public : 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_AD = geometry::detail::course<return_type>(sp1, p); + return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2); return_type crs_BA = crs_AB - geometry::math::pi<return_type>(); - return_type crs_BD = course(sp2, p); + return_type crs_BD = geometry::detail::course<return_type>(sp2, p); return_type d_crs1 = crs_AD - crs_AB; return_type d_crs2 = crs_BD - crs_BA; @@ -132,7 +139,7 @@ public : if(projection1 > 0.0 && projection2 > 0.0) { - return_type XTD = m_radius * geometry::math::abs( asin( sin( d1 / m_radius ) * sin( d_crs1 ) )); + return_type XTD = radius() * geometry::math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) )); #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Projection ON the segment" << std::endl; @@ -153,33 +160,12 @@ public : } } - inline return_type radius() const { return m_radius; } + inline typename Strategy::radius_type radius() const + { return m_strategy.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)); - } - }; @@ -188,120 +174,65 @@ private : namespace services { -template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> -struct tag<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +template <typename CalculationType, typename Strategy> +struct tag<cross_track<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 CalculationType, typename Strategy, typename P, typename PS> +struct return_type<cross_track<CalculationType, Strategy>, P, PS> + : cross_track<CalculationType, Strategy>::template return_type<P, PS> +{}; -template -< - typename Point, - typename PointOfSegment, - typename CalculationType, - typename Strategy, - typename P, - typename PS -> -struct similar_type<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS> +template <typename CalculationType, typename Strategy> +struct comparable_type<cross_track<CalculationType, Strategy> > { - typedef cross_track<Point, PointOfSegment, CalculationType, Strategy> type; + // There is no shortcut, so the strategy itself is its comparable type + typedef cross_track<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> > +struct get_comparable<cross_track<CalculationType, Strategy> > { typedef typename comparable_type < - cross_track<Point, PointOfSegment, CalculationType, Strategy> + cross_track<CalculationType, Strategy> >::type comparable_type; public : - static inline comparable_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy) + static inline comparable_type apply(cross_track<CalculationType, Strategy> const& strategy) { return comparable_type(strategy.radius()); } }; -template +template < - typename Point, typename PointOfSegment, - typename CalculationType, - typename Strategy + typename CalculationType, + typename Strategy, + typename P, typename PS > -struct result_from_distance<cross_track<Point, PointOfSegment, CalculationType, Strategy> > +struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS> { private : - typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type return_type; + typedef typename cross_track<CalculationType, Strategy>::template return_type<P, PS> return_type; public : template <typename T> - static inline return_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& , T const& distance) + static inline return_type apply(cross_track<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; -}; - /* @@ -311,15 +242,13 @@ 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, + segment_tag, Point, PointOfSegment, + spherical_polar_tag, spherical_polar_tag, Strategy > { typedef cross_track < - Point, - PointOfSegment, void, typename boost::mpl::if_ < @@ -338,22 +267,20 @@ struct default_strategy template <typename Point, typename PointOfSegment, typename Strategy> struct default_strategy < - segment_tag, Point, PointOfSegment, - spherical_equatorial_tag, spherical_equatorial_tag, + point_tag, 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, + point_tag, point_tag, Point, PointOfSegment, spherical_equatorial_tag, spherical_equatorial_tag >::type, Strategy @@ -362,6 +289,22 @@ struct default_strategy }; +template <typename PointOfSegment, typename Point, typename Strategy> +struct default_strategy + < + segment_tag, point_tag, PointOfSegment, Point, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + > +{ + typedef typename default_strategy + < + point_tag, segment_tag, Point, PointOfSegment, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + >::type type; +}; + } // namespace services #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp b/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp new file mode 100644 index 0000000000..fe32f77236 --- /dev/null +++ b/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp @@ -0,0 +1,287 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// 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_POINT_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP + + +#include <boost/geometry/core/access.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/calculation_type.hpp> + + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +template +< + typename CalculationType = void, + typename Strategy = haversine<double, CalculationType> +> +class cross_track_point_box +{ +public: + template <typename Point, typename Box> + struct return_type + : promote_floating_point + < + typename select_calculation_type + < + Point, + typename point_type<Box>::type, + CalculationType + >::type + > + {}; + + inline cross_track_point_box() + {} + + explicit inline cross_track_point_box(typename Strategy::radius_type const& r) + : m_pp_strategy(r) + {} + + inline cross_track_point_box(Strategy const& s) + : m_pp_strategy(s) + {} + + template <typename Point, typename Box> + inline typename return_type<Point, Box>::type + apply(Point const& point, Box const& box) const + { + +#if !defined(BOOST_MSVC) + BOOST_CONCEPT_ASSERT + ( + (concept::PointDistanceStrategy + < + Strategy, Point, + typename point_type<Box>::type + >) + ); +#endif + + typedef typename return_type<Point, Box>::type return_type; + typedef typename point_type<Box>::type box_point_t; + + // Create (counterclockwise) array of points, the fifth one closes it + // If every point is on the LEFT side (=1) or ON the border (=0) + // the distance should be equal to 0. + + // TODO: This strategy as well as other cross-track strategies + // and therefore e.g. spherical within(Point, Box) may not work + // properly for a Box degenerated to a Segment or Point + + boost::array<box_point_t, 5> bp; + geometry::detail::assign_box_corners_oriented<true>(box, bp); + bp[4] = bp[0]; + + for (int i = 1; i < 5; i++) + { + box_point_t const& p1 = bp[i - 1]; + box_point_t const& p2 = bp[i]; + + return_type const crs_AD = geometry::detail::course<return_type>(p1, point); + return_type const crs_AB = geometry::detail::course<return_type>(p1, p2); + return_type const d_crs1 = crs_AD - crs_AB; + return_type const sin_d_crs1 = sin(d_crs1); + + // this constant sin() is here to be consistent with the side strategy + return_type const sigXTD = asin(sin(0.001) * sin_d_crs1); + + // If the point is on the right side of the edge + if ( sigXTD > 0 ) + { + return_type const crs_BA = crs_AB - geometry::math::pi<return_type>(); + return_type const crs_BD = geometry::detail::course<return_type>(p2, point); + return_type const d_crs2 = crs_BD - crs_BA; + + return_type const projection1 = cos( d_crs1 ); + return_type const projection2 = cos( d_crs2 ); + + if(projection1 > 0.0 && projection2 > 0.0) + { + return_type const d1 = m_pp_strategy.apply(p1, point); + return_type const + XTD = radius() + * geometry::math::abs( + asin( sin( d1 / radius() ) * sin_d_crs1 ) + ); + + return return_type(XTD); + } + else + { + // OPTIMIZATION + // Return d1 if projection1 <= 0 and d2 if projection2 <= 0 + // if both == 0 then return d1 or d2 + // both shouldn't be < 0 + + return_type const d1 = m_pp_strategy.apply(p1, point); + return_type const d2 = m_pp_strategy.apply(p2, point); + + return return_type((std::min)( d1 , d2 )); + } + } + } + + // Return 0 if the point isn't on the right side of any segment + return return_type(0); + } + + inline typename Strategy::radius_type radius() const + { return m_pp_strategy.radius(); } + +private : + + Strategy m_pp_strategy; +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename CalculationType, typename Strategy> +struct tag<cross_track_point_box<CalculationType, Strategy> > +{ + typedef strategy_tag_distance_point_box type; +}; + + +template <typename CalculationType, typename Strategy, typename P, typename Box> +struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box> + : cross_track_point_box<CalculationType, Strategy>::template return_type<P, Box> +{}; + + +template <typename CalculationType, typename Strategy> +struct comparable_type<cross_track_point_box<CalculationType, Strategy> > +{ + // There is no shortcut, so the strategy itself is its comparable type + typedef cross_track_point_box<CalculationType, Strategy> type; +}; + + +template +< + typename CalculationType, + typename Strategy +> +struct get_comparable<cross_track_point_box<CalculationType, Strategy> > +{ + typedef typename comparable_type + < + cross_track_point_box<CalculationType, Strategy> + >::type comparable_type; +public : + static inline comparable_type apply( + cross_track_point_box<CalculationType, Strategy> const& strategy) + { + return cross_track_point_box<CalculationType, Strategy>(strategy.radius()); + } +}; + + +template +< + typename CalculationType, + typename Strategy, + typename P, typename Box +> +struct result_from_distance + < + cross_track_point_box<CalculationType, Strategy>, + P, + Box + > +{ +private : + typedef typename cross_track_point_box + < + CalculationType, Strategy + >::template return_type<P, Box> return_type; +public : + template <typename T> + static inline return_type apply( + cross_track_point_box<CalculationType, Strategy> const& , + T const& distance) + { + return distance; + } +}; + + +template <typename Point, typename Box, typename Strategy> +struct default_strategy + < + point_tag, box_tag, Point, Box, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + > +{ + typedef cross_track_point_box + < + void, + typename boost::mpl::if_ + < + boost::is_void<Strategy>, + typename default_strategy + < + point_tag, point_tag, + Point, typename point_type<Box>::type, + spherical_equatorial_tag, spherical_equatorial_tag + >::type, + Strategy + >::type + > type; +}; + + +template <typename Box, typename Point, typename Strategy> +struct default_strategy + < + box_tag, point_tag, Box, Point, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + > +{ + typedef typename default_strategy + < + point_tag, box_tag, Point, Box, + spherical_equatorial_tag, spherical_equatorial_tag, + Strategy + >::type type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP diff --git a/boost/geometry/strategies/spherical/distance_haversine.hpp b/boost/geometry/strategies/spherical/distance_haversine.hpp index 59ec1c33ff..8db29c5157 100644 --- a/boost/geometry/strategies/spherical/distance_haversine.hpp +++ b/boost/geometry/strategies/spherical/distance_haversine.hpp @@ -14,6 +14,7 @@ #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_calculation_type.hpp> #include <boost/geometry/util/promote_floating_point.hpp> @@ -39,52 +40,57 @@ namespace comparable // - applying asin (which is strictly (monotone) increasing) template < - typename Point1, - typename Point2 = Point1, + typename RadiusType, 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) + template <typename Point1, typename Point2> + struct calculation_type + : promote_floating_point + < + typename select_calculation_type + < + Point1, + Point2, + CalculationType + >::type + > + {}; + + typedef RadiusType radius_type; + + explicit inline haversine(RadiusType const& r = 1.0) : m_radius(r) {} - - static inline calculation_type apply(Point1 const& p1, Point2 const& p2) + template <typename Point1, typename Point2> + static inline typename calculation_type<Point1, Point2>::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)); + return calculate<typename calculation_type<Point1, Point2>::type>( + 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 + inline RadiusType 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) + template <typename R, typename T1, typename T2> + static inline R calculate(T1 const& lon1, T1 const& lat1, + T2 const& lon2, T2 const& lat2) { return math::hav(lat2 - lat1) + cos(lat1) * cos(lat2) * math::hav(lon2 - lon1); } - calculation_type m_radius; + RadiusType m_radius; }; @@ -95,19 +101,18 @@ private : \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 RadiusType \tparam_radius \tparam CalculationType \tparam_calculation \author Adapted from: http://williams.best.vwh.net/avform.htm \see http://en.wikipedia.org/wiki/Great-circle_distance -\note It says: <em>The great circle distance d between two +\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)) - </em> + d=2*asin(sqrt((sin((lat1-lat2) / 2))^2 + + cos(lat1)*cos(lat2)*(sin((lon1-lon2) / 2))^2)) + \qbk{ [heading See also] @@ -117,23 +122,26 @@ A mathematically equivalent formula, which is less subject */ template < - typename Point1, - typename Point2 = Point1, + typename RadiusType, typename CalculationType = void > class haversine { - typedef comparable::haversine<Point1, Point2, CalculationType> comparable_type; + typedef comparable::haversine<RadiusType, CalculationType> comparable_type; public : + template <typename Point1, typename Point2> + struct calculation_type + : services::return_type<comparable_type, Point1, Point2> + {}; - typedef typename services::return_type<comparable_type>::type calculation_type; + typedef RadiusType radius_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) + inline haversine(RadiusType const& radius = 1.0) : m_radius(radius) {} @@ -143,10 +151,13 @@ public : \param p1 first point \param p2 second point */ - inline calculation_type apply(Point1 const& p1, Point2 const& p2) const + template <typename Point1, typename Point2> + inline typename calculation_type<Point1, Point2>::type + apply(Point1 const& p1, Point2 const& p2) const { + typedef typename calculation_type<Point1, Point2>::type calculation_type; calculation_type const a = comparable_type::apply(p1, p2); - calculation_type const c = calculation_type(2.0) * asin(sqrt(a)); + calculation_type const c = calculation_type(2.0) * asin(math::sqrt(a)); return m_radius * c; } @@ -154,13 +165,13 @@ public : \brief access to radius value \return the radius */ - inline calculation_type radius() const + inline RadiusType radius() const { return m_radius; } private : - calculation_type m_radius; + RadiusType m_radius; }; @@ -168,52 +179,32 @@ private : namespace services { -template <typename Point1, typename Point2, typename CalculationType> -struct tag<haversine<Point1, Point2, CalculationType> > +template <typename RadiusType, typename CalculationType> +struct tag<haversine<RadiusType, 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 RadiusType, typename CalculationType, typename P1, typename P2> +struct return_type<haversine<RadiusType, CalculationType>, P1, P2> + : haversine<RadiusType, CalculationType>::template calculation_type<P1, P2> +{}; -template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> -struct similar_type<haversine<Point1, Point2, CalculationType>, P1, P2> +template <typename RadiusType, typename CalculationType> +struct comparable_type<haversine<RadiusType, CalculationType> > { - typedef haversine<P1, P2, CalculationType> type; + typedef comparable::haversine<RadiusType, CalculationType> type; }; -template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2> -struct get_similar<haversine<Point1, Point2, CalculationType>, P1, P2> +template <typename RadiusType, typename CalculationType> +struct get_comparable<haversine<RadiusType, CalculationType> > { 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; + typedef haversine<RadiusType, CalculationType> this_type; + typedef comparable::haversine<RadiusType, CalculationType> comparable_type; public : static inline comparable_type apply(this_type const& input) { @@ -221,12 +212,12 @@ public : } }; -template <typename Point1, typename Point2, typename CalculationType> -struct result_from_distance<haversine<Point1, Point2, CalculationType> > +template <typename RadiusType, typename CalculationType, typename P1, typename P2> +struct result_from_distance<haversine<RadiusType, CalculationType>, P1, P2> { private : - typedef haversine<Point1, Point2, CalculationType> this_type; - typedef typename return_type<this_type>::type return_type; + typedef haversine<RadiusType, CalculationType> this_type; + typedef typename return_type<this_type, P1, P2>::type return_type; public : template <typename T> static inline return_type apply(this_type const& , T const& value) @@ -237,51 +228,31 @@ public : // Specializations for comparable::haversine -template <typename Point1, typename Point2, typename CalculationType> -struct tag<comparable::haversine<Point1, Point2, CalculationType> > +template <typename RadiusType, typename CalculationType> +struct tag<comparable::haversine<RadiusType, 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 RadiusType, typename CalculationType, typename P1, typename P2> +struct return_type<comparable::haversine<RadiusType, CalculationType>, P1, P2> + : comparable::haversine<RadiusType, CalculationType>::template calculation_type<P1, P2> +{}; -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> > +template <typename RadiusType, typename CalculationType> +struct comparable_type<comparable::haversine<RadiusType, CalculationType> > { - typedef comparable::haversine<Point1, Point2, CalculationType> type; + typedef comparable::haversine<RadiusType, CalculationType> type; }; -template <typename Point1, typename Point2, typename CalculationType> -struct get_comparable<comparable::haversine<Point1, Point2, CalculationType> > +template <typename RadiusType, typename CalculationType> +struct get_comparable<comparable::haversine<RadiusType, CalculationType> > { private : - typedef comparable::haversine<Point1, Point2, CalculationType> this_type; + typedef comparable::haversine<RadiusType, CalculationType> this_type; public : static inline this_type apply(this_type const& input) { @@ -290,12 +261,12 @@ public : }; -template <typename Point1, typename Point2, typename CalculationType> -struct result_from_distance<comparable::haversine<Point1, Point2, CalculationType> > +template <typename RadiusType, typename CalculationType, typename P1, typename P2> +struct result_from_distance<comparable::haversine<RadiusType, CalculationType>, P1, P2> { private : - typedef comparable::haversine<Point1, Point2, CalculationType> strategy_type; - typedef typename return_type<strategy_type>::type return_type; + typedef comparable::haversine<RadiusType, CalculationType> strategy_type; + typedef typename return_type<strategy_type, P1, P2>::type return_type; public : template <typename T> static inline return_type apply(strategy_type const& strategy, T const& distance) @@ -306,12 +277,16 @@ public : }; -// Register it as the default for point-types +// 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> +struct default_strategy + < + point_tag, point_tag, Point1, Point2, + spherical_equatorial_tag, spherical_equatorial_tag + > { - typedef strategy::distance::haversine<Point1, Point2> type; + typedef strategy::distance::haversine<typename select_coordinate_type<Point1, Point2>::type> type; }; // Note: spherical polar coordinate system requires "get_as_radian_equatorial" diff --git a/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/boost/geometry/strategies/spherical/side_by_cross_track.hpp index b7cf279d5b..c4c5f24eeb 100644 --- a/boost/geometry/strategies/spherical/side_by_cross_track.hpp +++ b/boost/geometry/strategies/spherical/side_by_cross_track.hpp @@ -11,11 +11,14 @@ #include <boost/mpl/if.hpp> #include <boost/type_traits.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/algorithms/detail/course.hpp> + #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/util/math.hpp> @@ -30,29 +33,6 @@ 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) @@ -82,9 +62,11 @@ public : CalculationType >::type coordinate_type; + boost::ignore_unused<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 crs_AD = geometry::detail::course<double>(p1, p); + double crs_AB = geometry::detail::course<double>(p1, p2); double XTD = asin(sin(d1) * sin(crs_AD - crs_AB)); return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1; diff --git a/boost/geometry/strategies/spherical/ssf.hpp b/boost/geometry/strategies/spherical/ssf.hpp index ab7c67559a..41562950fd 100644 --- a/boost/geometry/strategies/spherical/ssf.hpp +++ b/boost/geometry/strategies/spherical/ssf.hpp @@ -88,13 +88,13 @@ public : // (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) + 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 diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp index 3aa9ab00f5..afc5d7046f 100644 --- a/boost/geometry/strategies/strategies.hpp +++ b/boost/geometry/strategies/strategies.hpp @@ -4,6 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -11,6 +14,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP #define BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP @@ -18,6 +23,7 @@ #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/strategies/area.hpp> +#include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/strategies/centroid.hpp> #include <boost/geometry/strategies/compare.hpp> #include <boost/geometry/strategies/convex_hull.hpp> @@ -29,10 +35,22 @@ #include <boost/geometry/strategies/cartesian/area_surveyor.hpp> #include <boost/geometry/strategies/cartesian/box_in_box.hpp> +#include <boost/geometry/strategies/cartesian/buffer_end_flat.hpp> +#include <boost/geometry/strategies/cartesian/buffer_end_round.hpp> +#include <boost/geometry/strategies/cartesian/buffer_join_miter.hpp> +#include <boost/geometry/strategies/cartesian/buffer_join_round.hpp> +#include <boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp> +#include <boost/geometry/strategies/cartesian/buffer_point_circle.hpp> +#include <boost/geometry/strategies/cartesian/buffer_point_square.hpp> +#include <boost/geometry/strategies/cartesian/buffer_side_straight.hpp> +#include <boost/geometry/strategies/cartesian/centroid_average.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_pythagoras_point_box.hpp> +#include <boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp> #include <boost/geometry/strategies/cartesian/distance_projected_point.hpp> +#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.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> @@ -41,14 +59,20 @@ #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/distance_cross_track_point_box.hpp> #include <boost/geometry/strategies/spherical/compare_circular.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> +#include <boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp> +#include <boost/geometry/strategies/agnostic/buffer_distance_asymmetric.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_point.hpp> #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp> +#include <boost/geometry/strategies/agnostic/relate.hpp> + #include <boost/geometry/strategies/strategy_transform.hpp> #include <boost/geometry/strategies/transform/matrix_transformers.hpp> diff --git a/boost/geometry/strategies/strategy_transform.hpp b/boost/geometry/strategies/strategy_transform.hpp index 61a408c617..9d3b1d910c 100644 --- a/boost/geometry/strategies/strategy_transform.hpp +++ b/boost/geometry/strategies/strategy_transform.hpp @@ -165,7 +165,7 @@ namespace detail // 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) @@ -179,7 +179,7 @@ namespace detail 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) @@ -188,7 +188,7 @@ namespace detail // 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); @@ -198,7 +198,7 @@ namespace detail set<1>(p, r_cos_delta * sin(lambda)); set<2>(p, r_sin_delta); } - + /// Helper function for conversion template <typename P, typename T> @@ -224,7 +224,7 @@ namespace detail 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) { @@ -234,7 +234,7 @@ namespace detail 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) @@ -242,7 +242,7 @@ namespace detail 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); + T const r = math::sqrt(x * x + y * y + z * z); set<2>(p, r); set_from_radian<0>(p, atan2(y, x)); if (r > 0.0) @@ -253,22 +253,22 @@ namespace detail 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; - } + 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 = math::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 @@ -383,11 +383,11 @@ struct from_cartesian_3_to_spherical_polar_3 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); - } + 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 @@ -486,7 +486,7 @@ struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2 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; + typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type; }; diff --git a/boost/geometry/strategies/tags.hpp b/boost/geometry/strategies/tags.hpp index 39f2f23036..7589c21071 100644 --- a/boost/geometry/strategies/tags.hpp +++ b/boost/geometry/strategies/tags.hpp @@ -34,6 +34,8 @@ namespace strategy struct strategy_tag_distance_point_point {}; struct strategy_tag_distance_point_segment {}; +struct strategy_tag_distance_point_box {}; +struct strategy_tag_distance_box_box {}; }} // namespace boost::geometry diff --git a/boost/geometry/strategies/transform/inverse_transformer.hpp b/boost/geometry/strategies/transform/inverse_transformer.hpp index 845a71ded3..685cf874b8 100644 --- a/boost/geometry/strategies/transform/inverse_transformer.hpp +++ b/boost/geometry/strategies/transform/inverse_transformer.hpp @@ -31,22 +31,23 @@ namespace strategy { namespace transform { /*! -\brief Transformation strategy to do an inverse ransformation in Cartesian system +\brief Transformation strategy to do an inverse transformation in a Cartesian coordinate system \ingroup strategies -\tparam P1 first point type -\tparam P2 second point type */ -template <typename P1, typename P2> +template +< + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2 +> class inverse_transformer - : public ublas_transformer<P1, P2, dimension<P1>::type::value, dimension<P2>::type::value> + : public ublas_transformer<CalculationType, Dimension1, Dimension2> { - 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; + typedef boost::numeric::ublas::matrix<CalculationType> matrix_type; // create a working copy of the input matrix_type copy(input.matrix()); @@ -60,7 +61,7 @@ public : if( res == 0 ) { // create identity matrix - this->m_matrix.assign(boost::numeric::ublas::identity_matrix<T>(copy.size1())); + this->m_matrix.assign(boost::numeric::ublas::identity_matrix<CalculationType>(copy.size1())); // backsubstitute to get the inverse boost::numeric::ublas::lu_substitute(copy, pm, this->m_matrix); diff --git a/boost/geometry/strategies/transform/map_transformer.hpp b/boost/geometry/strategies/transform/map_transformer.hpp index 150ff1de9b..1109e814b9 100644 --- a/boost/geometry/strategies/transform/map_transformer.hpp +++ b/boost/geometry/strategies/transform/map_transformer.hpp @@ -19,33 +19,36 @@ #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 +\brief Transformation strategy to map from one to another Cartesian coordinate 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 + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2, + bool Mirror = false, + bool SameScale = true > class map_transformer - : public ublas_transformer<P1, P2, Dimension1, Dimension2> + : public ublas_transformer<CalculationType, Dimension1, Dimension2> { - typedef typename select_coordinate_type<P1, P2>::type T; - typedef boost::numeric::ublas::matrix<T> M; + typedef boost::numeric::ublas::matrix<CalculationType> M; public : template <typename B, typename D> @@ -158,6 +161,9 @@ private : }} // namespace strategy::transform +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/strategies/transform/matrix_transformers.hpp b/boost/geometry/strategies/transform/matrix_transformers.hpp index 68da240934..27a3a2ae80 100644 --- a/boost/geometry/strategies/transform/matrix_transformers.hpp +++ b/boost/geometry/strategies/transform/matrix_transformers.hpp @@ -22,9 +22,20 @@ #define BOOST_UBLAS_TYPE_CHECK 0 #include <boost/numeric/conversion/cast.hpp> + +#if defined(__clang__) +// Avoid warning about unused UBLAS function: boost_numeric_ublas_abs +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + #include <boost/numeric/ublas/vector.hpp> #include <boost/numeric/ublas/matrix.hpp> +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/cs.hpp> @@ -46,14 +57,12 @@ namespace strategy { namespace transform \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 +\tparam Dimension1 number of dimensions to transform from +\tparam Dimension2 number of dimensions to transform to */ template < - typename P1, typename P2, + typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > @@ -62,13 +71,12 @@ class ublas_transformer }; -template <typename P1, typename P2> -class ublas_transformer<P1, P2, 2, 2> +template <typename CalculationType> +class ublas_transformer<CalculationType, 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; + typedef CalculationType ct; + typedef boost::numeric::ublas::matrix<ct> matrix_type; matrix_type m_matrix; public : @@ -91,17 +99,17 @@ public : inline ublas_transformer() : m_matrix(3, 3) {} + template <typename P1, typename P2> 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); + ct const& c1 = get<0>(p1); + ct 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); + ct p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2); + ct 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)); @@ -115,38 +123,37 @@ public : // 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> +template <typename CalculationType> +class ublas_transformer<CalculationType, 3, 2> : public ublas_transformer<CalculationType, 2, 2> { - typedef typename select_coordinate_type<P1, P2>::type coordinate_type; - typedef coordinate_type ct; // Abbreviation + typedef CalculationType ct; 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>( + : ublas_transformer<CalculationType, 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>() + : ublas_transformer<CalculationType, 2, 2>() {} }; -template <typename P1, typename P2> -class ublas_transformer<P1, P2, 3, 3> +template <typename CalculationType> +class ublas_transformer<CalculationType, 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; + typedef CalculationType ct; + typedef boost::numeric::ublas::matrix<ct> 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, @@ -163,13 +170,12 @@ protected : inline ublas_transformer() : m_matrix(4, 4) {} -public : - + template <typename P1, typename P2> 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); + ct const& c1 = get<0>(p1); + ct const& c2 = get<1>(p1); + ct const& c3 = get<2>(p1); typedef typename geometry::coordinate_type<P2>::type ct2; @@ -192,34 +198,30 @@ public : \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 +\tparam Dimension1 number of dimensions to transform from +\tparam Dimension2 number of dimensions to transform to */ template < - typename P1, typename P2, - std::size_t Dimension1 = geometry::dimension<P1>::type::value, - std::size_t Dimension2 = geometry::dimension<P2>::type::value + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2 > class translate_transformer { }; -template <typename P1, typename P2> -class translate_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2> +template<typename CalculationType> +class translate_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 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>( + inline translate_transformer(CalculationType const& translate_x, + CalculationType const& translate_y, + CalculationType const& = 0) + : ublas_transformer<CalculationType, 2, 2>( 1, 0, translate_x, 0, 1, translate_y, 0, 0, 1) @@ -227,16 +229,14 @@ public : }; -template <typename P1, typename P2> -class translate_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3> +template <typename CalculationType> +class translate_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 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>( + inline translate_transformer(CalculationType const& translate_x, + CalculationType const& translate_y, + CalculationType const& translate_z) + : ublas_transformer<CalculationType, 3, 3>( 1, 0, 0, translate_x, 0, 1, 0, translate_y, 0, 0, 1, translate_z, @@ -251,40 +251,37 @@ public : \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 +\tparam Dimension1 number of dimensions to transform from +\tparam Dimension2 number of dimensions to transform to */ template < - typename P1, typename P2 = P1, - std::size_t Dimension1 = geometry::dimension<P1>::type::value, - std::size_t Dimension2 = geometry::dimension<P2>::type::value + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2 > class scale_transformer { }; -template <typename P1, typename P2> -class scale_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2> +template <typename CalculationType> +class scale_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 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>( + inline scale_transformer(CalculationType const& scale_x, + CalculationType const& scale_y, + CalculationType const& = 0) + : ublas_transformer<CalculationType, 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>( + inline scale_transformer(CalculationType const& scale) + : ublas_transformer<CalculationType, 2, 2>( scale, 0, 0, 0, scale, 0, 0, 0, 1) @@ -292,15 +289,14 @@ public : }; -template <typename P1, typename P2> -class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3> +template <typename CalculationType> +class scale_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3> { - typedef typename select_coordinate_type<P1, P2>::type coordinate_type; - - inline scale_transformer(coordinate_type const& scale_x, - coordinate_type const& scale_y, - coordinate_type const& scale_z) - : ublas_transformer<P1, P2, 3, 3>( +public : + inline scale_transformer(CalculationType const& scale_x, + CalculationType const& scale_y, + CalculationType const& scale_z) + : ublas_transformer<CalculationType, 3, 3>( scale_x, 0, 0, 0, 0, scale_y, 0, 0, 0, 0, scale_z, 0, @@ -308,8 +304,8 @@ class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3> {} - inline scale_transformer(coordinate_type const& scale) - : ublas_transformer<P1, P2, 3, 3>( + inline scale_transformer(CalculationType const& scale) + : ublas_transformer<CalculationType, 3, 3>( scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, @@ -352,23 +348,16 @@ struct as_radian<degree> template < - typename P1, typename P2, - std::size_t Dimension1 = geometry::dimension<P1>::type::value, - std::size_t Dimension2 = geometry::dimension<P2>::type::value + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2 > class rad_rotate_transformer - : public ublas_transformer<P1, P2, Dimension1, Dimension2> + : public ublas_transformer<CalculationType, 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>( + inline rad_rotate_transformer(CalculationType const& angle) + : ublas_transformer<CalculationType, Dimension1, Dimension2>( cos(angle), sin(angle), 0, -sin(angle), cos(angle), 0, 0, 0, 1) @@ -381,33 +370,31 @@ public : /*! -\brief Strategy of rotate transformation in Cartesian system. +\brief Strategy for rotate transformation in Cartesian coordinate 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> +template +< + typename DegreeOrRadian, + typename CalculationType, + std::size_t Dimension1, + std::size_t Dimension2 +> +class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, 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 rotate_transformer(angle_type const& angle) + inline rotate_transformer(CalculationType const& angle) : detail::rad_rotate_transformer < - P1, P2 + CalculationType, Dimension1, Dimension2 >(detail::as_radian<DegreeOrRadian>::get(angle)) {} }; diff --git a/boost/geometry/strategies/within.hpp b/boost/geometry/strategies/within.hpp index 0852a22d2d..d625bc40e6 100644 --- a/boost/geometry/strategies/within.hpp +++ b/boost/geometry/strategies/within.hpp @@ -52,7 +52,7 @@ struct default_strategy { BOOST_MPL_ASSERT_MSG ( - false, NOT_IMPLEMENTED_FOR_THIS_TYPES + false, NOT_IMPLEMENTED_FOR_THESE_TYPES , (types<GeometryContained, GeometryContaining>) ); }; diff --git a/boost/geometry/util/bare_type.hpp b/boost/geometry/util/bare_type.hpp index 1b49de6436..26dd94a8ae 100644 --- a/boost/geometry/util/bare_type.hpp +++ b/boost/geometry/util/bare_type.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2012 Bruno Lalande, Paris, France. // Copyright (c) 2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -11,7 +16,10 @@ #ifndef BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP #define BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP -#include <boost/type_traits.hpp> + +#include <boost/type_traits/remove_const.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/type_traits/remove_reference.hpp> namespace boost { namespace geometry @@ -25,7 +33,13 @@ struct bare_type { typedef typename boost::remove_const < - typename boost::remove_pointer<T>::type + typename boost::remove_pointer + < + typename boost::remove_reference + < + T + >::type + >::type >::type type; }; diff --git a/boost/geometry/util/calculation_type.hpp b/boost/geometry/util/calculation_type.hpp index aef58909e7..2ac0de87d9 100644 --- a/boost/geometry/util/calculation_type.hpp +++ b/boost/geometry/util/calculation_type.hpp @@ -34,7 +34,7 @@ struct default_integral typedef boost::long_long_type type; #else typedef int type; -#endif +#endif }; /*! @@ -65,7 +65,7 @@ struct calculation_type DefaultIntegralCalculationType >::type::value )); - + typedef typename boost::mpl::if_ < @@ -153,12 +153,12 @@ struct ternary < typename select_most_precise < - typename coordinate_type<Geometry1>::type, + typename coordinate_type<Geometry1>::type, typename select_coordinate_type < Geometry2, Geometry3 - >::type + >::type >::type, CalculationType, DefaultFloatingPointCalculationType, diff --git a/boost/geometry/util/combine_if.hpp b/boost/geometry/util/combine_if.hpp new file mode 100644 index 0000000000..6d8d932a1c --- /dev/null +++ b/boost/geometry/util/combine_if.hpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_COMBINE_IF_HPP +#define BOOST_GEOMETRY_UTIL_COMBINE_IF_HPP + +#include <boost/mpl/fold.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/bind.hpp> +#include <boost/mpl/set.hpp> +#include <boost/mpl/insert.hpp> +#include <boost/mpl/placeholders.hpp> + +#include <boost/type_traits.hpp> + + +namespace boost { namespace geometry +{ + +namespace util +{ + + +/*! + \brief Meta-function to generate all the combination of pairs of types + from a given sequence Sequence except those that does not satisfy the + predicate Pred + \ingroup utility + \par Example + \code + typedef mpl::vector<mpl::int_<0>, mpl::int_<1> > types; + typedef combine_if<types, types, always<true_> >::type combinations; + typedef mpl::vector< + pair<mpl::int_<1>, mpl::int_<1> >, + pair<mpl::int_<1>, mpl::int_<0> >, + pair<mpl::int_<0>, mpl::int_<1> >, + pair<mpl::int_<0>, mpl::int_<0> > + > result_types; + + BOOST_MPL_ASSERT(( mpl::equal<combinations, result_types> )); + \endcode +*/ +template <typename Sequence1, typename Sequence2, typename Pred> +struct combine_if +{ + struct combine + { + template <typename Result, typename T> + struct apply + { + typedef typename mpl::fold<Sequence2, Result, + mpl::if_ + < + mpl::bind<typename mpl::lambda<Pred>::type, T, mpl::_2>, + mpl::insert<mpl::_1, mpl::pair<T, mpl::_2> >, + mpl::_1 + > + >::type type; + }; + }; + + typedef typename mpl::fold<Sequence1, mpl::set0<>, combine>::type type; +}; + + +} // namespace util + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_COMBINE_IF_HPP diff --git a/boost/geometry/util/compress_variant.hpp b/boost/geometry/util/compress_variant.hpp new file mode 100644 index 0000000000..a94cf28894 --- /dev/null +++ b/boost/geometry/util/compress_variant.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_UTIL_COMPRESS_VARIANT_HPP +#define BOOST_GEOMETRY_UTIL_COMPRESS_VARIANT_HPP + + +#include <boost/mpl/equal_to.hpp> +#include <boost/mpl/fold.hpp> +#include <boost/mpl/front.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/vector.hpp> +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry +{ + + +namespace detail +{ + +template <typename Variant> +struct unique_types: + mpl::fold< + typename mpl::reverse_fold< + typename Variant::types, + mpl::set<>, + mpl::insert< + mpl::placeholders::_1, + mpl::placeholders::_2 + > + >::type, + mpl::vector<>, + mpl::push_back<mpl::placeholders::_1, mpl::placeholders::_2> + > +{}; + +template <typename Types> +struct variant_or_single: + mpl::if_< + mpl::equal_to< + mpl::size<Types>, + mpl::int_<1> + >, + typename mpl::front<Types>::type, + typename make_variant_over<Types>::type + > +{}; + +} // namespace detail + + +/*! + \brief Meta-function that takes a boost::variant type and tries to minimize + it by doing the following: + - if there's any duplicate types, remove them + - if the result is a variant of one type, turn it into just that type + \ingroup utility + \par Example + \code + typedef variant<int, float, int, long> variant_type; + typedef compress_variant<variant_type>::type compressed; + typedef mpl::vector<int, float, long> result_types; + BOOST_MPL_ASSERT(( mpl::equal<compressed::types, result_types> )); + + typedef variant<int, int, int> one_type_variant_type; + typedef compress_variant<one_type_variant_type>::type single_type; + BOOST_MPL_ASSERT(( boost::equals<single_type, int> )); + \endcode +*/ + +template <typename Variant> +struct compress_variant: + detail::variant_or_single< + typename detail::unique_types<Variant>::type + > +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_COMPRESS_VARIANT_HPP diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp index 95cbdf2ce4..22c02168ad 100644 --- a/boost/geometry/util/math.hpp +++ b/boost/geometry/util/math.hpp @@ -1,8 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,6 +24,9 @@ #include <limits> #include <boost/math/constants/constants.hpp> +#include <boost/math/special_functions/round.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/type_traits/is_fundamental.hpp> #include <boost/geometry/util/select_most_precise.hpp> @@ -44,17 +53,17 @@ struct equals 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 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; - } + 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 @@ -76,18 +85,81 @@ 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; + if (equals<Type, true>::apply(a, b)) + { + return false; + } + return a < b; } }; -template <typename Type, bool IsFloatingPoint> +template <typename Type, bool IsFloatingPoint> struct equals_with_epsilon : public equals<Type, IsFloatingPoint> {}; +template +< + typename T, + bool IsFundemantal = boost::is_fundamental<T>::value /* false */ +> +struct square_root +{ + typedef T return_type; + + static inline T apply(T const& value) + { + // for non-fundamental number types assume that sqrt is + // defined either: + // 1) at T's scope, or + // 2) at global scope, or + // 3) in namespace std + using ::sqrt; + using std::sqrt; + + return sqrt(value); + } +}; + +template <> +struct square_root<float, true> +{ + typedef float return_type; + + static inline float apply(float const& value) + { + // for float use std::sqrt + return std::sqrt(value); + } +}; + +template <> +struct square_root<long double, true> +{ + typedef long double return_type; + + static inline long double apply(long double const& value) + { + // for long double use std::sqrt + return std::sqrt(value); + } +}; + +template <typename T> +struct square_root<T, true> +{ + typedef double return_type; + + static inline double apply(T const& value) + { + // for all other fundamental number types use also std::sqrt + // + // Note: in C++98 the only other possibility is double; + // in C++11 there are also overloads for integral types; + // this specialization works for those as well. + return std::sqrt(boost::numeric_cast<double>(value)); + } +}; + /*! \brief Short construct to enable partial specialization for PI, currently not possible in Math. @@ -102,6 +174,39 @@ struct define_pi } }; +template <typename T> +struct relaxed_epsilon +{ + static inline T apply(const T& factor) + { + return factor * std::numeric_limits<T>::epsilon(); + } +}; + +// ItoF ItoI FtoF +template <typename Result, typename Source, + bool ResultIsInteger = std::numeric_limits<Result>::is_integer, + bool SourceIsInteger = std::numeric_limits<Source>::is_integer> +struct round +{ + static inline Result apply(Source const& v) + { + return boost::numeric_cast<Result>(v); + } +}; + +// FtoI +template <typename Result, typename Source> +struct round<Result, Source, true, false> +{ + static inline Result apply(Source const& v) + { + namespace bmp = boost::math::policies; + // ignore rounding errors for backward compatibility + typedef bmp::policy< bmp::rounding_error<bmp::ignore_error> > policy; + return boost::numeric_cast<Result>(boost::math::round(v, policy())); + } +}; } // namespace detail #endif @@ -110,6 +215,12 @@ struct define_pi 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 @@ -143,7 +254,7 @@ 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, + select_type, boost::is_floating_point<select_type>::type::value >::apply(a, b); } @@ -201,18 +312,58 @@ inline T sqr(T const& value) return value * value; } +/*! +\brief Short utility to return the square root +\ingroup utility +\param value Value to calculate the square root from +\return The square root value +*/ +template <typename T> +inline typename detail::square_root<T>::return_type +sqrt(T const& value) +{ + return detail::square_root + < + T, boost::is_fundamental<T>::value + >::apply(value); +} /*! \brief Short utility to workaround gcc/clang problem that abs is converting to integer + and that older versions of MSVC does not support abs of long long... \ingroup utility */ template<typename T> -inline T abs(const T& t) +inline T abs(T const& value) { - using std::abs; - return abs(t); + T const zero = T(); + return value < zero ? -value : value; } +/*! +\brief Short utility to calculate the sign of a number: -1 (negative), 0 (zero), 1 (positive) +\ingroup utility +*/ +template <typename T> +static inline int sign(T const& value) +{ + T const zero = T(); + return value > zero ? 1 : value < zero ? -1 : 0; +} + +/*! +\brief Short utility to calculate the rounded value of a number. +\ingroup utility +\note If the source T is NOT an integral type and Result is an integral type + the value is rounded towards the closest integral value. Otherwise it's + just casted. +*/ +template <typename Result, typename T> +inline Result round(T const& v) +{ + // NOTE: boost::round() could be used instead but it throws in some situations + return detail::round<Result, T>::apply(v); +} } // namespace math diff --git a/boost/geometry/util/parameter_type_of.hpp b/boost/geometry/util/parameter_type_of.hpp index b8872d52bf..3ed09ab9bb 100644 --- a/boost/geometry/util/parameter_type_of.hpp +++ b/boost/geometry/util/parameter_type_of.hpp @@ -25,7 +25,7 @@ namespace boost { namespace geometry -{ +{ /*! @@ -46,7 +46,7 @@ struct parameter_type_of boost::mpl::int_<1>, boost::mpl::int_<0> >::type base_index_type; - + typedef typename boost::mpl::if_c < Index == 0, diff --git a/boost/geometry/util/range.hpp b/boost/geometry/util/range.hpp new file mode 100644 index 0000000000..fe3502f978 --- /dev/null +++ b/boost/geometry/util/range.hpp @@ -0,0 +1,325 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP +#define BOOST_GEOMETRY_UTIL_RANGE_HPP + +#include <algorithm> + +#include <boost/assert.hpp> +#include <boost/concept_check.hpp> +#include <boost/config.hpp> +#include <boost/range/concepts.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/empty.hpp> +#include <boost/range/size.hpp> +#include <boost/type_traits/is_convertible.hpp> + +#include <boost/geometry/core/mutable_range.hpp> + +namespace boost { namespace geometry { namespace range { + +// NOTE: For SinglePassRanges at could iterate over all elements until the i-th element is met. + +/*! +\brief Short utility to conveniently return an element of a RandomAccessRange. +\ingroup utility +*/ +template <typename RandomAccessRange> +inline typename boost::range_value<RandomAccessRange const>::type const& +at(RandomAccessRange const& rng, + typename boost::range_size<RandomAccessRange const>::type i) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<RandomAccessRange const> )); + BOOST_ASSERT(i < boost::size(rng)); + return *(boost::begin(rng) + i); +} + +/*! +\brief Short utility to conveniently return an element of a RandomAccessRange. +\ingroup utility +*/ +template <typename RandomAccessRange> +inline typename boost::range_value<RandomAccessRange>::type & +at(RandomAccessRange & rng, + typename boost::range_size<RandomAccessRange>::type i) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<RandomAccessRange> )); + BOOST_ASSERT(i < boost::size(rng)); + return *(boost::begin(rng) + i); +} + +/*! +\brief Short utility to conveniently return the front element of a Range. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_value<Range>::type const& +front(Range const& rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + return *boost::begin(rng); +} + +/*! +\brief Short utility to conveniently return the front element of a Range. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_value<Range>::type & +front(Range & rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + return *boost::begin(rng); +} + +// NOTE: For SinglePassRanges back() could iterate over all elements until the last element is met. + +/*! +\brief Short utility to conveniently return the back element of a BidirectionalRange. +\ingroup utility +*/ +template <typename BidirectionalRange> +inline typename boost::range_value<BidirectionalRange>::type const& +back(BidirectionalRange const& rng) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange const> )); + BOOST_ASSERT(!boost::empty(rng)); + return *(--boost::end(rng)); +} + +/*! +\brief Short utility to conveniently return the back element of a BidirectionalRange. +\ingroup utility +*/ +template <typename BidirectionalRange> +inline typename boost::range_value<BidirectionalRange>::type & +back(BidirectionalRange & rng) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange> )); + BOOST_ASSERT(!boost::empty(rng)); + return *(--boost::end(rng)); +} + + +/*! +\brief Short utility to conveniently clear a mutable range. + It uses traits::clear<>. +\ingroup utility +*/ +template <typename Range> +inline void clear(Range & rng) +{ + // NOTE: this trait is probably not needed since it could be implemented using resize() + geometry::traits::clear<Range>::apply(rng); +} + +/*! +\brief Short utility to conveniently insert a new element at the end of a mutable range. + It uses boost::geometry::traits::push_back<>. +\ingroup utility +*/ +template <typename Range> +inline void push_back(Range & rng, + typename boost::range_value<Range>::type const& value) +{ + geometry::traits::push_back<Range>::apply(rng, value); +} + +/*! +\brief Short utility to conveniently resize a mutable range. + It uses boost::geometry::traits::resize<>. +\ingroup utility +*/ +template <typename Range> +inline void resize(Range & rng, + typename boost::range_size<Range>::type new_size) +{ + geometry::traits::resize<Range>::apply(rng, new_size); +} + + +/*! +\brief Short utility to conveniently remove an element from the back of a mutable range. + It uses resize(). +\ingroup utility +*/ +template <typename Range> +inline void pop_back(Range & rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + range::resize(rng, boost::size(rng) - 1); +} + +namespace detail { + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template <typename It, + typename OutIt, + bool UseMove = boost::is_convertible + < + typename std::iterator_traits<It>::value_type &&, + typename std::iterator_traits<OutIt>::value_type + >::value> +struct copy_or_move_impl +{ + static inline OutIt apply(It first, It last, OutIt out) + { + return std::move(first, last, out); + } +}; + +template <typename It, typename OutIt> +struct copy_or_move_impl<It, OutIt, false> +{ + static inline OutIt apply(It first, It last, OutIt out) + { + return std::copy(first, last, out); + } +}; + +template <typename It, typename OutIt> +inline OutIt copy_or_move(It first, It last, OutIt out) +{ + return copy_or_move_impl<It, OutIt>::apply(first, last, out); +} + +#else + +template <typename It, typename OutIt> +inline OutIt copy_or_move(It first, It last, OutIt out) +{ + return std::copy(first, last, out); +} + +#endif + +} // namespace detail + +/*! +\brief Short utility to conveniently remove an element from a mutable range. + It uses std::copy() and resize(). Version taking mutable iterators. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_iterator<Range>::type +erase(Range & rng, + typename boost::range_iterator<Range>::type it) +{ + BOOST_ASSERT(!boost::empty(rng)); + BOOST_ASSERT(it != boost::end(rng)); + + typename boost::range_difference<Range>::type const + d = std::distance(boost::begin(rng), it); + + typename boost::range_iterator<Range>::type + next = it; + ++next; + + detail::copy_or_move(next, boost::end(rng), it); + range::resize(rng, boost::size(rng) - 1); + + // NOTE: In general this should be sufficient: + // return it; + // But in MSVC using the returned iterator causes + // assertion failures when iterator debugging is enabled + // Furthermore the code below should work in the case if resize() + // invalidates iterators when the container is resized down. + return boost::begin(rng) + d; +} + +/*! +\brief Short utility to conveniently remove an element from a mutable range. + It uses std::copy() and resize(). Version taking non-mutable iterators. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_iterator<Range>::type +erase(Range & rng, + typename boost::range_iterator<Range const>::type cit) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> )); + + typename boost::range_iterator<Range>::type + it = boost::begin(rng) + + std::distance(boost::const_begin(rng), cit); + + return erase(rng, it); +} + +/*! +\brief Short utility to conveniently remove a range of elements from a mutable range. + It uses std::copy() and resize(). Version taking mutable iterators. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_iterator<Range>::type +erase(Range & rng, + typename boost::range_iterator<Range>::type first, + typename boost::range_iterator<Range>::type last) +{ + typename boost::range_difference<Range>::type const + diff = std::distance(first, last); + BOOST_ASSERT(diff >= 0); + + std::size_t const count = static_cast<std::size_t>(diff); + BOOST_ASSERT(count <= boost::size(rng)); + + if ( count > 0 ) + { + typename boost::range_difference<Range>::type const + d = std::distance(boost::begin(rng), first); + + detail::copy_or_move(last, boost::end(rng), first); + range::resize(rng, boost::size(rng) - count); + + // NOTE: In general this should be sufficient: + // return first; + // But in MSVC using the returned iterator causes + // assertion failures when iterator debugging is enabled + // Furthermore the code below should work in the case if resize() + // invalidates iterators when the container is resized down. + return boost::begin(rng) + d; + } + + return first; +} + +/*! +\brief Short utility to conveniently remove a range of elements from a mutable range. + It uses std::copy() and resize(). Version taking non-mutable iterators. +\ingroup utility +*/ +template <typename Range> +inline typename boost::range_iterator<Range>::type +erase(Range & rng, + typename boost::range_iterator<Range const>::type cfirst, + typename boost::range_iterator<Range const>::type clast) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> )); + + typename boost::range_iterator<Range>::type + first = boost::begin(rng) + + std::distance(boost::const_begin(rng), cfirst); + typename boost::range_iterator<Range>::type + last = boost::begin(rng) + + std::distance(boost::const_begin(rng), clast); + + return erase(rng, first, last); +} + +}}} // namespace boost::geometry::range + +#endif // BOOST_GEOMETRY_UTIL_RANGE_HPP diff --git a/boost/geometry/util/rational.hpp b/boost/geometry/util/rational.hpp index 45bee20460..805c85eb46 100644 --- a/boost/geometry/util/rational.hpp +++ b/boost/geometry/util/rational.hpp @@ -21,11 +21,11 @@ #include <boost/geometry/util/select_most_precise.hpp> -namespace boost{ namespace geometry -{ +namespace boost{ namespace geometry +{ -// Specialize for Boost.Geometry's coordinate cast +// Specialize for Boost.Geometry's coordinate cast // (from string to coordinate type) namespace detail { @@ -39,13 +39,13 @@ struct coordinate_cast<rational<T> > std::string before_part = source.substr(0, p); std::string const after_part = source.substr(p + 1); - negate = false; + negate = false; - if (before_part.size() > 0 && before_part[0] == '-') - { - negate = true; - before_part.erase(0, 1); - } + 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(); @@ -70,10 +70,10 @@ struct coordinate_cast<rational<T> > } split_parts(source, p, before, after, negate, len); - return negate - ? -rational<T>(before, after) - : rational<T>(before, after) - ; + return negate + ? -rational<T>(before, after) + : rational<T>(before, after) + ; } @@ -85,10 +85,10 @@ struct coordinate_cast<rational<T> > den *= 10; } - return negate - ? -rational<T>(before) - rational<T>(after, den) - : rational<T>(before) + rational<T>(after, den) - ; + return negate + ? -rational<T>(before) - rational<T>(after, den) + : rational<T>(before) + rational<T>(after, den) + ; } }; @@ -115,19 +115,19 @@ struct select_most_precise<boost::rational<T>, double> // Specializes boost::rational to boost::numeric::bounds -namespace boost { namespace numeric +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> lowest() + { + return rational<T>(bounds<T>::lowest(), 1); } - static inline rational<T> highest() - { - return rational<T>(bounds<T>::highest(), 1); + static inline rational<T> highest() + { + return rational<T>(bounds<T>::highest(), 1); } }; diff --git a/boost/geometry/util/transform_variant.hpp b/boost/geometry/util/transform_variant.hpp new file mode 100644 index 0000000000..9e4a7aa152 --- /dev/null +++ b/boost/geometry/util/transform_variant.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// 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_TRANSFORM_VARIANT_HPP +#define BOOST_GEOMETRY_UTIL_TRANSFORM_VARIANT_HPP + + +#include <boost/mpl/transform.hpp> +#include <boost/variant/variant_fwd.hpp> + + +namespace boost { namespace geometry +{ + + +/*! + \brief Meta-function that takes a Sequence type, an MPL lambda + expression and an optional Inserter and returns a variant type over + the same types as the initial variant type, each transformed using + the lambda expression. + \ingroup utility + \par Example + \code + typedef mpl::vector<int, float, long> types; + typedef transform_variant<types, add_pointer<_> > transformed; + typedef variant<int*, float*, long*> result; + BOOST_MPL_ASSERT(( equal<result, transformed> )); + \endcode +*/ +template <typename Sequence, typename Op, typename In = boost::mpl::na> +struct transform_variant: + make_variant_over< + typename mpl::transform< + Sequence, + Op, + In + >::type + > +{}; + + +/*! + \brief Meta-function that takes a boost::variant type and an MPL lambda + expression and returns a variant type over the same types as the + initial variant type, each transformed using the lambda expression. + \ingroup utility + \par Example + \code + typedef variant<int, float, long> variant_type; + typedef transform_variant<variant_type, add_pointer<_> > transformed; + typedef variant<int*, float*, long*> result; + BOOST_MPL_ASSERT(( equal<result, transformed> )); + \endcode +*/ +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Op> +struct transform_variant<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Op, boost::mpl::na> : + make_variant_over< + typename mpl::transform< + typename variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, + Op + >::type + > +{}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_TRANSFORM_VARIANT_HPP diff --git a/boost/geometry/views/box_view.hpp b/boost/geometry/views/box_view.hpp index 26608b0860..4ecb941ec9 100644 --- a/boost/geometry/views/box_view.hpp +++ b/boost/geometry/views/box_view.hpp @@ -43,32 +43,36 @@ namespace boost { namespace geometry \qbk{[include reference/views/box_view.qbk]} */ template <typename Box, bool Clockwise = true> -struct box_view +struct box_view : public detail::points_view < - typename geometry::point_type<Box>::type, + 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 : - + +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); + // assign_box_corners_oriented requires a range + // an alternative for this workaround would be to pass a range here, + // e.g. use boost::array in points_view instead of c-array + std::pair<point_type*, point_type*> rng = std::make_pair(points, points + 5); + detail::assign_box_corners_oriented<!Clockwise>(m_box, rng); points[4] = points[0]; } private : diff --git a/boost/geometry/views/closeable_view.hpp b/boost/geometry/views/closeable_view.hpp index 376246d2dc..1f1eb2720b 100644 --- a/boost/geometry/views/closeable_view.hpp +++ b/boost/geometry/views/closeable_view.hpp @@ -28,6 +28,12 @@ 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 @@ -61,7 +67,7 @@ private : /*! \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 + 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 @@ -93,6 +99,9 @@ struct closeable_view<Range, open> #endif // DOXYGEN_NO_SPECIALIZATIONS +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/views/detail/indexed_point_view.hpp b/boost/geometry/views/detail/indexed_point_view.hpp new file mode 100644 index 0000000000..88b13ec5c4 --- /dev/null +++ b/boost/geometry/views/detail/indexed_point_view.hpp @@ -0,0 +1,112 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 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_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP + +#include <cstddef> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/util/math.hpp> + +namespace boost { namespace geometry +{ + +namespace detail +{ + +template <typename Geometry, std::size_t Index> +class indexed_point_view +{ + indexed_point_view & operator=(indexed_point_view const&); + +public: + typedef typename geometry::point_type<Geometry>::type point_type; + typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; + + indexed_point_view(Geometry & geometry) + : m_geometry(geometry) + {} + + template <std::size_t Dimension> + inline coordinate_type get() const + { + return geometry::get<Index, Dimension>(m_geometry); + } + + template <std::size_t Dimension> + inline void set(coordinate_type const& value) + { + geometry::set<Index, Dimension>(m_geometry, value); + } + +private: + Geometry & m_geometry; +}; + +} + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename Geometry, std::size_t Index> +struct tag< detail::indexed_point_view<Geometry, Index> > +{ + typedef point_tag type; +}; + +template <typename Geometry, std::size_t Index> +struct coordinate_type< detail::indexed_point_view<Geometry, Index> > +{ + typedef typename geometry::coordinate_type<Geometry>::type type; +}; + +template <typename Geometry, std::size_t Index> +struct coordinate_system< detail::indexed_point_view<Geometry, Index> > +{ + typedef typename geometry::coordinate_system<Geometry>::type type; +}; + +template <typename Geometry, std::size_t Index> +struct dimension< detail::indexed_point_view<Geometry, Index> > + : geometry::dimension<Geometry> +{}; + +template<typename Geometry, std::size_t Index, std::size_t Dimension> +struct access< detail::indexed_point_view<Geometry, Index>, Dimension > +{ + typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; + + static inline coordinate_type get( + detail::indexed_point_view<Geometry, Index> const& p) + { + return p.template get<Dimension>(); + } + + static inline void set( + detail::indexed_point_view<Geometry, Index> & p, + coordinate_type const& value) + { + p.template set<Dimension>(value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP diff --git a/boost/geometry/views/detail/normalized_view.hpp b/boost/geometry/views/detail/normalized_view.hpp new file mode 100644 index 0000000000..d50ffe48c8 --- /dev/null +++ b/boost/geometry/views/detail/normalized_view.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. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP + + +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/iterator.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/geometry/views/detail/range_type.hpp> +#include <boost/geometry/views/reversible_view.hpp> +#include <boost/geometry/views/closeable_view.hpp> + +namespace boost { namespace geometry { + + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail { + +template <typename Geometry> +struct normalized_view +{ + static const bool is_const = boost::is_const<Geometry>::value; + + //typedef typename ring_type<Geometry>::type ring_type; + + typedef typename detail::range_type<Geometry>::type range_type; + + typedef typename + boost::mpl::if_c + < + is_const, + range_type const, + range_type + >::type range; + + typedef typename + reversible_view + < + range, + order_as_direction + < + geometry::point_order<Geometry>::value + >::value + >::type reversible_type; + + typedef typename + boost::mpl::if_c + < + is_const, + reversible_type const, + reversible_type + >::type reversible; + + typedef typename + closeable_view + < + reversible, + geometry::closure<Geometry>::value + >::type closeable_type; + + typedef typename + boost::mpl::if_c + < + is_const, + closeable_type const, + closeable_type + >::type closeable; + + explicit inline normalized_view(range & r) + : m_reversible(r) + , m_closeable(m_reversible) + {} + + typedef typename boost::range_iterator<closeable>::type iterator; + typedef typename boost::range_const_iterator<closeable>::type const_iterator; + + inline const_iterator begin() const { return boost::begin(m_closeable); } + inline const_iterator end() const { return boost::end(m_closeable); } + + inline iterator begin() { return boost::begin(m_closeable); } + inline iterator end() { return boost::end(m_closeable); } + +private: + reversible_type m_reversible; + closeable_type m_closeable; +}; + +} // namespace detail + +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP diff --git a/boost/geometry/views/detail/points_view.hpp b/boost/geometry/views/detail/points_view.hpp index 91fbc41c19..a06084216b 100644 --- a/boost/geometry/views/detail/points_view.hpp +++ b/boost/geometry/views/detail/points_view.hpp @@ -36,6 +36,7 @@ class points_view // 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". + // ALTERNATIVE: use boost:array and its iterators struct points_iterator : public boost::iterator_facade < @@ -47,21 +48,21 @@ class points_view // Constructor: Begin iterator inline points_iterator(Point const* p) : m_points(p) - , m_index(0) + , m_index(0) {} // Constructor: End iterator inline points_iterator(Point const* p, bool) : m_points(p) - , m_index(MaxSize) + , m_index(MaxSize) {} // Constructor: default (for Range Concept checking). inline points_iterator() : m_points(NULL) - , m_index(MaxSize) + , m_index(MaxSize) {} - + typedef std::ptrdiff_t difference_type; private: @@ -73,7 +74,7 @@ class points_view { return m_points[m_index]; } - + // If it index larger (or smaller) return first point // (assuming initialized) return m_points[0]; @@ -98,14 +99,14 @@ class points_view { return other.m_index - this->m_index; } - + inline void advance(difference_type n) { m_index += n; } Point const* m_points; - int m_index; + difference_type m_index; }; public : @@ -127,8 +128,8 @@ protected : { copy.apply(m_points); } - -private : + +private : // Copy points here - box might define them otherwise Point m_points[MaxSize]; }; diff --git a/boost/geometry/views/detail/range_type.hpp b/boost/geometry/views/detail/range_type.hpp index a40670cf99..fff634c379 100644 --- a/boost/geometry/views/detail/range_type.hpp +++ b/boost/geometry/views/detail/range_type.hpp @@ -16,7 +16,7 @@ #include <boost/mpl/assert.hpp> -#include <boost/type_traits.hpp> +#include <boost/range/value_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tag.hpp> @@ -33,7 +33,8 @@ namespace dispatch { -template <typename GeometryTag, typename Geometry> +template <typename Geometry, + typename Tag = typename tag<Geometry>::type> struct range_type { BOOST_MPL_ASSERT_MSG @@ -45,31 +46,59 @@ struct range_type template <typename Geometry> -struct range_type<ring_tag, Geometry> +struct range_type<Geometry, ring_tag> { typedef Geometry type; }; + template <typename Geometry> -struct range_type<linestring_tag, Geometry> +struct range_type<Geometry, linestring_tag> { typedef Geometry type; }; template <typename Geometry> -struct range_type<polygon_tag, Geometry> +struct range_type<Geometry, polygon_tag> { typedef typename ring_type<Geometry>::type type; }; + template <typename Geometry> -struct range_type<box_tag, Geometry> +struct range_type<Geometry, box_tag> { typedef box_view<Geometry> type; }; +// multi-point acts itself as a range +template <typename Geometry> +struct range_type<Geometry, multi_point_tag> +{ + typedef Geometry type; +}; + + +template <typename Geometry> +struct range_type<Geometry, multi_linestring_tag> +{ + typedef typename boost::range_value<Geometry>::type type; +}; + + +template <typename Geometry> +struct range_type<Geometry, multi_polygon_tag> +{ + // Call its single-version + typedef typename dispatch::range_type + < + typename boost::range_value<Geometry>::type + >::type type; +}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -93,7 +122,6 @@ struct range_type { typedef typename dispatch::range_type < - typename tag<Geometry>::type, Geometry >::type type; }; diff --git a/boost/geometry/views/identity_view.hpp b/boost/geometry/views/identity_view.hpp index 5ce6e8e6d6..8947ebf6fc 100644 --- a/boost/geometry/views/identity_view.hpp +++ b/boost/geometry/views/identity_view.hpp @@ -21,6 +21,11 @@ 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 @@ -46,6 +51,9 @@ private : Range& m_range; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif }} // namespace boost::geometry diff --git a/boost/geometry/views/segment_view.hpp b/boost/geometry/views/segment_view.hpp index 50ff617a8d..ce676fc4bf 100644 --- a/boost/geometry/views/segment_view.hpp +++ b/boost/geometry/views/segment_view.hpp @@ -28,7 +28,7 @@ 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 +\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 @@ -45,26 +45,26 @@ template <typename Segment> struct segment_view : public detail::points_view < - typename geometry::point_type<Segment>::type, + 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 : - + +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]); |