diff options
Diffstat (limited to 'boost/geometry')
225 files changed, 10018 insertions, 3247 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp index 1a8828ba4b..6ffb5f9587 100644 --- a/boost/geometry/algorithms/append.hpp +++ b/boost/geometry/algorithms/append.hpp @@ -22,8 +22,10 @@ #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp index 7377798719..cb1501d8c9 100644 --- a/boost/geometry/algorithms/area.hpp +++ b/boost/geometry/algorithms/area.hpp @@ -18,8 +18,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> diff --git a/boost/geometry/algorithms/assign.hpp b/boost/geometry/algorithms/assign.hpp index 32f095b9ac..2f325448ad 100644 --- a/boost/geometry/algorithms/assign.hpp +++ b/boost/geometry/algorithms/assign.hpp @@ -26,6 +26,10 @@ #include <boost/numeric/conversion/cast.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/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> @@ -41,8 +45,6 @@ #include <boost/geometry/util/for_each_coordinate.hpp> -#include <boost/variant/variant_fwd.hpp> - namespace boost { namespace geometry { @@ -224,28 +226,27 @@ template <typename Geometry1, typename Geometry2> struct assign { static inline void - apply( - Geometry1& geometry1, - const Geometry2& geometry2) + 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; - + static bool const same_point_order + = point_order<Geometry1>::value == point_order<Geometry2>::value; BOOST_MPL_ASSERT_MSG ( - same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER - , (types<Geometry1, Geometry2>) + (same_point_order), + ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER, + (types<Geometry1, Geometry2>) ); + static bool const same_closure + = closure<Geometry1>::value == closure<Geometry2>::value; BOOST_MPL_ASSERT_MSG ( - same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE - , (types<Geometry1, Geometry2>) + (same_closure), + ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE, + (types<Geometry1, Geometry2>) ); dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1); @@ -317,8 +318,8 @@ struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > }; -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)> > +template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { struct visitor: static_visitor<void> { @@ -337,8 +338,8 @@ struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_ }; static inline void - apply(variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, - variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2) + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2) { return apply_visitor(visitor(), geometry1, geometry2); } diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp index b8b07ad4d9..d85d32a0c6 100644 --- a/boost/geometry/algorithms/buffer.hpp +++ b/boost/geometry/algorithms/buffer.hpp @@ -17,8 +17,9 @@ #include <cstddef> #include <boost/numeric/conversion/cast.hpp> -#include <boost/variant/static_visitor.hpp> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/clear.hpp> diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp index 65dc9c3753..67ed68ac03 100644 --- a/boost/geometry/algorithms/centroid.hpp +++ b/boost/geometry/algorithms/centroid.hpp @@ -5,8 +5,8 @@ // 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. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -23,9 +23,11 @@ #include <cstddef> +#include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> @@ -41,8 +43,9 @@ #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/detail/interior_iterator.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/centroid.hpp> #include <boost/geometry/strategies/concepts/centroid_concept.hpp> @@ -116,8 +119,8 @@ template < typename Indexed, typename Point, - std::size_t Dimension, - std::size_t DimensionCount + std::size_t Dimension = 0, + std::size_t DimensionCount = dimension<Indexed>::type::value > struct centroid_indexed_calculator { @@ -137,8 +140,7 @@ struct centroid_indexed_calculator centroid_indexed_calculator < - Indexed, Point, - Dimension + 1, DimensionCount + Indexed, Point, Dimension + 1 >::apply(indexed, centroid); } }; @@ -161,8 +163,7 @@ struct centroid_indexed { centroid_indexed_calculator < - Indexed, Point, - 0, dimension<Indexed>::type::value + Indexed, Point >::apply(indexed, centroid); } }; @@ -183,8 +184,9 @@ inline bool range_ok(Range const& range, Point& centroid) { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) throw centroid_exception(); -#endif +#else return false; +#endif } else // if (n == 1) { @@ -192,7 +194,7 @@ inline bool range_ok(Range const& range, Point& centroid) geometry::convert(*boost::begin(range), centroid); return false; } - return true; + //return true; // unreachable } /*! @@ -207,6 +209,8 @@ struct centroid_range_state Strategy const& strategy, typename Strategy::state_type& state) { + boost::ignore_unused(strategy); + typedef typename geometry::point_type<Ring const>::type point_type; typedef typename closeable_view<Ring const, Closure>::type view_type; @@ -237,7 +241,7 @@ template <closure_selector Closure> struct centroid_range { template<typename Range, typename Point, typename Strategy> - static inline void apply(Range const& range, Point& centroid, + static inline bool apply(Range const& range, Point& centroid, Strategy const& strategy) { if (range_ok(range, centroid)) @@ -248,11 +252,16 @@ struct centroid_range typename Strategy::state_type state; centroid_range_state<Closure>::apply(range, transformer, strategy, state); - strategy.result(state, centroid); - - // translate the result back - transformer.apply_reverse(centroid); + + if ( strategy.result(state, centroid) ) + { + // translate the result back + transformer.apply_reverse(centroid); + return true; + } } + + return false; } }; @@ -289,8 +298,8 @@ struct centroid_polygon_state struct centroid_polygon { template<typename Polygon, typename Point, typename Strategy> - static inline void apply(Polygon const& poly, Point& centroid, - Strategy const& strategy) + static inline bool apply(Polygon const& poly, Point& centroid, + Strategy const& strategy) { if (range_ok(exterior_ring(poly), centroid)) { @@ -300,11 +309,16 @@ struct centroid_polygon typename Strategy::state_type state; centroid_polygon_state::apply(poly, transformer, strategy, state); - strategy.result(state, centroid); - - // translate the result back - transformer.apply_reverse(centroid); + + if ( strategy.result(state, centroid) ) + { + // translate the result back + transformer.apply_reverse(centroid); + return true; + } } + + return false; } }; @@ -321,6 +335,7 @@ struct centroid_multi_point_state Strategy const& strategy, typename Strategy::state_type& state) { + boost::ignore_unused(strategy); strategy.apply(static_cast<Point const&>(transformer.apply(point)), state); } @@ -339,7 +354,7 @@ template <typename Policy> struct centroid_multi { template <typename Multi, typename Point, typename Strategy> - static inline void apply(Multi const& multi, + static inline bool apply(Multi const& multi, Point& centroid, Strategy const& strategy) { @@ -364,10 +379,31 @@ struct centroid_multi { Policy::apply(*it, transformer, strategy, state); } - Strategy::result(state, centroid); - // translate the result back - transformer.apply_reverse(centroid); + if ( strategy.result(state, centroid) ) + { + // translate the result back + transformer.apply_reverse(centroid); + return true; + } + + return false; + } +}; + + +template <typename Algorithm> +struct centroid_linear_areal +{ + template <typename Geometry, typename Point, typename Strategy> + static inline void apply(Geometry const& geom, + Point& centroid, + Strategy const& strategy) + { + if ( ! Algorithm::apply(geom, centroid, strategy) ) + { + geometry::point_on_border(centroid, geom); + } } }; @@ -405,32 +441,47 @@ struct centroid<Segment, segment_tag> template <typename Ring> struct centroid<Ring, ring_tag> - : detail::centroid::centroid_range<geometry::closure<Ring>::value> + : detail::centroid::centroid_linear_areal + < + detail::centroid::centroid_range<geometry::closure<Ring>::value> + > {}; template <typename Linestring> struct centroid<Linestring, linestring_tag> - : detail::centroid::centroid_range<closed> + : detail::centroid::centroid_linear_areal + < + detail::centroid::centroid_range<closed> + > {}; template <typename Polygon> struct centroid<Polygon, polygon_tag> - : detail::centroid::centroid_polygon + : detail::centroid::centroid_linear_areal + < + detail::centroid::centroid_polygon + > {}; template <typename MultiLinestring> struct centroid<MultiLinestring, multi_linestring_tag> - : detail::centroid::centroid_multi + : detail::centroid::centroid_linear_areal < - detail::centroid::centroid_range_state<closed> + detail::centroid::centroid_multi + < + detail::centroid::centroid_range_state<closed> + > > {}; template <typename MultiPolygon> struct centroid<MultiPolygon, multi_polygon_tag> - : detail::centroid::centroid_multi + : detail::centroid::centroid_linear_areal < - detail::centroid::centroid_polygon_state + detail::centroid::centroid_multi + < + detail::centroid::centroid_polygon_state + > > {}; diff --git a/boost/geometry/algorithms/clear.hpp b/boost/geometry/algorithms/clear.hpp index 1850816b1b..22b61e7c30 100644 --- a/boost/geometry/algorithms/clear.hpp +++ b/boost/geometry/algorithms/clear.hpp @@ -16,6 +16,7 @@ #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> diff --git a/boost/geometry/algorithms/convert.hpp b/boost/geometry/algorithms/convert.hpp index 914ef8f420..5d68854a45 100644 --- a/boost/geometry/algorithms/convert.hpp +++ b/boost/geometry/algorithms/convert.hpp @@ -22,8 +22,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> @@ -276,7 +277,7 @@ template bool UseAssignment = boost::is_same<Geometry1, Geometry2>::value && !boost::is_array<Geometry1>::value > -struct convert: not_implemented<Tag1, Tag2, mpl::int_<DimensionCount> > +struct convert: not_implemented<Tag1, Tag2, boost::mpl::int_<DimensionCount> > {}; diff --git a/boost/geometry/algorithms/convex_hull.hpp b/boost/geometry/algorithms/convex_hull.hpp index 09f4c5142d..c6db004f3d 100644 --- a/boost/geometry/algorithms/convex_hull.hpp +++ b/boost/geometry/algorithms/convex_hull.hpp @@ -4,8 +4,8 @@ // 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. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -20,8 +20,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/cs.hpp> @@ -35,6 +36,8 @@ #include <boost/geometry/strategies/concepts/convex_hull_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/util/condition.hpp> + #include <boost/geometry/views/detail/range_type.hpp> #include <boost/geometry/algorithms/num_points.hpp> @@ -122,7 +125,7 @@ struct convex_hull<Box, box_tag> boost::array<typename point_type<Box>::type, 4> range; geometry::detail::assign_box_corners_oriented<Reverse>(box, range); geometry::append(out, range); - if (Close) + if (BOOST_GEOMETRY_CONDITION(Close)) { geometry::append(out, *boost::begin(range)); } diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp index 3c61b2c0d2..11ed6ecff9 100644 --- a/boost/geometry/algorithms/correct.hpp +++ b/boost/geometry/algorithms/correct.hpp @@ -23,8 +23,9 @@ #include <boost/mpl/assert.hpp> #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp index e50dc338af..eb8e732409 100644 --- a/boost/geometry/algorithms/covered_by.hpp +++ b/boost/geometry/algorithms/covered_by.hpp @@ -22,8 +22,8 @@ #include <cstddef> -#include <boost/variant/static_visitor.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> diff --git a/boost/geometry/algorithms/crosses.hpp b/boost/geometry/algorithms/crosses.hpp index 91ed3e0806..cec4931a64 100644 --- a/boost/geometry/algorithms/crosses.hpp +++ b/boost/geometry/algorithms/crosses.hpp @@ -21,6 +21,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP #include <cstddef> + +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/access.hpp> @@ -141,8 +144,8 @@ namespace resolve_variant }; - 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)> > + template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> + struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { struct visitor: static_visitor<bool> { @@ -162,8 +165,8 @@ namespace resolve_variant static inline bool apply( - const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2) + const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2) { return apply_visitor(visitor(), geometry1, geometry2); } diff --git a/boost/geometry/algorithms/detail/azimuth.hpp b/boost/geometry/algorithms/detail/azimuth.hpp new file mode 100644 index 0000000000..7810b4814e --- /dev/null +++ b/boost/geometry/algorithms/detail/azimuth.hpp @@ -0,0 +1,158 @@ +// 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_AZIMUTH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/algorithms/detail/vincenty_inverse.hpp> + +namespace boost { namespace geometry +{ + +// An azimuth is an angle between a vector/segment from origin to a point of +// interest and a reference vector. Typically north-based azimuth is used. +// North direction is used as a reference, angle is measured clockwise +// (North - 0deg, East - 90deg). For consistency in 2d cartesian CS +// the reference vector is Y axis, angle is measured clockwise. +// http://en.wikipedia.org/wiki/Azimuth + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch +{ + +template <typename ReturnType, typename Tag> +struct azimuth + : not_implemented<Tag> +{}; + +template <typename ReturnType> +struct azimuth<ReturnType, geographic_tag> +{ + template <typename P1, typename P2, typename Spheroid> + static inline ReturnType apply(P1 const& p1, P2 const& p2, Spheroid const& spheroid) + { + return geometry::detail::vincenty_inverse<ReturnType> + ( get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2), + spheroid ).azimuth12(); + } + + template <typename P1, typename P2> + static inline ReturnType apply(P1 const& p1, P2 const& p2) + { + return apply(p1, p2, srs::spheroid<ReturnType>()); + } +}; + +template <typename ReturnType> +struct azimuth<ReturnType, spherical_equatorial_tag> +{ + template <typename P1, typename P2, typename Sphere> + static inline ReturnType apply(P1 const& p1, P2 const& p2, Sphere const& /*unused*/) + { + // 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)); + } + + template <typename P1, typename P2> + static inline ReturnType apply(P1 const& p1, P2 const& p2) + { + return apply(p1, p2, 0); // dummy model + } +}; + +template <typename ReturnType> +struct azimuth<ReturnType, spherical_polar_tag> + : azimuth<ReturnType, spherical_equatorial_tag> +{}; + +template <typename ReturnType> +struct azimuth<ReturnType, cartesian_tag> +{ + template <typename P1, typename P2, typename Plane> + static inline ReturnType apply(P1 const& p1, P2 const& p2, Plane const& /*unused*/) + { + ReturnType x = get<0>(p2) - get<0>(p1); + ReturnType y = get<1>(p2) - get<1>(p1); + + // NOTE: azimuth 0 is at Y axis, increasing right + // as in spherical/geographic where 0 is at North axis + return atan2(x, y); + } + + template <typename P1, typename P2> + static inline ReturnType apply(P1 const& p1, P2 const& p2) + { + return apply(p1, p2, 0); // dummy model + } +}; + +} // detail_dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/// Calculate azimuth between two points. +/// The result is in radians. +template <typename ReturnType, typename Point1, typename Point2> +inline ReturnType azimuth(Point1 const& p1, Point2 const& p2) +{ + return detail_dispatch::azimuth + < + ReturnType, + typename geometry::cs_tag<Point1>::type + >::apply(p1, p2); +} + +/// Calculate azimuth between two points. +/// The result is in radians. +template <typename ReturnType, typename Point1, typename Point2, typename Model> +inline ReturnType azimuth(Point1 const& p1, Point2 const& p2, Model const& model) +{ + return detail_dispatch::azimuth + < + ReturnType, + typename geometry::cs_tag<Point1>::type + >::apply(p1, p2, model); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index c959ee849b..127e4c3fb2 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -12,6 +12,7 @@ #include <cstddef> #include <iterator> +#include <boost/core/ignore_unused.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/range.hpp> @@ -20,6 +21,7 @@ #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/strategies/buffer.hpp> @@ -28,6 +30,7 @@ #include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp> #include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp> +#include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/simplify.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> @@ -144,15 +147,25 @@ struct buffer_range intersection_point); } + switch(join) { case strategy::buffer::join_continue : // No join, we get two consecutive sides - return; + break; case strategy::buffer::join_concave : - collection.add_piece(strategy::buffer::buffered_concave, - previous_input, prev_perp2, perp1); - return; + { + std::vector<output_point_type> range_out; + range_out.push_back(prev_perp2); + range_out.push_back(previous_input); + collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); + + range_out.clear(); + range_out.push_back(previous_input); + range_out.push_back(perp1); + collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); + } + break; case strategy::buffer::join_spike : { // For linestrings, only add spike at one side to avoid @@ -160,22 +173,24 @@ struct buffer_range 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); + collection.set_current_ring_concave(); } - return; + break; 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); + { + // 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); + } + } + break; } } @@ -225,18 +240,13 @@ struct buffer_range output_point_type& last_p1, output_point_type& last_p2) { + boost::ignore_unused(side_strategy); + 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 /* @@ -261,57 +271,50 @@ struct buffer_range 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); + generated_side.clear(); + side_strategy.apply(*prev, *it, side, + distance_strategy, generated_side); - if (generated_side.empty()) - { - break; - } + if (generated_side.empty()) + { + // Because input is simplified, this is improbable, + // but it can happen for degenerate geometries + // Further handling of this side is skipped + continue; + } - result = true; + 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); - } + 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); + 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(); - } + 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; } @@ -775,7 +778,7 @@ public: distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy); - collection.finish_ring(); + collection.finish_ring(false, geometry::num_interior_rings(polygon) > 0u); } apply_interior_rings(interior_rings(polygon), @@ -839,6 +842,8 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator VisitPiecesPolicy& visit_pieces_policy ) { + boost::ignore_unused(visit_pieces_policy); + typedef detail::buffer::buffered_piece_collection < typename geometry::ring_type<GeometryOutput>::type, @@ -852,6 +857,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type, areal_tag >::type::value; + bool const linear = boost::is_same + < + typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type, + linear_tag + >::type::value; dispatch::buffer_inserter < @@ -868,9 +878,10 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator robust_policy); collection.get_turns(); - if (areal) + collection.classify_turns(linear); + if (BOOST_GEOMETRY_CONDITION(areal)) { - collection.check_remaining_points(distance_strategy.factor()); + collection.check_remaining_points(distance_strategy); } // Visit the piece collection. This does nothing (by default), but @@ -889,7 +900,8 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator // - the output is counter clockwise // and avoid reversing twice bool reverse = distance_strategy.negative() && areal; - if (geometry::point_order<GeometryOutput>::value == counterclockwise) + if (BOOST_GEOMETRY_CONDITION( + geometry::point_order<GeometryOutput>::value == counterclockwise)) { reverse = ! reverse; } @@ -898,6 +910,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator collection.reverse(); } + if (distance_strategy.negative() && areal) + { + collection.discard_nonintersecting_deflated_rings(); + } + collection.template assign<GeometryOutput>(out); // Visit collection again diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index 6a2e6b32c5..c5bb8acc05 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -35,7 +35,7 @@ namespace detail { namespace buffer enum intersection_location_type { - location_ok, inside_buffer, inside_original + location_ok, inside_buffer, location_discard }; class backtrack_for_buffer @@ -120,10 +120,14 @@ struct buffer_turn_info return robust_point; } - intersection_location_type location; int count_within; + + bool within_original; + int count_on_original_boundary; + int count_in_original; // increased by +1 for in ext.ring, -1 for int.ring + int count_on_offsetted; int count_on_helper; int count_within_near_offsetted; @@ -138,6 +142,9 @@ struct buffer_turn_info : turn_index(-1) , location(location_ok) , count_within(0) + , within_original(false) + , count_on_original_boundary(0) + , count_in_original(0) , count_on_offsetted(0) , count_on_helper(0) , count_within_near_offsetted(0) diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 558a61fcb4..a501e3f197 100644 --- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -12,8 +12,9 @@ #include <algorithm> #include <cstddef> #include <set> -#include <boost/range.hpp> +#include <boost/core/ignore_unused.hpp> +#include <boost/range.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> @@ -24,13 +25,14 @@ #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/buffer/turn_in_original_visitor.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_box.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> @@ -41,6 +43,8 @@ #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/algorithms/detail/sections/sectionalize.hpp> +#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/util/range.hpp> @@ -89,7 +93,7 @@ enum segment_relation_code * 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) + * form together the robust_polygons (marked with r below) * The remaining piece-segments are helper-segments (marked with h) * * ooooooooooooooooo @@ -120,7 +124,7 @@ struct buffered_piece_collection // 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 geometry::model::box<robust_point_type> robust_box_type; typedef typename strategy::side::services::default_strategy < @@ -164,6 +168,9 @@ struct buffered_piece_collection struct piece { + typedef robust_ring_type piece_robust_ring_type; + typedef geometry::section<robust_box_type, 1> section_type; + strategy::buffer::piece_type type; int index; @@ -181,18 +188,58 @@ struct buffered_piece_collection #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 + std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end #endif + bool is_monotonic_increasing[2]; // 0=x, 1=y + bool is_monotonic_decreasing[2]; // 0=x, 1=y + + // Monotonic sections of pieces around points + std::vector<section_type> sections; + + // Robust representations // 3: complete ring robust_ring_type robust_ring; - geometry::model::box<robust_point_type> robust_envelope; + robust_box_type robust_envelope; + robust_box_type robust_offsetted_envelope; std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead }; + struct robust_original + { + typedef robust_ring_type original_robust_ring_type; + typedef geometry::sections<robust_box_type, 1> sections_type; + + inline robust_original() + : m_is_interior(false) + , m_has_interiors(true) + {} + + inline robust_original(robust_ring_type const& ring, + bool is_interior, bool has_interiors) + : m_ring(ring) + , m_is_interior(is_interior) + , m_has_interiors(has_interiors) + { + geometry::envelope(m_ring, m_box); + + // create monotonic sections in y-dimension + typedef boost::mpl::vector_c<std::size_t, 1> dimensions; + geometry::sectionalize<false, dimensions>(m_ring, + detail::no_rescale_policy(), m_sections); + } + + robust_ring_type m_ring; + robust_box_type m_box; + sections_type m_sections; + + bool m_is_interior; + bool m_has_interiors; + }; + typedef std::vector<piece> piece_vector_type; piece_vector_type m_pieces; @@ -200,11 +247,17 @@ struct buffered_piece_collection 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) + std::vector<robust_original> robust_originals; // robust representation of the original(s) robust_ring_type current_robust_ring; buffered_ring_collection<Ring> traversed_rings; segment_identifier current_segment_id; + // Specificly for offsetted rings around points + // but also for large joins with many points + typedef geometry::sections<robust_box_type, 2> sections_type; + sections_type monotonic_sections; + + RobustPolicy const& m_robust_policy; struct redundant_turn @@ -378,7 +431,7 @@ struct buffered_piece_collection } } - inline void classify_turns() + inline void classify_turns(bool linear) { for (typename boost::range_iterator<turn_vector_type>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) @@ -387,6 +440,10 @@ struct buffered_piece_collection { it->location = inside_buffer; } + if (it->count_on_original_boundary > 0 && ! linear) + { + 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 @@ -394,31 +451,40 @@ struct buffered_piece_collection // will never start a new ring from this type of points. it->selectable_start = false; } - } } - inline void check_remaining_points(int factor) + template <typename DistanceStrategy> + inline void check_remaining_points(DistanceStrategy const& distance_strategy) { - // TODO: use partition + // Check if a turn is inside any of the originals + + turn_in_original_visitor<turn_vector_type> visitor(m_turns); + geometry::partition + < + robust_box_type, + turn_get_box, turn_in_original_ovelaps_box, + original_get_box, original_ovelaps_box, + include_turn_policy, detail::partition::include_all_policy + >::apply(m_turns, robust_originals, visitor); + + bool const deflate = distance_strategy.negative(); 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) + buffer_turn_info_type& turn = *it; + if (turn.location == location_ok) { - int code = -1; - for (std::size_t i = 0; i < robust_polygons.size(); i++) + if (deflate && turn.count_in_original <= 0) { - if (geometry::covered_by(it->robust_point, robust_polygons[i])) - { - code = 1; - break; - } + // For deflate: it is not in original, discard + turn.location = location_discard; } - if (code * factor == 1) + else if (! deflate && turn.count_in_original > 0) { - it->location = inside_original; + // For inflate: it is in original, discard + turn.location = location_discard; } } } @@ -474,6 +540,7 @@ struct buffered_piece_collection // 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); + geometry::expand(pc.robust_offsetted_envelope, it->robust_point); } } @@ -502,9 +569,10 @@ struct buffered_piece_collection { 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 - ); + ( + 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++; @@ -517,25 +585,132 @@ struct buffered_piece_collection BOOST_ASSERT(assert_indices_in_robust_rings()); } + template <std::size_t Dimension> + static inline void determine_monotonicity(piece& pc, + robust_point_type const& current, + robust_point_type const& next) + { + if (geometry::get<Dimension>(current) >= geometry::get<Dimension>(next)) + { + pc.is_monotonic_increasing[Dimension] = false; + } + if (geometry::get<Dimension>(current) <= geometry::get<Dimension>(next)) + { + pc.is_monotonic_decreasing[Dimension] = false; + } + } + + static inline void determine_properties(piece& pc) + { + pc.is_monotonic_increasing[0] = true; + pc.is_monotonic_increasing[1] = true; + pc.is_monotonic_decreasing[0] = true; + pc.is_monotonic_decreasing[1] = true; + + if (pc.offsetted_count < 2) + { + return; + } + + typename robust_ring_type::const_iterator current = pc.robust_ring.begin(); + typename robust_ring_type::const_iterator next = current + 1; + + for (int i = 1; i < pc.offsetted_count; i++) + { + determine_monotonicity<0>(pc, *current, *next); + determine_monotonicity<1>(pc, *current, *next); + current = next; + ++next; + } + + } + + void determine_properties() + { + for (typename piece_vector_type::iterator it = boost::begin(m_pieces); + it != boost::end(m_pieces); + ++it) + { + determine_properties(*it); + } + } + + inline void reverse_negative_robust_rings() + { + for (typename piece_vector_type::iterator it = boost::begin(m_pieces); + it != boost::end(m_pieces); + ++it) + { + piece& pc = *it; + if (geometry::area(pc.robust_ring) < 0) + { + // Rings can be ccw: + // - in a concave piece + // - in a line-buffer with a negative buffer-distance + std::reverse(pc.robust_ring.begin(), pc.robust_ring.end()); + } + } + } + + inline void prepare_buffered_point_piece(piece& pc) + { + // create monotonic sections in y-dimension + typedef boost::mpl::vector_c<std::size_t, 1> dimensions; + geometry::sectionalize<false, dimensions>(pc.robust_ring, + detail::no_rescale_policy(), pc.sections); + + // TODO (next phase) determine min/max radius + } + + inline void prepare_buffered_point_pieces() + { + for (typename piece_vector_type::iterator it = boost::begin(m_pieces); + it != boost::end(m_pieces); + ++it) + { + if (it->type == geometry::strategy::buffer::buffered_point) + { + prepare_buffered_point_piece(*it); + } + } + } + inline void get_turns() { + for(typename boost::range_iterator<sections_type>::type it + = boost::begin(monotonic_sections); + it != boost::end(monotonic_sections); + ++it) + { + enlarge_box(it->bounding_box, 1); + } + { // Calculate the turns piece_turn_visitor < + piece_vector_type, buffered_ring_collection<buffered_ring<Ring> >, turn_vector_type, RobustPolicy - > visitor(offsetted_rings, m_turns, m_robust_policy); + > visitor(m_pieces, offsetted_rings, m_turns, m_robust_policy); geometry::partition < - model::box<robust_point_type>, piece_get_box, piece_ovelaps_box - >::apply(m_pieces, visitor); + robust_box_type, + detail::section::get_section_box, + detail::section::overlaps_section_box + >::apply(monotonic_sections, visitor); } insert_rescaled_piece_turns(); + reverse_negative_robust_rings(); + + determine_properties(); + + prepare_buffered_point_pieces(); + { // Check if it is inside any of the pieces turn_in_piece_visitor @@ -545,16 +720,12 @@ struct buffered_piece_collection geometry::partition < - model::box<robust_point_type>, + robust_box_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() @@ -571,7 +742,38 @@ struct buffered_piece_collection m_first_piece_index = boost::size(m_pieces); } - inline void finish_ring(bool is_interior = false) + inline void update_closing_point() + { + BOOST_ASSERT(! offsetted_rings.empty()); + buffered_ring<Ring>& added = offsetted_rings.back(); + if (! boost::empty(added)) + { + range::back(added) = range::front(added); + } + } + + inline void update_last_point(point_type const& p, + buffered_ring<Ring>& ring) + { + // For the first point of a new piece, and there were already + // points in the offsetted ring, for some piece types the first point + // is a duplicate of the last point of the previous piece. + + // TODO: disable that, that point should not be added + + // For now, it is made equal because due to numerical instability, + // it can be a tiny bit off, possibly causing a self-intersection + + BOOST_ASSERT(boost::size(m_pieces) > 0); + if (! ring.empty() + && current_segment_id.segment_index + == m_pieces.back().first_seg_id.segment_index) + { + ring.back() = p; + } + } + + inline void finish_ring(bool is_interior = false, bool has_interiors = false) { if (m_first_piece_index == -1) { @@ -588,41 +790,50 @@ struct buffered_piece_collection } m_first_piece_index = -1; - if (!current_robust_ring.empty()) + update_closing_point(); + + if (! current_robust_ring.empty()) { - BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back())); + 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; - } + robust_originals.push_back( + robust_original(current_robust_ring, + is_interior, has_interiors)); } } + inline void set_current_ring_concave() + { + BOOST_ASSERT(boost::size(offsetted_rings) > 0); + offsetted_rings.back().has_concave = true; + } + inline int add_point(point_type const& p) { - BOOST_ASSERT - ( - boost::size(offsetted_rings) > 0 - ); + BOOST_ASSERT(boost::size(offsetted_rings) > 0); + + buffered_ring<Ring>& current_ring = offsetted_rings.back(); + update_last_point(p, current_ring); current_segment_id.segment_index++; - offsetted_rings.back().push_back(p); - return offsetted_rings.back().size(); + current_ring.push_back(p); + return current_ring.size(); } //------------------------------------------------------------------------- - inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one) + inline piece& create_piece(strategy::buffer::piece_type type, + bool decrease_segment_index_by_one) { + if (type == strategy::buffer::buffered_concave) + { + offsetted_rings.back().has_concave = true; + } + piece pc; pc.type = type; pc.index = boost::size(m_pieces); @@ -634,6 +845,7 @@ struct buffered_piece_collection std::size_t const n = boost::size(offsetted_rings.back()); pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n; + pc.last_segment_index = pc.first_seg_id.segment_index; m_pieces.push_back(pc); return m_pieces.back(); @@ -641,6 +853,18 @@ struct buffered_piece_collection inline void init_rescale_piece(piece& pc, std::size_t helper_points_size) { + if (pc.first_seg_id.segment_index < 0) + { + // This indicates an error situation: an earlier piece was empty + // It currently does not happen + // std::cout << "EMPTY " << pc.type << " " << pc.index << " " << pc.first_seg_id.multi_index << std::endl; + pc.offsetted_count = 0; + return; + } + + BOOST_ASSERT(pc.first_seg_id.multi_index >= 0); + BOOST_ASSERT(pc.last_segment_index >= 0); + pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index; BOOST_ASSERT(pc.offsetted_count >= 0); @@ -674,16 +898,65 @@ struct buffered_piece_collection return rob_point; } + // TODO: this is shared with sectionalize, move to somewhere else (assign?) + template <typename Box, typename Value> + inline void enlarge_box(Box& box, Value value) + { + geometry::set<0, 0>(box, geometry::get<0, 0>(box) - value); + geometry::set<0, 1>(box, geometry::get<0, 1>(box) - value); + geometry::set<1, 0>(box, geometry::get<1, 0>(box) + value); + geometry::set<1, 1>(box, geometry::get<1, 1>(box) + value); + } + inline void calculate_robust_envelope(piece& pc) { + if (pc.offsetted_count == 0) + { + return; + } + geometry::detail::envelope::envelope_range::apply(pc.robust_ring, pc.robust_envelope); + + geometry::assign_inverse(pc.robust_offsetted_envelope); + for (int i = 0; i < pc.offsetted_count; i++) + { + geometry::expand(pc.robust_offsetted_envelope, pc.robust_ring[i]); + } + + // Take roundings into account, enlarge boxes with 1 integer + enlarge_box(pc.robust_envelope, 1); + enlarge_box(pc.robust_offsetted_envelope, 1); + } + + inline void sectionalize(piece& pc) + { + + buffered_ring<Ring> const& ring = offsetted_rings.back(); + + typedef geometry::detail::sectionalize::sectionalize_part + < + point_type, + boost::mpl::vector_c<std::size_t, 0, 1> // x,y dimension + > sectionalizer; + + // Create a ring-identifier. The source-index is the piece index + // The multi_index is as in this collection (the ring), but not used here + // The ring_index is not used + ring_identifier ring_id(pc.index, pc.first_seg_id.multi_index, -1); + + sectionalizer::apply(monotonic_sections, + boost::begin(ring) + pc.first_seg_id.segment_index, + boost::begin(ring) + pc.last_segment_index, + m_robust_policy, + ring_id, 10); } inline void finish_piece(piece& pc) { init_rescale_piece(pc, 0u); calculate_robust_envelope(pc); + sectionalize(pc); } inline void finish_piece(piece& pc, @@ -692,10 +965,16 @@ struct buffered_piece_collection const point_type& point3) { init_rescale_piece(pc, 3u); + if (pc.offsetted_count == 0) + { + return; + } + add_helper_point(pc, point1); robust_point_type mid_point = add_helper_point(pc, point2); add_helper_point(pc, point3); calculate_robust_envelope(pc); + sectionalize(pc); current_robust_ring.push_back(mid_point); } @@ -711,6 +990,7 @@ struct buffered_piece_collection 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); + sectionalize(pc); calculate_robust_envelope(pc); // Add mid-points in other order to current helper_ring @@ -730,10 +1010,7 @@ struct buffered_piece_collection template <typename Range> inline void add_range_to_piece(piece& pc, Range const& range, bool add_front) { - if (boost::size(range) == 0u) - { - return; - } + BOOST_ASSERT(boost::size(range) != 0u); typename Range::const_iterator it = boost::begin(range); @@ -753,10 +1030,15 @@ struct buffered_piece_collection template <typename Range> - inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one) + 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()); + + if (boost::size(range) > 0u) + { + add_range_to_piece(pc, range, offsetted_rings.back().empty()); + } finish_piece(pc); } @@ -772,13 +1054,14 @@ struct buffered_piece_collection } template <typename Range> - inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& 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) + if (boost::size(range) > 0u) { + add_range_to_piece(pc, range, offsetted_rings.back().empty()); finish_piece(pc, range.back(), p, range.front()); } else @@ -788,8 +1071,11 @@ struct buffered_piece_collection } template <typename EndcapStrategy, typename Range> - inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point) + inline void add_endcap(EndcapStrategy const& strategy, Range const& range, + point_type const& end_point) { + boost::ignore_unused(strategy); + if (range.empty()) { return; @@ -842,6 +1128,80 @@ struct buffered_piece_collection } } + inline bool point_coveredby_original(point_type const& point) + { + robust_point_type any_point; + geometry::recalculate(any_point, point, m_robust_policy); + + int count_in_original = 0; + + // Check of the robust point of this outputted ring is in + // any of the robust original rings + // This can go quadratic if the input has many rings, and there + // are many untouched deflated rings around + for (typename std::vector<robust_original>::const_iterator it + = robust_originals.begin(); + it != robust_originals.end(); + ++it) + { + robust_original const& original = *it; + if (detail::disjoint::disjoint_point_box(any_point, + original.m_box)) + { + continue; + } + + int const geometry_code + = detail::within::point_in_geometry(any_point, + original.m_ring); + + if (geometry_code == -1) + { + // Outside, continue + continue; + } + + // Apply for possibly nested interior rings + if (original.m_is_interior) + { + count_in_original--; + } + else if (original.m_has_interiors) + { + count_in_original++; + } + else + { + // Exterior ring without interior rings + return true; + } + } + return count_in_original > 0; + } + + // For a deflate, all rings around inner rings which are untouched + // (no intersections/turns) and which are OUTSIDE the original should + // be discarded + inline void discard_nonintersecting_deflated_rings() + { + for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it + = boost::begin(offsetted_rings); + it != boost::end(offsetted_rings); + ++it) + { + buffered_ring<Ring>& ring = *it; + if (! ring.has_intersections() + && boost::size(ring) > 0u + && geometry::area(ring) < 0) + { + if (! point_coveredby_original(geometry::range::front(ring))) + { + ring.is_untouched_outside_original = true; + } + } + } + } + inline void block_turns() { // To fix left-turn issues like #rt_u13 @@ -876,7 +1236,8 @@ struct buffered_piece_collection typedef detail::overlay::traverse < false, false, - buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >, + buffered_ring_collection<buffered_ring<Ring> >, + buffered_ring_collection<buffered_ring<Ring > >, backtrack_for_buffer > traverser; @@ -914,16 +1275,20 @@ struct buffered_piece_collection std::map<ring_identifier, properties> selected; - // Select all rings which do not have any self-intersection (other ones should be traversed) + // Select all rings which do not have any self-intersection + // Inner rings, for deflate, which do not have intersections, and + // which are outside originals, are skipped + // (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()) + if (! it->has_intersections() + && ! it->is_untouched_outside_original) { ring_identifier id(0, index, -1); - selected[id] = properties(*it, true); + selected[id] = properties(*it); } } @@ -935,7 +1300,7 @@ struct buffered_piece_collection ++it, ++index) { ring_identifier id(2, index, -1); - selected[id] = properties(*it, true); + selected[id] = properties(*it); } detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true); diff --git a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp index 03ec598c90..9ea8bc1e85 100644 --- a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp @@ -43,12 +43,16 @@ struct buffered_ring_collection_tag : polygonal_tag, multi_tag template <typename Ring> struct buffered_ring : public Ring { + bool has_concave; bool has_accepted_intersections; bool has_discarded_intersections; + bool is_untouched_outside_original; inline buffered_ring() - : has_accepted_intersections(false) + : has_concave(false) + , has_accepted_intersections(false) , has_discarded_intersections(false) + , is_untouched_outside_original(false) {} inline bool discarded() const diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index 395921ccaa..6a3daa282e 100644 --- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -16,6 +16,7 @@ #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> +#include <boost/geometry/algorithms/detail/sections/section_functions.hpp> namespace boost { namespace geometry @@ -27,32 +28,16 @@ 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 Pieces, typename Rings, typename Turns, typename RobustPolicy > class piece_turn_visitor { + Pieces const& m_pieces; Rings const& m_rings; Turns& m_turns; RobustPolicy const& m_robust_policy; @@ -69,6 +54,17 @@ class piece_turn_visitor || piece1.index == piece2.right_index; } + template <typename Piece> + inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const + { + if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index) + { + return false; + } + + return ! m_rings[piece1.first_seg_id.multi_index].has_concave; + } + template <typename Range, typename Iterator> inline void move_to_next_point(Range const& range, Iterator& next) const { @@ -93,46 +89,110 @@ class piece_turn_visitor return result; } - template <typename Piece> - inline void calculate_turns(Piece const& piece1, Piece const& piece2) + template <std::size_t Dimension, typename Iterator, typename Box> + inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond, + int& index, int dir, Box const& other_bounding_box) + { + for(; it_begin != it_beyond + && it_begin + 1 != it_beyond + && detail::section::preceding<Dimension>(dir, *(it_begin + 1), + other_bounding_box, m_robust_policy); + ++it_begin, index++) + {} + } + + template <std::size_t Dimension, typename Iterator, typename Box> + inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond, + int dir, Box const& other_bounding_box) + { + while (it_beyond != it_begin + && it_beyond - 1 != it_begin + && it_beyond - 2 != it_begin) + { + if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2), + other_bounding_box, m_robust_policy)) + { + --it_beyond; + } + else + { + return; + } + } + } + + template <typename Piece, typename Section> + inline void calculate_turns(Piece const& piece1, Piece const& piece2, + Section const& section1, Section const& section2) { 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) + int const piece1_first_index = piece1.first_seg_id.segment_index; + int const piece2_first_index = piece2.first_seg_id.segment_index; + if (piece1_first_index < 0 || piece2_first_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; + // Get indices of part of offsetted_rings for this monotonic section: + int const sec1_first_index = piece1_first_index + section1.begin_index; + int const sec2_first_index = piece2_first_index + section2.begin_index; + + // index of last point in section, beyond-end is one further + int const sec1_last_index = piece1_first_index + section1.end_index; + int const sec2_last_index = piece2_first_index + section2.end_index; + + // get geometry and iterators over these sections + ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index]; + iterator it1_first = boost::begin(ring1) + sec1_first_index; + iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1; + + ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index]; + iterator it2_first = boost::begin(ring2) + sec2_first_index; + iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1; + + // Set begin/end of monotonic ranges, in both x/y directions + int index1 = sec1_first_index; + move_begin_iterator<0>(it1_first, it1_beyond, index1, + section1.directions[0], section2.bounding_box); + move_end_iterator<0>(it1_first, it1_beyond, + section1.directions[0], section2.bounding_box); + move_begin_iterator<1>(it1_first, it1_beyond, index1, + section1.directions[1], section2.bounding_box); + move_end_iterator<1>(it1_first, it1_beyond, + section1.directions[1], section2.bounding_box); + + int index2 = sec2_first_index; + move_begin_iterator<0>(it2_first, it2_beyond, index2, + section2.directions[0], section1.bounding_box); + move_end_iterator<0>(it2_first, it2_beyond, + section2.directions[0], section1.bounding_box); + move_begin_iterator<1>(it2_first, it2_beyond, index2, + section2.directions[1], section1.bounding_box); + move_end_iterator<1>(it2_first, it2_beyond, + section2.directions[1], section1.bounding_box); turn_type the_model; the_model.operations[0].piece_index = piece1.index; the_model.operations[0].seg_id = piece1.first_seg_id; + the_model.operations[0].seg_id.segment_index = index1; // override iterator it1 = it1_first; for (iterator prev1 = it1++; - it1 != it1_last; + it1 != it1_beyond; 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; + the_model.operations[1].seg_id.segment_index = index2; // override iterator next1 = next_point(ring1, it1); iterator it2 = it2_first; for (iterator prev2 = it2++; - it2 != it2_last; + it2 != it2_beyond; prev2 = it2++, the_model.operations[1].seg_id.segment_index++) { iterator next2 = next_point(ring2, it2); @@ -158,26 +218,36 @@ class piece_turn_visitor public: - piece_turn_visitor(Rings const& ring_collection, + piece_turn_visitor(Pieces const& pieces, + Rings const& ring_collection, Turns& turns, RobustPolicy const& robust_policy) - : m_rings(ring_collection) + : m_pieces(pieces) + , m_rings(ring_collection) , m_turns(turns) , m_robust_policy(robust_policy) {} - template <typename Piece> - inline void apply(Piece const& piece1, Piece const& piece2, + template <typename Section> + inline void apply(Section const& section1, Section const& section2, 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)) + + typedef typename boost::range_value<Pieces const>::type piece_type; + piece_type const& piece1 = m_pieces[section1.ring_id.source_index]; + piece_type const& piece2 = m_pieces[section2.ring_id.source_index]; + + if ( piece1.index == piece2.index + || is_adjacent(piece1, piece2) + || is_on_same_convex_ring(piece1, piece2) + || detail::disjoint::disjoint_box_box(section1.bounding_box, + section2.bounding_box) ) { return; } - calculate_turns(piece1, piece2); + + calculate_turns(piece1, piece2, section1, section2); } }; diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp deleted file mode 100644 index 2b1c33d291..0000000000 --- a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp +++ /dev/null @@ -1,98 +0,0 @@ -// 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_original_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp new file mode 100644 index 0000000000..05fc6df8ff --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp @@ -0,0 +1,268 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 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_ORIGINAL_VISITOR +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR + + +#include <boost/core/ignore_unused.hpp> + +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +struct original_get_box +{ + template <typename Box, typename Original> + static inline void apply(Box& total, Original const& original) + { + geometry::expand(total, original.m_box); + } +}; + +struct original_ovelaps_box +{ + template <typename Box, typename Original> + static inline bool apply(Box const& box, Original const& original) + { + return ! detail::disjoint::disjoint_box_box(box, original.m_box); + } +}; + +struct include_turn_policy +{ + template <typename Turn> + static inline bool apply(Turn const& turn) + { + return turn.location == location_ok; + } +}; + +struct turn_in_original_ovelaps_box +{ + template <typename Box, typename Turn> + static inline bool apply(Box const& box, Turn const& turn) + { + if (turn.location != location_ok || turn.within_original) + { + // Skip all points already processed + return false; + } + + return ! geometry::detail::disjoint::disjoint_point_box( + turn.robust_point, box); + } +}; + +//! Check if specified is in range of specified iterators +//! Return value of strategy (true if we can bail out) +template +< + typename Strategy, + typename State, + typename Point, + typename Iterator +> +inline bool point_in_range(Strategy& strategy, State& state, + Point const& point, Iterator begin, Iterator end) +{ + boost::ignore_unused(strategy); + + Iterator it = begin; + for (Iterator previous = it++; it != end; ++previous, ++it) + { + if (! strategy.apply(point, *previous, *it, state)) + { + // We're probably on the boundary + return false; + } + } + return true; +} + +template +< + typename Strategy, + typename State, + typename Point, + typename CoordinateType, + typename Iterator +> +inline bool point_in_section(Strategy& strategy, State& state, + Point const& point, CoordinateType const& point_y, + Iterator begin, Iterator end, + int direction) +{ + if (direction == 0) + { + // Not a monotonic section, or no change in Y-direction + return point_in_range(strategy, state, point, begin, end); + } + + // We're in a monotonic section in y-direction + Iterator it = begin; + + for (Iterator previous = it++; it != end; ++previous, ++it) + { + // Depending on sections.direction we can quit for this section + CoordinateType const previous_y = geometry::get<1>(*previous); + + if (direction == 1 && point_y < previous_y) + { + // Section goes upwards, y increases, point is is below section + return true; + } + else if (direction == -1 && point_y > previous_y) + { + // Section goes downwards, y decreases, point is above section + return true; + } + + if (! strategy.apply(point, *previous, *it, state)) + { + // We're probably on the boundary + return false; + } + } + return true; +} + + +template <typename Point, typename Original> +inline int point_in_original(Point const& point, Original const& original) +{ + typedef strategy::within::winding<Point> strategy_type; + + typename strategy_type::state_type state; + strategy_type strategy; + + if (boost::size(original.m_sections) == 0 + || boost::size(original.m_ring) - boost::size(original.m_sections) < 16) + { + // There are no sections, or it does not profit to walk over sections + // instead of over points. Boundary of 16 is arbitrary but can influence + // performance + point_in_range(strategy, state, point, + original.m_ring.begin(), original.m_ring.end()); + return strategy.result(state); + } + + typedef typename Original::sections_type sections_type; + typedef typename boost::range_iterator<sections_type const>::type iterator_type; + typedef typename boost::range_value<sections_type const>::type section_type; + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + coordinate_type const point_y = geometry::get<1>(point); + + // Walk through all monotonic sections of this original + for (iterator_type it = boost::begin(original.m_sections); + it != boost::end(original.m_sections); + ++it) + { + section_type const& section = *it; + + if (! section.duplicate + && section.begin_index < section.end_index + && point_y >= geometry::get<min_corner, 1>(section.bounding_box) + && point_y <= geometry::get<max_corner, 1>(section.bounding_box)) + { + // y-coordinate of point overlaps with section + if (! point_in_section(strategy, state, point, point_y, + boost::begin(original.m_ring) + section.begin_index, + boost::begin(original.m_ring) + section.end_index + 1, + section.directions[0])) + { + // We're probably on the boundary + break; + } + } + } + + return strategy.result(state); +} + + +template <typename Turns> +class turn_in_original_visitor +{ +public: + turn_in_original_visitor(Turns& turns) + : m_mutable_turns(turns) + {} + + template <typename Turn, typename Original> + inline void apply(Turn const& turn, Original const& original, bool first = true) + { + boost::ignore_unused_variable_warning(first); + + if (turn.location != location_ok || turn.within_original) + { + // Skip all points already processed + return; + } + + if (geometry::disjoint(turn.robust_point, original.m_box)) + { + // Skip all disjoint + return; + } + + int const code = point_in_original(turn.robust_point, original); + + if (code == -1) + { + return; + } + + Turn& mutable_turn = m_mutable_turns[turn.turn_index]; + + if (code == 0) + { + // On border of original: always discard + mutable_turn.location = location_discard; + } + + // Point is inside an original ring + if (original.m_is_interior) + { + mutable_turn.count_in_original--; + } + else if (original.m_has_interiors) + { + mutable_turn.count_in_original++; + } + else + { + // It is an exterior ring and there are no interior rings. + // Then we are completely ready with this turn + mutable_turn.within_original = true; + mutable_turn.count_in_original = 1; + } + } + +private : + Turns& m_mutable_turns; +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index c02f56de3f..8803efdec9 100644 --- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -9,19 +9,23 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR + +#include <boost/core/ignore_unused.hpp> + #include <boost/range.hpp> #include <boost/geometry/arithmetic/dot_product.hpp> +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/comparable_distance.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/disjoint/box_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 { @@ -31,6 +35,33 @@ namespace boost { namespace geometry 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) + { + 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 + + // Skip all pieces not used as soon as possible + return false; + } + + return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope); + } +}; struct turn_get_box { @@ -46,96 +77,422 @@ 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); + return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box); } }; -template <typename Turns, typename Pieces> -class turn_in_piece_visitor + +enum analyse_result { - Turns& m_turns; // because partition is currently operating on const input only - Pieces const& m_pieces; // to check for piece-type + analyse_unknown, + analyse_continue, + analyse_disjoint, + analyse_within, + analyse_on_original_boundary, + analyse_on_offsetted, + analyse_near_offsetted +}; - typedef boost::long_long_type calculation_type; +template <typename Point> +inline bool in_box(Point const& previous, + Point const& current, Point const& point) +{ + // Get its box (TODO: this can be prepared-on-demand later) + typedef geometry::model::box<Point> box_type; + box_type box; + geometry::assign_inverse(box); + geometry::expand(box, previous); + geometry::expand(box, current); + + return geometry::covered_by(point, box); +} + +template <typename Point, typename Turn> +inline analyse_result check_segment(Point const& previous, + Point const& current, Turn const& turn, + bool from_monotonic) +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type side_strategy; + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + coordinate_type const twice_area + = side_strategy::template side_value + < + coordinate_type, + coordinate_type + >(previous, current, turn.robust_point); - template <typename Point> - static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) + if (twice_area == 0) { - typedef Point vector_type; - typedef typename geometry::coordinate_type<Point>::type coordinate_type; + // Collinear, only on segment if it is covered by its bbox + if (in_box(previous, current, turn.robust_point)) + { + return analyse_on_offsetted; + } + } + else if (twice_area < 0) + { + // It is in the triangle right-of the segment where the + // segment is the hypothenusa. Check if it is close + // (within rounding-area) + if (twice_area * twice_area < geometry::comparable_distance(previous, current) + && in_box(previous, current, turn.robust_point)) + { + return analyse_near_offsetted; + } + else if (from_monotonic) + { + return analyse_within; + } + } + else if (twice_area > 0 && from_monotonic) + { + // Left of segment + return analyse_disjoint; + } + + // Not monotonic, on left or right side: continue analysing + return analyse_continue; +} - 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); +class analyse_turn_wrt_point_piece +{ +public : + template <typename Turn, typename Piece> + static inline analyse_result apply(Turn const& turn, Piece const& piece) + { + typedef typename Piece::section_type section_type; + typedef typename Turn::robust_point_type point_type; + typedef typename geometry::coordinate_type<point_type>::type coordinate_type; - if (c1 < zero) + coordinate_type const point_y = geometry::get<1>(turn.robust_point); + + typedef strategy::within::winding<point_type> strategy_type; + + typename strategy_type::state_type state; + strategy_type strategy; + boost::ignore_unused(strategy); + + for (std::size_t s = 0; s < piece.sections.size(); s++) { - return false; + section_type const& section = piece.sections[s]; + // If point within vertical range of monotonic section: + if (! section.duplicate + && section.begin_index < section.end_index + && point_y >= geometry::get<min_corner, 1>(section.bounding_box) - 1 + && point_y <= geometry::get<max_corner, 1>(section.bounding_box) + 1) + { + for (int i = section.begin_index + 1; i <= section.end_index; i++) + { + point_type const& previous = piece.robust_ring[i - 1]; + point_type const& current = piece.robust_ring[i]; + + analyse_result code = check_segment(previous, current, turn, false); + if (code != analyse_continue) + { + return code; + } + + // Get the state (to determine it is within), we don't have + // to cover the on-segment case (covered above) + strategy.apply(turn.robust_point, previous, current, state); + } + } } - coordinate_type const c2 = dot_product(v, v); - if (c2 < c1) + + int const code = strategy.result(state); + if (code == 1) { - return false; + return analyse_within; + } + else if (code == -1) + { + return analyse_disjoint; } - return true; + // Should normally not occur - on-segment is covered + return analyse_unknown; } - template <typename Point, typename Piece> - inline bool on_offsetted(Point const& point, Piece const& piece) const +}; + +class analyse_turn_wrt_piece +{ + template <typename Point, typename Turn> + static inline analyse_result check_helper_segment(Point const& s1, + Point const& s2, Turn const& turn, + bool is_original, + Point const& offsetted) { typedef typename strategy::side::services::default_strategy < typename cs_tag<Point>::type >::type side_strategy; - geometry::equal_to<Point> comparator; + + switch(side_strategy::apply(s1, s2, turn.robust_point)) + { + case 1 : + return analyse_disjoint; // left of segment + case 0 : + { + // If is collinear, either on segment or before/after + typedef geometry::model::box<Point> box_type; + + box_type box; + geometry::assign_inverse(box); + geometry::expand(box, s1); + geometry::expand(box, s2); + + if (geometry::covered_by(turn.robust_point, box)) + { + // It is on the segment + if (! is_original + && geometry::comparable_distance(turn.robust_point, offsetted) <= 1) + { + // It is close to the offsetted-boundary, take + // any rounding-issues into account + return analyse_near_offsetted; + } + + // Points on helper-segments are considered as within + // Points on original boundary are processed differently + return is_original + ? analyse_on_original_boundary + : analyse_within; + } + + // It is collinear but not on the segment. Because these + // segments are convex, it is outside + // Unless the offsetted ring is collinear or concave w.r.t. + // helper-segment but that scenario is not yet supported + return analyse_disjoint; + } + break; + } + + // right of segment + return analyse_continue; + } + + template <typename Turn, typename Piece> + static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece) + { + typedef typename Turn::robust_point_type point_type; + geometry::equal_to<point_type> comparator; + + point_type points[4]; + + int helper_count = piece.robust_ring.size() - piece.offsetted_count; + if (helper_count == 4) + { + for (int i = 0; i < 4; i++) + { + points[i] = piece.robust_ring[piece.offsetted_count + i]; + } + } + else if (helper_count == 3) + { + // Triangular piece, assign points but assign second twice + for (int i = 0; i < 4; i++) + { + int index = i < 2 ? i : i - 1; + points[i] = piece.robust_ring[piece.offsetted_count + index]; + } + } + else + { + // Some pieces (e.g. around points) do not have helper segments. + // Others should have 3 (join) or 4 (side) + return analyse_continue; + } + + // First check point-equality + point_type const& point = turn.robust_point; + if (comparator(point, points[0]) || comparator(point, points[3])) + { + return analyse_on_offsetted; + } + if (comparator(point, points[1]) || comparator(point, points[2])) + { + return analyse_on_original_boundary; + } + + // Right side of the piece + analyse_result result + = check_helper_segment(points[0], points[1], turn, + false, points[0]); + if (result != analyse_continue) + { + return result; + } + + // Left side of the piece + result = check_helper_segment(points[2], points[3], turn, + false, points[3]); + if (result != analyse_continue) + { + return result; + } + + if (! comparator(points[1], points[2])) + { + // Side of the piece at side of original geometry + result = check_helper_segment(points[1], points[2], turn, + true, point); + if (result != analyse_continue) + { + return result; + } + } + + // We are within the \/ or |_| shaped piece, where the top is the + // offsetted ring. + if (! geometry::covered_by(point, piece.robust_offsetted_envelope)) + { + // Not in offsetted-area. This makes a cheap check possible + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<point_type>::type + >::type side_strategy; + + switch(side_strategy::apply(points[3], points[0], point)) + { + case 1 : return analyse_disjoint; + case -1 : return analyse_within; + case 0 : return analyse_disjoint; + } + } + + return analyse_continue; + } + + template <typename Turn, typename Piece, typename Compare> + static inline analyse_result check_monotonic(Turn const& turn, Piece const& piece, Compare const& compare) + { + typedef typename Piece::piece_robust_ring_type ring_type; + typedef typename ring_type::const_iterator it_type; + it_type end = piece.robust_ring.begin() + piece.offsetted_count; + it_type it = std::lower_bound(piece.robust_ring.begin(), + end, + turn.robust_point, + compare); + + if (it != end + && it != piece.robust_ring.begin()) + { + // iterator points to point larger than point + // w.r.t. specified direction, and prev points to a point smaller + // We now know if it is inside/outside + it_type prev = it - 1; + return check_segment(*prev, *it, turn, true); + } + return analyse_continue; + } + +public : + template <typename Turn, typename Piece> + static inline analyse_result apply(Turn const& turn, Piece const& piece) + { + typedef typename Turn::robust_point_type point_type; + analyse_result code = check_helper_segments(turn, piece); + if (code != analyse_continue) + { + return code; + } + + geometry::equal_to<point_type> comparator; + + if (piece.offsetted_count > 8) + { + // If the offset contains some points and is monotonic, we try + // to avoid walking all points linearly. + // We try it only once. + if (piece.is_monotonic_increasing[0]) + { + code = check_monotonic(turn, piece, geometry::less<point_type, 0>()); + if (code != analyse_continue) return code; + } + else if (piece.is_monotonic_increasing[1]) + { + code = check_monotonic(turn, piece, geometry::less<point_type, 1>()); + if (code != analyse_continue) return code; + } + else if (piece.is_monotonic_decreasing[0]) + { + code = check_monotonic(turn, piece, geometry::greater<point_type, 0>()); + if (code != analyse_continue) return code; + } + else if (piece.is_monotonic_decreasing[1]) + { + code = check_monotonic(turn, piece, geometry::greater<point_type, 1>()); + if (code != analyse_continue) return code; + } + } + + // It is small or not monotonic, walk linearly through offset + // TODO: this will be combined with winding strategy for (int i = 1; i < piece.offsetted_count; i++) { - Point const& previous = piece.robust_ring[i - 1]; - Point const& current = piece.robust_ring[i]; + point_type const& previous = piece.robust_ring[i - 1]; + point_type const& current = piece.robust_ring[i]; - // The robust ring contains duplicates, avoid applying side on them (will be 0) + // The robust ring can contain duplicates + // (on which any side or side-value would return 0) if (! comparator(previous, current)) { - int const side = side_strategy::apply(previous, current, point); - if (side == 0) + code = check_segment(previous, current, turn, false); + if (code != analyse_continue) { - // Collinear, check if projection falls on it - if (projection_on_segment(point, previous, current)) - { - return true; - } + return code; } } } - return false; + + return analyse_unknown; } - template <typename Point, typename Piece> - static inline - calculation_type comparable_distance_from_offsetted(Point const& point, - Piece const& piece) +}; + + +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 + + template <typename Operation, typename Piece> + inline bool skip(Operation const& op, Piece const& piece) const { - // 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); + if (op.piece_index == piece.index) + { + return true; + } + Piece const& pc = m_pieces[op.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 true; + } + if (pc.type == strategy::buffer::buffered_concave) + { + // If it is concave, the same applies: the IP will be + // located on one of the helper segments + return true; + } + } + + return false; } + public: inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces) @@ -157,81 +514,55 @@ public: 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 + // Turns cannot be located within flat-end or concave 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) + if (! geometry::covered_by(turn.robust_point, piece.robust_envelope)) { + // Easy check: if the turn is not in the envelope, we can safely return return; } - if (geometry_code == 0 && neighbour) + + if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece)) { return; } + // TODO: mutable_piece to make some on-demand preparations in analyse + analyse_result analyse_code = + piece.type == geometry::strategy::buffer::buffered_point + ? analyse_turn_wrt_point_piece::apply(turn, piece) + : analyse_turn_wrt_piece::apply(turn, piece); + Turn& mutable_turn = m_turns[turn.turn_index]; - if (geometry_code == 0) + switch(analyse_code) { - // 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 - { + case analyse_disjoint : + return; + case analyse_on_offsetted : mutable_turn.count_on_offsetted++; // value is not used anymore - } + return; + case analyse_on_original_boundary : + mutable_turn.count_on_original_boundary++; + return; + case analyse_within : + mutable_turn.count_within++; + return; + case analyse_near_offsetted : + mutable_turn.count_within_near_offsetted++; + return; + default : + break; } + // TODO: this point_in_geometry is a performance-bottleneck here and + // will be replaced completely by extending analyse_piece functionality + int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring); + 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++; - } + mutable_turn.count_within++; } } }; diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp index c7558b4ff1..04fa9ee86b 100644 --- a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp +++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp @@ -63,8 +63,7 @@ private: >::apply(geometry, *it_min, strategy); // check if other elements in the range are closer - RangeIterator it = first; - for (++it; it != last; ++it) + for (RangeIterator it = ++first; it != last; ++it) { Distance dist = dispatch::distance < diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp index 90248767ec..ceba59b41a 100644 --- a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp +++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp @@ -60,6 +60,7 @@ private: BOOST_ASSERT( queries_first != queries_last ); Distance const zero = Distance(0); + dist_min = zero; // create -- packing algorithm rtree_type rt(rtree_first, rtree_last); diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp index 1a57c8f4b3..c443a54e58 100644 --- a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp +++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp @@ -232,13 +232,13 @@ struct comparable_distance template < - BOOST_VARIANT_ENUM_PARAMS(typename A), - BOOST_VARIANT_ENUM_PARAMS(typename B) + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct comparable_distance < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> @@ -246,8 +246,8 @@ struct comparable_distance < typename comparable_distance_result < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type > @@ -279,12 +279,12 @@ struct comparable_distance template <typename Strategy> static inline typename comparable_distance_result < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2, + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); diff --git a/boost/geometry/algorithms/detail/course.hpp b/boost/geometry/algorithms/detail/course.hpp index e1a74c0fee..37424941bd 100644 --- a/boost/geometry/algorithms/detail/course.hpp +++ b/boost/geometry/algorithms/detail/course.hpp @@ -14,10 +14,7 @@ #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> +#include <boost/geometry/algorithms/detail/azimuth.hpp> namespace boost { namespace geometry { @@ -27,25 +24,12 @@ namespace detail { /// Calculate course (bearing) between two points. +/// +/// NOTE: left for convenience and temporary backward compatibility 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)); + return azimuth<ReturnType>(p1, p2); } } // namespace detail diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp index ccff9799fd..84671f257e 100644 --- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp @@ -74,7 +74,7 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount> /*! - \brief Internal utility function to detect of boxes are disjoint + \brief Internal utility function to detect if boxes are disjoint \note Is used from other algorithms, declared separately to avoid circular references */ diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp index 0c8079b8e4..d482c4a5a9 100644 --- a/boost/geometry/algorithms/detail/disjoint/implementation.hpp +++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp @@ -26,6 +26,7 @@ #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/multipoint_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> diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp index ec9057ba0d..96d6881296 100644 --- a/boost/geometry/algorithms/detail/disjoint/interface.hpp +++ b/boost/geometry/algorithms/detail/disjoint/interface.hpp @@ -23,8 +23,8 @@ #include <cstddef> -#include <boost/variant/static_visitor.hpp> #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/geometries/concepts/check.hpp> diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp index eefd351b8d..6a48b684a1 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp @@ -5,8 +5,8 @@ // 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. +// This file was modified by Oracle on 2013-2015. +// Modifications copyright (c) 2013-2015, 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 @@ -31,16 +31,20 @@ #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tag_cast.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/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/point_on_border.hpp> + +#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.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> @@ -48,25 +52,59 @@ namespace boost { namespace geometry { - #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { +template <typename Geometry1, typename Geometry2, + typename Tag1 = typename tag<Geometry1>::type, + typename Tag1OrMulti = typename tag_cast<Tag1, multi_tag>::type> +struct disjoint_no_intersections_policy +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + 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 Geometry1, typename Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag1> +struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag> +{ + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + { + // TODO: use partition or rtree on g2 + typedef typename boost::range_iterator<Geometry1 const>::type iterator; + for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it ) + { + typedef typename boost::range_value<Geometry1 const>::type value_type; + if ( ! disjoint_no_intersections_policy<value_type const, Geometry2> + ::apply(*it, g2) ) + { + return false; + } + } + return true; + } +}; + + +template<typename Geometry1, typename Geometry2, + typename NoIntersectionsPolicy + = disjoint_no_intersections_policy<Geometry1, 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); + return NoIntersectionsPolicy::apply(g1, g2); } }; @@ -88,38 +126,28 @@ 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); + typedef typename boost::range_value<InteriorRings>::type ring_type; + + typedef unary_disjoint_geometry_to_query_geometry + < + Segment, + disjoint_range_segment_or_box + < + ring_type, closure<ring_type>::value, Segment + > + > unary_predicate_type; + + return check_iterator_range + < + unary_predicate_type + >::apply(boost::begin(interior_rings), + boost::end(interior_rings), + unary_predicate_type(segment)); } @@ -155,7 +183,7 @@ 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 + return multirange_constant_size_geometry < MultiPolygon, Segment >::apply(multipolygon, segment); diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp index ad84d7191d..91f985edb8 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp @@ -98,11 +98,10 @@ struct assign_disjoint_policy typename Info, typename Point1, typename Point2, - typename IntersectionInfo, - typename DirInfo + typename IntersectionInfo > static inline void apply(Info& , Point1 const& , Point2 const&, - IntersectionInfo const&, DirInfo const&) + IntersectionInfo const&) {} }; @@ -115,28 +114,42 @@ struct disjoint_linear { typedef typename geometry::point_type<Geometry1>::type point_type; typedef detail::no_rescale_policy rescale_policy_type; + typedef typename geometry::segment_ratio_type + < + point_type, rescale_policy_type + >::type segment_ratio_type; typedef overlay::turn_info - < - point_type, - typename segment_ratio_type<point_type, rescale_policy_type>::type - > turn_info; - std::deque<turn_info> turns; + < + point_type, + segment_ratio_type, + typename detail::get_turns::turn_operation_type + < + Geometry1, Geometry2, segment_ratio_type + >::type + > turn_info_type; - 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 + std::deque<turn_info_type> turns; // 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 + disjoint_interrupt_policy interrupt_policy; + dispatch::get_turns < - reverse1, reverse2, - assign_disjoint_policy - >(geometry1, geometry2, robust_policy, turns, policy); + typename geometry::tag<Geometry1>::type, + typename geometry::tag<Geometry2>::type, + Geometry1, + Geometry2, + overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, // should be false + overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // should be false + detail::get_turns::get_turn_info_type + < + Geometry1, Geometry2, assign_disjoint_policy + > + >::apply(0, geometry1, 1, geometry2, + rescale_policy_type(), turns, interrupt_policy); - return !policy.has_intersections; + return !interrupt_policy.has_intersections; } }; diff --git a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp index d181726e2e..8d82f7c911 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp @@ -32,6 +32,7 @@ #include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> @@ -44,34 +45,6 @@ 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, @@ -160,7 +133,7 @@ template <typename MultiLinestring, typename SegmentOrBox> struct disjoint_linear_segment_or_box < MultiLinestring, SegmentOrBox, multi_linestring_tag - > : disjoint_multirange_segment_or_box<MultiLinestring, SegmentOrBox> + > : multirange_constant_size_geometry<MultiLinestring, SegmentOrBox> {}; diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp new file mode 100644 index 0000000000..7d1bb05242 --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp @@ -0,0 +1,162 @@ +// 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_DISJOINT_MULTIPOINT_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP + +#include <algorithm> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> +#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/less.hpp> + +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + +template<typename MultiPoint1, typename MultiPoint2> +class multipoint_multipoint +{ +private: + template <typename Iterator> + class unary_disjoint_predicate + : detail::relate::less + { + private: + typedef detail::relate::less base_type; + + public: + unary_disjoint_predicate(Iterator first, Iterator last) + : base_type(), m_first(first), m_last(last) + {} + + template <typename Point> + inline bool apply(Point const& point) const + { + return !std::binary_search(m_first, + m_last, + point, + static_cast<base_type const&>(*this)); + } + + private: + Iterator m_first, m_last; + }; + +public: + static inline bool apply(MultiPoint1 const& multipoint1, + MultiPoint2 const& multipoint2) + { + BOOST_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) ); + + typedef typename boost::range_value<MultiPoint1>::type point1_type; + + std::vector<point1_type> points1(boost::begin(multipoint1), + boost::end(multipoint1)); + + std::sort(points1.begin(), points1.end(), detail::relate::less()); + + typedef unary_disjoint_predicate + < + typename std::vector<point1_type>::const_iterator + > predicate_type; + + return check_iterator_range + < + predicate_type + >::apply(boost::begin(multipoint2), + boost::end(multipoint2), + predicate_type(points1.begin(), points1.end())); + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template<typename Point, typename MultiPoint, std::size_t DimensionCount> +struct disjoint + < + Point, MultiPoint, DimensionCount, point_tag, multi_point_tag, false + > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Point> +{}; + + +template<typename MultiPoint, typename Segment, std::size_t DimensionCount> +struct disjoint + < + MultiPoint, Segment, DimensionCount, multi_point_tag, segment_tag, false + > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Segment> +{}; + + +template<typename MultiPoint, typename Box, std::size_t DimensionCount> +struct disjoint + < + MultiPoint, Box, DimensionCount, multi_point_tag, box_tag, false + > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Box> +{}; + + +template<typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount> +struct disjoint + < + MultiPoint1, MultiPoint2, DimensionCount, + multi_point_tag, multi_point_tag, false + > +{ + static inline bool apply(MultiPoint1 const& multipoint1, + MultiPoint2 const& multipoint2) + { + if ( boost::size(multipoint2) < boost::size(multipoint1) ) + { + return detail::disjoint::multipoint_multipoint + < + MultiPoint2, MultiPoint1 + >::apply(multipoint2, multipoint1); + } + + return detail::disjoint::multipoint_multipoint + < + MultiPoint1, MultiPoint2 + >::apply(multipoint1, multipoint2); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp new file mode 100644 index 0000000000..78a683e46e --- /dev/null +++ b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp @@ -0,0 +1,85 @@ +// 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_DISJOINT_MULTIRANGE_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +template <typename Geometry, typename BinaryPredicate> +class unary_disjoint_geometry_to_query_geometry +{ +public: + unary_disjoint_geometry_to_query_geometry(Geometry const& geometry) + : m_geometry(geometry) + {} + + template <typename QueryGeometry> + inline bool apply(QueryGeometry const& query_geometry) const + { + return BinaryPredicate::apply(query_geometry, m_geometry); + } + +private: + Geometry const& m_geometry; +}; + + +template<typename MultiRange, typename ConstantSizeGeometry> +struct multirange_constant_size_geometry +{ + static inline bool apply(MultiRange const& multirange, + ConstantSizeGeometry const& constant_size_geometry) + { + typedef unary_disjoint_geometry_to_query_geometry + < + ConstantSizeGeometry, + dispatch::disjoint + < + typename boost::range_value<MultiRange>::type, + ConstantSizeGeometry + > + > unary_predicate_type; + + return detail::check_iterator_range + < + unary_predicate_type + >::apply(boost::begin(multirange), boost::end(multirange), + unary_predicate_type(constant_size_geometry)); + } + + static inline bool apply(ConstantSizeGeometry const& constant_size_geometry, + MultiRange const& multirange) + { + return apply(multirange, constant_size_geometry); + } +}; + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp index ea6609a153..12213db056 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp @@ -70,8 +70,21 @@ struct point_box<Point, Box, DimensionCount, DimensionCount> } }; +/*! + \brief Internal utility function to detect if point/box are disjoint + */ +template <typename Point, typename Box> +inline bool disjoint_point_box(Point const& point, Box const& box) +{ + return detail::disjoint::point_box + < + Point, Box, + 0, dimension<Point>::type::value + >::apply(point, box); +} + -}} // namespace detail::equals +}} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL 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 index 04d1095cba..57257dbdcc 100644 --- a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp +++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp @@ -35,6 +35,8 @@ #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/util/condition.hpp> + namespace boost { namespace geometry { @@ -215,7 +217,7 @@ public: // consider all distances of the points in the geometry to the // segment or box - comparable_return_type cd_min1; + comparable_return_type cd_min1(0); 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(); @@ -246,7 +248,7 @@ public: // consider all distances of the points in the segment or box to the // segments of the geometry - comparable_return_type cd_min2; + comparable_return_type cd_min2(0); segment_iterator_type sit_min; typename std::vector<segment_or_box_point>::const_iterator it_min; @@ -271,7 +273,7 @@ public: } } - if (is_comparable<Strategy>::value) + if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return (std::min)(cd_min1, cd_min2); } diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp index 9b377f524b..fa8cbd69ee 100644 --- a/boost/geometry/algorithms/detail/distance/interface.hpp +++ b/boost/geometry/algorithms/detail/distance/interface.hpp @@ -260,13 +260,13 @@ struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > template < - BOOST_VARIANT_ENUM_PARAMS(typename A), - BOOST_VARIANT_ENUM_PARAMS(typename B) + BOOST_VARIANT_ENUM_PARAMS(typename T1), + BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct distance < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> @@ -274,8 +274,8 @@ struct distance < typename distance_result < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type > @@ -304,12 +304,12 @@ struct distance template <typename Strategy> static inline typename distance_result < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2, + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp index 5f2c6e34fb..ccd3aa462e 100644 --- a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp +++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp @@ -18,7 +18,7 @@ #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> -#include <boost/geometry/algorithms/within.hpp> +#include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> @@ -113,16 +113,16 @@ template <typename MultiPoint, typename Areal, typename Strategy> class multipoint_to_areal { private: - struct within_areal + struct not_covered_by_areal { - within_areal(Areal const& areal) + not_covered_by_areal(Areal const& areal) : m_areal(areal) {} template <typename Point> inline bool apply(Point const& point) const { - return geometry::within(point, m_areal); + return !geometry::covered_by(point, m_areal); } Areal const& m_areal; @@ -140,27 +140,26 @@ public: Areal const& areal, Strategy const& strategy) { - within_areal predicate(areal); + not_covered_by_areal predicate(areal); if (check_iterator_range < - within_areal, false + not_covered_by_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); } - - 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); + return 0; } static inline return_type apply(Areal const& areal, diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp index f64a3e9fca..79d9adb703 100644 --- a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp +++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp @@ -28,6 +28,7 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/calculation_type.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/strategies/distance.hpp> @@ -151,7 +152,7 @@ public: } } - if (is_comparable<Strategy>::value) + if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return cd[imin]; } diff --git a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp index 2dcde64946..bdf056d76e 100644 --- a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp +++ b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp @@ -18,6 +18,8 @@ #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/condition.hpp> + #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> @@ -96,7 +98,7 @@ public: std::size_t imin = std::distance(boost::addressof(d[0]), std::min_element(d, d + 4)); - if (is_comparable<Strategy>::value) + if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return d[imin]; } diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index 5bcb5ffaa0..dc1cd74900 100644 --- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -17,7 +17,6 @@ #include <boost/numeric/conversion/cast.hpp> -#include <boost/range.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> @@ -28,7 +27,7 @@ #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/math.hpp> - +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -159,7 +158,7 @@ struct range_collect_vectors if ( collected_count > 1 ) { typedef typename boost::range_iterator<Collection>::type c_iterator; - c_iterator first = collection.begin() + c_old_size; + c_iterator first = range::pos(collection, c_old_size); if ( first->same_direction(collection.back()) ) { diff --git a/boost/geometry/algorithms/detail/flattening.hpp b/boost/geometry/algorithms/detail/flattening.hpp new file mode 100644 index 0000000000..8ed5fd9a89 --- /dev/null +++ b/boost/geometry/algorithms/detail/flattening.hpp @@ -0,0 +1,69 @@ +// Boost.Geometry + +// 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_FLATTENING_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP + +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch +{ + +template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type> +struct flattening + : not_implemented<Tag> +{}; + +template <typename ResultType, typename Geometry> +struct flattening<ResultType, Geometry, srs_sphere_tag> +{ + static inline ResultType apply(Geometry const& /*geometry*/) + { + return ResultType(0); + } +}; + +template <typename ResultType, typename Geometry> +struct flattening<ResultType, Geometry, srs_spheroid_tag> +{ + static inline ResultType apply(Geometry const& geometry) + { + return ResultType(get_radius<0>(geometry) - get_radius<2>(geometry)) + / ResultType(get_radius<0>(geometry)); + } +}; + +} // namespace detail_dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename ResultType, typename Geometry> +ResultType flattening(Geometry const& geometry) +{ + return detail_dispatch::flattening<ResultType, Geometry>::apply(geometry); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp index 323ab7c850..d57535e61f 100644 --- a/boost/geometry/algorithms/detail/intersection/interface.hpp +++ b/boost/geometry/algorithms/detail/intersection/interface.hpp @@ -223,8 +223,8 @@ struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > }; -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 <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename GeometryOut> struct visitor: static_visitor<bool> @@ -255,8 +255,8 @@ struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT template <typename GeometryOut> static inline bool apply( - const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2, + const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, + const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2, GeometryOut& geometry_out) { return apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2); diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp index 9a1a16507a..623632c44e 100644 --- a/boost/geometry/algorithms/detail/is_simple/areal.hpp +++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -19,6 +19,7 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> @@ -38,11 +39,12 @@ struct is_simple_ring { static inline bool apply(Ring const& ring) { + simplicity_failure_policy policy; return !detail::is_valid::has_duplicates < Ring, geometry::closure<Ring>::value - >::apply(ring); + >::apply(ring, policy); } }; 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 index 75c37c68f8..196d89b925 100644 --- a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp +++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -18,6 +18,8 @@ #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/util/range.hpp> @@ -26,7 +28,8 @@ #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/algorithms/equals.hpp> -#endif +#include <boost/geometry/algorithms/not_implemented.hpp> +#endif // BOOST_GEOMETRY_TEST_DEBUG namespace boost { namespace geometry @@ -37,39 +40,67 @@ namespace detail { namespace is_simple #ifdef BOOST_GEOMETRY_TEST_DEBUG -template <typename MultiLinestring> -inline void debug_print_boundary_points(MultiLinestring const& multilinestring) +template <typename Linear, typename Tag = typename tag<Linear>::type> +struct debug_boundary_points_printer + : not_implemented<Linear> +{}; + +template <typename Linestring> +struct debug_boundary_points_printer<Linestring, linestring_tag> { - typedef typename point_type<MultiLinestring>::type point_type; - typedef std::vector<point_type> point_vector; + static inline void apply(Linestring const& linestring) + { + std::cout << "boundary points: "; + std::cout << " " << geometry::dsv(range::front(linestring)); + std::cout << " " << geometry::dsv(range::back(linestring)); + std::cout << std::endl << std::endl; + } +}; - point_vector boundary_points; - for (typename boost::range_iterator<MultiLinestring const>::type it - = boost::begin(multilinestring); - it != boost::end(multilinestring); ++it) +template <typename MultiLinestring> +struct debug_boundary_points_printer<MultiLinestring, multi_linestring_tag> +{ + static inline void apply(MultiLinestring const& multilinestring) { - if ( boost::size(*it) > 1 - && !geometry::equals(range::front(*it), range::back(*it)) ) + 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) { - boundary_points.push_back( range::front(*it) ); - boundary_points.push_back( range::back(*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::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 << "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; } - std::cout << std::endl << std::endl; +}; + + +template <typename Linear> +inline void debug_print_boundary_points(Linear const& linear) +{ + debug_boundary_points_printer<Linear>::apply(linear); } #else -template <typename MultiLinestring> -inline void debug_print_boundary_points(MultiLinestring const&) +template <typename Linear> +inline void debug_print_boundary_points(Linear const&) { } #endif // BOOST_GEOMETRY_TEST_DEBUG diff --git a/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp b/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp new file mode 100644 index 0000000000..6504edd1d5 --- /dev/null +++ b/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_FAILURE_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP + +#include <boost/geometry/algorithms/validity_failure_type.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace is_simple +{ + + +struct simplicity_failure_policy +{ + template <validity_failure_type Failure> + static inline bool apply() + { + return Failure == no_failure; + } + + template <validity_failure_type Failure, typename Data> + static inline bool apply(Data const&) + { + return apply<Failure>(); + } + + template <validity_failure_type Failure, typename Data1, typename Data2> + static inline bool apply(Data1 const&, Data2 const&) + { + return apply<Failure>(); + } +}; + + +}} // namespace detail::is_simple +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp index 4239664ed1..fd84826970 100644 --- a/boost/geometry/algorithms/detail/is_simple/interface.hpp +++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp @@ -10,8 +10,8 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/geometries/concepts/check.hpp> diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp index f2efcb309d..4f3e875eef 100644 --- a/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -19,6 +19,7 @@ #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/range.hpp> @@ -29,8 +30,10 @@ #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/intersects.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/detail/signed_index_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> @@ -40,6 +43,7 @@ #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_simple/failure_policy.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> @@ -54,108 +58,211 @@ namespace detail { namespace is_simple { -template <typename Linestring, bool CheckSelfIntersections = true> -struct is_simple_linestring +template <typename Turn> +inline bool check_segment_indices(Turn const& turn, + signed_index_type last_index) { - static inline bool apply(Linestring const& linestring) + return + (turn.operations[0].seg_id.segment_index == 0 + && turn.operations[1].seg_id.segment_index == last_index) + || + (turn.operations[0].seg_id.segment_index == 0 + && turn.operations[1].seg_id.segment_index == last_index); +} + + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +class is_acceptable_turn + : not_implemented<Geometry> +{}; + +template <typename Linestring> +class is_acceptable_turn<Linestring, linestring_tag> +{ +public: + is_acceptable_turn(Linestring const& linestring) + : m_linestring(linestring) + , m_is_closed(geometry::equals(range::front(linestring), + range::back(linestring))) + {} + + template <typename Turn> + inline bool apply(Turn const& turn) const { - return !detail::is_valid::has_duplicates - < - Linestring, closed - >::apply(linestring) - && !detail::is_valid::has_spikes - < - Linestring, closed - >::apply(linestring) - && !(CheckSelfIntersections && geometry::intersects(linestring)); + BOOST_ASSERT(boost::size(m_linestring) > 1); + return m_is_closed + && turn.method == overlay::method_none + && check_segment_indices(turn, boost::size(m_linestring) - 2) + && turn.operations[0].fraction.is_zero(); } -}; - +private: + Linestring const& m_linestring; + bool const m_is_closed; +}; template <typename MultiLinestring> -class is_simple_multilinestring +class is_acceptable_turn<MultiLinestring, multi_linestring_tag> { private: - class is_acceptable_turn + typedef typename boost::range_value<MultiLinestring>::type linestring_type; + typedef is_acceptable_turn<linestring_type> base_type; + + template <typename Point, typename Linestring> + static inline bool is_boundary_point_of(Point const& point, + Linestring const& linestring) { - 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)) ); - } + 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 Turn, typename Linestring> + static inline bool is_closing_point_of(Turn const& turn, + Linestring const& linestring) + { + BOOST_ASSERT(boost::size(linestring) > 1); + return + turn.method == overlay::method_none + && + check_segment_indices(turn, boost::size(linestring) - 2) + && + geometry::equals(range::front(linestring), range::back(linestring)) + && + turn.operations[0].fraction.is_zero(); + ; + } + + 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 + { + linestring_type const& ls1 = + range::at(m_multilinestring, turn.operations[0].seg_id.multi_index); - template <typename Linestring1, typename Linestring2> - static inline bool have_same_boundary_points(Linestring1 const& ls1, - Linestring2 const& ls2) + linestring_type const& ls2 = + range::at(m_multilinestring, turn.operations[1].seg_id.multi_index); + + if (turn.operations[0].seg_id.multi_index + == turn.operations[1].seg_id.multi_index) { - 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)) - ) - ; + return is_closing_point_of(turn, ls1); } - public: - is_acceptable_turn(MultiLinestring const& multilinestring) - : m_multilinestring(multilinestring) - {} + 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) ); + } - template <typename Turn> - inline bool apply(Turn const& turn) const - { - typedef typename boost::range_value +private: + MultiLinestring const& m_multilinestring; +}; + + +template <typename Linear> +inline bool has_self_intersections(Linear const& linear) +{ + typedef typename point_type<Linear>::type point_type; + + // compute self turns + typedef detail::overlay::turn_info + < + point_type, + geometry::segment_ratio < - 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) ); - } + typename geometry::coordinate_type<point_type>::type + > + > turn_info; - private: - MultiLinestring const& m_multilinestring; - }; + std::deque<turn_info> turns; + typedef detail::overlay::get_turn_info + < + detail::disjoint::assign_disjoint_policy + > turn_policy; -public: - static inline bool apply(MultiLinestring const& multilinestring) + is_acceptable_turn<Linear> predicate(linear); + detail::overlay::predicate_based_interrupt_policy + < + is_acceptable_turn<Linear> + > interrupt_policy(predicate); + + detail::self_get_turn_points::get_turns + < + turn_policy + >::apply(linear, + detail::no_rescale_policy(), + turns, + interrupt_policy); + + detail::is_valid::debug_print_turns(turns.begin(), turns.end()); + debug_print_boundary_points(linear); + + return interrupt_policy.has_intersections; +} + + +template <typename Linestring, bool CheckSelfIntersections = true> +struct is_simple_linestring +{ + static inline bool apply(Linestring const& linestring) { - typedef typename boost::range_value<MultiLinestring>::type linestring; - typedef typename point_type<MultiLinestring>::type point_type; - typedef point_type point; + simplicity_failure_policy policy; + return ! detail::is_valid::has_duplicates + < + Linestring, closed + >::apply(linestring, policy) + && ! detail::is_valid::has_spikes + < + Linestring, closed + >::apply(linestring, policy) + && ! (CheckSelfIntersections && has_self_intersections(linestring)); + } +}; +template <typename MultiLinestring> +struct is_simple_multilinestring +{ + static inline bool apply(MultiLinestring const& multilinestring) + { // check each of the linestrings for simplicity - if ( !detail::check_iterator_range + // but do not compute self-intersections yet; these will be + // computed for the entire multilinestring + if ( ! detail::check_iterator_range < - is_simple_linestring<linestring>, + is_simple_linestring + < + typename boost::range_value<MultiLinestring>::type, + false // do not compute self-intersections + >, false // do not allow empty multilinestring >::apply(boost::begin(multilinestring), boost::end(multilinestring)) @@ -164,44 +271,8 @@ public: 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; + return ! has_self_intersections(multilinestring); } - }; diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp index d996eb64e9..71c9e6ba90 100644 --- a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp +++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -21,6 +21,7 @@ #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> +#include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> @@ -48,7 +49,11 @@ struct is_simple_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); + simplicity_failure_policy policy; + return !detail::is_valid::has_duplicates + < + MultiPoint, closed + >::apply(mp, policy); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp index f82b3f9bf1..139502af78 100644 --- a/boost/geometry/algorithms/detail/is_valid/box.hpp +++ b/boost/geometry/algorithms/detail/is_valid/box.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -16,6 +16,7 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -30,15 +31,22 @@ namespace detail { namespace is_valid template <typename Box, std::size_t I> struct has_valid_corners { - static inline bool apply(Box const& box) + template <typename VisitPolicy> + static inline bool apply(Box const& box, VisitPolicy& visitor) { - if ( geometry::get<geometry::max_corner, I-1>(box) - <= - geometry::get<geometry::min_corner, I-1>(box) ) + if (math::equals(geometry::get<geometry::min_corner, I-1>(box), + geometry::get<geometry::max_corner, I-1>(box))) { - return false; + return + visitor.template apply<failure_wrong_topological_dimension>(); } - return has_valid_corners<Box, I-1>::apply(box); + else if (geometry::get<geometry::min_corner, I-1>(box) + > + geometry::get<geometry::max_corner, I-1>(box)) + { + return visitor.template apply<failure_wrong_corner_order>(); + } + return has_valid_corners<Box, I-1>::apply(box, visitor); } }; @@ -46,9 +54,10 @@ struct has_valid_corners template <typename Box> struct has_valid_corners<Box, 0> { - static inline bool apply(Box const&) + template <typename VisitPolicy> + static inline bool apply(Box const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp index 6824921b63..ab99a9921b 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -25,33 +25,47 @@ namespace detail { namespace is_valid { #ifdef BOOST_GEOMETRY_TEST_DEBUG +template <typename Turn> +inline void debug_print_turn(Turn const& turn) +{ + std::cout << " [" + << geometry::method_char(turn.method) + << "," + << geometry::operation_char(turn.operations[0].operation) + << "/" + << geometry::operation_char(turn.operations[1].operation) + << " {" + << turn.operations[0].seg_id.multi_index + << ", " + << turn.operations[1].seg_id.multi_index + << "} {" + << turn.operations[0].seg_id.ring_index + << ", " + << turn.operations[1].seg_id.ring_index + << "} {" + << turn.operations[0].seg_id.segment_index + << ", " + << turn.operations[1].seg_id.segment_index + << "} " + << geometry::dsv(turn.point) + << "]"; +} + 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) - << "]"; + debug_print_turn(*tit); } std::cout << std::endl << std::endl; } #else +template <typename Turn> +inline void debug_print_turn(Turn const&) +{} + template <typename TurnIterator> inline void debug_print_turns(TurnIterator, TurnIterator) {} diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp index 6f1c263646..a10e0fe596 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp @@ -50,8 +50,8 @@ struct debug_validity_phase<Polygon, polygon_tag> std::cout << "computing and analyzing turns..." << std::endl; break; case 4: - std::cout << "checking if holes are inside the exterior ring..." - << std::endl; + std::cout << "checking if interior rings are inside " + << "the exterior ring..." << std::endl; break; case 5: std::cout << "checking connectivity of interior..." << std::endl; diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp index dd0922bb2b..5878841e70 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -15,8 +15,10 @@ #include <boost/geometry/core/closure.hpp> #include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> namespace boost { namespace geometry @@ -30,7 +32,8 @@ namespace detail { namespace is_valid template <typename Range, closure_selector Closure> struct has_duplicates { - static inline bool apply(Range const& range) + template <typename VisitPolicy> + static inline bool apply(Range const& range, VisitPolicy& visitor) { typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator; @@ -39,7 +42,7 @@ struct has_duplicates if ( boost::size(view) < 2 ) { - return false; + return ! visitor.template apply<no_failure>(); } geometry::equal_to<typename boost::range_value<Range>::type> equal; @@ -50,10 +53,10 @@ struct has_duplicates { if ( equal(*it, *next) ) { - return true; + return ! visitor.template apply<failure_duplicate_points>(*it); } } - return false; + return ! visitor.template apply<no_failure>(); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp index 9b95017482..090c026e8b 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -13,15 +13,22 @@ #include <algorithm> #include <boost/range.hpp> +#include <boost/type_traits/is_same.hpp> #include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> +#include <boost/geometry/io/dsv/write.hpp> namespace boost { namespace geometry @@ -60,7 +67,7 @@ struct not_equal_to template <typename OtherPoint> inline bool operator()(OtherPoint const& other) const { - return !geometry::equals(other, m_point); + return ! geometry::equals(other, m_point); } }; @@ -69,13 +76,17 @@ struct not_equal_to template <typename Range, closure_selector Closure> struct has_spikes { - static inline bool apply(Range const& range) + template <typename VisitPolicy> + static inline bool apply(Range const& range, VisitPolicy& visitor) { 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; + bool const is_linear + = boost::is_same<typename tag<Range>::type, linestring_tag>::value; + view_type const view(range); iterator prev = boost::begin(view); @@ -85,7 +96,7 @@ struct has_spikes { // the range has only one distinct point, so it // cannot have a spike - return false; + return ! visitor.template apply<no_failure>(); } iterator next = std::find_if(cur, boost::end(view), not_equal(*cur)); @@ -93,7 +104,7 @@ struct has_spikes { // the range has only two distinct points, so it // cannot have a spike - return false; + return ! visitor.template apply<no_failure>(); } while ( next != boost::end(view) ) @@ -102,7 +113,8 @@ struct has_spikes *next, *cur) ) { - return true; + return + ! visitor.template apply<failure_spikes>(is_linear, *cur); } prev = cur; cur = next; @@ -120,10 +132,18 @@ struct has_spikes 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); + if (detail::point_is_spike_or_equal(*prev, *next, *cur)) + { + return + ! visitor.template apply<failure_spikes>(is_linear, *cur); + } + else + { + return ! visitor.template apply<no_failure>(); + } } - return false; + return ! visitor.template apply<no_failure>(); } }; 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 index 220a67bcd1..ecbc4782b2 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,6 +10,11 @@ #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 <vector> + +#include <boost/assert.hpp> +#include <boost/range.hpp> + #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> @@ -22,7 +27,6 @@ #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> - namespace boost { namespace geometry { @@ -64,8 +68,10 @@ public: > turn_type; // returns true if all turns are valid - template <typename Turns> - static inline bool apply(Geometry const& geometry, Turns& turns) + template <typename Turns, typename VisitPolicy> + static inline bool apply(Geometry const& geometry, + Turns& turns, + VisitPolicy& visitor) { rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry); @@ -80,7 +86,23 @@ public: turns, interrupt_policy); - return !interrupt_policy.has_intersections; + if (interrupt_policy.has_intersections) + { + BOOST_ASSERT(! boost::empty(turns)); + return visitor.template apply<failure_self_intersections>(turns); + } + else + { + return visitor.template apply<no_failure>(); + } + } + + // returns true if all turns are valid + template <typename VisitPolicy> + static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) + { + std::vector<turn_type> turns; + return apply(geometry, turns, visitor); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp index 4b232fd436..f83b09c437 100644 --- a/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,13 +10,19 @@ #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 <sstream> +#include <string> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> +#include <boost/geometry/policies/is_valid/default_policy.hpp> +#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp> +#include <boost/geometry/policies/is_valid/failure_type_policy.hpp> namespace boost { namespace geometry @@ -28,48 +34,123 @@ namespace resolve_variant { template <typename Geometry> struct is_valid { - static inline bool apply(Geometry const& geometry) + template <typename VisitPolicy> + static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { concept::check<Geometry const>(); - return dispatch::is_valid<Geometry>::apply(geometry); + return dispatch::is_valid<Geometry>::apply(geometry, visitor); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename VisitPolicy> struct visitor : boost::static_visitor<bool> { + visitor(VisitPolicy& policy) : m_policy(policy) {} + template <typename Geometry> bool operator()(Geometry const& geometry) const { - return is_valid<Geometry>::apply(geometry); + return is_valid<Geometry>::apply(geometry, m_policy); } + + VisitPolicy& m_policy; }; + template <typename VisitPolicy> static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + VisitPolicy& policy_visitor) { - return boost::apply_visitor(visitor(), geometry); + return boost::apply_visitor(visitor<VisitPolicy>(policy_visitor), + geometry); } }; } // namespace resolve_variant +// Undocumented for now +template <typename Geometry, typename VisitPolicy> +inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor) +{ + return resolve_variant::is_valid<Geometry>::apply(geometry, visitor); +} + + /*! \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)} +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} \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); + is_valid_default_policy<> policy_visitor; + return is_valid(geometry, policy_visitor); +} + + +/*! +\brief \brief_check{is valid (in the OGC sense)} +\ingroup is_valid +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param failure An enumeration value indicating that the geometry is + valid or not, and if not valid indicating the reason why +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} + +\qbk{distinguish,with failure value} +\qbk{[include reference/algorithms/is_valid_with_failure.qbk]} +*/ +template <typename Geometry> +inline bool is_valid(Geometry const& geometry, validity_failure_type& failure) +{ + failure_type_policy<> policy_visitor; + bool result = is_valid(geometry, policy_visitor); + failure = policy_visitor.failure(); + return result; +} + + +/*! +\brief \brief_check{is valid (in the OGC sense)} +\ingroup is_valid +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param message A string containing a message stating if the geometry + is valid or not, and if not valid a reason why +\return \return_check{is valid (in the OGC sense); + furthermore, the following geometries are considered valid: + multi-geometries with no elements, + linear geometries containing spikes, + areal geometries with duplicate (consecutive) points} + +\qbk{distinguish,with message} +\qbk{[include reference/algorithms/is_valid_with_message.qbk]} +*/ +template <typename Geometry> +inline bool is_valid(Geometry const& geometry, std::string& message) +{ + std::ostringstream stream; + failing_reason_policy<> policy_visitor(stream); + bool result = is_valid(geometry, policy_visitor); + message = stream.str(); + return result; } diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp index f9d926770e..0d80d6f6c0 100644 --- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp +++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -72,6 +72,16 @@ template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_acceptable_turn {}; +template <typename Ring> +struct is_acceptable_turn<Ring, ring_tag> +{ + template <typename Turn> + static inline bool apply(Turn const&) + { + return false; + } +}; + template <typename Polygon> class is_acceptable_turn<Polygon, polygon_tag> { diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp index 244df9b035..69243563ec 100644 --- a/boost/geometry/algorithms/detail/is_valid/linear.hpp +++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -21,6 +21,7 @@ #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/validity_failure_type.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> @@ -36,11 +37,18 @@ namespace detail { namespace is_valid { -template <typename Linestring, bool AllowSpikes> +template <typename Linestring> struct is_valid_linestring { - static inline bool apply(Linestring const& linestring) + template <typename VisitPolicy> + static inline bool apply(Linestring const& linestring, + VisitPolicy& visitor) { + if (boost::size(linestring) < 2) + { + return visitor.template apply<failure_few_points>(); + } + std::size_t num_distinct = detail::num_distinct_consecutive_points < Linestring, @@ -49,14 +57,17 @@ struct is_valid_linestring not_equal_to<typename point_type<Linestring>::type> >::apply(linestring); - if ( num_distinct < 2u ) + if (num_distinct < 2u) { - return false; + return + visitor.template apply<failure_wrong_topological_dimension>(); } - return num_distinct == 2u - || AllowSpikes - || !has_spikes<Linestring, closed>::apply(linestring); + if (num_distinct == 2u) + { + return visitor.template apply<no_failure>(); + } + return ! has_spikes<Linestring, closed>::apply(linestring, visitor); } }; @@ -84,9 +95,11 @@ namespace dispatch // 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> +template <typename Linestring, bool AllowEmptyMultiGeometries> +struct is_valid + < + Linestring, linestring_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_linestring<Linestring> {}; @@ -96,21 +109,47 @@ struct is_valid<Linestring, linestring_tag, AllowSpikes> // 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> +template <typename MultiLinestring, bool AllowEmptyMultiGeometries> +class is_valid + < + MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries + > { - static inline bool apply(MultiLinestring const& multilinestring) +private: + template <typename VisitPolicy> + struct per_linestring + { + per_linestring(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Linestring> + inline bool apply(Linestring const& linestring) const + { + return detail::is_valid::is_valid_linestring + < + Linestring + >::apply(linestring, m_policy); + } + + VisitPolicy& m_policy; + }; + +public: + template <typename VisitPolicy> + static inline bool apply(MultiLinestring const& multilinestring, + VisitPolicy& visitor) { + if (AllowEmptyMultiGeometries && boost::empty(multilinestring)) + { + return visitor.template apply<no_failure>(); + } + return detail::check_iterator_range < - detail::is_valid::is_valid_linestring - < - typename boost::range_value<MultiLinestring>::type, - AllowSpikes - >, - false // do not allow empty multilinestring + per_linestring<VisitPolicy>, + false // do not check for empty multilinestring (done above) >::apply(boost::begin(multilinestring), - boost::end(multilinestring)); + boost::end(multilinestring), + per_linestring<VisitPolicy>(visitor)); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp index 3d0ebb5f82..9362bfca0e 100644 --- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -25,6 +25,7 @@ #include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> @@ -49,12 +50,11 @@ namespace detail { namespace is_valid { -template <typename MultiPolygon, bool AllowDuplicates> +template <typename MultiPolygon, bool AllowEmptyMultiGeometries> class is_valid_multipolygon : is_valid_polygon < typename boost::range_value<MultiPolygon>::type, - AllowDuplicates, true // check only the validity of rings > { @@ -62,18 +62,23 @@ private: typedef is_valid_polygon < typename boost::range_value<MultiPolygon>::type, - AllowDuplicates, true > base; - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool are_polygon_interiors_disjoint(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { // collect all polygons that have turns std::set<signed_index_type> multi_indices; @@ -89,22 +94,29 @@ private: for (PolygonIterator it = polygons_first; it != polygons_beyond; ++it, ++multi_index) { - if ( multi_indices.find(multi_index) == multi_indices.end() ) + if (multi_indices.find(multi_index) == multi_indices.end()) { polygon_iterators.push_back(it); } } - typename base::item_visitor visitor; + typename base::item_visitor_type item_visitor; geometry::partition < geometry::model::box<typename point_type<MultiPolygon>::type>, typename base::expand_box, typename base::overlaps_box - >::apply(polygon_iterators, visitor); + >::apply(polygon_iterators, item_visitor); - return !visitor.items_overlap; + if (item_visitor.items_overlap) + { + return visitor.template apply<failure_intersecting_interiors>(); + } + else + { + return visitor.template apply<no_failure>(); + } } @@ -132,11 +144,17 @@ private: template <typename Predicate> struct has_property_per_polygon { - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool apply(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { signed_index_type multi_index = 0; for (PolygonIterator it = polygons_first; it != polygons_beyond; @@ -157,9 +175,10 @@ private: turns_beyond, turns_beyond); - if ( !Predicate::apply(*it, + if (! Predicate::apply(*it, filtered_turns_first, - filtered_turns_beyond) ) + filtered_turns_beyond, + visitor)) { return false; } @@ -170,49 +189,82 @@ private: - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool have_holes_inside(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { return has_property_per_polygon < typename base::has_holes_inside >::apply(polygons_first, polygons_beyond, - turns_first, turns_beyond); + turns_first, turns_beyond, visitor); } - template <typename PolygonIterator, typename TurnIterator> + template + < + typename PolygonIterator, + typename TurnIterator, + typename VisitPolicy + > static inline bool have_connected_interior(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { return has_property_per_polygon < typename base::has_connected_interior >::apply(polygons_first, polygons_beyond, - turns_first, turns_beyond); + turns_first, turns_beyond, visitor); } + template <typename VisitPolicy> + struct per_polygon + { + per_polygon(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Polygon> + inline bool apply(Polygon const& polygon) const + { + return base::apply(polygon, m_policy); + } + + VisitPolicy& m_policy; + }; public: - static inline bool apply(MultiPolygon const& multipolygon) + template <typename VisitPolicy> + static inline bool apply(MultiPolygon const& multipolygon, + VisitPolicy& visitor) { typedef debug_validity_phase<MultiPolygon> debug_phase; + if (AllowEmptyMultiGeometries && boost::empty(multipolygon)) + { + return visitor.template apply<no_failure>(); + } + // check validity of all polygons ring debug_phase::apply(1); - if ( !detail::check_iterator_range + if (! detail::check_iterator_range < - base, - false // do not allow empty multi-polygons + per_polygon<VisitPolicy>, + false // do not check for empty multipolygon (done above) >::apply(boost::begin(multipolygon), - boost::end(multipolygon)) ) + boost::end(multipolygon), + per_polygon<VisitPolicy>(visitor))) { return false; } @@ -224,10 +276,11 @@ public: 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); + bool has_invalid_turns = + ! has_valid_turns::apply(multipolygon, turns, visitor); debug_print_turns(turns.begin(), turns.end()); - if ( has_invalid_turns ) + if (has_invalid_turns) { return false; } @@ -237,10 +290,11 @@ public: // exterior and not one inside the other debug_phase::apply(3); - if ( !have_holes_inside(boost::begin(multipolygon), + if (! have_holes_inside(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()) ) + turns.end(), + visitor)) { return false; } @@ -249,10 +303,11 @@ public: // check that each polygon's interior is connected debug_phase::apply(4); - if ( !have_connected_interior(boost::begin(multipolygon), + if (! have_connected_interior(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()) ) + turns.end(), + visitor)) { return false; } @@ -263,7 +318,8 @@ public: return are_polygon_interiors_disjoint(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), - turns.end()); + turns.end(), + visitor); } }; @@ -282,9 +338,14 @@ namespace dispatch // 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> +template <typename MultiPolygon, bool AllowEmptyMultiGeometries> +struct is_valid + < + MultiPolygon, multi_polygon_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_multipolygon + < + MultiPolygon, AllowEmptyMultiGeometries + > {}; diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp index 8a4818ef15..8e5ebaadcc 100644 --- a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp +++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -14,6 +14,7 @@ #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -30,9 +31,10 @@ namespace dispatch template <typename Point> struct is_valid<Point, point_tag> { - static inline bool apply(Point const&) + template <typename VisitPolicy> + static inline bool apply(Point const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; @@ -42,12 +44,24 @@ struct is_valid<Point, point_tag> // (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> +template <typename MultiPoint, bool AllowEmptyMultiGeometries> +struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries> { - static inline bool apply(MultiPoint const& multipoint) + template <typename VisitPolicy> + static inline bool apply(MultiPoint const& multipoint, + VisitPolicy& visitor) { - return boost::size(multipoint) > 0; + if (AllowEmptyMultiGeometries || boost::size(multipoint) > 0) + { + // we allow empty multi-geometries, so an empty multipoint + // is considered valid + return visitor.template apply<no_failure>(); + } + else + { + // we do not allow an empty multipoint + return visitor.template apply<failure_few_points>(); + } } }; diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp index 3a91999208..17eefd226f 100644 --- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -26,6 +26,7 @@ #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/geometries/box.hpp> @@ -36,6 +37,7 @@ #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> @@ -62,51 +64,58 @@ namespace detail { namespace is_valid { -template -< - typename Polygon, - bool AllowDuplicates, - bool CheckRingValidityOnly = false -> +template <typename Polygon, bool CheckRingValidityOnly = false> class is_valid_polygon { protected: typedef debug_validity_phase<Polygon> debug_phase; + template <typename VisitPolicy> + struct per_ring + { + per_ring(VisitPolicy& policy) : m_policy(policy) {} + + template <typename Ring> + inline bool apply(Ring const& ring) const + { + return detail::is_valid::is_valid_ring + < + Ring, false, true + >::apply(ring, m_policy); + } + VisitPolicy& m_policy; + }; - template <typename InteriorRings> - static bool has_valid_interior_rings(InteriorRings const& interior_rings) + template <typename InteriorRings, typename VisitPolicy> + static bool has_valid_interior_rings(InteriorRings const& interior_rings, + VisitPolicy& visitor) { 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 - > + per_ring<VisitPolicy>, + true // allow for empty interior ring range >::apply(boost::begin(interior_rings), - boost::end(interior_rings)); + boost::end(interior_rings), + per_ring<VisitPolicy>(visitor)); } struct has_valid_rings { - static inline bool apply(Polygon const& polygon) + template <typename VisitPolicy> + static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) { typedef typename ring_type<Polygon>::type ring_type; // check validity of exterior ring debug_phase::apply(1); - if ( !detail::is_valid::is_valid_ring + if (! detail::is_valid::is_valid_ring < ring_type, - AllowDuplicates, false // do not check self intersections - >::apply(exterior_ring(polygon)) ) + >::apply(exterior_ring(polygon), visitor)) { return false; } @@ -114,12 +123,13 @@ protected: // check validity of interior rings debug_phase::apply(2); - return has_valid_interior_rings(geometry::interior_rings(polygon)); + return has_valid_interior_rings(geometry::interior_rings(polygon), + visitor); } }; - // structs from partition -- start + // structs for partition -- start struct expand_box { template <typename Box, typename Iterator> @@ -135,24 +145,24 @@ protected: template <typename Box, typename Iterator> static inline bool apply(Box const& box, Iterator const& it) { - return !geometry::disjoint(*it, box); + return ! geometry::disjoint(*it, box); } }; - struct item_visitor + struct item_visitor_type { bool items_overlap; - item_visitor() : items_overlap(false) {} + item_visitor_type() : 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)) - ) + if (! items_overlap + && (geometry::within(*points_begin(*item1), *item2) + || geometry::within(*points_begin(*item2), *item1)) + ) { items_overlap = true; } @@ -165,27 +175,29 @@ protected: < typename RingIterator, typename ExteriorRing, - typename TurnIterator + typename TurnIterator, + typename VisitPolicy > static inline bool are_holes_inside(RingIterator rings_first, RingIterator rings_beyond, ExteriorRing const& exterior_ring, TurnIterator turns_first, - TurnIterator turns_beyond) + TurnIterator turns_beyond, + VisitPolicy& visitor) { // 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 ) + if (tit->operations[0].seg_id.ring_index == -1) { - BOOST_ASSERT( tit->operations[1].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 ) + else if (tit->operations[1].seg_id.ring_index == -1) { - BOOST_ASSERT( tit->operations[0].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); } } @@ -196,10 +208,10 @@ protected: { // 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) ) + if (ring_indices.find(ring_index) == ring_indices.end() + && ! geometry::covered_by(range::front(*it), exterior_ring)) { - return false; + return visitor.template apply<failure_interior_rings_outside>(); } } @@ -216,7 +228,7 @@ protected: for (RingIterator it = rings_first; it != rings_beyond; ++it, ++ring_index) { - if ( ring_indices.find(ring_index) == ring_indices.end() ) + if (ring_indices.find(ring_index) == ring_indices.end()) { ring_iterators.push_back(it); } @@ -224,47 +236,59 @@ protected: // call partition to check is interior rings are disjoint from // each other - item_visitor visitor; + item_visitor_type item_visitor; geometry::partition < geometry::model::box<typename point_type<Polygon>::type>, expand_box, overlaps_box - >::apply(ring_iterators, visitor); + >::apply(ring_iterators, item_visitor); - return !visitor.items_overlap; + if (item_visitor.items_overlap) + { + return visitor.template apply<failure_nested_interior_rings>(); + } + else + { + return visitor.template apply<no_failure>(); + } } template < typename InteriorRings, typename ExteriorRing, - typename TurnIterator + typename TurnIterator, + typename VisitPolicy > static inline bool are_holes_inside(InteriorRings const& interior_rings, ExteriorRing const& exterior_ring, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { return are_holes_inside(boost::begin(interior_rings), boost::end(interior_rings), exterior_ring, first, - beyond); + beyond, + visitor); } struct has_holes_inside { - template <typename TurnIterator> + template <typename TurnIterator, typename VisitPolicy> static inline bool apply(Polygon const& polygon, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { return are_holes_inside(geometry::interior_rings(polygon), geometry::exterior_ring(polygon), first, - beyond); + beyond, + visitor); } }; @@ -273,10 +297,11 @@ protected: struct has_connected_interior { - template <typename TurnIterator> + template <typename TurnIterator, typename VisitPolicy> static inline bool apply(Polygon const& polygon, TurnIterator first, - TurnIterator beyond) + TurnIterator beyond, + VisitPolicy& visitor) { typedef typename std::iterator_traits < @@ -299,19 +324,27 @@ protected: debug_print_complement_graph(std::cout, g); - return !g.has_cycles(); + if (g.has_cycles()) + { + return visitor.template apply<failure_disconnected_interior>(); + } + else + { + return visitor.template apply<no_failure>(); + } } }; public: - static inline bool apply(Polygon const& polygon) + template <typename VisitPolicy> + static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) { - if ( !has_valid_rings::apply(polygon) ) + if (! has_valid_rings::apply(polygon, visitor)) { return false; } - if ( CheckRingValidityOnly ) + if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly)) { return true; } @@ -322,10 +355,11 @@ public: 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); + bool has_invalid_turns + = ! has_valid_turns::apply(polygon, turns, visitor); debug_print_turns(turns.begin(), turns.end()); - if ( has_invalid_turns ) + if (has_invalid_turns) { return false; } @@ -333,7 +367,9 @@ public: // check if all interior rings are inside the exterior ring debug_phase::apply(4); - if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) ) + if (! has_holes_inside::apply(polygon, + turns.begin(), turns.end(), + visitor)) { return false; } @@ -343,7 +379,8 @@ public: return has_connected_interior::apply(polygon, turns.begin(), - turns.end()); + turns.end(), + visitor); } }; @@ -361,9 +398,11 @@ 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> +template <typename Polygon, bool AllowEmptyMultiGeometries> +struct is_valid + < + Polygon, polygon_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_polygon<Polygon> {}; diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp index c88df79b05..c663a96d28 100644 --- a/boost/geometry/algorithms/detail/is_valid/ring.hpp +++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -10,6 +10,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP +#include <deque> + #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> @@ -19,16 +21,22 @@ #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/validity_failure_type.hpp> +#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> +#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> #include <boost/geometry/strategies/area.hpp> +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include <boost/geometry/io/dsv/write.hpp> +#endif + namespace boost { namespace geometry { @@ -42,18 +50,27 @@ namespace detail { namespace is_valid template <typename Ring, closure_selector Closure /* open */> struct is_topologically_closed { - static inline bool apply(Ring const&) + template <typename VisitPolicy> + static inline bool apply(Ring const&, VisitPolicy& visitor) { - return true; + return visitor.template apply<no_failure>(); } }; template <typename Ring> struct is_topologically_closed<Ring, closed> { - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { - return geometry::equals(range::front(ring), range::back(ring)); + if (geometry::equals(range::front(ring), range::back(ring))) + { + return visitor.template apply<no_failure>(); + } + else + { + return visitor.template apply<failure_not_closed>(); + } } }; @@ -92,7 +109,8 @@ struct is_properly_oriented typedef typename default_area_result<Ring>::type area_result_type; - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { typename ring_area_predicate < @@ -101,7 +119,14 @@ struct is_properly_oriented // Check area area_result_type const zero = area_result_type(); - return predicate(ring_area_type::apply(ring, strategy_type()), zero); + if (predicate(ring_area_type::apply(ring, strategy_type()), zero)) + { + return visitor.template apply<no_failure>(); + } + else + { + return visitor.template apply<failure_wrong_orientation>(); + } } }; @@ -110,41 +135,60 @@ struct is_properly_oriented template < typename Ring, - bool AllowDuplicates, bool CheckSelfIntersections = true, bool IsInteriorRing = false > struct is_valid_ring { - static inline bool apply(Ring const& ring) + template <typename VisitPolicy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor) { // 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 + // (b) the ring consists of at most two distinct points + // (c) the ring is not topologically closed + // (d) the ring has spikes + // (e) the ring has duplicate points (if AllowDuplicates is false) + // (f) the boundary of the ring has self-intersections + // (g) 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; + typedef typename closeable_view<Ring const, closure>::type view_type; + + if (boost::size(ring) + < core_detail::closure::minimum_ring_size<closure>::value) + { + return visitor.template apply<failure_few_points>(); + } + + view_type const view(ring); + if (detail::num_distinct_consecutive_points + < + view_type, 4u, true, + not_equal_to<typename point_type<Ring>::type> + >::apply(view) + < 4u) + { + return + visitor.template apply<failure_wrong_topological_dimension>(); + } 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); + is_topologically_closed<Ring, closure>::apply(ring, visitor) + && ! has_duplicates<Ring, closure>::apply(ring, visitor) + && ! has_spikes<Ring, closure>::apply(ring, visitor) + && (! CheckSelfIntersections + || has_valid_self_turns<Ring>::apply(ring, visitor)) + && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor); } }; -}} // namespace dispatch +}} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL @@ -158,9 +202,11 @@ namespace dispatch // 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> +template <typename Ring, bool AllowEmptyMultiGeometries> +struct is_valid + < + Ring, ring_tag, AllowEmptyMultiGeometries + > : detail::is_valid::is_valid_ring<Ring> {}; diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp index 486289dabe..0b60890dc0 100644 --- a/boost/geometry/algorithms/detail/is_valid/segment.hpp +++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -15,6 +15,7 @@ #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> @@ -40,13 +41,22 @@ namespace dispatch template <typename Segment> struct is_valid<Segment, segment_tag> { - static inline bool apply(Segment const& segment) + template <typename VisitPolicy> + static inline bool apply(Segment const& segment, VisitPolicy& visitor) { 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]); + if(! geometry::equals(p[0], p[1])) + { + return visitor.template apply<no_failure>(); + } + else + { + return + visitor.template apply<failure_wrong_topological_dimension>(); + } } }; diff --git a/boost/geometry/algorithms/detail/not.hpp b/boost/geometry/algorithms/detail/not.hpp index abc3a4e168..43e71e2e37 100644 --- a/boost/geometry/algorithms/detail/not.hpp +++ b/boost/geometry/algorithms/detail/not.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -32,10 +37,12 @@ namespace detail \param geometry2 \param_geometry \return Negation of the result of the policy */ -template <typename Geometry1, typename Geometry2, typename Policy> +template <typename Policy> struct not_ { - static inline bool apply(Geometry1 const &geometry1, Geometry2 const& geometry2) + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2) { return ! Policy::apply(geometry1, geometry2); } diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp index d90f3cf7cf..002c946170 100644 --- a/boost/geometry/algorithms/detail/occupation_info.hpp +++ b/boost/geometry/algorithms/detail/occupation_info.hpp @@ -57,6 +57,12 @@ class occupation_info public : typedef std::vector<AngleInfo> collection_type; + int count; + + inline occupation_info() + : count(0) + {} + template <typename RobustPoint> inline void add(RobustPoint const& incoming_point, RobustPoint const& outgoing_point, 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 index d44db17ad3..285edfdd6c 100644 --- a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -20,6 +20,7 @@ #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> @@ -42,7 +43,7 @@ inline bool points_equal_or_close(Point1 const& point1, return true; } - if (! RobustPolicy::enabled) + if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled)) { return false; } @@ -127,7 +128,7 @@ inline void clean_closing_dups_and_spikes(Range& range, iterator_type first = boost::begin(range); iterator_type second = first + 1; iterator_type ultimate = boost::end(range) - 1; - if (closed) + if (BOOST_GEOMETRY_CONDITION(closed)) { ultimate--; } @@ -137,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range, if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) { range::erase(range, first); - if (closed) + if (BOOST_GEOMETRY_CONDITION(closed)) { // Remove closing last point range::resize(range, boost::size(range) - 1); diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 67b48cc471..178f3825d7 100644 --- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -18,11 +18,6 @@ #include <boost/geometry/geometries/box.hpp> -#ifdef BOOST_GEOMETRY_TIME_OVERLAY -# include <boost/timer.hpp> -#endif - - namespace boost { namespace geometry { @@ -186,11 +181,6 @@ inline void assign_parents(Geometry1 const& geometry1, typedef std::vector<helper> vector_type; typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type; -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - boost::timer timer; -#endif - - std::size_t count_total = ring_map.size(); std::size_t count_positive = 0; std::size_t index_positive = 0; // only used if count_positive>0 @@ -226,10 +216,6 @@ inline void assign_parents(Geometry1 const& geometry1, } } -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << " ap: created helper vector: " << timer.elapsed() << std::endl; -#endif - if (! check_for_orientation) { if (count_positive == count_total) @@ -272,11 +258,6 @@ inline void assign_parents(Geometry1 const& geometry1, < box_type, ring_info_helper_get_box, ring_info_helper_ovelaps_box >::apply(vector, visitor); - -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << " ap: quadradic loop: " << timer.elapsed() << std::endl; - std::cout << " ap: check_for_orientation " << check_for_orientation << std::endl; -#endif } if (check_for_orientation) diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp index 20a6d7f48d..13e0a5a51e 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp @@ -11,6 +11,7 @@ #include <boost/array.hpp> +#include <boost/assert.hpp> #include <boost/mpl/assert.hpp> #include <boost/range.hpp> @@ -21,8 +22,7 @@ #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> +#include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry @@ -37,41 +37,24 @@ namespace detail { namespace copy_segments template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point_range { - typedef typename closeable_view - < - Range const, - closure<Range>::value - >::type cview_type; - - typedef typename reversible_view - < - cview_type const, - Reverse ? iterate_reverse : iterate_forward - >::type rview_type; - static inline bool apply(Range const& range, SegmentIdentifier const& seg_id, bool second, PointOut& point) { + detail::normalized_view<Range const> view(range); + + signed_index_type const n = boost::size(view); signed_index_type index = seg_id.segment_index; if (second) { index++; - if (index >= int(boost::size(range))) + if (index >= n) { index = 0; } } - // Exception? - if (index >= int(boost::size(range))) - { - return false; - } - - cview_type cview(range); - rview_type view(cview); - + BOOST_ASSERT(index >= 0 && index < n); geometry::convert(*(boost::begin(view) + index), point); return true; @@ -323,6 +306,8 @@ inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geom concept::check<Geometry1 const>(); concept::check<Geometry2 const>(); + BOOST_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1); + if (seg_id.source_index == 0) { return dispatch::copy_segment_point diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 9484479b45..7ed93f542a 100644 --- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -56,13 +56,13 @@ struct indexed_turn_operation TurnOperation const* subject; inline indexed_turn_operation(std::size_t ti, std::size_t oi, - TurnOperation const& s, + TurnOperation const& sub, segment_identifier const& oid) : turn_index(ti) , operation_index(oi) , discarded(false) , other_seg_id(&oid) - , subject(&s) + , subject(boost::addressof(sub)) {} }; @@ -114,6 +114,12 @@ private : typedef typename geometry::point_type<Geometry1>::type point_type; + inline bool default_order(Indexed const& left, Indexed const& right) const + { + // We've nothing to sort on. Take the indexes + return left.turn_index < right.turn_index; + } + inline bool consider_relative_order(Indexed const& left, Indexed const& right) const { @@ -148,7 +154,12 @@ private : // 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; + if (side_rj_s != side_sj_r) + { + return side_rj_s < side_sj_r; + } + + return default_order(left, right); } public : @@ -157,30 +168,32 @@ 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; + if (! (left.subject->seg_id == right.subject->seg_id)) + { + return left.subject->seg_id < right.subject->seg_id; + } + + // Both left and right are located on the SAME segment. - if (sl == sr) + if (! (left.subject->fraction == right.subject->fraction)) { - // Both left and right are located on the SAME segment. - if (left.subject->fraction == right.subject->fraction) - { - // 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.subject->fraction < right.subject->fraction; + } - // 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 sl == sr - ? left.subject->fraction < right.subject->fraction - : sl < sr; + + // If that is not the case, cluster it later on. + // Indicate that this is necessary. + *m_clustered = true; + + return default_order(left, right); } }; diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index 85378e08b0..7bcc0b951e 100644 --- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -35,6 +35,23 @@ namespace boost { namespace geometry { +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) +class inconsistent_turns_exception : public geometry::exception +{ +public: + + inline inconsistent_turns_exception() {} + + virtual ~inconsistent_turns_exception() throw() + {} + + virtual char const* what() const throw() + { + return "Boost.Geometry Inconsistent Turns exception"; + } +}; +#endif + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay @@ -304,7 +321,14 @@ public: oit); } - BOOST_ASSERT( enter_count == 0 ); +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) + if (enter_count != 0) + { + throw inconsistent_turns_exception(); + } +#else + BOOST_ASSERT(enter_count == 0); +#endif return process_end(entered, linestring, current_segment_id, current_piece, diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index 240b6de036..b3b1a06f68 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015 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,6 +16,8 @@ #include <boost/assert.hpp> +#include <boost/core/ignore_unused.hpp> + #include <boost/geometry/core/access.hpp> #include <boost/geometry/strategies/intersection.hpp> @@ -104,17 +111,19 @@ struct base_turn_handler template <typename TurnInfo, typename IntersectionInfo> static inline void assign_point(TurnInfo& ti, method_type method, - IntersectionInfo const& info, int index) + IntersectionInfo const& info, unsigned int index) { ti.method = method; - BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this + + BOOST_ASSERT(index < info.count); + 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) + static inline unsigned int non_opposite_to_index(IntersectionInfo const& info) { return info.fractions[0].robust_rb < info.fractions[1].robust_rb ? 1 : 0; @@ -132,7 +141,7 @@ struct touch_interior : public base_turn_handler // Index: 0, P is the interior, Q is touching and vice versa template < - int Index, + unsigned int Index, typename Point1, typename Point2, typename IntersectionInfo, @@ -155,8 +164,9 @@ struct touch_interior : public base_turn_handler // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i - static int const index_p = Index; - static int const index_q = 1 - Index; + BOOST_STATIC_ASSERT(Index <= 1); + static unsigned int const index_p = Index; + static unsigned int const index_q = 1 - Index; int const side_qi_p = dir_info.sides.template get<index_q, 0>(); int const side_qk_p = side.qk_wrt_p1(); @@ -166,7 +176,7 @@ struct touch_interior : public base_turn_handler // Q crosses P from left->right or from right->left (test "ML1") // Union: folow P (left->right) or Q (right->left) // Intersection: other turn - int index = side_qk_p == -1 ? index_p : index_q; + unsigned int index = side_qk_p == -1 ? index_p : index_q; ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; return; @@ -193,7 +203,7 @@ struct touch_interior : public base_turn_handler // or Q turns right on the right side of P (test "MR2") // Union: take left turn (Q if Q turns left, P if Q turns right) // Intersection: other turn - int index = side_qk_q == 1 ? index_q : index_p; + unsigned int index = side_qk_q == 1 ? index_q : index_p; ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; } @@ -215,10 +225,10 @@ struct touch_interior : public base_turn_handler // Opposite direction, which is never travelled. // If Q turns left, P continues for intersection // If Q turns right, P continues for union - ti.operations[Index].operation = side_qk_q == 1 + ti.operations[index_p].operation = side_qk_q == 1 ? operation_intersection : operation_union; - ti.operations[1 - Index].operation = operation_blocked; + ti.operations[index_q].operation = operation_blocked; } } else @@ -503,27 +513,25 @@ struct equal_opposite : public base_turn_handler typename Point1, typename Point2, typename OutputIterator, - typename IntersectionInfo, - typename DirInfo + typename IntersectionInfo > static inline void apply(Point1 const& pi, Point2 const& qi, /* by value: */ TurnInfo tp, OutputIterator& out, - IntersectionInfo const& intersection_info, - DirInfo const& dir_info) + IntersectionInfo const& intersection_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++) + for (unsigned int i = 0; i < 2; i++) { tp.operations[i].operation = operation_opposite; } - for (unsigned int i = 0; i < intersection_info.count; i++) + for (unsigned int i = 0; i < intersection_info.i_info().count; i++) { - assign_point(tp, method_none, intersection_info, i); - AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + assign_point(tp, method_none, intersection_info.i_info(), i); + AssignPolicy::apply(tp, pi, qi, intersection_info); *out++ = tp; } } @@ -653,7 +661,7 @@ private : template < - int Index, + unsigned int Index, typename Point1, typename Point2, typename IntersectionInfo @@ -663,8 +671,9 @@ private : Point2 const& , Point2 const& , int side_rk_s, TurnInfo& tp, IntersectionInfo const& intersection_info) { - boost::ignore_unused_variable_warning(handle_robustness); - boost::ignore_unused_variable_warning(side_rk_s); + BOOST_STATIC_ASSERT(Index <= 1); + + boost::ignore_unused(handle_robustness, side_rk_s); operation_type blocked = operation_blocked; switch(side_rk_r) @@ -715,7 +724,6 @@ public: typename Point2, typename OutputIterator, typename IntersectionInfo, - typename DirInfo, typename SidePolicy > static inline void apply( @@ -727,10 +735,9 @@ public: OutputIterator& out, IntersectionInfo const& intersection_info, - DirInfo const& dir_info, SidePolicy const& side) { - apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer); + apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer); } public: @@ -740,7 +747,6 @@ public: typename Point2, typename OutputIterator, typename IntersectionInfo, - typename DirInfo, typename SidePolicy, typename TurnTransformer > @@ -752,50 +758,52 @@ public: TurnInfo const& tp_model, OutputIterator& out, - IntersectionInfo const& intersection_info, - DirInfo const& dir_info, + IntersectionInfo const& info, SidePolicy const& side, TurnTransformer turn_transformer, bool const is_pk_valid = true, bool const is_qk_valid = true) { TurnInfo tp = tp_model; + int const p_arrival = info.d_info().arrival[0]; + int const q_arrival = info.d_info().arrival[1]; + // If P arrives within Q, there is a turn dependent on P - if ( dir_info.arrival[0] == 1 + if ( p_arrival == 1 && is_pk_valid - && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) ) + && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) ) { turn_transformer(tp); - AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + AssignPolicy::apply(tp, pi, qi, info); *out++ = tp; } // If Q arrives within P, there is a turn dependent on Q - if ( dir_info.arrival[1] == 1 + if ( q_arrival == 1 && is_qk_valid - && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) ) + && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) ) { turn_transformer(tp); - AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + AssignPolicy::apply(tp, pi, qi, 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)) + if ((q_arrival == -1 && p_arrival == 0) + || (p_arrival == -1 && q_arrival == 0)) { - for (int i = 0; i < 2; i++) + for (unsigned int i = 0; i < 2; i++) { tp.operations[i].operation = operation_opposite; } - for (unsigned int i = 0; i < intersection_info.count; i++) + for (unsigned int i = 0; i < info.i_info().count; i++) { - assign_point(tp, method_collinear, intersection_info, i); - AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); + assign_point(tp, method_collinear, info.i_info(), i); + AssignPolicy::apply(tp, pi, qi, info); *out++ = tp; } } @@ -833,7 +841,7 @@ struct crosses : public base_turn_handler // Intersection: take Q // Otherwise: vice versa int const side_qi_p1 = dir_info.sides.template get<1, 0>(); - int const index = side_qi_p1 == 1 ? 0 : 1; + unsigned int const index = side_qi_p1 == 1 ? 0 : 1; ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; } @@ -867,10 +875,9 @@ struct assign_null_policy typename Info, typename Point1, typename Point2, - typename IntersectionInfo, - typename DirInfo + typename IntersectionInfo > - static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&) + static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&) {} }; @@ -933,7 +940,7 @@ struct get_turn_info && inters.i_info().count > 0) { only_convert::apply(tp, inters.i_info()); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -968,7 +975,7 @@ struct get_turn_info tp, inters.i_info(), inters.d_info(), swapped_side_calc); } - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -976,7 +983,7 @@ struct get_turn_info { 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()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -985,7 +992,7 @@ struct get_turn_info // Both touch (both arrive there) 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()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -997,7 +1004,7 @@ struct get_turn_info // 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()); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } else @@ -1007,7 +1014,7 @@ struct get_turn_info TurnInfo, AssignPolicy >::apply(pi, qi, - tp, out, inters.i_info(), inters.d_info()); + tp, out, inters); } } break; @@ -1032,7 +1039,7 @@ struct get_turn_info tp, inters.i_info(), inters.d_info(), inters.sides()); } - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } else @@ -1042,7 +1049,7 @@ struct get_turn_info TurnInfo, AssignPolicy >::apply(pi, pj, pk, qi, qj, qk, - tp, out, inters.i_info(), inters.d_info(), inters.sides()); + tp, out, inters, inters.sides()); } } break; @@ -1052,7 +1059,7 @@ struct get_turn_info if (AssignPolicy::include_degenerate) { only_convert::apply(tp, inters.i_info()); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } 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 index ca1b9d9d0c..4a3cacbedd 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp @@ -290,7 +290,7 @@ struct get_turn_info_for_endpoint linear_intersections::ip_info const& ip_info, TurnInfo const& tp_model, IntersectionInfo const& inters, - int ip_index, + unsigned int ip_index, OutputIterator out) { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR @@ -396,7 +396,7 @@ struct get_turn_info_for_endpoint 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, + IntersectionInfo const& inters, unsigned int ip_index, operation_type & op1, operation_type & op2) { boost::ignore_unused_variable_warning(i2); @@ -535,7 +535,7 @@ struct get_turn_info_for_endpoint typename OutputIterator> static inline void assign(Point1 const& pi, Point2 const& qi, IntersectionResult const& result, - int ip_index, + unsigned int ip_index, method_type method, operation_type op0, operation_type op1, turn_position pos0, turn_position pos1, @@ -585,7 +585,9 @@ struct get_turn_info_for_endpoint } } - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + // TODO: this should get an intersection_info, which is unavailable here + // Because the assign_null policy accepts any structure, we pass the result instead for now + AssignPolicy::apply(tp, pi, qi, result); *out++ = tp; } diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp index eead0d719b..e0d75108b9 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -2,8 +2,8 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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 diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp index 873567bbf5..71946543ee 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -2,18 +2,20 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// 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/util/condition.hpp> + #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> @@ -28,6 +30,8 @@ namespace detail { namespace overlay { template<typename AssignPolicy> struct get_turn_info_linear_areal { + // Currently only Linear spikes are handled + // Areal spikes are ignored static const bool handle_spikes = true; template @@ -122,7 +126,7 @@ struct get_turn_info_linear_areal calculate_spike_operation(tp.operations[0].operation, inters, is_p_last); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } @@ -135,7 +139,7 @@ struct get_turn_info_linear_areal replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -220,9 +224,9 @@ struct get_turn_info_linear_areal 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()); + AssignPolicy::apply(tp, pi, qi, inters); - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ignore_spike || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i??? tp, inters, is_p_last, is_q_last, out) ) @@ -256,10 +260,10 @@ struct get_turn_info_linear_areal 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()); + AssignPolicy::apply(tp, pi, qi, inters); // conditionally handle spikes - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, method_touch, append_equal, out) ) { @@ -273,7 +277,7 @@ struct get_turn_info_linear_areal TurnInfo, AssignPolicy >::apply(pi, qi, - tp, out, inters.i_info(), inters.d_info()); + tp, out, inters); } } } @@ -319,10 +323,10 @@ struct get_turn_info_linear_areal 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()); + AssignPolicy::apply(tp, pi, qi, inters); // conditionally handle spikes - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, method_replace, version, out) ) { @@ -336,7 +340,7 @@ struct get_turn_info_linear_areal turn_transformer_ec<false> transformer(method_touch_interior); // conditionally handle spikes - if ( handle_spikes ) + if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { append_opposite_spikes<append_collinear_opposite>( tp, inters, is_p_last, is_q_last, out); @@ -351,8 +355,9 @@ struct get_turn_info_linear_areal TurnInfo, AssignPolicy >::apply(pi, pj, pk, qi, qj, qk, - tp, out, inters.i_info(), inters.d_info(), - inters.sides(), transformer); + tp, out, inters, + inters.sides(), transformer, + !is_p_last, true); // qk is always valid } } } @@ -360,7 +365,7 @@ struct get_turn_info_linear_areal case '0' : { // degenerate points - if (AssignPolicy::include_degenerate) + if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) { only_convert::apply(tp, inters.i_info()); @@ -376,7 +381,7 @@ struct get_turn_info_linear_areal } // tp.operations[1].position = position_middle; - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } @@ -408,20 +413,37 @@ struct get_turn_info_linear_areal 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(); + + bool going_in = pk_q1 < 0; // Pk on the right + bool going_out = pk_q1 > 0; // Pk on the left - if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C + int const qk_q1 = inters.sides().qk_wrt_q1(); + + // special cases + if ( qk_q1 < 0 ) // Q turning R { - 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 + // spike on the edge point + // if it's already known that the spike is going out this musn't be checked + if ( ! going_out + && equals::equals_point_point(inters.rpj(), inters.rqj()) ) + { + int const pk_q2 = inters.sides().pk_wrt_q2(); + 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 + else if ( qk_q1 > 0 ) // Q turning L { - 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 + // spike on the edge point + // if it's already known that the spike is going in this musn't be checked + if ( ! going_in + && equals::equals_point_point(inters.rpj(), inters.rqj()) ) + { + int const pk_q2 = inters.sides().pk_wrt_q2(); + 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 ) @@ -461,10 +483,16 @@ struct get_turn_info_linear_areal && 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();*/ + /*bool is_q_spike = tp.operations[1].operation == operation_continue + && inters.is_spike_q(); + // both are collinear spikes on the same IP, we can just follow both + if ( is_p_spike && is_q_spike ) + { + return false; + } + // spike on Linear - it's turning back on the boundary of Areal + else*/ if ( is_p_spike ) { tp.method = method; @@ -477,7 +505,18 @@ struct get_turn_info_linear_areal return true; } - + // spike on Areal - Linear is going outside + /*else if ( is_q_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_continue; + *out++ = tp; + *out++ = tp; + + return true; + }*/ + return false; } @@ -492,48 +531,71 @@ struct get_turn_info_linear_areal bool is_p_last, bool /*is_q_last*/, OutIt out) { - bool is_p_spike = ( Version == append_touches ? + static const bool is_version_touches = (Version == append_touches); + + bool is_p_spike = ( is_version_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();*/ + /*bool is_q_spike = ( ( Version == append_touches + && tp.operations[1].operation == operation_continue ) + || ( Version == append_collinear_opposite + && tp.operations[1].operation == operation_none ) ) + && inters.is_spike_q(); - if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + if ( is_p_spike && is_q_spike ) { - if ( Version == append_touches ) - { - tp.operations[0].is_collinear = true; - //tp.operations[1].is_collinear = false; - tp.method = method_touch; - } - else + // u/u or nothing? + return false; + } + else*/ + if ( is_p_spike ) + { + if ( BOOST_GEOMETRY_CONDITION(is_version_touches) + || inters.d_info().arrival[0] == 1 ) { - 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); + if ( BOOST_GEOMETRY_CONDITION(is_version_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; - AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info()); - } + BOOST_ASSERT(inters.i_info().count > 1); + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); - tp.operations[0].operation = operation_blocked; + AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); + } + + 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; + } + } + /*else if ( is_q_spike ) + { + tp.operations[0].is_collinear = true; + tp.method = is_version_touches ? method_touch : method_touch_interior; + tp.operations[0].operation = operation_continue; 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; } @@ -587,7 +649,7 @@ struct get_turn_info_linear_areal operation_type & op1 = turn.operations[1].operation; // NOTE: probably only if methods are WRT IPs, not segments! - if ( IsFront + if ( BOOST_GEOMETRY_CONDITION(IsFront) || op0 == operation_intersection || op0 == operation_union || op1 == operation_intersection || op1 == operation_union ) { @@ -666,7 +728,9 @@ struct get_turn_info_linear_areal // 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 + bool was_first_point_handled = false; + if ( BOOST_GEOMETRY_CONDITION(EnableFirst) + && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication { TurnInfo tp = tp_model; tp.operations[0].position = position_front; @@ -735,14 +799,16 @@ struct get_turn_info_linear_areal // here is_p_first_ip == true tp.operations[0].is_collinear = false; - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; + + was_first_point_handled = true; } // ANALYSE AND ASSIGN LAST // IP on the last point of Linear Geometry - if ( EnableLast + if ( BOOST_GEOMETRY_CONDITION(EnableLast) && is_p_last && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication { @@ -783,13 +849,14 @@ struct get_turn_info_linear_areal // equals<> or collinear<> will assign the second point, // we'd like to assign the first one - int ip_index = ip_count > 1 ? 1 : 0; + unsigned 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()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; - return true; + // don't ignore the first IP if the segment is opposite + return !( opposite && ip_count > 1 ) || was_first_point_handled; } // don't ignore anything for now diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp index 4f0384877f..1ec88e54a0 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -2,8 +2,8 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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 @@ -17,6 +17,8 @@ #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> +#include <boost/geometry/util/condition.hpp> + namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL @@ -120,7 +122,7 @@ struct get_turn_info_linear_linear tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } @@ -132,7 +134,7 @@ struct get_turn_info_linear_linear replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -260,9 +262,9 @@ struct get_turn_info_linear_linear 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()); + AssignPolicy::apply(tp, pi, qi, inters); - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_opposite_spikes<append_touches>(tp, inters, is_p_last, is_q_last, out) ) @@ -293,18 +295,24 @@ struct get_turn_info_linear_linear equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, tp, inters.i_info(), inters.d_info(), inters.sides()); + operation_type spike_op + = ( tp.operations[0].operation != operation_continue + || tp.operations[1].operation != operation_continue ) ? + operation_union : + operation_continue; + // 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()); + AssignPolicy::apply(tp, pi, qi, inters); // conditionally handle spikes - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, - method_touch, operation_union, + method_touch, spike_op, out) ) { *out++ = tp; // no spikes @@ -318,7 +326,7 @@ struct get_turn_info_linear_linear < TurnInfo, AssignPolicy - >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info()); + >::apply(pi, qi, tp, out, inters); } } } @@ -351,7 +359,11 @@ struct get_turn_info_linear_linear tp, inters.i_info(), inters.d_info(), inters.sides()); method_replace = method_touch; - spike_op = operation_union; + if ( tp.operations[0].operation != operation_continue + || tp.operations[1].operation != operation_continue ) + { + spike_op = operation_union; + } } else { @@ -367,10 +379,10 @@ struct get_turn_info_linear_linear 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()); + AssignPolicy::apply(tp, pi, qi, inters); // conditionally handle spikes - if ( ! handle_spikes + if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, method_replace, spike_op, @@ -386,7 +398,7 @@ struct get_turn_info_linear_linear turn_transformer_ec transformer(method_touch_interior); // conditionally handle spikes - if ( handle_spikes ) + if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { append_opposite_spikes<append_collinear_opposite>(tp, inters, is_p_last, is_q_last, @@ -402,7 +414,7 @@ struct get_turn_info_linear_linear TurnInfo, AssignPolicy >::apply(pi, pj, pk, qi, qj, qk, - tp, out, inters.i_info(), inters.d_info(), inters.sides(), + tp, out, inters, inters.sides(), transformer, !is_p_last, !is_q_last); } } @@ -411,7 +423,7 @@ struct get_turn_info_linear_linear case '0' : { // degenerate points - if (AssignPolicy::include_degenerate) + if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) { only_convert::apply(tp, inters.i_info()); @@ -437,7 +449,7 @@ struct get_turn_info_linear_linear tp.operations[1].position = position_back; } - AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } @@ -478,6 +490,14 @@ struct get_turn_info_linear_linear if ( is_p_spike && is_q_spike ) { + if ( tp.method == method_equal + && tp.operations[0].operation == operation_continue + && tp.operations[1].operation == operation_continue ) + { + // treat both non-opposite collinear spikes as no-spikes + return false; + } + tp.method = method; tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_blocked; @@ -527,13 +547,15 @@ struct get_turn_info_linear_linear bool is_p_last, bool is_q_last, OutIt out) { - bool is_p_spike = ( Version == append_touches ? + static const bool is_version_touches = (Version == append_touches); + + bool is_p_spike = ( is_version_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 ? + bool is_q_spike = ( is_version_touches ? ( tp.operations[1].operation == operation_continue || tp.operations[1].operation == operation_intersection ) : true ) @@ -542,9 +564,11 @@ struct get_turn_info_linear_linear bool res = false; - if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + if ( is_p_spike + && ( BOOST_GEOMETRY_CONDITION(is_version_touches) + || inters.d_info().arrival[0] == 1 ) ) { - if ( Version == append_touches ) + if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = false; @@ -560,8 +584,7 @@ struct get_turn_info_linear_linear 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()); + AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); } tp.operations[0].operation = operation_blocked; @@ -574,9 +597,11 @@ struct get_turn_info_linear_linear res = true; } - if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) ) + if ( is_q_spike + && ( BOOST_GEOMETRY_CONDITION(is_version_touches) + || inters.d_info().arrival[1] == 1 ) ) { - if ( Version == append_touches ) + if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) { tp.operations[0].is_collinear = false; tp.operations[1].is_collinear = true; @@ -591,8 +616,7 @@ struct get_turn_info_linear_linear 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()); + AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); } tp.operations[0].operation = operation_intersection; diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp index a96538c43a..a5d8f3f023 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -54,6 +54,7 @@ #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> @@ -62,8 +63,7 @@ #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/section_functions.hpp> #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION # include <sstream> @@ -229,7 +229,7 @@ public : // section 2: [--------------] // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; - it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy); + it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy); ++prev1, ++it1, ++index1, ++next1, ++ndi1) { ever_circling_iterator<range1_iterator> nd_next1( @@ -247,7 +247,7 @@ public : next2++; for (prev2 = it2++, next2++; - it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy); + it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy); ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = same_source; @@ -299,8 +299,8 @@ public : if (InterruptPolicy::enabled) { if (interrupt_policy.apply( - std::make_pair(boost::begin(turns) + size_before, - boost::end(turns)))) + std::make_pair(range::pos(turns, size_before), + boost::end(turns)))) { return false; } @@ -318,25 +318,6 @@ private : typedef typename model::referring_segment<point1_type const> segment1_type; typedef typename model::referring_segment<point2_type const> segment2_type; - - template <size_t Dim, typename Point, typename Box, typename RobustPolicy> - static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) - { - 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, typename RobustPolicy> - static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) - { - 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, typename RobustPolicy> static inline void advance_to_non_duplicate_next(Iterator& next, RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy) @@ -387,7 +368,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, robust_policy); + for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy); prev = it++, index++, ndi++) {} // Go back one step because we want to start completely preceding @@ -395,24 +376,6 @@ private : } }; -struct get_section_box -{ - template <typename Box, typename InputItem> - static inline void apply(Box& total, InputItem const& item) - { - geometry::expand(total, item.bounding_box); - } -}; - -struct ovelaps_section_box -{ - template <typename Box, typename InputItem> - static inline bool apply(Box const& box, InputItem const& item) - { - return ! detail::disjoint::disjoint_box_box(box, item.bounding_box); - } -}; - template < typename Geometry1, typename Geometry2, @@ -496,12 +459,15 @@ public: point_type, RobustPolicy >::type > box_type; - typedef typename geometry::sections<box_type, 2> sections_type; + typedef geometry::sections<box_type, 2> sections_type; sections_type sec1, sec2; + typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions; - geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0); - geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1); + geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy, + sec1, 0); + geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy, + sec2, 1); // ... and then partition them, intersecting overlapping sections in visitor method section_visitor @@ -513,7 +479,9 @@ public: geometry::partition < - box_type, get_section_box, ovelaps_section_box + box_type, + detail::section::get_section_box, + detail::section::overlaps_section_box >::apply(sec1, sec2, visitor); } }; @@ -556,7 +524,8 @@ struct get_turns_cs RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, - int multi_index = -1, int ring_index = -1) + signed_index_type multi_index = -1, + signed_index_type ring_index = -1) { if ( boost::size(range) <= 1) { @@ -569,7 +538,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; + typedef typename boost::range_size<view_type>::type size_type; + size_type segments_count1 = boost::size(view) - 1; iterator_type it = boost::begin(view); @@ -582,7 +552,7 @@ struct get_turns_cs //char previous_side[2] = {0, 0}; - int index = 0; + signed_index_type index = 0; for (iterator_type prev = it++; it != boost::end(view); @@ -621,7 +591,7 @@ struct get_turns_cs 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, + size_type(index) == segments_count1, robust_policy, turns, interrupt_policy); // Future performance enhancement: @@ -726,7 +696,7 @@ struct get_turns_polygon_cs int source_id2, Box const& box, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, - int multi_index = -1) + signed_index_type multi_index = -1) { typedef typename geometry::ring_type<Polygon>::type ring_type; @@ -744,7 +714,7 @@ struct get_turns_polygon_cs turns, interrupt_policy, multi_index, -1); - int i = 0; + signed_index_type i = 0; typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); @@ -783,7 +753,7 @@ struct get_turns_multi_polygon_cs Multi const >::type iterator_type; - int i = 0; + signed_index_type i = 0; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it, ++i) diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp index 085933dd7a..277a223d47 100644 --- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp +++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -28,6 +28,11 @@ #include <boost/geometry/geometries/segment.hpp> +// TODO: the approach below should be completely replaced by the new +// get_left_turns, to keep the outgoing vector which has open space one of its +// sides. + + namespace boost { namespace geometry { @@ -76,6 +81,12 @@ private : RobustPolicy >::type robust_point_type; + inline bool default_order(Indexed const& left, Indexed const& right) const + { + // We've nothing to sort on. Take the indexes + return left.turn_index < right.turn_index; + } + // 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, @@ -336,7 +347,7 @@ private : #endif //debug_consider(0, left, right, header, false, "-> return", ret); - return left.turn_index < right.turn_index; + return default_order(left, right); } @@ -369,11 +380,17 @@ private : // Both located at same side (#58, pie_21_7_21_0_3) if (side_ri_p * side_si_p == 1 && side_si_r != 0) { - // Take the most left one if (left.subject->operation == operation_union && right.subject->operation == operation_union) { - bool ret = side_si_r == 1; + int const side_ri_s = m_strategy.apply(si, sj, ri); + if (side_si_r == side_ri_s) + { + return default_order(left, right); + } + + // Take the most left one + bool const ret = side_si_r == 1; //debug_consider(0, left, right, header, false, "same side", ret); return ret; } @@ -407,6 +424,12 @@ private : // One coming from left (#90, #94, #95) if (side_si_r != 0 && (side_ri_p != 0 || side_si_p != 0)) { + int const side_ri_s = m_strategy.apply(si, sj, ri); + if (side_si_r == side_ri_s) + { + return default_order(left, right); + } + bool ret = false; #if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO @@ -464,7 +487,7 @@ private : return ! consider_iu_iu(right, left, header, true); } - return left.turn_index < right.turn_index; + return default_order(left, right); } inline bool consider_ii(Indexed const& left, Indexed const& right, @@ -488,19 +511,17 @@ private : bool const ret = side_si_r != 1; return ret; } - return left.turn_index < right.turn_index; + return default_order(left, right); } public : inline bool operator()(Indexed const& left, Indexed const& right) const { - bool const default_order = left.turn_index < right.turn_index; - if ((m_turn_points[left.turn_index].discarded || left.discarded) && (m_turn_points[right.turn_index].discarded || right.discarded)) { - return default_order; + return default_order(left, right); } else if (m_turn_points[left.turn_index].discarded || left.discarded) { @@ -525,7 +546,7 @@ public : // uu/uu, Order is arbitrary // Note: uu/uu is discarded now before so this point will // not be reached. - return default_order; + return default_order(left, right); } else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union) && m_turn_points[right.turn_index].combination(operation_intersection, operation_union)) @@ -587,7 +608,7 @@ public : << std::endl; #endif - return default_order; + return default_order(left, right); } }; @@ -708,7 +729,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, for_operation, geometry1, geometry2, strategy); - // Then sort this range (discard rows will be ordered first and will be removed in enrich_assign) + // Then sort this range (discarded rows will be ordered first and will be removed in enrich_assign) std::sort(begin_cluster, end_cluster, sort_in_cluster < diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index a13a627456..3101de8c35 100644 --- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -43,9 +43,9 @@ #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> +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> +#include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry @@ -254,9 +254,10 @@ struct intersection_of_linestring_with_areal #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) int index = 0; - BOOST_FOREACH(turn_info const& turn, turns) + for(typename std::deque<turn_info>::const_iterator + it = turns.begin(); it != turns.end(); ++it) { - debug_follow(turn, turn.operations[0], index++); + debug_follow(*it, it->operations[0], index++); } #endif diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index 3a7a7a7f3e..d4ebcf296b 100644 --- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -144,11 +144,10 @@ protected: typename Info, typename Point1, typename Point2, - typename IntersectionInfo, - typename DirInfo + typename IntersectionInfo > static inline void apply(Info& , Point1 const& , Point2 const& , - IntersectionInfo const& , DirInfo const& ) + IntersectionInfo const& ) { } }; diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp index 44b5a0df3c..a2f52848d1 100644 --- a/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -44,10 +44,6 @@ # include <boost/geometry/io/dsv/write.hpp> #endif -#ifdef BOOST_GEOMETRY_TIME_OVERLAY -# include <boost/timer.hpp> -#endif - namespace boost { namespace geometry { @@ -57,19 +53,10 @@ namespace boost { namespace geometry namespace detail { namespace overlay { -// Skip for assemble process -template <typename TurnInfo> -inline bool skip(TurnInfo const& turn_info) -{ - return (turn_info.discarded || turn_info.both(operation_union)) - && ! turn_info.any_blocked() - && ! turn_info.both(operation_intersection) - ; -} - -template <typename TurnPoints, typename Map> -inline void map_turns(Map& map, TurnPoints const& turn_points) +template <typename TurnPoints, typename TurnInfoMap> +inline void get_ring_turn_info(TurnInfoMap& turn_info_map, + TurnPoints const& turn_points) { typedef typename boost::range_value<TurnPoints>::type turn_point_type; typedef typename turn_point_type::container_type container_type; @@ -79,20 +66,32 @@ inline void map_turns(Map& map, TurnPoints const& turn_points) it != boost::end(turn_points); ++it) { - if (! skip(*it)) + typename boost::range_value<TurnPoints>::type const& turn_info = *it; + bool both_uu = turn_info.both(operation_union); + bool skip = (turn_info.discarded || both_uu) + && ! turn_info.any_blocked() + && ! turn_info.both(operation_intersection) + ; + + for (typename boost::range_iterator<container_type const>::type + op_it = boost::begin(turn_info.operations); + op_it != boost::end(turn_info.operations); + ++op_it) { - for (typename boost::range_iterator<container_type const>::type - op_it = boost::begin(it->operations); - op_it != boost::end(it->operations); - ++op_it) + ring_identifier ring_id + ( + op_it->seg_id.source_index, + op_it->seg_id.multi_index, + op_it->seg_id.ring_index + ); + + if (! skip) { - ring_identifier ring_id - ( - op_it->seg_id.source_index, - op_it->seg_id.multi_index, - op_it->seg_id.ring_index - ); - map[ring_id]++; + turn_info_map[ring_id].has_normal_turn = true; + } + else if (both_uu) + { + turn_info_map[ring_id].has_uu_turn = true; } } } @@ -137,10 +136,10 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1, #endif - std::map<ring_identifier, int> empty; + std::map<ring_identifier, ring_turn_info> empty; std::map<ring_identifier, properties> all_of_one_of_them; - select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false); + select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them); ring_container_type rings; assign_parents(geometry1, geometry2, rings, all_of_one_of_them); return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out); @@ -193,10 +192,6 @@ struct overlay container_type turn_points; -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - boost::timer timer; -#endif - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "get turns" << std::endl; #endif @@ -207,10 +202,6 @@ std::cout << "get turns" << std::endl; 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; -#endif - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "enrich" << std::endl; #endif @@ -223,11 +214,6 @@ std::cout << "enrich" << std::endl; robust_policy, side_strategy); -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl; -#endif - - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "traverse" << std::endl; #endif @@ -245,27 +231,18 @@ std::cout << "traverse" << std::endl; turn_points, rings ); -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "traverse: " << timer.elapsed() << std::endl; -#endif - - - std::map<ring_identifier, int> map; - map_turns(map, turn_points); - -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "map_turns: " << timer.elapsed() << std::endl; -#endif - - typedef ring_properties<typename geometry::point_type<GeometryOut>::type> properties; - - std::map<ring_identifier, properties> selected; - select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty()); + std::map<ring_identifier, ring_turn_info> turn_info_per_ring; + get_ring_turn_info(turn_info_per_ring, turn_points); -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "select_rings: " << timer.elapsed() << std::endl; -#endif + typedef ring_properties + < + typename geometry::point_type<GeometryOut>::type + > properties; + // Select all rings which are NOT touched by any intersection point + std::map<ring_identifier, properties> selected_ring_properties; + select_rings<Direction>(geometry1, geometry2, turn_info_per_ring, + selected_ring_properties); // Add rings created during traversal { @@ -275,24 +252,15 @@ std::cout << "traverse" << std::endl; it != boost::end(rings); ++it) { - selected[id] = properties(*it, true); - selected[id].reversed = ReverseOut; + selected_ring_properties[id] = properties(*it); + selected_ring_properties[id].reversed = ReverseOut; id.multi_index++; } } -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "add traversal rings: " << timer.elapsed() << std::endl; -#endif - - - assign_parents(geometry1, geometry2, rings, selected); - -#ifdef BOOST_GEOMETRY_TIME_OVERLAY - std::cout << "assign_parents: " << timer.elapsed() << std::endl; -#endif + assign_parents(geometry1, geometry2, rings, selected_ring_properties); - return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out); + return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out); } }; diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp index a6088694da..b469052c84 100644 --- a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp +++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp @@ -33,8 +33,7 @@ struct ring_properties Point point; area_type area; - // Filled by "update_selection_map" - int within_code; + // Filled by "update_ring_selection" bool reversed; // Filled/used by "assign_rings" @@ -45,21 +44,22 @@ struct ring_properties inline ring_properties() : area(area_type()) - , within_code(-1) , reversed(false) , discarded(false) , parent_area(-1) {} template <typename RingOrBox> - inline ring_properties(RingOrBox const& ring_or_box, bool midpoint) - : within_code(-1) - , reversed(false) + inline ring_properties(RingOrBox const& ring_or_box) + : reversed(false) , discarded(false) , parent_area(-1) { this->area = geometry::area(ring_or_box); - geometry::point_on_border(this->point, ring_or_box, midpoint); + // We should take a point somewhere in the middle of the ring, + // to avoid taking a point on a (self)tangency, + // in cases where multiple points come together + geometry::point_on_border(this->point, ring_or_box, true); } inline area_type get_area() const diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp index 385658a190..d18e012b2d 100644 --- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -1,6 +1,6 @@ // 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. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, @@ -20,7 +20,6 @@ #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> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> @@ -34,6 +33,18 @@ namespace boost { namespace geometry namespace detail { namespace overlay { +struct ring_turn_info +{ + bool has_uu_turn; + bool has_normal_turn; + bool within_other; + + ring_turn_info() + : has_uu_turn(false) + , has_normal_turn(false) + , within_other(false) + {} +}; namespace dispatch { @@ -45,41 +56,41 @@ namespace dispatch template <typename Box> struct select_rings<box_tag, Box> { - template <typename Geometry, typename Map> + template <typename Geometry, typename RingPropertyMap> static inline void apply(Box const& box, Geometry const& , - ring_identifier const& id, Map& map, bool midpoint) + ring_identifier const& id, RingPropertyMap& ring_properties) { - map[id] = typename Map::mapped_type(box, midpoint); + ring_properties[id] = typename RingPropertyMap::mapped_type(box); } - template <typename Map> + template <typename RingPropertyMap> static inline void apply(Box const& box, - ring_identifier const& id, Map& map, bool midpoint) + ring_identifier const& id, RingPropertyMap& ring_properties) { - map[id] = typename Map::mapped_type(box, midpoint); + ring_properties[id] = typename RingPropertyMap::mapped_type(box); } }; template <typename Ring> struct select_rings<ring_tag, Ring> { - template <typename Geometry, typename Map> + template <typename Geometry, typename RingPropertyMap> static inline void apply(Ring const& ring, Geometry const& , - ring_identifier const& id, Map& map, bool midpoint) + ring_identifier const& id, RingPropertyMap& ring_properties) { if (boost::size(ring) > 0) { - map[id] = typename Map::mapped_type(ring, midpoint); + ring_properties[id] = typename RingPropertyMap::mapped_type(ring); } } - template <typename Map> + template <typename RingPropertyMap> static inline void apply(Ring const& ring, - ring_identifier const& id, Map& map, bool midpoint) + ring_identifier const& id, RingPropertyMap& ring_properties) { if (boost::size(ring) > 0) { - map[id] = typename Map::mapped_type(ring, midpoint); + ring_properties[id] = typename RingPropertyMap::mapped_type(ring); } } }; @@ -88,14 +99,14 @@ namespace dispatch template <typename Polygon> struct select_rings<polygon_tag, Polygon> { - template <typename Geometry, typename Map> + template <typename Geometry, typename RingPropertyMap> static inline void apply(Polygon const& polygon, Geometry const& geometry, - ring_identifier id, Map& map, bool midpoint) + ring_identifier id, RingPropertyMap& ring_properties) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef select_rings<ring_tag, ring_type> per_ring; - per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint); + per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties); typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); @@ -103,18 +114,18 @@ namespace dispatch it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; - per_ring::apply(*it, geometry, id, map, midpoint); + per_ring::apply(*it, geometry, id, ring_properties); } } - template <typename Map> + template <typename RingPropertyMap> static inline void apply(Polygon const& polygon, - ring_identifier id, Map& map, bool midpoint) + ring_identifier id, RingPropertyMap& ring_properties) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef select_rings<ring_tag, ring_type> per_ring; - per_ring::apply(exterior_ring(polygon), id, map, midpoint); + per_ring::apply(exterior_ring(polygon), id, ring_properties); typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); @@ -122,7 +133,7 @@ namespace dispatch it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; - per_ring::apply(*it, id, map, midpoint); + per_ring::apply(*it, id, ring_properties); } } }; @@ -130,9 +141,9 @@ namespace dispatch template <typename Multi> struct select_rings<multi_polygon_tag, Multi> { - template <typename Geometry, typename Map> + template <typename Geometry, typename RingPropertyMap> static inline void apply(Multi const& multi, Geometry const& geometry, - ring_identifier id, Map& map, bool midpoint) + ring_identifier id, RingPropertyMap& ring_properties) { typedef typename boost::range_iterator < @@ -145,7 +156,7 @@ namespace dispatch for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { id.ring_index = -1; - per_polygon::apply(*it, geometry, id, map, midpoint); + per_polygon::apply(*it, geometry, id, ring_properties); id.multi_index++; } } @@ -161,14 +172,12 @@ struct decide template<> struct decide<overlay_union> { - template <typename Code> - static bool include(ring_identifier const& , Code const& code) + static bool include(ring_identifier const& , ring_turn_info const& info) { - return code.within_code * -1 == 1; + return info.has_uu_turn || ! info.within_other; } - template <typename Code> - static bool reversed(ring_identifier const& , Code const& ) + static bool reversed(ring_identifier const& , ring_turn_info const& ) { return false; } @@ -177,31 +186,43 @@ struct decide<overlay_union> template<> struct decide<overlay_difference> { - template <typename Code> - static bool include(ring_identifier const& id, Code const& code) + static bool include(ring_identifier const& id, ring_turn_info const& info) { - bool is_first = id.source_index == 0; - return code.within_code * -1 * (is_first ? 1 : -1) == 1; + // Difference: A - B + + // If this is A (source_index=0) and there is only a u/u turn, + // then the ring is inside B + // If this is B (source_index=1) and there is only a u/u turn, + // then the ring is NOT inside A + + // If this is A and the ring is within the other geometry, + // then we should NOT include it. + // If this is B then we SHOULD include it. + + bool const is_first = id.source_index == 0; + bool const within_other = info.within_other + || (is_first && info.has_uu_turn); + return is_first ? ! within_other : within_other; } - template <typename Code> - static bool reversed(ring_identifier const& id, Code const& code) + static bool reversed(ring_identifier const& id, ring_turn_info const& info) { - return include(id, code) && id.source_index == 1; + // Difference: A - B + // If this is B, and the ring is included, it should be reversed afterwards + + return id.source_index == 1 && include(id, info); } }; template<> struct decide<overlay_intersection> { - template <typename Code> - static bool include(ring_identifier const& , Code const& code) + static bool include(ring_identifier const& , ring_turn_info const& info) { - return code.within_code * 1 == 1; + return ! info.has_uu_turn && info.within_other; } - template <typename Code> - static bool reversed(ring_identifier const& , Code const& ) + static bool reversed(ring_identifier const& , ring_turn_info const& ) { return false; } @@ -211,61 +232,60 @@ struct decide<overlay_intersection> template < overlay_type OverlayType, - typename Geometry1, typename Geometry2, - typename IntersectionMap, typename SelectionMap + typename Geometry1, + typename Geometry2, + typename TurnInfoMap, + typename RingPropertyMap > -inline void update_selection_map(Geometry1 const& geometry1, +inline void update_ring_selection(Geometry1 const& geometry1, Geometry2 const& geometry2, - IntersectionMap const& intersection_map, - SelectionMap const& map_with_all, SelectionMap& selection_map) + TurnInfoMap const& turn_info_map, + RingPropertyMap const& all_ring_properties, + RingPropertyMap& selected_ring_properties) { - selection_map.clear(); + selected_ring_properties.clear(); - for (typename SelectionMap::const_iterator it = boost::begin(map_with_all); - it != boost::end(map_with_all); + for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties); + it != boost::end(all_ring_properties); ++it) { - /* - int union_code = it->second.within_code * -1; - bool is_first = it->first.source_index == 0; - std::cout << it->first << " " << it->second.area - << ": " << it->second.within_code - << " union: " << union_code - << " intersection: " << (it->second.within_code * 1) - << " G1-G2: " << (union_code * (is_first ? 1 : -1)) - << " G2-G1: " << (union_code * (is_first ? -1 : 1)) - << " -> " << (decide<OverlayType>::include(it->first, it->second) ? "INC" : "") - << decide<OverlayType>::reverse(it->first, it->second) - << std::endl; - */ - - bool found = intersection_map.find(it->first) != intersection_map.end(); - if (! found) + ring_identifier const& id = it->first; + + ring_turn_info info; + + typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id); + if (tcit != turn_info_map.end()) { - ring_identifier const id = it->first; - typename SelectionMap::mapped_type properties = it->second; // Copy by value + info = tcit->second; // Copy by value + } - // Calculate the "within code" (previously this was done earlier but is - // 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 + if (info.has_normal_turn) + { + // There are normal turns on this ring. It should be traversed, we + // don't include the original ring + continue; + } + + if (! info.has_uu_turn) + { + // Check if the ring is within the other geometry, by taking + // a point lying on the ring switch(id.source_index) { case 0 : - properties.within_code - = geometry::within(properties.point, geometry2) ? 1 : -1; + info.within_other = geometry::within(it->second.point, geometry2); break; case 1 : - properties.within_code - = geometry::within(properties.point, geometry1) ? 1 : -1; + info.within_other = geometry::within(it->second.point, geometry1); break; } + } - if (decide<OverlayType>::include(id, properties)) - { - properties.reversed = decide<OverlayType>::reversed(id, properties); - selection_map[id] = properties; - } + if (decide<OverlayType>::include(id, info)) + { + typename RingPropertyMap::mapped_type properties = it->second; // Copy by value + properties.reversed = decide<OverlayType>::reversed(id, info); + selected_ring_properties[id] = properties; } } } @@ -277,44 +297,47 @@ inline void update_selection_map(Geometry1 const& geometry1, template < overlay_type OverlayType, - typename Geometry1, typename Geometry2, - typename IntersectionMap, typename SelectionMap + typename Geometry1, + typename Geometry2, + typename RingTurnInfoMap, + typename RingPropertyMap > inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, - IntersectionMap const& intersection_map, - SelectionMap& selection_map, bool midpoint) + RingTurnInfoMap const& turn_info_per_ring, + RingPropertyMap& selected_ring_properties) { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; - SelectionMap map_with_all; + RingPropertyMap all_ring_properties; dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2, - ring_identifier(0, -1, -1), map_with_all, midpoint); + ring_identifier(0, -1, -1), all_ring_properties); dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1, - ring_identifier(1, -1, -1), map_with_all, midpoint); + ring_identifier(1, -1, -1), all_ring_properties); - update_selection_map<OverlayType>(geometry1, geometry2, intersection_map, - map_with_all, selection_map); + update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring, + all_ring_properties, selected_ring_properties); } template < overlay_type OverlayType, typename Geometry, - typename IntersectionMap, typename SelectionMap + typename RingTurnInfoMap, + typename RingPropertyMap > inline void select_rings(Geometry const& geometry, - IntersectionMap const& intersection_map, - SelectionMap& selection_map, bool midpoint) + RingTurnInfoMap const& turn_info_per_ring, + RingPropertyMap& selected_ring_properties) { typedef typename geometry::tag<Geometry>::type tag; - SelectionMap map_with_all; + RingPropertyMap all_ring_properties; dispatch::select_rings<tag, Geometry>::apply(geometry, - ring_identifier(0, -1, -1), map_with_all, midpoint); + ring_identifier(0, -1, -1), all_ring_properties); - update_selection_map<OverlayType>(geometry, geometry, intersection_map, - map_with_all, selection_map); + update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring, + all_ring_properties, selected_ring_properties); } diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 8dffeae283..b1f984ffe1 100644 --- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -23,9 +23,12 @@ #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> +#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/util/condition.hpp> + namespace boost { namespace geometry { @@ -96,7 +99,7 @@ struct self_section_visitor m_rescale_policy, m_turns, m_interrupt_policy); } - if (m_interrupt_policy.has_intersections) + if (BOOST_GEOMETRY_CONDITION(m_interrupt_policy.has_intersections)) { // TODO: we should give partition an interrupt policy. // Now we throw, and catch below, to stop the partition loop. @@ -121,15 +124,19 @@ struct get_turns { typedef model::box < - typename geometry::point_type<Geometry>::type + typename geometry::robust_point_type + < + typename geometry::point_type<Geometry>::type, + RobustPolicy + >::type > box_type; - typedef typename geometry::sections - < - box_type, 1 - > sections_type; + + typedef geometry::sections<box_type, 1> sections_type; + + typedef boost::mpl::vector_c<std::size_t, 0> dimensions; sections_type sec; - geometry::sectionalize<false>(geometry, robust_policy, false, sec); + geometry::sectionalize<false, dimensions>(geometry, robust_policy, sec); self_section_visitor < @@ -142,8 +149,8 @@ struct get_turns geometry::partition < box_type, - detail::get_turns::get_section_box, - detail::get_turns::ovelaps_section_box + detail::section::get_section_box, + detail::section::overlaps_section_box >::apply(sec, visitor); } catch(self_ip_exception const& ) diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp index a44d5637bc..25a34ba2ec 100644 --- a/boost/geometry/algorithms/detail/partition.hpp +++ b/boost/geometry/algorithms/detail/partition.hpp @@ -10,7 +10,6 @@ #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> @@ -24,7 +23,7 @@ namespace detail { namespace partition typedef std::vector<std::size_t> index_vector_type; template <int Dimension, typename Box> -void divide_box(Box const& box, Box& lower_box, Box& upper_box) +inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) { typedef typename coordinate_type<Box>::type ctype; @@ -79,20 +78,39 @@ inline void divide_into_subsets(Box const& lower_box, } else { - // Is nowhere! Should not occur! - BOOST_ASSERT(false); + // Is nowhere. That is (since 1.58) possible, it might be + // skipped by the OverlapsPolicy to enhance performance } } } +template <typename ExpandPolicy, typename Box, typename InputCollection> +inline void expand_with_elements(Box& total, + InputCollection const& collection, + index_vector_type const& input) +{ + typedef boost::range_iterator<index_vector_type const>::type it_type; + for(it_type it = boost::begin(input); it != boost::end(input); ++it) + { + ExpandPolicy::apply(total, collection[*it]); + } +} + + // Match collection with itself template <typename InputCollection, typename Policy> inline void handle_one(InputCollection const& collection, index_vector_type const& input, Policy& policy) { + if (boost::size(input) == 0) + { + return; + } + typedef boost::range_iterator<index_vector_type const>::type index_iterator_type; + // Quadratic behaviour at lowest level (lowest quad, or all exceeding) for(index_iterator_type it1 = boost::begin(input); it1 != boost::end(input); @@ -118,6 +136,11 @@ inline void handle_two( InputCollection2 const& collection2, index_vector_type const& input2, Policy& policy) { + if (boost::size(input1) == 0 || boost::size(input2) == 0) + { + return; + } + typedef boost::range_iterator < index_vector_type const @@ -136,43 +159,116 @@ inline void handle_two( } } +inline bool recurse_ok(index_vector_type const& input, + std::size_t min_elements, std::size_t level) +{ + return boost::size(input) >= min_elements + && level < 100; +} + +inline bool recurse_ok(index_vector_type const& input1, + index_vector_type const& input2, + std::size_t min_elements, std::size_t level) +{ + return boost::size(input1) >= min_elements + && recurse_ok(input2, min_elements, level); +} + +inline bool recurse_ok(index_vector_type const& input1, + index_vector_type const& input2, + index_vector_type const& input3, + std::size_t min_elements, std::size_t level) +{ + return boost::size(input1) >= min_elements + && recurse_ok(input2, input3, min_elements, level); +} + +template +< + int Dimension, + typename Box, + typename OverlapsPolicy1, + typename OverlapsPolicy2, + typename ExpandPolicy1, + typename ExpandPolicy2, + typename VisitBoxPolicy +> +class partition_two_collections; + + template < int Dimension, typename Box, typename OverlapsPolicy, + typename ExpandPolicy, typename VisitBoxPolicy > class partition_one_collection { typedef std::vector<std::size_t> index_vector_type; - typedef typename coordinate_type<Box>::type ctype; - typedef partition_one_collection + + template <typename InputCollection> + static inline Box get_new_box(InputCollection const& collection, + index_vector_type const& input) + { + Box box; + geometry::assign_inverse(box); + expand_with_elements<ExpandPolicy>(box, collection, input); + return box; + } + + template <typename InputCollection, typename Policy> + static inline void next_level(Box const& box, + InputCollection const& collection, + index_vector_type const& input, + std::size_t level, std::size_t min_elements, + Policy& policy, VisitBoxPolicy& box_policy) + { + if (recurse_ok(input, min_elements, level)) + { + partition_one_collection < 1 - Dimension, Box, OverlapsPolicy, + ExpandPolicy, VisitBoxPolicy - > sub_divide; + >::apply(box, collection, input, + level + 1, min_elements, policy, box_policy); + } + else + { + handle_one(collection, input, policy); + } + } + // Function to switch to two collections if there are geometries exceeding + // the separation line template <typename InputCollection, typename Policy> - static inline void next_level(Box const& box, + static inline void next_level2(Box const& box, InputCollection const& collection, - index_vector_type const& input, - int level, std::size_t min_elements, + index_vector_type const& input1, + index_vector_type const& input2, + std::size_t level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) { - if (boost::size(input) > 0) + + if (recurse_ok(input1, input2, min_elements, level)) { - if (std::size_t(boost::size(input)) > min_elements && level < 100) - { - sub_divide::apply(box, collection, input, level + 1, - min_elements, policy, box_policy); - } - else - { - handle_one(collection, input, policy); - } + partition_two_collections + < + 1 - Dimension, + Box, + OverlapsPolicy, OverlapsPolicy, + ExpandPolicy, ExpandPolicy, + VisitBoxPolicy + >::apply(box, collection, input1, collection, input2, + level + 1, min_elements, policy, box_policy); + } + else + { + handle_two(collection, input1, collection, input2, policy); } } @@ -181,7 +277,7 @@ public : static inline void apply(Box const& box, InputCollection const& collection, index_vector_type const& input, - int level, + std::size_t level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) { @@ -196,11 +292,20 @@ public : if (boost::size(exceeding) > 0) { - // All what is not fitting a partition should be combined - // with each other, and with all which is fitting. - handle_one(collection, exceeding, policy); - handle_two(collection, exceeding, collection, lower, policy); - handle_two(collection, exceeding, collection, upper, policy); + // Get the box of exceeding-only + Box exceeding_box = get_new_box(collection, exceeding); + + // Recursively do exceeding elements only, in next dimension they + // will probably be less exceeding within the new box + next_level(exceeding_box, collection, exceeding, level, + min_elements, policy, box_policy); + + // Switch to two collections, combine exceeding with lower resp upper + // but not lower/lower, upper/upper + next_level2(exceeding_box, collection, exceeding, lower, level, + min_elements, policy, box_policy); + next_level2(exceeding_box, collection, exceeding, upper, level, + min_elements, policy, box_policy); } // Recursively call operation both parts @@ -217,20 +322,13 @@ template typename Box, typename OverlapsPolicy1, typename OverlapsPolicy2, + typename ExpandPolicy1, + typename ExpandPolicy2, typename VisitBoxPolicy > class partition_two_collections { typedef std::vector<std::size_t> index_vector_type; - typedef typename coordinate_type<Box>::type ctype; - typedef partition_two_collections - < - 1 - Dimension, - Box, - OverlapsPolicy1, - OverlapsPolicy2, - VisitBoxPolicy - > sub_divide; template < @@ -243,25 +341,50 @@ class partition_two_collections index_vector_type const& input1, InputCollection2 const& collection2, index_vector_type const& input2, - int level, std::size_t min_elements, + std::size_t level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) { - if (boost::size(input1) > 0 && boost::size(input2) > 0) - { - if (std::size_t(boost::size(input1)) > min_elements - && std::size_t(boost::size(input2)) > min_elements - && level < 100) - { - sub_divide::apply(box, collection1, input1, collection2, - input2, level + 1, min_elements, - policy, box_policy); - } - else - { - box_policy.apply(box, level + 1); - handle_two(collection1, input1, collection2, input2, policy); - } - } + partition_two_collections + < + 1 - Dimension, + Box, + OverlapsPolicy1, + OverlapsPolicy2, + ExpandPolicy1, + ExpandPolicy2, + VisitBoxPolicy + >::apply(box, collection1, input1, collection2, input2, + level + 1, min_elements, + policy, box_policy); + } + + template + < + typename ExpandPolicy, + typename InputCollection + > + static inline Box get_new_box(InputCollection const& collection, + index_vector_type const& input) + { + Box box; + geometry::assign_inverse(box); + expand_with_elements<ExpandPolicy>(box, collection, input); + return box; + } + + template + < + typename InputCollection1, + typename InputCollection2 + > + static inline Box get_new_box(InputCollection1 const& collection1, + index_vector_type const& input1, + InputCollection2 const& collection2, + index_vector_type const& input2) + { + Box box = get_new_box<ExpandPolicy1>(collection1, input1); + expand_with_elements<ExpandPolicy2>(box, collection2, input2); + return box; } public : @@ -274,7 +397,7 @@ public : static inline void apply(Box const& box, InputCollection1 const& collection1, index_vector_type const& input1, InputCollection2 const& collection2, index_vector_type const& input2, - int level, + std::size_t level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) { @@ -293,36 +416,100 @@ public : if (boost::size(exceeding1) > 0) { // All exceeding from 1 with 2: - handle_two(collection1, exceeding1, collection2, exceeding2, - policy); + + if (recurse_ok(exceeding1, exceeding2, min_elements, level)) + { + Box exceeding_box = get_new_box(collection1, exceeding1, + collection2, exceeding2); + next_level(exceeding_box, collection1, exceeding1, + collection2, exceeding2, level, + min_elements, policy, box_policy); + } + else + { + handle_two(collection1, exceeding1, collection2, exceeding2, + policy); + } // All exceeding from 1 with lower and upper of 2: - handle_two(collection1, exceeding1, collection2, lower2, policy); - handle_two(collection1, exceeding1, collection2, upper2, policy); + + // (Check sizes of all three collections to avoid recurse into + // the same combinations again and again) + if (recurse_ok(lower2, upper2, exceeding1, min_elements, level)) + { + Box exceeding_box + = get_new_box<ExpandPolicy1>(collection1, exceeding1); + next_level(exceeding_box, collection1, exceeding1, + collection2, lower2, level, min_elements, policy, box_policy); + next_level(exceeding_box, collection1, exceeding1, + collection2, upper2, level, min_elements, policy, box_policy); + } + else + { + handle_two(collection1, exceeding1, collection2, lower2, policy); + handle_two(collection1, exceeding1, collection2, upper2, policy); + } } + if (boost::size(exceeding2) > 0) { // All exceeding from 2 with lower and upper of 1: - handle_two(collection1, lower1, collection2, exceeding2, policy); - handle_two(collection1, upper1, collection2, exceeding2, policy); + if (recurse_ok(lower1, upper1, exceeding2, min_elements, level)) + { + Box exceeding_box + = get_new_box<ExpandPolicy2>(collection2, exceeding2); + next_level(exceeding_box, collection1, lower1, + collection2, exceeding2, level, min_elements, policy, box_policy); + next_level(exceeding_box, collection1, upper1, + collection2, exceeding2, level, min_elements, policy, box_policy); + } + else + { + handle_two(collection1, lower1, collection2, exceeding2, policy); + handle_two(collection1, upper1, collection2, exceeding2, policy); + } } - next_level(lower_box, collection1, lower1, collection2, lower2, level, - min_elements, policy, box_policy); - next_level(upper_box, collection1, upper1, collection2, upper2, level, - min_elements, policy, box_policy); + if (recurse_ok(lower1, lower2, min_elements, level)) + { + next_level(lower_box, collection1, lower1, collection2, lower2, level, + min_elements, policy, box_policy); + } + else + { + handle_two(collection1, lower1, collection2, lower2, policy); + } + if (recurse_ok(upper1, upper2, min_elements, level)) + { + next_level(upper_box, collection1, upper1, collection2, upper2, level, + min_elements, policy, box_policy); + } + else + { + handle_two(collection1, upper1, collection2, upper2, policy); + } } }; -}} // namespace detail::partition - struct visit_no_policy { template <typename Box> - static inline void apply(Box const&, int ) + static inline void apply(Box const&, std::size_t ) {} }; +struct include_all_policy +{ + template <typename Item> + static inline bool apply(Item const&) + { + return true; + } +}; + + +}} // namespace detail::partition + template < typename Box, @@ -330,13 +517,15 @@ template typename OverlapsPolicy1, typename ExpandPolicy2 = ExpandPolicy1, typename OverlapsPolicy2 = OverlapsPolicy1, - typename VisitBoxPolicy = visit_no_policy + typename IncludePolicy1 = detail::partition::include_all_policy, + typename IncludePolicy2 = detail::partition::include_all_policy, + typename VisitBoxPolicy = detail::partition::visit_no_policy > class partition { typedef std::vector<std::size_t> index_vector_type; - template <typename ExpandPolicy, typename InputCollection> + template <typename ExpandPolicy, typename IncludePolicy, typename InputCollection> static inline void expand_to_collection(InputCollection const& collection, Box& total, index_vector_type& index_vector) { @@ -346,8 +535,11 @@ class partition it != boost::end(collection); ++it, ++index) { - ExpandPolicy::apply(total, *it); - index_vector.push_back(index); + if (IncludePolicy::apply(*it)) + { + ExpandPolicy::apply(total, *it); + index_vector.push_back(index); + } } } @@ -356,7 +548,7 @@ public : static inline void apply(InputCollection const& collection, VisitPolicy& visitor, std::size_t min_elements = 16, - VisitBoxPolicy box_visitor = visit_no_policy() + VisitBoxPolicy box_visitor = detail::partition::visit_no_policy() ) { if (std::size_t(boost::size(collection)) > min_elements) @@ -364,12 +556,14 @@ public : index_vector_type index_vector; Box total; assign_inverse(total); - expand_to_collection<ExpandPolicy1>(collection, total, index_vector); + expand_to_collection<ExpandPolicy1, IncludePolicy1>(collection, + total, index_vector); detail::partition::partition_one_collection < 0, Box, OverlapsPolicy1, + ExpandPolicy1, VisitBoxPolicy >::apply(total, collection, index_vector, 0, min_elements, visitor, box_visitor); @@ -403,7 +597,7 @@ public : InputCollection2 const& collection2, VisitPolicy& visitor, std::size_t min_elements = 16, - VisitBoxPolicy box_visitor = visit_no_policy() + VisitBoxPolicy box_visitor = detail::partition::visit_no_policy() ) { if (std::size_t(boost::size(collection1)) > min_elements @@ -412,12 +606,15 @@ public : index_vector_type index_vector1, index_vector2; Box total; assign_inverse(total); - expand_to_collection<ExpandPolicy1>(collection1, total, index_vector1); - expand_to_collection<ExpandPolicy2>(collection2, total, index_vector2); + expand_to_collection<ExpandPolicy1, IncludePolicy1>(collection1, + total, index_vector1); + expand_to_collection<ExpandPolicy2, IncludePolicy2>(collection2, + total, index_vector2); detail::partition::partition_two_collections < - 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy + 0, Box, OverlapsPolicy1, OverlapsPolicy2, + ExpandPolicy1, ExpandPolicy2, VisitBoxPolicy >::apply(total, collection1, index_vector1, collection2, index_vector2, diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp index cd3acb5ba4..9db1ef8e0c 100644 --- a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp +++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp @@ -17,6 +17,7 @@ #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/condition.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry @@ -91,7 +92,7 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point, return true; } - if (! RobustPolicy::enabled) + if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled)) { return false; } diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp index 31d206ac99..2859841de4 100644 --- a/boost/geometry/algorithms/detail/relate/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp @@ -2,19 +2,21 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// 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/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> @@ -197,7 +199,7 @@ struct areal_areal // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; // get and analyse turns @@ -207,17 +209,17 @@ struct areal_areal interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result); turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(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 ) + if ( BOOST_GEOMETRY_CONDITION(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 ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; if ( turns.empty() ) @@ -242,7 +244,7 @@ struct areal_areal turns_analyser<turn_type, 0> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end()); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } @@ -257,7 +259,7 @@ struct areal_areal 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 ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } } @@ -281,7 +283,7 @@ struct areal_areal turns_analyser<turn_type, 1> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end()); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } @@ -549,7 +551,7 @@ struct areal_areal { analyser.apply(res, it); - if ( res.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(res.interrupt) ) return; } @@ -573,8 +575,7 @@ struct areal_areal { // 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) ) + if ( ! may_update<interior, interior, '2', transpose_result>(m_result) ) { m_flags |= 1; } @@ -595,7 +596,7 @@ struct areal_areal inline void no_turns(segment_identifier const& seg_id) { // if those flags are set nothing will change - if ( (m_flags & 3) == 3 ) + if ( m_flags == 7 ) { return; } @@ -614,15 +615,18 @@ struct areal_areal // 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) + // O(N) - running it in a loop 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; + + update<boundary, interior, '1', transpose_result>(m_result); + update<exterior, interior, '2', transpose_result>(m_result); + m_flags |= 4; } else { @@ -696,12 +700,6 @@ struct areal_areal 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 @@ -795,7 +793,8 @@ struct areal_areal { segment_identifier const& seg_id = turn.operations[OpId].seg_id; - int count = boost::numeric_cast<int>( + signed_index_type + count = boost::numeric_cast<signed_index_type>( geometry::num_interior_rings( detail::single_geometry(analyser.geometry, seg_id))); @@ -803,7 +802,10 @@ struct areal_areal } template <typename Analyser, typename Turn> - static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, int first, int last) + static inline void for_no_turns_rings(Analyser & analyser, + Turn const& turn, + signed_index_type first, + signed_index_type last) { segment_identifier seg_id = turn.operations[OpId].seg_id; diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp index 78fa03798d..2c44b009e7 100644 --- a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp +++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp @@ -14,6 +14,7 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> //#include <boost/geometry/algorithms/detail/sub_range.hpp> @@ -98,9 +99,9 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> std::vector<bool> detected_intersections(count, false); for ( TurnIt it = first ; it != last ; ++it ) { - int multi_index = it->operations[OpId].seg_id.multi_index; + signed_index_type 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); + std::size_t const index = static_cast<std::size_t>(multi_index); BOOST_ASSERT(index < count); detected_intersections[index] = true; } @@ -116,8 +117,8 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> if ( *it == false ) { found = true; - bool cont = pred(range::at(geometry, - std::distance(detected_intersections.begin(), it))); + std::size_t const index = std::size_t(std::distance(detected_intersections.begin(), it)); + bool cont = pred(range::at(geometry, index)); if ( !cont ) break; } @@ -375,14 +376,14 @@ static inline bool is_ip_on_boundary(IntersectionPoint const& ip, bool res = false; // IP on the last point of the linestring - if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) + if ( BOOST_GEOMETRY_CONDITION(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) + else if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) && operation_info.position == overlay::position_front ) { // check if this point is a boundary diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp index 3159ab329d..7d85a1d9a1 100644 --- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -2,21 +2,23 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// 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/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> @@ -193,6 +195,33 @@ struct linear_areal typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; + + template <typename Geometry> + struct is_multi + : boost::is_base_of + < + multi_tag, + typename tag<Geometry>::type + > + {}; + + template <typename Geom1, typename Geom2> + struct multi_turn_info + : turns::get_turns<Geom1, Geom2>::turn_info + { + multi_turn_info() : priority(0) {} + int priority; // single-geometry sorting priority + }; + + template <typename Geom1, typename Geom2> + struct turn_info_type + : boost::mpl::if_c + < + is_multi<Geometry2>::value, + multi_turn_info<Geom1, Geom2>, + typename turns::get_turns<Geom1, Geom2>::turn_info + > + {}; template <typename Result> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) @@ -202,17 +231,17 @@ struct linear_areal // 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 ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; // get and analyse turns - typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type; + typedef typename turn_info_type<Geometry1, Geometry2>::type 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 ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; boundary_checker<Geometry1> boundary_checker1(geometry1); @@ -224,12 +253,12 @@ struct linear_areal TransposeResult > pred1(geometry2, result, boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( 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 ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( turns.empty() ) @@ -238,14 +267,11 @@ struct linear_areal // 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 ) + if ( BOOST_GEOMETRY_CONDITION( 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()); + sort_dispatch(turns.begin(), turns.end(), is_multi<Geometry2>()); turns_analyser<turn_type> analyser; analyse_each_turn(result, analyser, @@ -253,7 +279,7 @@ struct linear_areal geometry1, geometry2, boundary_checker1); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; } @@ -297,7 +323,7 @@ struct linear_areal // if there was some previous ring if ( prev_seg_id_ptr != NULL ) { - int const next_ring_index = prev_seg_id_ptr->ring_index + 1; + signed_index_type 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 @@ -368,7 +394,7 @@ struct linear_areal // if there was some previous ring if ( prev_seg_id_ptr != NULL ) { - int const next_ring_index = prev_seg_id_ptr->ring_index + 1; + signed_index_type 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 @@ -383,6 +409,127 @@ struct linear_areal } } + template <typename It, typename Pred, typename Comp> + static void for_each_equal_range(It first, It last, Pred pred, Comp comp) + { + if ( first == last ) + return; + + It first_equal = first; + It prev = first; + for ( ++first ; ; ++first, ++prev ) + { + if ( first == last || !comp(*prev, *first) ) + { + pred(first_equal, first); + first_equal = first; + } + + if ( first == last ) + break; + } + } + + struct same_ip + { + template <typename Turn> + bool operator()(Turn const& left, Turn const& right) const + { + return left.operations[0].seg_id == right.operations[0].seg_id + && left.operations[0].fraction == right.operations[0].fraction; + } + }; + + struct same_ip_and_multi_index + { + template <typename Turn> + bool operator()(Turn const& left, Turn const& right) const + { + return same_ip()(left, right) + && left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index; + } + }; + + template <typename OpToPriority> + struct set_turns_group_priority + { + template <typename TurnIt> + void operator()(TurnIt first, TurnIt last) const + { + BOOST_ASSERT(first != last); + static OpToPriority op_to_priority; + // find the operation with the least priority + int least_priority = op_to_priority(first->operations[0]); + for ( TurnIt it = first + 1 ; it != last ; ++it ) + { + int priority = op_to_priority(it->operations[0]); + if ( priority < least_priority ) + least_priority = priority; + } + // set the least priority for all turns of the group + for ( TurnIt it = first ; it != last ; ++it ) + { + it->priority = least_priority; + } + } + }; + + template <typename SingleLess> + struct sort_turns_group + { + struct less + { + template <typename Turn> + bool operator()(Turn const& left, Turn const& right) const + { + return left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index ? + SingleLess()(left, right) : + left.priority < right.priority; + } + }; + + template <typename TurnIt> + void operator()(TurnIt first, TurnIt last) const + { + std::sort(first, last, less()); + } + }; + + template <typename TurnIt> + static void sort_dispatch(TurnIt first, TurnIt last, boost::true_type const& /*is_multi*/) + { + // sort turns by Linear seg_id, then by fraction, then by other multi_index + typedef turns::less<0, turns::less_other_multi_index<0> > less; + std::sort(first, last, less()); + + // For the same IP and multi_index - the same other's single geometry + // set priorities as the least operation found for the whole single geometry + // so e.g. single geometries containing 'u' will always be before those only containing 'i' + typedef turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic; + for_each_equal_range(first, last, + set_turns_group_priority<op_to_int_xuic>(), // least operation in xuic order + same_ip_and_multi_index()); // other's multi_index + + // When priorities for single geometries are set now sort turns for the same IP + // if multi_index is the same sort them according to the single-less + // else use priority of the whole single-geometry set earlier + typedef turns::less<0, turns::less_op_linear_areal_single<0> > single_less; + for_each_equal_range(first, last, + sort_turns_group<single_less>(), + same_ip()); + } + + template <typename TurnIt> + static void sort_dispatch(TurnIt first, TurnIt last, boost::false_type const& /*is_multi*/) + { + // sort turns by Linear seg_id, then by fraction, then + // for same ring id: x, u, i, c + // for different ring id: c, i, u, x + typedef turns::less<0, turns::less_op_linear_areal_single<0> > less; + std::sort(first, last, less()); + } + + // 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> @@ -458,6 +605,8 @@ struct linear_areal , m_boundary_counter(0) , m_interior_detected(false) , m_first_interior_other_id_ptr(NULL) + , m_first_from_unknown(false) + , m_first_from_unknown_boundary_detected(false) {} template <typename Result, @@ -485,6 +634,11 @@ struct linear_areal const bool first_in_range = m_seg_watcher.update(seg_id); + // TODO: should apply() for the post-last ip be called if first_in_range ? + // this would unify how last points in ranges are handled + // possibly replacing parts of the code below + // e.g. for is_multi and m_interior_detected + // handle possible exit bool fake_enter_detected = false; if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) @@ -495,8 +649,24 @@ struct linear_areal { m_exit_watcher.reset_detected_exit(); - // not the last IP update<interior, exterior, '1', TransposeResult>(res); + + // next single geometry + if ( first_in_range && m_previous_turn_ptr ) + { + // NOTE: similar code is in the post-last-ip-apply() + 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); + } + } } // fake exit point, reset state else if ( op == overlay::operation_intersection @@ -508,9 +678,12 @@ struct linear_areal } else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) { - // ignore multiple BLOCKs - if ( op == overlay::operation_blocked ) + // ignore multiple BLOCKs for this same single geometry1 + if ( op == overlay::operation_blocked + && seg_id.multi_index == m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) + { return; + } if ( ( op == overlay::operation_intersection || op == overlay::operation_continue ) @@ -522,11 +695,39 @@ struct linear_areal m_exit_watcher.reset_detected_exit(); } + if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) + && m_first_from_unknown ) + { + // For MultiPolygon many x/u operations may be generated as a first IP + // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString + // then we know that the LineString is outside + // Similar with the u/u turns, if it was the first one it doesn't mean that the + // Linestring came from the exterior + if ( ( m_previous_operation == overlay::operation_blocked + && ( op != overlay::operation_blocked // operation different than block + || seg_id.multi_index != m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) ) // or the next single-geometry + || ( m_previous_operation == overlay::operation_union + && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + ) + { + update<interior, exterior, '1', TransposeResult>(res); + if ( m_first_from_unknown_boundary_detected ) + { + update<boundary, exterior, '0', TransposeResult>(res); + } + + m_first_from_unknown = false; + m_first_from_unknown_boundary_detected = false; + } + } + // 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 +// UPDATE: THEY SHOULD BE NORMALIZED NOW + // TODO: THIS IS POTENTIALLY ERROREOUS! // THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS // IT WOULD GIVE WRONG RESULTS E.G. @@ -540,6 +741,30 @@ struct linear_areal { update<interior, interior, '1', TransposeResult>(res); m_interior_detected = false; + + // new range detected - reset previous state and check the boundary + if ( first_in_range ) + { + // actually it should be != NULL if m_interior_detected + // so an assert could be checked here + if ( 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); + } + } + + // The exit_watcher is reset below + // m_exit_watcher.reset(); + } } // fake interior overlap else if ( op == overlay::operation_continue ) @@ -560,10 +785,20 @@ struct linear_areal } } + // NOTE: If post-last-ip apply() was called this wouldn't be needed + if ( first_in_range ) + { + m_exit_watcher.reset(); + m_boundary_counter = 0; + m_first_from_unknown = false; + m_first_from_unknown_boundary_detected = false; + } + // i/u, c/u if ( op == overlay::operation_intersection || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection { + bool const first_point = first_in_range || m_first_from_unknown; bool no_enters_detected = m_exit_watcher.is_outside(); m_exit_watcher.enter(*it); @@ -592,7 +827,7 @@ struct linear_areal { // 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 ) + if ( first_point || !it->operations[op_id].is_collinear ) ++m_boundary_counter; update<interior, boundary, '1', TransposeResult>(res); @@ -619,7 +854,7 @@ struct linear_areal && 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 + bool const from_inside = first_point && calculate_from_inside(geometry, other_geometry, *it); @@ -630,7 +865,7 @@ struct linear_areal update<interior, exterior, '1', TransposeResult>(res); // if it's the first IP then the first point is outside - if ( first_in_range ) + if ( first_point ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), @@ -647,6 +882,12 @@ struct linear_areal } } } + + if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) ) + { + m_first_from_unknown = false; + m_first_from_unknown_boundary_detected = false; + } } // u/u, x/u else if ( op == overlay::operation_union || op == overlay::operation_blocked ) @@ -709,7 +950,11 @@ struct linear_areal 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 + // NOTE: this is not enough for MultiPolygon and operation_blocked + // For LS/MultiPolygon multiple x/u turns may be generated + // the first checked Polygon may be the one which LS is outside for. + bool const first_point = first_in_range || m_first_from_unknown; + bool const first_from_inside = first_point && calculate_from_inside(geometry, other_geometry, *it); @@ -719,14 +964,26 @@ struct linear_areal // notify the exit_watcher that we started inside m_exit_watcher.enter(*it); + // and reset unknown flags since we know that we started inside + m_first_from_unknown = false; + m_first_from_unknown_boundary_detected = false; } else { - update<interior, exterior, '1', TransposeResult>(res); + if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) + /*&& ( op == overlay::operation_blocked + || op == overlay::operation_union )*/ ) // if we're here it's u or x + { + m_first_from_unknown = true; + } + 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 ) ) + if ( first_point && ( !this_b || op_blocked ) ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), @@ -736,9 +993,23 @@ struct linear_areal if ( front_b ) { if ( first_from_inside ) + { update<boundary, interior, '0', TransposeResult>(res); + } else - update<boundary, exterior, '0', TransposeResult>(res); + { + if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) + /*&& ( op == overlay::operation_blocked + || op == overlay::operation_union )*/ ) // if we're here it's u or x + { + BOOST_ASSERT(m_first_from_unknown); + m_first_from_unknown_boundary_detected = true; + } + else + { + update<boundary, exterior, '0', TransposeResult>(res); + } + } } } } @@ -774,6 +1045,23 @@ struct linear_areal boost::ignore_unused(first, last); //BOOST_ASSERT( first != last ); + // For MultiPolygon many x/u operations may be generated as a first IP + // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString + // then we know that the LineString is outside + if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) + && m_first_from_unknown ) + { + update<interior, exterior, '1', TransposeResult>(res); + if ( m_first_from_unknown_boundary_detected ) + { + update<boundary, exterior, '0', TransposeResult>(res); + } + + // done below + //m_first_from_unknown = false; + //m_first_from_unknown_boundary_detected = false; + } + // 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 @@ -822,12 +1110,37 @@ struct linear_areal } } - BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue, - "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)"); + // This condition may be false if the Linestring is lying on the Polygon's collinear spike + // if Polygon's spikes are not handled in get_turns() or relate() (they currently aren't) + //BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue, + // "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)"); + // Currently one c/c turn is generated for the exit + // when a Linestring is going out on a collinear spike + // When a Linestring is going in on a collinear spike + // the turn is not generated for the entry + // So assume it's the former + if ( m_previous_operation == overlay::operation_continue ) + { + update<interior, exterior, '1', TransposeResult>(res); + + 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); + } + } // Reset exit watcher before the analysis of the next Linestring m_exit_watcher.reset(); m_boundary_counter = 0; + m_first_from_unknown = false; + m_first_from_unknown_boundary_detected = false; } // check if the passed turn's segment of Linear geometry arrived @@ -852,8 +1165,8 @@ struct linear_areal 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; + std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index); + std::size_t const q_seg_ij = static_cast<std::size_t>(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); @@ -876,7 +1189,7 @@ struct linear_areal // 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, + range::pos(range2, q_seg_jk), boost::end(range2)); // Will this sequence of points be always correct? @@ -945,6 +1258,8 @@ struct linear_areal unsigned m_boundary_counter; bool m_interior_detected; const segment_identifier * m_first_interior_other_id_ptr; + bool m_first_from_unknown; + bool m_first_from_unknown_boundary_detected; }; // call analyser.apply() for each turn in range @@ -971,7 +1286,7 @@ struct linear_areal geometry, other_geometry, boundary_checker); - if ( res.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) return; } @@ -1017,8 +1332,8 @@ struct linear_areal 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; + signed_index_type const multi_index = first->operations[1].seg_id.multi_index; + signed_index_type const ring_index = first->operations[1].seg_id.ring_index; fun(*first); ++first; diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 263c82de56..20a22c3018 100644 --- a/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -2,8 +2,8 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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 @@ -16,6 +16,7 @@ #include <boost/core/ignore_unused.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> @@ -117,7 +118,7 @@ struct linear_linear { // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; // get and analyse turns @@ -133,19 +134,19 @@ struct linear_linear detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> > >::apply(turns, geometry1, geometry2, interrupt_policy); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( 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 ) + if ( BOOST_GEOMETRY_CONDITION( 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 ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( turns.empty() ) @@ -171,7 +172,7 @@ struct linear_linear boundary_checker1, boundary_checker2); } - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( may_update<interior, interior, '1', true>(result) @@ -250,6 +251,7 @@ struct linear_linear : m_previous_turn_ptr(NULL) , m_previous_operation(overlay::operation_none) , m_degenerated_turn_ptr(NULL) + , m_collinear_spike_exit(false) {} template <typename Result, @@ -383,7 +385,8 @@ struct linear_linear // 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 ) + && it->operations[op_id].position != overlay::position_front + && ! m_collinear_spike_exit ) { update<interior, exterior, '1', transpose_result>(res); @@ -402,6 +405,8 @@ struct linear_linear } } } + + m_collinear_spike_exit = false; } // u/i, u/u, u/x, x/i, x/u, x/x else if ( op == overlay::operation_union || op == overlay::operation_blocked ) @@ -418,6 +423,11 @@ struct linear_linear if ( !was_outside && is_collinear ) { m_exit_watcher.exit(*it, false); + // if the position is not set to back it must be a spike + if ( it->operations[op_id].position != overlay::position_back ) + { + m_collinear_spike_exit = true; + } } bool const op_blocked = op == overlay::operation_blocked; @@ -456,6 +466,7 @@ struct linear_linear // if we are truly outside if ( was_outside && it->operations[op_id].position != overlay::position_front + && ! m_collinear_spike_exit /*&& !is_collinear*/ ) { update<interior, exterior, '1', transpose_result>(res); @@ -526,6 +537,7 @@ struct linear_linear && ( !this_b || op_blocked ) && was_outside && it->operations[op_id].position != overlay::position_front + && ! m_collinear_spike_exit /*&& !is_collinear*/ ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( @@ -607,6 +619,10 @@ struct linear_linear m_previous_turn_ptr = NULL; m_previous_operation = overlay::operation_none; m_degenerated_turn_ptr = NULL; + + // actually if this is set to true here there is some error + // in get_turns_ll or relate_ll, an assert could be checked here + m_collinear_spike_exit = false; } template <typename Result, @@ -724,6 +740,7 @@ struct linear_linear const TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; const TurnInfo * m_degenerated_turn_ptr; + bool m_collinear_spike_exit; }; template <typename Result, @@ -750,7 +767,7 @@ struct linear_linear geometry, other_geometry, boundary_checker, other_boundary_checker); - if ( res.interrupt ) + if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) return; } diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp index 86c236d357..62ab100919 100644 --- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp +++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp @@ -2,15 +2,15 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// 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 @@ -20,6 +20,8 @@ #include <boost/geometry/algorithms/detail/relate/topology_check.hpp> +#include <boost/geometry/util/condition.hpp> + namespace boost { namespace geometry { @@ -54,7 +56,7 @@ struct point_geometry set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); - if ( result.interrupt ) + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; // the point is on the boundary diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp index 1bcb5275d2..e26bda67f2 100644 --- a/boost/geometry/algorithms/detail/relate/result.hpp +++ b/boost/geometry/algorithms/detail/relate/result.hpp @@ -2,15 +2,15 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// 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 @@ -24,6 +24,7 @@ #include <boost/mpl/vector_c.hpp> #include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/util/condition.hpp> // TEMP - move this header to geometry/detail #include <boost/geometry/index/detail/tuples.hpp> @@ -235,17 +236,17 @@ struct interrupt_dispatch<Mask, true> static inline bool apply(Mask const& mask) { char m = mask.template get<F1, F2>(); - return check<V>(m); + return check_element<V>(m); } template <char V> - static inline bool check(char m) + static inline bool check_element(char m) { - if ( V >= '0' && V <= '9' ) + if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') ) { return m == 'F' || ( m < V && m >= '0' && m <= '9' ); } - else if ( V == 'T' ) + else if ( BOOST_GEOMETRY_CONDITION(V == 'T') ) { return m == 'F'; } @@ -394,7 +395,7 @@ inline bool may_update(Mask const& mask, Matrix const& matrix) ::template apply<F1, F2, D>(mask, matrix); } -// check() +// check_matrix() template <typename Mask> struct check_dispatch @@ -485,7 +486,7 @@ struct check_dispatch< boost::tuples::cons<Head, Tail> > }; template <typename Mask, typename Matrix> -inline bool check(Mask const& mask, Matrix const& matrix) +inline bool check_matrix(Mask const& mask, Matrix const& matrix) { return check_dispatch<Mask>::apply(mask, matrix); } @@ -546,7 +547,7 @@ public: result_type result() const { return !interrupt - && check(m_mask, static_cast<base_t const&>(*this)); + && check_matrix(m_mask, static_cast<base_t const&>(*this)); } template <field F1, field F2, char D> @@ -964,7 +965,7 @@ struct static_check_dispatch<StaticMask, true> }; template <typename StaticMask> -struct static_check +struct static_check_matrix { template <typename Matrix> static inline bool apply(Matrix const& matrix) @@ -997,7 +998,7 @@ public: result_type result() const { return (!Interrupt || !interrupt) - && static_check<StaticMask>:: + && static_check_matrix<StaticMask>:: apply(static_cast<base_t const&>(*this)); } diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp index a2e56a8882..636c9756d8 100644 --- a/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/boost/geometry/algorithms/detail/relate/turns.hpp @@ -1,16 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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 // Use, modification and distribution is subject to the 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 @@ -19,8 +20,12 @@ #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> + #include <boost/type_traits/is_base_of.hpp> + namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL @@ -35,10 +40,16 @@ struct assign_policy // GET_TURNS -template <typename Geometry1, - typename Geometry2, - typename GetTurnPolicy - = detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > > +template +< + typename Geometry1, + typename Geometry2, + typename GetTurnPolicy = detail::get_turns::get_turn_info_type + < + Geometry1, Geometry2, assign_policy<> + >, + typename RobustPolicy = detail::no_rescale_policy +> struct get_turns { typedef typename geometry::point_type<Geometry1>::type point1_type; @@ -46,11 +57,14 @@ struct get_turns typedef overlay::turn_info < point1_type, - typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type, + typename segment_ratio_type<point1_type, RobustPolicy>::type, typename detail::get_turns::turn_operation_type < Geometry1, Geometry2, - typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type + typename segment_ratio_type + < + point1_type, RobustPolicy + >::type >::type > turn_info; @@ -73,6 +87,12 @@ struct get_turns 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; + RobustPolicy robust_policy = geometry::get_rescale_policy + < + RobustPolicy + >(geometry1, geometry2); + + dispatch::get_turns < typename geometry::tag<Geometry1>::type, @@ -83,7 +103,7 @@ struct get_turns reverse2, GetTurnPolicy >::apply(0, geometry1, 1, geometry2, - detail::no_rescale_policy(), turns, interrupt_policy); + robust_policy, turns, interrupt_policy); } }; @@ -125,7 +145,7 @@ struct less_op_linear_linear {}; template <std::size_t OpId> -struct less_op_linear_areal +struct less_op_linear_areal_single { template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const @@ -137,27 +157,19 @@ struct less_op_linear_areal 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]; + 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); - } + 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_xuic(left.operations[OpId]) < op_to_int_xuic(right.operations[OpId]); - return left_other_seg_id.multi_index < right_other_seg_id.multi_index; + return op_to_int_xiuc(left_operation) + < op_to_int_xiuc(right_operation); } } }; @@ -217,6 +229,19 @@ struct less_op_areal_areal } }; +template <std::size_t OpId> +struct less_other_multi_index +{ + static const std::size_t other_op_id = (OpId + 1) % 2; + + template <typename Turn> + inline bool operator()(Turn const& left, Turn const& right) const + { + return left.operations[other_op_id].seg_id.multi_index + < right.operations[other_op_id].seg_id.multi_index; + } +}; + // sort turns by G1 - source_index == 0 by: // seg_id -> distance -> operation template <std::size_t OpId = 0, diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp index 63feb12a71..d139a3fdd2 100644 --- a/boost/geometry/algorithms/detail/sections/range_by_section.hpp +++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp @@ -58,7 +58,8 @@ struct full_section_polygon { return section.ring_id.ring_index < 0 ? geometry::exterior_ring(polygon) - : range::at(geometry::interior_rings(polygon), section.ring_id.ring_index); + : range::at(geometry::interior_rings(polygon), + static_cast<std::size_t>(section.ring_id.ring_index)); } }; @@ -74,13 +75,15 @@ struct full_section_multi static inline typename ring_return_type<MultiGeometry const>::type apply( MultiGeometry const& multi, Section const& section) { + typedef typename boost::range_size<MultiGeometry>::type size_type; + BOOST_ASSERT ( section.ring_id.multi_index >= 0 - && section.ring_id.multi_index < int(boost::size(multi)) + && size_type(section.ring_id.multi_index) < boost::size(multi) ); - return Policy::apply(range::at(multi, section.ring_id.multi_index), section); + return Policy::apply(range::at(multi, size_type(section.ring_id.multi_index)), section); } }; diff --git a/boost/geometry/algorithms/detail/sections/section_box_policies.hpp b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp new file mode 100644 index 0000000000..cf06700306 --- /dev/null +++ b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp @@ -0,0 +1,49 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015 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_SECTIONS_SECTION_BOX_POLICIES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP + + +#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> +#include <boost/geometry/algorithms/expand.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace section +{ + +struct get_section_box +{ + template <typename Box, typename Section> + static inline void apply(Box& total, Section const& section) + { + geometry::expand(total, section.bounding_box); + } +}; + +struct overlaps_section_box +{ + template <typename Box, typename Section> + static inline bool apply(Box const& box, Section const& section) + { + return ! detail::disjoint::disjoint_box_box(box, section.bounding_box); + } +}; + + +}} // namespace detail::section +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp new file mode 100644 index 0000000000..ba1cf931b2 --- /dev/null +++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015 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_SECTIONS_FUNCTIONS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP + + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace section +{ + +template +< + std::size_t Dimension, + typename Point, + typename RobustBox, + typename RobustPolicy +> +static inline bool preceding(int dir, Point const& point, + RobustBox const& robust_box, + RobustPolicy const& robust_policy) +{ + typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box)) + || (dir == -1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box)); +} + +template +< + std::size_t Dimension, + typename Point, + typename RobustBox, + typename RobustPolicy +> +static inline bool exceeding(int dir, Point const& point, + RobustBox const& robust_box, + RobustPolicy const& robust_policy) +{ + typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box)) + || (dir == -1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box)); +} + + +}} // namespace detail::section +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 250577c0c2..a744ea0a34 100644 --- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -8,6 +8,9 @@ // 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. @@ -15,8 +18,6 @@ // 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 @@ -25,7 +26,9 @@ #include <boost/concept/requires.hpp> #include <boost/mpl/assert.hpp> +#include <boost/mpl/vector_c.hpp> #include <boost/range.hpp> +#include <boost/static_assert.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/expand.hpp> @@ -63,12 +66,15 @@ namespace boost { namespace geometry \tparam DimensionCount number of dimensions for this section \ingroup sectionalize */ -template <typename Box, std::size_t DimensionCount> +template +< + typename Box, + std::size_t DimensionCount +> struct section { typedef Box box_type; - - int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this + static std::size_t const dimension_count = DimensionCount; int directions[DimensionCount]; ring_identifier ring_id; @@ -85,8 +91,7 @@ struct section bool is_non_duplicate_last; inline section() - : id(-1) - , begin_index(-1) + : begin_index(-1) , end_index(-1) , count(0) , range_count(0) @@ -122,75 +127,83 @@ struct sections : std::vector<section<Box, DimensionCount> > namespace detail { namespace sectionalize { -template <std::size_t Dimension, std::size_t DimensionCount> +template +< + typename DimensionVector, + std::size_t Index, + std::size_t Count +> struct get_direction_loop { + typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension; + template <typename Segment> static inline void apply(Segment const& seg, - int directions[DimensionCount]) + int directions[Count]) { typedef typename coordinate_type<Segment>::type coordinate_type; + coordinate_type const diff = - geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg); + geometry::get<1, dimension::value>(seg) + - geometry::get<0, dimension::value>(seg); coordinate_type zero = coordinate_type(); - directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0; + directions[Index] = diff > zero ? 1 : diff < zero ? -1 : 0; get_direction_loop - < - Dimension + 1, DimensionCount - >::apply(seg, directions); + < + DimensionVector, + Index + 1, + Count + >::apply(seg, directions); } }; -template <std::size_t DimensionCount> -struct get_direction_loop<DimensionCount, DimensionCount> +template <typename DimensionVector, std::size_t Count> +struct get_direction_loop<DimensionVector, Count, Count> { template <typename Segment> - static inline void apply(Segment const&, int [DimensionCount]) + static inline void apply(Segment const&, int [Count]) {} }; -template <typename T, std::size_t Dimension, std::size_t DimensionCount> +//! Copy one static array to another +template <typename T, std::size_t Index, std::size_t Count> struct copy_loop { - static inline void apply(T const source[DimensionCount], - T target[DimensionCount]) + static inline void apply(T const source[Count], T target[Count]) { - target[Dimension] = source[Dimension]; - copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target); + target[Index] = source[Index]; + copy_loop<T, Index + 1, Count>::apply(source, target); } }; -template <typename T, std::size_t DimensionCount> -struct copy_loop<T, DimensionCount, DimensionCount> +template <typename T, std::size_t Count> +struct copy_loop<T, Count, Count> { - static inline void apply(T const [DimensionCount], T [DimensionCount]) + static inline void apply(T const [Count], T [Count]) {} }; -template <typename T, std::size_t Dimension, std::size_t DimensionCount> +//! Compare two static arrays +template <typename T, std::size_t Index, std::size_t Count> struct compare_loop { - static inline bool apply(T const source[DimensionCount], - T const target[DimensionCount]) + static inline bool apply(T const array1[Count], T const array2[Count]) { - bool const not_equal = target[Dimension] != source[Dimension]; - - return not_equal + return array1[Index] != array2[Index] ? false : compare_loop < - T, Dimension + 1, DimensionCount - >::apply(source, target); + T, Index + 1, Count + >::apply(array1, array2); } }; -template <typename T, std::size_t DimensionCount> -struct compare_loop<T, DimensionCount, DimensionCount> +template <typename T, std::size_t Count> +struct compare_loop<T, Count, Count> { - static inline bool apply(T const [DimensionCount], - T const [DimensionCount]) + static inline bool apply(T const [Count], T const [Count]) { return true; @@ -215,9 +228,9 @@ struct check_duplicate_loop } return check_duplicate_loop - < + < Dimension + 1, DimensionCount - >::apply(seg); + >::apply(seg); } }; @@ -231,20 +244,21 @@ struct check_duplicate_loop<DimensionCount, DimensionCount> } }; -template <typename T, std::size_t Dimension, std::size_t DimensionCount> +//! Assign a value to a static array +template <typename T, std::size_t Index, std::size_t Count> struct assign_loop { - static inline void apply(T dims[DimensionCount], int const value) + static inline void apply(T dims[Count], int const value) { - dims[Dimension] = value; - assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value); + dims[Index] = value; + assign_loop<T, Index + 1, Count>::apply(dims, value); } }; -template <typename T, std::size_t DimensionCount> -struct assign_loop<T, DimensionCount, DimensionCount> +template <typename T, std::size_t Count> +struct assign_loop<T, Count, Count> { - static inline void apply(T [DimensionCount], int const) + static inline void apply(T [Count], int const) { } }; @@ -253,35 +267,42 @@ struct assign_loop<T, DimensionCount, DimensionCount> template < typename Point, - std::size_t DimensionCount + typename DimensionVector > struct sectionalize_part { + static const std::size_t dimension_count + = boost::mpl::size<DimensionVector>::value; + template < - typename Range, // Can be closeable_view + typename Iterator, typename RobustPolicy, typename Sections > static inline void apply(Sections& sections, - Range const& range, + Iterator begin, Iterator end, 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 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; + BOOST_STATIC_ASSERT + ( + (static_cast<int>(section_type::dimension_count) + == static_cast<int>(boost::mpl::size<DimensionVector>::value)) + ); - if ( boost::empty(range) ) + typedef typename geometry::robust_point_type + < + Point, + RobustPolicy + >::type robust_point_type; + + std::size_t const count = std::distance(begin, end); + if (count == 0) { return; } @@ -293,21 +314,24 @@ struct sectionalize_part bool mark_first_non_duplicated = true; std::size_t last_non_duplicate_index = sections.size(); - iterator_type it = boost::begin(range); + Iterator it = begin; + robust_point_type previous_robust_point; + geometry::recalculate(previous_robust_point, *it, robust_policy); - for(iterator_type previous = it++; - it != boost::end(range); + for(Iterator previous = it++; + it != end; ++previous, ++it, index++) { - segment_type segment(*previous, *it); - robust_segment_type robust_segment; - geometry::recalculate(robust_segment, segment, robust_policy); + robust_point_type current_robust_point; + geometry::recalculate(current_robust_point, *it, robust_policy); + model::referring_segment<robust_point_type> robust_segment( + previous_robust_point, current_robust_point); - int direction_classes[DimensionCount] = {0}; + int direction_classes[dimension_count] = {0}; get_direction_loop - < - 0, DimensionCount - >::apply(robust_segment, direction_classes); + < + DimensionVector, 0, dimension_count + >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. // Those sections might be omitted, if wished, lateron @@ -317,7 +341,7 @@ struct sectionalize_part { // Recheck because ALL dimensions should be checked, // not only first one. - // (DimensionCount might be < dimension<P>::value) + // (dimension_count might be < dimension<P>::value) if (check_duplicate_loop < 0, geometry::dimension<Point>::type::value @@ -332,21 +356,20 @@ struct sectionalize_part // Actual value is not important as long as it is not -1,0,1 assign_loop < - int, 0, DimensionCount + int, 0, dimension_count >::apply(direction_classes, -99); } } if (section.count > 0 - && (!compare_loop + && (! compare_loop < - int, 0, DimensionCount + int, 0, dimension_count >::apply(direction_classes, section.directions) - || section.count > max_count - ) + || section.count > max_count) ) { - if ( !section.duplicate ) + if (! section.duplicate) { last_non_duplicate_index = sections.size(); } @@ -361,9 +384,9 @@ struct sectionalize_part section.ring_id = ring_id; section.duplicate = duplicate; section.non_duplicate_index = ndi; - section.range_count = boost::size(range); + section.range_count = count; - if ( mark_first_non_duplicated && !duplicate ) + if (mark_first_non_duplicated && ! duplicate) { section.is_non_duplicate_first = true; mark_first_non_duplicated = false; @@ -371,25 +394,26 @@ struct sectionalize_part copy_loop < - int, 0, DimensionCount + int, 0, dimension_count >::apply(direction_classes, section.directions); - expand_box(*previous, robust_policy, section); + geometry::expand(section.bounding_box, previous_robust_point); } - expand_box(*it, robust_policy, section); + geometry::expand(section.bounding_box, current_robust_point); section.end_index = index + 1; section.count++; if (! duplicate) { ndi++; } + previous_robust_point = current_robust_point; } // Add last section if applicable if (section.count > 0) { - if ( !section.duplicate ) + if (! section.duplicate) { last_non_duplicate_index = sections.size(); } @@ -397,30 +421,21 @@ struct sectionalize_part sections.push_back(section); } - if ( last_non_duplicate_index < sections.size() - && !sections[last_non_duplicate_index].duplicate ) + 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 < - closure_selector Closure, bool Reverse, + closure_selector Closure, + bool Reverse, typename Point, - std::size_t DimensionCount + typename DimensionVector > struct sectionalize_range { @@ -432,13 +447,12 @@ struct sectionalize_range > 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 + typedef typename closeable_view<Range const, Closure>::type cview_type; + typedef typename reversible_view < cview_type const, Reverse ? iterate_reverse : iterate_forward @@ -460,15 +474,16 @@ struct sectionalize_range return; } - sectionalize_part<Point, DimensionCount> - ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count); + sectionalize_part<Point, DimensionVector>::apply(sections, + boost::begin(view), boost::end(view), + robust_policy, ring_id, max_count); } }; template < bool Reverse, - std::size_t DimensionCount + typename DimensionVector > struct sectionalize_polygon { @@ -480,20 +495,18 @@ struct sectionalize_polygon > 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 sectionalize_range - < + < closure<Polygon>::value, Reverse, - point_type, DimensionCount - > per_range; + point_type, DimensionVector + > per_range; ring_id.ring_index = -1; - per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count); + per_range::apply(exterior_ring(poly), robust_policy, sections, ring_id, max_count); ring_id.ring_index++; typename interior_return_type<Polygon const>::type @@ -501,15 +514,12 @@ struct sectionalize_polygon for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index) { - per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); + per_range::apply(*it, robust_policy, sections, ring_id, max_count); } } }; -template -< - std::size_t DimensionCount -> +template <typename DimensionVector> struct sectionalize_box { template @@ -520,7 +530,6 @@ struct sectionalize_box > 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) { @@ -547,16 +556,16 @@ struct sectionalize_box points.push_back(ll); sectionalize_range - < + < closed, false, - point_type, - DimensionCount - >::apply(points, robust_policy, make_rescaled_boxes, sections, - ring_id, max_count); + point_type, + DimensionVector + >::apply(points, robust_policy, sections, + ring_id, max_count); } }; -template <std::size_t DimensionCount, typename Policy> +template <typename DimensionVector, typename Policy> struct sectionalize_multi { template @@ -567,7 +576,6 @@ struct sectionalize_multi > 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; @@ -576,25 +584,12 @@ struct sectionalize_multi it != boost::end(multi); ++it, ++ring_id.multi_index) { - Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); + Policy::apply(*it, robust_policy, sections, ring_id, max_count); } } }; template <typename Sections> -inline void set_section_unique_ids(Sections& sections) -{ - // Set ID's. - int index = 0; - for (typename boost::range_iterator<Sections>::type it = boost::begin(sections); - it != boost::end(sections); - ++it) - { - it->id = index++; - } -} - -template <typename Sections> inline void enlarge_sections(Sections& sections) { // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border) @@ -631,7 +626,7 @@ template typename Tag, typename Geometry, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > struct sectionalize { @@ -646,29 +641,29 @@ template < typename Box, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > -struct sectionalize<box_tag, Box, Reverse, DimensionCount> - : detail::sectionalize::sectionalize_box<DimensionCount> +struct sectionalize<box_tag, Box, Reverse, DimensionVector> + : detail::sectionalize::sectionalize_box<DimensionVector> {}; template < typename LineString, - std::size_t DimensionCount + typename DimensionVector > struct sectionalize < linestring_tag, LineString, false, - DimensionCount + DimensionVector > : detail::sectionalize::sectionalize_range < closed, false, typename point_type<LineString>::type, - DimensionCount + DimensionVector > {}; @@ -676,14 +671,14 @@ template < typename Ring, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > -struct sectionalize<ring_tag, Ring, Reverse, DimensionCount> +struct sectionalize<ring_tag, Ring, Reverse, DimensionVector> : detail::sectionalize::sectionalize_range < geometry::closure<Ring>::value, Reverse, typename point_type<Ring>::type, - DimensionCount + DimensionVector > {}; @@ -691,12 +686,12 @@ template < typename Polygon, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > -struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount> +struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector> : detail::sectionalize::sectionalize_polygon < - Reverse, DimensionCount + Reverse, DimensionVector > {}; @@ -704,16 +699,16 @@ template < typename MultiPolygon, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > -struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount> +struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector> : detail::sectionalize::sectionalize_multi < - DimensionCount, + DimensionVector, detail::sectionalize::sectionalize_polygon < Reverse, - DimensionCount + DimensionVector > > @@ -723,17 +718,17 @@ template < typename MultiLinestring, bool Reverse, - std::size_t DimensionCount + typename DimensionVector > -struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount> +struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector> : detail::sectionalize::sectionalize_multi < - DimensionCount, + DimensionVector, detail::sectionalize::sectionalize_range < closed, false, typename point_type<MultiLinestring>::type, - DimensionCount + DimensionVector > > @@ -750,54 +745,61 @@ struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCou \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 + \param max_count maximal number of points per section + (defaults to 10, this seems to give the fastest results) + */ -template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy> +template +< + bool Reverse, + typename DimensionVector, + 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) + int source_index = 0, + std::size_t max_count = 10) { concept::check<Geometry const>(); + typedef typename boost::range_value<Sections>::type section_type; + + // Compiletime check for point type of section boxes + // and point type related to robust policy + typedef typename geometry::coordinate_type + < + typename section_type::box_type + >::type ctype1; + typedef typename geometry::coordinate_type + < + typename geometry::robust_point_type + < + typename geometry::point_type<Geometry>::type, + RobustPolicy + >::type + >::type ctype2; + + BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>)); + + 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 dispatch::sectionalize < typename tag<Geometry>::type, Geometry, Reverse, - Sections::value - >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10); - - 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); + DimensionVector + >::apply(geometry, robust_policy, sections, ring_id, max_count); } -#endif }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/single_geometry.hpp b/boost/geometry/algorithms/detail/single_geometry.hpp index c65ff8bf84..f38295ada6 100644 --- a/boost/geometry/algorithms/detail/single_geometry.hpp +++ b/boost/geometry/algorithms/detail/single_geometry.hpp @@ -55,7 +55,8 @@ struct single_geometry<Geometry, true> static inline return_type apply(Geometry & g, Id const& id) { BOOST_ASSERT(id.multi_index >= 0); - return range::at(g, id.multi_index); + typedef typename boost::range_size<Geometry>::type size_type; + return range::at(g, static_cast<size_type>(id.multi_index)); } }; diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp index a68f31362a..eda3ce58ba 100644 --- a/boost/geometry/algorithms/detail/sub_range.hpp +++ b/boost/geometry/algorithms/detail/sub_range.hpp @@ -44,7 +44,7 @@ struct sub_range<Geometry, Tag, false> template <typename Geometry> struct sub_range<Geometry, polygon_tag, false> { - typedef typename geometry::ring_type<Geometry>::type & return_type; + typedef typename geometry::ring_return_type<Geometry>::type return_type; template <typename Id> static inline return_type apply(Geometry & geometry, Id const& id) @@ -55,7 +55,11 @@ struct sub_range<Geometry, polygon_tag, false> } else { - std::size_t ri = static_cast<std::size_t>(id.ring_index); + typedef typename boost::range_size + < + typename geometry::interior_type<Geometry>::type + >::type size_type; + size_type const ri = static_cast<size_type>(id.ring_index); return range::at(geometry::interior_rings(geometry), ri); } } @@ -81,7 +85,9 @@ struct sub_range<Geometry, Tag, true> 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); + typedef typename boost::range_size<Geometry>::type size_type; + size_type const mi = static_cast<size_type>(id.multi_index); + return sub_sub_range::apply(range::at(geometry, mi), id); } }; diff --git a/boost/geometry/algorithms/detail/turns/print_turns.hpp b/boost/geometry/algorithms/detail/turns/print_turns.hpp index b339e11c94..9d4e45c41f 100644 --- a/boost/geometry/algorithms/detail/turns/print_turns.hpp +++ b/boost/geometry/algorithms/detail/turns/print_turns.hpp @@ -10,9 +10,9 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP +#include <algorithm> #include <iostream> -#include <boost/foreach.hpp> #include <boost/range.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> @@ -27,21 +27,16 @@ 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) +struct turn_printer { - typedef typename boost::range_value<Turns>::type turn_info; + turn_printer(std::ostream & os) + : index(0) + , out(os) + {} - std::cout << geometry::wkt(g1) << std::endl; - std::cout << geometry::wkt(g2) << std::endl; - int index = 0; - BOOST_FOREACH(turn_info const& turn, turns) + template <typename Turn> + void operator()(Turn const& turn) { - std::ostream& out = std::cout; out << index << ": " << geometry::method_char(turn.method); @@ -81,8 +76,22 @@ static inline void print_turns(Geometry1 const& g1, out << ' ' << geometry::dsv(turn.point) << ' '; ++index; - std::cout << std::endl; + out << std::endl; } + + int index; + std::ostream & out; +}; + +template <typename Geometry1, typename Geometry2, typename Turns> +static inline void print_turns(Geometry1 const& g1, + Geometry2 const& g2, + Turns const& turns) +{ + std::cout << geometry::wkt(g1) << std::endl; + std::cout << geometry::wkt(g2) << std::endl; + + std::for_each(boost::begin(turns), boost::end(turns), turn_printer(std::cout)); } diff --git a/boost/geometry/algorithms/detail/vincenty_direct.hpp b/boost/geometry/algorithms/detail/vincenty_direct.hpp new file mode 100644 index 0000000000..775687cfdb --- /dev/null +++ b/boost/geometry/algorithms/detail/vincenty_direct.hpp @@ -0,0 +1,190 @@ +// Boost.Geometry + +// 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_VINCENTY_DIRECT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_DIRECT_HPP + + +#include <boost/math/constants/constants.hpp> + +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/algorithms/detail/flattening.hpp> + + +#ifndef BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS +#define BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS 1000 +#endif + + +namespace boost { namespace geometry { namespace detail +{ + +/*! +\brief The solution of the direct problem of geodesics on latlong coordinates, after Vincenty, 1975 +\author See + - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf + - http://www.icsm.gov.au/gda/gdav2.3.pdf +\author Adapted from various implementations to get it close to the original document + - http://www.movable-type.co.uk/scripts/LatLongVincenty.html + - http://exogen.case.edu/projects/geopy/source/geopy.distance.html + - http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink + +*/ +template <typename CT> +class vincenty_direct +{ +public: + template <typename T, typename Dist, typename Azi, typename Spheroid> + vincenty_direct(T const& lo1, + T const& la1, + Dist const& distance, + Azi const& azimuth12, + Spheroid const& spheroid) + : lon1(lo1) + , lat1(la1) + , is_distance_zero(false) + { + if ( math::equals(distance, Dist(0)) || distance < Dist(0) ) + { + is_distance_zero = true; + return; + } + + CT const radius_a = CT(get_radius<0>(spheroid)); + CT const radius_b = CT(get_radius<2>(spheroid)); + flattening = geometry::detail::flattening<CT>(spheroid); + + sin_azimuth12 = sin(azimuth12); + cos_azimuth12 = cos(azimuth12); + + // U: reduced latitude, defined by tan U = (1-f) tan phi + one_min_f = CT(1) - flattening; + CT const tan_U1 = one_min_f * tan(lat1); + CT const sigma1 = atan2(tan_U1, cos_azimuth12); // (1) + + // may be calculated from tan using 1 sqrt() + CT const U1 = atan(tan_U1); + sin_U1 = sin(U1); + cos_U1 = cos(U1); + + sin_alpha = cos_U1 * sin_azimuth12; // (2) + sin_alpha_sqr = math::sqr(sin_alpha); + cos_alpha_sqr = CT(1) - sin_alpha_sqr; + + CT const b_sqr = radius_b * radius_b; + CT const u_sqr = cos_alpha_sqr * (radius_a * radius_a - b_sqr) / b_sqr; + CT const A = CT(1) + (u_sqr/CT(16384)) * (CT(4096) + u_sqr*(CT(-768) + u_sqr*(CT(320) - u_sqr*CT(175)))); // (3) + CT const B = (u_sqr/CT(1024))*(CT(256) + u_sqr*(CT(-128) + u_sqr*(CT(74) - u_sqr*CT(47)))); // (4) + + CT s_div_bA = distance / (radius_b * A); + sigma = s_div_bA; // (7) + + CT previous_sigma; + + int counter = 0; // robustness + + do + { + previous_sigma = sigma; + + CT const two_sigma_m = CT(2) * sigma1 + sigma; // (5) + + sin_sigma = sin(sigma); + cos_sigma = cos(sigma); + CT const sin_sigma_sqr = math::sqr(sin_sigma); + cos_2sigma_m = cos(two_sigma_m); + cos_2sigma_m_sqr = math::sqr(cos_2sigma_m); + + CT const delta_sigma = B * sin_sigma * (cos_2sigma_m + + (B/CT(4)) * ( cos_sigma * (CT(-1) + CT(2)*cos_2sigma_m_sqr) + - (B/CT(6) * cos_2sigma_m * (CT(-3)+CT(4)*sin_sigma_sqr) * (CT(-3)+CT(4)*cos_2sigma_m_sqr)) )); // (6) + + sigma = s_div_bA + delta_sigma; // (7) + + ++counter; // robustness + + } while ( geometry::math::abs(previous_sigma - sigma) > CT(1e-12) + //&& geometry::math::abs(sigma) < pi + && counter < BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS ); // robustness + } + + inline CT lat2() const + { + if ( is_distance_zero ) + { + return lat1; + } + + return atan2( sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_azimuth12, + one_min_f * math::sqrt(sin_alpha_sqr + math::sqr(sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_azimuth12))); // (8) + } + + inline CT lon2() const + { + if ( is_distance_zero ) + { + return lon1; + } + + CT const lambda = atan2( sin_sigma * sin_azimuth12, + cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_azimuth12); // (9) + CT const C = (flattening/CT(16)) * cos_alpha_sqr * ( CT(4) + flattening * ( CT(4) - CT(3) * cos_alpha_sqr ) ); // (10) + CT const L = lambda - (CT(1) - C) * flattening * sin_alpha + * ( sigma + C * sin_sigma * ( cos_2sigma_m + C * cos_sigma * ( CT(-1) + CT(2) * cos_2sigma_m_sqr ) ) ); // (11) + + return lon1 + L; + } + + inline CT azimuth21() const + { + // NOTE: signs of X and Y are different than in the original paper + return is_distance_zero ? + CT(0) : + atan2(-sin_alpha, sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_azimuth12); // (12) + } + +private: + CT sigma; + CT sin_sigma; + CT cos_sigma; + + CT cos_2sigma_m; + CT cos_2sigma_m_sqr; + + CT sin_alpha; + CT sin_alpha_sqr; + CT cos_alpha_sqr; + + CT sin_azimuth12; + CT cos_azimuth12; + + CT sin_U1; + CT cos_U1; + + CT flattening; + CT one_min_f; + + CT const lon1; + CT const lat1; + + bool is_distance_zero; +}; + +}}} // namespace boost::geometry::detail + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_DIRECT_HPP diff --git a/boost/geometry/algorithms/detail/vincenty_inverse.hpp b/boost/geometry/algorithms/detail/vincenty_inverse.hpp new file mode 100644 index 0000000000..861452af00 --- /dev/null +++ b/boost/geometry/algorithms/detail/vincenty_inverse.hpp @@ -0,0 +1,218 @@ +// Boost.Geometry + +// 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_VINCENTY_INVERSE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_INVERSE_HPP + + +#include <boost/math/constants/constants.hpp> + +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/algorithms/detail/flattening.hpp> + + +#ifndef BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS +#define BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS 1000 +#endif + + +namespace boost { namespace geometry { namespace detail +{ + +/*! +\brief The solution of the inverse problem of geodesics on latlong coordinates, after Vincenty, 1975 +\author See + - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf + - http://www.icsm.gov.au/gda/gdav2.3.pdf +\author Adapted from various implementations to get it close to the original document + - http://www.movable-type.co.uk/scripts/LatLongVincenty.html + - http://exogen.case.edu/projects/geopy/source/geopy.distance.html + - http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink + +*/ +template <typename CT> +class vincenty_inverse +{ +public: + template <typename T1, typename T2, typename Spheroid> + vincenty_inverse(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2, + Spheroid const& spheroid) + : is_result_zero(false) + { + if (math::equals(lat1, lat2) && math::equals(lon1, lon2)) + { + is_result_zero = true; + return; + } + + CT const c1 = 1; + CT const c2 = 2; + CT const c3 = 3; + CT const c4 = 4; + CT const c16 = 16; + CT const c_e_12 = CT(1e-12); + + CT const pi = geometry::math::pi<CT>(); + CT const two_pi = c2 * pi; + + // lambda: difference in longitude on an auxiliary sphere + CT L = lon2 - lon1; + CT lambda = L; + + if (L < -pi) L += two_pi; + if (L > pi) L -= two_pi; + + radius_a = CT(get_radius<0>(spheroid)); + radius_b = CT(get_radius<2>(spheroid)); + CT const flattening = geometry::detail::flattening<CT>(spheroid); + + // U: reduced latitude, defined by tan U = (1-f) tan phi + CT const one_min_f = c1 - flattening; + CT const tan_U1 = one_min_f * tan(lat1); // above (1) + CT const tan_U2 = one_min_f * tan(lat2); // above (1) + + // calculate sin U and cos U using trigonometric identities + CT const temp_den_U1 = math::sqrt(c1 + math::sqr(tan_U1)); + CT const temp_den_U2 = math::sqrt(c1 + math::sqr(tan_U2)); + // cos = 1 / sqrt(1 + tan^2) + cos_U1 = c1 / temp_den_U1; + cos_U2 = c1 / temp_den_U2; + // sin = tan / sqrt(1 + tan^2) + sin_U1 = tan_U1 / temp_den_U1; + sin_U2 = tan_U2 / temp_den_U2; + + // calculate sin U and cos U directly + //CT const U1 = atan(tan_U1); + //CT const U2 = atan(tan_U2); + //cos_U1 = cos(U1); + //cos_U2 = cos(U2); + //sin_U1 = tan_U1 * cos_U1; // sin(U1); + //sin_U2 = tan_U2 * cos_U2; // sin(U2); + + CT previous_lambda; + + int counter = 0; // robustness + + do + { + previous_lambda = lambda; // (13) + sin_lambda = sin(lambda); + cos_lambda = cos(lambda); + sin_sigma = math::sqrt(math::sqr(cos_U2 * sin_lambda) + math::sqr(cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda)); // (14) + CT cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda; // (15) + sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma; // (17) + cos2_alpha = c1 - math::sqr(sin_alpha); + cos2_sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18) + + CT C = flattening/c16 * cos2_alpha * (c4 + flattening * (c4 - c3 * cos2_alpha)); // (10) + sigma = atan2(sin_sigma, cos_sigma); // (16) + lambda = L + (c1 - C) * flattening * sin_alpha * + (sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * (-c1 + c2 * math::sqr(cos2_sigma_m)))); // (11) + + ++counter; // robustness + + } while ( geometry::math::abs(previous_lambda - lambda) > c_e_12 + && geometry::math::abs(lambda) < pi + && counter < BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS ); // robustness + } + + inline CT distance() const + { + if ( is_result_zero ) + { + return CT(0); + } + + // Oops getting hard here + // (again, problem is that ttmath cannot divide by doubles, which is OK) + CT const c1 = 1; + CT const c2 = 2; + CT const c3 = 3; + CT const c4 = 4; + CT const c6 = 6; + CT const c47 = 47; + CT const c74 = 74; + CT const c128 = 128; + CT const c256 = 256; + CT const c175 = 175; + CT const c320 = 320; + CT const c768 = 768; + CT const c1024 = 1024; + CT const c4096 = 4096; + CT const c16384 = 16384; + + //CT sqr_u = cos2_alpha * (math::sqr(radius_a) - math::sqr(radius_b)) / math::sqr(radius_b); // above (1) + CT sqr_u = cos2_alpha * ( math::sqr(radius_a / radius_b) - c1 ); // above (1) + + CT A = c1 + sqr_u/c16384 * (c4096 + sqr_u * (-c768 + sqr_u * (c320 - c175 * sqr_u))); // (3) + CT B = sqr_u/c1024 * (c256 + sqr_u * ( -c128 + sqr_u * (c74 - c47 * sqr_u))); // (4) + CT delta_sigma = B * sin_sigma * ( cos2_sigma_m + (B/c4) * (cos(sigma)* (-c1 + c2 * cos2_sigma_m) + - (B/c6) * cos2_sigma_m * (-c3 + c4 * math::sqr(sin_sigma)) * (-c3 + c4 * cos2_sigma_m))); // (6) + + return radius_b * A * (sigma - delta_sigma); // (19) + } + + inline CT azimuth12() const + { + return is_result_zero ? + CT(0) : + atan2(cos_U2 * sin_lambda, cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda); // (20) + } + + inline CT azimuth21() const + { + // NOTE: signs of X and Y are different than in the original paper + return is_result_zero ? + CT(0) : + atan2(-cos_U1 * sin_lambda, sin_U1 * cos_U2 - cos_U1 * sin_U2 * cos_lambda); // (21) + } + +private: + // alpha: azimuth of the geodesic at the equator + CT cos2_alpha; + CT sin_alpha; + + // sigma: angular distance p1,p2 on the sphere + // sigma1: angular distance on the sphere from the equator to p1 + // sigma_m: angular distance on the sphere from the equator to the midpoint of the line + CT sigma; + CT sin_sigma; + CT cos2_sigma_m; + + CT sin_lambda; + CT cos_lambda; + + // set only once + CT cos_U1; + CT cos_U2; + CT sin_U1; + CT sin_U2; + + // set only once + CT radius_a; + CT radius_b; + + bool is_result_zero; +}; + +}}} // namespace boost::geometry::detail + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_INVERSE_HPP diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index 6f1c1816cb..e7486f0e45 100644 --- a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -5,8 +5,8 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015, 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. @@ -21,6 +21,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP #include <boost/assert.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/mpl/assert.hpp> #include <boost/range.hpp> #include <boost/type_traits/is_same.hpp> @@ -35,6 +36,7 @@ #include <boost/geometry/strategies/within.hpp> #include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/util/range.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry { @@ -58,7 +60,7 @@ inline T check_result_type(T 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); + boost::ignore_unused(strategy); typedef typename boost::range_iterator<Range const>::type iterator_type; typename Strategy::state_type state; @@ -147,7 +149,7 @@ 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); + boost::ignore_unused(strategy); return strategy.apply(point1, point2) ? 1 : -1; } }; @@ -158,6 +160,8 @@ 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) { + boost::ignore_unused(strategy); + typedef typename geometry::point_type<Segment>::type point_type; point_type p0, p1; // TODO: don't copy points @@ -194,11 +198,11 @@ struct point_in_geometry<Linestring, linestring_tag> return -1; // exterior // if the linestring doesn't have a boundary - if ( detail::equals::equals_point_point(*boost::begin(linestring), *(--boost::end(linestring))) ) + if (detail::equals::equals_point_point(range::front(linestring), range::back(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))) ) + else if (detail::equals::equals_point_point(point, range::front(linestring)) + || detail::equals::equals_point_point(point, range::back(linestring))) return 0; // boundary else return 1; // interior @@ -207,7 +211,7 @@ struct point_in_geometry<Linestring, linestring_tag> // throw an exception here? /*else if ( count == 1 ) { - if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) ) + if ( detail::equals::equals_point_point(point, range::front(linestring)) ) return 1; }*/ @@ -333,8 +337,8 @@ struct point_in_geometry<Geometry, multi_linestring_tag> if ( boost::size(*it) < 2 ) continue; - point_type const& front = *boost::begin(*it); - point_type const& back = *(--boost::end(*it)); + point_type const& front = range::front(*it); + point_type const& back = range::back(*it); // is closed_ring - no boundary if ( detail::equals::equals_point_point(front, back) ) diff --git a/boost/geometry/algorithms/dispatch/is_valid.hpp b/boost/geometry/algorithms/dispatch/is_valid.hpp index 266bab9181..5d8108655c 100644 --- a/boost/geometry/algorithms/dispatch/is_valid.hpp +++ b/boost/geometry/algorithms/dispatch/is_valid.hpp @@ -27,10 +27,8 @@ 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 + // for multi-geometries: determines if empty multi-geometries are allowed + bool AllowEmptyMultiGeometries = true > struct is_valid : not_implemented<Geometry> diff --git a/boost/geometry/algorithms/envelope.hpp b/boost/geometry/algorithms/envelope.hpp index e06ed71e81..bd1ea9cb7a 100644 --- a/boost/geometry/algorithms/envelope.hpp +++ b/boost/geometry/algorithms/envelope.hpp @@ -18,8 +18,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/assign.hpp> diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp index c6b718da1b..7c709c808d 100644 --- a/boost/geometry/algorithms/equals.hpp +++ b/boost/geometry/algorithms/equals.hpp @@ -1,14 +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) 2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. +// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015 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. @@ -26,6 +27,10 @@ #include <boost/range.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/geometry_id.hpp> @@ -50,8 +55,6 @@ #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 { @@ -234,8 +237,6 @@ template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse> struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse> : geometry::detail::not_ < - P1, - P2, detail::disjoint::point_point<P1, P2, 0, DimensionCount> > {}; diff --git a/boost/geometry/algorithms/expand.hpp b/boost/geometry/algorithms/expand.hpp index 19e40aa2d0..9dc0a48e06 100644 --- a/boost/geometry/algorithms/expand.hpp +++ b/boost/geometry/algorithms/expand.hpp @@ -20,6 +20,10 @@ #include <boost/numeric/conversion/cast.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/coordinate_dimension.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -29,9 +33,6 @@ #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 { diff --git a/boost/geometry/algorithms/length.hpp b/boost/geometry/algorithms/length.hpp index 6cbec5303e..fad17ade46 100644 --- a/boost/geometry/algorithms/length.hpp +++ b/boost/geometry/algorithms/length.hpp @@ -4,10 +4,11 @@ // 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. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015, 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. @@ -22,6 +23,7 @@ #include <iterator> #include <boost/concept_check.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> #include <boost/mpl/fold.hpp> @@ -69,6 +71,7 @@ struct segment_length static inline typename default_length_result<Segment>::type apply( Segment const& segment, Strategy const& strategy) { + boost::ignore_unused(strategy); typedef typename point_type<Segment>::type point_type; point_type p1, p2; geometry::detail::assign_point_from_index<0>(segment, p1); @@ -92,7 +95,7 @@ struct range_length static inline return_type apply( Range const& range, Strategy const& strategy) { - boost::ignore_unused_variable_warning(strategy); + boost::ignore_unused(strategy); typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_iterator < diff --git a/boost/geometry/algorithms/not_implemented.hpp b/boost/geometry/algorithms/not_implemented.hpp index cd40a2772f..9c416074ed 100644 --- a/boost/geometry/algorithms/not_implemented.hpp +++ b/boost/geometry/algorithms/not_implemented.hpp @@ -1,8 +1,13 @@ // 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. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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,6 +22,7 @@ #include <boost/mpl/assert.hpp> +#include <boost/mpl/identity.hpp> #include <boost/geometry/core/tags.hpp> @@ -87,7 +93,7 @@ template <> struct tag_to_term<multi_point_tag> { typedef info::MULT template <> struct tag_to_term<multi_linestring_tag> { typedef info::MULTI_LINESTRING type; }; template <> struct tag_to_term<multi_polygon_tag> { typedef info::MULTI_POLYGON type; }; template <> struct tag_to_term<geometry_collection_tag> { typedef info::GEOMETRY_COLLECTION type; }; -template <int D> struct tag_to_term<mpl::int_<D> > { typedef info::DIMENSION<D> type; }; +template <int D> struct tag_to_term<boost::mpl::int_<D> > { typedef info::DIMENSION<D> type; }; } @@ -103,9 +109,18 @@ struct not_implemented : nyi::not_implemented_tag, nyi::not_implemented_error < - typename mpl::identity<typename nyi::tag_to_term<Term1>::type>::type, - typename mpl::identity<typename nyi::tag_to_term<Term2>::type>::type, - typename mpl::identity<typename nyi::tag_to_term<Term3>::type>::type + typename boost::mpl::identity + < + typename nyi::tag_to_term<Term1>::type + >::type, + typename boost::mpl::identity + < + typename nyi::tag_to_term<Term2>::type + >::type, + typename boost::mpl::identity + < + typename nyi::tag_to_term<Term3>::type + >::type > {}; diff --git a/boost/geometry/algorithms/num_geometries.hpp b/boost/geometry/algorithms/num_geometries.hpp index d37d0bfabe..8144c22ab0 100644 --- a/boost/geometry/algorithms/num_geometries.hpp +++ b/boost/geometry/algorithms/num_geometries.hpp @@ -23,8 +23,9 @@ #include <cstddef> #include <boost/range.hpp> -#include <boost/variant/static_visitor.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> diff --git a/boost/geometry/algorithms/num_interior_rings.hpp b/boost/geometry/algorithms/num_interior_rings.hpp index e198b37a75..04b4eb2a7c 100644 --- a/boost/geometry/algorithms/num_interior_rings.hpp +++ b/boost/geometry/algorithms/num_interior_rings.hpp @@ -24,8 +24,8 @@ #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/tag.hpp> diff --git a/boost/geometry/algorithms/num_points.hpp b/boost/geometry/algorithms/num_points.hpp index 4c2ad3b08c..214fe9c8b0 100644 --- a/boost/geometry/algorithms/num_points.hpp +++ b/boost/geometry/algorithms/num_points.hpp @@ -26,8 +26,8 @@ #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> diff --git a/boost/geometry/algorithms/num_segments.hpp b/boost/geometry/algorithms/num_segments.hpp index cbb5685967..08af226caf 100644 --- a/boost/geometry/algorithms/num_segments.hpp +++ b/boost/geometry/algorithms/num_segments.hpp @@ -17,8 +17,8 @@ #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> diff --git a/boost/geometry/algorithms/perimeter.hpp b/boost/geometry/algorithms/perimeter.hpp index 0ec153c1f4..1b5ccacf9c 100644 --- a/boost/geometry/algorithms/perimeter.hpp +++ b/boost/geometry/algorithms/perimeter.hpp @@ -20,8 +20,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/length.hpp> diff --git a/boost/geometry/algorithms/remove_spikes.hpp b/boost/geometry/algorithms/remove_spikes.hpp index e62ea9fe3d..a96a2c29d0 100644 --- a/boost/geometry/algorithms/remove_spikes.hpp +++ b/boost/geometry/algorithms/remove_spikes.hpp @@ -16,8 +16,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> @@ -26,11 +27,15 @@ #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> +#include <boost/geometry/util/condition.hpp> + /* Remove spikes from a ring/polygon. @@ -94,7 +99,7 @@ struct range_remove_spikes } // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent - if (geometry::closure<Range>::value == geometry::closed) + if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) ) { cleaned.pop_back(); } @@ -127,7 +132,7 @@ struct range_remove_spikes } // Close if necessary - if (geometry::closure<Range>::value == geometry::closed) + if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) ) { cleaned.push_back(cleaned.front()); } diff --git a/boost/geometry/algorithms/reverse.hpp b/boost/geometry/algorithms/reverse.hpp index 17b23ffdfb..578771bfe3 100644 --- a/boost/geometry/algorithms/reverse.hpp +++ b/boost/geometry/algorithms/reverse.hpp @@ -19,8 +19,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> diff --git a/boost/geometry/algorithms/simplify.hpp b/boost/geometry/algorithms/simplify.hpp index 101b1324e1..0047546718 100644 --- a/boost/geometry/algorithms/simplify.hpp +++ b/boost/geometry/algorithms/simplify.hpp @@ -1,8 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -16,9 +16,11 @@ #include <cstddef> +#include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> -#include <boost/variant/static_visitor.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> @@ -32,6 +34,7 @@ #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/strategies/distance.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/convert.hpp> @@ -52,6 +55,8 @@ struct simplify_range_insert static inline void apply(Range const& range, OutputIterator out, Distance const& max_distance, Strategy const& strategy) { + boost::ignore_unused(strategy); + if (boost::size(range) <= 2 || max_distance < 0) { std::copy(boost::begin(range), boost::end(range), out); diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp index a06071d428..48334d7255 100644 --- a/boost/geometry/algorithms/touches.hpp +++ b/boost/geometry/algorithms/touches.hpp @@ -23,6 +23,10 @@ #include <deque> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/for_each_range.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> @@ -32,9 +36,6 @@ #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> diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp index 1d6e8d0a35..357263a4ea 100644 --- a/boost/geometry/algorithms/transform.hpp +++ b/boost/geometry/algorithms/transform.hpp @@ -20,8 +20,9 @@ #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/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/assign.hpp> diff --git a/boost/geometry/algorithms/validity_failure_type.hpp b/boost/geometry/algorithms/validity_failure_type.hpp new file mode 100644 index 0000000000..42de99c585 --- /dev/null +++ b/boost/geometry/algorithms/validity_failure_type.hpp @@ -0,0 +1,87 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_VALIDITY_FAILURE_TYPE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_VALIDITY_FAILURE_TYPE_HPP + + +namespace boost { namespace geometry +{ + + +/*! +\brief Enumerates the possible validity failure types for a geometry +\ingroup enum +\details The enumeration validity_failure_type enumerates the possible + reasons for which a geometry may be found as invalid by the + is_valid algorithm. + Besides the values that indicate invalidity, there is an + additional value (no_failure) that indicates validity. + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.is_valid The is_valid +algorithm taking a reference to validity_failure_type as second argument] +} +*/ +enum validity_failure_type +{ + /// The geometry is valid + /// + no_failure = 0, + /// The geometry has a very small number of points, e.g., less + /// than 2 for linestrings, less than 3 for open rings, a closed + /// multi-polygon that contains a polygon with less than 4 points, etc. + /// (applies to linestrings, rings, polygons, multi-linestrings + /// and multi-polygons) + failure_few_points = 10, + /// The topological dimension of the geometry is smaller than its + /// dimension, e.g., a linestring with 3 identical points, an open + /// polygon with an interior ring consisting of 3 collinear points, etc. + /// (applies to linear and areal geometries, including segments + /// and boxes) + failure_wrong_topological_dimension = 11, + /// The geometry contains spikes + /// (applies to linear and areal geometries) + failure_spikes = 12, + /// The geometry has (consecutive) duplicate points + /// (applies to areal geometries only) + failure_duplicate_points = 13, + /// The geometry is defined as closed, the starting/ending points + /// are not equal + /// (applies to areal geometries only) + failure_not_closed = 20, // for areal geometries + /// The geometry has invalid self-intersections. + /// (applies to areal geometries only) + failure_self_intersections = 21, // for areal geometries + /// The actual orientation of the geometry is different from the one defined + /// (applies to areal geometries only) + failure_wrong_orientation = 22, // for areal geometries + /// The geometry contains interior rings that lie outside the exterior ring + /// (applies to polygons and multi-polygons only) + failure_interior_rings_outside = 30, // for (multi-)polygons + /// The geometry has nested interior rings + /// (applies to polygons and multi-polygons only) + failure_nested_interior_rings = 31, // for (multi-)polygons + /// The interior of the geometry is disconnected + /// (applies to polygons and multi-polygons only) + failure_disconnected_interior = 32, // for (multi-)polygons + /// The multi-polygon contains polygons whose interiors are not disjoint + /// (applies to multi-polygons only) + failure_intersecting_interiors = 40, // for multi-polygons + /// The top-right corner of the box is lexicographically smaller + /// than its bottom-left corner + /// (applies to boxes only) + failure_wrong_corner_order = 50 // for boxes +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_VALIDITY_FAILURE_TYPE_HPP diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp index f66b1ed1c6..9f2b6fedf7 100644 --- a/boost/geometry/algorithms/within.hpp +++ b/boost/geometry/algorithms/within.hpp @@ -24,8 +24,9 @@ #include <boost/concept_check.hpp> #include <boost/range.hpp> -#include <boost/variant/static_visitor.hpp> + #include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/make.hpp> diff --git a/boost/geometry/core/cs.hpp b/boost/geometry/core/cs.hpp index cf6c56b53c..301fb6b76f 100644 --- a/boost/geometry/core/cs.hpp +++ b/boost/geometry/core/cs.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,7 +21,8 @@ #include <cstddef> -#include <boost/type_traits.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/integral_constant.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tags.hpp> @@ -45,6 +51,35 @@ struct degree {}; struct radian {}; +#ifndef DOXYGEN_NO_DETAIL +namespace core_detail +{ + +template <typename DegreeOrRadian> +struct coordinate_system_units +{ + BOOST_MPL_ASSERT_MSG + ((false), + COORDINATE_SYSTEM_UNITS_MUST_BE_DEGREES_OR_RADIANS, + (types<DegreeOrRadian>)); +}; + +template <> +struct coordinate_system_units<geometry::degree> +{ + typedef geometry::degree units; +}; + +template <> +struct coordinate_system_units<geometry::radian> +{ + typedef geometry::radian units; +}; + +} // namespace core_detail +#endif // DOXYGEN_NO_DETAIL + + namespace cs { @@ -73,7 +108,10 @@ known as lat,long or lo,la or phi,lambda template<typename DegreeOrRadian> struct geographic { - typedef DegreeOrRadian units; + typedef typename core_detail::coordinate_system_units + < + DegreeOrRadian + >::units units; }; @@ -99,7 +137,10 @@ struct geographic template<typename DegreeOrRadian> struct spherical { - typedef DegreeOrRadian units; + typedef typename core_detail::coordinate_system_units + < + DegreeOrRadian + >::units units; }; @@ -116,7 +157,10 @@ struct spherical template<typename DegreeOrRadian> struct spherical_equatorial { - typedef DegreeOrRadian units; + typedef typename core_detail::coordinate_system_units + < + DegreeOrRadian + >::units units; }; @@ -131,7 +175,10 @@ struct spherical_equatorial template<typename DegreeOrRadian> struct polar { - typedef DegreeOrRadian units; + typedef typename core_detail::coordinate_system_units + < + DegreeOrRadian + >::units units; }; diff --git a/boost/geometry/core/interior_type.hpp b/boost/geometry/core/interior_type.hpp index 02328372f0..e6c4537e41 100644 --- a/boost/geometry/core/interior_type.hpp +++ b/boost/geometry/core/interior_type.hpp @@ -86,7 +86,7 @@ struct interior_return_type<polygon_tag, Polygon> { typedef typename boost::remove_const<Polygon>::type nc_polygon_type; - typedef typename mpl::if_ + typedef typename boost::mpl::if_ < boost::is_const<Polygon>, typename traits::interior_const_type<nc_polygon_type>::type, diff --git a/boost/geometry/core/radius.hpp b/boost/geometry/core/radius.hpp new file mode 100644 index 0000000000..ee6d5d246f --- /dev/null +++ b/boost/geometry/core/radius.hpp @@ -0,0 +1,250 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (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. + +// 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_CORE_RADIUS_HPP +#define BOOST_GEOMETRY_CORE_RADIUS_HPP + + +#include <cstddef> + +#include <boost/static_assert.hpp> + +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/bare_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace traits +{ + +/*! + \brief Traits class to get/set radius of a circle/sphere/(ellipse) + \details the radius access meta-functions give read/write access to the radius of a circle or a sphere, + or to the major/minor axis or an ellipse, or to one of the 3 equatorial radii of an ellipsoid. + + It should be specialized per geometry, in namespace core_dispatch. Those specializations should + forward the call via traits to the geometry class, which could be specified by the user. + + There is a corresponding generic radius_get and radius_set function + \par Geometries: + - n-sphere (circle,sphere) + - upcoming ellipse + \par Specializations should provide: + - inline static T get(Geometry const& geometry) + - inline static void set(Geometry& geometry, T const& radius) + \ingroup traits +*/ +template <typename Geometry, std::size_t Dimension> +struct radius_access {}; + + +/*! + \brief Traits class indicating the type (double,float,...) of the radius of a circle or a sphere + \par Geometries: + - n-sphere (circle,sphere) + - upcoming ellipse + \par Specializations should provide: + - typedef T type (double,float,int,etc) + \ingroup traits +*/ +template <typename Geometry> +struct radius_type {}; + +} // namespace traits + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Tag, typename Geometry> +struct radius_type +{ + //typedef core_dispatch_specialization_required type; +}; + +/*! + \brief radius access meta-functions, used by concept n-sphere and upcoming ellipse. +*/ +template <typename Tag, + typename Geometry, + std::size_t Dimension, + typename IsPointer> +struct radius_access +{ + //static inline CoordinateType get(Geometry const& ) {} + //static inline void set(Geometry& g, CoordinateType const& value) {} +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! + \brief Metafunction to get the type of radius of a circle / sphere / ellipse / etc. + \ingroup access + \tparam Geometry the type of geometry +*/ +template <typename Geometry> +struct radius_type +{ + typedef typename core_dispatch::radius_type + < + typename tag<Geometry>::type, + typename util::bare_type<Geometry>::type + >::type type; +}; + +/*! + \brief Function to get radius of a circle / sphere / ellipse / etc. + \return radius The radius for a given axis + \ingroup access + \param geometry the geometry to get the radius from + \tparam I index of the axis +*/ +template <std::size_t I, typename Geometry> +inline typename radius_type<Geometry>::type get_radius(Geometry const& geometry) +{ + return core_dispatch::radius_access + < + typename tag<Geometry>::type, + typename util::bare_type<Geometry>::type, + I, + typename boost::is_pointer<Geometry>::type + >::get(geometry); +} + +/*! + \brief Function to set the radius of a circle / sphere / ellipse / etc. + \ingroup access + \tparam I index of the axis + \param geometry the geometry to change + \param radius the radius to set +*/ +template <std::size_t I, typename Geometry> +inline void set_radius(Geometry& geometry, + typename radius_type<Geometry>::type const& radius) +{ + core_dispatch::radius_access + < + typename tag<Geometry>::type, + typename util::bare_type<Geometry>::type, + I, + typename boost::is_pointer<Geometry>::type + >::set(geometry, radius); +} + + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Tag, typename Geometry, std::size_t Dimension> +struct radius_access +{ + static inline typename radius_type<Geometry>::type get(Geometry const& geometry) + { + return traits::radius_access<Geometry, Dimension>::get(geometry); + } + static inline void set(Geometry& geometry, + typename radius_type<Geometry>::type const& value) + { + traits::radius_access<Geometry, Dimension>::set(geometry, value); + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace core_dispatch +{ + +template <typename Tag, + typename Geometry, + std::size_t Dimension> +struct radius_access<Tag, Geometry, Dimension, boost::true_type> +{ + typedef typename geometry::radius_type<Geometry>::type radius_type; + + static inline radius_type get(const Geometry * geometry) + { + return radius_access + < + Tag, + Geometry, + Dimension, + typename boost::is_pointer<Geometry>::type + >::get(*geometry); + } + + static inline void set(Geometry * geometry, radius_type const& value) + { + return radius_access + < + Tag, + Geometry, + Dimension, + typename boost::is_pointer<Geometry>::type + >::set(*geometry, value); + } +}; + + +template <typename Geometry> +struct radius_type<srs_sphere_tag, Geometry> +{ + typedef typename traits::radius_type<Geometry>::type type; +}; + +template <typename Geometry, std::size_t Dimension> +struct radius_access<srs_sphere_tag, Geometry, Dimension, boost::false_type> + : detail::radius_access<srs_sphere_tag, Geometry, Dimension> +{ + BOOST_STATIC_ASSERT(Dimension == 0); + //BOOST_STATIC_ASSERT(Dimension < 3); +}; + +template <typename Geometry> +struct radius_type<srs_spheroid_tag, Geometry> +{ + typedef typename traits::radius_type<Geometry>::type type; +}; + +template <typename Geometry, std::size_t Dimension> +struct radius_access<srs_spheroid_tag, Geometry, Dimension, boost::false_type> + : detail::radius_access<srs_spheroid_tag, Geometry, Dimension> +{ + BOOST_STATIC_ASSERT(Dimension == 0 || Dimension == 2); + //BOOST_STATIC_ASSERT(Dimension < 3); +}; + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_RADIUS_HPP diff --git a/boost/geometry/core/ring_type.hpp b/boost/geometry/core/ring_type.hpp index fe551f060f..c007931126 100644 --- a/boost/geometry/core/ring_type.hpp +++ b/boost/geometry/core/ring_type.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -95,7 +100,7 @@ struct ring_return_type<polygon_tag, Polygon> { typedef typename boost::remove_const<Polygon>::type nc_polygon_type; - typedef typename mpl::if_ + typedef typename boost::mpl::if_ < boost::is_const<Polygon>, typename traits::ring_const_type<nc_polygon_type>::type, @@ -110,7 +115,7 @@ struct ring_return_type<multi_linestring_tag, MultiLinestring> typedef typename ring_return_type < linestring_tag, - typename mpl::if_ + typename boost::mpl::if_ < boost::is_const<MultiLinestring>, typename boost::range_value<MultiLinestring>::type const, @@ -126,7 +131,7 @@ struct ring_return_type<multi_polygon_tag, MultiPolygon> typedef typename ring_return_type < polygon_tag, - typename mpl::if_ + typename boost::mpl::if_ < boost::is_const<MultiPolygon>, typename boost::range_value<MultiPolygon>::type const, diff --git a/boost/geometry/core/srs.hpp b/boost/geometry/core/srs.hpp new file mode 100644 index 0000000000..bf1b4e28a5 --- /dev/null +++ b/boost/geometry/core/srs.hpp @@ -0,0 +1,195 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// 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. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_CORE_SRS_HPP +#define BOOST_GEOMETRY_CORE_SRS_HPP + + +#include <cstddef> + +#include <boost/static_assert.hpp> + +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +namespace srs +{ + +/*! + \brief Defines spheroid radius values for use in geographical CS calculations + \note See http://en.wikipedia.org/wiki/Figure_of_the_Earth + and http://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS84 +*/ +template <typename RadiusType> +class spheroid +{ +public: + spheroid(RadiusType const& a, RadiusType const& b) + : m_a(a) + , m_b(b) + {} + + spheroid() + : m_a(RadiusType(6378137.0)) + , m_b(RadiusType(6356752.314245)) + {} + + template <std::size_t I> + RadiusType get_radius() const + { + BOOST_STATIC_ASSERT(I < 3); + + return I < 2 ? m_a : m_b; + } + + template <std::size_t I> + void set_radius(RadiusType const& radius) + { + BOOST_STATIC_ASSERT(I < 3); + + (I < 2 ? m_a : m_b) = radius; + } + +private: + RadiusType m_a, m_b; // equatorial radius, polar radius +}; + +} // namespace srs + +// Traits specializations for spheroid +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename RadiusType> +struct tag< srs::spheroid<RadiusType> > +{ + typedef srs_spheroid_tag type; +}; + +template <typename RadiusType> +struct radius_type< srs::spheroid<RadiusType> > +{ + typedef RadiusType type; +}; + +template <typename RadiusType, std::size_t Dimension> +struct radius_access<srs::spheroid<RadiusType>, Dimension> +{ + typedef srs::spheroid<RadiusType> spheroid_type; + + static inline RadiusType get(spheroid_type const& s) + { + return s.template get_radius<Dimension>(); + } + + static inline void set(spheroid_type& s, RadiusType const& value) + { + s.template set_radius<Dimension>(value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +namespace srs +{ + +/*! + \brief Defines sphere radius value for use in spherical CS calculations +*/ +template <typename RadiusType> +class sphere +{ +public: + explicit sphere(RadiusType const& r) + : m_r(r) + {} + sphere() + : m_r(RadiusType((2.0 * 6378137.0 + 6356752.314245) / 3.0)) + {} + + template <std::size_t I> + RadiusType get_radius() const + { + BOOST_STATIC_ASSERT(I < 3); + + return m_r; + } + + template <std::size_t I> + void set_radius(RadiusType const& radius) + { + BOOST_STATIC_ASSERT(I < 3); + + m_r = radius; + } + +private: + RadiusType m_r; // radius +}; + +} // namespace srs + +// Traits specializations for sphere +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template <typename RadiusType> +struct tag< srs::sphere<RadiusType> > +{ + typedef srs_sphere_tag type; +}; + +template <typename RadiusType> +struct radius_type< srs::sphere<RadiusType> > +{ + typedef RadiusType type; +}; + +template <typename RadiusType, std::size_t Dimension> +struct radius_access<srs::sphere<RadiusType>, Dimension> +{ + typedef srs::sphere<RadiusType> sphere_type; + + static inline RadiusType get(sphere_type const& s) + { + return s.template get_radius<Dimension>(); + } + + static inline void set(sphere_type& s, RadiusType const& value) + { + s.template set_radius<Dimension>(value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_SRS_HPP diff --git a/boost/geometry/core/tags.hpp b/boost/geometry/core/tags.hpp index 160477b8c4..5d6acb1878 100644 --- a/boost/geometry/core/tags.hpp +++ b/boost/geometry/core/tags.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. @@ -37,6 +42,14 @@ struct spherical_equatorial_tag : spherical_tag {}; struct geographic_tag : spherical_tag {}; +// Tags defining coordinate systems reference models + +/// For reference spheroid defining parameters of geographical coordinate system +struct srs_spheroid_tag {}; + +/// For reference sphere defining parameters of spherical coordinate system +struct srs_sphere_tag : srs_spheroid_tag {}; + // Tags defining tag hierarchy diff --git a/boost/geometry/geometries/adapted/boost_fusion.hpp b/boost/geometry/geometries/adapted/boost_fusion.hpp index a9aba916a5..2f3594e4e7 100644 --- a/boost/geometry/geometries/adapted/boost_fusion.hpp +++ b/boost/geometry/geometries/adapted/boost_fusion.hpp @@ -1,7 +1,12 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2011-2012 Akira Takahashi -// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2011-2015 Akira Takahashi +// Copyright (c) 2011-2015 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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 @@ -13,23 +18,24 @@ #include <cstddef> +#include <boost/core/enable_if.hpp> + #include <boost/fusion/include/is_sequence.hpp> #include <boost/fusion/include/size.hpp> #include <boost/fusion/include/tag_of.hpp> #include <boost/fusion/include/front.hpp> #include <boost/fusion/include/at.hpp> -#include <boost/utility/enable_if.hpp> - #include <boost/fusion/mpl.hpp> -#include <boost/mpl/front.hpp> + +#include <boost/mpl/and.hpp> #include <boost/mpl/count_if.hpp> +#include <boost/mpl/front.hpp> +#include <boost/mpl/placeholders.hpp> #include <boost/mpl/pop_front.hpp> #include <boost/mpl/size.hpp> + #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_reference.hpp> -#include <boost/mpl/placeholders.hpp> -#include <boost/mpl/and.hpp> -#include <boost/mpl/front.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> @@ -65,7 +71,7 @@ struct is_coordinate_size : boost::mpl::bool_< template<typename Sequence> struct is_fusion_sequence - : mpl::and_<boost::fusion::traits::is_sequence<Sequence>, + : boost::mpl::and_<boost::fusion::traits::is_sequence<Sequence>, fusion_adapt_detail::is_coordinate_size<Sequence>, fusion_adapt_detail::all_same<Sequence> > {}; diff --git a/boost/geometry/geometries/concepts/point_concept.hpp b/boost/geometry/geometries/concepts/point_concept.hpp index 1e1b31e61f..db49771129 100644 --- a/boost/geometry/geometries/concepts/point_concept.hpp +++ b/boost/geometry/geometries/concepts/point_concept.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. @@ -17,6 +22,7 @@ #include <cstddef> #include <boost/concept_check.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> @@ -24,7 +30,6 @@ - namespace boost { namespace geometry { namespace concept { @@ -46,6 +51,9 @@ The point concept is defined as following: with two functions: - \b get to get a coordinate value - \b set to set a coordinate value (this one is not checked for ConstPoint) +- for non-Cartesian coordinate systems, the coordinate system's units + must either be boost::geometry::degree or boost::geometry::radian + \par Example: @@ -90,8 +98,12 @@ class Point typedef typename coordinate_type<Geometry>::type ctype; typedef typename coordinate_system<Geometry>::type csystem; - enum { ccount = dimension<Geometry>::value }; + // The following enum is used to fully instantiate the coordinate + // system class; this is needed in order to check the units passed + // to it for non-Cartesian coordinate systems. + enum { cs_check = sizeof(csystem) }; + enum { ccount = dimension<Geometry>::value }; template <typename P, std::size_t Dimension, std::size_t DimensionCount> struct dimension_checker @@ -139,8 +151,12 @@ class ConstPoint typedef typename coordinate_type<Geometry>::type ctype; typedef typename coordinate_system<Geometry>::type csystem; - enum { ccount = dimension<Geometry>::value }; + // The following enum is used to fully instantiate the coordinate + // system class; this is needed in order to check the units passed + // to it for non-Cartesian coordinate systems. + enum { cs_check = sizeof(csystem) }; + enum { ccount = dimension<Geometry>::value }; template <typename P, std::size_t Dimension, std::size_t DimensionCount> struct dimension_checker @@ -149,7 +165,7 @@ class ConstPoint { const P* p = 0; ctype coord(geometry::get<Dimension>(*p)); - boost::ignore_unused_variable_warning(coord); + boost::ignore_unused(coord); dimension_checker<P, Dimension+1, DimensionCount>::apply(); } }; diff --git a/boost/geometry/geometries/linestring.hpp b/boost/geometry/geometries/linestring.hpp index 38bc3d4c49..68dc87a3cf 100644 --- a/boost/geometry/geometries/linestring.hpp +++ b/boost/geometry/geometries/linestring.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. @@ -25,6 +26,12 @@ #include <boost/geometry/geometries/concepts/point_concept.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif namespace boost { namespace geometry { @@ -68,6 +75,30 @@ public : inline linestring(Iterator begin, Iterator end) : base_type(begin, end) {} + +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + + /// \constructor_initializer_list{linestring} + inline linestring(std::initializer_list<Point> l) + : base_type(l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it should be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{linestring} +// inline linestring & operator=(std::initializer_list<Point> l) +// { +// base_type::assign(l.begin(), l.end()); +// return *this; +// } +//#endif + +#endif +#endif }; } // namespace model diff --git a/boost/geometry/geometries/multi_linestring.hpp b/boost/geometry/geometries/multi_linestring.hpp index 2ba8e7196b..195a58139c 100644 --- a/boost/geometry/geometries/multi_linestring.hpp +++ b/boost/geometry/geometries/multi_linestring.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. @@ -22,6 +23,12 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/linestring_concept.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif namespace boost { namespace geometry { @@ -50,6 +57,39 @@ template class multi_linestring : public Container<LineString, Allocator<LineString> > { BOOST_CONCEPT_ASSERT( (concept::Linestring<LineString>) ); + +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST + + typedef Container<LineString, Allocator<LineString> > base_type; + +public: + /// \constructor_default{multi_linestring} + multi_linestring() + : base_type() + {} + +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + + /// \constructor_initializer_list{multi_linestring} + inline multi_linestring(std::initializer_list<LineString> l) + : base_type(l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it shoudl be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{multi_linestring} +// inline multi_linestring & operator=(std::initializer_list<LineString> l) +// { +// base_type::assign(l.begin(), l.end()); +// return *this; +// } +//#endif + +#endif +#endif }; diff --git a/boost/geometry/geometries/multi_point.hpp b/boost/geometry/geometries/multi_point.hpp index d0a782a1de..a5e64bb91c 100644 --- a/boost/geometry/geometries/multi_point.hpp +++ b/boost/geometry/geometries/multi_point.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. @@ -22,6 +23,12 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/point_concept.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif namespace boost { namespace geometry { @@ -66,6 +73,30 @@ public : inline multi_point(Iterator begin, Iterator end) : base_type(begin, end) {} + +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + + /// \constructor_initializer_list{multi_point} + inline multi_point(std::initializer_list<Point> l) + : base_type(l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it shoudl be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{multi_point} +// inline multi_point & operator=(std::initializer_list<Point> l) +// { +// base_type::assign(l.begin(), l.end()); +// return *this; +// } +//#endif + +#endif +#endif }; } // namespace model diff --git a/boost/geometry/geometries/multi_polygon.hpp b/boost/geometry/geometries/multi_polygon.hpp index 228074cd34..51fcf235f8 100644 --- a/boost/geometry/geometries/multi_polygon.hpp +++ b/boost/geometry/geometries/multi_polygon.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. @@ -22,6 +23,13 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/polygon_concept.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif + namespace boost { namespace geometry { @@ -48,6 +56,39 @@ template class multi_polygon : public Container<Polygon, Allocator<Polygon> > { BOOST_CONCEPT_ASSERT( (concept::Polygon<Polygon>) ); + +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST + + typedef Container<Polygon, Allocator<Polygon> > base_type; + +public: + /// \constructor_default{multi_polygon} + multi_polygon() + : base_type() + {} + +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + + /// \constructor_initializer_list{multi_polygon} + inline multi_polygon(std::initializer_list<Polygon> l) + : base_type(l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it shoudl be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{multi_polygon} +// inline multi_polygon & operator=(std::initializer_list<Polygon> l) +// { +// base_type::assign(l.begin(), l.end()); +// return *this; +// } +//#endif + +#endif +#endif }; diff --git a/boost/geometry/geometries/point.hpp b/boost/geometry/geometries/point.hpp index a25340c463..056c7d5d02 100644 --- a/boost/geometry/geometries/point.hpp +++ b/boost/geometry/geometries/point.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. @@ -23,7 +29,6 @@ #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 { @@ -38,6 +43,37 @@ namespace boost { namespace geometry namespace model { +namespace detail +{ + +template <std::size_t DimensionCount, std::size_t Index> +struct array_assign +{ + template <typename T> + static inline void apply(T values[], T const& value) + { + values[Index] = value; + } +}; + +// Specialization avoiding assigning element [2] for only 2 dimensions +template <> struct array_assign<2, 2> +{ + template <typename T> static inline void apply(T [], T const& ) {} +}; + +// Specialization avoiding assigning elements for (rarely used) points in 1 dim +template <> struct array_assign<1, 1> +{ + template <typename T> static inline void apply(T [], T const& ) {} +}; + +template <> struct array_assign<1, 2> +{ + template <typename T> static inline void apply(T [], T const& ) {} +}; + +} /*! \brief Basic point class, having coordinates defined in a neutral way \details Defines a neutral point class, fulfilling the Point Concept. @@ -64,18 +100,43 @@ template > class point { +private: + // The following enum is used to fully instantiate the + // CoordinateSystem class and check the correctness of the units + // passed for non-Cartesian coordinate systems. + enum { cs_check = sizeof(CoordinateSystem) }; + public: /// @brief Default constructor, no initialization inline point() - {} + { + BOOST_STATIC_ASSERT(DimensionCount >= 1); + } + + /// @brief Constructor to set one value + explicit inline point(CoordinateType const& v0) + { + detail::array_assign<DimensionCount, 0>::apply(m_values, v0); + detail::array_assign<DimensionCount, 1>::apply(m_values, CoordinateType()); + detail::array_assign<DimensionCount, 2>::apply(m_values, CoordinateType()); + } + + /// @brief Constructor to set two values + inline point(CoordinateType const& v0, CoordinateType const& v1) + { + detail::array_assign<DimensionCount, 0>::apply(m_values, v0); + detail::array_assign<DimensionCount, 1>::apply(m_values, v1); + detail::array_assign<DimensionCount, 2>::apply(m_values, CoordinateType()); + } - /// @brief Constructor to set one, two or three values - explicit inline point(CoordinateType const& v0, CoordinateType const& v1 = 0, CoordinateType const& v2 = 0) + /// @brief Constructor to set three values + inline point(CoordinateType const& v0, CoordinateType const& v1, + CoordinateType const& v2) { - if (DimensionCount >= 1) m_values[0] = v0; - if (DimensionCount >= 2) m_values[1] = v1; - if (DimensionCount >= 3) m_values[2] = v2; + detail::array_assign<DimensionCount, 0>::apply(m_values, v0); + detail::array_assign<DimensionCount, 1>::apply(m_values, v1); + detail::array_assign<DimensionCount, 2>::apply(m_values, v2); } /// @brief Get a coordinate diff --git a/boost/geometry/geometries/polygon.hpp b/boost/geometry/geometries/polygon.hpp index ec8d1ec38f..5f2e87a11d 100644 --- a/boost/geometry/geometries/polygon.hpp +++ b/boost/geometry/geometries/polygon.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. @@ -26,6 +27,13 @@ #include <boost/geometry/geometries/concepts/point_concept.hpp> #include <boost/geometry/geometries/ring.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif + namespace boost { namespace geometry { @@ -83,6 +91,46 @@ public: inline ring_type& outer() { return m_outer; } inline inner_container_type & inners() { return m_inners; } +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST + + /// \constructor_default{polygon} + inline polygon() + : m_outer() + , m_inners() + {} + +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + /// \constructor_initializer_list{polygon} + inline polygon(std::initializer_list<ring_type> l) + : m_outer(l.size() > 0 ? *l.begin() : ring_type()) + , m_inners(l.size() > 0 ? l.begin() + 1 : l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it shoudl be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{polygon} +// inline polygon & operator=(std::initializer_list<ring_type> l) +// { +// if ( l.size() > 0 ) +// { +// m_outer = *l.begin(); +// m_inners.assign(l.begin() + 1, l.end()); +// } +// else +// { +// m_outer.clear(); +// m_inners.clear(); +// } +// return *this; +// } +//#endif + +#endif +#endif + /// Utility method, clears outer and inner rings inline void clear() { diff --git a/boost/geometry/geometries/ring.hpp b/boost/geometry/geometries/ring.hpp index 998619785a..502c95d759 100644 --- a/boost/geometry/geometries/ring.hpp +++ b/boost/geometry/geometries/ring.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. @@ -26,6 +27,12 @@ #include <boost/geometry/geometries/concepts/point_concept.hpp> +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#include <boost/config.hpp> +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#endif namespace boost { namespace geometry { @@ -72,6 +79,30 @@ public : inline ring(Iterator begin, Iterator end) : base_type(begin, end) {} + +#ifdef BOOST_GEOMETRY_EXPERIMENTAL_ENABLE_INITIALIZER_LIST +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + + /// \constructor_initializer_list{ring} + inline ring(std::initializer_list<Point> l) + : base_type(l.begin(), l.end()) + {} + +// Commented out for now in order to support Boost.Assign +// Without this assignment operator first the object should be created +// from initializer list, then it shoudl be moved. +//// Without this workaround in MSVC the assignment operator is ambiguous +//#ifndef BOOST_MSVC +// /// \assignment_initializer_list{ring} +// inline ring & operator=(std::initializer_list<Point> l) +// { +// base_type::assign(l.begin(), l.end()); +// return *this; +// } +//#endif + +#endif +#endif }; } // namespace model diff --git a/boost/geometry/geometries/variant.hpp b/boost/geometry/geometries/variant.hpp index 9db11d5a82..881eab9c8b 100644 --- a/boost/geometry/geometries/variant.hpp +++ b/boost/geometry/geometries/variant.hpp @@ -16,6 +16,7 @@ #include <boost/variant/variant_fwd.hpp> +#include <boost/mpl/front.hpp> namespace boost { namespace geometry { @@ -23,7 +24,11 @@ namespace boost { namespace geometry { template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct point_type<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > - : point_type<T0> + : point_type< + typename boost::mpl::front< + typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types + >::type + > {}; diff --git a/boost/geometry/geometry.hpp b/boost/geometry/geometry.hpp index 110f0e60ff..8d34a0e4ef 100644 --- a/boost/geometry/geometry.hpp +++ b/boost/geometry/geometry.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015 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. @@ -25,6 +31,7 @@ #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/srs.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> @@ -34,9 +41,9 @@ #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/radius.hpp> #include <boost/geometry/core/topological_dimension.hpp> - #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/arithmetic/dot_product.hpp> diff --git a/boost/geometry/index/detail/algorithms/is_valid.hpp b/boost/geometry/index/detail/algorithms/is_valid.hpp index d85ac56d69..676eec2d2a 100644 --- a/boost/geometry/index/detail/algorithms/is_valid.hpp +++ b/boost/geometry/index/detail/algorithms/is_valid.hpp @@ -80,6 +80,9 @@ struct is_valid<Indexable, segment_tag> template <typename Indexable> inline bool is_valid(Indexable const& b) { + // CONSIDER: detection of NaNs + // e.g. by comparison of b with copy of b + return dispatch::is_valid<Indexable>::apply(b); } diff --git a/boost/geometry/index/detail/assert.hpp b/boost/geometry/index/detail/assert.hpp index 22af315bc8..311f37f640 100644 --- a/boost/geometry/index/detail/assert.hpp +++ b/boost/geometry/index/detail/assert.hpp @@ -1,6 +1,6 @@ // Boost.Geometry Index // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// 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 @@ -11,20 +11,11 @@ #include <boost/assert.hpp> +#ifndef BOOST_GEOMETRY_INDEX_ASSERT + #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_ASSERT #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 index 572368e273..0cd882fc94 100644 --- a/boost/geometry/index/detail/bounded_view.hpp +++ b/boost/geometry/index/detail/bounded_view.hpp @@ -155,7 +155,7 @@ struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>, //static inline void set(box_type & b, coordinate_type const& value) //{ - // BOOST_ASSERT(false); + // BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view"); //} }; @@ -173,7 +173,7 @@ struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>, //static inline void set(box_type & b, coordinate_type const& value) //{ - // BOOST_ASSERT(false); + // BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view"); //} }; diff --git a/boost/geometry/index/detail/distance_predicates.hpp b/boost/geometry/index/detail/distance_predicates.hpp index 3e057290a6..9a9371df95 100644 --- a/boost/geometry/index/detail/distance_predicates.hpp +++ b/boost/geometry/index/detail/distance_predicates.hpp @@ -3,7 +3,7 @@ // Spatial index distance predicates, calculators and checkers // used in nearest query - specialized for envelopes // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -104,13 +104,13 @@ struct 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 > +struct calculate_distance< predicates::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) + static inline bool apply(predicates::nearest<PointRelation> const& p, Indexable const& i, result_type & result) { result = geometry::comparable_distance(relation::value(p.point_or_relation), i); return true; @@ -118,12 +118,12 @@ struct calculate_distance< nearest<PointRelation>, Indexable, Tag > }; template <typename Point, typename Indexable> -struct calculate_distance< nearest< to_centroid<Point> >, Indexable, value_tag> +struct calculate_distance< predicates::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) + static inline bool apply(predicates::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; @@ -131,12 +131,12 @@ struct calculate_distance< nearest< to_centroid<Point> >, Indexable, value_tag> }; template <typename Point, typename Indexable> -struct calculate_distance< nearest< to_furthest<Point> >, Indexable, value_tag> +struct calculate_distance< predicates::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) + static inline bool apply(predicates::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; @@ -144,13 +144,13 @@ struct calculate_distance< nearest< to_furthest<Point> >, Indexable, value_tag> }; template <typename SegmentOrLinestring, typename Indexable, typename Tag> -struct calculate_distance< path<SegmentOrLinestring>, Indexable, Tag> +struct calculate_distance< predicates::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) + static inline bool apply(predicates::path<SegmentOrLinestring> const& p, Indexable const& i, result_type & result) { return index::detail::path_intersection(i, p.geometry, result); } diff --git a/boost/geometry/index/detail/exception.hpp b/boost/geometry/index/detail/exception.hpp index c3ea0e1923..e2090533e7 100644 --- a/boost/geometry/index/detail/exception.hpp +++ b/boost/geometry/index/detail/exception.hpp @@ -1,6 +1,6 @@ // Boost.Geometry Index // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// 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 @@ -9,10 +9,14 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP +#include <boost/core/no_exceptions_support.hpp> + #ifndef BOOST_NO_EXCEPTIONS #include <stdexcept> +#include <boost/throw_exception.hpp> #else #include <cstdlib> +#include <boost/geometry/index/detail/assert.hpp> #endif namespace boost { namespace geometry { namespace index { namespace detail { @@ -21,47 +25,58 @@ namespace boost { namespace geometry { namespace index { namespace detail { inline void throw_runtime_error(const char * str) { - throw std::runtime_error(str); + BOOST_THROW_EXCEPTION(std::runtime_error(str)); } inline void throw_logic_error(const char * str) { - throw std::logic_error(str); + BOOST_THROW_EXCEPTION(std::logic_error(str)); } inline void throw_invalid_argument(const char * str) { - throw std::invalid_argument(str); + BOOST_THROW_EXCEPTION(std::invalid_argument(str)); } inline void throw_length_error(const char * str) { - throw std::length_error(str); + BOOST_THROW_EXCEPTION(std::length_error(str)); +} + +inline void throw_out_of_range(const char * str) +{ + BOOST_THROW_EXCEPTION(std::out_of_range(str)); } #else inline void throw_runtime_error(const char * str) { - BOOST_ASSERT_MSG(!"runtime_error thrown", str); + BOOST_GEOMETRY_INDEX_ASSERT(!"runtime_error thrown", str); std::abort(); } inline void throw_logic_error(const char * str) { - BOOST_ASSERT_MSG(!"logic_error thrown", str); + BOOST_GEOMETRY_INDEX_ASSERT(!"logic_error thrown", str); std::abort(); } inline void throw_invalid_argument(const char * str) { - BOOST_ASSERT_MSG(!"invalid_argument thrown", str); + BOOST_GEOMETRY_INDEX_ASSERT(!"invalid_argument thrown", str); std::abort(); } inline void throw_length_error(const char * str) { - BOOST_ASSERT_MSG(!"length_error thrown", str); + BOOST_GEOMETRY_INDEX_ASSERT(!"length_error thrown", str); + std::abort(); +} + +inline void throw_out_of_range(const char * str) +{ + BOOST_GEOMETRY_INDEX_ASSERT(!"out_of_range thrown", str); std::abort(); } diff --git a/boost/geometry/index/detail/predicates.hpp b/boost/geometry/index/detail/predicates.hpp index b92256649a..60f80207d8 100644 --- a/boost/geometry/index/detail/predicates.hpp +++ b/boost/geometry/index/detail/predicates.hpp @@ -2,7 +2,7 @@ // // Spatial query predicates definition and checks. // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -16,6 +16,8 @@ namespace boost { namespace geometry { namespace index { namespace detail { +namespace predicates { + // ------------------------------------------------------------------ // // predicates // ------------------------------------------------------------------ // @@ -92,6 +94,8 @@ struct path unsigned count; }; +} // namespace predicates + // ------------------------------------------------------------------ // // predicate_check // ------------------------------------------------------------------ // @@ -108,20 +112,20 @@ struct predicate_check // ------------------------------------------------------------------ // template <typename Fun> -struct predicate_check<satisfies<Fun, false>, value_tag> +struct predicate_check<predicates::satisfies<Fun, false>, value_tag> { template <typename Value, typename Indexable> - static inline bool apply(satisfies<Fun, false> const& p, Value const& v, Indexable const&) + static inline bool apply(predicates::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> +struct predicate_check<predicates::satisfies<Fun, true>, value_tag> { template <typename Value, typename Indexable> - static inline bool apply(satisfies<Fun, true> const& p, Value const& v, Indexable const&) + static inline bool apply(predicates::satisfies<Fun, true> const& p, Value const& v, Indexable const&) { return !p.fun(v); } @@ -136,7 +140,7 @@ struct spatial_predicate_call }; template <> -struct spatial_predicate_call<contains_tag> +struct spatial_predicate_call<predicates::contains_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -146,7 +150,7 @@ struct spatial_predicate_call<contains_tag> }; template <> -struct spatial_predicate_call<covered_by_tag> +struct spatial_predicate_call<predicates::covered_by_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -156,7 +160,7 @@ struct spatial_predicate_call<covered_by_tag> }; template <> -struct spatial_predicate_call<covers_tag> +struct spatial_predicate_call<predicates::covers_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -166,7 +170,7 @@ struct spatial_predicate_call<covers_tag> }; template <> -struct spatial_predicate_call<disjoint_tag> +struct spatial_predicate_call<predicates::disjoint_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -176,7 +180,7 @@ struct spatial_predicate_call<disjoint_tag> }; template <> -struct spatial_predicate_call<intersects_tag> +struct spatial_predicate_call<predicates::intersects_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -186,7 +190,7 @@ struct spatial_predicate_call<intersects_tag> }; template <> -struct spatial_predicate_call<overlaps_tag> +struct spatial_predicate_call<predicates::overlaps_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -196,7 +200,7 @@ struct spatial_predicate_call<overlaps_tag> }; template <> -struct spatial_predicate_call<touches_tag> +struct spatial_predicate_call<predicates::touches_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -206,7 +210,7 @@ struct spatial_predicate_call<touches_tag> }; template <> -struct spatial_predicate_call<within_tag> +struct spatial_predicate_call<predicates::within_tag> { template <typename G1, typename G2> static inline bool apply(G1 const& g1, G2 const& g2) @@ -219,9 +223,9 @@ struct spatial_predicate_call<within_tag> // spatial predicate template <typename Geometry, typename Tag> -struct predicate_check<spatial_predicate<Geometry, Tag, false>, value_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, value_tag> { - typedef spatial_predicate<Geometry, Tag, false> Pred; + typedef predicates::spatial_predicate<Geometry, Tag, false> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& p, Value const&, Indexable const& i) @@ -232,9 +236,9 @@ struct predicate_check<spatial_predicate<Geometry, Tag, false>, value_tag> // negated spatial predicate template <typename Geometry, typename Tag> -struct predicate_check<spatial_predicate<Geometry, Tag, true>, value_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, value_tag> { - typedef spatial_predicate<Geometry, Tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, Tag, true> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& p, Value const&, Indexable const& i) @@ -246,20 +250,20 @@ struct predicate_check<spatial_predicate<Geometry, Tag, true>, value_tag> // ------------------------------------------------------------------ // template <typename DistancePredicates> -struct predicate_check<nearest<DistancePredicates>, value_tag> +struct predicate_check<predicates::nearest<DistancePredicates>, value_tag> { template <typename Value, typename Box> - static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&) + static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&) { return true; } }; template <typename Linestring> -struct predicate_check<path<Linestring>, value_tag> +struct predicate_check<predicates::path<Linestring>, value_tag> { template <typename Value, typename Box> - static inline bool apply(path<Linestring> const&, Value const&, Box const&) + static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&) { return true; } @@ -270,10 +274,10 @@ struct predicate_check<path<Linestring>, value_tag> // ------------------------------------------------------------------ // template <typename Fun, bool Negated> -struct predicate_check<satisfies<Fun, Negated>, bounds_tag> +struct predicate_check<predicates::satisfies<Fun, Negated>, bounds_tag> { template <typename Value, typename Box> - static bool apply(satisfies<Fun, Negated> const&, Value const&, Box const&) + static bool apply(predicates::satisfies<Fun, Negated> const&, Value const&, Box const&) { return true; } @@ -295,53 +299,53 @@ struct predicate_check<satisfies<Fun, Negated>, bounds_tag> // spatial predicate - default template <typename Geometry, typename Tag> -struct predicate_check<spatial_predicate<Geometry, Tag, false>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, bounds_tag> { - typedef spatial_predicate<Geometry, Tag, false> Pred; + typedef predicates::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); + return spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry); } }; // spatial predicate - contains template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, contains_tag, false>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, false>, bounds_tag> { - typedef spatial_predicate<Geometry, contains_tag, false> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::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); + return spatial_predicate_call<predicates::contains_tag>::apply(i, p.geometry); } }; // spatial predicate - covers template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, covers_tag, false>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, false>, bounds_tag> { - typedef spatial_predicate<Geometry, covers_tag, false> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::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); + return spatial_predicate_call<predicates::covers_tag>::apply(i, p.geometry); } }; // spatial predicate - disjoint template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, disjoint_tag, false>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::disjoint_tag, false>, bounds_tag> { - typedef spatial_predicate<Geometry, disjoint_tag, false> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::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); + return !spatial_predicate_call<predicates::covered_by_tag>::apply(i, p.geometry); } }; @@ -359,9 +363,9 @@ struct predicate_check<spatial_predicate<Geometry, disjoint_tag, false>, bounds_ // negated spatial predicate - default template <typename Geometry, typename Tag> -struct predicate_check<spatial_predicate<Geometry, Tag, true>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, Tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, Tag, true> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& p, Value const&, Indexable const& i) @@ -372,9 +376,9 @@ struct predicate_check<spatial_predicate<Geometry, Tag, true>, bounds_tag> // negated spatial predicate - contains template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, contains_tag, true>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, contains_tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::contains_tag, true> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& , Value const&, Indexable const& ) @@ -385,9 +389,9 @@ struct predicate_check<spatial_predicate<Geometry, contains_tag, true>, bounds_t // negated spatial predicate - covers template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, covers_tag, true>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, covers_tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::covers_tag, true> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& , Value const&, Indexable const& ) @@ -398,22 +402,22 @@ struct predicate_check<spatial_predicate<Geometry, covers_tag, true>, bounds_tag // negated spatial predicate - intersects template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, intersects_tag, true>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::intersects_tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, intersects_tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::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); + return !spatial_predicate_call<predicates::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> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, overlaps_tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true> Pred; template <typename Value, typename Indexable> static inline bool apply(Pred const& , Value const&, Indexable const& ) @@ -424,34 +428,34 @@ struct predicate_check<spatial_predicate<Geometry, overlaps_tag, true>, bounds_t // negated spatial predicate - touches template <typename Geometry> -struct predicate_check<spatial_predicate<Geometry, touches_tag, true>, bounds_tag> +struct predicate_check<predicates::spatial_predicate<Geometry, predicates::touches_tag, true>, bounds_tag> { - typedef spatial_predicate<Geometry, touches_tag, true> Pred; + typedef predicates::spatial_predicate<Geometry, predicates::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); + return !spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry); } }; // ------------------------------------------------------------------ // template <typename DistancePredicates> -struct predicate_check<nearest<DistancePredicates>, bounds_tag> +struct predicate_check<predicates::nearest<DistancePredicates>, bounds_tag> { template <typename Value, typename Box> - static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&) + static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&) { return true; } }; template <typename Linestring> -struct predicate_check<path<Linestring>, bounds_tag> +struct predicate_check<predicates::path<Linestring>, bounds_tag> { template <typename Value, typename Box> - static inline bool apply(path<Linestring> const&, Value const&, Box const&) + static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&) { return true; } @@ -697,13 +701,13 @@ struct predicates_is_distance }; template <typename DistancePredicates> -struct predicates_is_distance< nearest<DistancePredicates> > +struct predicates_is_distance< predicates::nearest<DistancePredicates> > { static const unsigned value = 1; }; template <typename Linestring> -struct predicates_is_distance< path<Linestring> > +struct predicates_is_distance< predicates::path<Linestring> > { static const unsigned value = 1; }; diff --git a/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp index 05a64c7b72..a10b046c0d 100644 --- a/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp +++ b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp @@ -149,7 +149,7 @@ struct find_greatest_normalized_separation // highest_low - lowest_high separation = difference<separation_type>(lowest_high, highest_low); - // BOOST_ASSERT(0 <= width); + // BOOST_GEOMETRY_INDEX_ASSERT(0 <= width); if ( std::numeric_limits<coordinate_type>::epsilon() < width ) separation /= width; diff --git a/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp b/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp deleted file mode 100644 index dd55c6d76c..0000000000 --- a/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// 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/dynamic_visitor.hpp b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp deleted file mode 100644 index 43dff56bcb..0000000000 --- a/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// 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 index a632ece66a..528d473170 100644 --- a/boost/geometry/index/detail/rtree/node/node.hpp +++ b/boost/geometry/index/detail/rtree/node/node.hpp @@ -2,7 +2,7 @@ // // R-tree nodes // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -16,8 +16,8 @@ #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/scoped_deallocator.hpp> //#include <boost/geometry/index/detail/rtree/node/weak_visitor.hpp> //#include <boost/geometry/index/detail/rtree/node/weak_dynamic.hpp> @@ -27,7 +27,7 @@ #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/index/detail/rtree/node/subtree_destroyer.hpp> #include <boost/geometry/algorithms/expand.hpp> @@ -70,11 +70,11 @@ struct destroy_element 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators) { - node_auto_ptr dummy(element.second, allocators); + subtree_destroyer dummy(element.second, allocators); element.second = 0; } @@ -108,11 +108,11 @@ private: 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; + typedef rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; for ( ; first != last ; ++first ) { - node_auto_ptr dummy(first->second, allocators); + subtree_destroyer dummy(first->second, allocators); first->second = 0; } } diff --git a/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp b/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp new file mode 100644 index 0000000000..2d08d89ef7 --- /dev/null +++ b/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp @@ -0,0 +1,48 @@ +// Boost.Geometry Index +// +// R-tree scoped deallocator +// +// Copyright (c) 2011-2015 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_SCOPED_DEALLOCATOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template <typename Alloc> +class scoped_deallocator +{ + scoped_deallocator(scoped_deallocator const&); + scoped_deallocator & operator=(scoped_deallocator const&); +public: + typedef typename Alloc::pointer pointer; + inline scoped_deallocator(pointer p, Alloc & a) + : m_ptr(p), m_alloc(a) + {} + inline ~scoped_deallocator() + { + if ( m_ptr ) + { + boost::container::allocator_traits<Alloc>::deallocate(m_alloc, m_ptr, 1); + } + } + inline void release() + { + m_ptr = 0; + } +private: + pointer m_ptr; + Alloc & m_alloc; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP diff --git a/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp b/boost/geometry/index/detail/rtree/node/subtree_destroyer.hpp index c19e123b62..3376068eed 100644 --- a/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp +++ b/boost/geometry/index/detail/rtree/node/subtree_destroyer.hpp @@ -1,15 +1,15 @@ // Boost.Geometry Index // -// R-tree node auto ptr +// R-tree subtree scoped destroyer // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SUBTREE_DESTROYED_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SUBTREE_DESTROYED_HPP #include <boost/geometry/index/detail/rtree/visitors/destroy.hpp> @@ -17,31 +17,29 @@ 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 +class subtree_destroyer { 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&); + subtree_destroyer(subtree_destroyer const&); + subtree_destroyer & operator=(subtree_destroyer const&); public: - node_auto_ptr(pointer ptr, Allocators & allocators) + subtree_destroyer(pointer ptr, Allocators & allocators) : m_ptr(ptr) , m_allocators(allocators) {} - ~node_auto_ptr() + ~subtree_destroyer() { reset(); } void reset(pointer ptr = 0) { - if ( m_ptr ) + if ( m_ptr && m_ptr != ptr ) { detail::rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(m_ptr, m_allocators); detail::rtree::apply_visitor(del_v, *m_ptr); @@ -78,4 +76,4 @@ private: }}} // namespace boost::geometry::index -#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SUBTREE_DESTROYED_HPP diff --git a/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp index f13dd10360..8e052e5216 100644 --- a/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp +++ b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp @@ -96,7 +96,8 @@ class allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag> typename node< Value, Parameters, Box, allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>, - node_variant_dynamic_tag>::type + node_variant_dynamic_tag + >::type >::other { typedef typename Allocator::template rebind< @@ -180,7 +181,7 @@ struct create_variant_node if ( 0 == p ) throw_runtime_error("boost::geometry::index::rtree node creation failed"); - auto_deallocator<AllocNode> deallocator(alloc_node, p); + scoped_deallocator<AllocNode> deallocator(p, alloc_node); Al::construct(alloc_node, boost::addressof(*p), Node(alloc_node)); // implicit cast to Variant diff --git a/boost/geometry/index/detail/rtree/node/variant_static.hpp b/boost/geometry/index/detail/rtree/node/variant_static.hpp index f6e9761b2d..174ceb7e7f 100644 --- a/boost/geometry/index/detail/rtree/node/variant_static.hpp +++ b/boost/geometry/index/detail/rtree/node/variant_static.hpp @@ -79,7 +79,7 @@ struct visitor<Value, Parameters, Box, Allocators, node_variant_static_tag, IsVi // allocators template <typename Allocator, typename Value, typename Parameters, typename Box> -struct allocators<Allocator, Value, Parameters, Box, node_variant_static_tag> +class allocators<Allocator, Value, Parameters, Box, node_variant_static_tag> : public Allocator::template rebind< typename node< Value, Parameters, Box, @@ -153,40 +153,6 @@ public: 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 diff --git a/boost/geometry/index/detail/rtree/node/variant_visitor.hpp b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp index ffd67039d2..e272f9e1d9 100644 --- a/boost/geometry/index/detail/rtree/node/variant_visitor.hpp +++ b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp @@ -11,7 +11,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP -#include <boost/variant.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/get.hpp> +#include <boost/variant/variant.hpp> namespace boost { namespace geometry { namespace index { diff --git a/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp index b828b35f45..d49e347826 100644 --- a/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp +++ b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp @@ -197,7 +197,7 @@ struct create_weak_node if ( 0 == p ) throw_runtime_error("boost::geometry::index::rtree node creation failed"); - auto_deallocator<AllocNode> deallocator(alloc_node, p); + scoped_deallocator<AllocNode> deallocator(p, alloc_node); Al::construct(alloc_node, boost::addressof(*p), alloc_node); diff --git a/boost/geometry/index/detail/rtree/pack_create.hpp b/boost/geometry/index/detail/rtree/pack_create.hpp index 46bf357fc4..b7be41ab2b 100644 --- a/boost/geometry/index/detail/rtree/pack_create.hpp +++ b/boost/geometry/index/detail/rtree/pack_create.hpp @@ -2,7 +2,7 @@ // // R-tree initial packing // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -122,7 +122,7 @@ class pack 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; typedef typename Allocators::size_type size_type; typedef typename geometry::point_type<Box>::type point_type; @@ -161,10 +161,21 @@ public: geometry::assign_inverse(hint_box); for ( ; first != last ; ++first ) { - geometry::expand(hint_box, translator(*first)); + // NOTE: support for iterators not returning true references adapted + // to Geometry concept and default translator returning true reference + // An alternative would be to dereference the iterator and translate + // in one expression each time the indexable was needed. + typename std::iterator_traits<InIt>::reference in_ref = *first; + typename Translator::result_type indexable = translator(in_ref); + + // NOTE: added for consistency with insert() + // CONSIDER: alternative - ignore invalid indexable or throw an exception + BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(indexable), "Indexable is invalid"); + + geometry::expand(hint_box, indexable); point_type pt; - geometry::centroid(translator(*first), pt); + geometry::centroid(indexable, pt); entries.push_back(std::make_pair(pt, first)); } @@ -187,17 +198,19 @@ private: 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); + BOOST_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count, + "unexpected parameters"); if ( subtree_counts.maxc <= 1 ) { // ROOT or LEAF - BOOST_ASSERT(values_count <= parameters.get_max_elements()); + BOOST_GEOMETRY_INDEX_ASSERT(values_count <= parameters.get_max_elements(), + "too big number of 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); + subtree_destroyer auto_remover(n, allocators); leaf & l = rtree::get<leaf>(*n); // reserve space for values @@ -207,8 +220,11 @@ private: geometry::assign_inverse(elements_box); for ( ; first != last ; ++first ) { - rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C) + // NOTE: push_back() must be called at the end in order to support move_iterator. + // The iterator is dereferenced 2x (no temporary reference) to support + // non-true reference types and move_iterator without boost::forward<>. geometry::expand(elements_box, translator(*(first->second))); + rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C) } auto_remover.release(); @@ -222,7 +238,7 @@ private: // 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); + subtree_destroyer auto_remover(n, allocators); internal_node & in = rtree::get<internal_node>(*n); // reserve space for values @@ -248,9 +264,11 @@ private: 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_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count, + "unexpected parameters"); - BOOST_ASSERT_MSG( subtree_counts.minc <= values_count, "too small number of elements"); + BOOST_GEOMETRY_INDEX_ASSERT(subtree_counts.minc <= values_count, + "too small number of elements"); // only one packet if ( values_count <= subtree_counts.maxc ) @@ -262,7 +280,7 @@ private: // 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); + subtree_destroyer 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(); @@ -343,7 +361,7 @@ private: { if ( subtree_counts.minc <= r ) // e.g. 10 <= 2 == false { - //BOOST_ASSERT_MSG(0 < n, "unexpected value"); + //BOOST_GEOMETRY_INDEX_ASSERT(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 @@ -354,7 +372,7 @@ private: 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"); + //BOOST_GEOMETRY_INDEX_ASSERT(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 diff --git a/boost/geometry/index/detail/rtree/query_iterators.hpp b/boost/geometry/index/detail/rtree/query_iterators.hpp index 8366fca191..74000d03ef 100644 --- a/boost/geometry/index/detail/rtree/query_iterators.hpp +++ b/boost/geometry/index/detail/rtree/query_iterators.hpp @@ -2,7 +2,7 @@ // // R-tree query iterators // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -11,9 +11,8 @@ #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 +#include <boost/scoped_ptr.hpp> + //#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { @@ -29,27 +28,27 @@ struct end_query_iterator reference operator*() const { - BOOST_ASSERT_MSG(false, "iterator not dereferencable"); + BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable"); pointer p(0); return *p; } const value_type * operator->() const { - BOOST_ASSERT_MSG(false, "iterator not dereferencable"); + BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable"); const value_type * p = 0; return p; } end_query_iterator & operator++() { - BOOST_ASSERT_MSG(false, "iterator not incrementable"); + BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable"); return *this; } end_query_iterator operator++(int) { - BOOST_ASSERT_MSG(false, "iterator not incrementable"); + BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable"); return *this; } @@ -197,9 +196,6 @@ inline bool operator!=(L const& l, R const& 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 { @@ -246,73 +242,7 @@ public: 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"); + BOOST_GEOMETRY_INDEX_ASSERT(p, "iterators can't be compared"); return m_iterator == p->m_iterator; } @@ -320,13 +250,12 @@ 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; + typedef boost::scoped_ptr<iterator_base> iterator_ptr; public: typedef std::input_iterator_tag iterator_category; @@ -353,21 +282,24 @@ public: #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); + if ( this != boost::addressof(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()) + : m_ptr(0) { - o.m_ptr.release(); + m_ptr.swap(o.m_ptr); } query_iterator & operator=(query_iterator && o) { if ( this != boost::addressof(o) ) { - m_ptr.reset(o.m_ptr.get()); - o.m_ptr.release(); + m_ptr.swap(o.m_ptr); + o.m_ptr.reset(); } return *this; } @@ -378,20 +310,23 @@ private: public: query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o) { - m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0); + if ( this != boost::addressof(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()) + : m_ptr(0) { - o.m_ptr.release(); + m_ptr.swap(o.m_ptr); } 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(); + m_ptr.swap(o.m_ptr); + o.m_ptr.reset(); } return *this; } @@ -444,156 +379,4 @@ private: }}}}}} // 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/insert.hpp b/boost/geometry/index/detail/rtree/rstar/insert.hpp index e544d6dd1e..ce92140872 100644 --- a/boost/geometry/index/detail/rtree/rstar/insert.hpp +++ b/boost/geometry/index/detail/rtree/rstar/insert.hpp @@ -472,8 +472,9 @@ public: , m_relative_level(relative_level), m_allocators(allocators) {} - inline void operator()(internal_node & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + inline void operator()(internal_node & n) { + boost::ignore_unused(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 @@ -498,8 +499,9 @@ public: } } - inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + inline void operator()(leaf & n) { + boost::ignore_unused(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 diff --git a/boost/geometry/index/detail/rtree/utilities/are_counts_ok.hpp b/boost/geometry/index/detail/rtree/utilities/are_counts_ok.hpp new file mode 100644 index 0000000000..10a1bec6ad --- /dev/null +++ b/boost/geometry/index/detail/rtree/utilities/are_counts_ok.hpp @@ -0,0 +1,110 @@ +// Boost.Geometry Index +// +// R-tree nodes elements numbers validating visitor implementation +// +// Copyright (c) 2011-2015 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_COUNTS_OK_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_COUNTS_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_counts_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; + typedef typename Options::parameters_type parameters_type; + +public: + inline are_counts_ok(parameters_type const& parameters) + : result(true), m_current_level(0), m_parameters(parameters) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type<internal_node>::type elements_type; + elements_type const& elements = rtree::elements(n); + + // root internal node shouldn't contain 0 elements + if ( elements.empty() + || !check_count(elements) ) + { + 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() && result == true ; + ++it) + { + rtree::apply_visitor(*this, *it->second); + } + + 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 ( ( m_current_level > 0 && elements.empty() ) + || !check_count(elements) ) + { + result = false; + } + } + + bool result; + +private: + template <typename Elements> + bool check_count(Elements const& elements) + { + // root may contain count < min but should never contain count > max + return elements.size() <= m_parameters.get_max_elements() + && ( elements.size() >= m_parameters.get_min_elements() + || m_current_level == 0 ); + } + + size_t m_current_level; + parameters_type const& m_parameters; +}; + +} // namespace visitors + +template <typename Rtree> inline +bool are_counts_ok(Rtree const& tree) +{ + typedef utilities::view<Rtree> RTV; + RTV rtv(tree); + + visitors::are_counts_ok< + typename RTV::value_type, + typename RTV::options_type, + typename RTV::box_type, + typename RTV::allocators_type + > v(tree.parameters()); + + rtv.apply_visitor(v); + + return v.result; +} + +}}}}}} // namespace boost::geometry::index::detail::rtree::utilities + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_COUNTS_OK_HPP diff --git a/boost/geometry/index/detail/rtree/visitors/copy.hpp b/boost/geometry/index/detail/rtree/visitors/copy.hpp index 8fc25ac803..86ffc99caf 100644 --- a/boost/geometry/index/detail/rtree/visitors/copy.hpp +++ b/boost/geometry/index/detail/rtree/visitors/copy.hpp @@ -2,7 +2,7 @@ // // R-tree deep copying visitor implementation // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -24,7 +24,7 @@ public: 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; typedef typename Allocators::node_pointer node_pointer; explicit inline copy(Allocators & allocators) @@ -35,7 +35,7 @@ public: 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); + subtree_destroyer new_node(raw_new_node, m_allocators); typedef typename rtree::elements_type<internal_node>::type elements_type; elements_type & elements = rtree::elements(n); @@ -48,7 +48,7 @@ public: 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); + subtree_destroyer auto_result(result, m_allocators); elements_dst.push_back( rtree::make_ptr_pair(it->first, result) ); // MAY THROW, STRONG (E: alloc, copy) @@ -62,7 +62,7 @@ public: 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); + subtree_destroyer new_node(raw_new_node, m_allocators); typedef typename rtree::elements_type<leaf>::type elements_type; elements_type & elements = rtree::elements(l); diff --git a/boost/geometry/index/detail/rtree/visitors/destroy.hpp b/boost/geometry/index/detail/rtree/visitors/destroy.hpp index 62722b97a8..b4a800eac2 100644 --- a/boost/geometry/index/detail/rtree/visitors/destroy.hpp +++ b/boost/geometry/index/detail/rtree/visitors/destroy.hpp @@ -2,7 +2,7 @@ // // R-tree destroying visitor implementation // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// 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 @@ -51,8 +51,9 @@ public: rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, node_to_destroy); } - inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(l)) + inline void operator()(leaf & l) { + boost::ignore_unused(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); diff --git a/boost/geometry/index/detail/rtree/visitors/distance_query.hpp b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp index 342cc4bbc3..fc0929e9ed 100644 --- a/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -344,7 +344,7 @@ public: , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)()) { - BOOST_ASSERT_MSG(0 < max_count(), "k must be greather than 0"); + BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0"); } const_reference dereference() const @@ -399,7 +399,7 @@ public: } // if node is further than the furthest neighbour, following nodes also will be further - BOOST_ASSERT_MSG(neighbors.size() <= max_count(), "unexpected neighbours count"); + BOOST_GEOMETRY_INDEX_ASSERT(neighbors.size() <= max_count(), "unexpected neighbours count"); if ( max_count() <= neighbors.size() && is_node_prunable(neighbors.back().first, branches[current_branch].first) ) { @@ -426,10 +426,10 @@ public: 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"); + BOOST_GEOMETRY_INDEX_ASSERT(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; } diff --git a/boost/geometry/index/detail/rtree/visitors/insert.hpp b/boost/geometry/index/detail/rtree/visitors/insert.hpp index 388b3193f6..e697c065e1 100644 --- a/boost/geometry/index/detail/rtree/visitors/insert.hpp +++ b/boost/geometry/index/detail/rtree/visitors/insert.hpp @@ -2,7 +2,7 @@ // // R-tree inserting visitor implementation // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -115,7 +115,7 @@ protected: 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; public: typedef index::detail::varray< @@ -133,8 +133,8 @@ public: { // 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 additional node, use auto destroyer for automatic destruction on exception + subtree_destroyer 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); @@ -232,7 +232,7 @@ protected: 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; typedef typename Allocators::node_pointer node_pointer; typedef typename Allocators::size_type size_type; @@ -340,7 +340,7 @@ protected: // 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); + subtree_destroyer 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() ) @@ -356,7 +356,7 @@ protected: 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) + subtree_destroyer new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc) BOOST_TRY { @@ -365,7 +365,7 @@ protected: } BOOST_CATCH(...) { - // clear new root to not delete in the ~node_auto_ptr() potentially stored old root node + // clear new root to not delete in the ~subtree_destroyer() potentially stored old root node rtree::elements(rtree::get<internal_node>(*new_root)).clear(); BOOST_RETHROW // RETHROW } diff --git a/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp index 6d21afd99e..dd2159c71e 100644 --- a/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp +++ b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp @@ -2,7 +2,7 @@ // // R-tree leaf node checking visitor implementation // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -21,9 +21,13 @@ struct is_leaf : public rtree::visitor<Value, typename Options::parameters_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; + is_leaf() + : result(false) + {} + inline void operator()(internal_node const&) { - result = false; + // result = false; } inline void operator()(leaf const&) diff --git a/boost/geometry/index/detail/rtree/visitors/remove.hpp b/boost/geometry/index/detail/rtree/visitors/remove.hpp index d4890a368b..494d5a019e 100644 --- a/boost/geometry/index/detail/rtree/visitors/remove.hpp +++ b/boost/geometry/index/detail/rtree/visitors/remove.hpp @@ -2,7 +2,7 @@ // // R-tree removing visitor implementation // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -30,7 +30,7 @@ class remove 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; typedef typename Allocators::node_pointer node_pointer; typedef typename Allocators::size_type size_type; @@ -152,7 +152,7 @@ public: // 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"); + BOOST_GEOMETRY_INDEX_ASSERT(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(); @@ -222,6 +222,13 @@ private: return elements.size() < m_parameters.get_min_elements(); } + static inline bool is_leaf(node const& n) + { + visitors::is_leaf<Value, Options, Box, Allocators> ilv; + rtree::apply_visitor(ilv, n); + return ilv.result; + } + void reinsert_removed_nodes_elements() { typename UnderflowNodes::reverse_iterator it = m_underflowed_nodes.rbegin(); @@ -232,9 +239,11 @@ private: // 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 ) + // it->first is an index of a level of a node, not children + // counted from the leafs level + bool const node_is_leaf = it->first == 1; + BOOST_GEOMETRY_INDEX_ASSERT(node_is_leaf == is_leaf(*it->second), "unexpected condition"); + if ( node_is_leaf ) { reinsert_node_elements(rtree::get<leaf>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc) @@ -255,7 +264,7 @@ private: // destroy current and remaining nodes for ( ; it != m_underflowed_nodes.rend() ; ++it ) { - node_auto_ptr dummy(it->second, m_allocators); + subtree_destroyer dummy(it->second, m_allocators); } //m_underflowed_nodes.clear(); diff --git a/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp index 0a43111ac4..f00189fe77 100644 --- a/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -2,7 +2,7 @@ // // R-tree spatial query visitor implementation // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// 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 @@ -116,7 +116,7 @@ public: const_reference dereference() const { - BOOST_ASSERT_MSG(m_values, "not dereferencable"); + BOOST_GEOMETRY_INDEX_ASSERT(m_values, "not dereferencable"); return *m_current; } diff --git a/boost/geometry/index/detail/serialization.hpp b/boost/geometry/index/detail/serialization.hpp index 34036e3904..550a37565b 100644 --- a/boost/geometry/index/detail/serialization.hpp +++ b/boost/geometry/index/detail/serialization.hpp @@ -1,6 +1,6 @@ // Boost.Geometry Index // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -353,7 +353,7 @@ class load 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer; typedef typename Allocators::size_type size_type; public: @@ -385,7 +385,7 @@ private: 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); + subtree_destroyer auto_remover(n, allocators); internal_node & in = rtree::get<internal_node>(*n); elements_type & elements = rtree::elements(in); @@ -408,7 +408,7 @@ private: 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); + subtree_destroyer auto_remover(n, allocators); leaf & l = rtree::get<leaf>(*n); typedef typename rtree::elements_type<leaf>::type elements_type; @@ -537,7 +537,7 @@ void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsig 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; + typedef detail::rtree::subtree_destroyer<value_type, options_type, translator_type, box_type, allocators_type> subtree_destroyer; view tree(rt); @@ -554,7 +554,7 @@ void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsig 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()); + subtree_destroyer 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(); @@ -564,7 +564,7 @@ void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsig tree.members().values_count = values_count; tree.members().leafs_level = leafs_level; - node_auto_ptr remover(tree.members().root, tree.members().allocators()); + subtree_destroyer remover(tree.members().root, tree.members().allocators()); tree.members().root = n; } diff --git a/boost/geometry/index/detail/varray.hpp b/boost/geometry/index/detail/varray.hpp index 63577e64a7..1b084aafdb 100644 --- a/boost/geometry/index/detail/varray.hpp +++ b/boost/geometry/index/detail/varray.hpp @@ -1,6 +1,6 @@ // Boost.Container varray // -// Copyright (c) 2012-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2015 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2011-2013 Andrew Hundt. // // Use, modification and distribution is subject to the Boost Software License, @@ -13,7 +13,10 @@ // TODO - REMOVE/CHANGE #include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/workaround.hpp> -#include <boost/container/detail/preprocessor.hpp> + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include <boost/move/detail/fwd_macros.hpp> +#endif #include <boost/config.hpp> #include <boost/swap.hpp> @@ -32,12 +35,11 @@ #include <boost/iterator/iterator_concepts.hpp> #include <boost/geometry/index/detail/assert.hpp> +#include <boost/geometry/index/detail/exception.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 @@ -79,12 +81,8 @@ struct checker 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 + throw_out_of_range("index out of bounds"); ::boost::ignore_unused_variable_warning(v); ::boost::ignore_unused_variable_warning(i); @@ -920,9 +918,9 @@ public: difference_type n = std::distance(first, last); //TODO - add invalid range check? - //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + //BOOST_GEOMETRY_INDEX_ASSERT(0 <= n, "invalid range"); //TODO - add this->size() check? - //BOOST_ASSERT_MSG(n <= this->size(), "invalid range"); + //BOOST_GEOMETRY_INDEX_ASSERT(n <= this->size(), "invalid range"); sv::move(last, this->end(), first); // may throw sv::destroy(this->end() - n, this->end()); @@ -984,7 +982,7 @@ public: } #if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) -#if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @pre <tt>size() < capacity()</tt> //! //! @brief Inserts a Value constructed with @@ -1065,27 +1063,23 @@ public: return position; } -#else // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED +#else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(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, _)) \ + #define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_EMPLACE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void emplace_back(BOOST_MOVE_UREF##N) \ { \ 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*/\ + namespace sv = varray_detail; \ + sv::construct(dti(), this->end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*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, _)) \ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace(iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ { \ typedef typename vt::disable_trivial_init dti; \ namespace sv = varray_detail; \ @@ -1095,7 +1089,7 @@ public: \ if ( position == this->end() ) \ { \ - sv::construct(dti(), position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + sv::construct(dti(), position BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ ++m_size; /*update end*/ \ } \ else \ @@ -1104,24 +1098,24 @@ public: /* 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*/\ + 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::construct(dti(), val_p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*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() + + BOOST_MOVE_ITERATE_0TO9(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_EMPLACE) + #undef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_EMPLACE -#endif // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE //! @brief Removes all elements from the container. @@ -1614,7 +1608,8 @@ private: // 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)); + //BOOST_GEOMETRY_INDEX_ASSERT(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la), + // "incompatible ranges"); namespace sv = varray_detail; for (; first_sm != last_sm ; ++first_sm, ++first_la) @@ -1639,7 +1634,8 @@ private: // 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)); + //BOOST_GEOMETRY_INDEX_ASSERT(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la), + // "incompatible ranges"); namespace sv = varray_detail; for (; first_sm != last_sm ; ++first_sm, ++first_la) @@ -1961,7 +1957,7 @@ public: errh::check_iterator_end_eq(*this, first); errh::check_iterator_end_eq(*this, last); - //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + //BOOST_GEOMETRY_INDEX_ASSERT(0 <= n, "invalid range"); } // basic diff --git a/boost/geometry/index/detail/varray_detail.hpp b/boost/geometry/index/detail/varray_detail.hpp index 962d4d8288..31b77c40fe 100644 --- a/boost/geometry/index/detail/varray_detail.hpp +++ b/boost/geometry/index/detail/varray_detail.hpp @@ -2,7 +2,7 @@ // // varray details // -// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2015 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2011-2013 Andrew Hundt. // // Use, modification and distribution is subject to the Boost Software License, @@ -39,9 +39,13 @@ #include <boost/detail/no_exceptions_support.hpp> #include <boost/config.hpp> #include <boost/move/move.hpp> -#include <boost/utility/addressof.hpp> +#include <boost/core/addressof.hpp> #include <boost/iterator/iterator_traits.hpp> +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include <boost/move/detail/fwd_macros.hpp> +#endif + // 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) @@ -618,22 +622,22 @@ void construct(DisableTrivialInit const&, // !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) > \ +#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT(N) \ +template <typename DisableTrivialInit, typename I, typename P BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \ inline \ void construct(DisableTrivialInit const&, \ I pos, \ - BOOST_CONTAINER_PP_PARAM(P, p) \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + BOOST_FWD_REF(P) p \ + BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ { \ 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*/ \ + V(boost::forward<P>(p) BOOST_MOVE_I##N BOOST_MOVE_FWD##N); /*may throw*/ \ } \ -// -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) -#include BOOST_PP_LOCAL_ITERATE() + +BOOST_MOVE_ITERATE_1TO9(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT) +#undef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT #endif // !BOOST_NO_CXX11_VARIADIC_TEMPLATES #endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE diff --git a/boost/geometry/index/equal_to.hpp b/boost/geometry/index/equal_to.hpp index 5fbaa8209f..b0cf098f1d 100644 --- a/boost/geometry/index/equal_to.hpp +++ b/boost/geometry/index/equal_to.hpp @@ -24,6 +24,15 @@ struct equals } }; +template <typename Geometry, typename Tag> +struct equals<Geometry *, Tag> +{ + inline static bool apply(const Geometry * g1, const Geometry * g2) + { + return g1 == g2; + } +}; + template <typename T> struct equals<T, void> { diff --git a/boost/geometry/index/parameters.hpp b/boost/geometry/index/parameters.hpp index fd6df716ee..2b94907686 100644 --- a/boost/geometry/index/parameters.hpp +++ b/boost/geometry/index/parameters.hpp @@ -70,8 +70,7 @@ inline size_t default_rstar_reinserted_elements_d_calc(size_t max_elements, size \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 -> + size_t MinElements = detail::default_min_elements_s<MaxElements>::value> struct linear { BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1), diff --git a/boost/geometry/index/predicates.hpp b/boost/geometry/index/predicates.hpp index 10033abff8..3bb1bf4d87 100644 --- a/boost/geometry/index/predicates.hpp +++ b/boost/geometry/index/predicates.hpp @@ -2,7 +2,7 @@ // // Spatial query predicates // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -43,10 +43,15 @@ bgi::query(spatial_index, bgi::contains(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::contains_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::contains_tag, false> contains(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::contains_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::contains_tag, + false + >(g); } /*! @@ -68,10 +73,15 @@ bgi::query(spatial_index, bgi::covered_by(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::covered_by_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::covered_by_tag, false> covered_by(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::covered_by_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::covered_by_tag, + false + >(g); } /*! @@ -93,10 +103,15 @@ bgi::query(spatial_index, bgi::covers(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::covers_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::covers_tag, false> covers(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::covers_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::covers_tag, + false + >(g); } /*! @@ -118,10 +133,15 @@ bgi::query(spatial_index, bgi::disjoint(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::disjoint_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::disjoint_tag, false> disjoint(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::disjoint_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::disjoint_tag, + false + >(g); } /*! @@ -145,10 +165,15 @@ bgi::query(spatial_index, bgi::intersects(polygon), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::intersects_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::intersects_tag, false> intersects(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::intersects_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::intersects_tag, + false + >(g); } /*! @@ -170,10 +195,15 @@ bgi::query(spatial_index, bgi::overlaps(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::overlaps_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::overlaps_tag, false> overlaps(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::overlaps_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::overlaps_tag, + false + >(g); } #ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL @@ -192,10 +222,15 @@ returns true. \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::touches_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::touches_tag, false> touches(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::touches_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::touches_tag, + false + >(g); } #endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL @@ -219,10 +254,15 @@ bgi::query(spatial_index, bgi::within(box), std::back_inserter(result)); \param g The Geometry object. */ template <typename Geometry> inline -detail::spatial_predicate<Geometry, detail::within_tag, false> +detail::predicates::spatial_predicate<Geometry, detail::predicates::within_tag, false> within(Geometry const& g) { - return detail::spatial_predicate<Geometry, detail::within_tag, false>(g); + return detail::predicates::spatial_predicate + < + Geometry, + detail::predicates::within_tag, + false + >(g); } /*! @@ -259,10 +299,10 @@ std::back_inserter(result)); \param pred The unary predicate function or function object. */ template <typename UnaryPredicate> inline -detail::satisfies<UnaryPredicate, false> +detail::predicates::satisfies<UnaryPredicate, false> satisfies(UnaryPredicate const& pred) { - return detail::satisfies<UnaryPredicate, false>(pred); + return detail::predicates::satisfies<UnaryPredicate, false>(pred); } /*! @@ -289,10 +329,10 @@ Only one \c nearest() predicate may be used in a query. \param k The maximum number of values to return. */ template <typename Geometry> inline -detail::nearest<Geometry> +detail::predicates::nearest<Geometry> nearest(Geometry const& geometry, unsigned k) { - return detail::nearest<Geometry>(geometry, k); + return detail::predicates::nearest<Geometry>(geometry, k); } #ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL @@ -319,15 +359,15 @@ Only one distance predicate (\c nearest() or \c path()) may be used in a query. \param k The maximum number of values to return. */ template <typename SegmentOrLinestring> inline -detail::path<SegmentOrLinestring> +detail::predicates::path<SegmentOrLinestring> path(SegmentOrLinestring const& linestring, unsigned k) { - return detail::path<SegmentOrLinestring>(linestring, k); + return detail::predicates::path<SegmentOrLinestring>(linestring, k); } #endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL -namespace detail { +namespace detail { namespace predicates { // operator! generators @@ -378,7 +418,7 @@ operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p) >::apply(t, p); } -} // namespace detail +}} // namespace detail::predicates }}} // namespace boost::geometry::index diff --git a/boost/geometry/index/rtree.hpp b/boost/geometry/index/rtree.hpp index 503f47b89f..9d5d57d059 100644 --- a/boost/geometry/index/rtree.hpp +++ b/boost/geometry/index/rtree.hpp @@ -3,7 +3,7 @@ // R-tree implementation // // Copyright (c) 2008 Federico J. Fernandez. -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2015 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 @@ -96,12 +96,13 @@ 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. +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. +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: @@ -116,23 +117,31 @@ Predefined algorithms with run-time parameters are: \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>. +The object of IndexableGetter type translates from Value to Indexable each time +r-tree requires it. This means that this operation is done for each Value +access. Therefore the IndexableGetter should return the Indexable by +a reference type. The Indexable should not be calculated since it could harm +the performance. The default IndexableGetter can translate all types adapted +to Point, Box or Segment concepts (called Indexables). Furthermore, it can +handle <tt>std::pair<Indexable, T></tt>, <tt>boost::tuple<Indexable, ...></tt> +and <tt>std::tuple<Indexable, ...></tt> when possible. For example, for Value +of type <tt>std::pair<Box, int></tt>, 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. +The object of EqualTo type compares Values and returns <tt>true</tt> if they +are 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 +<tt>operator==</tt> 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. +\tparam Allocator The allocator used to allocate/deallocate memory, + construct/destroy nodes and Values. */ template < typename Value, @@ -188,7 +197,7 @@ private: 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; + typedef detail::rtree::subtree_destroyer<value_type, options_type, translator_type, box_type, allocators_type> subtree_destroyer; friend class detail::rtree::utilities::view<rtree>; #ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL @@ -1088,6 +1097,8 @@ public: template <typename ValueOrIndexable> size_type count(ValueOrIndexable const& vori) const { + // the input should be convertible to Value or Indexable type + enum { as_val = 0, as_ind, dont_know }; typedef boost::mpl::int_ < @@ -1113,15 +1124,9 @@ public: 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; + // NOTE: If an object of convertible but not the same type is passed + // into the function, here a temporary will be created. + return this->template raw_count<value_or_indexable>(vori); } /*! @@ -1239,6 +1244,7 @@ private: inline void raw_insert(value_type const& value) { BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + // CONSIDER: alternative - ignore invalid indexable or throw an exception BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(m_members.translator()(value)), "Indexable is invalid"); detail::rtree::visitors::insert< @@ -1356,7 +1362,7 @@ private: dst.m_members.parameters() = src.m_members.parameters(); } - // TODO use node_auto_ptr + // TODO use subtree_destroyer if ( dst.m_members.root ) { detail::rtree::visitors::destroy<value_type, options_type, translator_type, box_type, allocators_type> @@ -1492,6 +1498,33 @@ private: return distance_v.finish(); } + + /*! + \brief Count elements corresponding to value or indexable. + + \par Exception-safety + strong + */ + template <typename ValueOrIndexable> + size_type raw_count(ValueOrIndexable const& vori) const + { + if ( !m_members.root ) + return 0; + + detail::rtree::visitors::count + < + ValueOrIndexable, + value_type, + options_type, + translator_type, + box_type, + allocators_type + > count_v(vori, m_members.translator()); + + detail::rtree::apply_visitor(count_v, *m_members.root); + + return count_v.found_count; + } struct members_holder : public translator_type diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp index 748eecdbe6..2415f21a69 100644 --- a/boost/geometry/io/wkt/read.hpp +++ b/boost/geometry/io/wkt/read.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. @@ -29,6 +34,7 @@ #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> @@ -38,6 +44,7 @@ #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/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -98,7 +105,9 @@ namespace detail { namespace wkt typedef boost::tokenizer<boost::char_separator<char> > tokenizer; -template <typename Point, std::size_t Dimension, std::size_t DimensionCount> +template <typename Point, + std::size_t Dimension = 0, + std::size_t DimensionCount = geometry::dimension<Point>::value> struct parsing_assigner { static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, @@ -208,12 +217,7 @@ struct container_inserter while (it != end && *it != ")") { - parsing_assigner - < - Point, - 0, - dimension<Point>::value - >::apply(it, end, point, wkt); + parsing_assigner<Point>::apply(it, end, point, wkt); out = point; ++out; if (it != end && *it == ",") @@ -227,35 +231,94 @@ struct container_inserter }; +template <typename Geometry, + closure_selector Closure = closure<Geometry>::value> +struct stateful_range_appender +{ + typedef typename geometry::point_type<Geometry>::type point_type; + + // NOTE: Geometry is a reference + inline void append(Geometry geom, point_type const& point, bool) + { + geometry::append(geom, point); + } +}; + +template <typename Geometry> +struct stateful_range_appender<Geometry, open> +{ + typedef typename geometry::point_type<Geometry>::type point_type; + typedef typename boost::range_size + < + typename util::bare_type<Geometry>::type + >::type size_type; + + BOOST_STATIC_ASSERT(( boost::is_same + < + typename tag<Geometry>::type, + ring_tag + >::value )); + + inline stateful_range_appender() + : pt_index(0) + {} + + // NOTE: Geometry is a reference + inline void append(Geometry geom, point_type const& point, bool is_next_expected) + { + bool should_append = true; + + if (pt_index == 0) + { + first_point = point; + //should_append = true; + } + else + { + // NOTE: if there is not enough Points, they're always appended + should_append + = is_next_expected + || pt_index < core_detail::closure::minimum_ring_size<open>::value + || !detail::equals::equals_point_point(point, first_point); + } + ++pt_index; + + if (should_append) + { + geometry::append(geom, point); + } + } + +private: + size_type pt_index; + point_type first_point; +}; + // Geometry is a value-type or reference-type template <typename Geometry> struct container_appender { - typedef typename geometry::point_type - < - typename boost::remove_reference<Geometry>::type - >::type point_type; + typedef typename geometry::point_type<Geometry>::type point_type; static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, - std::string const& wkt, Geometry out) + std::string const& wkt, Geometry out) { handle_open_parenthesis(it, end, wkt); - point_type point; + stateful_range_appender<Geometry> appender; // Parse points until closing parenthesis - while (it != end && *it != ")") { - parsing_assigner - < - point_type, - 0, - dimension<point_type>::value - >::apply(it, end, point, wkt); - - geometry::append(out, point); - if (it != end && *it == ",") + point_type point; + + parsing_assigner<point_type>::apply(it, end, point, wkt); + + bool const is_next_expected = it != end && *it == ","; + + appender.append(out, point, is_next_expected); + + if (is_next_expected) { ++it; } @@ -276,7 +339,7 @@ struct point_parser std::string const& wkt, P& point) { handle_open_parenthesis(it, end, wkt); - parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt); + parsing_assigner<P>::apply(it, end, point, wkt); handle_close_parenthesis(it, end, wkt); } }; @@ -512,7 +575,7 @@ 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); + parsing_assigner<P>::apply(it, end, point, wkt); } }; @@ -617,7 +680,7 @@ struct box_parser } check_end(it, end, wkt); - int index = 0; + unsigned int index = 0; std::size_t n = boost::size(points); if (n == 2) { diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp index 6c1a2e153e..add40e2551 100644 --- a/boost/geometry/io/wkt/write.hpp +++ b/boost/geometry/io/wkt/write.hpp @@ -20,6 +20,7 @@ #include <boost/array.hpp> #include <boost/range.hpp> + #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> diff --git a/boost/geometry/iterators/closing_iterator.hpp b/boost/geometry/iterators/closing_iterator.hpp index a9f67d4788..e263f3aafb 100644 --- a/boost/geometry/iterators/closing_iterator.hpp +++ b/boost/geometry/iterators/closing_iterator.hpp @@ -42,12 +42,14 @@ struct closing_iterator boost::random_access_traversal_tag > { + typedef typename boost::range_difference<Range>::type difference_type; + /// Constructor including the range it is based on explicit inline closing_iterator(Range& range) : m_range(&range) , m_iterator(boost::begin(range)) , m_end(boost::end(range)) - , m_size(boost::size(range)) + , m_size(static_cast<difference_type>(boost::size(range))) , m_index(0) {} @@ -56,8 +58,8 @@ struct closing_iterator : m_range(&range) , m_iterator(boost::end(range)) , m_end(boost::end(range)) - , m_size(boost::size(range)) - , m_index(m_size + 1) + , m_size(static_cast<difference_type>(boost::size(range))) + , m_index((m_size == 0) ? 0 : m_size + 1) {} /// Default constructor @@ -67,18 +69,6 @@ struct closing_iterator , m_index(0) {} - inline closing_iterator<Range>& operator=(closing_iterator<Range> const& source) - { - m_range = source.m_range; - m_iterator = source.m_iterator; - m_end = source.m_end; - m_size = source.m_size; - m_index = source.m_index; - return *this; - } - - typedef std::ptrdiff_t difference_type; - private: friend class boost::iterator_core_access; diff --git a/boost/geometry/iterators/concatenate_iterator.hpp b/boost/geometry/iterators/concatenate_iterator.hpp index 20112b4c4c..5c4ae0af1e 100644 --- a/boost/geometry/iterators/concatenate_iterator.hpp +++ b/boost/geometry/iterators/concatenate_iterator.hpp @@ -89,36 +89,6 @@ public: (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; diff --git a/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp index d79fda84d9..e65b12b459 100644 --- a/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp +++ b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp @@ -100,23 +100,36 @@ class range_segment_iterator Reference > { + static inline bool has_less_than_two_elements(Range const& r) + { + return boost::size(r) < ((closure<Range>::value == open) ? 1u : 2u); + } + public: typedef typename range_iterator_type<Range>::type iterator_type; // default constructor range_segment_iterator() - : m_it() + : m_it(), m_has_less_than_two_elements(false) {} // for begin range_segment_iterator(Range& r) : m_it(range_iterator_begin<Range>::apply(r)) + , m_has_less_than_two_elements(has_less_than_two_elements(r)) {} // for end range_segment_iterator(Range& r, bool) - : m_it(--range_iterator_end<Range>::apply(r)) - {} + : m_it(range_iterator_end<Range>::apply(r)) + , m_has_less_than_two_elements(has_less_than_two_elements(r)) + { + if (! m_has_less_than_two_elements) + { + // the range consists of at least two items + --m_it; + } + } template < @@ -143,33 +156,6 @@ public: 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; @@ -178,6 +164,11 @@ private: inline Reference dereference() const { + if (m_has_less_than_two_elements) + { + return Reference(*m_it, *m_it); + } + iterator_type next(m_it); ++next; return Reference(*m_it, *next); @@ -211,6 +202,7 @@ private: private: iterator_type m_it; + bool m_has_less_than_two_elements; }; diff --git a/boost/geometry/iterators/ever_circling_iterator.hpp b/boost/geometry/iterators/ever_circling_iterator.hpp index 50b20480cd..cfb588b79f 100644 --- a/boost/geometry/iterators/ever_circling_iterator.hpp +++ b/boost/geometry/iterators/ever_circling_iterator.hpp @@ -119,15 +119,6 @@ struct ever_circling_range_iterator , m_index(0) {} - inline ever_circling_range_iterator<Range>& operator=(ever_circling_range_iterator<Range> const& source) - { - m_range = source.m_range; - m_iterator = source.m_iterator; - m_size = source.m_size; - m_index = source.m_index; - return *this; - } - typedef std::ptrdiff_t difference_type; private: diff --git a/boost/geometry/iterators/flatten_iterator.hpp b/boost/geometry/iterators/flatten_iterator.hpp index 078079dc2c..07450afbea 100644 --- a/boost/geometry/iterators/flatten_iterator.hpp +++ b/boost/geometry/iterators/flatten_iterator.hpp @@ -107,42 +107,15 @@ public: (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) + flatten_iterator& operator=(flatten_iterator 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; + // avoid assigning an iterator having singular value + if ( other.m_outer_it != other.m_outer_end ) + { + m_inner_it = other.m_inner_it; + } return *this; } @@ -162,8 +135,8 @@ private: static inline bool empty(OuterIterator outer_it) { - return - AccessInnerBegin::apply(*outer_it) == AccessInnerEnd::apply(*outer_it); + return AccessInnerBegin::apply(*outer_it) + == AccessInnerEnd::apply(*outer_it); } inline void advance_through_empty() diff --git a/boost/geometry/iterators/point_iterator.hpp b/boost/geometry/iterators/point_iterator.hpp index 075339aa58..5971cfcef0 100644 --- a/boost/geometry/iterators/point_iterator.hpp +++ b/boost/geometry/iterators/point_iterator.hpp @@ -11,6 +11,7 @@ #define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP #include <boost/assert.hpp> +#include <boost/iterator/iterator_adaptor.hpp> #include <boost/mpl/assert.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/range.hpp> @@ -245,33 +246,26 @@ struct points_end<MultiPolygon, multi_polygon_tag> // MK:: need to add doc here template <typename Geometry> class point_iterator - : public detail::point_iterator::iterator_type<Geometry>::type + : public boost::iterator_adaptor + < + point_iterator<Geometry>, + typename 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) {} + inline point_iterator(typename point_iterator::base_type const& base_it) + : point_iterator::iterator_adaptor_(base_it) {} public: inline point_iterator() {} template <typename OtherGeometry> inline point_iterator(point_iterator<OtherGeometry> const& other) - : base(*other.base_ptr()) + : point_iterator::iterator_adaptor_(other.base()) { static const bool is_conv = boost::is_convertible< diff --git a/boost/geometry/iterators/point_reverse_iterator.hpp b/boost/geometry/iterators/point_reverse_iterator.hpp index 1c2ac0169d..b464c5f22a 100644 --- a/boost/geometry/iterators/point_reverse_iterator.hpp +++ b/boost/geometry/iterators/point_reverse_iterator.hpp @@ -27,17 +27,7 @@ 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; - } + typedef std::reverse_iterator<point_iterator<Geometry> > base_type; template <typename OtherGeometry> friend class point_reverse_iterator; template <typename G> @@ -46,7 +36,8 @@ private: template <typename G> friend inline point_reverse_iterator<G> points_rend(G&); - inline point_reverse_iterator(base const& base_it) : base(base_it) {} + inline point_reverse_iterator(base_type const& base_it) + : base_type(base_it) {} public: inline point_reverse_iterator() {} @@ -54,7 +45,7 @@ public: template <typename OtherGeometry> inline point_reverse_iterator(point_reverse_iterator<OtherGeometry> const& other) - : base(*other.base_ptr()) + : base_type(other.base()) { static const bool is_conv = boost::is_convertible < diff --git a/boost/geometry/iterators/segment_iterator.hpp b/boost/geometry/iterators/segment_iterator.hpp index 206d7fc503..71aff39c43 100644 --- a/boost/geometry/iterators/segment_iterator.hpp +++ b/boost/geometry/iterators/segment_iterator.hpp @@ -272,6 +272,16 @@ private: inline segment_iterator(base const& base_it) : base(base_it) {} public: + // The following typedef is needed for this iterator to be + // bidirectional. + // Normally we would not have to define this. However, due to the + // fact that the value type of the iterator is not a reference, + // the iterator_facade framework (used to define the base class of + // this iterator) degrades automatically the iterator's category + // to input iterator. With the following typedef we recover the + // correct iterator category. + typedef std::bidirectional_iterator_tag iterator_category; + inline segment_iterator() {} template <typename OtherGeometry> @@ -291,6 +301,32 @@ public: NOT_CONVERTIBLE, (segment_iterator<OtherGeometry>)); } + + inline segment_iterator& operator++() // prefix + { + base::operator++(); + return *this; + } + + inline segment_iterator& operator--() // prefix + { + base::operator--(); + return *this; + } + + inline segment_iterator operator++(int) // postfix + { + segment_iterator copy(*this); + base::operator++(); + return copy; + } + + inline segment_iterator operator--(int) // postfix + { + segment_iterator copy(*this); + base::operator--(); + return copy; + } }; diff --git a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp deleted file mode 100644 index c780c4cd9a..0000000000 --- a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp +++ /dev/null @@ -1,16 +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_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP -#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP - - -#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> - - -#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP diff --git a/boost/geometry/policies/is_valid/default_policy.hpp b/boost/geometry/policies/is_valid/default_policy.hpp new file mode 100644 index 0000000000..c1bd347e11 --- /dev/null +++ b/boost/geometry/policies/is_valid/default_policy.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_POLICIES_IS_VALID_DEFAULT_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_IS_VALID_DEFAULT_POLICY_HPP + +#include <boost/geometry/algorithms/validity_failure_type.hpp> + + +namespace boost { namespace geometry +{ + + +template <bool AllowDuplicates = true, bool AllowSpikes = true> +class is_valid_default_policy +{ +protected: + static inline bool is_valid(validity_failure_type failure) + { + return failure == no_failure + || (AllowDuplicates && failure == failure_duplicate_points); + } + + static inline bool is_valid(validity_failure_type failure, bool is_linear) + { + return is_valid(failure) + || (is_linear && AllowSpikes && failure == failure_spikes); + } + +public: + template <validity_failure_type Failure> + static inline bool apply() + { + return is_valid(Failure); + } + + template <validity_failure_type Failure, typename Data> + static inline bool apply(Data const&) + { + return is_valid(Failure); + } + + template <validity_failure_type Failure, typename Data1, typename Data2> + static inline bool apply(Data1 const& data1, Data2 const&) + { + return is_valid(Failure, data1); + } +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_IS_VALID_DEFAULT_POLICY_HPP diff --git a/boost/geometry/policies/is_valid/failing_reason_policy.hpp b/boost/geometry/policies/is_valid/failing_reason_policy.hpp new file mode 100644 index 0000000000..b99803bead --- /dev/null +++ b/boost/geometry/policies/is_valid/failing_reason_policy.hpp @@ -0,0 +1,218 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP + +#include <sstream> + +#include <boost/geometry/io/dsv/write.hpp> +#include <boost/geometry/util/range.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> + + +namespace boost { namespace geometry +{ + + +inline char const* validity_failure_type_message(validity_failure_type failure) +{ + switch (failure) + { + case no_failure: + return "Geometry is valid"; + case failure_few_points: + return "Geometry has too few points"; + case failure_wrong_topological_dimension: + return "Geometry has wrong topological dimension"; + case failure_not_closed: + return "Geometry is defined as closed but is open"; + case failure_spikes: + return "Geometry has spikes"; + case failure_self_intersections: + return "Geometry has invalid self-intersections"; + case failure_wrong_orientation: + return "Geometry has wrong orientation"; + case failure_interior_rings_outside: + return "Geometry has interior rings defined outside the outer boundary"; + case failure_nested_interior_rings: + return "Geometry has nested interior rings"; + case failure_disconnected_interior: + return "Geometry has disconnected interior"; + case failure_intersecting_interiors: + return "Multi-polygon has intersecting interiors"; + case failure_duplicate_points: + return "Geometry has duplicate (consecutive) points"; + case failure_wrong_corner_order: + return "Box has corners in wrong order"; + default: // to avoid -Wreturn-type warning + return ""; + } +} + + +template <bool AllowDuplicates = true, bool AllowSpikes = true> +class failing_reason_policy +{ +private: + static inline + validity_failure_type transform_failure_type(validity_failure_type failure) + { + if (AllowDuplicates && failure == failure_duplicate_points) + { + return no_failure; + } + return failure; + } + + static inline + validity_failure_type transform_failure_type(validity_failure_type failure, + bool is_linear) + { + if (is_linear && AllowSpikes && failure == failure_spikes) + { + return no_failure; + } + return transform_failure_type(failure); + } + + inline void set_failure_message(validity_failure_type failure) + { + m_oss.str(""); + m_oss.clear(); + m_oss << validity_failure_type_message(failure); + } + + template + < + validity_failure_type Failure, + typename Data1, + typename Data2 = Data1, + typename Dummy = void + > + struct process_data + { + static inline void apply(std::ostringstream&, Data1 const&) + { + } + + static inline void apply(std::ostringstream&, + Data1 const&, + Data2 const&) + { + } + }; + + template <typename SpikePoint> + struct process_data<failure_spikes, bool, SpikePoint> + { + static inline void apply(std::ostringstream& oss, + bool is_linear, + SpikePoint const& spike_point) + { + if (is_linear && AllowSpikes) + { + return; + } + + oss << ". A spike point was found with apex at " + << geometry::dsv(spike_point); + } + }; + + template <typename Turns> + struct process_data<failure_self_intersections, Turns> + { + static inline + void apply_to_segment_identifier(std::ostringstream& oss, + segment_identifier seg_id) + { + oss << "{" << seg_id.source_index + << ", " << seg_id.multi_index + << ", " << seg_id.ring_index + << ", " << seg_id.segment_index + << "}"; + } + + static inline void apply(std::ostringstream& oss, + Turns const& turns) + { + typedef typename boost::range_value<Turns>::type turn_type; + turn_type const& turn = range::front(turns); + oss << ". A self-intersection point was found at " + << geometry::dsv(turn.point); + + oss << "; method: " << method_char(turn.method) + << "; operations: " + << operation_char(turn.operations[0].operation) + << "/" + << operation_char(turn.operations[1].operation) + << "; segment IDs {source, multi, ring, segment}: "; + apply_to_segment_identifier(oss, turn.operations[0].seg_id); + oss << "/"; + apply_to_segment_identifier(oss, turn.operations[1].seg_id); + } + }; + + template <typename Point> + struct process_data<failure_duplicate_points, Point> + { + static inline void apply(std::ostringstream& oss, + Point const& point) + { + if (AllowDuplicates) + { + return; + } + oss << ". Duplicate points were found near point " + << geometry::dsv(point); + } + }; + +public: + failing_reason_policy(std::ostringstream& oss) + : m_oss(oss) + {} + + template <validity_failure_type Failure> + inline bool apply() + { + validity_failure_type const failure = transform_failure_type(Failure); + set_failure_message(failure); + return failure == no_failure; + } + + template <validity_failure_type Failure, typename Data> + inline bool apply(Data const& data) + { + validity_failure_type const failure = transform_failure_type(Failure); + set_failure_message(failure); + process_data<Failure, Data>::apply(m_oss, data); + return failure == no_failure; + } + + template <validity_failure_type Failure, typename Data1, typename Data2> + inline bool apply(Data1 const& data1, Data2 const& data2) + { + validity_failure_type const failure + = transform_failure_type(Failure, data1); + set_failure_message(failure); + process_data<Failure, Data1, Data2>::apply(m_oss, data1, data2); + return failure == no_failure; + } + +private: + std::ostringstream& m_oss; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP diff --git a/boost/geometry/policies/is_valid/failure_type_policy.hpp b/boost/geometry/policies/is_valid/failure_type_policy.hpp new file mode 100644 index 0000000000..9fb569e283 --- /dev/null +++ b/boost/geometry/policies/is_valid/failure_type_policy.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_POLICIES_IS_VALID_FAILURE_TYPE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_IS_VALID_FAILURE_TYPE_POLICY_HPP + +#include <boost/geometry/algorithms/validity_failure_type.hpp> + + +namespace boost { namespace geometry +{ + + +// policy that simply keeps (and can return) the failure type +template <bool AllowDuplicates = true, bool AllowSpikes = true> +class failure_type_policy +{ +private: + static inline + validity_failure_type transform_failure_type(validity_failure_type failure) + { + if (AllowDuplicates && failure == failure_duplicate_points) + { + return no_failure; + } + return failure; + } + + static inline + validity_failure_type transform_failure_type(validity_failure_type failure, + bool is_linear) + { + if (is_linear && AllowSpikes && failure == failure_spikes) + { + return no_failure; + } + return transform_failure_type(failure); + } + +public: + failure_type_policy() + : m_failure(no_failure) + {} + + template <validity_failure_type Failure> + inline bool apply() + { + m_failure = transform_failure_type(Failure); + return m_failure == no_failure; + } + + template <validity_failure_type Failure, typename Data> + inline bool apply(Data const&) + { + return apply<Failure>(); + } + + template <validity_failure_type Failure, typename Data1, typename Data2> + inline bool apply(Data1 const& data1, Data2 const&) + { + m_failure = transform_failure_type(Failure, data1); + return m_failure == no_failure; + } + + validity_failure_type failure() const + { + return m_failure; + } + +private: + validity_failure_type m_failure; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_IS_VALID_FAILURE_TYPE_POLICY_HPP diff --git a/boost/geometry/policies/relate/direction.hpp b/boost/geometry/policies/relate/direction.hpp index 02fed94b10..2c903bd79f 100644 --- a/boost/geometry/policies/relate/direction.hpp +++ b/boost/geometry/policies/relate/direction.hpp @@ -206,22 +206,51 @@ struct segments_direction } } + static inline int arrival_from_position_value(int /*v_from*/, int v_to) + { + return v_to == 2 ? 1 + : v_to == 1 || v_to == 3 ? 0 + //: v_from >= 1 && v_from <= 3 ? -1 + : -1; + + // NOTE: this should be an equivalent of the above for the other order + /* (v_from < 3 && v_to > 3) || (v_from > 3 && v_to < 3) ? 1 + : v_from == 3 || v_to == 3 ? 0 + : -1;*/ + } + + static inline void analyse_position_value(int pos_val, + int & in_segment_count, + int & on_end_count, + int & outside_segment_count) + { + if ( pos_val == 1 || pos_val == 3 ) + { + on_end_count++; + } + else if ( pos_val == 2 ) + { + in_segment_count++; + } + else + { + outside_segment_count++; + } + } + 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) + Segment1 const& , Segment2 const& , bool opposite, + int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a, + Ratio const& /*ra_from_wrt_b*/, Ratio const& /*ra_to_wrt_b*/, + Ratio const& /*rb_from_wrt_a*/, Ratio const& /*rb_to_wrt_a*/) { - // 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; - return_type r('c', opposite); // 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); + r.arrival[0] = arrival_from_position_value(a1_wrt_b, a2_wrt_b); + r.arrival[1] = arrival_from_position_value(b1_wrt_a, b2_wrt_a); // Analyse them int a_in_segment_count = 0; @@ -230,13 +259,13 @@ struct segments_direction int b_in_segment_count = 0; int b_on_end_count = 0; int b_outside_segment_count = 0; - analyze(ra_from_wrt_b, + analyse_position_value(a1_wrt_b, a_in_segment_count, a_on_end_count, a_outside_segment_count); - analyze(ra_to_wrt_b, + analyse_position_value(a2_wrt_b, a_in_segment_count, a_on_end_count, a_outside_segment_count); - analyze(rb_from_wrt_a, + analyse_position_value(b1_wrt_a, b_in_segment_count, b_on_end_count, b_outside_segment_count); - analyze(rb_to_wrt_a, + analyse_position_value(b2_wrt_a, b_in_segment_count, b_on_end_count, b_outside_segment_count); if (a_on_end_count == 1 diff --git a/boost/geometry/policies/relate/intersection_points.hpp b/boost/geometry/policies/relate/intersection_points.hpp index aa2f697a2a..082dc4ca7f 100644 --- a/boost/geometry/policies/relate/intersection_points.hpp +++ b/boost/geometry/policies/relate/intersection_points.hpp @@ -19,6 +19,7 @@ #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/promote_integral.hpp> #include <boost/geometry/util/select_calculation_type.hpp> #include <boost/geometry/util/select_most_precise.hpp> #include <boost/geometry/util/math.hpp> @@ -60,12 +61,24 @@ struct segments_intersection_points // 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())); + + typedef typename promote_integral<coordinate_type>::type promoted_type; + + promoted_type const numerator + = boost::numeric_cast<promoted_type>(ratio.numerator()); + promoted_type const denominator + = boost::numeric_cast<promoted_type>(ratio.denominator()); + promoted_type const dx_promoted = boost::numeric_cast<promoted_type>(dx); + promoted_type const dy_promoted = boost::numeric_cast<promoted_type>(dy); + + set<0>(point, get<0, 0>(segment) + boost::numeric_cast + < + coordinate_type + >(numerator * dx_promoted / denominator)); + set<1>(point, get<0, 1>(segment) + boost::numeric_cast + < + coordinate_type + >(numerator * dy_promoted / denominator)); } @@ -100,19 +113,20 @@ struct segments_intersection_points template <typename Segment1, typename Segment2, typename Ratio> static inline return_type segments_collinear( - Segment1 const& a, Segment2 const& b, + Segment1 const& a, Segment2 const& b, bool /*opposite*/, + int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a, 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; - int index = 0, count_a = 0, count_b = 0; + unsigned 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() + if (a1_wrt_b >= 1 && a1_wrt_b <= 3 // ra_from_wrt_b.on_segment() && index < 2) { // a1--------->a2 @@ -126,7 +140,7 @@ struct segments_intersection_points index++; count_a++; } - if (rb_from_wrt_a.in_segment() + if (b1_wrt_a == 2 //rb_from_wrt_a.in_segment() && index < 2) { // We take the first intersection point of B @@ -143,7 +157,7 @@ struct segments_intersection_points count_b++; } - if (ra_to_wrt_b.on_segment() + if (a2_wrt_b >= 1 && a2_wrt_b <= 3 //ra_to_wrt_b.on_segment() && index < 2) { // Similarly, second IP (here a2) @@ -155,7 +169,7 @@ struct segments_intersection_points index++; count_a++; } - if (rb_to_wrt_a.in_segment() + if (b2_wrt_a == 2 // rb_to_wrt_a.in_segment() && index < 2) { detail::assign_point_from_index<1>(b, result.intersections[index]); diff --git a/boost/geometry/policies/relate/tupled.hpp b/boost/geometry/policies/relate/tupled.hpp index 6da9095c4e..4b65432f20 100644 --- a/boost/geometry/policies/relate/tupled.hpp +++ b/boost/geometry/policies/relate/tupled.hpp @@ -47,13 +47,22 @@ struct segments_tupled 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) + Segment1 const& segment1, Segment2 const& segment2, + bool opposite, + int pa1, int pa2, int pb1, int pb2, + Ratio const& ra1, Ratio const& ra2, + Ratio const& rb1, Ratio const& rb2) { return boost::make_tuple ( - Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2), - Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2) + Policy1::segments_collinear(segment1, segment2, + opposite, + pa1, pa2, pb1, pb2, + ra1, ra2, rb1, rb2), + Policy2::segments_collinear(segment1, segment2, + opposite, + pa1, pa2, pb1, pb2, + ra1, ra2, rb1, rb2) ); } diff --git a/boost/geometry/policies/robustness/get_rescale_policy.hpp b/boost/geometry/policies/robustness/get_rescale_policy.hpp index ed7c1eb94c..52570995f6 100644 --- a/boost/geometry/policies/robustness/get_rescale_policy.hpp +++ b/boost/geometry/policies/robustness/get_rescale_policy.hpp @@ -1,9 +1,14 @@ // 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. +// Copyright (c) 2014-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2014-2015 Mateusz Loskot, London, UK. +// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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 @@ -41,35 +46,52 @@ namespace boost { namespace geometry 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) +template +< + typename Box, + typename Point, + typename RobustPoint, + typename Factor +> +inline void scale_box_to_integer_range(Box const& box, + 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 + // Scale box 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 diff = boost::numeric_cast<num_type>(detail::get_max_size(box)); 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 + factor = math::equals(diff, num_type()) || diff >= range ? 1 : boost::numeric_cast<num_type>( boost::numeric_cast<boost::long_long_type>(half + range / diff)); + BOOST_ASSERT(factor >= 1); + // Assign input/output minimal points - detail::assign_point_from_index<0>(env, min_point); + detail::assign_point_from_index<0>(box, 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 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_box_to_integer_range(env, min_point, min_robust_point, factor); +} + template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor> static inline void init_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2, @@ -82,25 +104,7 @@ static inline void init_rescale_policy(Geometry1 const& 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); + scale_box_to_integer_range(env, min_point, min_robust_point, factor); } diff --git a/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp index 7b7cd1890f..446d2f02cd 100644 --- a/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp +++ b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp @@ -9,6 +9,8 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP #define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP +#include <boost/core/ignore_unused.hpp> + #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/util/math.hpp> @@ -79,6 +81,8 @@ public : inline NumericType max_distance(JoinStrategy const& join_strategy, EndStrategy const& end_strategy) const { + boost::ignore_unused(join_strategy, end_strategy); + NumericType const left = geometry::math::abs(m_left); NumericType const right = geometry::math::abs(m_right); NumericType const dist = (std::max)(left, right); diff --git a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp index bc0c46f644..73bd21ac73 100644 --- a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp +++ b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp @@ -9,6 +9,9 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP #define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP + +#include <boost/core/ignore_unused.hpp> + #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/util/math.hpp> @@ -76,6 +79,8 @@ public : inline NumericType max_distance(JoinStrategy const& join_strategy, EndStrategy const& end_strategy) const { + boost::ignore_unused(join_strategy, end_strategy); + NumericType const dist = geometry::math::abs(m_distance); return (std::max)(join_strategy.max_distance(dist), end_strategy.max_distance(dist)); diff --git a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp index a960a6f1f9..1d59e13cf6 100644 --- a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp +++ b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp @@ -364,7 +364,7 @@ private: // 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 (count < 4) { // there should be only one missing *out++ = *boost::begin(first); diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp index f4ed7a634f..641533fc6a 100644 --- a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -73,7 +73,7 @@ struct winding_side_equal PointOfSegment ss1, ss2; set<1-D>(ss1, get<1-D>(se)); set<1-D>(ss2, get<1-D>(se)); - if ( count > 0 ) // UP + if (count > 0) // UP { set<D>(ss1, 0); set<D>(ss2, 1); @@ -127,7 +127,7 @@ struct winding_side_between set<1-D>(ss1, get<1-D>(s1)); set<1-D>(ss2, get<1-D>(s1)); - if ( count > 0 ) // UP + if (count > 0) // UP { set<D>(ss1, 0); set<D>(ss2, 1); @@ -140,9 +140,9 @@ struct winding_side_between int const seg_side = strategy_side_type::apply(ss1, ss2, s2); - if ( seg_side != 0 ) // segment not vertical + if (seg_side != 0) // segment not vertical { - if ( strategy_side_type::apply(ss1, ss2, point) == -seg_side ) // point on the opposite side than s2 + if (strategy_side_type::apply(ss1, ss2, point) == -seg_side) // point on the opposite side than s2 { return -seg_side; } @@ -151,7 +151,7 @@ struct winding_side_between 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 + if (strategy_side_type::apply(ss1, ss2, point) == seg_side) // point behind s2 { return seg_side; } @@ -308,7 +308,7 @@ public : if (count != 0) { int side = 0; - if ( count == 1 || count == -1 ) + if (count == 1 || count == -1) { side = winding_side_equal<cs_t> ::template apply<1>(point, eq1 ? s1 : s2, count); diff --git a/boost/geometry/strategies/agnostic/relate.hpp b/boost/geometry/strategies/agnostic/relate.hpp index 318047fadb..9e8753251d 100644 --- a/boost/geometry/strategies/agnostic/relate.hpp +++ b/boost/geometry/strategies/agnostic/relate.hpp @@ -20,10 +20,9 @@ namespace boost { namespace geometry namespace strategy { namespace relate { -template <typename StaticMask> +template <typename Geometry1, typename Geometry2, 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); @@ -44,13 +43,23 @@ 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; + typedef strategy::relate::relate + < + Geometry1, + Geometry2, + 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; + typedef strategy::relate::relate + < + Geometry1, + Geometry2, + detail::relate::static_mask_within + > type; }; @@ -71,13 +80,23 @@ 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; + typedef strategy::relate::relate + < + Geometry1, + Geometry2, + 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; + typedef strategy::relate::relate + < + Geometry1, + Geometry2, + detail::relate::static_mask_covered_by + > type; }; diff --git a/boost/geometry/strategies/agnostic/side_by_azimuth.hpp b/boost/geometry/strategies/agnostic/side_by_azimuth.hpp new file mode 100644 index 0000000000..14c69a0597 --- /dev/null +++ b/boost/geometry/strategies/agnostic/side_by_azimuth.hpp @@ -0,0 +1,87 @@ +// Boost.Geometry + +// 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_STRATEGIES_AGNOSTIC_SIDE_BY_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_SIDE_BY_AZIMUTH_HPP + +#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/azimuth.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/strategies/side.hpp> +//#include <boost/geometry/strategies/concepts/side_concept.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace side +{ + +/*! +\brief Check at which side of a segment a point lies + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam Model Reference model of coordinate system. +\tparam CalculationType \tparam_calculation + */ +template <typename Model, typename CalculationType = void> +class side_by_azimuth +{ +public: + side_by_azimuth(Model const& model = Model()) + : m_model(model) + {} + + template <typename P1, typename P2, typename P> + inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename promote_floating_point + < + typename select_calculation_type_alt + < + CalculationType, + P1, P2, P + >::type + >::type calc_t; + + calc_t d1 = 0.001; + calc_t crs_AD = geometry::detail::azimuth<calc_t>(p1, p, m_model); + calc_t crs_AB = geometry::detail::azimuth<calc_t>(p1, p2, m_model); + calc_t XTD = asin(sin(d1) * sin(crs_AD - crs_AB)); + + return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1; + } + +private: + Model m_model; +}; + +}} // namespace strategy::side + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_SIDE_BY_AZIMUTH_HPP diff --git a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp index 8ad3bbc50d..99e7d9b50f 100644 --- a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp +++ b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp @@ -1,8 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 1995, 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 1995, 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 1995 Maarten Hilferink, Amsterdam, the Netherlands +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -15,6 +20,9 @@ #include <cstddef> +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER +#include <iostream> +#endif #include <vector> #include <boost/range.hpp> @@ -23,10 +31,7 @@ #include <boost/geometry/strategies/distance.hpp> - -//#define GL_DEBUG_DOUGLAS_PEUCKER - -#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER #include <boost/geometry/io/dsv/write.hpp> #endif @@ -126,7 +131,7 @@ namespace detail // because we want to consider a candidate point in between if (size <= 2) { -#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER if (begin != end) { std::cout << "ignore between " << dsv(begin->p) @@ -140,7 +145,7 @@ namespace detail iterator_type last = end - 1; -#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER std::cout << "find between " << dsv(begin->p) << " and " << dsv(last->p) << " size=" << size << std::endl; @@ -155,7 +160,7 @@ namespace detail { distance_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p); -#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER std::cout << "consider " << dsv(it->p) << " at " << double(dist) << ((dist > max_dist) ? " maybe" : " no") @@ -173,7 +178,7 @@ namespace detail // and handle segments in between recursively if ( less()(max_dist, md) ) { -#ifdef GL_DEBUG_DOUGLAS_PEUCKER +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER std::cout << "use " << dsv(candidate->p) << std::endl; #endif @@ -193,6 +198,10 @@ namespace detail OutputIterator out, distance_type max_distance) const { +#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER + std::cout << "max distance: " << max_distance + << std::endl << std::endl; +#endif distance_strategy_type strategy; // Copy coordinates, a vector of references to all points @@ -228,8 +237,6 @@ namespace detail } }; - - } #endif // DOXYGEN_NO_DETAIL @@ -269,18 +276,28 @@ public : PointDistanceStrategy >::distance_type distance_type; - typedef distance_type return_type; - template <typename Range, typename OutputIterator> static inline OutputIterator apply(Range const& range, OutputIterator out, - distance_type max_distance) + distance_type const& max_distance) { - return detail::douglas_peucker + namespace services = strategy::distance::services; + + typedef typename services::comparable_type < - Point, PointDistanceStrategy - >().apply(range, out, max_distance); + >::type comparable_distance_strategy_type; + + return detail::douglas_peucker + < + Point, comparable_distance_strategy_type + >().apply(range, out, + services::result_from_distance + < + comparable_distance_strategy_type, Point, Point + >::apply(comparable_distance_strategy_type(), + max_distance) + ); } }; diff --git a/boost/geometry/strategies/cartesian/buffer_end_round.hpp b/boost/geometry/strategies/cartesian/buffer_end_round.hpp index 74780d6165..a233f1c4be 100644 --- a/boost/geometry/strategies/cartesian/buffer_end_round.hpp +++ b/boost/geometry/strategies/cartesian/buffer_end_round.hpp @@ -95,8 +95,9 @@ public : //! \brief Constructs the strategy //! \param points_per_circle points which would be used for a full circle + //! (if points_per_circle is smaller than 4, it is internally set to 4) explicit inline end_round(std::size_t points_per_circle = 90) - : m_points_per_circle(points_per_circle) + : m_points_per_circle((points_per_circle < 4u) ? 4u : points_per_circle) {} #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -106,7 +107,7 @@ public : inline void apply(Point const& penultimate_point, Point const& perp_left_point, Point const& ultimate_point, - Point const& , + Point const& perp_right_point, buffer_side_selector side, DistanceStrategy const& distance, RangeOut& range_out) const @@ -142,6 +143,13 @@ public : 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); } + + if (m_points_per_circle % 2 == 1) + { + // For a half circle, if the number of points is not even, + // we should insert the end point too, to generate a full cap + range_out.push_back(perp_right_point); + } } template <typename NumericType> diff --git a/boost/geometry/strategies/cartesian/buffer_join_miter.hpp b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp index 8fcf3b996c..99ec80527f 100644 --- a/boost/geometry/strategies/cartesian/buffer_join_miter.hpp +++ b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp @@ -35,6 +35,8 @@ namespace strategy { namespace buffer 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. + If the buffer distance is 5.0, and the miter limit is 2.0, generated points + will be located at a distance of at most 10.0 (2*5) units. This strategy is only applicable for Cartesian coordinate systems. \qbk{ diff --git a/boost/geometry/strategies/cartesian/buffer_join_round.hpp b/boost/geometry/strategies/cartesian/buffer_join_round.hpp index 9e467c85a0..9ec51cd1ec 100644 --- a/boost/geometry/strategies/cartesian/buffer_join_round.hpp +++ b/boost/geometry/strategies/cartesian/buffer_join_round.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2015 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,6 +9,8 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP +#include <algorithm> + #include <boost/assert.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/policies/compare.hpp> @@ -69,34 +71,38 @@ private : 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); + PromotedType const dx1 = get<0>(perp1) - get<0>(vertex); + PromotedType const dy1 = get<1>(perp1) - get<1>(vertex); + PromotedType const dx2 = get<0>(perp2) - get<0>(vertex); + PromotedType const dy2 = get<1>(perp2) - get<1>(vertex); - BOOST_ASSERT(buffer_distance != 0); + PromotedType const two = 2.0; + PromotedType const two_pi = two * geometry::math::pi<PromotedType>(); - dx1 /= buffer_distance; - dy1 /= buffer_distance; - dx2 /= buffer_distance; - dy2 /= buffer_distance; + PromotedType const angle1 = atan2(dy1, dx1); + PromotedType angle2 = atan2(dy2, dx2); + while (angle2 > angle1) + { + angle2 -= two_pi; + } + PromotedType const angle_diff = angle1 - angle2; - PromotedType angle_diff = acos(dx1 * dx2 + dy1 * dy2); + // Divide the angle into an integer amount of steps to make it + // visually correct also for a low number of points / circle - 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 a full circle is divided into 3 parts (e.g. angle is 125), + // the one point in between must still be generated + // The calculation below: + // - generates 1 point in between for an angle of 125 based on 3 points + // - generates 0 points in between for an angle of 90 based on 4 points - if (n <= 1) - { - return; - } + int const n = (std::max)(static_cast<int>( + ceil(m_points_per_circle * angle_diff / two_pi)), 1); - PromotedType const angle1 = atan2(dy1, dx1); - PromotedType diff = angle_diff / PromotedType(n); + PromotedType const diff = angle_diff / static_cast<PromotedType>(n); PromotedType a = angle1 - diff; + // Walk to n - 1 to avoid generating the last point for (int i = 0; i < n - 1; i++, a -= diff) { Point p; diff --git a/boost/geometry/strategies/cartesian/buffer_point_circle.hpp b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp index f64a82d8fc..86ebc43c9c 100644 --- a/boost/geometry/strategies/cartesian/buffer_point_circle.hpp +++ b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp @@ -1,5 +1,12 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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) @@ -45,9 +52,10 @@ class point_circle { public : //! \brief Constructs the strategy - //! \param count number of points for the created circle + //! \param count number of points for the created circle (if count + //! is smaller than 3, count is internally set to 3) explicit point_circle(std::size_t count = 90) - : m_count(count) + : m_count((count < 3u) ? 3u : count) {} #ifndef DOXYGEN_SHOULD_SKIP_THIS diff --git a/boost/geometry/strategies/cartesian/cart_intersect.hpp b/boost/geometry/strategies/cartesian/cart_intersect.hpp index 66af2d2e9c..a7bd385226 100644 --- a/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -1,7 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// 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 +// 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 @@ -194,7 +200,11 @@ struct relate_cartesian_segments get<1>(robust_b1) - get<1>(robust_a1), robust_db0, robust_db); - if (robust_da0 == 0) + math::detail::equals_factor_policy<robust_coordinate_type> + policy(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b); + robust_coordinate_type const zero = 0; + if (math::detail::equals_by_policy(robust_da0, zero, policy) + || math::detail::equals_by_policy(robust_db0, zero, policy)) { // If this is the case, no rescaling is done for FP precision. // We set it to collinear, but it indicates a robustness issue. @@ -211,25 +221,31 @@ struct relate_cartesian_segments if (collinear) { - 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) + std::pair<bool, bool> const collinear_use_first + = is_x_more_significant(geometry::math::abs(robust_dx_a), + geometry::math::abs(robust_dy_a), + geometry::math::abs(robust_dx_b), + geometry::math::abs(robust_dy_b), + a_is_point, b_is_point); + + if (collinear_use_first.second) { - return relate_collinear<0, ratio_type>(a, b, - robust_a1, robust_a2, robust_b1, robust_b2, - a_is_point, b_is_point); - } - else - { - // 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); + // Degenerate cases: segments of single point, lying on other segment, are not disjoint + // This situation is collinear too + + if (collinear_use_first.first) + { + return relate_collinear<0, ratio_type>(a, b, + robust_a1, robust_a2, robust_b1, robust_b2, + a_is_point, b_is_point); + } + else + { + // 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); + } } } @@ -237,6 +253,40 @@ struct relate_cartesian_segments } private: + // first is true if x is more significant + // second is true if the more significant difference is not 0 + template <typename RobustCoordinateType> + static inline std::pair<bool, bool> + is_x_more_significant(RobustCoordinateType const& abs_robust_dx_a, + RobustCoordinateType const& abs_robust_dy_a, + RobustCoordinateType const& abs_robust_dx_b, + RobustCoordinateType const& abs_robust_dy_b, + bool const a_is_point, + bool const b_is_point) + { + //BOOST_ASSERT_MSG(!(a_is_point && b_is_point), "both segments shouldn't be degenerated"); + + // for degenerated segments the second is always true because this function + // shouldn't be called if both segments were degenerated + + if (a_is_point) + { + return std::make_pair(abs_robust_dx_b >= abs_robust_dy_b, true); + } + else if (b_is_point) + { + return std::make_pair(abs_robust_dx_a >= abs_robust_dy_a, true); + } + else + { + RobustCoordinateType const min_dx = (std::min)(abs_robust_dx_a, abs_robust_dx_b); + RobustCoordinateType const min_dy = (std::min)(abs_robust_dy_a, abs_robust_dy_b); + return min_dx == min_dy ? + std::make_pair(true, min_dx > RobustCoordinateType(0)) : + std::make_pair(min_dx > min_dy, true); + } + } + template < std::size_t Dimension, @@ -319,17 +369,58 @@ private: 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); + RatioType ra_from(oa_1 - ob_1, length_b); + RatioType ra_to(oa_2 - ob_1, length_b); + RatioType rb_from(ob_1 - oa_1, length_a); + RatioType rb_to(ob_2 - oa_1, length_a); + + // use absolute measure to detect endpoints intersection + // NOTE: it'd be possible to calculate bx_wrt_a using ax_wrt_b values + int const a1_wrt_b = position_value(oa_1, ob_1, ob_2); + int const a2_wrt_b = position_value(oa_2, ob_1, ob_2); + int const b1_wrt_a = position_value(ob_1, oa_1, oa_2); + int const b2_wrt_a = position_value(ob_2, oa_1, oa_2); + + // fix the ratios if necessary + // CONSIDER: fixing ratios also in other cases, if they're inconsistent + // e.g. if ratio == 1 or 0 (so IP at the endpoint) + // but position value indicates that the IP is in the middle of the segment + // because one of the segments is very long + // In such case the ratios could be moved into the middle direction + // by some small value (e.g. EPS+1ULP) + if (a1_wrt_b == 1) + { + ra_from.assign(0, 1); + rb_from.assign(0, 1); + } + else if (a1_wrt_b == 3) + { + ra_from.assign(1, 1); + rb_to.assign(0, 1); + } + + if (a2_wrt_b == 1) + { + ra_to.assign(0, 1); + rb_from.assign(1, 1); + } + else if (a2_wrt_b == 3) + { + ra_to.assign(1, 1); + rb_to.assign(1, 1); + } - if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right())) + if ((a1_wrt_b < 1 && a2_wrt_b < 1) || (a1_wrt_b > 3 && a2_wrt_b > 3)) + //if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right())) { return Policy::disjoint(); } - return Policy::segments_collinear(a, b, ra_from, ra_to, rb_from, rb_to); + bool const opposite = math::sign(length_a) != math::sign(length_b); + + return Policy::segments_collinear(a, b, opposite, + a1_wrt_b, a2_wrt_b, b1_wrt_a, b2_wrt_a, + ra_from, ra_to, rb_from, rb_to); } /// Relate segments where one is degenerate @@ -351,8 +442,32 @@ private: // b1/b2 (4..4) // Ratio: (4-2)/(6-2) RatioType const ratio(d - s1, s2 - s1); + + if (!ratio.on_segment()) + { + return Policy::disjoint(); + } + return Policy::one_degenerate(degenerate_segment, ratio, a_degenerate); } + + template <typename ProjCoord1, typename ProjCoord2> + static inline int position_value(ProjCoord1 const& ca1, + ProjCoord2 const& cb1, + ProjCoord2 const& cb2) + { + // S1x 0 1 2 3 4 + // S2 |----------> + return math::equals(ca1, cb1) ? 1 + : math::equals(ca1, cb2) ? 3 + : cb1 < cb2 ? + ( ca1 < cb1 ? 0 + : ca1 > cb2 ? 4 + : 2 ) + : ( ca1 > cb1 ? 0 + : ca1 < cb2 ? 4 + : 2 ); + } }; diff --git a/boost/geometry/strategies/cartesian/centroid_average.hpp b/boost/geometry/strategies/cartesian/centroid_average.hpp index 76e2f7144c..c12f6e2024 100644 --- a/boost/geometry/strategies/cartesian/centroid_average.hpp +++ b/boost/geometry/strategies/cartesian/centroid_average.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 2015. +// Modifications copyright (c) 2015 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,6 +20,8 @@ #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP +#include <cstddef> + #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/core/coordinate_type.hpp> @@ -46,7 +53,7 @@ private : class sum { friend class average; - int count; + std::size_t count; PointCentroid centroid; public : @@ -68,10 +75,15 @@ public : state.count++; } - static inline void result(sum const& state, PointCentroid& centroid) + static inline bool result(sum const& state, PointCentroid& centroid) { centroid = state.centroid; - divide_value(centroid, state.count); + if ( state.count > 0 ) + { + divide_value(centroid, state.count); + return true; + } + return false; } }; diff --git a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp index f199fb80e5..0357f17e7a 100644 --- a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp +++ b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.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 2015. +// Modifications copyright (c) 2015 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,6 +20,8 @@ #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP +#include <cstddef> + #include <boost/mpl/if.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/type_traits.hpp> @@ -143,7 +150,7 @@ private : class sums { friend class bashein_detmer; - int count; + std::size_t count; calculation_type sum_a2; calculation_type sum_x; calculation_type sum_y; diff --git a/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/boost/geometry/strategies/cartesian/side_by_triangle.hpp index 5d589ffc86..77443d46a9 100644 --- a/boost/geometry/strategies/cartesian/side_by_triangle.hpp +++ b/boost/geometry/strategies/cartesian/side_by_triangle.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -22,6 +27,9 @@ #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/algorithms/detail/relate/less.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> + namespace boost { namespace geometry { @@ -38,6 +46,24 @@ namespace strategy { namespace side template <typename CalculationType = void> class side_by_triangle { + template <typename Policy> + struct eps_policy + { + eps_policy() {} + template <typename Type> + eps_policy(Type const& a, Type const& b, Type const& c, Type const& d) + : policy(a, b, c, d) + {} + Policy policy; + }; + + struct eps_empty + { + eps_empty() {} + template <typename Type> + eps_empty(Type const&, Type const&, Type const&, Type const&) {} + }; + public : // Template member function, because it is not always trivial @@ -47,23 +73,34 @@ 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) + template + < + typename CoordinateType, + typename PromotedType, + typename P1, + typename P2, + typename P, + typename EpsPolicy + > + static inline + PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy) { - coordinate_type const x = get<0>(p); - coordinate_type const y = get<1>(p); + CoordinateType const x = get<0>(p); + CoordinateType 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); + CoordinateType const sx1 = get<0>(p1); + CoordinateType const sy1 = get<1>(p1); + CoordinateType const sx2 = get<0>(p2); + CoordinateType 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; + PromotedType const dx = sx2 - sx1; + PromotedType const dy = sy2 - sy1; + PromotedType const dpx = x - sx1; + PromotedType const dpy = y - sy1; - return geometry::detail::determinant<promoted_type> + eps_policy = EpsPolicy(dx, dy, dpx, dpy); + + return geometry::detail::determinant<PromotedType> ( dx, dy, dpx, dpy @@ -71,9 +108,99 @@ public : } + template + < + typename CoordinateType, + typename PromotedType, + typename P1, + typename P2, + typename P + > + static inline + PromotedType side_value(P1 const& p1, P2 const& p2, P const& p) + { + eps_empty dummy; + return side_value<CoordinateType, PromotedType>(p1, p2, p, dummy); + } + + + template + < + typename CoordinateType, + typename PromotedType, + bool AreAllIntegralCoordinates + > + struct compute_side_value + { + template <typename P1, typename P2, typename P, typename EpsPolicy> + static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) + { + return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp); + } + }; + + template <typename CoordinateType, typename PromotedType> + struct compute_side_value<CoordinateType, PromotedType, false> + { + template <typename P1, typename P2, typename P, typename EpsPolicy> + static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) + { + // For robustness purposes, first check if any two points are + // the same; in this case simply return that the points are + // collinear + if (geometry::detail::equals::equals_point_point(p1, p2) + || geometry::detail::equals::equals_point_point(p1, p) + || geometry::detail::equals::equals_point_point(p2, p)) + { + return PromotedType(0); + } + + // The side_by_triangle strategy computes the signed area of + // the point triplet (p1, p2, p); as such it is (in theory) + // invariant under cyclic permutations of its three arguments. + // + // In the context of numerical errors that arise in + // floating-point computations, and in order to make the strategy + // consistent with respect to cyclic permutations of its three + // arguments, we cyclically permute them so that the first + // argument is always the lexicographically smallest point. + + geometry::detail::relate::less less; + if (less(p, p1)) + { + if (less(p, p2)) + { + // p is the lexicographically smallest + return side_value<CoordinateType, PromotedType>(p, p1, p2, epsp); + } + else + { + // p2 is the lexicographically smallest + return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp); + } + } + + if (less(p1, p2)) + { + // p1 is the lexicographically smallest + return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp); + } + else + { + // p2 is the lexicographically smallest + return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp); + } + } + }; + + template <typename P1, typename P2, typename P> static inline int apply(P1 const& p1, P2 const& p2, P const& p) { + typedef typename coordinate_type<P1>::type coordinate_type1; + typedef typename coordinate_type<P2>::type coordinate_type2; + typedef typename coordinate_type<P>::type coordinate_type3; + typedef typename boost::mpl::if_c < boost::is_void<CalculationType>::type::value, @@ -81,10 +208,9 @@ public : < typename select_most_precise < - typename coordinate_type<P1>::type, - typename coordinate_type<P2>::type + coordinate_type1, coordinate_type2 >::type, - typename coordinate_type<P>::type + coordinate_type3 >::type, CalculationType >::type coordinate_type; @@ -96,10 +222,19 @@ public : double >::type promoted_type; - promoted_type const s = side_value<coordinate_type, promoted_type>(p1, p2, p); - promoted_type const zero = promoted_type(); + bool const are_all_integral_coordinates = + boost::is_integral<coordinate_type1>::value + && boost::is_integral<coordinate_type2>::value + && boost::is_integral<coordinate_type3>::value; - return math::equals(s, zero) ? 0 + eps_policy< math::detail::equals_factor_policy<promoted_type> > epsp; + promoted_type s = compute_side_value + < + coordinate_type, promoted_type, are_all_integral_coordinates + >::apply(p1, p2, p, epsp); + + promoted_type const zero = promoted_type(); + return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0 : s > zero ? 1 : -1; } diff --git a/boost/geometry/strategies/cartesian/side_of_intersection.hpp b/boost/geometry/strategies/cartesian/side_of_intersection.hpp new file mode 100644 index 0000000000..39487676c1 --- /dev/null +++ b/boost/geometry/strategies/cartesian/side_of_intersection.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015 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_SIDE_OF_INTERSECTION_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP + + +#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace side +{ + +// Calculates the side of the intersection-point (if any) of +// of segment a//b w.r.t. segment c +// This is calculated without (re)calculating the IP itself again and fully +// based on integer mathematics; there are no divisions +// It can be used for either integer (rescaled) points, and also for FP +class side_of_intersection +{ +public : + + // Calculates the side of the intersection-point (if any) of + // of segment a//b w.r.t. segment c + // This is calculated without (re)calculating the IP itself again and fully + // based on integer mathematics + template <typename T, typename Segment> + static inline T side_value(Segment const& a, Segment const& b, + Segment const& c) + { + // The first point of the three segments is reused several times + T const ax = get<0, 0>(a); + T const ay = get<0, 1>(a); + T const bx = get<0, 0>(b); + T const by = get<0, 1>(b); + T const cx = get<0, 0>(c); + T const cy = get<0, 1>(c); + + T const dx_a = get<1, 0>(a) - ax; + T const dy_a = get<1, 1>(a) - ay; + + T const dx_b = get<1, 0>(b) - bx; + T const dy_b = get<1, 1>(b) - by; + + T const dx_c = get<1, 0>(c) - cx; + T const dy_c = get<1, 1>(c) - cy; + + // Cramer's rule: d (see cart_intersect.hpp) + T const d = geometry::detail::determinant<T> + ( + dx_a, dy_a, + dx_b, dy_b + ); + + T const zero = T(); + if (d == zero) + { + // There is no IP of a//b, they are collinear or parallel + // We don't have to divide but we can already conclude the side-value + // is meaningless and the resulting determinant will be 0 + return zero; + } + + // Cramer's rule: da (see cart_intersect.hpp) + T const da = geometry::detail::determinant<T> + ( + dx_b, dy_b, + ax - bx, ay - by + ); + + // IP is at (ax + (da/d) * dx_a, ay + (da/d) * dy_a) + // Side of IP is w.r.t. c is: determinant(dx_c, dy_c, ipx-cx, ipy-cy) + // We replace ipx by expression above and multiply each term by d + T const result = geometry::detail::determinant<T> + ( + dx_c * d, dy_c * d, + d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da + ); + + // Note: result / (d * d) + // is identical to the side_value of side_by_triangle + // Therefore, the sign is always the same as that result, and the + // resulting side (left,right,collinear) is the same + + return result; + + } + + template <typename Segment> + static inline int apply(Segment const& a, Segment const& b, Segment const& c) + { + typedef typename geometry::coordinate_type<Segment>::type coordinate_type; + coordinate_type const s = side_value<coordinate_type>(a, b, c); + coordinate_type const zero = coordinate_type(); + return math::equals(s, zero) ? 0 + : s > zero ? 1 + : -1; + } + +}; + + +}} // namespace strategy::side + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP diff --git a/boost/geometry/strategies/comparable_distance_result.hpp b/boost/geometry/strategies/comparable_distance_result.hpp index a258ddb9b4..5ba9b1603d 100644 --- a/boost/geometry/strategies/comparable_distance_result.hpp +++ b/boost/geometry/strategies/comparable_distance_result.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -91,9 +91,9 @@ struct comparable_distance_result // A set of all variant type combinations that are compatible and // implemented typedef typename util::combine_if< - typename mpl::vector1<Geometry1>, + typename boost::mpl::vector1<Geometry1>, typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, - mpl::always<mpl::true_> + boost::mpl::always<boost::mpl::true_> >::type possible_input_types; // The (possibly variant) result type resulting from these combinations @@ -101,11 +101,11 @@ struct comparable_distance_result typename transform_variant< possible_input_types, resolve_strategy::comparable_distance_result< - mpl::first<mpl::_>, - mpl::second<mpl::_>, + boost::mpl::first<boost::mpl::_>, + boost::mpl::second<boost::mpl::_>, Strategy >, - mpl::back_inserter<mpl::vector0<> > + boost::mpl::back_inserter<boost::mpl::vector0<> > >::type >::type type; }; @@ -144,7 +144,7 @@ struct comparable_distance_result < typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, - mpl::always<mpl::true_> + boost::mpl::always<boost::mpl::true_> >::type possible_input_types; // The (possibly variant) result type resulting from these combinations @@ -152,11 +152,11 @@ struct comparable_distance_result typename transform_variant< possible_input_types, resolve_strategy::comparable_distance_result< - mpl::first<mpl::_>, - mpl::second<mpl::_>, + boost::mpl::first<boost::mpl::_>, + boost::mpl::second<boost::mpl::_>, Strategy >, - mpl::back_inserter<mpl::vector0<> > + boost::mpl::back_inserter<boost::mpl::vector0<> > >::type >::type type; }; diff --git a/boost/geometry/strategies/concepts/distance_concept.hpp b/boost/geometry/strategies/concepts/distance_concept.hpp index a0cbbd21ed..6e75fa95a6 100644 --- a/boost/geometry/strategies/concepts/distance_concept.hpp +++ b/boost/geometry/strategies/concepts/distance_concept.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. @@ -19,6 +24,8 @@ #include <boost/concept_check.hpp> #include <boost/core/ignore_unused.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> #include <boost/geometry/util/parameter_type_of.hpp> @@ -26,13 +33,15 @@ #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/geometries/point.hpp> +#include <boost/geometry/strategies/tags.hpp> + namespace boost { namespace geometry { namespace concept { /*! - \brief Checks strategy for point-segment-distance + \brief Checks strategy for point-point or point-box or box-box distance \ingroup distance */ template <typename Strategy, typename Point1, typename Point2> @@ -57,7 +66,7 @@ private : ApplyMethod, 1 >::type ptype2; - // 2) must define meta-function return_type + // 2) must define meta-function "return_type" typedef typename strategy::distance::services::return_type < Strategy, ptype1, ptype2 @@ -75,6 +84,16 @@ private : Strategy >::type tag; + static const bool is_correct_strategy_tag = + boost::is_same<tag, strategy_tag_distance_point_point>::value + || boost::is_same<tag, strategy_tag_distance_point_box>::value + || boost::is_same<tag, strategy_tag_distance_box_box>::value; + + BOOST_MPL_ASSERT_MSG + ((is_correct_strategy_tag), + INCORRECT_STRATEGY_TAG, + (types<tag>)); + // 5) must implement apply with arguments Strategy* str = 0; ptype1 *p1 = 0; @@ -111,7 +130,7 @@ public : /*! - \brief Checks strategy for point-segment-distance + \brief Checks strategy for point-segment distance \ingroup strategy_concepts */ template <typename Strategy, typename Point, typename PointOfSegment> @@ -125,6 +144,7 @@ private : template <typename ApplyMethod> static void apply(ApplyMethod) { + // 1) inspect and define both arguments of apply typedef typename parameter_type_of < ApplyMethod, 0 @@ -135,10 +155,28 @@ private : ApplyMethod, 1 >::type sptype; - // must define meta-function return_type - typedef typename strategy::distance::services::return_type<Strategy, ptype, sptype>::type rtype; + namespace services = strategy::distance::services; + // 2) must define meta-function "tag" + typedef typename services::tag<Strategy>::type tag; + BOOST_MPL_ASSERT_MSG + ((boost::is_same + < + tag, strategy_tag_distance_point_segment + >::value), + INCORRECT_STRATEGY_TAG, + (types<tag>)); + // 3) must define meta-function "return_type" + typedef typename services::return_type + < + Strategy, ptype, sptype + >::type rtype; + + // 4) must define meta-function "comparable_type" + typedef typename services::comparable_type<Strategy>::type ctype; + + // 5) must implement apply with arguments Strategy *str = 0; ptype *p = 0; sptype *sp1 = 0; @@ -146,8 +184,16 @@ private : rtype r = str->apply(*p, *sp1, *sp2); - boost::ignore_unused_variable_warning(str); - boost::ignore_unused_variable_warning(r); + // 6) must define (meta-)struct "get_comparable" with apply + ctype cstrategy = services::get_comparable<Strategy>::apply(*str); + + // 7) must define (meta-)struct "result_from_distance" with apply + r = services::result_from_distance + < + Strategy, ptype, sptype + >::apply(*str, rtype(1.0)); + + boost::ignore_unused(str, r, cstrategy); } }; diff --git a/boost/geometry/strategies/distance_result.hpp b/boost/geometry/strategies/distance_result.hpp index 185a511464..e4f326d3ee 100644 --- a/boost/geometry/strategies/distance_result.hpp +++ b/boost/geometry/strategies/distance_result.hpp @@ -1,13 +1,13 @@ // 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. +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -100,14 +100,14 @@ struct distance_result // A set of all variant type combinations that are compatible and // implemented typedef typename util::combine_if< - typename mpl::vector1<Geometry1>, + typename boost::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_> + // util::is_implemented2<boost::mpl::_1, boost::mpl::_2, dispatch::distance<boost::mpl::_1, boost::mpl::_2> > + boost::mpl::always<boost::mpl::true_> >::type possible_input_types; // The (possibly variant) result type resulting from these combinations @@ -115,11 +115,11 @@ struct distance_result typename transform_variant< possible_input_types, resolve_strategy::distance_result< - mpl::first<mpl::_>, - mpl::second<mpl::_>, + boost::mpl::first<boost::mpl::_>, + boost::mpl::second<boost::mpl::_>, Strategy >, - mpl::back_inserter<mpl::vector0<> > + boost::mpl::back_inserter<boost::mpl::vector0<> > >::type >::type type; }; @@ -163,8 +163,8 @@ struct distance_result // 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_> + // util::is_implemented2<boost::mpl::_1, boost::mpl::_2, dispatch::distance<boost::mpl::_1, boost::mpl::_2> > + boost::mpl::always<boost::mpl::true_> >::type possible_input_types; // The (possibly variant) result type resulting from these combinations @@ -172,11 +172,11 @@ struct distance_result typename transform_variant< possible_input_types, resolve_strategy::distance_result< - mpl::first<mpl::_>, - mpl::second<mpl::_>, + boost::mpl::first<boost::mpl::_>, + boost::mpl::second<boost::mpl::_>, Strategy >, - mpl::back_inserter<mpl::vector0<> > + boost::mpl::back_inserter<boost::mpl::vector0<> > >::type >::type type; }; diff --git a/boost/geometry/strategies/geographic/distance_andoyer.hpp b/boost/geometry/strategies/geographic/distance_andoyer.hpp new file mode 100644 index 0000000000..64de8c1a41 --- /dev/null +++ b/boost/geometry/strategies/geographic/distance_andoyer.hpp @@ -0,0 +1,224 @@ +// 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_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/algorithms/detail/flattening.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + + +/*! +\brief Point-point distance approximation taking flattening into account +\ingroup distance +\tparam Spheroid The reference spheroid model +\tparam CalculationType \tparam_calculation +\author After Andoyer, 19xx, republished 1950, republished by Meeus, 1999 +\note Although not so well-known, the approximation is very good: in all cases the results +are about the same as Vincenty. In my (Barend's) testcases the results didn't differ more than 6 m +\see http://nacc.upc.es/tierra/node16.html +\see http://sci.tech-archive.net/Archive/sci.geo.satellite-nav/2004-12/2724.html +\see http://home.att.net/~srschmitt/great_circle_route.html (implementation) +\see http://www.codeguru.com/Cpp/Cpp/algorithms/article.php/c5115 (implementation) +\see http://futureboy.homeip.net/frinksamp/navigation.frink (implementation) +\see http://www.voidware.com/earthdist.htm (implementation) +*/ +template +< + typename Spheroid, + typename CalculationType = void +> +class andoyer +{ +public : + template <typename Point1, typename Point2> + struct calculation_type + : promote_floating_point + < + typename select_calculation_type + < + Point1, + Point2, + CalculationType + >::type + > + {}; + + typedef Spheroid model_type; + + inline andoyer() + : m_spheroid() + {} + + explicit inline andoyer(Spheroid const& spheroid) + : m_spheroid(spheroid) + {} + + + template <typename Point1, typename Point2> + inline typename calculation_type<Point1, Point2>::type + apply(Point1 const& point1, Point2 const& point2) const + { + return calc<typename calculation_type<Point1, Point2>::type> + ( + get_as_radian<0>(point1), get_as_radian<1>(point1), + get_as_radian<0>(point2), get_as_radian<1>(point2) + ); + } + + inline Spheroid const& model() const + { + return m_spheroid; + } + +private : + template <typename CT, typename T> + inline CT calc(T const& lon1, + T const& lat1, + T const& lon2, + T const& lat2) const + { + CT const G = (lat1 - lat2) / 2.0; + CT const lambda = (lon1 - lon2) / 2.0; + + if (geometry::math::equals(lambda, 0.0) + && geometry::math::equals(G, 0.0)) + { + return 0.0; + } + + CT const F = (lat1 + lat2) / 2.0; + + CT const sinG2 = math::sqr(sin(G)); + CT const cosG2 = math::sqr(cos(G)); + CT const sinF2 = math::sqr(sin(F)); + CT const cosF2 = math::sqr(cos(F)); + CT const sinL2 = math::sqr(sin(lambda)); + CT const cosL2 = math::sqr(cos(lambda)); + + CT const S = sinG2 * cosL2 + cosF2 * sinL2; + CT const C = cosG2 * cosL2 + sinF2 * sinL2; + + CT const c0 = 0; + CT const c1 = 1; + CT const c2 = 2; + CT const c3 = 3; + + if (geometry::math::equals(S, c0) || geometry::math::equals(C, c0)) + { + return c0; + } + + CT const radius_a = CT(get_radius<0>(m_spheroid)); + CT const flattening = geometry::detail::flattening<CT>(m_spheroid); + + CT const omega = atan(math::sqrt(S / C)); + CT const r3 = c3 * math::sqrt(S * C) / omega; // not sure if this is r or greek nu + CT const D = c2 * omega * radius_a; + CT const H1 = (r3 - c1) / (c2 * C); + CT const H2 = (r3 + c1) / (c2 * S); + + return D * (c1 + flattening * (H1 * sinF2 * cosG2 - H2 * cosF2 * sinG2) ); + } + + Spheroid m_spheroid; +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Spheroid, typename CalculationType> +struct tag<andoyer<Spheroid, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Spheroid, typename CalculationType, typename P1, typename P2> +struct return_type<andoyer<Spheroid, CalculationType>, P1, P2> + : andoyer<Spheroid, CalculationType>::template calculation_type<P1, P2> +{}; + + +template <typename Spheroid, typename CalculationType> +struct comparable_type<andoyer<Spheroid, CalculationType> > +{ + typedef andoyer<Spheroid, CalculationType> type; +}; + + +template <typename Spheroid, typename CalculationType> +struct get_comparable<andoyer<Spheroid, CalculationType> > +{ + static inline andoyer<Spheroid, CalculationType> apply(andoyer<Spheroid, CalculationType> const& input) + { + return input; + } +}; + +template <typename Spheroid, typename CalculationType, typename P1, typename P2> +struct result_from_distance<andoyer<Spheroid, CalculationType>, P1, P2> +{ + template <typename T> + static inline typename return_type<andoyer<Spheroid, CalculationType>, P1, P2>::type + apply(andoyer<Spheroid, CalculationType> const& , T const& value) + { + return value; + } +}; + + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag> +{ + typedef strategy::distance::andoyer + < + srs::spheroid + < + typename select_coordinate_type<Point1, Point2>::type + > + > type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP diff --git a/boost/geometry/strategies/geographic/distance_vincenty.hpp b/boost/geometry/strategies/geographic/distance_vincenty.hpp new file mode 100644 index 0000000000..56dd14bbdc --- /dev/null +++ b/boost/geometry/strategies/geographic/distance_vincenty.hpp @@ -0,0 +1,161 @@ +// Boost.Geometry + +// 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_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/radian_access.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/algorithms/detail/vincenty_inverse.hpp> + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +/*! +\brief Distance calculation formulae on latlong coordinates, after Vincenty, 1975 +\ingroup distance +\tparam Spheroid The reference spheroid model +\tparam CalculationType \tparam_calculation +\author See + - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf + - http://www.icsm.gov.au/gda/gdav2.3.pdf +\author Adapted from various implementations to get it close to the original document + - http://www.movable-type.co.uk/scripts/LatLongVincenty.html + - http://exogen.case.edu/projects/geopy/source/geopy.distance.html + - http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink + +*/ +template +< + typename Spheroid, + typename CalculationType = void +> +class vincenty +{ +public : + template <typename Point1, typename Point2> + struct calculation_type + : promote_floating_point + < + typename select_calculation_type + < + Point1, + Point2, + CalculationType + >::type + > + {}; + + typedef Spheroid model_type; + + inline vincenty() + : m_spheroid() + {} + + explicit inline vincenty(Spheroid const& spheroid) + : m_spheroid(spheroid) + {} + + template <typename Point1, typename Point2> + inline typename calculation_type<Point1, Point2>::type + apply(Point1 const& point1, Point2 const& point2) const + { + return geometry::detail::vincenty_inverse + < + typename calculation_type<Point1, Point2>::type + >(get_as_radian<0>(point1), + get_as_radian<1>(point1), + get_as_radian<0>(point2), + get_as_radian<1>(point2), + m_spheroid).distance(); + } + + inline Spheroid const& model() const + { + return m_spheroid; + } + +private : + Spheroid m_spheroid; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template <typename Spheroid, typename CalculationType> +struct tag<vincenty<Spheroid, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template <typename Spheroid, typename CalculationType, typename P1, typename P2> +struct return_type<vincenty<Spheroid, CalculationType>, P1, P2> + : vincenty<Spheroid, CalculationType>::template calculation_type<P1, P2> +{}; + + +template <typename Spheroid, typename CalculationType> +struct comparable_type<vincenty<Spheroid, CalculationType> > +{ + typedef vincenty<Spheroid, CalculationType> type; +}; + + +template <typename Spheroid, typename CalculationType> +struct get_comparable<vincenty<Spheroid, CalculationType> > +{ + static inline vincenty<Spheroid, CalculationType> apply(vincenty<Spheroid, CalculationType> const& input) + { + return input; + } +}; + +template <typename Spheroid, typename CalculationType, typename P1, typename P2> +struct result_from_distance<vincenty<Spheroid, CalculationType>, P1, P2 > +{ + template <typename T> + static inline typename return_type<vincenty<Spheroid, CalculationType>, P1, P2>::type + apply(vincenty<Spheroid, CalculationType> const& , T const& value) + { + return value; + } +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +// We might add a vincenty-like strategy also for point-segment distance, but to calculate the projected point is not trivial + + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP diff --git a/boost/geometry/strategies/geographic/mapping_ssf.hpp b/boost/geometry/strategies/geographic/mapping_ssf.hpp new file mode 100644 index 0000000000..3beedc7809 --- /dev/null +++ b/boost/geometry/strategies/geographic/mapping_ssf.hpp @@ -0,0 +1,185 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-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_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP + + +#include <boost/core/ignore_unused.hpp> + +#include <boost/geometry/core/radius.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/spherical/ssf.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace side +{ + + +// An enumeration type defining types of mapping of geographical +// latitude to spherical latitude. +// See: http://en.wikipedia.org/wiki/Great_ellipse +// http://en.wikipedia.org/wiki/Latitude#Auxiliary_latitudes +enum mapping_type { mapping_geodetic, mapping_reduced, mapping_geocentric }; + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Spheroid, mapping_type Mapping> +struct mapper +{ + explicit inline mapper(Spheroid const& /*spheroid*/) {} + + template <typename CalculationType> + static inline CalculationType const& apply(CalculationType const& lat) + { + return lat; + } +}; + +template <typename Spheroid> +struct mapper<Spheroid, mapping_reduced> +{ + typedef typename promote_floating_point + < + typename radius_type<Spheroid>::type + >::type fraction_type; + + explicit inline mapper(Spheroid const& spheroid) + { + fraction_type const a = geometry::get_radius<0>(spheroid); + fraction_type const b = geometry::get_radius<2>(spheroid); + b_div_a = b / a; + } + + template <typename CalculationType> + inline CalculationType apply(CalculationType const& lat) const + { + return atan(static_cast<CalculationType>(b_div_a) * tan(lat)); + } + + fraction_type b_div_a; +}; + +template <typename Spheroid> +struct mapper<Spheroid, mapping_geocentric> +{ + typedef typename promote_floating_point + < + typename radius_type<Spheroid>::type + >::type fraction_type; + + explicit inline mapper(Spheroid const& spheroid) + { + fraction_type const a = geometry::get_radius<0>(spheroid); + fraction_type const b = geometry::get_radius<2>(spheroid); + sqr_b_div_a = b / a; + sqr_b_div_a *= sqr_b_div_a; + } + + template <typename CalculationType> + inline CalculationType apply(CalculationType const& lat) const + { + return atan(static_cast<CalculationType>(sqr_b_div_a) * tan(lat)); + } + + fraction_type sqr_b_div_a; +}; + +} +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Check at which side of a geographical segment a point lies + left of segment (> 0), right of segment (< 0), on segment (0). + The check is performed by mapping the geographical coordinates + to spherical coordinates and using spherical_side_formula. +\ingroup strategies +\tparam Spheroid The reference spheroid model +\tparam Mapping The type of mapping of geographical to spherical latitude +\tparam CalculationType \tparam_calculation + */ +template <typename Spheroid, + mapping_type Mapping = mapping_geodetic, + typename CalculationType = void> +class mapping_spherical_side_formula +{ + +public : + inline mapping_spherical_side_formula() + : m_mapper(Spheroid()) + {} + + explicit inline mapping_spherical_side_formula(Spheroid const& spheroid) + : m_mapper(spheroid) + {} + + template <typename P1, typename P2, typename P> + inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename promote_floating_point + < + typename select_calculation_type_alt + < + CalculationType, + P1, P2, P + >::type + >::type calculation_type; + + calculation_type lon1 = get_as_radian<0>(p1); + calculation_type lat1 = m_mapper.template apply<calculation_type>(get_as_radian<1>(p1)); + calculation_type lon2 = get_as_radian<0>(p2); + calculation_type lat2 = m_mapper.template apply<calculation_type>(get_as_radian<1>(p2)); + calculation_type lon = get_as_radian<0>(p); + calculation_type lat = m_mapper.template apply<calculation_type>(get_as_radian<1>(p)); + + return detail::spherical_side_formula(lon1, lat1, lon2, lat2, lon, lat); + } + +private: + side::detail::mapper<Spheroid, Mapping> const m_mapper; +}; + +// The specialization for geodetic latitude which can be used directly +template <typename Spheroid, + typename CalculationType> +class mapping_spherical_side_formula<Spheroid, mapping_geodetic, CalculationType> +{ + +public : + inline mapping_spherical_side_formula() {} + explicit inline mapping_spherical_side_formula(Spheroid const& /*spheroid*/) {} + + template <typename P1, typename P2, typename P> + static inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + return spherical_side_formula<CalculationType>::apply(p1, p2, p); + } +}; + +}} // namespace strategy::side + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP diff --git a/boost/geometry/strategies/spherical/distance_cross_track.hpp b/boost/geometry/strategies/spherical/distance_cross_track.hpp index a40f03dbaf..486c7effbd 100644 --- a/boost/geometry/strategies/spherical/distance_cross_track.hpp +++ b/boost/geometry/strategies/spherical/distance_cross_track.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 @@ -9,15 +14,17 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP +#include <algorithm> #include <boost/config.hpp> #include <boost/concept_check.hpp> #include <boost/mpl/if.hpp> -#include <boost/type_traits.hpp> +#include <boost/type_traits/is_void.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/course.hpp> @@ -25,39 +32,297 @@ #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> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK # include <boost/geometry/io/dsv/write.hpp> #endif - namespace boost { namespace geometry { namespace strategy { namespace distance { -/*! -\brief Strategy functor for distance point to segment calculation -\ingroup strategies -\details Class which calculates the distance of a point to a segment, for points on a sphere or globe -\see http://williams.best.vwh.net/avform.htm -\tparam CalculationType \tparam_calculation -\tparam Strategy underlying point-point distance strategy, defaults to haversine -\qbk{ -[heading See also] -[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] -} +namespace comparable +{ +/* + Given a spherical segment AB and a point D, we are interested in + computing the distance of D from AB. This is usually known as the + cross track distance. + + If the projection (along great circles) of the point D lies inside + the segment AB, then the distance (cross track error) XTD is given + by the formula (see http://williams.best.vwh.net/avform.htm#XTE): + + XTD = asin( sin(dist_AD) * sin(crs_AD-crs_AB) ) + + where dist_AD is the great circle distance between the points A and + B, and crs_AD, crs_AB is the course (bearing) between the points A, + D and A, B, respectively. + + If the point D does not project inside the arc AB, then the distance + of D from AB is the minimum of the two distances dist_AD and dist_BD. + + Our reference implementation for this procedure is listed below + (this was the old Boost.Geometry implementation of the cross track distance), + where: + * The member variable m_strategy is the underlying haversine strategy. + * p stands for the point D. + * sp1 stands for the segment endpoint A. + * sp2 stands for the segment endpoint B. + + ================= reference implementation -- start ================= + + return_type d1 = m_strategy.apply(sp1, p); + return_type d3 = m_strategy.apply(sp1, sp2); + + if (geometry::math::equals(d3, 0.0)) + { + // "Degenerate" segment, return either d1 or d2 + return d1; + } + + return_type d2 = m_strategy.apply(sp2, p); + + return_type crs_AD = 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 = geometry::detail::course<return_type>(sp2, p); + return_type d_crs1 = crs_AD - crs_AB; + return_type d_crs2 = crs_BD - crs_BA; + + // d1, d2, d3 are in principle not needed, only the sign matters + return_type projection1 = cos( d_crs1 ) * d1 / d3; + return_type projection2 = cos( d_crs2 ) * d2 / d3; + + if (projection1 > 0.0 && projection2 > 0.0) + { + return_type XTD + = radius() * math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) )); + + // Return shortest distance, projected point on segment sp1-sp2 + return return_type(XTD); + } + else + { + // Return shortest distance, project either on point sp1 or sp2 + return return_type( (std::min)( d1 , d2 ) ); + } + + ================= reference implementation -- end ================= + + + Motivation + ---------- + In what follows we develop a comparable version of the cross track + distance strategy, that meets the following goals: + * It is more efficient than the original cross track strategy (less + operations and less calls to mathematical functions). + * Distances using the comparable cross track strategy can not only + be compared with other distances using the same strategy, but also with + distances computed with the comparable version of the haversine strategy. + * It can serve as the basis for the computation of the cross track distance, + as it is more efficient to compute its comparable version and + transform that to the actual cross track distance, rather than + follow/use the reference implementation listed above. + + Major idea + ---------- + The idea here is to use the comparable haversine strategy to compute + the distances d1, d2 and d3 in the above listing. Once we have done + that we need also to make sure that instead of returning XTD (as + computed above) that we return a distance CXTD that is compatible + with the comparable haversine distance. To achieve this CXTD must satisfy + the relation: + XTD = 2 * R * asin( sqrt(XTD) ) + where R is the sphere's radius. + + Below we perform the mathematical analysis that show how to compute CXTD. + + + Mathematical analysis + --------------------- + Below we use the following trigonometric identities: + sin(2 * x) = 2 * sin(x) * cos(x) + cos(asin(x)) = sqrt(1 - x^2) + + Observation: + The distance d1 needed when the projection of the point D is within the + segment must be the true distance. However, comparable::haversine<> + returns a comparable distance instead of the one needed. + To remedy this, we implicitly compute what is needed. + More precisely, we need to compute sin(true_d1): + + sin(true_d1) = sin(2 * asin(sqrt(d1))) + = 2 * sin(asin(sqrt(d1)) * cos(asin(sqrt(d1))) + = 2 * sqrt(d1) * sqrt(1-(sqrt(d1))^2) + = 2 * sqrt(d1 - d1 * d1) + This relation is used below. + + As we mentioned above the goal is to find CXTD (named "a" below for + brevity) such that ("b" below stands for "d1", and "c" for "d_crs1"): + + 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c)) + + Analysis: + 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c)) + <=> 2 * asin(sqrt(a)) == asin(sqrt(b-b^2) * sin(c)) + <=> sin(2 * asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c) + <=> 2 * sin(asin(sqrt(a))) * cos(asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c) + <=> 2 * sqrt(a) * sqrt(1-a) == 2 * sqrt(b-b^2) * sin(c) + <=> sqrt(a) * sqrt(1-a) == sqrt(b-b^2) * sin(c) + <=> sqrt(a-a^2) == sqrt(b-b^2) * sin(c) + <=> a-a^2 == (b-b^2) * (sin(c))^2 + + Consider the quadratic equation: x^2-x+p^2 == 0, + where p = sqrt(b-b^2) * sin(c); its discriminant is: + d = 1 - 4 * p^2 = 1 - 4 * (b-b^2) * (sin(c))^2 + + The two solutions are: + a_1 = (1 - sqrt(d)) / 2 + a_2 = (1 + sqrt(d)) / 2 + + Which one to choose? + "a" refers to the distance (on the unit sphere) of D from the + supporting great circle Circ(A,B) of the segment AB. + The two different values for "a" correspond to the lengths of the two + arcs delimited D and the points of intersection of Circ(A,B) and the + great circle perperdicular to Circ(A,B) passing through D. + Clearly, the value we want is the smallest among these two distances, + hence the root we must choose is the smallest root among the two. + + So the answer is: + CXTD = ( 1 - sqrt(1 - 4 * (b-b^2) * (sin(c))^2) ) / 2 + + Therefore, in order to implement the comparable version of the cross + track strategy we need to: + (1) Use the comparable version of the haversine strategy instead of + the non-comparable one. + (2) Instead of return XTD when D projects inside the segment AB, we + need to return CXTD, given by the following formula: + CXTD = ( 1 - sqrt(1 - 4 * (d1-d1^2) * (sin(d_crs1))^2) ) / 2; + + + Complexity Analysis + ------------------- + In the analysis that follows we refer to the actual implementation below. + In particular, instead of computing CXTD as above, we use the more + efficient (operation-wise) computation of CXTD shown here: + + return_type sin_d_crs1 = sin(d_crs1); + return_type d1_x_sin = d1 * sin_d_crs1; + return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin); + return d / (0.5 + math::sqrt(0.25 - d)); + + Notice that instead of computing: + 0.5 - 0.5 * sqrt(1 - 4 * d) = 0.5 - sqrt(0.25 - d) + we use the following formula instead: + d / (0.5 + sqrt(0.25 - d)). + This is done for numerical robustness. The expression 0.5 - sqrt(0.25 - x) + has large numerical errors for values of x close to 0 (if using doubles + the error start to become large even when d is as large as 0.001). + To remedy that, we re-write 0.5 - sqrt(0.25 - x) as: + 0.5 - sqrt(0.25 - d) + = (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d)) / (0.5 + sqrt(0.25 - d)). + The numerator is the difference of two squares: + (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d)) + = 0.5^2 - (sqrt(0.25 - d))^ = 0.25 - (0.25 - d) = d, + which gives the expression we use. + + For the complexity analysis, we distinguish between two cases: + (A) The distance is realized between the point D and an + endpoint of the segment AB + + Gains: + Since we are using comparable::haversine<> which is called + 3 times, we gain: + -> 3 calls to sqrt + -> 3 calls to asin + -> 6 multiplications + + Loses: None + + So the net gain is: + -> 6 function calls (sqrt/asin) + -> 6 arithmetic operations + + If we use comparable::cross_track<> to compute + cross_track<> we need to account for a call to sqrt, a call + to asin and 2 multiplications. In this case the net gain is: + -> 4 function calls (sqrt/asin) + -> 4 arithmetic operations + + + (B) The distance is realized between the point D and an + interior point of the segment AB + + Gains: + Since we are using comparable::haversine<> which is called + 3 times, we gain: + -> 3 calls to sqrt + -> 3 calls to asin + -> 6 multiplications + Also we gain the operations used to compute XTD: + -> 2 calls to sin + -> 1 call to asin + -> 1 call to abs + -> 2 multiplications + -> 1 division + So the total gains are: + -> 9 calls to sqrt/sin/asin + -> 1 call to abs + -> 8 multiplications + -> 1 division + + Loses: + To compute a distance compatible with comparable::haversine<> + we need to perform a few more operations, namely: + -> 1 call to sin + -> 1 call to sqrt + -> 2 multiplications + -> 1 division + -> 1 addition + -> 2 subtractions + + So roughly speaking the net gain is: + -> 8 fewer function calls and 3 fewer arithmetic operations + + If we were to implement cross_track directly from the + comparable version (much like what haversine<> does using + comparable::haversine<>) we need additionally + -> 2 function calls (asin/sqrt) + -> 2 multiplications + + So it pays off to re-implement cross_track<> to use + comparable::cross_track<>; in this case the net gain would be: + -> 6 function calls + -> 1 arithmetic operation + + Summary/Conclusion + ------------------ + Following the mathematical and complexity analysis above, the + comparable cross track strategy (as implemented below) satisfies + all the goal mentioned in the beginning: + * It is more efficient than its non-comparable counter-part. + * Comparable distances using this new strategy can also be compared + with comparable distances computed with the comparable haversine + strategy. + * It turns out to be more efficient to compute the actual cross + track distance XTD by first computing CXTD, and then computing + XTD by means of the formula: + XTD = 2 * R * asin( sqrt(CXTD) ) */ + template < typename CalculationType = void, - typename Strategy = haversine<double, CalculationType> + typename Strategy = comparable::haversine<double, CalculationType> > class cross_track { @@ -106,6 +371,14 @@ public : typedef typename return_type<Point, PointOfSegment>::type return_type; +#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK + std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; + std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; + std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " " << crs_BD * geometry::math::r2d << std::endl; + std::cout << "Projection AD-AB " << projection1 << " : " << d_crs1 * geometry::math::r2d << std::endl; + std::cout << "Projection BD-BA " << projection2 << " : " << d_crs2 * geometry::math::r2d << std::endl; +#endif + // http://williams.best.vwh.net/avform.htm#XTE return_type d1 = m_strategy.apply(sp1, p); return_type d3 = m_strategy.apply(sp1, sp2); @@ -129,25 +402,34 @@ public : return_type projection1 = cos( d_crs1 ) * d1 / d3; return_type projection2 = cos( d_crs2 ) * d2 / d3; -#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK - std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; - std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; - std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " " << crs_BD * geometry::math::r2d << std::endl; - std::cout << "Projection AD-AB " << projection1 << " : " << d_crs1 * geometry::math::r2d << std::endl; - std::cout << "Projection BD-BA " << projection2 << " : " << d_crs2 * geometry::math::r2d << std::endl; -#endif - - if(projection1 > 0.0 && projection2 > 0.0) + if (projection1 > 0.0 && projection2 > 0.0) { - return_type XTD = radius() * geometry::math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) )); +#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK + return_type XTD = radius() * geometry::math::abs( asin( sin( d1 ) * sin( d_crs1 ) )); - #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Projection ON the segment" << std::endl; - std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; + std::cout << "XTD: " << XTD + << " d1: " << (d1 * radius()) + << " d2: " << (d2 * radius()) + << std::endl; #endif - - // Return shortest distance, projected point on segment sp1-sp2 - return return_type(XTD); + return_type const half(0.5); + return_type const quarter(0.25); + + return_type sin_d_crs1 = sin(d_crs1); + /* + This is the straightforward obvious way to continue: + + return_type discriminant + = 1.0 - 4.0 * (d1 - d1 * d1) * sin_d_crs1 * sin_d_crs1; + return 0.5 - 0.5 * math::sqrt(discriminant); + + Below we optimize the number of arithmetic operations + and account for numerical robustness: + */ + return_type d1_x_sin = d1 * sin_d_crs1; + return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin); + return d / (half + math::sqrt(quarter - d)); } else { @@ -164,6 +446,95 @@ public : { return m_strategy.radius(); } private : + Strategy m_strategy; +}; + +} // namespace comparable + + +/*! +\brief Strategy functor for distance point to segment calculation +\ingroup strategies +\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 CalculationType \tparam_calculation +\tparam Strategy underlying point-point distance strategy, defaults to haversine + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)] +} + +*/ +template +< + typename CalculationType = void, + typename Strategy = haversine<double, CalculationType> +> +class cross_track +{ +public : + template <typename Point, typename PointOfSegment> + struct return_type + : promote_floating_point + < + typename select_calculation_type + < + Point, + PointOfSegment, + CalculationType + >::type + > + {}; + + inline cross_track() + {} + + explicit inline cross_track(typename Strategy::radius_type const& r) + : m_strategy(r) + {} + + inline cross_track(Strategy const& s) + : m_strategy(s) + {} + + + // It might be useful in the future + // to overload constructor with strategy info. + // crosstrack(...) {} + + + 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; + typedef cross_track<CalculationType, Strategy> this_type; + + typedef typename services::comparable_type + < + this_type + >::type comparable_type; + + comparable_type cstrategy + = services::get_comparable<this_type>::apply(m_strategy); + + return_type const a = cstrategy.apply(p, sp1, sp2); + return_type const c = return_type(2.0) * asin(math::sqrt(a)); + return c * radius(); + } + + inline typename Strategy::radius_type radius() const + { return m_strategy.radius(); } + +private : Strategy m_strategy; }; @@ -190,8 +561,10 @@ struct return_type<cross_track<CalculationType, Strategy>, P, PS> template <typename CalculationType, typename Strategy> struct comparable_type<cross_track<CalculationType, Strategy> > { - // There is no shortcut, so the strategy itself is its comparable type - typedef cross_track<CalculationType, Strategy> type; + typedef comparable::cross_track + < + CalculationType, typename comparable_type<Strategy>::type + > type; }; @@ -207,7 +580,8 @@ struct get_comparable<cross_track<CalculationType, Strategy> > cross_track<CalculationType, Strategy> >::type comparable_type; public : - static inline comparable_type apply(cross_track<CalculationType, Strategy> const& strategy) + static inline comparable_type + apply(cross_track<CalculationType, Strategy> const& strategy) { return comparable_type(strategy.radius()); } @@ -218,21 +592,95 @@ template < typename CalculationType, typename Strategy, - typename P, typename PS + typename P, + typename PS > struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS> { private : - typedef typename cross_track<CalculationType, Strategy>::template return_type<P, PS> return_type; + typedef typename cross_track + < + CalculationType, Strategy + >::template return_type<P, PS>::type return_type; public : template <typename T> - static inline return_type apply(cross_track<CalculationType, Strategy> const& , T const& distance) + static inline return_type + apply(cross_track<CalculationType, Strategy> const& , T const& distance) { return distance; } }; +// Specializations for comparable::cross_track +template <typename RadiusType, typename CalculationType> +struct tag<comparable::cross_track<RadiusType, CalculationType> > +{ + typedef strategy_tag_distance_point_segment type; +}; + + +template +< + typename RadiusType, + typename CalculationType, + typename P, + typename PS +> +struct return_type<comparable::cross_track<RadiusType, CalculationType>, P, PS> + : comparable::cross_track + < + RadiusType, CalculationType + >::template return_type<P, PS> +{}; + + +template <typename RadiusType, typename CalculationType> +struct comparable_type<comparable::cross_track<RadiusType, CalculationType> > +{ + typedef comparable::cross_track<RadiusType, CalculationType> type; +}; + + +template <typename RadiusType, typename CalculationType> +struct get_comparable<comparable::cross_track<RadiusType, CalculationType> > +{ +private : + typedef comparable::cross_track<RadiusType, CalculationType> this_type; +public : + static inline this_type apply(this_type const& input) + { + return input; + } +}; + + +template +< + typename RadiusType, + typename CalculationType, + typename P, + typename PS +> +struct result_from_distance + < + comparable::cross_track<RadiusType, CalculationType>, P, PS + > +{ +private : + typedef comparable::cross_track<RadiusType, CalculationType> strategy_type; + typedef typename return_type<strategy_type, P, PS>::type return_type; +public : + template <typename T> + static inline return_type apply(strategy_type const& strategy, + T const& distance) + { + return_type const s + = sin( (distance / strategy.radius()) / return_type(2.0) ); + return s * s; + } +}; + /* @@ -309,17 +757,8 @@ struct default_strategy } // namespace services #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - }} // namespace strategy::distance - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - - -#endif - - }} // namespace boost::geometry - #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP diff --git a/boost/geometry/strategies/spherical/distance_haversine.hpp b/boost/geometry/strategies/spherical/distance_haversine.hpp index 8db29c5157..8b32056f3e 100644 --- a/boost/geometry/strategies/spherical/distance_haversine.hpp +++ b/boost/geometry/strategies/spherical/distance_haversine.hpp @@ -158,7 +158,7 @@ public : 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(math::sqrt(a)); - return m_radius * c; + return calculation_type(m_radius) * c; } /*! diff --git a/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/boost/geometry/strategies/spherical/side_by_cross_track.hpp index c4c5f24eeb..3f7be05557 100644 --- a/boost/geometry/strategies/spherical/side_by_cross_track.hpp +++ b/boost/geometry/strategies/spherical/side_by_cross_track.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) @@ -9,18 +14,15 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP -#include <boost/mpl/if.hpp> -#include <boost/type_traits.hpp> -#include <boost/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> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> #include <boost/geometry/strategies/side.hpp> //#include <boost/geometry/strategies/concepts/side_concept.hpp> @@ -47,27 +49,19 @@ public : template <typename P1, typename P2, typename P> static inline int apply(P1 const& p1, P2 const& p2, P const& p) { - typedef typename boost::mpl::if_c + typedef typename promote_floating_point < - boost::is_void<CalculationType>::type::value, - typename select_most_precise + typename select_calculation_type_alt < - typename select_most_precise - < - typename coordinate_type<P1>::type, - typename coordinate_type<P2>::type - >::type, - typename coordinate_type<P>::type - >::type, - CalculationType - >::type coordinate_type; - - boost::ignore_unused<coordinate_type>(); - - double d1 = 0.001; // m_strategy.apply(sp1, p); - 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)); + CalculationType, + P1, P2, P + >::type + >::type calc_t; + + calc_t d1 = 0.001; // m_strategy.apply(sp1, p); + calc_t crs_AD = geometry::detail::course<calc_t>(p1, p); + calc_t crs_AB = geometry::detail::course<calc_t>(p1, p2); + calc_t 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 41562950fd..81f3205e90 100644 --- a/boost/geometry/strategies/spherical/ssf.hpp +++ b/boost/geometry/strategies/spherical/ssf.hpp @@ -16,8 +16,9 @@ #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> -#include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> #include <boost/geometry/strategies/side.hpp> //#include <boost/geometry/strategies/concepts/side_concept.hpp> @@ -30,6 +31,43 @@ namespace boost { namespace geometry namespace strategy { namespace side { +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename T> +int spherical_side_formula(T const& lambda1, T const& delta1, + T const& lambda2, T const& delta2, + T const& lambda, T const& delta) +{ + // Create temporary points (vectors) on unit a sphere + T const cos_delta1 = cos(delta1); + T const c1x = cos_delta1 * cos(lambda1); + T const c1y = cos_delta1 * sin(lambda1); + T const c1z = sin(delta1); + + T const cos_delta2 = cos(delta2); + T const c2x = cos_delta2 * cos(lambda2); + T const c2y = cos_delta2 * sin(lambda2); + T const c2z = sin(delta2); + + // (Third point is converted directly) + T const cos_delta = cos(delta); + + // Apply the "Spherical Side Formula" as presented on my blog + T const dist + = (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda) + + (c1z * c2x - c1x * c2z) * cos_delta * sin(lambda) + + (c1x * c2y - c1y * c2x) * sin(delta); + + T zero = T(); + return dist > zero ? 1 + : dist < zero ? -1 + : 0; +} + +} +#endif // DOXYGEN_NO_DETAIL /*! \brief Check at which side of a Great Circle segment a point lies @@ -45,60 +83,25 @@ public : template <typename P1, typename P2, typename P> static inline int apply(P1 const& p1, P2 const& p2, P const& p) { - typedef typename boost::mpl::if_c + typedef typename promote_floating_point < - boost::is_void<CalculationType>::type::value, - - // Select at least a double... - typename select_most_precise + typename select_calculation_type_alt < - typename select_most_precise - < - typename select_most_precise - < - typename coordinate_type<P1>::type, - typename coordinate_type<P2>::type - >::type, - typename coordinate_type<P>::type - >::type, - double - >::type, - CalculationType - >::type coordinate_type; - - // Convenient shortcuts - typedef coordinate_type ct; - ct const lambda1 = get_as_radian<0>(p1); - ct const delta1 = get_as_radian<1>(p1); - ct const lambda2 = get_as_radian<0>(p2); - ct const delta2 = get_as_radian<1>(p2); - ct const lambda = get_as_radian<0>(p); - ct const delta = get_as_radian<1>(p); - - // Create temporary points (vectors) on unit a sphere - ct const cos_delta1 = cos(delta1); - ct const c1x = cos_delta1 * cos(lambda1); - ct const c1y = cos_delta1 * sin(lambda1); - ct const c1z = sin(delta1); - - ct const cos_delta2 = cos(delta2); - ct const c2x = cos_delta2 * cos(lambda2); - ct const c2y = cos_delta2 * sin(lambda2); - ct const c2z = sin(delta2); - - // (Third point is converted directly) - ct const cos_delta = cos(delta); - - // Apply the "Spherical Side Formula" as presented on my blog - ct const dist - = (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda) - + (c1z * c2x - c1x * c2z) * cos_delta * sin(lambda) - + (c1x * c2y - c1y * c2x) * sin(delta); - - ct zero = ct(); - return dist > zero ? 1 - : dist < zero ? -1 - : 0; + CalculationType, + P1, P2, P + >::type + >::type calculation_type; + + calculation_type const lambda1 = get_as_radian<0>(p1); + calculation_type const delta1 = get_as_radian<1>(p1); + calculation_type const lambda2 = get_as_radian<0>(p2); + calculation_type const delta2 = get_as_radian<1>(p2); + calculation_type const lambda = get_as_radian<0>(p); + calculation_type const delta = get_as_radian<1>(p); + + return detail::spherical_side_formula(lambda1, delta1, + lambda2, delta2, + lambda, delta); } }; diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp index afc5d7046f..bf436dba2b 100644 --- a/boost/geometry/strategies/strategies.hpp +++ b/boost/geometry/strategies/strategies.hpp @@ -63,6 +63,9 @@ #include <boost/geometry/strategies/spherical/compare_circular.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> +#include <boost/geometry/strategies/geographic/distance_andoyer.hpp> +#include <boost/geometry/strategies/geographic/distance_vincenty.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> diff --git a/boost/geometry/util/combine_if.hpp b/boost/geometry/util/combine_if.hpp index 6d8d932a1c..cfc3449267 100644 --- a/boost/geometry/util/combine_if.hpp +++ b/boost/geometry/util/combine_if.hpp @@ -1,6 +1,11 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014 Samuel Debionne, Grenoble, France. +// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -36,16 +41,16 @@ namespace util \ingroup utility \par Example \code - typedef mpl::vector<mpl::int_<0>, mpl::int_<1> > types; + typedef boost::mpl::vector<boost::mpl::int_<0>, boost::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> > + typedef boost::mpl::vector< + pair<boost::mpl::int_<1>, boost::mpl::int_<1> >, + pair<boost::mpl::int_<1>, boost::mpl::int_<0> >, + pair<boost::mpl::int_<0>, boost::mpl::int_<1> >, + pair<boost::mpl::int_<0>, boost::mpl::int_<0> > > result_types; - BOOST_MPL_ASSERT(( mpl::equal<combinations, result_types> )); + BOOST_MPL_ASSERT(( boost::mpl::equal<combinations, result_types> )); \endcode */ template <typename Sequence1, typename Sequence2, typename Pred> @@ -56,18 +61,29 @@ struct combine_if template <typename Result, typename T> struct apply { - typedef typename mpl::fold<Sequence2, Result, - mpl::if_ + typedef typename boost::mpl::fold<Sequence2, Result, + boost::mpl::if_ < - mpl::bind<typename mpl::lambda<Pred>::type, T, mpl::_2>, - mpl::insert<mpl::_1, mpl::pair<T, mpl::_2> >, - mpl::_1 + boost::mpl::bind + < + typename boost::mpl::lambda<Pred>::type, + T, + boost::mpl::_2 + >, + boost::mpl::insert + < + boost::mpl::_1, boost::mpl::pair<T, boost::mpl::_2> + >, + boost::mpl::_1 > >::type type; }; }; - typedef typename mpl::fold<Sequence1, mpl::set0<>, combine>::type type; + typedef typename boost::mpl::fold + < + Sequence1, boost::mpl::set0<>, combine + >::type type; }; diff --git a/boost/geometry/util/compress_variant.hpp b/boost/geometry/util/compress_variant.hpp index a94cf28894..363385965d 100644 --- a/boost/geometry/util/compress_variant.hpp +++ b/boost/geometry/util/compress_variant.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -36,28 +41,31 @@ namespace detail template <typename Variant> struct unique_types: - mpl::fold< - typename mpl::reverse_fold< + boost::mpl::fold< + typename boost::mpl::reverse_fold< typename Variant::types, - mpl::set<>, - mpl::insert< - mpl::placeholders::_1, - mpl::placeholders::_2 + boost::mpl::set<>, + boost::mpl::insert< + boost::mpl::placeholders::_1, + boost::mpl::placeholders::_2 > >::type, - mpl::vector<>, - mpl::push_back<mpl::placeholders::_1, mpl::placeholders::_2> + boost::mpl::vector<>, + boost::mpl::push_back + < + boost::mpl::placeholders::_1, boost::mpl::placeholders::_2 + > > {}; template <typename Types> struct variant_or_single: - mpl::if_< - mpl::equal_to< - mpl::size<Types>, - mpl::int_<1> + boost::mpl::if_< + boost::mpl::equal_to< + boost::mpl::size<Types>, + boost::mpl::int_<1> >, - typename mpl::front<Types>::type, + typename boost::mpl::front<Types>::type, typename make_variant_over<Types>::type > {}; @@ -75,8 +83,8 @@ struct variant_or_single: \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 boost::mpl::vector<int, float, long> result_types; + BOOST_MPL_ASSERT(( boost::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; diff --git a/boost/geometry/util/condition.hpp b/boost/geometry/util/condition.hpp new file mode 100644 index 0000000000..aea4ad3ad1 --- /dev/null +++ b/boost/geometry/util/condition.hpp @@ -0,0 +1,44 @@ +// Boost.Geometry + +// Copyright (c) 2015 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_UTIL_CONDITION_HPP +#define BOOST_GEOMETRY_UTIL_CONDITION_HPP + + +#include <boost/config.hpp> + + +// The macro defined in this file allows to suppress the MSVC +// compiler warning C4127: conditional expression is constant + +#ifdef BOOST_MSVC + +// NOTE: The code commented out below contains an alternative implementation +// of a macro using a free function. It was left here in case if in the future +// version of MSVC for the code currently used in the macro implementation +// the warning was generated. + +//#ifndef DOXYGEN_NO_DETAIL +//namespace boost { namespace geometry { namespace detail { +//BOOST_FORCEINLINE bool condition(bool const b) { return b; } +//}}} // boost::geometry::detail +//#endif // DOXYGEN_NO_DETAIL +//#define BOOST_GEOMETRY_CONDITION(CONDITION) boost::geometry::detail::condition(CONDITION) + +#define BOOST_GEOMETRY_CONDITION(CONDITION) ((void)0, (CONDITION)) + +#else + +#define BOOST_GEOMETRY_CONDITION(CONDITION) (CONDITION) + +#endif + + +#endif // BOOST_GEOMETRY_UTIL_CONDITION_HPP diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp index 22c02168ad..4042f4e4cd 100644 --- a/boost/geometry/util/math.hpp +++ b/boost/geometry/util/math.hpp @@ -1,11 +1,11 @@ // 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) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015. +// Modifications copyright (c) 2014-2015, 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 @@ -23,7 +23,12 @@ #include <cmath> #include <limits> +#include <boost/core/ignore_unused.hpp> + #include <boost/math/constants/constants.hpp> +#ifdef BOOST_GEOMETRY_SQRT_CHECK_FINITENESS +#include <boost/math/special_functions/fpclassify.hpp> +#endif // BOOST_GEOMETRY_SQRT_CHECK_FINITENESS #include <boost/math/special_functions/round.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/type_traits/is_fundamental.hpp> @@ -40,11 +45,104 @@ namespace math namespace detail { +template <typename T> +inline T const& greatest(T const& v1, T const& v2) +{ + return (std::max)(v1, v2); +} + +template <typename T> +inline T const& greatest(T const& v1, T const& v2, T const& v3) +{ + return (std::max)(greatest(v1, v2), v3); +} + +template <typename T> +inline T const& greatest(T const& v1, T const& v2, T const& v3, T const& v4) +{ + return (std::max)(greatest(v1, v2, v3), v4); +} + +template <typename T> +inline T const& greatest(T const& v1, T const& v2, T const& v3, T const& v4, T const& v5) +{ + return (std::max)(greatest(v1, v2, v3, v4), v5); +} + + +template <typename T, + bool IsFloatingPoint = boost::is_floating_point<T>::value> +struct abs +{ + static inline T apply(T const& value) + { + T const zero = T(); + return value < zero ? -value : value; + } +}; + +template <typename T> +struct abs<T, true> +{ + static inline T apply(T const& value) + { + return fabs(value); + } +}; + + +struct equals_default_policy +{ + template <typename T> + static inline T apply(T const& a, T const& b) + { + // See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17 + return greatest(abs<T>::apply(a), abs<T>::apply(b), T(1)); + } +}; + +template <typename T, + bool IsFloatingPoint = boost::is_floating_point<T>::value> +struct equals_factor_policy +{ + equals_factor_policy() + : factor(1) {} + explicit equals_factor_policy(T const& v) + : factor(greatest(abs<T>::apply(v), T(1))) + {} + equals_factor_policy(T const& v0, T const& v1, T const& v2, T const& v3) + : factor(greatest(abs<T>::apply(v0), abs<T>::apply(v1), + abs<T>::apply(v2), abs<T>::apply(v3), + T(1))) + {} + + T const& apply(T const&, T const&) const + { + return factor; + } + + T factor; +}; + +template <typename T> +struct equals_factor_policy<T, false> +{ + equals_factor_policy() {} + explicit equals_factor_policy(T const&) {} + equals_factor_policy(T const& , T const& , T const& , T const& ) {} + + static inline T apply(T const&, T const&) + { + return T(1); + } +}; -template <typename Type, bool IsFloatingPoint> +template <typename Type, + bool IsFloatingPoint = boost::is_floating_point<Type>::value> struct equals { - static inline bool apply(Type const& a, Type const& b) + template <typename Policy> + static inline bool apply(Type const& a, Type const& b, Policy const&) { return a == b; } @@ -53,25 +151,31 @@ struct equals template <typename Type> struct equals<Type, true> { - static inline Type get_max(Type const& a, Type const& b, Type const& c) + template <typename Policy> + static inline bool apply(Type const& a, Type const& b, Policy const& policy) { - return (std::max)((std::max)(a, b), c); - } + boost::ignore_unused(policy); - static inline bool apply(Type const& a, Type const& b) - { if (a == b) { return true; } - // See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17, - // FUTURE: replace by some boost tool or boost::test::close_at_tolerance - return std::abs(a - b) <= std::numeric_limits<Type>::epsilon() * get_max(std::abs(a), std::abs(b), 1.0); + return abs<Type>::apply(a - b) <= std::numeric_limits<Type>::epsilon() * policy.apply(a, b); } }; -template <typename Type, bool IsFloatingPoint> +template <typename T1, typename T2, typename Policy> +inline bool equals_by_policy(T1 const& a, T2 const& b, Policy const& policy) +{ + return detail::equals + < + typename select_most_precise<T1, T2>::type + >::apply(a, b, policy); +} + +template <typename Type, + bool IsFloatingPoint = boost::is_floating_point<Type>::value> struct smaller { static inline bool apply(Type const& a, Type const& b) @@ -85,7 +189,7 @@ struct smaller<Type, true> { static inline bool apply(Type const& a, Type const& b) { - if (equals<Type, true>::apply(a, b)) + if (equals<Type, true>::apply(a, b, equals_default_policy())) { return false; } @@ -94,8 +198,11 @@ struct smaller<Type, true> }; -template <typename Type, bool IsFloatingPoint> -struct equals_with_epsilon : public equals<Type, IsFloatingPoint> {}; +template <typename Type, + bool IsFloatingPoint = boost::is_floating_point<Type>::value> +struct equals_with_epsilon + : public equals<Type, IsFloatingPoint> +{}; template < @@ -120,28 +227,52 @@ struct square_root } }; -template <> -struct square_root<float, true> +template <typename FundamentalFP> +struct square_root_for_fundamental_fp { - typedef float return_type; + typedef FundamentalFP return_type; - static inline float apply(float const& value) + static inline FundamentalFP apply(FundamentalFP const& value) { - // for float use std::sqrt +#ifdef BOOST_GEOMETRY_SQRT_CHECK_FINITENESS + // This is a workaround for some 32-bit platforms. + // For some of those platforms it has been reported that + // std::sqrt(nan) and/or std::sqrt(-nan) returns a finite value. + // For those platforms we need to define the macro + // BOOST_GEOMETRY_SQRT_CHECK_FINITENESS so that the argument + // to std::sqrt is checked appropriately before passed to std::sqrt + if (boost::math::isfinite(value)) + { + return std::sqrt(value); + } + else if (boost::math::isinf(value) && value < 0) + { + return -std::numeric_limits<FundamentalFP>::quiet_NaN(); + } + return value; +#else + // for fundamental floating point numbers use std::sqrt return std::sqrt(value); +#endif // BOOST_GEOMETRY_SQRT_CHECK_FINITENESS } }; template <> -struct square_root<long double, true> +struct square_root<float, true> + : square_root_for_fundamental_fp<float> { - 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 <> +struct square_root<double, true> + : square_root_for_fundamental_fp<double> +{ +}; + +template <> +struct square_root<long double, true> + : square_root_for_fundamental_fp<long double> +{ }; template <typename T> @@ -156,7 +287,10 @@ struct square_root<T, true> // 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)); + return square_root_for_fundamental_fp + < + double + >::apply(boost::numeric_cast<double>(value)); } }; @@ -240,44 +374,36 @@ inline T relaxed_epsilon(T const& factor) template <typename T1, typename T2> inline bool equals(T1 const& a, T2 const& b) { - typedef typename select_most_precise<T1, T2>::type select_type; return detail::equals < - select_type, - boost::is_floating_point<select_type>::type::value - >::apply(a, b); + typename select_most_precise<T1, T2>::type + >::apply(a, b, detail::equals_default_policy()); } template <typename T1, typename T2> inline bool equals_with_epsilon(T1 const& a, T2 const& b) { - typedef typename select_most_precise<T1, T2>::type select_type; return detail::equals_with_epsilon < - select_type, - boost::is_floating_point<select_type>::type::value - >::apply(a, b); + typename select_most_precise<T1, T2>::type + >::apply(a, b, detail::equals_default_policy()); } template <typename T1, typename T2> inline bool smaller(T1 const& a, T2 const& b) { - typedef typename select_most_precise<T1, T2>::type select_type; return detail::smaller < - select_type, - boost::is_floating_point<select_type>::type::value + typename select_most_precise<T1, T2>::type >::apply(a, b); } template <typename T1, typename T2> inline bool larger(T1 const& a, T2 const& b) { - typedef typename select_most_precise<T1, T2>::type select_type; return detail::smaller < - select_type, - boost::is_floating_point<select_type>::type::value + typename select_most_precise<T1, T2>::type >::apply(b, a); } @@ -336,8 +462,7 @@ sqrt(T const& value) template<typename T> inline T abs(T const& value) { - T const zero = T(); - return value < zero ? -value : value; + return detail::abs<T>::apply(value); } /*! @@ -356,12 +481,11 @@ static inline int sign(T const& value) \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. + 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); } diff --git a/boost/geometry/util/promote_integral.hpp b/boost/geometry/util/promote_integral.hpp new file mode 100644 index 0000000000..6b23403be3 --- /dev/null +++ b/boost/geometry/util/promote_integral.hpp @@ -0,0 +1,318 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, 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_UTIL_PROMOTE_INTEGRAL_HPP +#define BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP + +// For now deactivate the use of multiprecision integers +// TODO: activate it later +#define BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER + +#include <climits> +#include <cstddef> + +#include <boost/mpl/begin.hpp> +#include <boost/mpl/deref.hpp> +#include <boost/mpl/end.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/list.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/size_t.hpp> + +#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) +#include <boost/multiprecision/cpp_int.hpp> +#endif + +#include <boost/type_traits/integral_constant.hpp> +#include <boost/type_traits/is_fundamental.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_unsigned.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace promote_integral +{ + +// meta-function that returns the bit size of a type +template +< + typename T, + bool IsFundamental = boost::is_fundamental<T>::type::value +> +struct bit_size +{}; + + +// for fundamental types, just return CHAR_BIT * sizeof(T) +template <typename T> +struct bit_size<T, true> + : boost::mpl::size_t<(CHAR_BIT * sizeof(T))> +{}; + + +#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) +// partial specialization for cpp_int +template +< + unsigned MinSize, + unsigned MaxSize, + boost::multiprecision::cpp_integer_type SignType, + boost::multiprecision::cpp_int_check_type Checked, + typename Allocator, + boost::multiprecision::expression_template_option ExpressionTemplates +> +struct bit_size + < + boost::multiprecision::number + < + boost::multiprecision::cpp_int_backend + < + MinSize, MaxSize, SignType, Checked, Allocator + >, + ExpressionTemplates + >, + false + > : boost::mpl::size_t<MaxSize> +{}; +#endif // BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER + + +template +< + typename T, + typename Iterator, + typename EndIterator, + std::size_t MinSize +> +struct promote_to_larger +{ + typedef typename boost::mpl::deref<Iterator>::type current_type; + + typedef typename boost::mpl::if_c + < + (bit_size<current_type>::type::value >= MinSize), + current_type, + typename promote_to_larger + < + T, + typename boost::mpl::next<Iterator>::type, + EndIterator, + MinSize + >::type + >::type type; +}; + +// The following specialization is required to finish the loop over +// all list elements +template <typename T, typename EndIterator, std::size_t MinSize> +struct promote_to_larger<T, EndIterator, EndIterator, MinSize> +{ + // if promotion fails, keep the number T + // (and cross fingers that overflow will not occur) + typedef T type; +}; + +}} // namespace detail::promote_integral +#endif // DOXYGEN_NO_DETAIL + + + +/*! + \brief Meta-function to define an integral type with size + than is (roughly) twice the bit size of T + \ingroup utility + \details + This meta-function tries to promote the fundamental integral type T + to a another integral type with size (roughly) twice the bit size of T. + + To do this, two times the bit size of T is tested against the bit sizes of: + short, int, long, boost::long_long_type, boost::int128_t + and the one that first matches is chosen. + + For unsigned types the bit size of T is tested against the bit + sizes of the types above, if T is promoted to a signed type, or + the bit sizes of + unsigned short, unsigned int, unsigned long, std::size_t, + boost::ulong_long_type, boost::uint128_t + if T is promoted to an unsigned type. + + By default an unsigned type is promoted to a signed type. + This behavior is controlled by the PromoteUnsignedToUnsigned + boolean template parameter, whose default value is "false". + To promote an unsigned type to an unsigned type set the value of + this template parameter to "true". + + If the macro BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is not + defined, boost's multiprecision integer cpp_int<> is used as a + last resort. + + If BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is defined and an + appropriate type cannot be detected, the input type is returned as is. + + Finally, if the passed type is either a floating-point type or a + user-defined type it is returned as is. + + \note boost::long_long_type and boost::ulong_long_type are + considered only if the macro BOOST_HAS_LONG_LONG is defined + + \note boost::int128_type and boost::uint128_type are considered + only if the macros BOOST_HAS_INT128 and BOOST_GEOMETRY_ENABLE_INT128 + are defined +*/ +template +< + typename T, + bool PromoteUnsignedToUnsigned = false, + bool UseCheckedInteger = false, + bool IsIntegral = boost::is_integral<T>::type::value +> +class promote_integral +{ +private: + static bool const is_unsigned = boost::is_unsigned<T>::type::value; + + typedef detail::promote_integral::bit_size<T> bit_size_type; + +#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) + // Define the proper check policy for the multiprecision integer + typedef typename boost::mpl::if_c + < + UseCheckedInteger, + boost::integral_constant + < + boost::multiprecision::cpp_int_check_type, + boost::multiprecision::checked + >, + boost::integral_constant + < + boost::multiprecision::cpp_int_check_type, + boost::multiprecision::unchecked + > + >::type check_policy_type; + + // Meta-function to get the multiprecision integer type for the + // given size and sign type (signed/unsigned) + template + < + unsigned int Size, + boost::multiprecision::cpp_integer_type SignType + > + struct multiprecision_integer_type + { + typedef boost::multiprecision::number + < + boost::multiprecision::cpp_int_backend + < + Size, + Size, + SignType, + check_policy_type::value, + void + > + > type; + }; +#endif + + // Define the minimum size (in bits) needed for the promoted type + // If T is the input type and P the promoted type, then the + // minimum number of bits for P are (below b stands for the number + // of bits of T): + // * if T is unsigned and P is unsigned: 2 * b + // * if T is signed and P is signed: 2 * b - 1 + // * if T is unsigned and P is signed: 2 * b + 1 + typedef typename boost::mpl::if_c + < + (PromoteUnsignedToUnsigned && is_unsigned), + boost::mpl::size_t<(2 * bit_size_type::value)>, + typename boost::mpl::if_c + < + is_unsigned, + boost::mpl::size_t<(2 * bit_size_type::value + 1)>, + boost::mpl::size_t<(2 * bit_size_type::value - 1)> + >::type + >::type min_bit_size_type; + + // Define the list of signed integral types we are going to use + // for promotion + typedef boost::mpl::list + < + short, int, long +#if defined(BOOST_HAS_LONG_LONG) + , boost::long_long_type +#endif +#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) + , boost::int128_type +#endif +#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) + , typename multiprecision_integer_type + < + min_bit_size_type::value, + boost::multiprecision::signed_magnitude + >::type +#endif + > signed_integral_types; + + // Define the list of unsigned integral types we are going to use + // for promotion + typedef boost::mpl::list + < + unsigned short, unsigned int, unsigned long, std::size_t +#if defined(BOOST_HAS_LONG_LONG) + , boost::ulong_long_type +#endif +#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) + , boost::uint128_type +#endif +#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) + , typename multiprecision_integer_type + < + min_bit_size_type::value, + boost::multiprecision::unsigned_magnitude + >::type +#endif + > unsigned_integral_types; + + // Define the list of integral types that will be used for + // promotion (depending in whether we was to promote unsigned to + // unsigned or not) + typedef typename boost::mpl::if_c + < + (is_unsigned && PromoteUnsignedToUnsigned), + unsigned_integral_types, + signed_integral_types + >::type integral_types; + +public: + typedef typename detail::promote_integral::promote_to_larger + < + T, + typename boost::mpl::begin<integral_types>::type, + typename boost::mpl::end<integral_types>::type, + min_bit_size_type::value + >::type type; +}; + + +template <typename T, bool PromoteUnsignedToUnsigned, bool UseCheckedInteger> +class promote_integral + < + T, PromoteUnsignedToUnsigned, UseCheckedInteger, false + > +{ +public: + typedef T type; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP diff --git a/boost/geometry/util/range.hpp b/boost/geometry/util/range.hpp index fe3502f978..cf69413411 100644 --- a/boost/geometry/util/range.hpp +++ b/boost/geometry/util/range.hpp @@ -2,15 +2,15 @@ // 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. +// This file was modified by Oracle on 2013, 2014, 2015. +// Modifications copyright (c) 2013-2015 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) -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - #ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP #define BOOST_GEOMETRY_UTIL_RANGE_HPP @@ -30,20 +30,63 @@ namespace boost { namespace geometry { namespace range { -// NOTE: For SinglePassRanges at could iterate over all elements until the i-th element is met. +namespace detail { + +// NOTE: For SinglePassRanges pos could iterate over all elements until the i-th element was met. + +template <typename RandomAccessRange> +struct pos +{ + typedef typename boost::range_iterator<RandomAccessRange>::type iterator; + typedef typename boost::range_size<RandomAccessRange>::type size_type; + typedef typename boost::range_difference<RandomAccessRange>::type difference_type; + + static inline iterator apply(RandomAccessRange & rng, size_type i) + { + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<RandomAccessRange> )); + return boost::begin(rng) + static_cast<difference_type>(i); + } +}; + +} // namespace detail + +/*! +\brief Short utility to conveniently return an iterator of a RandomAccessRange. +\ingroup utility +*/ +template <typename RandomAccessRange> +inline typename boost::range_iterator<RandomAccessRange const>::type +pos(RandomAccessRange const& rng, + typename boost::range_size<RandomAccessRange const>::type i) +{ + BOOST_ASSERT(i <= boost::size(rng)); + return detail::pos<RandomAccessRange const>::apply(rng, i); +} + +/*! +\brief Short utility to conveniently return an iterator of a RandomAccessRange. +\ingroup utility +*/ +template <typename RandomAccessRange> +inline typename boost::range_iterator<RandomAccessRange>::type +pos(RandomAccessRange & rng, + typename boost::range_size<RandomAccessRange>::type i) +{ + BOOST_ASSERT(i <= boost::size(rng)); + return detail::pos<RandomAccessRange>::apply(rng, i); +} /*! \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& +inline typename boost::range_reference<RandomAccessRange const>::type 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); + return * detail::pos<RandomAccessRange const>::apply(rng, i); } /*! @@ -51,13 +94,12 @@ at(RandomAccessRange const& rng, \ingroup utility */ template <typename RandomAccessRange> -inline typename boost::range_value<RandomAccessRange>::type & +inline typename boost::range_reference<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); + return * detail::pos<RandomAccessRange>::apply(rng, i); } /*! @@ -65,7 +107,7 @@ at(RandomAccessRange & rng, \ingroup utility */ template <typename Range> -inline typename boost::range_value<Range>::type const& +inline typename boost::range_reference<Range const>::type front(Range const& rng) { BOOST_ASSERT(!boost::empty(rng)); @@ -77,7 +119,7 @@ front(Range const& rng) \ingroup utility */ template <typename Range> -inline typename boost::range_value<Range>::type & +inline typename boost::range_reference<Range>::type front(Range & rng) { BOOST_ASSERT(!boost::empty(rng)); @@ -91,12 +133,12 @@ front(Range & rng) \ingroup utility */ template <typename BidirectionalRange> -inline typename boost::range_value<BidirectionalRange>::type const& +inline typename boost::range_reference<BidirectionalRange const>::type back(BidirectionalRange const& rng) { BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange const> )); BOOST_ASSERT(!boost::empty(rng)); - return *(--boost::end(rng)); + return *(boost::rbegin(rng)); } /*! @@ -104,12 +146,12 @@ back(BidirectionalRange const& rng) \ingroup utility */ template <typename BidirectionalRange> -inline typename boost::range_value<BidirectionalRange>::type & +inline typename boost::range_reference<BidirectionalRange>::type back(BidirectionalRange & rng) { - BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange> )); + BOOST_RANGE_CONCEPT_ASSERT((boost::BidirectionalRangeConcept<BidirectionalRange>)); BOOST_ASSERT(!boost::empty(rng)); - return *(--boost::end(rng)); + return *(boost::rbegin(rng)); } diff --git a/boost/geometry/util/select_calculation_type.hpp b/boost/geometry/util/select_calculation_type.hpp index 4946c45e84..0e3faf229b 100644 --- a/boost/geometry/util/select_calculation_type.hpp +++ b/boost/geometry/util/select_calculation_type.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. @@ -50,6 +55,28 @@ struct select_calculation_type >::type type; }; +// alternative version supporting more than 2 Geometries + +template <typename CalculationType, + typename Geometry1, + typename Geometry2 = void, + typename Geometry3 = void> +struct select_calculation_type_alt +{ + typedef typename + boost::mpl::if_ + < + boost::is_void<CalculationType>, + typename select_coordinate_type + < + Geometry1, + Geometry2, + Geometry3 + >::type, + CalculationType + >::type type; +}; + }} // namespace boost::geometry diff --git a/boost/geometry/util/select_coordinate_type.hpp b/boost/geometry/util/select_coordinate_type.hpp index 8309da42b7..12a6b72a73 100644 --- a/boost/geometry/util/select_coordinate_type.hpp +++ b/boost/geometry/util/select_coordinate_type.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. @@ -28,16 +33,35 @@ namespace boost { namespace geometry of two geometries \ingroup utility */ -template <typename T1, typename T2> +template <typename T1, typename T2 = void, typename T3 = void> struct select_coordinate_type { typedef typename select_most_precise < typename coordinate_type<T1>::type, + typename coordinate_type<T2>::type, + typename coordinate_type<T3>::type + >::type type; +}; + +template <typename T1, typename T2> +struct select_coordinate_type<T1, T2, void> +{ + typedef typename select_most_precise + < + typename coordinate_type<T1>::type, typename coordinate_type<T2>::type >::type type; }; +template <typename T1> +struct select_coordinate_type<T1, void, void> +{ + typedef typename select_most_precise + < + typename coordinate_type<T1>::type + >::type type; +}; }} // namespace boost::geometry diff --git a/boost/geometry/util/select_most_precise.hpp b/boost/geometry/util/select_most_precise.hpp index d55fdbfd98..b5b1388cf8 100644 --- a/boost/geometry/util/select_most_precise.hpp +++ b/boost/geometry/util/select_most_precise.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. @@ -113,9 +118,19 @@ struct select_floating_point<false, true, T1, T2> \note If both types are non-fundamental, the result is indeterminate and currently the first one is chosen. */ -template <typename T1, typename T2> +template <typename T1, typename T2 = void, typename T3 = void> struct select_most_precise { + typedef typename select_most_precise + < + typename select_most_precise<T1, T2>::type, + T3 + >::type type; +}; + +template <typename T1, typename T2> +struct select_most_precise<T1, T2, void> +{ static const bool second_larger = sizeof(T2) > sizeof(T1); static const bool one_not_fundamental = ! (boost::is_fundamental<T1>::type::value @@ -155,7 +170,11 @@ struct select_most_precise >::type type; }; - +template <typename T1> +struct select_most_precise<T1, void, void> +{ + typedef T1 type; +}; }} // namespace boost::geometry diff --git a/boost/geometry/util/transform_variant.hpp b/boost/geometry/util/transform_variant.hpp index 9e4a7aa152..f0836bcbf2 100644 --- a/boost/geometry/util/transform_variant.hpp +++ b/boost/geometry/util/transform_variant.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-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, 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. @@ -31,7 +36,7 @@ namespace boost { namespace geometry \ingroup utility \par Example \code - typedef mpl::vector<int, float, long> types; + typedef boost::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> )); @@ -40,7 +45,7 @@ namespace boost { namespace geometry template <typename Sequence, typename Op, typename In = boost::mpl::na> struct transform_variant: make_variant_over< - typename mpl::transform< + typename boost::mpl::transform< Sequence, Op, In @@ -65,7 +70,7 @@ struct transform_variant: 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 boost::mpl::transform< typename variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types, Op >::type diff --git a/boost/geometry/views/detail/normalized_view.hpp b/boost/geometry/views/detail/normalized_view.hpp index d50ffe48c8..1e9cda9ce2 100644 --- a/boost/geometry/views/detail/normalized_view.hpp +++ b/boost/geometry/views/detail/normalized_view.hpp @@ -28,6 +28,7 @@ #include <boost/geometry/views/detail/range_type.hpp> #include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/util/order_as_direction.hpp> namespace boost { namespace geometry { |