diff options
Diffstat (limited to 'boost/geometry')
166 files changed, 11108 insertions, 3400 deletions
diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp index 4751d4e742..18aea24036 100644 --- a/boost/geometry/algorithms/area.hpp +++ b/boost/geometry/algorithms/area.hpp @@ -4,6 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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. @@ -303,7 +307,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr [heading Available Strategies] \* [link geometry.reference.strategies.strategy_area_surveyor Surveyor (cartesian)] -\* [link geometry.reference.strategies.strategy_area_huiller Huiller (spherical)] +\* [link geometry.reference.strategies.strategy_area_spherical Spherical] +[/link geometry.reference.strategies.strategy_area_geographic Geographic] } */ template <typename Geometry, typename Strategy> diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp index e1d3c20e44..fd6f0fbe6a 100644 --- a/boost/geometry/algorithms/buffer.hpp +++ b/boost/geometry/algorithms/buffer.hpp @@ -4,6 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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. @@ -274,6 +278,11 @@ inline void buffer(GeometryIn const& geometry_in, geometry::envelope(geometry_in, box); geometry::buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy)); + typename strategy::intersection::services::default_strategy + < + typename cs_tag<GeometryIn>::type + >::type intersection_strategy; + rescale_policy_type rescale_policy = boost::geometry::get_rescale_policy<rescale_policy_type>(box); @@ -283,6 +292,7 @@ inline void buffer(GeometryIn const& geometry_in, join_strategy, end_strategy, point_strategy, + intersection_strategy, rescale_policy); } diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp index fc2908ab1c..6a58033f37 100644 --- a/boost/geometry/algorithms/centroid.hpp +++ b/boost/geometry/algorithms/centroid.hpp @@ -3,7 +3,7 @@ // 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. +// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2015. // Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. @@ -26,6 +26,7 @@ #include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> +#include <boost/throw_exception.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> @@ -183,7 +184,7 @@ inline bool range_ok(Range const& range, Point& centroid) else if (n <= 0) { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) - throw centroid_exception(); + BOOST_THROW_EXCEPTION(centroid_exception()); #else return false; #endif @@ -366,7 +367,7 @@ struct centroid_multi // to calculate the centroid if (geometry::is_empty(multi)) { - throw centroid_exception(); + BOOST_THROW_EXCEPTION(centroid_exception()); } #endif diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp index 2001d5810c..f9d9dcc486 100644 --- a/boost/geometry/algorithms/covered_by.hpp +++ b/boost/geometry/algorithms/covered_by.hpp @@ -4,8 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,8 +16,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_COVERED_BY_HPP #define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP @@ -51,9 +51,13 @@ struct use_point_in_geometry struct use_relate { template <typename Geometry1, typename Geometry2, typename Strategy> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/) + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return Strategy::apply(geometry1, geometry2); + typedef typename detail::de9im::static_mask_covered_by_type + < + Geometry1, Geometry2 + >::type covered_by_mask; + return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy); } }; @@ -281,23 +285,8 @@ struct covered_by Geometry2 const& geometry2, default_strategy) { - typedef typename point_type<Geometry1>::type point_type1; - typedef typename point_type<Geometry2>::type point_type2; - typedef typename strategy::covered_by::services::default_strategy < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag<Geometry1>::type, - typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, Geometry1, Geometry2 >::type strategy_type; diff --git a/boost/geometry/algorithms/crosses.hpp b/boost/geometry/algorithms/crosses.hpp index 73d86ef529..c9e3651ab2 100644 --- a/boost/geometry/algorithms/crosses.hpp +++ b/boost/geometry/algorithms/crosses.hpp @@ -5,8 +5,10 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017 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,8 +17,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_CROSSES_HPP #define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP @@ -26,12 +26,12 @@ #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/algorithms/relate.hpp> +#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/core/access.hpp> - #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> -#include <boost/geometry/algorithms/relate.hpp> -#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> namespace boost { namespace geometry { @@ -62,20 +62,51 @@ struct crosses #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +struct crosses +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + concepts::check<Geometry1 const>(); + concepts::check<Geometry2 const>(); + + return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename strategy::relate::services::default_strategy + < + Geometry1, + Geometry2 + >::type strategy_type; + + return apply(geometry1, geometry2, strategy_type()); + } +}; + +} // namespace resolve_strategy + + namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct crosses { - static inline bool - apply( - const Geometry1& geometry1, - const Geometry2& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - - return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2); + return resolve_strategy::crosses::apply(geometry1, geometry2, strategy); } }; @@ -83,12 +114,15 @@ namespace resolve_variant template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { + template <typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2) + visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) + , m_strategy(strategy) {} template <typename Geometry1> @@ -98,15 +132,16 @@ namespace resolve_variant < Geometry1, Geometry2 - >::apply(geometry1, m_geometry2); + >::apply(geometry1, m_geometry2, m_strategy); } }; - static inline bool - apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2) + template <typename Strategy> + static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry2), geometry1); + return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; @@ -114,12 +149,15 @@ namespace resolve_variant template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct crosses<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1) + visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) + , m_strategy(strategy) {} template <typename Geometry2> @@ -129,15 +167,16 @@ namespace resolve_variant < Geometry1, Geometry2 - >::apply(m_geometry1, geometry2); + >::apply(m_geometry1, geometry2, m_strategy); } }; - static inline bool - apply(Geometry1 const& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry1), geometry2); + return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; @@ -145,8 +184,15 @@ namespace resolve_variant 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)> > { + template <typename Strategy> struct visitor: static_visitor<bool> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + template <typename Geometry1, typename Geometry2> result_type operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const @@ -155,15 +201,16 @@ namespace resolve_variant < Geometry1, Geometry2 - >::apply(geometry1, geometry2); + >::apply(geometry1, geometry2, m_strategy); } }; - static inline bool - apply(const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2) + template <typename Strategy> + static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(), geometry1, geometry2); + return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; @@ -175,6 +222,31 @@ namespace resolve_variant \ingroup crosses \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Crosses} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{crosses} +\return \return_check2{crosses} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/crosses.qbk]} +*/ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool crosses(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + return resolve_variant::crosses + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); +} + +/*! +\brief \brief_check2{crosses} +\ingroup crosses +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{crosses} @@ -184,7 +256,10 @@ namespace resolve_variant template <typename Geometry1, typename Geometry2> inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2); + return resolve_variant::crosses + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/azimuth.hpp b/boost/geometry/algorithms/detail/azimuth.hpp index 7e0d1691ed..a5863d7d24 100644 --- a/boost/geometry/algorithms/detail/azimuth.hpp +++ b/boost/geometry/algorithms/detail/azimuth.hpp @@ -2,9 +2,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2016. -// Modifications copyright (c) 2014-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2016, 2017. +// Modifications copyright (c) 2014-2017, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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, @@ -23,6 +24,7 @@ #include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/formulas/spherical.hpp> #include <boost/geometry/formulas/vincenty_inverse.hpp> namespace boost { namespace geometry @@ -69,22 +71,9 @@ 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)); + return geometry::formula::spherical_azimuth<ReturnType, false> + ( get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2)).azimuth; } template <typename P1, typename P2> diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 8447532a6c..029053dda3 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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) @@ -449,13 +453,14 @@ struct buffer_inserter<point_tag, Point, RingOutput> } }; - +// Not a specialization, but called from specializations of ring and of polygon. +// Calling code starts/finishes ring before/after apply template < typename RingInput, typename RingOutput > -struct buffer_inserter<ring_tag, RingInput, RingOutput> +struct buffer_inserter_ring { typedef typename point_type<RingOutput>::type output_point_type; @@ -568,6 +573,43 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput> template < + typename RingInput, + typename RingOutput +> +struct buffer_inserter<ring_tag, RingInput, RingOutput> +{ + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline strategy::buffer::result_code apply(RingInput const& ring, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + collection.start_new_ring(); + strategy::buffer::result_code const code + = buffer_inserter_ring<RingInput, RingOutput>::apply(ring, + collection, distance, + side_strategy, join_strategy, end_strategy, point_strategy, + robust_policy); + collection.finish_ring(code); + return code; + } +}; + +template +< typename Linestring, typename Polygon > @@ -709,7 +751,7 @@ private: typedef typename ring_type<PolygonInput>::type input_ring_type; typedef typename ring_type<PolygonOutput>::type output_ring_type; - typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy; + typedef buffer_inserter_ring<input_ring_type, output_ring_type> policy; template @@ -854,6 +896,7 @@ template typename JoinStrategy, typename EndStrategy, typename PointStrategy, + typename IntersectionStrategy, typename RobustPolicy, typename VisitPiecesPolicy > @@ -863,6 +906,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, VisitPiecesPolicy& visit_pieces_policy ) @@ -872,9 +916,10 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator typedef detail::buffer::buffered_piece_collection < typename geometry::ring_type<GeometryOutput>::type, + IntersectionStrategy, RobustPolicy > collection_type; - collection_type collection(robust_policy); + collection_type collection(intersection_strategy, robust_policy); collection_type const& const_collection = collection; bool const areal = boost::is_same @@ -961,6 +1006,7 @@ template typename JoinStrategy, typename EndStrategy, typename PointStrategy, + typename IntersectionStrategy, typename RobustPolicy > inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, @@ -969,13 +1015,14 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) { detail::buffer::visit_pieces_default_policy visitor; buffer_inserter<GeometryOutput>(geometry_input, out, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy, visitor); + intersection_strategy, robust_policy, visitor); } #endif // DOXYGEN_NO_DETAIL diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index c1f04f93b5..92dcdcc7b0 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, 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) @@ -52,6 +56,7 @@ public : typename Rings, typename Turns, typename Geometry, + typename Strategy, typename RobustPolicy, typename Visitor > @@ -63,6 +68,7 @@ public : detail::overlay::traverse_error_type /*traverse_error*/, Geometry const& , Geometry const& , + Strategy const& , RobustPolicy const& , state_type& state, Visitor& /*visitor*/ diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index e7214428e6..7fbbb790bb 100644 --- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2016. -// Modifications copyright (c) 2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2017. +// Modifications copyright (c) 2016-2017 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, @@ -117,10 +117,13 @@ enum segment_relation_code */ -template <typename Ring, typename RobustPolicy> +template <typename Ring, typename IntersectionStrategy, typename RobustPolicy> struct buffered_piece_collection { - typedef buffered_piece_collection<Ring, RobustPolicy> this_type; + typedef buffered_piece_collection + < + Ring, IntersectionStrategy, RobustPolicy + > this_type; typedef typename geometry::point_type<Ring>::type point_type; typedef typename geometry::coordinate_type<Ring>::type coordinate_type; @@ -303,7 +306,7 @@ struct buffered_piece_collection cluster_type m_clusters; - + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; struct redundant_turn @@ -314,8 +317,10 @@ struct buffered_piece_collection } }; - buffered_piece_collection(RobustPolicy const& robust_policy) + buffered_piece_collection(IntersectionStrategy const& intersection_strategy, + RobustPolicy const& robust_policy) : m_first_piece_index(-1) + , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) {} @@ -512,10 +517,11 @@ struct buffered_piece_collection 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); + include_turn_policy, + detail::partition::include_all_policy + >::apply(m_turns, robust_originals, visitor, + turn_get_box(), turn_in_original_ovelaps_box(), + original_get_box(), original_ovelaps_box()); bool const deflate = distance_strategy.negative(); @@ -767,15 +773,17 @@ struct buffered_piece_collection piece_vector_type, buffered_ring_collection<buffered_ring<Ring> >, turn_vector_type, + IntersectionStrategy, RobustPolicy - > visitor(m_pieces, offsetted_rings, m_turns, m_robust_policy); + > visitor(m_pieces, offsetted_rings, m_turns, + m_intersection_strategy, m_robust_policy); geometry::partition < - robust_box_type, - detail::section::get_section_box, - detail::section::overlaps_section_box - >::apply(monotonic_sections, visitor); + robust_box_type + >::apply(monotonic_sections, visitor, + detail::section::get_section_box(), + detail::section::overlaps_section_box()); } insert_rescaled_piece_turns(); @@ -795,10 +803,10 @@ struct buffered_piece_collection geometry::partition < - robust_box_type, - turn_get_box, turn_ovelaps_box, - piece_get_box, piece_ovelaps_box - >::apply(m_turns, m_pieces, visitor); + robust_box_type + >::apply(m_turns, m_pieces, visitor, + turn_get_box(), turn_ovelaps_box(), + piece_get_box(), piece_ovelaps_box()); } } @@ -1354,7 +1362,8 @@ struct buffered_piece_collection traversed_rings.clear(); buffer_overlay_visitor visitor; traverser::apply(offsetted_rings, offsetted_rings, - m_robust_policy, m_turns, traversed_rings, + m_intersection_strategy, m_robust_policy, + m_turns, traversed_rings, m_clusters, visitor); } diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index 3425ee6ffd..178c7bcafe 100644 --- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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) @@ -62,6 +66,7 @@ template typename Pieces, typename Rings, typename Turns, + typename IntersectionStrategy, typename RobustPolicy > class piece_turn_visitor @@ -69,6 +74,7 @@ class piece_turn_visitor Pieces const& m_pieces; Rings const& m_rings; Turns& m_turns; + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; template <typename Piece> @@ -243,7 +249,9 @@ class piece_turn_visitor turn_policy::apply(*prev1, *it1, *next1, *prev2, *it2, *next2, false, false, false, false, - the_model, m_robust_policy, + the_model, + m_intersection_strategy, + m_robust_policy, std::back_inserter(m_turns)); } } @@ -254,10 +262,12 @@ public: piece_turn_visitor(Pieces const& pieces, Rings const& ring_collection, Turns& turns, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) : m_pieces(pieces) , m_rings(ring_collection) , m_turns(turns) + , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) {} diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp index b23e70171b..732a2f5753 100644 --- a/boost/geometry/algorithms/detail/calculate_sum.hpp +++ b/boost/geometry/algorithms/detail/calculate_sum.hpp @@ -8,6 +8,10 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2016. +// Modifications copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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) @@ -30,7 +34,7 @@ class calculate_polygon_sum template <typename ReturnType, typename Policy, typename Rings, typename Strategy> static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy) { - ReturnType sum = ReturnType(); + ReturnType sum = ReturnType(0); for (typename boost::range_iterator<Rings const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp index 284858a130..664c995384 100644 --- a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/disjoint/areal_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-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -39,15 +39,45 @@ namespace detail { namespace disjoint { -template<typename Geometry> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct check_each_ring_for_within_call_covered_by +{ + /*! + \tparam Strategy point_in_geometry strategy + */ + template <typename Point, typename Strategy> + static inline bool apply(Point const& p, Geometry const& g, Strategy const& strategy) + { + return geometry::covered_by(p, g, strategy); + } +}; + +template <typename Geometry> +struct check_each_ring_for_within_call_covered_by<Geometry, box_tag> +{ + template <typename Point, typename Strategy> + static inline bool apply(Point const& p, Geometry const& g, Strategy const& ) + { + return geometry::covered_by(p, g); + } +}; + + +/*! +\tparam Strategy point_in_geometry strategy +*/ +template<typename Geometry, typename Strategy> struct check_each_ring_for_within { bool not_disjoint; Geometry const& m_geometry; + Strategy const& m_strategy; - inline check_each_ring_for_within(Geometry const& g) + inline check_each_ring_for_within(Geometry const& g, + Strategy const& strategy) : not_disjoint(false) , m_geometry(g) + , m_strategy(strategy) {} template <typename Range> @@ -56,17 +86,26 @@ struct check_each_ring_for_within typename point_type<Range>::type pt; not_disjoint = not_disjoint || ( geometry::point_on_border(pt, range) - && geometry::covered_by(pt, m_geometry) ); + && check_each_ring_for_within_call_covered_by + < + Geometry + >::apply(pt, m_geometry, m_strategy) ); } }; - -template <typename FirstGeometry, typename SecondGeometry> +/*! +\tparam Strategy point_in_geometry strategy +*/ +template <typename FirstGeometry, typename SecondGeometry, typename Strategy> inline bool rings_containing(FirstGeometry const& geometry1, - SecondGeometry const& geometry2) + SecondGeometry const& geometry2, + Strategy const& strategy) { - check_each_ring_for_within<FirstGeometry> checker(geometry1); + check_each_ring_for_within + < + FirstGeometry, Strategy + > checker(geometry1, strategy); geometry::detail::for_each_range(geometry2, checker); return checker.not_disjoint; } @@ -76,10 +115,15 @@ inline bool rings_containing(FirstGeometry const& geometry1, template <typename Geometry1, typename Geometry2> struct general_areal { - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + /*! + \tparam Strategy relate (segments intersection) strategy + */ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2) ) + if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy) ) { return false; } @@ -90,8 +134,10 @@ struct general_areal // We check that using a point on the border (external boundary), // and see if that is contained in the other geometry. And vice versa. - if ( rings_containing(geometry1, geometry2) - || rings_containing(geometry2, geometry1) ) + if ( rings_containing(geometry1, geometry2, + strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>()) + || rings_containing(geometry2, geometry1, + strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>()) ) { return false; } diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp index 3b81755e20..f830f8161c 100644 --- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2016. -// Modifications copyright (c) 2013-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -52,6 +52,12 @@ template > struct box_box { + template <typename Strategy> + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) + { + return apply(box1, box2); + } + static inline bool apply(Box1 const& box1, Box2 const& box2) { if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2)) @@ -84,6 +90,12 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount, CSTag> template <typename Box1, typename Box2, std::size_t DimensionCount> struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag> { + template <typename Strategy> + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) + { + return apply(box1, box2); + } + static inline bool apply(Box1 const& box1, Box2 const& box2) { typedef typename geometry::select_most_precise diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp index ce7fe6d45c..64898e35fe 100644 --- a/boost/geometry/algorithms/detail/disjoint/interface.hpp +++ b/boost/geometry/algorithms/detail/disjoint/interface.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-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -27,43 +27,51 @@ #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/algorithms/detail/relate/interface.hpp> +#include <boost/geometry/algorithms/dispatch/disjoint.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/algorithms/dispatch/disjoint.hpp> +#include <boost/geometry/strategies/disjoint.hpp> namespace boost { namespace geometry { - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch +namespace resolve_strategy { - -// If reversal is needed, perform it -template -< - typename Geometry1, typename Geometry2, - std::size_t DimensionCount, - typename Tag1, typename Tag2 -> -struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true> +struct disjoint { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return disjoint + return dispatch::disjoint + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename strategy::disjoint::services::default_strategy < - Geometry2, Geometry1, - DimensionCount, - Tag2, Tag1 - >::apply(g2, g1); + Geometry1, Geometry2 + >::type strategy_type; + + return dispatch::disjoint + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy_type()); } }; - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH +} // namespace resolve_strategy namespace resolve_variant { @@ -71,7 +79,8 @@ namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct disjoint { - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions < @@ -79,88 +88,135 @@ struct disjoint Geometry2 const >(); - return dispatch::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2); + return resolve_strategy::disjoint::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct disjoint<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {} + visitor(Geometry2 const& geometry2, Strategy const& strategy) + : m_geometry2(geometry2) + , m_strategy(strategy) + {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { - return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2); + return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); } }; - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2) + template <typename Strategy> + static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry2), geometry1); + return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {} + visitor(Geometry1 const& geometry1, Strategy const& strategy) + : m_geometry1(geometry1) + , m_strategy(strategy) + {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { - return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2); + return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); } }; - static inline bool - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry1), geometry2); + return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; -template < +template +< BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > -struct disjoint< - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> -> +struct disjoint + < + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> + > { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { - return disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2); + return disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); } }; - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2) + template <typename Strategy> + static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(), geometry1, geometry2); + return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant +/*! +\brief \brief_check2{are disjoint} +\ingroup disjoint +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Disjoint} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{disjoint} +\return \return_check2{are disjoint} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/disjoint.qbk]} +*/ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool disjoint(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + return resolve_variant::disjoint + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); +} + /*! \brief \brief_check2{are disjoint} @@ -177,7 +233,10 @@ template <typename Geometry1, typename Geometry2> inline bool disjoint(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2); + return resolve_variant::disjoint + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp index 6a48b684a1..e6077d3e7f 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-2015. -// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -61,19 +61,28 @@ template <typename Geometry1, typename Geometry2, typename Tag1OrMulti = typename tag_cast<Tag1, multi_tag>::type> struct disjoint_no_intersections_policy { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + /*! + \tparam Strategy point_in_geometry strategy + */ + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { typedef typename point_type<Geometry1>::type point1_type; point1_type p; geometry::point_on_border(p, g1); - return !geometry::covered_by(p, g2); + + return !geometry::covered_by(p, g2, strategy); } }; 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) + /*! + \tparam Strategy point_in_geometry strategy + */ + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { // TODO: use partition or rtree on g2 typedef typename boost::range_iterator<Geometry1 const>::type iterator; @@ -81,7 +90,7 @@ struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag> { typedef typename boost::range_value<Geometry1 const>::type value_type; if ( ! disjoint_no_intersections_policy<value_type const, Geometry2> - ::apply(*it, g2) ) + ::apply(*it, g2, strategy) ) { return false; } @@ -96,15 +105,21 @@ template<typename Geometry1, typename Geometry2, = disjoint_no_intersections_policy<Geometry1, Geometry2> > struct disjoint_linear_areal { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + /*! + \tparam Strategy relate (segments intersection) strategy + */ + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { // if there are intersections - return false - if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2) ) + if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2, strategy) ) { return false; } - return NoIntersectionsPolicy::apply(g1, g2); + return NoIntersectionsPolicy + ::apply(g1, g2, + strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>()); } }; @@ -126,16 +141,18 @@ template <typename Segment, typename Polygon> class disjoint_segment_areal<Segment, Polygon, polygon_tag> { private: - template <typename InteriorRings> + template <typename InteriorRings, typename Strategy> static inline bool check_interior_rings(InteriorRings const& interior_rings, - Segment const& segment) + Segment const& segment, + Strategy const& strategy) { typedef typename boost::range_value<InteriorRings>::type ring_type; typedef unary_disjoint_geometry_to_query_geometry < Segment, + Strategy, disjoint_range_segment_or_box < ring_type, closure<ring_type>::value, Segment @@ -147,24 +164,27 @@ private: unary_predicate_type >::apply(boost::begin(interior_rings), boost::end(interior_rings), - unary_predicate_type(segment)); + unary_predicate_type(segment, strategy)); } public: - static inline bool apply(Segment const& segment, Polygon const& polygon) + template <typename IntersectionStrategy> + static inline bool apply(Segment const& segment, + Polygon const& polygon, + IntersectionStrategy const& strategy) { typedef typename geometry::ring_type<Polygon>::type ring; if ( !disjoint_range_segment_or_box < ring, closure<Polygon>::value, Segment - >::apply(geometry::exterior_ring(polygon), segment) ) + >::apply(geometry::exterior_ring(polygon), segment, strategy) ) { return false; } - if ( !check_interior_rings(geometry::interior_rings(polygon), segment) ) + if ( !check_interior_rings(geometry::interior_rings(polygon), segment, strategy) ) { return false; } @@ -172,7 +192,8 @@ public: typename point_type<Segment>::type p; detail::assign_point_from_index<0>(segment, p); - return !geometry::covered_by(p, polygon); + return !geometry::covered_by(p, polygon, + strategy.template get_point_in_geometry_strategy<Segment, Polygon>()); } }; @@ -180,13 +201,14 @@ public: template <typename Segment, typename MultiPolygon> struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag> { - static inline - bool apply(Segment const& segment, MultiPolygon const& multipolygon) + template <typename IntersectionStrategy> + static inline bool apply(Segment const& segment, MultiPolygon const& multipolygon, + IntersectionStrategy const& strategy) { return multirange_constant_size_geometry < MultiPolygon, Segment - >::apply(multipolygon, segment); + >::apply(multipolygon, segment, strategy); } }; @@ -194,20 +216,24 @@ struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag> template <typename Segment, typename Ring> struct disjoint_segment_areal<Segment, Ring, ring_tag> { - static inline bool apply(Segment const& segment, Ring const& ring) + template <typename IntersectionStrategy> + static inline bool apply(Segment const& segment, + Ring const& ring, + IntersectionStrategy const& strategy) { if ( !disjoint_range_segment_or_box < Ring, closure<Ring>::value, Segment - >::apply(ring, segment) ) + >::apply(ring, segment, strategy) ) { return false; } typename point_type<Segment>::type p; detail::assign_point_from_index<0>(segment, p); - - return !geometry::covered_by(p, ring); + + return !geometry::covered_by(p, ring, + strategy.template get_point_in_geometry_strategy<Segment, Ring>()); } }; @@ -231,14 +257,15 @@ struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false> template <typename Areal, typename Linear> struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false> -{ - static inline - bool apply(Areal const& areal, Linear const& linear) +{ + template <typename Strategy> + static inline bool apply(Areal const& areal, Linear const& linear, + Strategy const& strategy) { return detail::disjoint::disjoint_linear_areal < Linear, Areal - >::apply(linear, areal); + >::apply(linear, areal, strategy); } }; @@ -246,12 +273,14 @@ struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false> template <typename Areal, typename Segment> struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false> { - static inline bool apply(Areal const& g1, Segment const& g2) + template <typename Strategy> + static inline bool apply(Areal const& g1, Segment const& g2, + Strategy const& strategy) { return detail::disjoint::disjoint_segment_areal < Segment, Areal - >::apply(g2, g1); + >::apply(g2, g1, strategy); } }; diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp index 91f985edb8..989b8df247 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.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-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -53,7 +53,9 @@ namespace detail { namespace disjoint template <typename Segment1, typename Segment2> struct disjoint_segment { - static inline bool apply(Segment1 const& segment1, Segment2 const& segment2) + template <typename Strategy> + static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, + Strategy const& strategy) { typedef typename point_type<Segment1>::type point_type; @@ -62,23 +64,23 @@ struct disjoint_segment rescale_policy_type robust_policy; typedef segment_intersection_points - < - point_type, - typename segment_ratio_type + < + point_type, + typename segment_ratio_type < point_type, rescale_policy_type >::type - > intersection_return_type; + > intersection_return_type; - intersection_return_type is - = strategy::intersection::relate_cartesian_segments + typedef policies::relate::segments_intersection_points < - policies::relate::segments_intersection_points - < - intersection_return_type - > - >::apply(segment1, segment2, robust_policy); + intersection_return_type + > intersection_policy; + + intersection_return_type is = strategy.apply(segment1, segment2, + intersection_policy(), + robust_policy); return is.count == 0; } @@ -109,8 +111,10 @@ struct assign_disjoint_policy template <typename Geometry1, typename Geometry2> struct disjoint_linear { - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point_type; typedef detail::no_rescale_policy rescale_policy_type; @@ -147,7 +151,7 @@ struct disjoint_linear Geometry1, Geometry2, assign_disjoint_policy > >::apply(0, geometry1, 1, geometry2, - rescale_policy_type(), turns, interrupt_policy); + strategy, rescale_policy_type(), turns, interrupt_policy); 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 8d82f7c911..b4c71c8f30 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp @@ -53,8 +53,10 @@ template > struct disjoint_range_segment_or_box { - static inline - bool apply(Range const& range, SegmentOrBox const& segment_or_box) + template <typename Strategy> + static inline bool apply(Range const& range, + SegmentOrBox const& segment_or_box, + Strategy const& strategy) { typedef typename closeable_view<Range const, Closure>::type view_type; @@ -85,7 +87,8 @@ struct disjoint_range_segment_or_box < point_type, SegmentOrBox >::apply(geometry::range::front<view_type const>(view), - segment_or_box); + segment_or_box, + strategy.template get_point_in_geometry_strategy<Range, SegmentOrBox>()); } else { @@ -99,7 +102,7 @@ struct disjoint_range_segment_or_box if ( !dispatch::disjoint < range_segment, SegmentOrBox - >::apply(rng_segment, segment_or_box) ) + >::apply(rng_segment, segment_or_box, strategy) ) { return false; } diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp index 29e438e546..7c1a93cdb7 100644 --- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -14,8 +15,10 @@ #include <vector> #include <boost/range.hpp> +#include <boost/mpl/assert.hpp> #include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> @@ -105,36 +108,74 @@ template <typename MultiPoint, typename Linear> class multipoint_linear { private: - // structs for partition -- start - struct expand_box + struct expand_box_point { - template <typename Box, typename Geometry> - static inline void apply(Box& total, Geometry const& geometry) + template <typename Box, typename Point> + static inline void apply(Box& total, Point const& point) { - geometry::expand(total, geometry::return_envelope<Box>(geometry)); + geometry::expand(total, point); } + }; + // TODO: After adding non-cartesian Segment envelope to the library + // this policy should be modified to take envelope strategy. + struct expand_box_segment + { + template <typename Box, typename Segment> + static inline void apply(Box& total, Segment const& segment) + { + geometry::expand(total, geometry::return_envelope<Box>(segment)); + } }; - struct overlaps_box + struct overlaps_box_point { - template <typename Box, typename Geometry> - static inline bool apply(Box const& box, Geometry const& geometry) + template <typename Box, typename Point> + static inline bool apply(Box const& box, Point const& point) { - return ! dispatch::disjoint<Geometry, Box>::apply(geometry, box); + // The default strategy is enough in this case + typedef typename strategy::disjoint::services::default_strategy + < + Point, Box + >::type strategy_type; + return ! dispatch::disjoint<Point, Box>::apply(point, box, strategy_type()); } }; + // TODO: After implementing disjoint Segment/Box for non-cartesian geometries + // this strategy should be passed here. + // TODO: This Segment/Box strategy should somehow be derived from Point/Segment strategy + // which by default is winding containing CS-specific side strategy + // TODO: disjoint Segment/Box will be called in this case which may take + // quite long in non-cartesian CS. So we should consider passing range of bounding boxes + // of segments after calculating them once. + struct overlaps_box_segment + { + template <typename Box, typename Segment> + static inline bool apply(Box const& box, Segment const& segment) + { + typedef typename strategy::disjoint::services::default_strategy + < + Segment, Box + >::type strategy_type; + return ! dispatch::disjoint<Segment, Box>::apply(segment, box, strategy_type()); + } + }; + + template <typename PtSegStrategy> class item_visitor_type { public: - item_visitor_type() : m_intersection_found(false) {} + item_visitor_type(PtSegStrategy const& strategy) + : m_intersection_found(false) + , m_strategy(strategy) + {} template <typename Item1, typename Item2> inline void apply(Item1 const& item1, Item2 const& item2) { if (! m_intersection_found - && ! dispatch::disjoint<Item1, Item2>::apply(item1, item2)) + && ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy)) { m_intersection_found = true; } @@ -144,6 +185,7 @@ private: private: bool m_intersection_found; + PtSegStrategy const& m_strategy; }; // structs for partition -- end @@ -172,23 +214,25 @@ private: }; public: - static inline bool apply(MultiPoint const& multipoint, Linear const& linear) + template <typename Strategy> + static inline bool apply(MultiPoint const& multipoint, Linear const& linear, Strategy const& strategy) { - item_visitor_type visitor; + item_visitor_type<Strategy> visitor(strategy); geometry::partition < - geometry::model::box<typename point_type<MultiPoint>::type>, - expand_box, - overlaps_box - >::apply(multipoint, segment_range(linear), visitor); + geometry::model::box<typename point_type<MultiPoint>::type> + >::apply(multipoint, segment_range(linear), visitor, + expand_box_point(), overlaps_box_point(), + expand_box_segment(), overlaps_box_segment()); return ! visitor.intersection_found(); } - static inline bool apply(Linear const& linear, MultiPoint const& multipoint) + template <typename Strategy> + static inline bool apply(Linear const& linear, MultiPoint const& multipoint, Strategy const& strategy) { - return apply(multipoint, linear); + return apply(multipoint, linear, strategy); } }; @@ -240,8 +284,10 @@ struct disjoint multi_point_tag, multi_point_tag, false > { + template <typename Strategy> static inline bool apply(MultiPoint1 const& multipoint1, - MultiPoint2 const& multipoint2) + MultiPoint2 const& multipoint2, + Strategy const& ) { if ( boost::size(multipoint2) < boost::size(multipoint1) ) { diff --git a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp index 78a683e46e..53fb1642af 100644 --- a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -25,34 +26,40 @@ namespace detail { namespace disjoint { -template <typename Geometry, typename BinaryPredicate> +template <typename Geometry, typename Strategy, typename BinaryPredicate> class unary_disjoint_geometry_to_query_geometry { public: - unary_disjoint_geometry_to_query_geometry(Geometry const& geometry) + unary_disjoint_geometry_to_query_geometry(Geometry const& geometry, + Strategy const& strategy) : m_geometry(geometry) + , m_strategy(strategy) {} template <typename QueryGeometry> inline bool apply(QueryGeometry const& query_geometry) const { - return BinaryPredicate::apply(query_geometry, m_geometry); + return BinaryPredicate::apply(query_geometry, m_geometry, m_strategy); } private: Geometry const& m_geometry; + Strategy const& m_strategy; }; template<typename MultiRange, typename ConstantSizeGeometry> struct multirange_constant_size_geometry { + template <typename Strategy> static inline bool apply(MultiRange const& multirange, - ConstantSizeGeometry const& constant_size_geometry) + ConstantSizeGeometry const& constant_size_geometry, + Strategy const& strategy) { typedef unary_disjoint_geometry_to_query_geometry < ConstantSizeGeometry, + Strategy, dispatch::disjoint < typename boost::range_value<MultiRange>::type, @@ -64,13 +71,15 @@ struct multirange_constant_size_geometry < unary_predicate_type >::apply(boost::begin(multirange), boost::end(multirange), - unary_predicate_type(constant_size_geometry)); + unary_predicate_type(constant_size_geometry, strategy)); } + template <typename Strategy> static inline bool apply(ConstantSizeGeometry const& constant_size_geometry, - MultiRange const& multirange) + MultiRange const& multirange, + Strategy const& strategy) { - return apply(multirange, constant_size_geometry); + return apply(multirange, constant_size_geometry, strategy); } }; diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp index 2f1085ada9..2e6773d221 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2013-2016. -// Modifications copyright (c) 2013-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -28,7 +28,7 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> -#include <boost/geometry/strategies/cartesian/point_in_box.hpp> +#include <boost/geometry/strategies/disjoint.hpp> namespace boost { namespace geometry { @@ -44,13 +44,13 @@ namespace detail { namespace disjoint template <typename Point, typename Box> inline bool disjoint_point_box(Point const& point, Box const& box) { + typedef typename strategy::disjoint::services::default_strategy + < + Point, Box + >::type strategy_type; + // ! covered_by(point, box) - return ! strategy::within::relate_point_box_loop - < - strategy::within::covered_by_range, - Point, Box, - 0, dimension<Point>::type::value - >::apply(point, box); + return ! strategy_type::apply(point, box); } @@ -66,15 +66,11 @@ namespace dispatch template <typename Point, typename Box, std::size_t DimensionCount> struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false> { - static inline bool apply(Point const& point, Box const& box) + template <typename Strategy> + static inline bool apply(Point const& point, Box const& box, Strategy const& ) { // ! covered_by(point, box) - return ! strategy::within::relate_point_box_loop - < - strategy::within::covered_by_range, - Point, Box, - 0, DimensionCount - >::apply(point, box); + return ! Strategy::apply(point, box); } }; diff --git a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp index 9ae43f73d0..66bd7c26ce 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp @@ -39,11 +39,12 @@ namespace detail { namespace disjoint struct reverse_covered_by { - template <typename Geometry1, typename Geometry2> - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return ! geometry::covered_by(geometry1, geometry2); + return ! geometry::covered_by(geometry1, geometry2, strategy); } }; diff --git a/boost/geometry/algorithms/detail/disjoint/point_point.hpp b/boost/geometry/algorithms/detail/disjoint/point_point.hpp index 7580b7287b..13ac34d718 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_point.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_point.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017, 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 @@ -59,6 +59,12 @@ namespace detail { namespace disjoint template <std::size_t Dimension, std::size_t DimensionCount> struct point_point_generic { + template <typename Point1, typename Point2, typename Strategy> + static inline bool apply(Point1 const& p1, Point2 const& p2, Strategy const& ) + { + return apply(p1, p2); + } + template <typename Point1, typename Point2> static inline bool apply(Point1 const& p1, Point2 const& p2) { @@ -75,7 +81,7 @@ template <std::size_t DimensionCount> struct point_point_generic<DimensionCount, DimensionCount> { template <typename Point1, typename Point2> - static inline bool apply(Point1 const&, Point2 const&) + static inline bool apply(Point1 const&, Point2 const& ) { return false; } @@ -135,6 +141,12 @@ private: }; public: + template <typename Point1, typename Point2, typename Strategy> + static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& ) + { + return apply(point1, point2); + } + template <typename Point1, typename Point2> static inline bool apply(Point1 const& point1, Point2 const& point2) { diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp index cc0c7949e3..c2741ce72c 100644 --- a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/segment_box.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-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -22,19 +22,8 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP #include <cstddef> -#include <utility> -#include <boost/numeric/conversion/cast.hpp> - -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/calculation_type.hpp> - -#include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/point_type.hpp> - -#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> @@ -47,236 +36,19 @@ namespace boost { namespace geometry namespace detail { namespace disjoint { - -template <std::size_t I> -struct compute_tmin_tmax_per_dim -{ - template <typename SegmentPoint, typename Box, typename RelativeDistance> - static inline void apply(SegmentPoint const& p0, - SegmentPoint const& p1, - Box const& box, - RelativeDistance& ti_min, - RelativeDistance& ti_max, - RelativeDistance& diff) - { - typedef typename coordinate_type<Box>::type box_coordinate_type; - typedef typename coordinate_type - < - SegmentPoint - >::type point_coordinate_type; - - RelativeDistance c_p0 = boost::numeric_cast - < - point_coordinate_type - >( geometry::get<I>(p0) ); - - RelativeDistance c_p1 = boost::numeric_cast - < - point_coordinate_type - >( geometry::get<I>(p1) ); - - RelativeDistance c_b_min = boost::numeric_cast - < - box_coordinate_type - >( geometry::get<geometry::min_corner, I>(box) ); - - RelativeDistance c_b_max = boost::numeric_cast - < - box_coordinate_type - >( geometry::get<geometry::max_corner, I>(box) ); - - if ( geometry::get<I>(p1) >= geometry::get<I>(p0) ) - { - diff = c_p1 - c_p0; - ti_min = c_b_min - c_p0; - ti_max = c_b_max - c_p0; - } - else - { - diff = c_p0 - c_p1; - ti_min = c_p0 - c_b_max; - ti_max = c_p0 - c_b_min; - } - } -}; - - -template -< - typename RelativeDistance, - typename SegmentPoint, - typename Box, - std::size_t I, - std::size_t Dimension -> -struct disjoint_segment_box_impl -{ - template <typename RelativeDistancePair> - static inline bool apply(SegmentPoint const& p0, - SegmentPoint const& p1, - Box const& box, - RelativeDistancePair& t_min, - RelativeDistancePair& t_max) - { - RelativeDistance ti_min, ti_max, diff; - - compute_tmin_tmax_per_dim<I>::apply(p0, p1, box, ti_min, ti_max, diff); - - if ( geometry::math::equals(diff, 0) ) - { - if ( (geometry::math::equals(t_min.second, 0) - && t_min.first > ti_max) - || - (geometry::math::equals(t_max.second, 0) - && t_max.first < ti_min) - || - (math::sign(ti_min) * math::sign(ti_max) > 0) ) - { - return true; - } - } - - RelativeDistance t_min_x_diff = t_min.first * diff; - RelativeDistance t_max_x_diff = t_max.first * diff; - - if ( t_min_x_diff > ti_max * t_min.second - || t_max_x_diff < ti_min * t_max.second ) - { - return true; - } - - if ( ti_min * t_min.second > t_min_x_diff ) - { - t_min.first = ti_min; - t_min.second = diff; - } - if ( ti_max * t_max.second < t_max_x_diff ) - { - t_max.first = ti_max; - t_max.second = diff; - } - - if ( t_min.first > t_min.second || t_max.first < 0 ) - { - return true; - } - - return disjoint_segment_box_impl - < - RelativeDistance, - SegmentPoint, - Box, - I + 1, - Dimension - >::apply(p0, p1, box, t_min, t_max); - } -}; - - -template -< - typename RelativeDistance, - typename SegmentPoint, - typename Box, - std::size_t Dimension -> -struct disjoint_segment_box_impl - < - RelativeDistance, SegmentPoint, Box, 0, Dimension - > -{ - static inline bool apply(SegmentPoint const& p0, - SegmentPoint const& p1, - Box const& box) - { - std::pair<RelativeDistance, RelativeDistance> t_min, t_max; - RelativeDistance diff; - - compute_tmin_tmax_per_dim<0>::apply(p0, p1, box, - t_min.first, t_max.first, diff); - - if ( geometry::math::equals(diff, 0) ) - { - if ( geometry::math::equals(t_min.first, 0) ) { t_min.first = -1; } - if ( geometry::math::equals(t_max.first, 0) ) { t_max.first = 1; } - - if (math::sign(t_min.first) * math::sign(t_max.first) > 0) - { - return true; - } - } - - if ( t_min.first > diff || t_max.first < 0 ) - { - return true; - } - - t_min.second = t_max.second = diff; - - return disjoint_segment_box_impl - < - RelativeDistance, SegmentPoint, Box, 1, Dimension - >::apply(p0, p1, box, t_min, t_max); - } -}; - - -template -< - typename RelativeDistance, - typename SegmentPoint, - typename Box, - std::size_t Dimension -> -struct disjoint_segment_box_impl - < - RelativeDistance, SegmentPoint, Box, Dimension, Dimension - > -{ - template <typename RelativeDistancePair> - static inline bool apply(SegmentPoint const&, SegmentPoint const&, - Box const&, - RelativeDistancePair&, RelativeDistancePair&) - { - return false; - } -}; - - -//========================================================================= - - -template <typename Segment, typename Box> struct disjoint_segment_box -{ - static inline bool apply(Segment const& segment, Box const& box) +{ + template <typename Segment, typename Box, typename Strategy> + static inline bool apply(Segment const& segment, Box const& box, Strategy const& strategy) { - assert_dimension_equal<Segment, Box>(); - - typedef typename util::calculation_type::geometric::binary - < - Segment, Box, void - >::type relative_distance_type; - - typedef typename point_type<Segment>::type segment_point_type; - segment_point_type p0, p1; - geometry::detail::assign_point_from_index<0>(segment, p0); - geometry::detail::assign_point_from_index<1>(segment, p1); - - return disjoint_segment_box_impl - < - relative_distance_type, segment_point_type, Box, - 0, dimension<Box>::value - >::apply(p0, p1, box); + return strategy.apply(segment, box); } }; - }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -284,7 +56,7 @@ namespace dispatch template <typename Segment, typename Box, std::size_t DimensionCount> struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false> - : detail::disjoint::disjoint_segment_box<Segment, Box> + : detail::disjoint::disjoint_segment_box {}; diff --git a/boost/geometry/algorithms/detail/envelope/box.hpp b/boost/geometry/algorithms/detail/envelope/box.hpp index 3790262948..795f51392e 100644 --- a/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/boost/geometry/algorithms/detail/envelope/box.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -97,8 +98,10 @@ struct envelope_indexed_box_on_spheroid struct envelope_box { - template<typename BoxIn, typename BoxOut> - static inline void apply(BoxIn const& box_in, BoxOut& mbr) + template<typename BoxIn, typename BoxOut, typename Strategy> + static inline void apply(BoxIn const& box_in, + BoxOut& mbr, + Strategy const&) { envelope_indexed_box < @@ -115,8 +118,10 @@ struct envelope_box struct envelope_box_on_spheroid { - template <typename BoxIn, typename BoxOut> - static inline void apply(BoxIn const& box_in, BoxOut& mbr) + template <typename BoxIn, typename BoxOut, typename Strategy> + static inline void apply(BoxIn const& box_in, + BoxOut& mbr, + Strategy const&) { BoxIn box_in_normalized = detail::return_normalized<BoxIn>(box_in); diff --git a/boost/geometry/algorithms/detail/envelope/implementation.hpp b/boost/geometry/algorithms/detail/envelope/implementation.hpp index c1dbf8e589..d549700791 100644 --- a/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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 @@ -45,8 +46,8 @@ namespace detail { namespace envelope struct envelope_polygon { - template <typename Polygon, typename Box> - static inline void apply(Polygon const& polygon, Box& mbr) + template <typename Polygon, typename Box, typename Strategy> + static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy) { typename ring_return_type<Polygon const>::type ext_ring = exterior_ring(polygon); @@ -57,12 +58,12 @@ struct envelope_polygon envelope_multi_range < envelope_range - >::apply(interior_rings(polygon), mbr); + >::apply(interior_rings(polygon), mbr, strategy); } else { // otherwise, consider only the exterior ring - envelope_range::apply(ext_ring, mbr); + envelope_range::apply(ext_ring, mbr, strategy); } } }; diff --git a/boost/geometry/algorithms/detail/envelope/interface.hpp b/boost/geometry/algorithms/detail/envelope/interface.hpp index befe4e42db..8e9c35b395 100644 --- a/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -4,10 +4,12 @@ // 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. +// This file was modified by Oracle on 2015, 2016, 2017. +// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // 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. @@ -27,54 +29,124 @@ #include <boost/geometry/algorithms/dispatch/envelope.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/envelope.hpp> +#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> +#include <boost/geometry/strategies/spherical/envelope_segment.hpp> +#include <boost/geometry/strategies/geographic/envelope_segment.hpp> namespace boost { namespace geometry { -namespace resolve_variant +namespace resolve_strategy { template <typename Geometry> struct envelope { + template <typename Box, typename Strategy> + static inline void apply(Geometry const& geometry, + Box& box, + Strategy const& strategy) + { + dispatch::envelope<Geometry>::apply(geometry, box, strategy); + } + template <typename Box> - static inline void apply(Geometry const& geometry, Box& box) + static inline void apply(Geometry const& geometry, + Box& box, + default_strategy) + { + typedef typename point_type<Geometry>::type point_type; + typedef typename coordinate_type<point_type>::type coordinate_type; + + typedef typename strategy::envelope::services::default_strategy + < + typename cs_tag<point_type>::type, + coordinate_type + >::type strategy_type; + + dispatch::envelope<Geometry>::apply(geometry, box, strategy_type()); + } +}; + +} // namespace resolve_strategy + +namespace resolve_variant +{ + +template <typename Geometry> +struct envelope +{ + template <typename Box, typename Strategy> + static inline void apply(Geometry const& geometry, + Box& box, + Strategy const& strategy) { concepts::check<Geometry const>(); concepts::check<Box>(); - dispatch::envelope<Geometry>::apply(geometry, box); + resolve_strategy::envelope<Geometry>::apply(geometry, box, strategy); } }; + template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename Box> + template <typename Box, typename Strategy> struct visitor: boost::static_visitor<void> { Box& m_box; + Strategy const& m_strategy; - visitor(Box& box): m_box(box) {} + visitor(Box& box, Strategy const& strategy) + : m_box(box) + , m_strategy(strategy) + {} template <typename Geometry> void operator()(Geometry const& geometry) const { - envelope<Geometry>::apply(geometry, m_box); + envelope<Geometry>::apply(geometry, m_box, m_strategy); } }; - template <typename Box> + template <typename Box, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - Box& box) + Box& box, + Strategy const& strategy) { - boost::apply_visitor(visitor<Box>(box), geometry); + boost::apply_visitor(visitor<Box, Strategy>(box, strategy), geometry); } }; } // namespace resolve_variant +/*! +\brief \brief_calc{envelope (with strategy)} +\ingroup envelope +\details \details_calc{envelope,\det_envelope}. +\tparam Geometry \tparam_geometry +\tparam Box \tparam_box +\tparam Strategy \tparam_strategy{Envelope} +\param geometry \param_geometry +\param mbr \param_box \param_set{envelope} +\param strategy \param_strategy{envelope} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/envelope.qbk]} +\qbk{ +[heading Example] +[envelope] [envelope_output] +} +*/ +template<typename Geometry, typename Box, typename Strategy> +inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy) +{ + resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); +} /*! \brief \brief_calc{envelope} @@ -94,7 +166,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > template<typename Geometry, typename Box> inline void envelope(Geometry const& geometry, Box& mbr) { - resolve_variant::envelope<Geometry>::apply(geometry, mbr); + resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); } @@ -104,6 +176,32 @@ inline void envelope(Geometry const& geometry, Box& mbr) \details \details_calc{return_envelope,\det_envelope}. \details_return{envelope} \tparam Box \tparam_box \tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{Envelope} +\param geometry \param_geometry +\param strategy \param_strategy{envelope} +\return \return_calc{envelope} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/envelope.qbk]} +\qbk{ +[heading Example] +[return_envelope] [return_envelope_output] +} +*/ +template<typename Box, typename Geometry, typename Strategy> +inline Box return_envelope(Geometry const& geometry, Strategy const& strategy) +{ + Box mbr; + resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); + return mbr; +} + +/*! +\brief \brief_calc{envelope} +\ingroup envelope +\details \details_calc{return_envelope,\det_envelope}. \details_return{envelope} +\tparam Box \tparam_box +\tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{envelope} @@ -117,7 +215,7 @@ template<typename Box, typename Geometry> inline Box return_envelope(Geometry const& geometry) { Box mbr; - resolve_variant::envelope<Geometry>::apply(geometry, mbr); + resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); return mbr; } diff --git a/boost/geometry/algorithms/detail/envelope/linear.hpp b/boost/geometry/algorithms/detail/envelope/linear.hpp index 49c3cf3135..09d8a76da5 100644 --- a/boost/geometry/algorithms/detail/envelope/linear.hpp +++ b/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -36,12 +37,15 @@ namespace detail { namespace envelope struct envelope_linestring_on_spheroid { - template <typename Linestring, typename Box> - static inline void apply(Linestring const& linestring, Box& mbr) + template <typename Linestring, typename Box, typename Strategy> + static inline void apply(Linestring const& linestring, + Box& mbr, + Strategy const& strategy) { envelope_range::apply(geometry::segments_begin(linestring), geometry::segments_end(linestring), - mbr); + mbr, + strategy); } }; @@ -65,6 +69,11 @@ struct envelope<Linestring, linestring_tag, spherical_equatorial_tag> : detail::envelope::envelope_linestring_on_spheroid {}; +template <typename Linestring> +struct envelope<Linestring, linestring_tag, geographic_tag> + : detail::envelope::envelope_linestring_on_spheroid +{}; + template <typename MultiLinestring, typename CS_Tag> struct envelope @@ -86,6 +95,15 @@ struct envelope > {}; +template <typename MultiLinestring> +struct envelope + < + MultiLinestring, multi_linestring_tag, geographic_tag + > : detail::envelope::envelope_multi_range_on_spheroid + < + detail::envelope::envelope_linestring_on_spheroid + > +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/boost/geometry/algorithms/detail/envelope/multipoint.hpp index 210debfdba..efee4701c9 100644 --- a/boost/geometry/algorithms/detail/envelope/multipoint.hpp +++ b/boost/geometry/algorithms/detail/envelope/multipoint.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -226,8 +227,8 @@ private: } public: - template <typename MultiPoint, typename Box> - static inline void apply(MultiPoint const& multipoint, Box& mbr) + template <typename MultiPoint, typename Box, typename Strategy> + static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy) { typedef typename point_type<MultiPoint>::type point_type; typedef typename coordinate_type<MultiPoint>::type coordinate_type; @@ -255,7 +256,7 @@ public: return dispatch::envelope < typename boost::range_value<MultiPoint>::type - >::apply(range::front(multipoint), mbr); + >::apply(range::front(multipoint), mbr, strategy); } // analyze the points and put the non-pole ones in the @@ -329,7 +330,7 @@ public: // compute envelope for higher coordinates iterator_type it = boost::begin(multipoint); - envelope_one_point<2, dimension<Box>::value>::apply(*it, mbr); + envelope_one_point<2, dimension<Box>::value>::apply(*it, mbr, strategy); for (++it; it != boost::end(multipoint); ++it) { @@ -338,7 +339,7 @@ public: strategy::compare::default_strategy, strategy::compare::default_strategy, 2, dimension<Box>::value - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); } } }; diff --git a/boost/geometry/algorithms/detail/envelope/point.hpp b/boost/geometry/algorithms/detail/envelope/point.hpp index e914e7e8a0..ee0559bf5f 100644 --- a/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/boost/geometry/algorithms/detail/envelope/point.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -58,8 +59,8 @@ struct envelope_one_point >::apply(point, box_corner); } - template <typename Point, typename Box> - static inline void apply(Point const& point, Box& mbr) + template <typename Point, typename Box, typename Strategy> + static inline void apply(Point const& point, Box& mbr, Strategy const&) { apply<min_corner>(point, mbr); apply<max_corner>(point, mbr); @@ -69,8 +70,8 @@ struct envelope_one_point struct envelope_point_on_spheroid { - template<typename Point, typename Box> - static inline void apply(Point const& point, Box& mbr) + template<typename Point, typename Box, typename Strategy> + static inline void apply(Point const& point, Box& mbr, Strategy const& strategy) { Point normalized_point = detail::return_normalized<Point>(point); @@ -88,7 +89,7 @@ struct envelope_point_on_spheroid envelope_one_point < 2, dimension<Point>::value - >::apply(normalized_point, mbr); + >::apply(normalized_point, mbr, strategy); } }; diff --git a/boost/geometry/algorithms/detail/envelope/range.hpp b/boost/geometry/algorithms/detail/envelope/range.hpp index 63b518114b..b5591f61ab 100644 --- a/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/boost/geometry/algorithms/detail/envelope/range.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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 @@ -51,8 +52,11 @@ namespace detail { namespace envelope // implementation for simple ranges struct envelope_range { - template <typename Iterator, typename Box> - static inline void apply(Iterator first, Iterator last, Box& mbr) + template <typename Iterator, typename Box, typename Strategy> + static inline void apply(Iterator first, + Iterator last, + Box& mbr, + Strategy const& strategy) { typedef typename std::iterator_traits<Iterator>::value_type value_type; @@ -63,20 +67,20 @@ struct envelope_range if (it != last) { // initialize box with first element in range - dispatch::envelope<value_type>::apply(*it, mbr); + dispatch::envelope<value_type>::apply(*it, mbr, strategy); // consider now the remaining elements in the range (if any) for (++it; it != last; ++it) { - dispatch::expand<Box, value_type>::apply(mbr, *it); + dispatch::expand<Box, value_type>::apply(mbr, *it, strategy); } } } - template <typename Range, typename Box> - static inline void apply(Range const& range, Box& mbr) + template <typename Range, typename Box, typename Strategy> + static inline void apply(Range const& range, Box& mbr, Strategy const& strategy) { - return apply(boost::begin(range), boost::end(range), mbr); + return apply(boost::begin(range), boost::end(range), mbr, strategy); } }; @@ -85,8 +89,10 @@ struct envelope_range template <typename EnvelopePolicy> struct envelope_multi_range { - template <typename MultiRange, typename Box> - static inline void apply(MultiRange const& multirange, Box& mbr) + template <typename MultiRange, typename Box, typename Strategy> + static inline void apply(MultiRange const& multirange, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_iterator < @@ -103,14 +109,14 @@ struct envelope_multi_range if (initialized) { Box helper_mbr; - EnvelopePolicy::apply(*it, helper_mbr); + EnvelopePolicy::apply(*it, helper_mbr, strategy); - dispatch::expand<Box, Box>::apply(mbr, helper_mbr); + dispatch::expand<Box, Box>::apply(mbr, helper_mbr, strategy); } else { // compute the initial envelope - EnvelopePolicy::apply(*it, mbr); + EnvelopePolicy::apply(*it, mbr, strategy); initialized = true; } } @@ -129,8 +135,10 @@ struct envelope_multi_range template <typename EnvelopePolicy> struct envelope_multi_range_on_spheroid { - template <typename MultiRange, typename Box> - static inline void apply(MultiRange const& multirange, Box& mbr) + template <typename MultiRange, typename Box, typename Strategy> + static inline void apply(MultiRange const& multirange, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_iterator < @@ -147,7 +155,7 @@ struct envelope_multi_range_on_spheroid if (! geometry::is_empty(*it)) { Box helper_box; - EnvelopePolicy::apply(*it, helper_box); + EnvelopePolicy::apply(*it, helper_box, strategy); boxes.push_back(helper_box); } } @@ -159,7 +167,7 @@ struct envelope_multi_range_on_spheroid // and the MBR is simply initialized if (! boxes.empty()) { - envelope_range_of_boxes::apply(boxes, mbr); + envelope_range_of_boxes::apply(boxes, mbr, strategy); } else { diff --git a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp index 64bdb9b9cb..f61fc422de 100644 --- a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -149,8 +150,10 @@ struct envelope_range_of_longitudes template <std::size_t Dimension, std::size_t DimensionCount> struct envelope_range_of_boxes_by_expansion { - template <typename RangeOfBoxes, typename Box> - static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) + template <typename RangeOfBoxes, typename Box, typename Strategy> + static inline void apply(RangeOfBoxes const& range_of_boxes, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_value<RangeOfBoxes>::type box_type; @@ -196,7 +199,7 @@ struct envelope_range_of_boxes_by_expansion min_corner, Dimension, DimensionCount - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); detail::expand::indexed_loop < @@ -205,7 +208,7 @@ struct envelope_range_of_boxes_by_expansion max_corner, Dimension, DimensionCount - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); } } @@ -225,8 +228,10 @@ struct envelope_range_of_boxes } }; - template <typename RangeOfBoxes, typename Box> - static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) + template <typename RangeOfBoxes, typename Box, typename Strategy> + static inline void apply(RangeOfBoxes const& range_of_boxes, + Box& mbr, + Strategy const& strategy) { // boxes in the range are assumed to be normalized already @@ -313,7 +318,7 @@ struct envelope_range_of_boxes envelope_range_of_boxes_by_expansion < 2, dimension<Box>::value - >::apply(range_of_boxes, mbr); + >::apply(range_of_boxes, mbr, strategy); } }; diff --git a/boost/geometry/algorithms/detail/envelope/segment.hpp b/boost/geometry/algorithms/detail/envelope/segment.hpp index 6186e72a3a..7631e84883 100644 --- a/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -4,9 +4,10 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015-2017. +// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -26,6 +27,7 @@ #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/srs.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/radian_access.hpp> #include <boost/geometry/core/tags.hpp> @@ -34,10 +36,9 @@ #include <boost/geometry/geometries/helper_geometry.hpp> -#include <boost/geometry/strategies/compare.hpp> +#include <boost/geometry/formulas/vertex_latitude.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> -#include <boost/geometry/algorithms/detail/normalize.hpp> #include <boost/geometry/algorithms/detail/envelope/point.hpp> #include <boost/geometry/algorithms/detail/envelope/transform_units.hpp> @@ -46,7 +47,6 @@ #include <boost/geometry/algorithms/dispatch/envelope.hpp> - namespace boost { namespace geometry { @@ -54,63 +54,36 @@ namespace boost { namespace geometry namespace detail { namespace envelope { - -template <std::size_t Dimension, std::size_t DimensionCount> -struct envelope_one_segment +template <typename CalculationType, typename CS_Tag> +struct envelope_segment_call_vertex_latitude { - template<typename Point, typename Box> - static inline void apply(Point const& p1, Point const& p2, Box& mbr) + template <typename T1, typename T2, typename Strategy> + static inline CalculationType apply(T1 const& lat1, + T2 const& alp1, + Strategy const& ) { - envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr); - detail::expand::point_loop - < - strategy::compare::default_strategy, - strategy::compare::default_strategy, - Dimension, - DimensionCount - >::apply(mbr, p2); + return geometry::formula::vertex_latitude<CalculationType, CS_Tag> + ::apply(lat1, alp1); } }; - -// Computes the MBR of a segment given by (lon1, lat1) and (lon2, -// lat2), and with azimuths a1 and a2 at the two endpoints of the -// segment. -// It is assumed that the spherical coordinates of the segment are -// normalized and in radians. -// The longitudes and latitudes of the endpoints are overridden by -// those of the box. -class compute_mbr_of_segment +template <typename CalculationType> +struct envelope_segment_call_vertex_latitude<CalculationType, geographic_tag> { -private: - // computes the azimuths of the segment with endpoints (lon1, lat1) - // and (lon2, lat2) - // radians - template <typename CalculationType> - static inline void azimuths(CalculationType const& lon1, - CalculationType const& lat1, - CalculationType const& lon2, - CalculationType const& lat2, - CalculationType& a1, - CalculationType& a2) + template <typename T1, typename T2, typename Strategy> + static inline CalculationType apply(T1 const& lat1, + T2 const& alp1, + Strategy const& strategy) { - BOOST_GEOMETRY_ASSERT(lon1 <= lon2); - - CalculationType dlon = lon2 - lon1; - CalculationType sin_dlon = sin(dlon); - CalculationType cos_dlon = cos(dlon); - CalculationType cos_lat1 = cos(lat1); - CalculationType cos_lat2 = cos(lat2); - CalculationType sin_lat1 = sin(lat1); - CalculationType sin_lat2 = sin(lat2); - - a1 = atan2(sin_dlon * cos_lat2, - cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon); - - a2 = atan2(-sin_dlon * cos_lat1, - cos_lat2 * sin_lat1 - sin_lat2 * cos_lat1 * cos_dlon); - a2 += math::pi<CalculationType>(); + return geometry::formula::vertex_latitude<CalculationType, geographic_tag> + ::apply(lat1, alp1, strategy.model()); } +}; + +template <typename CS_Tag> +class envelope_segment_impl +{ +private: // degrees or radians template <typename CalculationType> @@ -134,8 +107,8 @@ private: static CalculationType const pi_half = math::half_pi<CalculationType>(); return (a1 < a2) - ? (a1 < pi_half && pi_half < a2) - : (a1 > pi_half && pi_half > a2); + ? (a1 < pi_half && pi_half < a2) + : (a1 > pi_half && pi_half > a2); } // radians or degrees @@ -151,21 +124,13 @@ private: return math::abs(lon1 - lon2) > constants::half_period(); // > pi } - // radians - template <typename CalculationType> - static inline CalculationType max_latitude(CalculationType const& azimuth, - CalculationType const& latitude) - { - // azimuth and latitude are assumed to be in radians - return acos( math::abs(cos(latitude) * sin(azimuth)) ); - } - // degrees or radians - template <typename Units, typename CalculationType> + template <typename Units, typename CalculationType, typename Strategy> static inline void compute_box_corners(CalculationType& lon1, CalculationType& lat1, CalculationType& lon2, - CalculationType& lat2) + CalculationType& lat2, + Strategy const& strategy) { // coordinates are assumed to be in radians BOOST_GEOMETRY_ASSERT(lon1 <= lon2); @@ -175,13 +140,14 @@ private: CalculationType lon2_rad = math::as_radian<Units>(lon2); CalculationType lat2_rad = math::as_radian<Units>(lat2); - CalculationType a1 = 0, a2 = 0; - azimuths(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); + CalculationType a1, a2; + strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); if (lat1 > lat2) { std::swap(lat1, lat2); std::swap(lat1_rad, lat2_rad); + std::swap(a1, a2); } if (math::equals(a1, a2)) @@ -192,12 +158,16 @@ private: if (contains_pi_half(a1, a2)) { + CalculationType p_max = envelope_segment_call_vertex_latitude + <CalculationType, CS_Tag>::apply(lat1_rad, a1, strategy); + CalculationType const mid_lat = lat1 + lat2; if (mid_lat < 0) { // update using min latitude - CalculationType const lat_min_rad = -max_latitude(a1, lat1_rad); - CalculationType const lat_min = math::from_radian<Units>(lat_min_rad); + CalculationType const lat_min_rad = -p_max; + CalculationType const lat_min + = math::from_radian<Units>(lat_min_rad); if (lat1 > lat_min) { @@ -207,8 +177,9 @@ private: else if (mid_lat > 0) { // update using max latitude - CalculationType const lat_max_rad = max_latitude(a1, lat1_rad); - CalculationType const lat_max = math::from_radian<Units>(lat_max_rad); + CalculationType const lat_max_rad = p_max; + CalculationType const lat_max + = math::from_radian<Units>(lat_max_rad); if (lat2 < lat_max) { @@ -218,11 +189,12 @@ private: } } - template <typename Units, typename CalculationType> + template <typename Units, typename CalculationType, typename Strategy> static inline void apply(CalculationType& lon1, CalculationType& lat1, CalculationType& lon2, - CalculationType& lat2) + CalculationType& lat2, + Strategy const& strategy) { typedef math::detail::constants_on_spheroid < @@ -278,16 +250,22 @@ private: swap(lon1, lat1, lon2, lat2); } - compute_box_corners<Units>(lon1, lat1, lon2, lat2); + compute_box_corners<Units>(lon1, lat1, lon2, lat2, strategy); } public: - template <typename Units, typename CalculationType, typename Box> + template < + typename Units, + typename CalculationType, + typename Box, + typename Strategy + > static inline void apply(CalculationType lon1, CalculationType lat1, CalculationType lon2, CalculationType lat2, - Box& mbr) + Box& mbr, + Strategy const& strategy) { typedef typename coordinate_type<Box>::type box_coordinate_type; @@ -298,7 +276,7 @@ public: helper_box_type radian_mbr; - apply<Units>(lon1, lat1, lon2, lat2); + apply<Units>(lon1, lat1, lon2, lat2, strategy); geometry::set < @@ -324,29 +302,42 @@ public: } }; +template <std::size_t Dimension, std::size_t DimensionCount> +struct envelope_one_segment +{ + template<typename Point, typename Box, typename Strategy> + static inline void apply(Point const& p1, + Point const& p2, + Box& mbr, + Strategy const& strategy) + { + envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr, strategy); + detail::expand::point_loop + < + strategy::compare::default_strategy, + strategy::compare::default_strategy, + Dimension, + DimensionCount + >::apply(mbr, p2, strategy); + } +}; + template <std::size_t DimensionCount> -struct envelope_segment_on_sphere +struct envelope_segment { - template <typename Point, typename Box> - static inline void apply(Point const& p1, Point const& p2, Box& mbr) + template <typename Point, typename Box, typename Strategy> + static inline void apply(Point const& p1, + Point const& p2, + Box& mbr, + Strategy const& strategy) { // first compute the envelope range for the first two coordinates - Point p1_normalized = detail::return_normalized<Point>(p1); - Point p2_normalized = detail::return_normalized<Point>(p2); - - typedef typename coordinate_system<Point>::type::units units_type; - - compute_mbr_of_segment::template apply<units_type>( - geometry::get<0>(p1_normalized), - geometry::get<1>(p1_normalized), - geometry::get<0>(p2_normalized), - geometry::get<1>(p2_normalized), - mbr); + strategy.apply(p1, p2, mbr); // now compute the envelope range for coordinates of // dimension 2 and higher - envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr); + envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy); } template <typename Segment, typename Box> @@ -359,21 +350,6 @@ struct envelope_segment_on_sphere } }; - - -template <std::size_t DimensionCount, typename CS_Tag> -struct envelope_segment - : envelope_one_segment<0, DimensionCount> -{}; - - -template <std::size_t DimensionCount> -struct envelope_segment<DimensionCount, spherical_equatorial_tag> - : envelope_segment_on_sphere<DimensionCount> -{}; - - - }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL @@ -383,23 +359,24 @@ namespace dispatch { -template <typename Segment, typename CS_Tag> -struct envelope<Segment, segment_tag, CS_Tag> +template <typename Segment> +struct envelope<Segment, segment_tag> { - template <typename Box> - static inline void apply(Segment const& segment, Box& mbr) + template <typename Box, typename Strategy> + static inline void apply(Segment const& segment, + Box& mbr, + Strategy const& strategy) { 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]); detail::envelope::envelope_segment < - dimension<Segment>::value, CS_Tag - >::apply(p[0], p[1], mbr); + dimension<Segment>::value + >::apply(p[0], p[1], mbr, strategy); } }; - } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index eab73ea680..9625f18426 100644 --- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -3,7 +3,12 @@ // 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. +// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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. @@ -20,6 +25,7 @@ #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/interior_rings.hpp> @@ -32,21 +38,37 @@ #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/range.hpp> +#include <boost/geometry/views/detail/normalized_view.hpp> + +#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> +#include <boost/geometry/strategies/spherical/ssf.hpp> + namespace boost { namespace geometry { +// TODO: dispatch only by SideStrategy instead of Geometry/CSTag? + // Since these vectors (though ray would be a better name) are used in the // implementation of equals() for Areal geometries the internal representation -// should be consistent with the default side strategy for CS because currently -// it's used in other relops. - -template < +// should be consistent with the side strategy. +template +< typename T, typename Geometry, + typename SideStrategy, typename CSTag = typename cs_tag<Geometry>::type > struct collected_vector + : nyi::not_implemented_tag +{}; + +// compatible with side_by_triangle cartesian strategy +template <typename T, typename Geometry, typename CT, typename CSTag> +struct collected_vector + < + T, Geometry, strategy::side::side_by_triangle<CT>, CSTag + > { typedef T type; @@ -136,8 +158,13 @@ private: //T dx_0, dy_0; }; -template <typename T, typename Geometry> -struct collected_vector<T, Geometry, spherical_equatorial_tag> +// Compatible with spherical_side_formula which currently +// is the default spherical and geographical strategy +template <typename T, typename Geometry, typename CT, typename CSTag> +struct collected_vector + < + T, Geometry, strategy::side::spherical_side_formula<CT>, CSTag + > { typedef T type; @@ -232,11 +259,27 @@ private: vector_type next; // used for collinearity check }; -template <typename T, typename Geometry> -struct collected_vector<T, Geometry, spherical_polar_tag> - : public collected_vector<T, Geometry, spherical_equatorial_tag> +// Specialization for spherical polar +template <typename T, typename Geometry, typename CT> +struct collected_vector + < + T, Geometry, + strategy::side::spherical_side_formula<CT>, + spherical_polar_tag + > + : public collected_vector + < + T, Geometry, + strategy::side::spherical_side_formula<CT>, + spherical_equatorial_tag + > { - typedef collected_vector<T, Geometry, spherical_equatorial_tag> base_type; + typedef collected_vector + < + T, Geometry, + strategy::side::spherical_side_formula<CT>, + spherical_equatorial_tag + > base_type; collected_vector() {} @@ -265,24 +308,6 @@ private: } }; -// This is consistent with the currently used default geographic side -// and intersection strategies. Spherical strategies are used by default. -// When default strategies are changed in the future this specialization -// should be changed too. -template <typename T, typename Geometry> -struct collected_vector<T, Geometry, geographic_tag> - : public collected_vector<T, Geometry, spherical_equatorial_tag> -{ - typedef collected_vector<T, Geometry, spherical_equatorial_tag> base_type; - - collected_vector() {} - - template <typename Point> - collected_vector(Point const& p1, Point const& p2) - : base_type(p1, p2) - {} -}; - #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace collect_vectors @@ -297,6 +322,18 @@ struct range_collect_vectors static inline void apply(Collection& collection, Range const& range) { + typedef geometry::detail::normalized_view + < + Range const + > normalized_range_type; + + apply_impl(collection, normalized_range_type(range)); + } + +private: + template <typename NormalizedRange> + static inline void apply_impl(Collection& collection, NormalizedRange const& range) + { if (boost::size(range) < 2) { return; @@ -305,7 +342,7 @@ struct range_collect_vectors typedef typename boost::range_size<Collection>::type collection_size_t; collection_size_t c_old_size = boost::size(collection); - typedef typename boost::range_iterator<Range const>::type iterator; + typedef typename boost::range_iterator<NormalizedRange const>::type iterator; bool is_first = true; iterator it = boost::begin(range); diff --git a/boost/geometry/algorithms/detail/expand/box.hpp b/boost/geometry/algorithms/detail/expand/box.hpp index 4c89e6f1d4..3edb23f5ae 100644 --- a/boost/geometry/algorithms/detail/expand/box.hpp +++ b/boost/geometry/algorithms/detail/expand/box.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -44,16 +45,18 @@ namespace detail { namespace expand struct box_on_spheroid { - template <typename BoxOut, typename BoxIn> - static inline void apply(BoxOut& box_out, BoxIn const& box_in) + template <typename BoxOut, typename BoxIn, typename Strategy> + static inline void apply(BoxOut& box_out, + BoxIn const& box_in, + Strategy const& strategy) { // normalize both boxes and convert box-in to be of type of box-out BoxOut mbrs[2]; - detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0]); - detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1]); + detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0], strategy); + detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1], strategy); // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out); + detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out, strategy); } }; diff --git a/boost/geometry/algorithms/detail/expand/indexed.hpp b/boost/geometry/algorithms/detail/expand/indexed.hpp index bdd6eb4506..28cf0e2e4f 100644 --- a/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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 @@ -49,8 +50,8 @@ template > struct indexed_loop { - template <typename Box, typename Geometry> - static inline void apply(Box& box, Geometry const& source) + template <typename Box, typename Geometry, typename Strategy> + static inline void apply(Box& box, Geometry const& source, Strategy const& strategy) { typedef typename strategy::compare::detail::select_strategy < @@ -87,7 +88,7 @@ struct indexed_loop < StrategyLess, StrategyGreater, Index, Dimension + 1, DimensionCount - >::apply(box, source); + >::apply(box, source, strategy); } }; @@ -103,8 +104,8 @@ struct indexed_loop Index, DimensionCount, DimensionCount > { - template <typename Box, typename Geometry> - static inline void apply(Box&, Geometry const&) {} + template <typename Box, typename Geometry, typename Strategy> + static inline void apply(Box&, Geometry const&, Strategy const&) {} }; @@ -117,20 +118,22 @@ template > struct expand_indexed { - template <typename Box, typename Geometry> - static inline void apply(Box& box, Geometry const& geometry) + template <typename Box, typename Geometry, typename Strategy> + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { indexed_loop < StrategyLess, StrategyGreater, 0, Dimension, DimensionCount - >::apply(box, geometry); + >::apply(box, geometry, strategy); indexed_loop < StrategyLess, StrategyGreater, 1, Dimension, DimensionCount - >::apply(box, geometry); + >::apply(box, geometry, strategy); } }; diff --git a/boost/geometry/algorithms/detail/expand/interface.hpp b/boost/geometry/algorithms/detail/expand/interface.hpp index 140754af4e..5aacd8e72a 100644 --- a/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/boost/geometry/algorithms/detail/expand/interface.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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 @@ -28,10 +29,50 @@ #include <boost/geometry/algorithms/dispatch/expand.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> + +#include <boost/geometry/strategies/envelope.hpp> +#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> +#include <boost/geometry/strategies/spherical/envelope_segment.hpp> +#include <boost/geometry/strategies/geographic/envelope_segment.hpp> namespace boost { namespace geometry { +namespace resolve_strategy +{ + +template <typename Geometry> +struct expand +{ + template <typename Box, typename Strategy> + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) + { + dispatch::expand<Box, Geometry>::apply(box, geometry, strategy); + } + + template <typename Box> + static inline void apply(Box& box, + Geometry const& geometry, + default_strategy) + { + typedef typename point_type<Geometry>::type point_type; + typedef typename coordinate_type<point_type>::type coordinate_type; + + typedef typename strategy::envelope::services::default_strategy + < + typename cs_tag<point_type>::type, + coordinate_type + >::type strategy_type; + + dispatch::expand<Box, Geometry>::apply(box, geometry, strategy_type()); + } +}; + +} //namespace resolve_strategy + namespace resolve_variant { @@ -39,40 +80,48 @@ namespace resolve_variant template <typename Geometry> struct expand { - template <typename Box> - static inline void apply(Box& box, Geometry const& geometry) + template <typename Box, typename Strategy> + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { concepts::check<Box>(); concepts::check<Geometry const>(); concepts::check_concepts_and_equal_dimensions<Box, Geometry const>(); - dispatch::expand<Box, Geometry>::apply(box, geometry); + resolve_strategy::expand<Geometry>::apply(box, geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename Box> + template <typename Box, typename Strategy> struct visitor: boost::static_visitor<void> { Box& m_box; + Strategy const& m_strategy; - visitor(Box& box) : m_box(box) {} + visitor(Box& box, Strategy const& strategy) + : m_box(box) + , m_strategy(strategy) + {} template <typename Geometry> void operator()(Geometry const& geometry) const { - return expand<Geometry>::apply(m_box, geometry); + return expand<Geometry>::apply(m_box, geometry, m_strategy); } }; - template <class Box> + template <class Box, typename Strategy> static inline void apply(Box& box, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Box>(box), geometry); + return boost::apply_visitor(visitor<Box, Strategy>(box, strategy), + geometry); } }; @@ -106,21 +155,43 @@ inline void expand(Box& box, Geometry const& geometry, } ***/ +/*! +\brief Expands (with strategy) +\ingroup expand +\tparam Box type of the box +\tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{expand} +\param box box to be expanded using another geometry, mutable +\param geometry \param_geometry geometry which envelope (bounding box) +\param strategy \param_strategy{expand} +will be added to the box + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/expand.qbk]} + */ +template <typename Box, typename Geometry, typename Strategy> +inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy) +{ + + resolve_variant::expand<Geometry>::apply(box, geometry, strategy); +} /*! -\brief Expands a box using the bounding box (envelope) of another geometry (box, point) +\brief Expands a box using the bounding box (envelope) of another geometry +(box, point) \ingroup expand \tparam Box type of the box \tparam Geometry \tparam_geometry \param box box to be expanded using another geometry, mutable -\param geometry \param_geometry geometry which envelope (bounding box) will be added to the box +\param geometry \param_geometry geometry which envelope (bounding box) will be +added to the box \qbk{[include reference/algorithms/expand.qbk]} */ template <typename Box, typename Geometry> inline void expand(Box& box, Geometry const& geometry) { - resolve_variant::expand<Geometry>::apply(box, geometry); + resolve_variant::expand<Geometry>::apply(box, geometry, default_strategy()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/expand/point.hpp b/boost/geometry/algorithms/detail/expand/point.hpp index 56b7f1c738..f0cbd1db02 100644 --- a/boost/geometry/algorithms/detail/expand/point.hpp +++ b/boost/geometry/algorithms/detail/expand/point.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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 @@ -59,8 +60,8 @@ template > struct point_loop { - template <typename Box, typename Point> - static inline void apply(Box& box, Point const& source) + template <typename Box, typename Point, typename Strategy> + static inline void apply(Box& box, Point const& source, Strategy const& strategy) { typedef typename strategy::compare::detail::select_strategy < @@ -95,22 +96,24 @@ struct point_loop point_loop < StrategyLess, StrategyGreater, Dimension + 1, DimensionCount - >::apply(box, source); + >::apply(box, source, strategy); } }; template < - typename StrategyLess, typename StrategyGreater, std::size_t DimensionCount + typename StrategyLess, + typename StrategyGreater, + std::size_t DimensionCount > struct point_loop < StrategyLess, StrategyGreater, DimensionCount, DimensionCount > { - template <typename Box, typename Point> - static inline void apply(Box&, Point const&) {} + template <typename Box, typename Point, typename Strategy> + static inline void apply(Box&, Point const&, Strategy const&) {} }; @@ -123,8 +126,10 @@ template > struct point_loop_on_spheroid { - template <typename Box, typename Point> - static inline void apply(Box& box, Point const& point) + template <typename Box, typename Point, typename Strategy> + static inline void apply(Box& box, + Point const& point, + Strategy const& strategy) { typedef typename point_type<Box>::type box_point_type; typedef typename coordinate_type<Box>::type box_coordinate_type; @@ -224,7 +229,7 @@ struct point_loop_on_spheroid point_loop < StrategyLess, StrategyGreater, 2, DimensionCount - >::apply(box, point); + >::apply(box, point, strategy); } }; diff --git a/boost/geometry/algorithms/detail/expand/segment.hpp b/boost/geometry/algorithms/detail/expand/segment.hpp index 041c1e175f..0570e944d4 100644 --- a/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/boost/geometry/algorithms/detail/expand/segment.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -39,25 +40,29 @@ namespace boost { namespace geometry namespace detail { namespace expand { - -struct segment_on_sphere +struct segment { - template <typename Box, typename Segment> - static inline void apply(Box& box, Segment const& segment) + template <typename Box, typename Segment, typename Strategy> + static inline void apply(Box& box, + Segment const& segment, + Strategy const& strategy) { Box mbrs[2]; // compute the envelope of the segment - detail::envelope::envelope_segment_on_sphere + 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]); + detail::envelope::envelope_segment < dimension<Segment>::value - >::apply(segment, mbrs[0]); + >::apply(p[0], p[1], mbrs[0], strategy); // normalize the box - detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1]); + detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1], strategy); // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box); + detail::envelope::envelope_range_of_boxes::apply(mbrs, box, strategy); } }; @@ -69,7 +74,6 @@ struct segment_on_sphere namespace dispatch { - template < typename Box, typename Segment, @@ -103,13 +107,27 @@ struct expand StrategyLess, StrategyGreater, box_tag, segment_tag, spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::segment_on_sphere + > : detail::expand::segment {}; +template +< + typename Box, typename Segment, + typename StrategyLess, typename StrategyGreater +> +struct expand + < + Box, Segment, + StrategyLess, StrategyGreater, + box_tag, segment_tag, + geographic_tag, geographic_tag + > : detail::expand::segment +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry + #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp index 24746ac627..9a388a4d80 100644 --- a/boost/geometry/algorithms/detail/has_self_intersections.hpp +++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -1,6 +1,11 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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 @@ -12,6 +17,8 @@ #include <deque> #include <boost/range.hpp> +#include <boost/throw_exception.hpp> + #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> @@ -59,8 +66,9 @@ namespace detail { namespace overlay { -template <typename Geometry, typename RobustPolicy> +template <typename Geometry, typename Strategy, typename RobustPolicy> inline bool has_self_intersections(Geometry const& geometry, + Strategy const& strategy, RobustPolicy const& robust_policy, bool throw_on_self_intersection = true) { @@ -73,7 +81,7 @@ inline bool has_self_intersections(Geometry const& geometry, std::deque<turn_info> turns; detail::disjoint::disjoint_interrupt_policy policy; - geometry::self_turns<detail::overlay::assign_null_policy>(geometry, robust_policy, turns, policy); + geometry::self_turns<detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy); #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS bool first = true; @@ -113,7 +121,7 @@ inline bool has_self_intersections(Geometry const& geometry, #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) if (throw_on_self_intersection) { - throw overlay_invalid_input_exception(); + BOOST_THROW_EXCEPTION(overlay_invalid_input_exception()); } #endif return true; @@ -132,11 +140,16 @@ inline bool has_self_intersections(Geometry const& geometry, typedef typename geometry::rescale_policy_type<point_type>::type rescale_policy_type; + typename strategy::intersection::services::default_strategy + < + typename cs_tag<Geometry>::type + >::type strategy; + rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry); - return has_self_intersections(geometry, robust_policy, - throw_on_self_intersection); + return has_self_intersections(geometry, strategy, robust_policy, + throw_on_self_intersection); } diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp index e0955de3d8..0efc9731b5 100644 --- a/boost/geometry/algorithms/detail/intersection/interface.hpp +++ b/boost/geometry/algorithms/detail/intersection/interface.hpp @@ -2,8 +2,8 @@ // 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. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,12 +15,14 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP -// TODO: those headers probably may be removed -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/algorithms/intersects.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -51,10 +53,11 @@ struct intersection typedef typename boost::range_value<GeometryOut>::type OneOut; intersection_insert - < - Geometry1, Geometry2, OneOut, - overlay_intersection - >::apply(geometry1, geometry2, robust_policy, range::back_inserter(geometry_out), strategy); + < + Geometry1, Geometry2, OneOut, + overlay_intersection + >::apply(geometry1, geometry2, robust_policy, + range::back_inserter(geometry_out), strategy); return true; } @@ -84,11 +87,12 @@ struct intersection GeometryOut& out, Strategy const& strategy) { - return intersection< - Geometry2, Geometry1, - Tag2, Tag1, - false - >::apply(g2, g1, robust_policy, out, strategy); + return intersection + < + Geometry2, Geometry1, + Tag2, Tag1, + false + >::apply(g2, g1, robust_policy, out, strategy); } }; @@ -96,47 +100,93 @@ struct intersection } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH - + +namespace resolve_strategy { + +struct intersection +{ + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename GeometryOut, + typename Strategy + > + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + GeometryOut & geometry_out, + Strategy const& strategy) + { + return dispatch::intersection + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, robust_policy, geometry_out, + strategy); + } + + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename GeometryOut + > + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + GeometryOut & geometry_out, + default_strategy) + { + typedef typename strategy::relate::services::default_strategy + < + Geometry1, Geometry2 + >::type strategy_type; + + return dispatch::intersection + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, robust_policy, geometry_out, + strategy_type()); + } +}; + +} // resolve_strategy + + namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct intersection { - template <typename GeometryOut> - static inline bool - apply( - const Geometry1& geometry1, - const Geometry2& geometry2, - GeometryOut& geometry_out) + template <typename GeometryOut, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename geometry::rescale_overlay_policy_type - < - Geometry1, - Geometry2 - >::type rescale_policy_type; + < + Geometry1, + Geometry2 + >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); - typedef intersection_strategies - < - typename cs_tag<Geometry1>::type, - Geometry1, - Geometry2, - typename geometry::point_type<Geometry1>::type, - rescale_policy_type - > strategy; - - return dispatch::intersection - < - Geometry1, - Geometry2 - >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy()); + return resolve_strategy::intersection::apply(geometry1, + geometry2, + robust_policy, + geometry_out, + strategy); } }; @@ -144,40 +194,43 @@ struct intersection template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { - template <typename GeometryOut> + template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; GeometryOut& m_geometry_out; + Strategy const& m_strategy; visitor(Geometry2 const& geometry2, - GeometryOut& geometry_out) + GeometryOut& geometry_out, + Strategy const& strategy) : m_geometry2(geometry2) , m_geometry_out(geometry_out) + , m_strategy(strategy) {} template <typename Geometry1> - result_type operator()(Geometry1 const& geometry1) const + bool operator()(Geometry1 const& geometry1) const { return intersection - < - Geometry1, - Geometry2 - >::template apply - < - GeometryOut - > - (geometry1, m_geometry2, m_geometry_out); + < + Geometry1, + Geometry2 + >::apply(geometry1, m_geometry2, m_geometry_out, m_strategy); } }; - template <typename GeometryOut> + template <typename GeometryOut, typename Strategy> static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, - GeometryOut& geometry_out) + GeometryOut& geometry_out, + Strategy const& strategy) { - return boost::apply_visitor(visitor<GeometryOut>(geometry2, geometry_out), geometry1); + return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry2, + geometry_out, + strategy), + geometry1); } }; @@ -185,40 +238,43 @@ struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename GeometryOut> + template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; GeometryOut& m_geometry_out; + Strategy const& m_strategy; visitor(Geometry1 const& geometry1, - GeometryOut& geometry_out) + GeometryOut& geometry_out, + Strategy const& strategy) : m_geometry1(geometry1) , m_geometry_out(geometry_out) + , m_strategy(strategy) {} template <typename Geometry2> - result_type operator()(Geometry2 const& geometry2) const + bool operator()(Geometry2 const& geometry2) const { return intersection - < - Geometry1, - Geometry2 - >::template apply - < - GeometryOut - > - (m_geometry1, geometry2, m_geometry_out); + < + Geometry1, + Geometry2 + >::apply(m_geometry1, geometry2, m_geometry_out, m_strategy); } }; - template <typename GeometryOut> + template <typename GeometryOut, typename Strategy> static inline bool apply(Geometry1 const& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2, - GeometryOut& geometry_out) + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) { - return boost::apply_visitor(visitor<GeometryOut>(geometry1, geometry_out), geometry2); + return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry1, + geometry_out, + strategy), + geometry2); } }; @@ -226,38 +282,39 @@ struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > 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> + template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { GeometryOut& m_geometry_out; + Strategy const& m_strategy; - visitor(GeometryOut& geometry_out) + visitor(GeometryOut& geometry_out, Strategy const& strategy) : m_geometry_out(geometry_out) + , m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> - result_type operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const { return intersection - < - Geometry1, - Geometry2 - >::template apply - < - GeometryOut - > - (geometry1, geometry2, m_geometry_out); + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, m_geometry_out, m_strategy); } }; - template <typename GeometryOut> + template <typename GeometryOut, typename Strategy> static inline bool - apply(const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2, - GeometryOut& geometry_out) + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) { - return boost::apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2); + return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry_out, + strategy), + geometry1, geometry2); } }; @@ -272,32 +329,66 @@ struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIAN \tparam Geometry2 \tparam_geometry \tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box) +\tparam Strategy \tparam_strategy{Intersection} \param geometry1 \param_geometry \param geometry2 \param_geometry \param geometry_out The output geometry, either a multi_point, multi_polygon, multi_linestring, or a box (for intersection of two boxes) +\param strategy \param_strategy{intersection} +\qbk{distinguish,with strategy} \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename Geometry1, typename Geometry2, - typename GeometryOut + typename GeometryOut, + typename Strategy > inline bool intersection(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out) + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) { return resolve_variant::intersection < - Geometry1, - Geometry2 - >::template apply + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, geometry_out, strategy); +} + + +/*! +\brief \brief_calc2{intersection} +\ingroup intersection +\details \details_calc2{intersection, spatial set theoretic intersection}. +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which + the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box) +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param geometry_out The output geometry, either a multi_point, multi_polygon, + multi_linestring, or a box (for intersection of two boxes) + +\qbk{[include reference/algorithms/intersection.qbk]} +*/ +template +< + typename Geometry1, + typename Geometry2, + typename GeometryOut +> +inline bool intersection(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out) +{ + return resolve_variant::intersection < - GeometryOut - > - (geometry1, geometry2, geometry_out); + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, geometry_out, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/is_simple/always_simple.hpp b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp index 91e2ef76bd..5cec5e1924 100644 --- a/boost/geometry/algorithms/detail/is_simple/always_simple.hpp +++ b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -27,7 +28,8 @@ namespace detail { namespace is_simple template <typename Geometry> struct always_simple { - static inline bool apply(Geometry const&) + template <typename Strategy> + static inline bool apply(Geometry const&, Strategy const&) { return true; } diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp index a2322e4831..d4d6db9bce 100644 --- a/boost/geometry/algorithms/detail/is_simple/areal.hpp +++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -37,6 +38,12 @@ namespace detail { namespace is_simple template <typename Ring> struct is_simple_ring { + template <typename Strategy> + static inline bool apply(Ring const& ring, Strategy const&) + { + return apply(ring); + } + static inline bool apply(Ring const& ring) { simplicity_failure_policy policy; @@ -69,6 +76,12 @@ private: } public: + template <typename Strategy> + static inline bool apply(Polygon const& polygon, Strategy const&) + { + return apply(polygon); + } + static inline bool apply(Polygon const& polygon) { return @@ -119,7 +132,8 @@ struct is_simple<Polygon, polygon_tag> template <typename MultiPolygon> struct is_simple<MultiPolygon, multi_polygon_tag> { - static inline bool apply(MultiPolygon const& multipolygon) + template <typename Strategy> + static inline bool apply(MultiPolygon const& multipolygon, Strategy const&) { return detail::check_iterator_range diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp index 6d425232b0..af0127dc75 100644 --- a/boost/geometry/algorithms/detail/is_simple/interface.hpp +++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -17,46 +18,106 @@ #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { +namespace resolve_strategy +{ + +struct is_simple +{ + template <typename Geometry, typename Strategy> + static inline bool apply(Geometry const& geometry, + Strategy const& strategy) + { + return dispatch::is_simple<Geometry>::apply(geometry, strategy); + } + + template <typename Geometry> + static inline bool apply(Geometry const& geometry, + default_strategy) + { + // NOTE: Currently the strategy is only used for Linear geometries + typedef typename strategy::intersection::services::default_strategy + < + typename cs_tag<Geometry>::type + >::type strategy_type; + + return dispatch::is_simple<Geometry>::apply(geometry, strategy_type()); + } +}; -namespace resolve_variant { +} // namespace resolve_strategy + +namespace resolve_variant +{ template <typename Geometry> struct is_simple { - static inline bool apply(Geometry const& geometry) + template <typename Strategy> + static inline bool apply(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); - return dispatch::is_simple<Geometry>::apply(geometry); + + return resolve_strategy::is_simple::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename Strategy> struct visitor : boost::static_visitor<bool> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + template <typename Geometry> bool operator()(Geometry const& geometry) const { - return is_simple<Geometry>::apply(geometry); + return is_simple<Geometry>::apply(geometry, m_strategy); } }; + template <typename Strategy> static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) + apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, + Strategy const& strategy) { - return boost::apply_visitor(visitor(), geometry); + return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant +/*! +\brief \brief_check{is simple} +\ingroup is_simple +\tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{Is_simple} +\param geometry \param_geometry +\param strategy \param_strategy{is_simple} +\return \return_check{is simple} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/is_simple.qbk]} +*/ +template <typename Geometry, typename Strategy> +inline bool is_simple(Geometry const& geometry, Strategy const& strategy) +{ + return resolve_variant::is_simple<Geometry>::apply(geometry, strategy); +} + /*! \brief \brief_check{is simple} @@ -70,7 +131,7 @@ struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > template <typename Geometry> inline bool is_simple(Geometry const& geometry) { - return resolve_variant::is_simple<Geometry>::apply(geometry); + return resolve_variant::is_simple<Geometry>::apply(geometry, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp index 16d7b3a803..52b9d9d1c8 100644 --- a/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -48,6 +49,8 @@ #include <boost/geometry/algorithms/dispatch/is_simple.hpp> +#include <boost/geometry/strategies/intersection.hpp> + namespace boost { namespace geometry { @@ -186,8 +189,8 @@ private: }; -template <typename Linear> -inline bool has_self_intersections(Linear const& linear) +template <typename Linear, typename Strategy> +inline bool has_self_intersections(Linear const& linear, Strategy const& strategy) { typedef typename point_type<Linear>::type point_type; @@ -218,6 +221,7 @@ inline bool has_self_intersections(Linear const& linear) < turn_policy >::apply(linear, + strategy, detail::no_rescale_policy(), turns, interrupt_policy); @@ -243,8 +247,19 @@ struct is_simple_linestring && ! detail::is_valid::has_spikes < Linestring, closed - >::apply(linestring, policy) - && ! (CheckSelfIntersections && has_self_intersections(linestring)); + >::apply(linestring, policy); + } +}; + +template <typename Linestring> +struct is_simple_linestring<Linestring, true> +{ + template <typename Strategy> + static inline bool apply(Linestring const& linestring, + Strategy const& strategy) + { + return is_simple_linestring<Linestring, false>::apply(linestring) + && ! has_self_intersections(linestring, strategy); } }; @@ -252,7 +267,9 @@ struct is_simple_linestring template <typename MultiLinestring> struct is_simple_multilinestring { - static inline bool apply(MultiLinestring const& multilinestring) + template <typename Strategy> + static inline bool apply(MultiLinestring const& multilinestring, + Strategy const& strategy) { // check each of the linestrings for simplicity // but do not compute self-intersections yet; these will be @@ -272,7 +289,7 @@ struct is_simple_multilinestring return false; } - return ! has_self_intersections(multilinestring); + return ! has_self_intersections(multilinestring, strategy); } }; diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp index f9f43d1cdb..61f0bc9130 100644 --- a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp +++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -38,7 +39,8 @@ namespace detail { namespace is_simple template <typename MultiPoint> struct is_simple_multipoint { - static inline bool apply(MultiPoint const& multipoint) + template <typename Strategy> + static inline bool apply(MultiPoint const& multipoint, Strategy const&) { if (boost::empty(multipoint)) { diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp index 863ce625fe..69a4d4e78e 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -71,8 +71,8 @@ struct has_valid_corners<Box, 0> template <typename Box> struct is_valid_box { - template <typename VisitPolicy> - static inline bool apply(Box const& box, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Box const& box, VisitPolicy& visitor, Strategy const&) { return ! has_invalid_coordinate<Box>::apply(box, visitor) 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 0a81213743..b91dc6a697 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,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -69,10 +70,11 @@ public: > turn_type; // returns true if all turns are valid - template <typename Turns, typename VisitPolicy> + template <typename Turns, typename VisitPolicy, typename Strategy> static inline bool apply(Geometry const& geometry, Turns& turns, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const& strategy) { boost::ignore_unused(visitor); @@ -85,6 +87,7 @@ public: > interrupt_policy; geometry::self_turns<turn_policy>(geometry, + strategy, robust_policy, turns, interrupt_policy); @@ -101,11 +104,11 @@ public: } // returns true if all turns are valid - template <typename VisitPolicy> - static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { std::vector<turn_type> turns; - return apply(geometry, turns, visitor); + return apply(geometry, turns, visitor, strategy); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp index 5a04a92824..ee013377c4 100644 --- a/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -23,48 +24,88 @@ #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> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { + +namespace resolve_strategy +{ + +struct is_valid +{ + template <typename Geometry, typename VisitPolicy, typename Strategy> + static inline bool apply(Geometry const& geometry, + VisitPolicy& visitor, + Strategy const& strategy) + { + return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy); + } + + template <typename Geometry, typename VisitPolicy> + static inline bool apply(Geometry const& geometry, + VisitPolicy& visitor, + default_strategy) + { + // NOTE: Currently the strategy is only used for Areal geometries + typedef typename strategy::intersection::services::default_strategy + < + typename cs_tag<Geometry>::type + >::type strategy_type; + + return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy_type()); + } +}; +} // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_variant +{ template <typename Geometry> struct is_valid { - template <typename VisitPolicy> - static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Geometry const& geometry, + VisitPolicy& visitor, + Strategy const& strategy) { concepts::check<Geometry const>(); - return dispatch::is_valid<Geometry>::apply(geometry, visitor); + + return resolve_strategy::is_valid::apply(geometry, visitor, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> struct visitor : boost::static_visitor<bool> { - visitor(VisitPolicy& policy) : m_policy(policy) {} + visitor(VisitPolicy& policy, Strategy const& strategy) + : m_policy(policy) + , m_strategy(strategy) + {} template <typename Geometry> bool operator()(Geometry const& geometry) const { - return is_valid<Geometry>::apply(geometry, m_policy); + return is_valid<Geometry>::apply(geometry, m_policy, m_strategy); } VisitPolicy& m_policy; + Strategy const& m_strategy; }; - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - VisitPolicy& policy_visitor) + VisitPolicy& policy_visitor, + Strategy const& strategy) { - return boost::apply_visitor(visitor<VisitPolicy>(policy_visitor), + return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy), geometry); } }; @@ -73,10 +114,12 @@ struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > // Undocumented for now -template <typename Geometry, typename VisitPolicy> -inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor) +template <typename Geometry, typename VisitPolicy, typename Strategy> +inline bool is_valid(Geometry const& geometry, + VisitPolicy& visitor, + Strategy const& strategy) { - return resolve_variant::is_valid<Geometry>::apply(geometry, visitor); + return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); } @@ -84,6 +127,29 @@ inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor) \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{Is_valid} +\param geometry \param_geometry +\param strategy \param_strategy{is_valid} +\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 strategy} +\qbk{[include reference/algorithms/is_valid.qbk]} +*/ +template <typename Geometry, typename Strategy> +inline bool is_valid(Geometry const& geometry, Strategy const& strategy) +{ + is_valid_default_policy<> visitor; + return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); +} + +/*! +\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); furthermore, the following geometries are considered valid: @@ -96,8 +162,7 @@ inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor) template <typename Geometry> inline bool is_valid(Geometry const& geometry) { - is_valid_default_policy<> policy_visitor; - return geometry::is_valid(geometry, policy_visitor); + return is_valid(geometry, default_strategy()); } @@ -105,6 +170,33 @@ inline bool is_valid(Geometry const& geometry) \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{Is_valid} +\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 +\param strategy \param_strategy{is_valid} +\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 and strategy} +\qbk{[include reference/algorithms/is_valid_with_failure.qbk]} +*/ +template <typename Geometry, typename Strategy> +inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy) +{ + failure_type_policy<> visitor; + bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); + failure = 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 failure An enumeration value indicating that the geometry is valid or not, and if not valid indicating the reason why @@ -120,10 +212,7 @@ inline bool is_valid(Geometry const& geometry) template <typename Geometry> inline bool is_valid(Geometry const& geometry, validity_failure_type& failure) { - failure_type_policy<> policy_visitor; - bool result = geometry::is_valid(geometry, policy_visitor); - failure = policy_visitor.failure(); - return result; + return is_valid(geometry, failure, default_strategy()); } @@ -131,28 +220,52 @@ inline bool is_valid(Geometry const& geometry, validity_failure_type& failure) \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry +\tparam Strategy \tparam_strategy{Is_valid} \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 +\param strategy \param_strategy{is_valid} \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{distinguish,with message and strategy} \qbk{[include reference/algorithms/is_valid_with_message.qbk]} */ -template <typename Geometry> -inline bool is_valid(Geometry const& geometry, std::string& message) +template <typename Geometry, typename Strategy> +inline bool is_valid(Geometry const& geometry, std::string& message, Strategy const& strategy) { std::ostringstream stream; - failing_reason_policy<> policy_visitor(stream); - bool result = geometry::is_valid(geometry, policy_visitor); + failing_reason_policy<> visitor(stream); + bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); message = stream.str(); 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) +{ + return is_valid(geometry, message, default_strategy()); +} + }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp index a49e077237..6bc6b86cf8 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -77,6 +77,14 @@ struct is_valid_linestring } return ! has_spikes<Linestring, closed>::apply(linestring, visitor); } + + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Linestring const& linestring, + VisitPolicy& visitor, + Strategy const&) + { + return apply(linestring, visitor); + } }; @@ -142,9 +150,10 @@ private: }; public: - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiLinestring const& multilinestring, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const&) { if (BOOST_GEOMETRY_CONDITION( AllowEmptyMultiGeometries && boost::empty(multilinestring))) diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp index 0025445c2c..84dacc57f1 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -43,6 +43,8 @@ #include <boost/geometry/algorithms/dispatch/is_valid.hpp> +#include <boost/geometry/strategies/intersection.hpp> + namespace boost { namespace geometry { @@ -109,10 +111,10 @@ private: geometry::partition < - geometry::model::box<typename point_type<MultiPolygon>::type>, - typename base::expand_box, - typename base::overlaps_box - >::apply(polygon_iterators, item_visitor); + geometry::model::box<typename point_type<MultiPolygon>::type> + >::apply(polygon_iterators, item_visitor, + typename base::expand_box(), + typename base::overlaps_box()); if (item_visitor.items_overlap) { @@ -235,23 +237,28 @@ private: } - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> struct per_polygon { - per_polygon(VisitPolicy& policy) : m_policy(policy) {} + per_polygon(VisitPolicy& policy, Strategy const& strategy) + : m_policy(policy) + , m_strategy(strategy) + {} template <typename Polygon> inline bool apply(Polygon const& polygon) const { - return base::apply(polygon, m_policy); + return base::apply(polygon, m_policy, m_strategy); } VisitPolicy& m_policy; + Strategy const& m_strategy; }; public: - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiPolygon const& multipolygon, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const& strategy) { typedef debug_validity_phase<MultiPolygon> debug_phase; @@ -266,11 +273,11 @@ public: if (! detail::check_iterator_range < - per_polygon<VisitPolicy>, + per_polygon<VisitPolicy, Strategy>, false // do not check for empty multipolygon (done above) >::apply(boost::begin(multipolygon), boost::end(multipolygon), - per_polygon<VisitPolicy>(visitor))) + per_polygon<VisitPolicy, Strategy>(visitor, strategy))) { return false; } @@ -283,7 +290,7 @@ public: std::deque<typename has_valid_turns::turn_type> turns; bool has_invalid_turns = - ! has_valid_turns::apply(multipolygon, turns, visitor); + ! has_valid_turns::apply(multipolygon, turns, visitor, strategy); debug_print_turns(turns.begin(), turns.end()); if (has_invalid_turns) diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp index 51035f7a73..f77f7a35eb 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -36,8 +36,8 @@ namespace dispatch template <typename Point> struct is_valid<Point, point_tag> { - template <typename VisitPolicy> - static inline bool apply(Point const& point, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Point const& point, VisitPolicy& visitor, Strategy const&) { boost::ignore_unused(visitor); return ! detail::is_valid::has_invalid_coordinate @@ -56,9 +56,10 @@ struct is_valid<Point, point_tag> template <typename MultiPoint, bool AllowEmptyMultiGeometries> struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries> { - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiPoint const& multipoint, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const&) { boost::ignore_unused(multipoint, visitor); diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp index bbe8e8fc39..f7e22fb8d2 100644 --- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -74,10 +75,13 @@ class is_valid_polygon protected: typedef debug_validity_phase<Polygon> debug_phase; - template <typename VisitPolicy> + template <typename VisitPolicy, typename Strategy> struct per_ring { - per_ring(VisitPolicy& policy) : m_policy(policy) {} + per_ring(VisitPolicy& policy, Strategy const& strategy) + : m_policy(policy) + , m_strategy(strategy) + {} template <typename Ring> inline bool apply(Ring const& ring) const @@ -85,30 +89,34 @@ protected: return detail::is_valid::is_valid_ring < Ring, false, true - >::apply(ring, m_policy); + >::apply(ring, m_policy, m_strategy); } VisitPolicy& m_policy; + Strategy const& m_strategy; }; - template <typename InteriorRings, typename VisitPolicy> + template <typename InteriorRings, typename VisitPolicy, typename Strategy> static bool has_valid_interior_rings(InteriorRings const& interior_rings, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const& strategy) { return detail::check_iterator_range < - per_ring<VisitPolicy>, + per_ring<VisitPolicy, Strategy>, true // allow for empty interior ring range >::apply(boost::begin(interior_rings), boost::end(interior_rings), - per_ring<VisitPolicy>(visitor)); + per_ring<VisitPolicy, Strategy>(visitor, strategy)); } struct has_valid_rings { - template <typename VisitPolicy> - static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Polygon const& polygon, + VisitPolicy& visitor, + Strategy const& strategy) { typedef typename ring_type<Polygon>::type ring_type; @@ -119,7 +127,7 @@ protected: < ring_type, false // do not check self intersections - >::apply(exterior_ring(polygon), visitor)) + >::apply(exterior_ring(polygon), visitor, strategy)) { return false; } @@ -128,7 +136,8 @@ protected: debug_phase::apply(2); return has_valid_interior_rings(geometry::interior_rings(polygon), - visitor); + visitor, + strategy); } }; @@ -246,10 +255,8 @@ protected: geometry::partition < - geometry::model::box<typename point_type<Polygon>::type>, - expand_box, - overlaps_box - >::apply(ring_iterators, item_visitor); + geometry::model::box<typename point_type<Polygon>::type> + >::apply(ring_iterators, item_visitor, expand_box(), overlaps_box()); if (item_visitor.items_overlap) { @@ -346,10 +353,12 @@ protected: }; public: - template <typename VisitPolicy> - static inline bool apply(Polygon const& polygon, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Polygon const& polygon, + VisitPolicy& visitor, + Strategy const& strategy) { - if (! has_valid_rings::apply(polygon, visitor)) + if (! has_valid_rings::apply(polygon, visitor, strategy)) { return false; } @@ -366,7 +375,7 @@ public: std::deque<typename has_valid_turns::turn_type> turns; bool has_invalid_turns - = ! has_valid_turns::apply(polygon, turns, visitor); + = ! has_valid_turns::apply(polygon, turns, visitor, strategy); debug_print_turns(turns.begin(), turns.end()); if (has_invalid_turns) diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp index 925c03a472..9ab68fdc48 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -101,26 +101,21 @@ struct ring_area_predicate<ResultType, true> template <typename Ring, bool IsInteriorRing> struct is_properly_oriented { - typedef typename point_type<Ring>::type point_type; - - typedef typename strategy::area::services::default_strategy - < - typename cs_tag<point_type>::type, - point_type - >::type strategy_type; + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor, + Strategy const& strategy) + { + boost::ignore_unused(visitor); - typedef detail::area::ring_area - < - order_as_direction<geometry::point_order<Ring>::value>::value, - geometry::closure<Ring>::value - > ring_area_type; + typedef typename point_type<Ring>::type point_type; - typedef typename default_area_result<Ring>::type area_result_type; + typedef detail::area::ring_area + < + order_as_direction<geometry::point_order<Ring>::value>::value, + geometry::closure<Ring>::value + > ring_area_type; - template <typename VisitPolicy> - static inline bool apply(Ring const& ring, VisitPolicy& visitor) - { - boost::ignore_unused(visitor); + typedef typename default_area_result<Ring>::type area_result_type; typename ring_area_predicate < @@ -128,8 +123,11 @@ struct is_properly_oriented >::type predicate; // Check area - area_result_type const zero = area_result_type(); - if (predicate(ring_area_type::apply(ring, strategy_type()), zero)) + area_result_type const zero = 0; + area_result_type const area + = ring_area_type::apply(ring, + strategy.template get_area_strategy<point_type>()); + if (predicate(area, zero)) { return visitor.template apply<no_failure>(); } @@ -150,8 +148,9 @@ template > struct is_valid_ring { - template <typename VisitPolicy> - static inline bool apply(Ring const& ring, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Ring const& ring, VisitPolicy& visitor, + Strategy const& strategy) { // return invalid if any of the following condition holds: // (a) the ring's point coordinates are not invalid (e.g., NaN) @@ -198,8 +197,8 @@ struct is_valid_ring && ! 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); + || has_valid_self_turns<Ring>::apply(ring, visitor, strategy)) + && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp index f92f73381f..30cbf7afdb 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-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, 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 @@ -44,8 +44,8 @@ namespace dispatch template <typename Segment> struct is_valid<Segment, segment_tag> { - template <typename VisitPolicy> - static inline bool apply(Segment const& segment, VisitPolicy& visitor) + template <typename VisitPolicy, typename Strategy> + static inline bool apply(Segment const& segment, VisitPolicy& visitor, Strategy const&) { boost::ignore_unused(visitor); diff --git a/boost/geometry/algorithms/detail/not.hpp b/boost/geometry/algorithms/detail/not.hpp index 43e71e2e37..95cdfa24e6 100644 --- a/boost/geometry/algorithms/detail/not.hpp +++ b/boost/geometry/algorithms/detail/not.hpp @@ -4,10 +4,11 @@ // 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. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017, 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. @@ -46,6 +47,14 @@ struct not_ { return ! Policy::apply(geometry1, geometry2); } + + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return ! Policy::apply(geometry1, geometry2, strategy); + } }; diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 047eb4993e..2408b4b68e 100644 --- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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) @@ -258,8 +262,9 @@ inline void assign_parents(Geometry1 const& geometry1, geometry::partition < - box_type, ring_info_helper_get_box, ring_info_helper_ovelaps_box - >::apply(vector, visitor); + box_type + >::apply(vector, visitor, ring_info_helper_get_box(), + ring_info_helper_ovelaps_box()); } if (check_for_orientation) diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp index a8171e1482..9beb8ad64f 100644 --- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp +++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, 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) @@ -106,19 +110,27 @@ class backtrack_check_self_intersections public : typedef state state_type; - template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy, typename Visitor> + template + < + typename Operation, + typename Rings, typename Ring, typename Turns, + typename Strategy, + typename RobustPolicy, + typename Visitor + > static inline void apply(std::size_t size_at_start, - Rings& rings, Ring& ring, - Turns& turns, - typename boost::range_value<Turns>::type const& turn, - Operation& operation, - traverse_error_type traverse_error, - Geometry1 const& geometry1, - Geometry2 const& geometry2, - RobustPolicy const& robust_policy, - state_type& state, - Visitor& visitor - ) + Rings& rings, + Ring& ring, + Turns& turns, + typename boost::range_value<Turns>::type const& turn, + Operation& operation, + traverse_error_type traverse_error, + Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy, + RobustPolicy const& robust_policy, + state_type& state, + Visitor& visitor) { visitor.visit_traverse_reject(turns, turn, operation, traverse_error); @@ -128,8 +140,8 @@ public : if (! state.m_checked) { state.m_checked = true; - has_self_intersections(geometry1, robust_policy); - has_self_intersections(geometry2, robust_policy); + has_self_intersections(geometry1, strategy, robust_policy); + has_self_intersections(geometry2, strategy, robust_policy); } // Make bad output clean diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index b9e48cdbfc..c249ff57ff 100644 --- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -1,5 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. + // Copyright (c) 2014-2015, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. @@ -15,6 +17,7 @@ #include <iterator> #include <boost/range.hpp> +#include <boost/throw_exception.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/tag.hpp> @@ -307,7 +310,7 @@ public: #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) if (enter_count != 0) { - throw inconsistent_turns_exception(); + BOOST_THROW_EXCEPTION(inconsistent_turns_exception()); } #else BOOST_GEOMETRY_ASSERT(enter_count == 0); diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp index 99281eaecb..94667d0ed0 100644 --- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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) @@ -39,29 +44,33 @@ template > struct get_turn_without_info { - template <typename RobustPolicy, typename OutputIterator> + template <typename Strategy, typename RobustPolicy, typename OutputIterator> static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/, Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/, bool /*is_p_first*/, bool /*is_p_last*/, bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& , + Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator out) { - typedef intersection_strategies - < - typename cs_tag<typename TurnInfo::point_type>::type, - Point1, - Point2, - typename TurnInfo::point_type, - RobustPolicy - > si; + typedef typename TurnInfo::point_type turn_point_type; - typedef typename si::segment_intersection_strategy_type strategy; + typedef policies::relate::segments_intersection_points + < + segment_intersection_points + < + turn_point_type, + typename geometry::segment_ratio_type + < + turn_point_type, RobustPolicy + >::type + > + > policy_type; typedef model::referring_segment<Point1 const> segment_type1; - typedef model::referring_segment<Point1 const> segment_type2; + typedef model::referring_segment<Point2 const> segment_type2; segment_type1 p1(pi, pj); segment_type2 q1(qi, qj); @@ -75,15 +84,14 @@ struct get_turn_without_info geometry::recalculate(pj_rob, pj, robust_policy); geometry::recalculate(qi_rob, qi, robust_policy); geometry::recalculate(qj_rob, qj, robust_policy); - typename strategy::return_type result - = strategy::apply(p1, q1, robust_policy, - pi_rob, pj_rob, qi_rob, qj_rob); + typename policy_type::return_type result + = strategy.apply(p1, q1, policy_type(), robust_policy, + pi_rob, pj_rob, qi_rob, qj_rob); - for (std::size_t i = 0; i < result.template get<0>().count; i++) + for (std::size_t i = 0; i < result.count; i++) { - TurnInfo tp; - geometry::convert(result.template get<0>().intersections[i], tp.point); + geometry::convert(result.intersections[i], tp.point); *out++ = tp; } @@ -102,12 +110,14 @@ template typename Geometry1, typename Geometry2, typename RobustPolicy, - typename Turns + typename Turns, + typename Strategy > inline void get_intersection_points(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, - Turns& turns) + Turns& turns, + Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>(); @@ -142,6 +152,7 @@ inline void get_intersection_points(Geometry1 const& geometry1, >::type::apply( 0, geometry1, 1, geometry2, + strategy, robust_policy, turns, interrupt_policy); } diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index a4cce3fd32..08bc342186 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -1,9 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -16,10 +17,10 @@ #include <boost/core/ignore_unused.hpp> +#include <boost/throw_exception.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> -#include <boost/geometry/strategies/intersection_strategies.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> @@ -644,7 +645,7 @@ struct collinear : public base_turn_handler // causes currently cycling include problems typedef typename geometry::coordinate_type<Point1>::type ctype; ctype const dx = get<0>(a) - get<0>(b); - ctype const dy = get<1>(b) - get<1>(b); + ctype const dy = get<1>(a) - get<1>(b); return dx * dx + dy * dy; } }; @@ -930,6 +931,7 @@ struct get_turn_info typename Point1, typename Point2, typename TurnInfo, + typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > @@ -939,13 +941,19 @@ struct get_turn_info bool /*is_p_first*/, bool /*is_p_last*/, bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& tp_model, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, OutputIterator out) { - typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> - inters_info; + typedef intersection_info + < + Point1, Point2, + typename TurnInfo::point_type, + IntersectionStrategy, + RobustPolicy + > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); + inters_info inters(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy); char const method = inters.d_info().how; @@ -991,9 +999,12 @@ struct get_turn_info < typename inters_info::cs_tag, typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type + typename inters_info::robust_point1_type, + typename inters_info::side_strategy_type > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk()); + inters.rpi(), inters.rpj(), inters.rpk(), + inters.get_side_strategy()); + policy::template apply<1>(qi, qj, qk, pi, pj, pk, tp, inters.i_info(), inters.d_info(), swapped_side_calc); @@ -1093,7 +1104,7 @@ struct get_turn_info std::cout << "TURN: Unknown method: " << method << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) - throw turn_info_exception(method); + BOOST_THROW_EXCEPTION(turn_info_exception(method)); #endif } break; 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 85cdfbc02d..48716634c5 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 @@ -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, 2017. +// Modifications copyright (c) 2013-2017 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_FOR_ENDPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP @@ -427,8 +427,11 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { - side_calculator<cs_tag, RobustPoint1, RobustPoint2, RobustPoint2> - side_calc(ri2, ri1, rj1, ri2, rj2, rk2); + side_calculator<cs_tag, + RobustPoint1, RobustPoint2, + typename IntersectionInfo::side_strategy_type, + RobustPoint2> + side_calc(ri2, ri1, rj1, ri2, rj2, rk2, inters.get_side_strategy()); std::pair<operation_type, operation_type> operations = operations_of_equal(side_calc); @@ -478,8 +481,10 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { - side_calculator<cs_tag, RobustPoint1, RobustPoint2, RobustPoint2> - side_calc(ri2, rj1, ri1, ri2, rj2, rk2); + side_calculator<cs_tag, RobustPoint1, RobustPoint2, + typename IntersectionInfo::side_strategy_type, + RobustPoint2> + side_calc(ri2, rj1, ri1, ri2, rj2, rk2, inters.get_side_strategy()); std::pair<operation_type, operation_type> operations = operations_of_equal(side_calc); 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 3e7da1d797..5f2cb07faf 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -2,15 +2,15 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 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_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP @@ -37,32 +37,27 @@ struct turn_operation_linear }; template <typename TurnPointCSTag, typename PointP, typename PointQ, + typename SideStrategy, typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ > struct side_calculator { - // This strategy should be the same as side strategy defined in - // intersection_strategies<> which is used in various places - // of the library - typedef typename strategy::side::services::default_strategy - < - TurnPointCSTag - >::type side; - inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, - Qi const& qi, Qj const& qj, Qk const& qk) + Qi const& qi, Qj const& qj, Qk const& qk, + SideStrategy const& side_strategy) : m_pi(pi), m_pj(pj), m_pk(pk) , m_qi(qi), m_qj(qj), m_qk(qk) + , m_side_strategy(side_strategy) {} - inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); } - inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); } - inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); } - inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); } + inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); } + inline int pk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_pk); } + inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); } + inline int qk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_qk); } - inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); } - inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); } + inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); } + inline int qk_wrt_p2() const { return m_side_strategy.apply(m_pj, m_pk, m_qk); } Pi const& m_pi; Pj const& m_pj; @@ -70,6 +65,8 @@ struct side_calculator Qi const& m_qi; Qj const& m_qj; Qk const& m_qk; + + SideStrategy const& m_side_strategy; }; template <typename Point1, typename Point2, typename RobustPolicy> @@ -99,7 +96,7 @@ struct robust_points robust_point2_type m_rqi, m_rqj, m_rqk; }; -template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy> +template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy> class intersection_info_base : private robust_points<Point1, Point2, RobustPolicy> { @@ -114,14 +111,17 @@ public: typedef typename cs_tag<TurnPoint>::type cs_tag; - typedef side_calculator<cs_tag, robust_point1_type, robust_point2_type> side_calculator_type; + typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; + typedef side_calculator<cs_tag, robust_point1_type, robust_point2_type, side_strategy_type> side_calculator_type; intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) : base(pi, pj, pk, qi, qj, qk, robust_policy) , m_side_calc(base::m_rpi, base::m_rpj, base::m_rpk, - base::m_rqi, base::m_rqj, base::m_rqk) + base::m_rqi, base::m_rqj, base::m_rqk, + intersection_strategy.get_side_strategy()) , m_pi(pi), m_pj(pj), m_pk(pk) , m_qi(qi), m_qj(qj), m_qk(qk) {} @@ -155,8 +155,8 @@ private: point2_type const& m_qk; }; -template <typename Point1, typename Point2, typename TurnPoint> -class intersection_info_base<Point1, Point2, TurnPoint, detail::no_rescale_policy> +template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy> +class intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, detail::no_rescale_policy> { public: typedef Point1 point1_type; @@ -167,12 +167,15 @@ public: typedef typename cs_tag<TurnPoint>::type cs_tag; - typedef side_calculator<cs_tag, Point1, Point2> side_calculator_type; + typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; + typedef side_calculator<cs_tag, Point1, Point2, side_strategy_type> side_calculator_type; intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, + IntersectionStrategy const& intersection_strategy, no_rescale_policy const& /*robust_policy*/) - : m_side_calc(pi, pj, pk, qi, qj, qk) + : m_side_calc(pi, pj, pk, qi, qj, qk, + intersection_strategy.get_side_strategy()) {} inline Point1 const& pi() const { return m_side_calc.m_pi; } @@ -203,40 +206,58 @@ template typename Point1, typename Point2, typename TurnPoint, + typename IntersectionStrategy, typename RobustPolicy > class intersection_info - : public intersection_info_base<Point1, Point2, TurnPoint, RobustPolicy> + : public intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy> { - typedef intersection_info_base<Point1, Point2, TurnPoint, RobustPolicy> base; + typedef intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy> base; + +public: + typedef segment_intersection_points + < + TurnPoint, + typename geometry::segment_ratio_type + < + TurnPoint, RobustPolicy + >::type + > intersection_point_type; - typedef typename intersection_strategies + // NOTE: formerly defined in intersection_strategies + typedef policies::relate::segments_tupled < - typename base::cs_tag, - Point1, - Point2, - TurnPoint, - RobustPolicy - >::segment_intersection_strategy_type strategy; + policies::relate::segments_intersection_points + < + intersection_point_type + >, + policies::relate::segments_direction + > intersection_policy_type; + + typedef IntersectionStrategy intersection_strategy_type; + typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; -public: typedef model::referring_segment<Point1 const> segment_type1; typedef model::referring_segment<Point2 const> segment_type2; typedef typename base::side_calculator_type side_calculator_type; - typedef typename strategy::return_type result_type; + typedef typename intersection_policy_type::return_type result_type; typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) - : base(pi, pj, pk, qi, qj, qk, robust_policy) - , m_result(strategy::apply(segment_type1(pi, pj), - segment_type2(qi, qj), - robust_policy, - base::rpi(), base::rpj(), - base::rqi(), base::rqj())) + : base(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy) + , m_result(intersection_strategy.apply( + segment_type1(pi, pj), + segment_type2(qi, qj), + intersection_policy_type(), + robust_policy, + base::rpi(), base::rpj(), + base::rqi(), base::rqj())) + , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) {} @@ -244,6 +265,16 @@ public: inline i_info_type const& i_info() const { return m_result.template get<0>(); } inline d_info_type const& d_info() const { return m_result.template get<1>(); } + inline intersection_strategy_type const& get_intersection_strategy() const + { + return m_intersection_strategy; + } + + inline side_strategy_type get_side_strategy() const + { + return m_intersection_strategy.get_side_strategy(); + } + // TODO: it's more like is_spike_ip_p inline bool is_spike_p() const { @@ -307,17 +338,18 @@ private: { typedef model::referring_segment<Point const> seg; - typedef intersection_strategies - < - typename base::cs_tag, Point, Point, Point, RobustPolicy - > si; - - typedef typename si::segment_intersection_strategy_type strategy; - - typename strategy::return_type result - = strategy::apply(seg(i, j), seg(j, k), m_robust_policy); + // no need to calcualte direction info + typedef policies::relate::segments_intersection_points + < + intersection_point_type + > policy_type; + + typename policy_type::return_type const result + = m_intersection_strategy.apply(seg(i, j), seg(j, k), + policy_type(), + m_robust_policy); - return result.template get<0>().count == 2; + return result.count == 2; } template <std::size_t OpId> @@ -344,6 +376,7 @@ private: } result_type m_result; + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; }; 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 121728d822..46c1305cd7 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -1,9 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -14,6 +15,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP +#include <boost/throw_exception.hpp> + #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> @@ -41,6 +44,7 @@ struct get_turn_info_linear_areal typename Point1, typename Point2, typename TurnInfo, + typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > @@ -50,13 +54,19 @@ struct get_turn_info_linear_areal bool is_p_first, bool is_p_last, bool is_q_first, bool is_q_last, TurnInfo const& tp_model, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, OutputIterator out) { - typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> - inters_info; + typedef intersection_info + < + Point1, Point2, + typename TurnInfo::point_type, + IntersectionStrategy, + RobustPolicy + > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); + inters_info inters(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy); char const method = inters.d_info().how; @@ -108,9 +118,11 @@ struct get_turn_info_linear_areal < typename inters_info::cs_tag, typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type + typename inters_info::robust_point1_type, + typename inters_info::side_strategy_type > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk()); + inters.rpi(), inters.rpj(), inters.rpk(), + inters.get_side_strategy()); policy::template apply<1>(qi, qj, qk, pi, pj, pk, tp, inters.i_info(), inters.d_info(), swapped_side_calc); @@ -395,7 +407,7 @@ struct get_turn_info_linear_areal std::cout << "TURN: Unknown method: " << method << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) - throw turn_info_exception(method); + BOOST_THROW_EXCEPTION(turn_info_exception(method)); #endif } break; @@ -747,6 +759,9 @@ struct get_turn_info_linear_areal } else { + typedef typename IntersectionInfo::robust_point1_type rp1_type; + typedef typename IntersectionInfo::robust_point2_type rp2_type; + method_type replaced_method = method_touch_interior; if ( ip0.is_qj ) @@ -754,11 +769,12 @@ struct get_turn_info_linear_areal side_calculator < typename IntersectionInfo::cs_tag, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point2_type, - typename IntersectionInfo::robust_point2_type + rp1_type, rp2_type, + typename IntersectionInfo::side_strategy_type, + rp2_type > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), - inters.rqi(), inters.rqj(), inters.rqk()); + inters.rqi(), inters.rqj(), inters.rqk(), + inters.get_side_strategy()); std::pair<operation_type, operation_type> operations = get_info_e::operations_of_equal(side_calc); @@ -773,16 +789,13 @@ struct get_turn_info_linear_areal side_calculator < typename IntersectionInfo::cs_tag, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point2_type, - typename IntersectionInfo::robust_point2_type, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point2_type, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point2_type + rp1_type, rp2_type, + typename IntersectionInfo::side_strategy_type, + rp2_type, rp1_type, rp1_type, + rp2_type, rp1_type, rp2_type > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), - inters.rqi(), inters.rpi(), inters.rqj()); + inters.rqi(), inters.rpi(), inters.rqj(), + inters.get_side_strategy()); std::pair<operation_type, operation_type> operations = get_info_e::operations_of_equal(side_calc); @@ -832,9 +845,11 @@ struct get_turn_info_linear_areal typename IntersectionInfo::cs_tag, typename IntersectionInfo::robust_point1_type, typename IntersectionInfo::robust_point2_type, + typename IntersectionInfo::side_strategy_type, typename IntersectionInfo::robust_point2_type > side_calc(inters.rqi(), inters.rpj(), inters.rpi(), - inters.rqi(), inters.rqj(), inters.rqk()); + inters.rqi(), inters.rqj(), inters.rqk(), + inters.get_side_strategy()); std::pair<operation_type, operation_type> operations = get_info_e::operations_of_equal(side_calc); 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 6bb3a74bb8..58fd4bb5c7 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -1,19 +1,22 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 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_LL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP +#include <boost/throw_exception.hpp> + #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> @@ -36,6 +39,7 @@ struct get_turn_info_linear_linear typename Point1, typename Point2, typename TurnInfo, + typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > @@ -45,13 +49,19 @@ struct get_turn_info_linear_linear bool is_p_first, bool is_p_last, bool is_q_first, bool is_q_last, TurnInfo const& tp_model, + IntersectionStrategy const& strategy, RobustPolicy const& robust_policy, OutputIterator out) { - typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy> - inters_info; + typedef intersection_info + < + Point1, Point2, + typename TurnInfo::point_type, + IntersectionStrategy, + RobustPolicy + > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy); + inters_info inters(pi, pj, pk, qi, qj, qk, strategy, robust_policy); char const method = inters.d_info().how; @@ -103,9 +113,11 @@ struct get_turn_info_linear_linear < typename inters_info::cs_tag, typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type + typename inters_info::robust_point1_type, + typename inters_info::side_strategy_type > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk()); + inters.rpi(), inters.rpj(), inters.rpk(), + inters.get_side_strategy()); policy::template apply<1>(qi, qj, qk, pi, pj, pk, tp, inters.i_info(), inters.d_info(), @@ -463,7 +475,7 @@ struct get_turn_info_linear_linear std::cout << "TURN: Unknown method: " << method << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) - throw turn_info_exception(method); + BOOST_THROW_EXCEPTION(turn_info_exception(method)); #endif } break; diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 1eb18b74d4..4e97a84a37 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -3,15 +3,15 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 2016. -// Modifications copyright (c) 2014, 2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2016, 2017. +// Modifications copyright (c) 2014-2017 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_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP @@ -45,7 +45,6 @@ #include <boost/geometry/iterators/ever_circling_iterator.hpp> -#include <boost/geometry/strategies/cartesian/cart_intersect.hpp> #include <boost/geometry/strategies/intersection_strategies.hpp> #include <boost/geometry/strategies/intersection_result.hpp> @@ -174,11 +173,12 @@ class get_turns_in_sections public : // Returns true if terminated, false if interrupted - template <typename Turns, typename RobustPolicy, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( int source_id1, Geometry1 const& geometry1, Section1 const& sec1, int source_id2, Geometry2 const& geometry2, Section2 const& sec2, bool skip_larger, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) @@ -295,7 +295,8 @@ public : TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2, is_1_first, is_1_last, is_2_first, is_2_last, - ti, robust_policy, std::back_inserter(turns)); + ti, intersection_strategy, robust_policy, + std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -381,9 +382,10 @@ template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, - typename Turns, typename TurnPolicy, + typename IntersectionStrategy, typename RobustPolicy, + typename Turns, typename InterruptPolicy > struct section_visitor @@ -392,16 +394,20 @@ struct section_visitor Geometry1 const& m_geometry1; int m_source_id2; Geometry2 const& m_geometry2; + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; section_visitor(int id1, Geometry1 const& g1, - int id2, Geometry2 const& g2, - RobustPolicy const& robust_policy, - Turns& turns, InterruptPolicy& ip) + int id2, Geometry2 const& g2, + IntersectionStrategy const& intersection_strategy, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& ip) : m_source_id1(id1), m_geometry1(g1) , m_source_id2(id2), m_geometry2(g2) + , m_intersection_strategy(intersection_strategy) , m_rescale_policy(robust_policy) , m_turns(turns) , m_interrupt_policy(ip) @@ -423,6 +429,7 @@ struct section_visitor m_source_id1, m_geometry1, sec1, m_source_id2, m_geometry2, sec2, false, + m_intersection_strategy, m_rescale_policy, m_turns, m_interrupt_policy); } @@ -441,10 +448,11 @@ class get_turns_generic { public: - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Geometry1 const& geometry1, int source_id2, Geometry2 const& geometry2, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) @@ -475,15 +483,19 @@ public: < Geometry1, Geometry2, Reverse1, Reverse2, - Turns, TurnPolicy, RobustPolicy, InterruptPolicy - > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy); + TurnPolicy, + IntersectionStrategy, RobustPolicy, + Turns, InterruptPolicy + > visitor(source_id1, geometry1, source_id2, geometry2, + intersection_strategy, robust_policy, + turns, interrupt_policy); geometry::partition < - box_type, - detail::section::get_section_box, - detail::section::overlaps_section_box - >::apply(sec1, sec2, visitor); + box_type + >::apply(sec1, sec2, visitor, + detail::section::get_section_box(), + detail::section::overlaps_section_box()); } }; @@ -518,10 +530,11 @@ struct get_turns_cs >::type iterator_type; - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Range const& range, int source_id2, Box const& box, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, @@ -593,8 +606,10 @@ struct get_turns_cs // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes index == 0, size_type(index) == segments_count1, + intersection_strategy, robust_policy, - turns, interrupt_policy); + turns, + interrupt_policy); // Future performance enhancement: // return if told by the interrupt policy } @@ -622,7 +637,7 @@ private: else return 0; } - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2, // Points from a range: point_type const& rp0, @@ -635,6 +650,7 @@ private: box_point_type const& bp3, bool const is_range_first, bool const is_range_last, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, // Output Turns& turns, @@ -653,25 +669,29 @@ private: TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2, is_range_first, is_range_last, true, false, - ti, robust_policy, std::back_inserter(turns)); + ti, intersection_strategy, robust_policy, + std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1); TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3, is_range_first, is_range_last, false, false, - ti, robust_policy, std::back_inserter(turns)); + ti, intersection_strategy, robust_policy, + std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2); TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0, is_range_first, is_range_last, false, false, - ti, robust_policy, std::back_inserter(turns)); + ti, intersection_strategy, robust_policy, + std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3); TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1, is_range_first, is_range_last, false, true, - ti, robust_policy, std::back_inserter(turns)); + ti, intersection_strategy, robust_policy, + std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -691,12 +711,14 @@ template > struct get_turns_polygon_cs { - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Polygon const& polygon, int source_id2, Box const& box, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, - Turns& turns, InterruptPolicy& interrupt_policy, + Turns& turns, + InterruptPolicy& interrupt_policy, signed_size_type multi_index = -1) { typedef typename geometry::ring_type<Polygon>::type ring_type; @@ -711,8 +733,10 @@ struct get_turns_polygon_cs intersector_type::apply( source_id1, geometry::exterior_ring(polygon), source_id2, box, + intersection_strategy, robust_policy, - turns, interrupt_policy, + turns, + interrupt_policy, multi_index, -1); signed_size_type i = 0; @@ -725,6 +749,7 @@ struct get_turns_polygon_cs intersector_type::apply( source_id1, *it, source_id2, box, + intersection_strategy, robust_policy, turns, interrupt_policy, multi_index, i); @@ -742,12 +767,14 @@ template > struct get_turns_multi_polygon_cs { - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Multi const& multi, int source_id2, Box const& box, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, - Turns& turns, InterruptPolicy& interrupt_policy) + Turns& turns, + InterruptPolicy& interrupt_policy) { typedef typename boost::range_iterator < @@ -766,7 +793,8 @@ struct get_turns_multi_polygon_cs Reverse, ReverseBox, TurnPolicy >::apply(source_id1, *it, source_id2, box, - robust_policy, turns, interrupt_policy, i); + intersection_strategy, robust_policy, + turns, interrupt_policy, i); } } }; @@ -918,13 +946,13 @@ template > struct get_turns_reversed { - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> - static inline void apply( - int source_id1, Geometry1 const& g1, - int source_id2, Geometry2 const& g2, - RobustPolicy const& robust_policy, - Turns& turns, - InterruptPolicy& interrupt_policy) + template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> + static inline void apply(int source_id1, Geometry1 const& g1, + int source_id2, Geometry2 const& g2, + IntersectionStrategy const& intersection_strategy, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy) { get_turns < @@ -932,8 +960,9 @@ struct get_turns_reversed Geometry2, Geometry1, Reverse2, Reverse1, TurnPolicy - >::apply(source_id2, g2, source_id1, g1, robust_policy, - turns, interrupt_policy); + >::apply(source_id2, g2, source_id1, g1, + intersection_strategy, robust_policy, + turns, interrupt_policy); } }; @@ -951,6 +980,7 @@ struct get_turns_reversed \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s) \param geometry1 \param_geometry \param geometry2 \param_geometry +\param intersection_strategy segments intersection strategy \param robust_policy policy to handle robustness issues \param turns container which will contain turn points \param interrupt_policy policy determining if process is stopped @@ -962,15 +992,17 @@ template typename AssignPolicy, typename Geometry1, typename Geometry2, + typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void get_turns(Geometry1 const& geometry1, - Geometry2 const& geometry2, - RobustPolicy const& robust_policy, - Turns& turns, - InterruptPolicy& interrupt_policy) + Geometry2 const& geometry2, + IntersectionStrategy const& intersection_strategy, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy) { concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>(); @@ -996,11 +1028,11 @@ inline void get_turns(Geometry1 const& geometry1, Reverse1, Reverse2, TurnPolicy > - >::type::apply( - 0, geometry1, - 1, geometry2, - robust_policy, - turns, interrupt_policy); + >::type::apply(0, geometry1, + 1, geometry2, + intersection_strategy, + robust_policy, + turns, interrupt_policy); } #if defined(_MSC_VER) diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index bb82003a23..3244480f48 100644 --- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -2,10 +2,11 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2015. -// Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 2017. +// Modifications copyright (c) 2014-2017 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 @@ -71,7 +72,7 @@ struct intersection_segment_segment_point Segment2 const& segment2, RobustPolicy const& robust_policy, OutputIterator out, - Strategy const& ) + Strategy const& strategy) { typedef typename point_type<PointOut>::type point_type; @@ -106,16 +107,15 @@ struct intersection_segment_segment_point >::type > intersection_return_type; - typedef strategy::intersection::relate_cartesian_segments + typedef policies::relate::segments_intersection_points < - policies::relate::segments_intersection_points - < - intersection_return_type - > - > policy; + intersection_return_type + > policy_type; - intersection_return_type is = policy::apply(segment1, segment2, - robust_policy, pi_rob, pj_rob, qi_rob, qj_rob); + intersection_return_type + is = strategy.apply(segment1, segment2, + policy_type(), robust_policy, + pi_rob, pj_rob, qi_rob, qj_rob); for (std::size_t i = 0; i < is.count; i++) { @@ -134,13 +134,14 @@ struct intersection_linestring_linestring_point < typename Linestring1, typename Linestring2, typename RobustPolicy, - typename OutputIterator, typename Strategy + typename OutputIterator, + typename Strategy > static inline OutputIterator apply(Linestring1 const& linestring1, Linestring2 const& linestring2, RobustPolicy const& robust_policy, OutputIterator out, - Strategy const& ) + Strategy const& strategy) { typedef typename point_type<PointOut>::type point_type; @@ -151,7 +152,8 @@ struct intersection_linestring_linestring_point > turn_info; std::deque<turn_info> turns; - geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns); + geometry::get_intersection_points(linestring1, linestring2, + robust_policy, turns, strategy); for (typename boost::range_iterator<std::deque<turn_info> const>::type it = boost::begin(turns); it != boost::end(turns); ++it) @@ -295,7 +297,7 @@ struct intersection_of_linestring_with_areal static inline OutputIterator apply(LineString const& linestring, Areal const& areal, RobustPolicy const& robust_policy, OutputIterator out, - Strategy const& ) + Strategy const& strategy) { if (boost::size(linestring) == 0) { @@ -325,7 +327,7 @@ struct intersection_of_linestring_with_areal false, (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), detail::overlay::assign_null_policy - >(linestring, areal, robust_policy, turns, policy); + >(linestring, areal, strategy, robust_policy, turns, policy); if (no_crossing_turns_or_empty(turns)) { @@ -621,7 +623,7 @@ struct intersection_insert static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, - OutputIterator out, Strategy const& ) + OutputIterator out, Strategy const& strategy) { typedef detail::overlay::turn_info @@ -635,7 +637,7 @@ struct intersection_insert geometry::get_turns < false, false, detail::overlay::assign_null_policy - >(geometry1, geometry2, robust_policy, turns, policy); + >(geometry1, geometry2, strategy, robust_policy, turns, policy); for (typename std::vector<turn_info>::const_iterator it = turns.begin(); it != turns.end(); ++it) { @@ -996,7 +998,11 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - typedef typename Strategy::rescale_policy_type rescale_policy_type; + typedef typename geometry::rescale_policy_type + < + typename geometry::point_type<Geometry1>::type // TODO from both + >::type rescale_policy_type; + rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); @@ -1037,22 +1043,13 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - typedef typename geometry::rescale_policy_type - < - typename geometry::point_type<Geometry1>::type // TODO from both - >::type rescale_policy_type; - - typedef intersection_strategies + typedef typename strategy::intersection::services::default_strategy < - typename cs_tag<GeometryOut>::type, - Geometry1, - Geometry2, - typename geometry::point_type<GeometryOut>::type, - rescale_policy_type - > strategy; - + typename cs_tag<GeometryOut>::type + >::type strategy_type; + return intersection_insert<GeometryOut>(geometry1, geometry2, out, - strategy()); + strategy_type()); } }} // namespace detail::intersection diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index 34517f6590..a74bb33ba1 100644 --- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -1,11 +1,12 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP @@ -158,11 +159,13 @@ protected: typename Turns, typename LinearGeometry1, typename LinearGeometry2, + typename IntersectionStrategy, typename RobustPolicy > static inline void compute_turns(Turns& turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, + IntersectionStrategy const& strategy, RobustPolicy const& robust_policy) { turns.clear(); @@ -180,7 +183,7 @@ protected: assign_policy >, RobustPolicy - >::apply(turns, linear1, linear2, interrupt_policy, robust_policy); + >::apply(turns, linear1, linear2, interrupt_policy, strategy, robust_policy); } @@ -237,7 +240,7 @@ public: Linear2 const& linear2, RobustPolicy const& robust_policy, OutputIterator oit, - Strategy const& ) + Strategy const& strategy) { typedef typename detail::relate::turns::get_turns < @@ -255,7 +258,7 @@ public: typedef std::vector<turn_info> turns_container; turns_container turns; - compute_turns(turns, linear1, linear2, robust_policy); + compute_turns(turns, linear1, linear2, strategy, robust_policy); if ( turns.empty() ) { diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp index 09c80025a0..f1af2f1949 100644 --- a/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -3,10 +3,11 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017, 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 @@ -184,7 +185,7 @@ struct overlay Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, - Strategy const& , + Strategy const& strategy, Visitor& visitor) { bool const is_empty1 = geometry::is_empty(geometry1); @@ -233,7 +234,7 @@ std::cout << "get turns" << std::endl; < Reverse1, Reverse2, detail::overlay::assign_null_policy - >(geometry1, geometry2, robust_policy, turns, policy); + >(geometry1, geometry2, strategy, robust_policy, turns, policy); visitor.visit_turns(1, turns); @@ -262,6 +263,7 @@ std::cout << "traverse" << std::endl; traverse<Reverse1, Reverse2, Geometry1, Geometry2, OverlayType>::apply ( geometry1, geometry2, + strategy, robust_policy, turns, rings, clusters, diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp index 156cb54867..a26f54e008 100644 --- a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp @@ -1,12 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2017, 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 // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html -// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle - #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_LINEAR_HPP @@ -69,12 +70,12 @@ struct point_linear_point Linear const& linear, RobustPolicy const&, OutputIterator oit, - Strategy const&) + Strategy const& strategy) { action_selector_pl_l < PointOut, OverlayType - >::apply(point, Policy::apply(point, linear), oit); + >::apply(point, Policy::apply(point, linear, strategy), oit); return oit; } }; @@ -95,7 +96,7 @@ struct multipoint_segment_point Segment const& segment, RobustPolicy const&, OutputIterator oit, - Strategy const&) + Strategy const& strategy) { for (typename boost::range_iterator<MultiPoint const>::type it = boost::begin(multipoint); @@ -105,7 +106,7 @@ struct multipoint_segment_point action_selector_pl_l < PointOut, OverlayType - >::apply(*it, Policy::apply(*it, segment), oit); + >::apply(*it, Policy::apply(*it, segment, strategy), oit); } return oit; @@ -145,11 +146,14 @@ private: } }; - template <typename OutputIterator> + template <typename OutputIterator, typename Strategy> class item_visitor_type { public: - item_visitor_type(OutputIterator& oit) : m_oit(oit) {} + item_visitor_type(OutputIterator& oit, Strategy const& strategy) + : m_oit(oit) + , m_strategy(strategy) + {} template <typename Item1, typename Item2> inline void apply(Item1 const& item1, Item2 const& item2) @@ -157,11 +161,12 @@ private: action_selector_pl_l < PointOut, overlay_intersection - >::apply(item1, Policy::apply(item1, item2), m_oit); + >::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit); } private: OutputIterator& m_oit; + Strategy const& m_strategy; }; // structs for partition -- end @@ -189,12 +194,13 @@ private: Linear const& m_linear; }; - template <typename OutputIterator> + template <typename OutputIterator, typename Strategy> static inline OutputIterator get_common_points(MultiPoint const& multipoint, Linear const& linear, - OutputIterator oit) + OutputIterator oit, + Strategy const& strategy) { - item_visitor_type<OutputIterator> item_visitor(oit); + item_visitor_type<OutputIterator, Strategy> item_visitor(oit, strategy); segment_range rng(linear); @@ -203,10 +209,9 @@ private: geometry::model::box < typename boost::range_value<MultiPoint>::type - >, - expand_box, - overlaps_box - >::apply(multipoint, rng, item_visitor); + > + >::apply(multipoint, rng, item_visitor, + expand_box(), overlaps_box()); return oit; } @@ -228,7 +233,8 @@ public: // compute the common points get_common_points(multipoint, linear, - std::back_inserter(common_points)); + std::back_inserter(common_points), + strategy); return multipoint_multipoint_point < diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index aedf22e1fb..8540ef98a0 100644 --- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 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) @@ -61,20 +66,25 @@ template typename Geometry, typename Turns, typename TurnPolicy, + typename IntersectionStrategy, typename RobustPolicy, typename InterruptPolicy > struct self_section_visitor { Geometry const& m_geometry; + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; inline self_section_visitor(Geometry const& g, - RobustPolicy const& rp, - Turns& turns, InterruptPolicy& ip) + IntersectionStrategy const& is, + RobustPolicy const& rp, + Turns& turns, + InterruptPolicy& ip) : m_geometry(g) + , m_intersection_strategy(is) , m_rescale_policy(rp) , m_turns(turns) , m_interrupt_policy(ip) @@ -97,6 +107,7 @@ struct self_section_visitor 0, m_geometry, sec1, 0, m_geometry, sec2, false, + m_intersection_strategy, m_rescale_policy, m_turns, m_interrupt_policy); } @@ -116,9 +127,10 @@ struct self_section_visitor template<typename TurnPolicy> struct get_turns { - template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Geometry const& geometry, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) @@ -142,17 +154,17 @@ struct get_turns self_section_visitor < Geometry, - Turns, TurnPolicy, RobustPolicy, InterruptPolicy - > visitor(geometry, robust_policy, turns, interrupt_policy); + Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy + > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy); try { geometry::partition < - box_type, - detail::section::get_section_box, - detail::section::overlaps_section_box - >::apply(sec, visitor); + box_type + >::apply(sec, visitor, + detail::section::get_section_box(), + detail::section::overlaps_section_box()); } catch(self_ip_exception const& ) { @@ -208,9 +220,10 @@ struct self_get_turn_points TurnPolicy > { - template <typename RobustPolicy, typename Turns, typename InterruptPolicy> + template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Box const& , + Strategy const& , RobustPolicy const& , Turns& , InterruptPolicy& ) @@ -259,6 +272,7 @@ struct self_get_turn_points \tparam Turns type of intersection container (e.g. vector of "intersection/turn point"'s) \param geometry geometry + \param strategy strategy to be used \param robust_policy policy to handle robustness issues \param turns container which will contain intersection points \param interrupt_policy policy determining if process is stopped @@ -268,13 +282,15 @@ template < typename AssignPolicy, typename Geometry, + typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, - RobustPolicy const& robust_policy, - Turns& turns, InterruptPolicy& interrupt_policy) + IntersectionStrategy const& strategy, + RobustPolicy const& robust_policy, + Turns& turns, InterruptPolicy& interrupt_policy) { concepts::check<Geometry const>(); @@ -285,7 +301,7 @@ inline void self_turns(Geometry const& geometry, typename tag<Geometry>::type, Geometry, turn_policy - >::apply(geometry, robust_policy, turns, interrupt_policy); + >::apply(geometry, strategy, robust_policy, turns, interrupt_policy); } diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp index 5adc0fcf69..bc828920e9 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -140,10 +140,10 @@ struct traversal { for (int i = 0; i < 2; i++) { - turn_operation_type& op = turn.operations[i]; - if (op.visited.none()) + turn_operation_type& turn_op = turn.operations[i]; + if (turn_op.visited.none()) { - op.visited.set_visited(); + turn_op.visited.set_visited(); } } } diff --git a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp index e0dfee19a8..9ab82a77c1 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, 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) @@ -38,6 +42,7 @@ template typename Geometry2, typename Turns, typename Clusters, + typename IntersectionStrategy, typename RobustPolicy, typename Visitor, typename Backtrack @@ -56,12 +61,14 @@ struct traversal_ring_creator inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters const& clusters, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Visitor& visitor) : m_trav(geometry1, geometry2, turns, clusters, robust_policy,visitor) , m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_clusters(clusters) + , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) , m_visitor(visitor) { @@ -280,7 +287,8 @@ struct traversal_ring_creator rings, ring, m_turns, start_turn, m_turns[turn_index].operations[op_index], traverse_error, - m_geometry1, m_geometry2, m_robust_policy, + m_geometry1, m_geometry2, + m_intersection_strategy, m_robust_policy, state, m_visitor); } } @@ -314,6 +322,7 @@ private: Geometry2 const& m_geometry2; Turns& m_turns; Clusters const& m_clusters; + IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; Visitor& m_visitor; }; diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp index f01e50eb03..058f6c9458 100644 --- a/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -58,6 +58,7 @@ class traverse public : template < + typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename Rings, @@ -66,6 +67,7 @@ public : > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, Rings& rings, Clusters& clusters, @@ -88,10 +90,11 @@ public : Reverse1, Reverse2, OverlayType, Geometry1, Geometry2, Turns, Clusters, + IntersectionStrategy, RobustPolicy, Visitor, Backtrack > trav(geometry1, geometry2, turns, clusters, - robust_policy, visitor); + intersection_strategy, robust_policy, visitor); std::size_t finalized_ring_size = boost::size(rings); diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp index 8b19add479..12c6a54661 100644 --- a/boost/geometry/algorithms/detail/partition.hpp +++ b/boost/geometry/algorithms/detail/partition.hpp @@ -2,10 +2,11 @@ // 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. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017 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 @@ -47,13 +48,14 @@ inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) // Divide forward_range into three subsets: lower, upper and oversized // (not-fitting) // (lower == left or bottom, upper == right or top) -template <typename OverlapsPolicy, typename Box, typename IteratorVector> +template <typename Box, typename IteratorVector, typename OverlapsPolicy> inline void divide_into_subsets(Box const& lower_box, - Box const& upper_box, - IteratorVector const& input, - IteratorVector& lower, - IteratorVector& upper, - IteratorVector& exceeding) + Box const& upper_box, + IteratorVector const& input, + IteratorVector& lower, + IteratorVector& upper, + IteratorVector& exceeding, + OverlapsPolicy const& overlaps_policy) { typedef typename boost::range_iterator < @@ -62,8 +64,8 @@ inline void divide_into_subsets(Box const& lower_box, for(it_type it = boost::begin(input); it != boost::end(input); ++it) { - bool const lower_overlapping = OverlapsPolicy::apply(lower_box, **it); - bool const upper_overlapping = OverlapsPolicy::apply(upper_box, **it); + bool const lower_overlapping = overlaps_policy.apply(lower_box, **it); + bool const upper_overlapping = overlaps_policy.apply(upper_box, **it); if (lower_overlapping && upper_overlapping) { @@ -87,23 +89,24 @@ inline void divide_into_subsets(Box const& lower_box, template < - typename ExpandPolicy, typename Box, - typename IteratorVector + typename IteratorVector, + typename ExpandPolicy > -inline void expand_with_elements(Box& total, IteratorVector const& input) +inline void expand_with_elements(Box& total, IteratorVector const& input, + ExpandPolicy const& expand_policy) { typedef typename boost::range_iterator<IteratorVector const>::type it_type; for(it_type it = boost::begin(input); it != boost::end(input); ++it) { - ExpandPolicy::apply(total, **it); + expand_policy.apply(total, **it); } } // Match forward_range with itself -template <typename Policy, typename IteratorVector> -inline void handle_one(IteratorVector const& input, Policy& policy) +template <typename IteratorVector, typename VisitPolicy> +inline void handle_one(IteratorVector const& input, VisitPolicy& visitor) { if (boost::size(input) == 0) { @@ -118,7 +121,7 @@ inline void handle_one(IteratorVector const& input, Policy& policy) it_type it2 = it1; for (++it2; it2 != boost::end(input); ++it2) { - policy.apply(**it1, **it2); + visitor.apply(**it1, **it2); } } } @@ -126,13 +129,13 @@ inline void handle_one(IteratorVector const& input, Policy& policy) // Match forward range 1 with forward range 2 template < - typename Policy, typename IteratorVector1, - typename IteratorVector2 + typename IteratorVector2, + typename VisitPolicy > inline void handle_two(IteratorVector1 const& input1, - IteratorVector2 const& input2, - Policy& policy) + IteratorVector2 const& input2, + VisitPolicy& visitor) { typedef typename boost::range_iterator < @@ -157,14 +160,14 @@ inline void handle_two(IteratorVector1 const& input1, it2 != boost::end(input2); ++it2) { - policy.apply(**it1, **it2); + visitor.apply(**it1, **it2); } } } template <typename IteratorVector> inline bool recurse_ok(IteratorVector const& input, - std::size_t min_elements, std::size_t level) + std::size_t min_elements, std::size_t level) { return boost::size(input) >= min_elements && level < 100; @@ -172,8 +175,8 @@ inline bool recurse_ok(IteratorVector const& input, template <typename IteratorVector1, typename IteratorVector2> inline bool recurse_ok(IteratorVector1 const& input1, - IteratorVector2 const& input2, - std::size_t min_elements, std::size_t level) + IteratorVector2 const& input2, + std::size_t min_elements, std::size_t level) { return boost::size(input1) >= min_elements && recurse_ok(input2, min_elements, level); @@ -186,103 +189,114 @@ template typename IteratorVector3 > inline bool recurse_ok(IteratorVector1 const& input1, - IteratorVector2 const& input2, - IteratorVector3 const& input3, - std::size_t min_elements, std::size_t level) + IteratorVector2 const& input2, + IteratorVector3 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 -> + +template <int Dimension, typename Box> class partition_two_ranges; -template -< - int Dimension, - typename Box, - typename OverlapsPolicy, - typename ExpandPolicy, - typename VisitBoxPolicy -> +template <int Dimension, typename Box> class partition_one_range { - template <typename IteratorVector> - static inline Box get_new_box(IteratorVector const& input) + template <typename IteratorVector, typename ExpandPolicy> + static inline Box get_new_box(IteratorVector const& input, + ExpandPolicy const& expand_policy) { Box box; geometry::assign_inverse(box); - expand_with_elements<ExpandPolicy>(box, input); + expand_with_elements(box, input, expand_policy); return box; } - template <typename Policy, typename IteratorVector> + template + < + typename IteratorVector, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy, + typename VisitBoxPolicy + > static inline void next_level(Box const& box, - IteratorVector const& input, - std::size_t level, std::size_t min_elements, - Policy& policy, VisitBoxPolicy& box_policy) + IteratorVector const& input, + std::size_t level, std::size_t min_elements, + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy, + VisitBoxPolicy& box_policy) { if (recurse_ok(input, min_elements, level)) { partition_one_range - < - 1 - Dimension, - Box, - OverlapsPolicy, - ExpandPolicy, - VisitBoxPolicy - >::apply(box, input, level + 1, min_elements, policy, box_policy); + < + 1 - Dimension, + Box + >::apply(box, input, level + 1, min_elements, + visitor, expand_policy, overlaps_policy, box_policy); } else { - handle_one(input, policy); + handle_one(input, visitor); } } // Function to switch to two forward ranges if there are // geometries exceeding the separation line - template <typename Policy, typename IteratorVector> + template + < + typename IteratorVector, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy, + typename VisitBoxPolicy + > static inline void next_level2(Box const& box, IteratorVector const& input1, IteratorVector const& input2, std::size_t level, std::size_t min_elements, - Policy& policy, VisitBoxPolicy& box_policy) + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy, + VisitBoxPolicy& box_policy) { if (recurse_ok(input1, input2, min_elements, level)) { partition_two_ranges - < - 1 - Dimension, - Box, - OverlapsPolicy, OverlapsPolicy, - ExpandPolicy, ExpandPolicy, - VisitBoxPolicy - >::apply(box, input1, input2, level + 1, min_elements, - policy, box_policy); + < + 1 - Dimension, Box + >::apply(box, input1, input2, level + 1, min_elements, + visitor, expand_policy, overlaps_policy, + expand_policy, overlaps_policy, box_policy); } else { - handle_two(input1, input2, policy); + handle_two(input1, input2, visitor); } } public : - template <typename Policy, typename IteratorVector> + template + < + typename IteratorVector, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy, + typename VisitBoxPolicy + > static inline void apply(Box const& box, - IteratorVector const& input, - std::size_t level, - std::size_t min_elements, - Policy& policy, VisitBoxPolicy& box_policy) + IteratorVector const& input, + std::size_t level, + std::size_t min_elements, + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy, + VisitBoxPolicy& box_policy) { box_policy.apply(box, level); @@ -290,101 +304,121 @@ public : divide_box<Dimension>(box, lower_box, upper_box); IteratorVector lower, upper, exceeding; - divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, - input, lower, upper, exceeding); + divide_into_subsets(lower_box, upper_box, + input, lower, upper, exceeding, + overlaps_policy); if (boost::size(exceeding) > 0) { // Get the box of exceeding-only - Box exceeding_box = get_new_box(exceeding); + Box exceeding_box = get_new_box(exceeding, expand_policy); // Recursively do exceeding elements only, in next dimension they // will probably be less exceeding within the new box next_level(exceeding_box, exceeding, level, min_elements, - policy, box_policy); + visitor, expand_policy, overlaps_policy, box_policy); // Switch to two forward ranges, combine exceeding with // lower resp upper, but not lower/lower, upper/upper next_level2(exceeding_box, exceeding, lower, level, min_elements, - policy, box_policy); + visitor, expand_policy, overlaps_policy, box_policy); next_level2(exceeding_box, exceeding, upper, level, min_elements, - policy, box_policy); + visitor, expand_policy, overlaps_policy, box_policy); } // Recursively call operation both parts - next_level(lower_box, lower, level, min_elements, policy, box_policy); - next_level(upper_box, upper, level, min_elements, policy, box_policy); + next_level(lower_box, lower, level, min_elements, + visitor, expand_policy, overlaps_policy, box_policy); + next_level(upper_box, upper, level, min_elements, + visitor, expand_policy, overlaps_policy, box_policy); } }; template < int Dimension, - typename Box, - typename OverlapsPolicy1, - typename OverlapsPolicy2, - typename ExpandPolicy1, - typename ExpandPolicy2, - typename VisitBoxPolicy + typename Box > class partition_two_ranges { template < - typename Policy, typename IteratorVector1, - typename IteratorVector2 + typename IteratorVector2, + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2, + typename OverlapsPolicy2, + typename VisitBoxPolicy > static inline void next_level(Box const& box, IteratorVector1 const& input1, IteratorVector2 const& input2, std::size_t level, std::size_t min_elements, - Policy& policy, VisitBoxPolicy& box_policy) + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1, + ExpandPolicy2 const& expand_policy2, + OverlapsPolicy2 const& overlaps_policy2, + VisitBoxPolicy& box_policy) { partition_two_ranges < - 1 - Dimension, - Box, - OverlapsPolicy1, - OverlapsPolicy2, - ExpandPolicy1, - ExpandPolicy2, - VisitBoxPolicy + 1 - Dimension, Box >::apply(box, input1, input2, level + 1, min_elements, - policy, box_policy); + visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } - template <typename ExpandPolicy, typename IteratorVector> - static inline Box get_new_box(IteratorVector const& input) + template <typename IteratorVector, typename ExpandPolicy> + static inline Box get_new_box(IteratorVector const& input, + ExpandPolicy const& expand_policy) { Box box; geometry::assign_inverse(box); - expand_with_elements<ExpandPolicy>(box, input); + expand_with_elements(box, input, expand_policy); return box; } - template <typename IteratorVector1, typename IteratorVector2> + template + < + typename IteratorVector1, typename IteratorVector2, + typename ExpandPolicy1, typename ExpandPolicy2 + > static inline Box get_new_box(IteratorVector1 const& input1, - IteratorVector2 const& input2) + IteratorVector2 const& input2, + ExpandPolicy1 const& expand_policy1, + ExpandPolicy2 const& expand_policy2) { - Box box = get_new_box<ExpandPolicy1>(input1); - expand_with_elements<ExpandPolicy2>(box, input2); + Box box = get_new_box(input1, expand_policy1); + expand_with_elements(box, input2, expand_policy2); return box; } public : template < - typename Policy, typename IteratorVector1, - typename IteratorVector2 + typename IteratorVector2, + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2, + typename OverlapsPolicy2, + typename VisitBoxPolicy > static inline void apply(Box const& box, IteratorVector1 const& input1, IteratorVector2 const& input2, std::size_t level, std::size_t min_elements, - Policy& policy, VisitBoxPolicy& box_policy) + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1, + ExpandPolicy2 const& expand_policy2, + OverlapsPolicy2 const& overlaps_policy2, + VisitBoxPolicy& box_policy) { box_policy.apply(box, level); @@ -393,10 +427,12 @@ public : IteratorVector1 lower1, upper1, exceeding1; IteratorVector2 lower2, upper2, exceeding2; - divide_into_subsets<OverlapsPolicy1>(lower_box, upper_box, - input1, lower1, upper1, exceeding1); - divide_into_subsets<OverlapsPolicy2>(lower_box, upper_box, - input2, lower2, upper2, exceeding2); + divide_into_subsets(lower_box, upper_box, + input1, lower1, upper1, exceeding1, + overlaps_policy1); + divide_into_subsets(lower_box, upper_box, + input2, lower2, upper2, exceeding2, + overlaps_policy2); if (boost::size(exceeding1) > 0) { @@ -404,13 +440,15 @@ public : if (recurse_ok(exceeding1, exceeding2, min_elements, level)) { - Box exceeding_box = get_new_box(exceeding1, exceeding2); + Box exceeding_box = get_new_box(exceeding1, exceeding2, + expand_policy1, expand_policy2); next_level(exceeding_box, exceeding1, exceeding2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } else { - handle_two(exceeding1, exceeding2, policy); + handle_two(exceeding1, exceeding2, visitor); } // All exceeding from 1 with lower and upper of 2: @@ -419,16 +457,18 @@ public : // the same combinations again and again) if (recurse_ok(lower2, upper2, exceeding1, min_elements, level)) { - Box exceeding_box = get_new_box<ExpandPolicy1>(exceeding1); + Box exceeding_box = get_new_box(exceeding1, expand_policy1); next_level(exceeding_box, exceeding1, lower2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); next_level(exceeding_box, exceeding1, upper2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } else { - handle_two(exceeding1, lower2, policy); - handle_two(exceeding1, upper2, policy); + handle_two(exceeding1, lower2, visitor); + handle_two(exceeding1, upper2, visitor); } } @@ -437,36 +477,40 @@ public : // All exceeding from 2 with lower and upper of 1: if (recurse_ok(lower1, upper1, exceeding2, min_elements, level)) { - Box exceeding_box = get_new_box<ExpandPolicy2>(exceeding2); + Box exceeding_box = get_new_box(exceeding2, expand_policy2); next_level(exceeding_box, lower1, exceeding2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); next_level(exceeding_box, upper1, exceeding2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } else { - handle_two(lower1, exceeding2, policy); - handle_two(upper1, exceeding2, policy); + handle_two(lower1, exceeding2, visitor); + handle_two(upper1, exceeding2, visitor); } } if (recurse_ok(lower1, lower2, min_elements, level)) { next_level(lower_box, lower1, lower2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } else { - handle_two(lower1, lower2, policy); + handle_two(lower1, lower2, visitor); } if (recurse_ok(upper1, upper2, min_elements, level)) { next_level(upper_box, upper1, upper2, level, - min_elements, policy, box_policy); + min_elements, visitor, expand_policy1, overlaps_policy1, + expand_policy2, overlaps_policy2, box_policy); } else { - handle_two(upper1, upper2, policy); + handle_two(upper1, upper2, visitor); } } }; @@ -493,46 +537,86 @@ struct include_all_policy template < typename Box, - typename ExpandPolicy1, - typename OverlapsPolicy1, - typename ExpandPolicy2 = ExpandPolicy1, - typename OverlapsPolicy2 = OverlapsPolicy1, typename IncludePolicy1 = detail::partition::include_all_policy, - typename IncludePolicy2 = detail::partition::include_all_policy, - typename VisitBoxPolicy = detail::partition::visit_no_policy + typename IncludePolicy2 = detail::partition::include_all_policy > class partition { + static const std::size_t default_min_elements = 16; + template < - typename ExpandPolicy, typename IncludePolicy, typename ForwardRange, - typename IteratorVector + typename IteratorVector, + typename ExpandPolicy > static inline void expand_to_range(ForwardRange const& forward_range, - Box& total, IteratorVector& iterator_vector) + Box& total, + IteratorVector& iterator_vector, + ExpandPolicy const& expand_policy) { - for(typename boost::range_iterator<ForwardRange const>::type it - = boost::begin(forward_range); + for(typename boost::range_iterator<ForwardRange const>::type + it = boost::begin(forward_range); it != boost::end(forward_range); ++it) { if (IncludePolicy::apply(*it)) { - ExpandPolicy::apply(total, *it); + expand_policy.apply(total, *it); iterator_vector.push_back(it); } } } -public : - template <typename ForwardRange, typename VisitPolicy> +public: + template + < + typename ForwardRange, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy + > static inline void apply(ForwardRange const& forward_range, - VisitPolicy& visitor, - std::size_t min_elements = 16, - VisitBoxPolicy box_visitor = detail::partition::visit_no_policy() - ) + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy) + { + apply(forward_range, visitor, expand_policy, overlaps_policy, + default_min_elements, detail::partition::visit_no_policy()); + } + + template + < + typename ForwardRange, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy + > + static inline void apply(ForwardRange const& forward_range, + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy, + std::size_t min_elements) + { + apply(forward_range, visitor, expand_policy, overlaps_policy, + min_elements, detail::partition::visit_no_policy()); + } + + template + < + typename ForwardRange, + typename VisitPolicy, + typename ExpandPolicy, + typename OverlapsPolicy, + typename VisitBoxPolicy + > + static inline void apply(ForwardRange const& forward_range, + VisitPolicy& visitor, + ExpandPolicy const& expand_policy, + OverlapsPolicy const& overlaps_policy, + std::size_t min_elements, + VisitBoxPolicy box_visitor) { typedef typename boost::range_iterator < @@ -544,17 +628,14 @@ public : std::vector<iterator_type> iterator_vector; Box total; assign_inverse(total); - expand_to_range<ExpandPolicy1, IncludePolicy1>(forward_range, - total, iterator_vector); + expand_to_range<IncludePolicy1>(forward_range, total, + iterator_vector, expand_policy); detail::partition::partition_one_range < - 0, Box, - OverlapsPolicy1, - ExpandPolicy1, - VisitBoxPolicy + 0, Box >::apply(total, iterator_vector, 0, min_elements, - visitor, box_visitor); + visitor, expand_policy, overlaps_policy, box_visitor); } else { @@ -575,15 +656,88 @@ public : < typename ForwardRange1, typename ForwardRange2, - typename VisitPolicy + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1 + > + static inline void apply(ForwardRange1 const& forward_range1, + ForwardRange2 const& forward_range2, + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1) + { + apply(forward_range1, forward_range2, visitor, + expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1, + default_min_elements, detail::partition::visit_no_policy()); + } + + template + < + typename ForwardRange1, + typename ForwardRange2, + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2, + typename OverlapsPolicy2 + > + static inline void apply(ForwardRange1 const& forward_range1, + ForwardRange2 const& forward_range2, + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1, + ExpandPolicy2 const& expand_policy2, + OverlapsPolicy2 const& overlaps_policy2) + { + apply(forward_range1, forward_range2, visitor, + expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, + default_min_elements, detail::partition::visit_no_policy()); + } + + template + < + typename ForwardRange1, + typename ForwardRange2, + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2, + typename OverlapsPolicy2 + > + static inline void apply(ForwardRange1 const& forward_range1, + ForwardRange2 const& forward_range2, + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1, + ExpandPolicy2 const& expand_policy2, + OverlapsPolicy2 const& overlaps_policy2, + std::size_t min_elements) + { + apply(forward_range1, forward_range2, visitor, + expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy1, + min_elements, detail::partition::visit_no_policy()); + } + + template + < + typename ForwardRange1, + typename ForwardRange2, + typename VisitPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2, + typename OverlapsPolicy2, + typename VisitBoxPolicy > static inline void apply(ForwardRange1 const& forward_range1, - ForwardRange2 const& forward_range2, - VisitPolicy& visitor, - std::size_t min_elements = 16, - VisitBoxPolicy box_visitor - = detail::partition::visit_no_policy() - ) + ForwardRange2 const& forward_range2, + VisitPolicy& visitor, + ExpandPolicy1 const& expand_policy1, + OverlapsPolicy1 const& overlaps_policy1, + ExpandPolicy2 const& expand_policy2, + OverlapsPolicy2 const& overlaps_policy2, + std::size_t min_elements, + VisitBoxPolicy box_visitor) { typedef typename boost::range_iterator < @@ -602,17 +756,18 @@ public : std::vector<iterator_type2> iterator_vector2; Box total; assign_inverse(total); - expand_to_range<ExpandPolicy1, IncludePolicy1>(forward_range1, - total, iterator_vector1); - expand_to_range<ExpandPolicy2, IncludePolicy2>(forward_range2, - total, iterator_vector2); + expand_to_range<IncludePolicy1>(forward_range1, total, + iterator_vector1, expand_policy1); + expand_to_range<IncludePolicy2>(forward_range2, total, + iterator_vector2, expand_policy2); detail::partition::partition_two_ranges < - 0, Box, OverlapsPolicy1, OverlapsPolicy2, - ExpandPolicy1, ExpandPolicy2, VisitBoxPolicy + 0, Box >::apply(total, iterator_vector1, iterator_vector2, - 0, min_elements, visitor, box_visitor); + 0, min_elements, visitor, expand_policy1, + overlaps_policy1, expand_policy2, overlaps_policy2, + box_visitor); } else { diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp index a74954326b..800fbb2e96 100644 --- a/boost/geometry/algorithms/detail/relate/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -40,12 +40,21 @@ namespace detail { namespace relate { // Use the rtree in this case! // may be used to set EI and EB for an Areal geometry for which no turns were generated -template <typename OtherAreal, typename Result, bool TransposeResult> +template +< + typename OtherAreal, + typename Result, + typename PointInArealStrategy, + bool TransposeResult +> class no_turns_aa_pred { public: - no_turns_aa_pred(OtherAreal const& other_areal, Result & res) + no_turns_aa_pred(OtherAreal const& other_areal, + Result & res, + PointInArealStrategy const& point_in_areal_strategy) : m_result(res) + , m_point_in_areal_strategy(point_in_areal_strategy) , m_other_areal(other_areal) , m_flags(0) { @@ -68,6 +77,8 @@ public: template <typename Areal> bool operator()(Areal const& areal) { + using detail::within::point_in_geometry; + // if those flags are set nothing will change if ( m_flags == 3 ) { @@ -87,7 +98,9 @@ public: // check if the areal is inside the other_areal // TODO: This is O(N) // Run in a loop O(NM) - optimize! - int const pig = detail::within::point_in_geometry(pt, m_other_areal); + int const pig = point_in_geometry(pt, + m_other_areal, + m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT( pig != 0 ); // inside @@ -119,7 +132,9 @@ public: // TODO: O(N) // Optimize! - int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal); + int const hpig = point_in_geometry(range::front(range_ref), + m_other_areal, + m_point_in_areal_strategy); // hole outside if ( hpig < 0 ) @@ -155,7 +170,9 @@ public: // TODO: O(N) // Optimize! - int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal); + int const hpig = point_in_geometry(range::front(range_ref), + m_other_areal, + m_point_in_areal_strategy); // hole inside if ( hpig > 0 ) @@ -174,6 +191,7 @@ public: private: Result & m_result; + PointInArealStrategy const& m_point_in_areal_strategy; OtherAreal const& m_other_areal; int m_flags; }; @@ -191,8 +209,10 @@ struct areal_areal typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; - template <typename Result> - static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + template <typename Result, typename IntersectionStrategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + IntersectionStrategy const& intersection_strategy) { // TODO: If Areal geometry may have infinite size, change the following line: @@ -208,16 +228,31 @@ struct areal_areal interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result); - turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy); + turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - no_turns_aa_pred<Geometry2, Result, false> pred1(geometry2, result); + typedef typename IntersectionStrategy::template point_in_geometry_strategy + < + Geometry1, Geometry2 + >::type point_in_areal_strategy12_type; + point_in_areal_strategy12_type point_in_areal_strategy12 + = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(); + typedef typename IntersectionStrategy::template point_in_geometry_strategy + < + Geometry2, Geometry1 + >::type point_in_areal_strategy21_type; + point_in_areal_strategy21_type point_in_areal_strategy21 + = intersection_strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>(); + + no_turns_aa_pred<Geometry2, Result, point_in_areal_strategy12_type, false> + pred1(geometry2, result, point_in_areal_strategy12); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - no_turns_aa_pred<Geometry1, Result, true> pred2(geometry1, result); + no_turns_aa_pred<Geometry1, Result, point_in_areal_strategy21_type, true> + pred2(geometry1, result, point_in_areal_strategy21); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; @@ -256,7 +291,8 @@ struct areal_areal { // analyse rings for which turns were not generated // or only i/i or u/u was generated - uncertain_rings_analyser<0, Result, Geometry1, Geometry2> rings_analyser(result, geometry1, geometry2); + uncertain_rings_analyser<0, Result, Geometry1, Geometry2, point_in_areal_strategy12_type> + rings_analyser(result, geometry1, geometry2, point_in_areal_strategy12); analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) @@ -295,7 +331,8 @@ struct areal_areal { // analyse rings for which turns were not generated // or only i/i or u/u was generated - uncertain_rings_analyser<1, Result, Geometry2, Geometry1> rings_analyser(result, geometry2, geometry1); + uncertain_rings_analyser<1, Result, Geometry2, Geometry1, point_in_areal_strategy21_type> + rings_analyser(result, geometry2, geometry1, point_in_areal_strategy21); analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end()); //if ( result.interrupt ) @@ -565,7 +602,14 @@ struct areal_areal analyser.apply(res); } - template <std::size_t OpId, typename Result, typename Geometry, typename OtherGeometry> + template + < + std::size_t OpId, + typename Result, + typename Geometry, + typename OtherGeometry, + typename PointInArealStrategy + > class uncertain_rings_analyser { static const bool transpose_result = OpId != 0; @@ -574,10 +618,13 @@ struct areal_areal public: inline uncertain_rings_analyser(Result & result, Geometry const& geom, - OtherGeometry const& other_geom) - : geometry(geom), other_geometry(other_geom) + OtherGeometry const& other_geom, + PointInArealStrategy const& point_in_areal_strategy) + : geometry(geom) + , other_geometry(other_geom) , interrupt(result.interrupt) // just in case, could be false as well , m_result(result) + , m_point_in_areal_strategy(point_in_areal_strategy) , m_flags(0) { // check which relations must be analysed @@ -624,7 +671,10 @@ struct areal_areal // TODO: optimize! e.g. use spatial index // O(N) - running it in a loop gives O(NM) - int const pig = detail::within::point_in_geometry(range::front(range_ref), other_geometry); + using detail::within::point_in_geometry; + int const pig = point_in_geometry(range::front(range_ref), + other_geometry, + m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT(pig != 0); if ( pig > 0 ) @@ -713,6 +763,7 @@ struct areal_areal private: Result & m_result; + PointInArealStrategy const& m_point_in_areal_strategy; int m_flags; }; diff --git a/boost/geometry/algorithms/detail/relate/implementation.hpp b/boost/geometry/algorithms/detail/relate/implementation.hpp index a6f1545ed1..3bd0f806c1 100644 --- a/boost/geometry/algorithms/detail/relate/implementation.hpp +++ b/boost/geometry/algorithms/detail/relate/implementation.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -25,6 +25,9 @@ #include <boost/geometry/algorithms/detail/relate/linear_areal.hpp> #include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> +#include <boost/geometry/strategies/intersection.hpp> +#include <boost/geometry/strategies/within.hpp> + namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/relate/interface.hpp b/boost/geometry/algorithms/detail/relate/interface.hpp index 95d452931c..3575fe2bc4 100644 --- a/boost/geometry/algorithms/detail/relate/interface.hpp +++ b/boost/geometry/algorithms/detail/relate/interface.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -29,6 +29,7 @@ #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/relate.hpp> namespace boost { namespace geometry { @@ -186,18 +187,59 @@ struct result_handler_type<Geometry1, Geometry2, StaticSequence, true> > type; }; + }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL +namespace resolve_strategy { + +struct relate +{ + template <typename Geometry1, typename Geometry2, typename ResultHandler, typename Strategy> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + ResultHandler & handler, + Strategy const& strategy) + { + dispatch::relate + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, handler, strategy); + } + + template <typename Geometry1, typename Geometry2, typename ResultHandler> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + ResultHandler & handler, + default_strategy) + { + typedef typename strategy::relate::services::default_strategy + < + Geometry1, + Geometry2 + >::type strategy_type; + + dispatch::relate + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, handler, strategy_type()); + } +}; + +} // resolve_strategy + namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct relate { - template <typename Mask> + template <typename Mask, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, - Mask const& mask) + Mask const& mask, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); @@ -210,11 +252,7 @@ struct relate Mask >::type handler(mask); - dispatch::relate - < - Geometry1, - Geometry2 - >::apply(geometry1, geometry2, handler); + resolve_strategy::relate::apply(geometry1, geometry2, handler, strategy); return handler.result(); } @@ -223,60 +261,64 @@ struct relate template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct relate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { - template <typename Mask> + template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Geometry2 const& m_geometry2; Mask const& m_mask; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2, Mask const& mask) - : m_geometry2(geometry2), m_mask(mask) {} + visitor(Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) + : m_geometry2(geometry2), m_mask(mask), m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return relate<Geometry1, Geometry2> - ::apply(geometry1, m_geometry2, m_mask); + ::apply(geometry1, m_geometry2, m_mask, m_strategy); } }; - template <typename Mask> + template <typename Mask, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, - Mask const& mask) + Mask const& mask, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Mask>(geometry2, mask), geometry1); + return boost::apply_visitor(visitor<Mask, Strategy>(geometry2, mask, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct relate<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename Mask> + template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Geometry1 const& m_geometry1; Mask const& m_mask; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1, Mask const& mask) - : m_geometry1(geometry1), m_mask(mask) {} + visitor(Geometry1 const& geometry1, Mask const& mask, Strategy const& strategy) + : m_geometry1(geometry1), m_mask(mask), m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return relate<Geometry1, Geometry2> - ::apply(m_geometry1, geometry2, m_mask); + ::apply(m_geometry1, geometry2, m_mask, m_strategy); } }; - template <typename Mask> + template <typename Mask, typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Mask const& mask) + Mask const& mask, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Mask>(geometry1, mask), geometry2); + return boost::apply_visitor(visitor<Mask, Strategy>(geometry1, mask, strategy), geometry2); } }; @@ -289,30 +331,32 @@ struct relate< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { - template <typename Mask> + template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Mask const& m_mask; + Strategy const& m_strategy; - visitor(Mask const& mask) - : m_mask(mask) {} + visitor(Mask const& mask, Strategy const& strategy) + : m_mask(mask), m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return relate<Geometry1, Geometry2> - ::apply(geometry1, geometry2, m_mask); + ::apply(geometry1, geometry2, m_mask, m_strategy); } }; - template <typename Mask> + template <typename Mask, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Mask const& mask) + Mask const& mask, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Mask>(mask), geometry1, geometry2); + return boost::apply_visitor(visitor<Mask, Strategy>(mask, strategy), geometry1, geometry2); } }; @@ -324,6 +368,35 @@ struct relate< \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Mask An intersection model Mask type. +\tparam Strategy \tparam_strategy{Relate} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param mask An intersection model mask object. +\param strategy \param_strategy{relate} +\return true if the relation is compatible with the mask, false otherwise. + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/relate.qbk]} + */ +template <typename Geometry1, typename Geometry2, typename Mask, typename Strategy> +inline bool relate(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Mask const& mask, + Strategy const& strategy) +{ + return resolve_variant::relate + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, mask, strategy); +} + +/*! +\brief Checks relation between a pair of geometries defined by a mask. +\ingroup relate +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Mask An intersection model Mask type. \param geometry1 \param_geometry \param geometry2 \param_geometry \param mask An intersection model mask object. @@ -340,7 +413,7 @@ inline bool relate(Geometry1 const& geometry1, < Geometry1, Geometry2 - >::apply(geometry1, geometry2, mask); + >::apply(geometry1, geometry2, mask, default_strategy()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp index 58ba7bd1af..f1b4fdf81a 100644 --- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -46,15 +46,24 @@ namespace detail { namespace relate { // Use the rtree in this case! // may be used to set IE and BE for a Linear geometry for which no turns were generated -template <typename Geometry2, typename Result, typename BoundaryChecker, bool TransposeResult> +template +< + typename Geometry2, + typename Result, + typename PointInArealStrategy, + typename BoundaryChecker, + bool TransposeResult +> class no_turns_la_linestring_pred { public: no_turns_la_linestring_pred(Geometry2 const& geometry2, Result & res, + PointInArealStrategy const& point_in_areal_strategy, BoundaryChecker const& boundary_checker) : m_geometry2(geometry2) , m_result(res) + , m_point_in_areal_strategy(point_in_areal_strategy) , m_boundary_checker(boundary_checker) , m_interrupt_flags(0) { @@ -98,7 +107,9 @@ public: return false; } - int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2); + int const pig = detail::within::point_in_geometry(range::front(linestring), + m_geometry2, + m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT_MSG(pig != 0, "There should be no IPs"); if ( pig > 0 ) @@ -138,6 +149,7 @@ public: private: Geometry2 const& m_geometry2; Result & m_result; + PointInArealStrategy const& m_point_in_areal_strategy; BoundaryChecker const& m_boundary_checker; unsigned m_interrupt_flags; }; @@ -225,8 +237,10 @@ struct linear_areal > {}; - template <typename Result> - static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + template <typename Result, typename IntersectionStrategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + IntersectionStrategy const& intersection_strategy) { // TODO: If Areal geometry may have infinite size, change the following line: @@ -242,7 +256,7 @@ struct linear_areal interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result); - turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy); + turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; @@ -251,9 +265,13 @@ struct linear_areal < Geometry2, Result, + typename IntersectionStrategy::template point_in_geometry_strategy<Geometry1, Geometry2>::type, boundary_checker<Geometry1>, TransposeResult - > pred1(geometry2, result, boundary_checker1); + > pred1(geometry2, + result, + intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(), + boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; @@ -279,7 +297,8 @@ struct linear_areal analyse_each_turn(result, analyser, turns.begin(), turns.end(), geometry1, geometry2, - boundary_checker1); + boundary_checker1, + intersection_strategy.get_side_strategy()); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; @@ -615,11 +634,13 @@ struct linear_areal typename TurnIt, typename Geometry, typename OtherGeometry, - typename BoundaryChecker> + typename BoundaryChecker, + typename SideStrategy> void apply(Result & res, TurnIt it, Geometry const& geometry, OtherGeometry const& other_geometry, - BoundaryChecker const& boundary_checker) + BoundaryChecker const& boundary_checker, + SideStrategy const& side_strategy) { overlay::operation_type op = it->operations[op_id].operation; @@ -856,7 +877,8 @@ struct linear_areal bool const from_inside = first_point && calculate_from_inside(geometry, other_geometry, - *it); + *it, + side_strategy); if ( from_inside ) update<interior, interior, '1', TransposeResult>(res); @@ -956,7 +978,8 @@ struct linear_areal bool const first_from_inside = first_point && calculate_from_inside(geometry, other_geometry, - *it); + *it, + side_strategy); if ( first_from_inside ) { update<interior, interior, '1', TransposeResult>(res); @@ -1144,10 +1167,11 @@ struct linear_areal // check if the passed turn's segment of Linear geometry arrived // from the inside or the outside of the Areal geometry - template <typename Turn> + template <typename Turn, typename SideStrategy> static inline bool calculate_from_inside(Geometry1 const& geometry1, Geometry2 const& geometry2, - Turn const& turn) + Turn const& turn, + SideStrategy const& side_strategy) { typedef typename cs_tag<typename Turn::point_type>::type cs_tag; @@ -1194,16 +1218,18 @@ struct linear_areal boost::end(range2)); // Will this sequence of points be always correct? - overlay::side_calculator<cs_tag, point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it); + overlay::side_calculator<cs_tag, point1_type, point2_type, SideStrategy> + side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it, side_strategy); return calculate_from_inside_sides(side_calc); } else { - point1_type new_qj; + point2_type new_qj; geometry::convert(turn.point, new_qj); - overlay::side_calculator<cs_tag, point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj); + overlay::side_calculator<cs_tag, point1_type, point2_type, SideStrategy> + side_calc(qi_conv, new_pj, pi, qi, new_qj, qj, side_strategy); return calculate_from_inside_sides(side_calc); } @@ -1270,13 +1296,15 @@ struct linear_areal typename Analyser, typename Geometry, typename OtherGeometry, - typename BoundaryChecker> + typename BoundaryChecker, + typename SideStrategy> static inline void analyse_each_turn(Result & res, Analyser & analyser, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& other_geometry, - BoundaryChecker const& boundary_checker) + BoundaryChecker const& boundary_checker, + SideStrategy const& side_strategy) { if ( first == last ) return; @@ -1285,7 +1313,8 @@ struct linear_areal { analyser.apply(res, it, geometry, other_geometry, - boundary_checker); + boundary_checker, + side_strategy); if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) return; @@ -1420,10 +1449,12 @@ struct areal_linear static const bool interruption_enabled = linear_areal_type::interruption_enabled; - template <typename Result> - static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + template <typename Result, typename IntersectionStrategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + IntersectionStrategy const& intersection_strategy) { - linear_areal_type::apply(geometry2, geometry1, result); + linear_areal_type::apply(geometry2, geometry1, result, intersection_strategy); } }; diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 7a3f373e03..520f2bd775 100644 --- a/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -2,15 +2,15 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 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_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP @@ -119,8 +119,10 @@ struct linear_linear typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; - template <typename Result> - static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + template <typename Result, typename IntersectionStrategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + IntersectionStrategy const& intersection_strategy) { // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T @@ -138,7 +140,7 @@ struct linear_linear Geometry1, Geometry2, detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> > - >::apply(turns, geometry1, geometry2, interrupt_policy); + >::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp index be08016a16..a0c6c0d49b 100644 --- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp +++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -37,10 +37,10 @@ struct point_geometry static const bool interruption_enabled = true; - template <typename Result> - static inline void apply(Point const& point, Geometry const& geometry, Result & result) + template <typename Result, typename Strategy> + static inline void apply(Point const& point, Geometry const& geometry, Result & result, Strategy const& strategy) { - int pig = detail::within::point_in_geometry(point, geometry); + int pig = detail::within::point_in_geometry(point, geometry, strategy); if ( pig > 0 ) // within { @@ -95,10 +95,10 @@ struct geometry_point static const bool interruption_enabled = true; - template <typename Result> - static inline void apply(Geometry const& geometry, Point const& point, Result & result) + template <typename Result, typename Strategy> + static inline void apply(Geometry const& geometry, Point const& point, Result & result, Strategy const& strategy) { - point_geometry<Point, Geometry, true>::apply(point, geometry, result); + point_geometry<Point, Geometry, true>::apply(point, geometry, result, strategy); } }; diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp index e55be08225..b41d346f0b 100644 --- a/boost/geometry/algorithms/detail/relate/point_point.hpp +++ b/boost/geometry/algorithms/detail/relate/point_point.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, 2017. +// Modifications copyright (c) 2013-2017, 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_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP @@ -35,8 +35,10 @@ struct point_point { static const bool interruption_enabled = false; - template <typename Result> - static inline void apply(Point1 const& point1, Point2 const& point2, Result & result) + template <typename Result, typename Strategy> + static inline void apply(Point1 const& point1, Point2 const& point2, + Result & result, + Strategy const& /*strategy*/) { bool equal = detail::equals::equals_point_point(point1, point2); if ( equal ) @@ -86,8 +88,10 @@ struct point_multipoint { static const bool interruption_enabled = false; - template <typename Result> - static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result) + template <typename Result, typename Strategy> + static inline void apply(Point const& point, MultiPoint const& multi_point, + Result & result, + Strategy const& /*strategy*/) { if ( boost::empty(multi_point) ) { @@ -122,10 +126,12 @@ struct multipoint_point { static const bool interruption_enabled = false; - template <typename Result> - static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result) + template <typename Result, typename Strategy> + static inline void apply(MultiPoint const& multi_point, Point const& point, + Result & result, + Strategy const& strategy) { - point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result); + point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result, strategy); } }; @@ -134,8 +140,10 @@ struct multipoint_multipoint { static const bool interruption_enabled = true; - template <typename Result> - static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result) + template <typename Result, typename Strategy> + static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, + Result & result, + Strategy const& /*strategy*/) { { // TODO: throw on empty input? diff --git a/boost/geometry/algorithms/detail/relate/relate_impl.hpp b/boost/geometry/algorithms/detail/relate/relate_impl.hpp index e8e422993d..2ec2361c03 100644 --- a/boost/geometry/algorithms/detail/relate/relate_impl.hpp +++ b/boost/geometry/algorithms/detail/relate/relate_impl.hpp @@ -57,7 +57,8 @@ struct relate_impl implemented_tag >::type { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { typename detail::relate::result_handler_type < @@ -66,7 +67,7 @@ struct relate_impl typename StaticMaskTrait<Geometry1, Geometry2>::type >::type handler; - dispatch::relate<Geometry1, Geometry2>::apply(g1, g2, handler); + dispatch::relate<Geometry1, Geometry2>::apply(g1, g2, handler, strategy); return handler.result(); } diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp index a92badf65b..07287dc625 100644 --- a/boost/geometry/algorithms/detail/relate/result.hpp +++ b/boost/geometry/algorithms/detail/relate/result.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2016. // Modifications copyright (c) 2013-2016 Oracle and/or its affiliates. @@ -24,6 +25,7 @@ #include <boost/mpl/is_sequence.hpp> #include <boost/mpl/next.hpp> #include <boost/static_assert.hpp> +#include <boost/throw_exception.hpp> #include <boost/tuple/tuple.hpp> #include <boost/type_traits/integral_constant.hpp> @@ -266,7 +268,7 @@ private: || ( c >= '0' && c <= '9' ); if ( !is_valid ) { - throw geometry::invalid_input_exception(); + BOOST_THROW_EXCEPTION(geometry::invalid_input_exception()); } } diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp index 09d74dec3a..6fa05eaf21 100644 --- a/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/boost/geometry/algorithms/detail/relate/turns.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 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 @@ -75,28 +75,35 @@ struct get_turns { detail::get_turns::no_interrupt_policy interrupt_policy; - apply(turns, geometry1, geometry2, interrupt_policy); + typename strategy::intersection::services::default_strategy + < + typename cs_tag<Geometry1>::type + >::type intersection_strategy; + + apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); } - template <typename Turns, typename InterruptPolicy> + template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy> static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2, - InterruptPolicy & interrupt_policy) + InterruptPolicy & interrupt_policy, + IntersectionStrategy const& intersection_strategy) { RobustPolicy robust_policy = geometry::get_rescale_policy < RobustPolicy >(geometry1, geometry2); - apply(turns, geometry1, geometry2, interrupt_policy, robust_policy); + apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy, robust_policy); } - template <typename Turns, typename InterruptPolicy> + template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy> static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2, InterruptPolicy & interrupt_policy, + IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) { static const bool reverse1 = detail::overlay::do_reverse @@ -119,7 +126,8 @@ struct get_turns reverse2, GetTurnPolicy >::apply(0, geometry1, 1, geometry2, - robust_policy, turns, interrupt_policy); + intersection_strategy, robust_policy, + turns, interrupt_policy); } }; diff --git a/boost/geometry/algorithms/detail/relation/interface.hpp b/boost/geometry/algorithms/detail/relation/interface.hpp index e9a9474551..83d27ed72f 100644 --- a/boost/geometry/algorithms/detail/relation/interface.hpp +++ b/boost/geometry/algorithms/detail/relation/interface.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -35,16 +35,16 @@ struct result_handler_type<Geometry1, Geometry2, geometry::de9im::matrix, false> }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL - namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct relation { - template <typename Matrix> + template <typename Matrix, typename Strategy> static inline Matrix apply(Geometry1 const& geometry1, - Geometry2 const& geometry2) + Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); @@ -57,11 +57,7 @@ struct relation Matrix >::type handler; - dispatch::relate - < - Geometry1, - Geometry2 - >::apply(geometry1, geometry2, handler); + resolve_strategy::relate::apply(geometry1, geometry2, handler, strategy); return handler.result(); } @@ -70,56 +66,60 @@ struct relation template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct relation<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { - template <typename Matrix> + template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { Geometry2 const& m_geometry2; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2) - : m_geometry2(geometry2) {} + visitor(Geometry2 const& geometry2, Strategy const& strategy) + : m_geometry2(geometry2), m_strategy(strategy) {} template <typename Geometry1> Matrix operator()(Geometry1 const& geometry1) const { return relation<Geometry1, Geometry2> - ::template apply<Matrix>(geometry1, m_geometry2); + ::template apply<Matrix>(geometry1, m_geometry2, m_strategy); } }; - template <typename Matrix> + template <typename Matrix, typename Strategy> static inline Matrix apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2) + Geometry2 const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Matrix>(geometry2), geometry1); + return boost::apply_visitor(visitor<Matrix, Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct relation<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { - template <typename Matrix> + template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { Geometry1 const& m_geometry1; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1) - : m_geometry1(geometry1) {} + visitor(Geometry1 const& geometry1, Strategy const& strategy) + : m_geometry1(geometry1), m_strategy(strategy) {} template <typename Geometry2> Matrix operator()(Geometry2 const& geometry2) const { return relation<Geometry1, Geometry2> - ::template apply<Matrix>(m_geometry1, geometry2); + ::template apply<Matrix>(m_geometry1, geometry2, m_strategy); } }; - template <typename Matrix> + template <typename Matrix, typename Strategy> static inline Matrix apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Matrix>(geometry1), geometry2); + return boost::apply_visitor(visitor<Matrix, Strategy>(geometry1, strategy), geometry2); } }; @@ -134,24 +134,30 @@ struct relation boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { - template <typename Matrix> + template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) {} + template <typename Geometry1, typename Geometry2> Matrix operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return relation<Geometry1, Geometry2> - ::template apply<Matrix>(geometry1, geometry2); + ::template apply<Matrix>(geometry1, geometry2, m_strategy); } }; - template <typename Matrix> + template <typename Matrix, typename Strategy> static inline Matrix apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2) + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Matrix>(), geometry1, geometry2); + return boost::apply_visitor(visitor<Matrix, Strategy>(strategy), geometry1, geometry2); } }; @@ -163,6 +169,33 @@ struct relation \ingroup relation \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Relation} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{relation} +\return The DE-9IM matrix expressing the relation between geometries. + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/relation.qbk]} + */ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline de9im::matrix relation(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + return resolve_variant::relation + < + Geometry1, + Geometry2 + >::template apply<de9im::matrix>(geometry1, geometry2, strategy); +} + + +/*! +\brief Calculates the relation between a pair of geometries as defined in DE-9IM. +\ingroup relation +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return The DE-9IM matrix expressing the relation between geometries. @@ -177,7 +210,7 @@ inline de9im::matrix relation(Geometry1 const& geometry1, < Geometry1, Geometry2 - >::template apply<de9im::matrix>(geometry1, geometry2); + >::template apply<de9im::matrix>(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp index 2f82e1a8bd..3d45a46d16 100644 --- a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp +++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp @@ -3,6 +3,7 @@ // 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) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. @@ -16,9 +17,13 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP + #include <boost/geometry/core/exception.hpp> #include <boost/geometry/algorithms/is_empty.hpp> +#include <boost/throw_exception.hpp> + + // BSG 2012-02-06: we use this currently only for distance. // For other scalar results area,length,perimeter it is commented on purpose. // Reason is that for distance there is no other choice. distance of two @@ -46,7 +51,7 @@ inline void throw_on_empty_input(Geometry const& geometry) #if ! defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) if (geometry::is_empty(geometry)) { - throw empty_input_exception(); + BOOST_THROW_EXCEPTION(empty_input_exception()); } #else boost::ignore_unused(geometry); diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index a73364c333..a24f4d21e2 100644 --- a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -5,8 +5,10 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017, 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,8 +17,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_WITHIN_POINT_IN_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP @@ -35,8 +35,7 @@ #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/concepts/within_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> -#include <boost/geometry/strategies/within.hpp> -#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/relate.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> @@ -46,6 +45,7 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { + // TODO: is this needed? inline int check_result_type(int result) { @@ -83,50 +83,11 @@ int point_in_range(Point const& point, Range const& range, Strategy const& strat template <typename Geometry, typename Point, typename Range> inline int point_in_range(Point const& point, Range const& range) { - typedef typename point_type<Point>::type point_type1; - typedef typename point_type<Geometry>::type point_type2; - - typedef typename strategy::within::services::default_strategy + typedef typename strategy::point_in_geometry::services::default_strategy < - typename tag<Point>::type, - typename tag<Geometry>::type, - typename tag<Point>::type, - typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, - Point, - Geometry + Point, Geometry >::type strategy_type; - typedef typename strategy::covered_by::services::default_strategy - < - typename tag<Point>::type, - typename tag<Geometry>::type, - typename tag<Point>::type, - typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, - Point, - Geometry - >::type strategy_type2; - - static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value; - BOOST_MPL_ASSERT_MSG((same_strategies), - DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, - (strategy_type, strategy_type2)); - return point_in_range(point, range, strategy_type()); } @@ -414,50 +375,11 @@ inline int point_in_geometry(Point const& point, Geometry const& geometry, Strat template <typename Point, typename Geometry> inline int point_in_geometry(Point const& point, Geometry const& geometry) { - typedef typename point_type<Point>::type point_type1; - typedef typename point_type<Geometry>::type point_type2; - - typedef typename strategy::within::services::default_strategy + typedef typename strategy::point_in_geometry::services::default_strategy < - typename tag<Point>::type, - typename tag<Geometry>::type, - typename tag<Point>::type, - typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, - Point, - Geometry + Point, Geometry >::type strategy_type; - typedef typename strategy::covered_by::services::default_strategy - < - typename tag<Point>::type, - typename tag<Geometry>::type, - typename tag<Point>::type, - typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, - Point, - Geometry - >::type strategy_type2; - - static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value; - BOOST_MPL_ASSERT_MSG((same_strategies), - DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, - (strategy_type, strategy_type2)); - return point_in_geometry(point, geometry, strategy_type()); } diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp index f7ca48cbe6..c11ceca243 100644 --- a/boost/geometry/algorithms/difference.hpp +++ b/boost/geometry/algorithms/difference.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, 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,10 +14,16 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP -#include <algorithm> + +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/util/range.hpp> + namespace boost { namespace geometry { @@ -49,10 +60,10 @@ template typename Strategy > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, - RobustPolicy const& robust_policy, - OutputIterator out, - Strategy const& strategy) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); @@ -93,25 +104,18 @@ template typename OutputIterator > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, - RobustPolicy const& robust_policy, - OutputIterator out) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - concepts::check<GeometryOut>(); - - typedef intersection_strategies + typedef typename strategy::relate::services::default_strategy < - typename cs_tag<GeometryOut>::type, Geometry1, - Geometry2, - typename geometry::point_type<GeometryOut>::type, - RobustPolicy - > strategy; + Geometry2 + >::type strategy_type; return difference_insert<GeometryOut>(geometry1, geometry2, - robust_policy, out, strategy()); + robust_policy, out, strategy_type()); } @@ -119,6 +123,215 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, #endif // DOXYGEN_NO_DETAIL +namespace resolve_strategy { + +struct difference +{ + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection, + typename Strategy + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + Strategy const& strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + detail::difference::difference_insert<geometry_out>( + geometry1, geometry2, robust_policy, + range::back_inserter(output_collection), + strategy); + } + + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + default_strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + detail::difference::difference_insert<geometry_out>( + geometry1, geometry2, robust_policy, + range::back_inserter(output_collection)); + } +}; + +} // resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct difference +{ + template <typename Collection, typename Strategy> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, + geometry2); + + resolve_strategy::difference::apply(geometry1, geometry2, + robust_policy, + output_collection, + strategy); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry2 const& m_geometry2; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + : m_geometry2(geometry2) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1> + void operator()(Geometry1 const& geometry1) const + { + difference + < + Geometry1, + Geometry2 + >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry2, + output_collection, + strategy), + geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry1 const& m_geometry1; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, + Collection& output_collection, + Strategy const& strategy) + : m_geometry1(geometry1) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry2> + void operator()(Geometry2 const& geometry2) const + { + difference + < + Geometry1, + Geometry2 + >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(Geometry1 const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry1, + output_collection, + strategy), + geometry2); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Collection& output_collection, Strategy const& strategy) + : m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1, typename Geometry2> + void operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + difference + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(output_collection, + strategy), + geometry1, geometry2); + } +}; + +} // namespace resolve_variant + /*! \brief_calc2{difference} @@ -127,39 +340,63 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection \tparam_output_collection +\tparam Strategy \tparam_strategy{Difference} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection +\param strategy \param_strategy{difference} +\qbk{distinguish,with strategy} \qbk{[include reference/algorithms/difference.qbk]} */ template < typename Geometry1, typename Geometry2, - typename Collection + typename Collection, + typename Strategy > inline void difference(Geometry1 const& geometry1, - Geometry2 const& geometry2, Collection& output_collection) + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - - typedef typename boost::range_value<Collection>::type geometry_out; - concepts::check<geometry_out>(); - - typedef typename geometry::rescale_overlay_policy_type + resolve_variant::difference < Geometry1, Geometry2 - >::type rescale_policy_type; + >::apply(geometry1, geometry2, output_collection, strategy); +} - rescale_policy_type robust_policy - = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); - detail::difference::difference_insert<geometry_out>( - geometry1, geometry2, robust_policy, - range::back_inserter(output_collection)); +/*! +\brief_calc2{difference} +\ingroup difference +\details \details_calc2{difference, spatial set theoretic difference}. +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Collection \tparam_output_collection +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param output_collection the output collection + +\qbk{[include reference/algorithms/difference.qbk]} +*/ +template +< + typename Geometry1, + typename Geometry2, + typename Collection +> +inline void difference(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection) +{ + resolve_variant::difference + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, output_collection, default_strategy()); } diff --git a/boost/geometry/algorithms/dispatch/disjoint.hpp b/boost/geometry/algorithms/dispatch/disjoint.hpp index 627bcff83c..78015f1a55 100644 --- a/boost/geometry/algorithms/dispatch/disjoint.hpp +++ b/boost/geometry/algorithms/dispatch/disjoint.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-2017. +// Modifications copyright (c) 2013-2017, 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 @@ -60,6 +60,29 @@ struct disjoint : not_implemented<Geometry1, Geometry2> {}; + +// If reversal is needed, perform it +template +< + typename Geometry1, typename Geometry2, + std::size_t DimensionCount, + typename Tag1, typename Tag2 +> +struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) + { + return disjoint + < + Geometry2, Geometry1, + DimensionCount, + Tag2, Tag1 + >::apply(g2, g1, strategy); + } +}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp index d04d5c7f3a..1479ea66fa 100644 --- a/boost/geometry/algorithms/equals.hpp +++ b/boost/geometry/algorithms/equals.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 2015, 2016. -// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 2016, 2017. +// Modifications copyright (c) 2014-2017 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 @@ -26,6 +26,7 @@ #include <vector> #include <boost/range.hpp> +#include <boost/type_traits/is_base_of.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> @@ -40,7 +41,6 @@ #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> -#include <boost/geometry/algorithms/detail/not.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> // For trivial checks @@ -70,25 +70,44 @@ template std::size_t Dimension, std::size_t DimensionCount > +struct point_point +{ + template <typename Point1, typename Point2, typename Strategy> + static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy) + { + return ! detail::disjoint::point_point + < + Point1, Point2, + Dimension, DimensionCount + >::apply(point1, point2, strategy); + } +}; + + +template +< + std::size_t Dimension, + std::size_t DimensionCount +> struct box_box { - template <typename Box1, typename Box2> - static inline bool apply(Box1 const& box1, Box2 const& box2) + template <typename Box1, typename Box2, typename Strategy> + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) { if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2)) || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2))) { return false; } - return box_box<Dimension + 1, DimensionCount>::apply(box1, box2); + return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy); } }; template <std::size_t DimensionCount> struct box_box<DimensionCount, DimensionCount> { - template <typename Box1, typename Box2> - static inline bool apply(Box1 const& , Box2 const& ) + template <typename Box1, typename Box2, typename Strategy> + static inline bool apply(Box1 const& , Box2 const& , Strategy const& ) { return true; } @@ -97,8 +116,8 @@ struct box_box<DimensionCount, DimensionCount> struct segment_segment { - template <typename Segment1, typename Segment2> - static inline bool apply(Segment1 const& segment1, Segment2 const& segment2) + template <typename Segment1, typename Segment2, typename Strategy> + static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& ) { return equals::equals_point_point( indexed_point_view<Segment1 const, 0>(segment1), @@ -119,55 +138,75 @@ struct segment_segment struct area_check { - template <typename Geometry1, typename Geometry2> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return geometry::math::equals( - geometry::area(geometry1), - geometry::area(geometry2)); + geometry::area(geometry1, + strategy.template get_area_strategy<Geometry1>()), + geometry::area(geometry2, + strategy.template get_area_strategy<Geometry2>())); } }; struct length_check { - template <typename Geometry1, typename Geometry2> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return geometry::math::equals( - geometry::length(geometry1), - geometry::length(geometry2)); + geometry::length(geometry1, + strategy.template get_distance_strategy<Geometry1>()), + geometry::length(geometry2, + strategy.template get_distance_strategy<Geometry2>())); } }; +template <typename Geometry1, typename Geometry2, typename IntersectionStrategy> +struct collected_vector +{ + typedef typename geometry::select_most_precise + < + typename select_coordinate_type + < + Geometry1, Geometry2 + >::type, + double + >::type calculation_type; + + typedef geometry::collected_vector + < + calculation_type, + Geometry1, + typename IntersectionStrategy::side_strategy_type + > type; +}; + template <typename TrivialCheck> struct equals_by_collection { - template <typename Geometry1, typename Geometry2> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - if (! TrivialCheck::apply(geometry1, geometry2)) + if (! TrivialCheck::apply(geometry1, geometry2, strategy)) { return false; } - typedef typename geometry::select_most_precise - < - typename select_coordinate_type - < - Geometry1, Geometry2 - >::type, - double - >::type calculation_type; - - typedef geometry::collected_vector + typedef typename collected_vector < - calculation_type, - Geometry1 - > collected_vector; + Geometry1, Geometry2, Strategy + >::type collected_vector_type; - std::vector<collected_vector> c1, c2; + std::vector<collected_vector_type> c1, c2; geometry::collect_vectors(c1, geometry1); geometry::collect_vectors(c2, geometry2); @@ -195,6 +234,53 @@ struct equals_by_relate > {}; +// If collect_vectors which is a SideStrategy-dispatched optimization +// is implemented in a way consistent with the Intersection/Side Strategy +// then collect_vectors is used, otherwise relate is used. +// NOTE: the result could be coneptually different for invalid +// geometries in different coordinate systems because collect_vectors +// and relate treat invalid geometries differently. +template<typename TrivialCheck> +struct equals_by_collection_or_relate +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + typedef typename boost::is_base_of + < + nyi::not_implemented_tag, + typename collected_vector + < + Geometry1, Geometry2, Strategy + >::type + >::type enable_relate_type; + + return apply(geometry1, geometry2, strategy, enable_relate_type()); + } + +private: + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy, + boost::false_type /*enable_relate*/) + { + return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy, + boost::true_type /*enable_relate*/) + { + return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); + } +}; + + }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL @@ -226,7 +312,8 @@ template struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true> : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false> { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { return equals < @@ -234,19 +321,30 @@ struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true> Tag2, Tag1, DimensionCount, false - >::apply(g2, g1); + >::apply(g2, g1, strategy); } }; template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse> struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse> - : geometry::detail::not_ - < - detail::disjoint::point_point<P1, P2, 0, DimensionCount> - > + : detail::equals::point_point<0, DimensionCount> +{}; + +template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse> +struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse> + : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2> {}; +template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse> +struct equals<MultiPoint, Point, multi_point_tag, point_tag, DimensionCount, Reverse> + : detail::equals::equals_by_relate<MultiPoint, Point> +{}; + +template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse> +struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse> + : detail::equals::equals_by_relate<Point, MultiPoint> +{}; template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse> struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse> @@ -256,19 +354,19 @@ struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse> template <typename Ring1, typename Ring2, bool Reverse> struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse> - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Polygon1, typename Polygon2, bool Reverse> struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse> - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Polygon, typename Ring, bool Reverse> struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse> - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; @@ -290,7 +388,6 @@ struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reve template <typename LineString1, typename LineString2, bool Reverse> struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse> - //: detail::equals::equals_by_collection<detail::equals::length_check> : detail::equals::equals_by_relate<LineString1, LineString2> {}; @@ -313,7 +410,7 @@ struct equals 2, Reverse > - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; @@ -325,7 +422,7 @@ struct equals 2, Reverse > - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename MultiPolygon, typename Ring, bool Reverse> @@ -336,7 +433,7 @@ struct equals 2, Reverse > - : detail::equals::equals_by_collection<detail::equals::area_check> + : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; @@ -344,80 +441,129 @@ struct equals #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +struct equals +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return dispatch::equals + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename strategy::relate::services::default_strategy + < + Geometry1, + Geometry2 + >::type strategy_type; + + return dispatch::equals + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy_type()); + } +}; + +} // namespace resolve_strategy + + namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct equals { + template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2) + Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions - < - Geometry1 const, - Geometry2 const - >(); + < + Geometry1 const, + Geometry2 const + >(); - return dispatch::equals<Geometry1, Geometry2> - ::apply(geometry1, geometry2); + return resolve_strategy::equals + ::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { + template <typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2) + visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) + , m_strategy(strategy) {} template <typename Geometry1> inline bool operator()(Geometry1 const& geometry1) const { return equals<Geometry1, Geometry2> - ::apply(geometry1, m_geometry2); + ::apply(geometry1, m_geometry2, m_strategy); } }; + template <typename Strategy> static inline bool apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2 + Geometry2 const& geometry2, + Strategy const& strategy ) { - return boost::apply_visitor(visitor(geometry2), geometry1); + return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1) + visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) + , m_strategy(strategy) {} template <typename Geometry2> inline bool operator()(Geometry2 const& geometry2) const { return equals<Geometry1, Geometry2> - ::apply(m_geometry1, geometry2); + ::apply(m_geometry1, geometry2, m_strategy); } }; + template <typename Strategy> static inline bool apply( Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2 + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy ) { - return boost::apply_visitor(visitor(geometry1), geometry2); + return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; @@ -430,24 +576,33 @@ struct equals< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { + template <typename Strategy> struct visitor: static_visitor<bool> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + template <typename Geometry1, typename Geometry2> inline bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return equals<Geometry1, Geometry2> - ::apply(geometry1, geometry2); + ::apply(geometry1, geometry2, m_strategy); } }; + template <typename Strategy> static inline bool apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2 + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy ) { - return boost::apply_visitor(visitor(), geometry1, geometry2); + return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; @@ -464,18 +619,48 @@ struct equals< \ingroup equals \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Equals} \param geometry1 \param_geometry \param geometry2 \param_geometry +\param strategy \param_strategy{equals} \return \return_check2{are spatially equal} +\qbk{distinguish,with strategy} \qbk{[include reference/algorithms/equals.qbk]} + */ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool equals(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + return resolve_variant::equals + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); +} + +/*! +\brief \brief_check{are spatially equal} +\details \details_check12{equals, is spatially equal}. Spatially equal means + that the same point set is included. A box can therefore be spatially equal + to a ring or a polygon, or a linestring can be spatially equal to a + multi-linestring or a segment. This only works theoretically, not all + combinations are implemented yet. +\ingroup equals +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\return \return_check2{are spatially equal} + +\qbk{[include reference/algorithms/equals.qbk]} */ template <typename Geometry1, typename Geometry2> inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::equals<Geometry1, Geometry2> - ::apply(geometry1, geometry2); + ::apply(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp index 5349db76bb..12ae169f12 100644 --- a/boost/geometry/algorithms/intersects.hpp +++ b/boost/geometry/algorithms/intersects.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 2013-2014. -// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2017. +// Modifications copyright (c) 2013-2017, 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. @@ -29,6 +30,8 @@ #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/strategies/relate.hpp> + namespace boost { namespace geometry { @@ -52,6 +55,10 @@ inline bool intersects(Geometry const& geometry) concepts::check<Geometry const>(); typedef typename geometry::point_type<Geometry>::type point_type; + typedef typename strategy::relate::services::default_strategy + < + Geometry, Geometry + >::type strategy_type; typedef detail::no_rescale_policy rescale_policy_type; typedef detail::overlay::turn_info @@ -67,13 +74,14 @@ inline bool intersects(Geometry const& geometry) detail::overlay::assign_null_policy > turn_policy; + strategy_type strategy; rescale_policy_type robust_policy; detail::disjoint::disjoint_interrupt_policy policy; detail::self_get_turn_points::get_turns < turn_policy - >::apply(geometry, robust_policy, turns, policy); + >::apply(geometry, strategy, robust_policy, turns, policy); return policy.has_intersections; } @@ -83,6 +91,32 @@ inline bool intersects(Geometry const& geometry) \ingroup intersects \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Intersects} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{intersects} +\return \return_check2{intersect each other} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/intersects.qbk]} + */ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool intersects(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + concepts::check<Geometry1 const>(); + concepts::check<Geometry2 const>(); + + return ! geometry::disjoint(geometry1, geometry2, strategy); +} + + +/*! +\brief \brief_check2{have at least one intersection} +\ingroup intersects +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{intersect each other} diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp index 32738c294c..bedf17599b 100644 --- a/boost/geometry/algorithms/overlaps.hpp +++ b/boost/geometry/algorithms/overlaps.hpp @@ -4,8 +4,8 @@ // 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. +// This file was modified by Oracle on 2014, 2015, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -113,8 +113,8 @@ struct box_box_loop<DimensionCount, DimensionCount> struct box_box { - template <typename Box1, typename Box2> - static inline bool apply(Box1 const& b1, Box2 const& b2) + template <typename Box1, typename Box2, typename Strategy> + static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/) { bool overlaps = true; bool within1 = true; @@ -137,7 +137,6 @@ struct box_box }} // namespace detail::overlaps #endif // DOXYGEN_NO_DETAIL -//struct not_implemented_for_this_geometry_type : public boost::false_type {}; #ifndef DOXYGEN_NO_DISPATCH namespace dispatch @@ -175,6 +174,35 @@ struct overlaps<Box1, Box2, box_tag, box_tag> \ingroup overlaps \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Overlaps} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{overlaps} +\return \return_check2{overlap} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/overlaps.qbk]} +*/ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool overlaps(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + concepts::check<Geometry1 const>(); + concepts::check<Geometry2 const>(); + + return dispatch::overlaps + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); +} + +/*! +\brief \brief_check2{overlap} +\ingroup overlaps +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{overlap} @@ -187,11 +215,17 @@ inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2) concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); + typedef typename strategy::relate::services::default_strategy + < + Geometry1, + Geometry2 + >::type strategy_type; + return dispatch::overlaps < Geometry1, Geometry2 - >::apply(geometry1, geometry2); + >::apply(geometry1, geometry2, strategy_type()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/sym_difference.hpp b/boost/geometry/algorithms/sym_difference.hpp index 33f94c9321..725230cd5b 100644 --- a/boost/geometry/algorithms/sym_difference.hpp +++ b/boost/geometry/algorithms/sym_difference.hpp @@ -2,10 +2,11 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017 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 @@ -14,13 +15,21 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP + #include <algorithm> #include <iterator> #include <vector> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> +#include <boost/variant/variant_fwd.hpp> + #include <boost/geometry/algorithms/intersection.hpp> #include <boost/geometry/algorithms/union.hpp> #include <boost/geometry/geometries/multi_polygon.hpp> +#include <boost/geometry/policies/robustness/get_rescale_policy.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -276,14 +285,10 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, concepts::check<Geometry2 const>(); concepts::check<GeometryOut>(); - typedef intersection_strategies + typedef typename strategy::intersection::services::default_strategy < - typename cs_tag<GeometryOut>::type, - Geometry1, - Geometry2, - typename geometry::point_type<GeometryOut>::type, - RobustPolicy - > strategy_type; + typename cs_tag<GeometryOut>::type + >::type strategy_type; return sym_difference_insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy_type()); } @@ -292,6 +297,216 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, #endif // DOXYGEN_NO_DETAIL +namespace resolve_strategy { + +struct sym_difference +{ + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection, + typename Strategy + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + Strategy const& strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + detail::sym_difference::sym_difference_insert<geometry_out>( + geometry1, geometry2, robust_policy, + range::back_inserter(output_collection), + strategy); + } + + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + default_strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + detail::sym_difference::sym_difference_insert<geometry_out>( + geometry1, geometry2, robust_policy, + range::back_inserter(output_collection)); + } +}; + +} // resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct sym_difference +{ + template <typename Collection, typename Strategy> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, + geometry2); + + resolve_strategy::sym_difference::apply(geometry1, geometry2, + robust_policy, + output_collection, + strategy); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry2 const& m_geometry2; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + : m_geometry2(geometry2) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1> + void operator()(Geometry1 const& geometry1) const + { + sym_difference + < + Geometry1, + Geometry2 + >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry2, + output_collection, + strategy), + geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct sym_difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry1 const& m_geometry1; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, + Collection& output_collection, + Strategy const& strategy) + : m_geometry1(geometry1) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry2> + void operator()(Geometry2 const& geometry2) const + { + sym_difference + < + Geometry1, + Geometry2 + >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(Geometry1 const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry1, + output_collection, + strategy), + geometry2); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Collection& output_collection, Strategy const& strategy) + : m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1, typename Geometry2> + void operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + sym_difference + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(output_collection, + strategy), + geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc2{symmetric difference} \ingroup sym_difference @@ -300,39 +515,64 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc +\tparam Strategy \tparam_strategy{Sym_difference} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection +\param strategy \param_strategy{sym_difference} +\qbk{distinguish,with strategy} \qbk{[include reference/algorithms/sym_difference.qbk]} */ template < typename Geometry1, typename Geometry2, - typename Collection + typename Collection, + typename Strategy > inline void sym_difference(Geometry1 const& geometry1, - Geometry2 const& geometry2, Collection& output_collection) + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - - typedef typename boost::range_value<Collection>::type geometry_out; - concepts::check<geometry_out>(); - - typedef typename geometry::rescale_overlay_policy_type + resolve_variant::sym_difference < Geometry1, Geometry2 - >::type rescale_policy_type; + >::apply(geometry1, geometry2, output_collection, strategy); +} - rescale_policy_type robust_policy - = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); - detail::sym_difference::sym_difference_insert<geometry_out>( - geometry1, geometry2, robust_policy, - range::back_inserter(output_collection)); +/*! +\brief \brief_calc2{symmetric difference} +\ingroup sym_difference +\details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}. +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Collection output collection, either a multi-geometry, + or a std::vector<Geometry> / std::deque<Geometry> etc +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param output_collection the output collection + +\qbk{[include reference/algorithms/sym_difference.qbk]} +*/ +template +< + typename Geometry1, + typename Geometry2, + typename Collection +> +inline void sym_difference(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection) +{ + resolve_variant::sym_difference + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, output_collection, default_strategy()); } diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp index 6384cc2a88..49e104d258 100644 --- a/boost/geometry/algorithms/touches.hpp +++ b/boost/geometry/algorithms/touches.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -104,8 +104,8 @@ struct box_box_loop<DimensionCount, DimensionCount> struct box_box { - template <typename Box1, typename Box2> - static inline bool apply(Box1 const& b1, Box2 const& b2) + template <typename Box1, typename Box2, typename Strategy> + static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/) { BOOST_STATIC_ASSERT((boost::is_same < @@ -205,15 +205,17 @@ struct areal_interrupt_policy } }; -template<typename Geometry> +template<typename Geometry, typename PointInRingStrategy> struct check_each_ring_for_within { bool has_within; Geometry const& m_geometry; + PointInRingStrategy const& m_strategy; - inline check_each_ring_for_within(Geometry const& g) + inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy) : has_within(false) , m_geometry(g) + , m_strategy(strategy) {} template <typename Range> @@ -221,18 +223,31 @@ struct check_each_ring_for_within { typename geometry::point_type<Range>::type p; geometry::point_on_border(p, range); - if ( !has_within && geometry::within(p, m_geometry) ) + if ( !has_within && geometry::within(p, m_geometry, m_strategy) ) { has_within = true; } } }; -template <typename FirstGeometry, typename SecondGeometry> +template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy> inline bool rings_containing(FirstGeometry const& geometry1, - SecondGeometry const& geometry2) + SecondGeometry const& geometry2, + IntersectionStrategy const& strategy) { - check_each_ring_for_within<FirstGeometry> checker(geometry1); + // NOTE: This strategy could be defined inside IntersectionStrategy + typedef typename IntersectionStrategy::template point_in_geometry_strategy + < + FirstGeometry, SecondGeometry + >::type point_in_ring_strategy_type; + + point_in_ring_strategy_type point_in_ring_strategy + = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>(); + + check_each_ring_for_within + < + FirstGeometry, point_in_ring_strategy_type + > checker(geometry1, point_in_ring_strategy); geometry::detail::for_each_range(geometry2, checker); return checker.has_within; } @@ -240,8 +255,10 @@ inline bool rings_containing(FirstGeometry const& geometry1, template <typename Geometry1, typename Geometry2> struct areal_areal { - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename IntersectionStrategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + IntersectionStrategy const& strategy) { typedef detail::no_rescale_policy rescale_policy_type; typedef typename geometry::point_type<Geometry1>::type point_type; @@ -259,11 +276,11 @@ struct areal_areal detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, detail::overlay::assign_null_policy - >(geometry1, geometry2, robust_policy, turns, policy); + >(geometry1, geometry2, strategy, robust_policy, turns, policy); return policy.result() - && ! geometry::detail::touches::rings_containing(geometry1, geometry2) - && ! geometry::detail::touches::rings_containing(geometry2, geometry1); + && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy) + && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy); } }; @@ -271,10 +288,10 @@ struct areal_areal struct use_point_in_geometry { - template <typename Point, typename Geometry> - static inline bool apply(Point const& point, Geometry const& geometry) + template <typename Point, typename Geometry, typename Strategy> + static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { - return detail::within::point_in_geometry(point, geometry) == 0; + return detail::within::point_in_geometry(point, geometry, strategy) == 0; } }; @@ -288,7 +305,8 @@ namespace dispatch { template < - typename Geometry1, typename Geometry2, + typename Geometry1, + typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type, @@ -309,18 +327,30 @@ template struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true> : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false> { - static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) + template <typename Strategy> + static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { - return touches<Geometry2, Geometry1>::apply(g2, g1); + return touches<Geometry2, Geometry1>::apply(g2, g1, strategy); } }; // P/P -template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> -struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false> { - static inline bool apply(Geometry1 const& , Geometry2 const& ) + template <typename Strategy> + static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&) + { + return false; + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag2> +struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&) { return false; } @@ -403,66 +433,115 @@ struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false> #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +struct touches +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return dispatch::touches + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); + } + + template <typename Geometry1, typename Geometry2> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) + { + typedef typename strategy::relate::services::default_strategy + < + Geometry1, + Geometry2 + >::type strategy_type; + + return dispatch::touches + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy_type()); + } +}; + +} // namespace resolve_strategy + + namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct touches { - static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + template <typename Strategy> + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - return dispatch::touches<Geometry1, Geometry2> - ::apply(geometry1, geometry2); + return resolve_strategy::touches::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; + Strategy const& m_strategy; - visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {} + visitor(Geometry2 const& geometry2, Strategy const& strategy) + : m_geometry2(geometry2) + , m_strategy(strategy) + {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { - return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2); + return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); } }; - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2) + template <typename Strategy> + static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry2), geometry1); + return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; + Strategy const& m_strategy; - visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {} + visitor(Geometry1 const& geometry1, Strategy const& strategy) + : m_geometry1(geometry1) + , m_strategy(strategy) + {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { - return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2); + return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); } }; - static inline bool - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(geometry1), geometry2); + return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; @@ -471,21 +550,29 @@ template <BOOST_VARIANT_ENUM_PARAMS(typename T1), struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { + template <typename Strategy> struct visitor: boost::static_visitor<bool> { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { - return touches<Geometry1, Geometry2>::apply(geometry1, geometry2); + return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); } }; - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2) + template <typename Strategy> + static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Strategy const& strategy) { - return boost::apply_visitor(visitor(), geometry1, geometry2); + return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; @@ -496,6 +583,10 @@ struct self_touches { concepts::check<Geometry const>(); + typedef typename strategy::relate::services::default_strategy + < + Geometry, Geometry + >::type strategy_type; typedef detail::no_rescale_policy rescale_policy_type; typedef typename geometry::point_type<Geometry>::type point_type; typedef detail::overlay::turn_info @@ -511,11 +602,12 @@ struct self_touches std::deque<turn_info> turns; detail::touches::areal_interrupt_policy policy; + strategy_type strategy; rescale_policy_type robust_policy; detail::self_get_turn_points::get_turns < policy_type - >::apply(geometry, robust_policy, turns, policy); + >::apply(geometry, strategy, robust_policy, turns, policy); return policy.result(); } @@ -578,7 +670,35 @@ inline bool touches(Geometry const& geometry) template <typename Geometry1, typename Geometry2> inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::touches<Geometry1, Geometry2>::apply(geometry1, geometry2); + return resolve_variant::touches + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, default_strategy()); +} + +/*! +\brief \brief_check2{have at least one touching point (tangent - non overlapping)} +\ingroup touches +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Strategy \tparam_strategy{Touches} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param strategy \param_strategy{touches} +\return \return_check2{touch each other} + +\qbk{distinguish,with strategy} +\qbk{[include reference/algorithms/touches.qbk]} + */ +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool touches(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) +{ + return resolve_variant::touches + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); } diff --git a/boost/geometry/algorithms/union.hpp b/boost/geometry/algorithms/union.hpp index f0e55ec981..d3a2daf66e 100644 --- a/boost/geometry/algorithms/union.hpp +++ b/boost/geometry/algorithms/union.hpp @@ -2,10 +2,11 @@ // 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. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017 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 @@ -24,6 +25,8 @@ #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> @@ -214,14 +217,10 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, Geometry2 >::type rescale_policy_type; - typedef intersection_strategies + typename strategy::intersection::services::default_strategy < - typename cs_tag<GeometryOut>::type, - Geometry1, - Geometry2, - typename geometry::point_type<GeometryOut>::type, - rescale_policy_type - > strategy; + typename cs_tag<GeometryOut>::type + >::type strategy; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2); @@ -229,7 +228,7 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, return dispatch::union_insert < Geometry1, Geometry2, GeometryOut - >::apply(geometry1, geometry2, robust_policy, out, strategy()); + >::apply(geometry1, geometry2, robust_policy, out, strategy); } @@ -237,6 +236,228 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, #endif // DOXYGEN_NO_DETAIL +namespace resolve_strategy { + +struct union_ +{ + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection, + typename Strategy + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + Strategy const& strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + dispatch::union_insert + < + Geometry1, Geometry2, geometry_out + >::apply(geometry1, geometry2, robust_policy, + range::back_inserter(output_collection), + strategy); + } + + template + < + typename Geometry1, + typename Geometry2, + typename RobustPolicy, + typename Collection + > + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + Collection & output_collection, + default_strategy) + { + typedef typename boost::range_value<Collection>::type geometry_out; + + typedef typename strategy::intersection::services::default_strategy + < + typename cs_tag<geometry_out>::type + >::type strategy_type; + + dispatch::union_insert + < + Geometry1, Geometry2, geometry_out + >::apply(geometry1, geometry2, robust_policy, + range::back_inserter(output_collection), + strategy_type()); + } +}; + +} // resolve_strategy + + +namespace resolve_variant +{ + +template <typename Geometry1, typename Geometry2> +struct union_ +{ + template <typename Collection, typename Strategy> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + concepts::check<Geometry1 const>(); + concepts::check<Geometry2 const>(); + concepts::check<typename boost::range_value<Collection>::type>(); + + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>(geometry1, + geometry2); + + resolve_strategy::union_::apply(geometry1, geometry2, + robust_policy, + output_collection, + strategy); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> +struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry2 const& m_geometry2; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + : m_geometry2(geometry2) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1> + void operator()(Geometry1 const& geometry1) const + { + union_ + < + Geometry1, + Geometry2 + >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry2, + output_collection, + strategy), + geometry1); + } +}; + + +template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> +struct union_<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Geometry1 const& m_geometry1; + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1, + Collection& output_collection, + Strategy const& strategy) + : m_geometry1(geometry1) + , m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry2> + void operator()(Geometry2 const& geometry2) const + { + union_ + < + Geometry1, + Geometry2 + >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(Geometry1 const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(geometry1, + output_collection, + strategy), + geometry2); + } +}; + + +template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> +struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +{ + template <typename Collection, typename Strategy> + struct visitor: static_visitor<> + { + Collection& m_output_collection; + Strategy const& m_strategy; + + visitor(Collection& output_collection, Strategy const& strategy) + : m_output_collection(output_collection) + , m_strategy(strategy) + {} + + template <typename Geometry1, typename Geometry2> + void operator()(Geometry1 const& geometry1, + Geometry2 const& geometry2) const + { + union_ + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, m_output_collection, m_strategy); + } + }; + + template <typename Collection, typename Strategy> + static inline void + apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, + variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, + Collection& output_collection, + Strategy const& strategy) + { + boost::apply_visitor(visitor<Collection, Strategy>(output_collection, + strategy), + geometry1, geometry2); + } +}; + +} // namespace resolve_variant /*! @@ -247,31 +468,66 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc +\tparam Strategy \tparam_strategy{Union_} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection +\param strategy \param_strategy{union_} \note Called union_ because union is a reserved word. +\qbk{distinguish,with strategy} \qbk{[include reference/algorithms/union.qbk]} */ template < typename Geometry1, typename Geometry2, - typename Collection + typename Collection, + typename Strategy > inline void union_(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Collection& output_collection) + Geometry2 const& geometry2, + Collection& output_collection, + Strategy const& strategy) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); + resolve_variant::union_ + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, output_collection, strategy); +} - typedef typename boost::range_value<Collection>::type geometry_out; - concepts::check<geometry_out>(); - detail::union_::union_insert<geometry_out>(geometry1, geometry2, - range::back_inserter(output_collection)); +/*! +\brief Combines two geometries which each other +\ingroup union +\details \details_calc2{union, spatial set theoretic union}. +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Collection output collection, either a multi-geometry, + or a std::vector<Geometry> / std::deque<Geometry> etc +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param output_collection the output collection +\note Called union_ because union is a reserved word. + +\qbk{[include reference/algorithms/union.qbk]} +*/ +template +< + typename Geometry1, + typename Geometry2, + typename Collection +> +inline void union_(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Collection& output_collection) +{ + resolve_variant::union_ + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, output_collection, default_strategy()); } diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp index a1e6a58f8d..ba170dd27b 100644 --- a/boost/geometry/algorithms/within.hpp +++ b/boost/geometry/algorithms/within.hpp @@ -4,8 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -14,8 +16,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_WITHIN_HPP #define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP @@ -52,6 +52,7 @@ #include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> +#include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> @@ -75,9 +76,13 @@ struct use_point_in_geometry struct use_relate { template <typename Geometry1, typename Geometry2, typename Strategy> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/) + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return Strategy::apply(geometry1, geometry2); + typedef typename detail::de9im::static_mask_within_type + < + Geometry1, Geometry2 + >::type within_mask; + return geometry::relate(geometry1, geometry2, within_mask(), strategy); } }; @@ -300,23 +305,8 @@ struct within Geometry2 const& geometry2, default_strategy) { - typedef typename point_type<Geometry1>::type point_type1; - typedef typename point_type<Geometry2>::type point_type2; - typedef typename strategy::within::services::default_strategy < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag<Geometry1>::type, - typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, - typename tag_cast - < - typename cs_tag<point_type1>::type, spherical_tag - >::type, - typename tag_cast - < - typename cs_tag<point_type2>::type, spherical_tag - >::type, Geometry1, Geometry2 >::type strategy_type; @@ -517,8 +507,9 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) } */ template<typename Geometry1, typename Geometry2, typename Strategy> -inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, - Strategy const& strategy) +inline bool within(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return resolve_variant::within < diff --git a/boost/geometry/arithmetic/normalize.hpp b/boost/geometry/arithmetic/normalize.hpp new file mode 100644 index 0000000000..7dfdbd2b03 --- /dev/null +++ b/boost/geometry/arithmetic/normalize.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016, 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_ARITHMETIC_NORMALIZE_HPP +#define BOOST_GEOMETRY_ARITHMETIC_NORMALIZE_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> + +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/arithmetic/dot_product.hpp> +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Point> +inline typename coordinate_type<Point>::type vec_length_sqr(Point const& pt) +{ + return dot_product(pt, pt); +} + +template <typename Point> +inline typename coordinate_type<Point>::type vec_length(Point const& pt) +{ + // NOTE: hypot() could be used instead of sqrt() + return math::sqrt(dot_product(pt, pt)); +} + +template <typename Point> +inline bool vec_normalize(Point & pt, typename coordinate_type<Point>::type & len) +{ + typedef typename coordinate_type<Point>::type coord_t; + + coord_t const c0 = 0; + len = vec_length(pt); + + if (math::equals(len, c0)) + { + return false; + } + + divide_value(pt, len); + return true; +} + +template <typename Point> +inline bool vec_normalize(Point & pt) +{ + typedef typename coordinate_type<Point>::type coord_t; + coord_t len; + return vec_normalize(pt, len); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ARITHMETIC_NORMALIZE_HPP diff --git a/boost/geometry/core/srs.hpp b/boost/geometry/core/srs.hpp index bf1b4e28a5..5c78b9f1fc 100644 --- a/boost/geometry/core/srs.hpp +++ b/boost/geometry/core/srs.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, 2016, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -51,7 +51,7 @@ public: spheroid() : m_a(RadiusType(6378137.0)) - , m_b(RadiusType(6356752.314245)) + , m_b(RadiusType(6356752.3142451793)) {} template <std::size_t I> @@ -126,8 +126,9 @@ public: explicit sphere(RadiusType const& r) : m_r(r) {} + sphere() - : m_r(RadiusType((2.0 * 6378137.0 + 6356752.314245) / 3.0)) + : m_r(RadiusType((2.0 * 6378137.0 + 6356752.3142451793) / 3.0)) {} template <std::size_t I> diff --git a/boost/geometry/formulas/andoyer_inverse.hpp b/boost/geometry/formulas/andoyer_inverse.hpp index 57b5ab5384..902fd7d8f6 100644 --- a/boost/geometry/formulas/andoyer_inverse.hpp +++ b/boost/geometry/formulas/andoyer_inverse.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2015-2016 Oracle and/or its affiliates. +// Copyright (c) 2015-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -20,9 +20,8 @@ #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> -#include <boost/geometry/algorithms/detail/flattening.hpp> - #include <boost/geometry/formulas/differential_quantities.hpp> +#include <boost/geometry/formulas/flattening.hpp> #include <boost/geometry/formulas/result_inverse.hpp> @@ -75,7 +74,7 @@ public: CT const c0 = CT(0); CT const c1 = CT(1); CT const pi = math::pi<CT>(); - CT const f = detail::flattening<CT>(spheroid); + CT const f = formula::flattening<CT>(spheroid); CT const dlon = lon2 - lon1; CT const sin_dlon = sin(dlon); @@ -97,7 +96,7 @@ public: CT const d = acos(cos_d); // [0, pi] CT const sin_d = sin(d); // [-1, 1] - + if ( BOOST_GEOMETRY_CONDITION(EnableDistance) ) { CT const K = math::sqr(sin_lat1-sin_lat2); @@ -138,7 +137,14 @@ public: CT A = c0; CT U = c0; - if ( ! math::equals(cos_lat2, c0) ) + if (math::equals(cos_lat2, c0)) + { + if (sin_lat2 < c0) + { + A = pi; + } + } + else { CT const tan_lat2 = sin_lat2/cos_lat2; CT const M = cos_lat1*tan_lat2-sin_lat1*cos_dlon; @@ -149,7 +155,14 @@ public: CT B = c0; CT V = c0; - if ( ! math::equals(cos_lat1, c0) ) + if (math::equals(cos_lat1, c0)) + { + if (sin_lat1 < c0) + { + B = pi; + } + } + else { CT const tan_lat1 = sin_lat1/cos_lat1; CT const N = cos_lat2*tan_lat1-sin_lat2*cos_dlon; diff --git a/boost/geometry/formulas/area_formulas.hpp b/boost/geometry/formulas/area_formulas.hpp new file mode 100644 index 0000000000..6a0b525e25 --- /dev/null +++ b/boost/geometry/formulas/area_formulas.hpp @@ -0,0 +1,578 @@ +// Boost.Geometry + +// Copyright (c) 2015-2016 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_AREA_FORMULAS_HPP +#define BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP + +#include <boost/geometry/formulas/flattening.hpp> +#include <boost/math/special_functions/hypot.hpp> + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief Formulas for computing spherical and ellipsoidal polygon area. + The current class computes the area of the trapezoid defined by a segment + the two meridians passing by the endpoints and the equator. +\author See +- Danielsen JS, The area under the geodesic. Surv Rev 30(232): +61–66, 1989 +- Charles F.F Karney, Algorithms for geodesics, 2011 +https://arxiv.org/pdf/1109.4448.pdf +*/ + +template < + typename CT, + std::size_t SeriesOrder = 2, + bool ExpandEpsN = true +> +class area_formulas +{ + +public: + + //TODO: move the following to a more general space to be used by other + // classes as well + /* + Evaluate the polynomial in x using Horner's method. + */ + template <typename NT, typename IteratorType> + static inline NT horner_evaluate(NT x, + IteratorType begin, + IteratorType end) + { + NT result(0); + IteratorType it = end; + do + { + result = result * x + *--it; + } + while (it != begin); + return result; + } + + /* + Clenshaw algorithm for summing trigonometric series + https://en.wikipedia.org/wiki/Clenshaw_algorithm + */ + template <typename NT, typename IteratorType> + static inline NT clenshaw_sum(NT cosx, + IteratorType begin, + IteratorType end) + { + IteratorType it = end; + bool odd = true; + CT b_k, b_k1(0), b_k2(0); + do + { + CT c_k = odd ? *--it : NT(0); + b_k = c_k + NT(2) * cosx * b_k1 - b_k2; + b_k2 = b_k1; + b_k1 = b_k; + odd = !odd; + } + while (it != begin); + + return *begin + b_k1 * cosx - b_k2; + } + + template<typename T> + static inline void normalize(T& x, T& y) + { + T h = boost::math::hypot(x, y); + x /= h; + y /= h; + } + + /* + Generate and evaluate the series expansion of the following integral + + I4 = -integrate( (t(ep2) - t(k2*sin(sigma1)^2)) / (ep2 - k2*sin(sigma1)^2) + * sin(sigma1)/2, sigma1, pi/2, sigma ) + where + + t(x) = sqrt(1+1/x)*asinh(sqrt(x)) + x + + valid for ep2 and k2 small. We substitute k2 = 4 * eps / (1 - eps)^2 + and ep2 = 4 * n / (1 - n)^2 and expand in eps and n. + + The resulting sum of the series is of the form + + sum(C4[l] * cos((2*l+1)*sigma), l, 0, maxpow-1) ) + + The above expansion is performed in Computer Algebra System Maxima. + The C++ code (that yields the function evaluate_coeffs_n below) is generated + by the following Maxima script and is based on script: + http://geographiclib.sourceforge.net/html/geod.mac + + // Maxima script begin + taylordepth:5$ + ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$ + jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1], + ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$ + + compute(maxpow):=block([int,t,intexp,area, x,ep2,k2], + maxpow:maxpow-1, + t : sqrt(1+1/x) * asinh(sqrt(x)) + x, + int:-(tf(ep2) - tf(k2*sin(sigma)^2)) / (ep2 - k2*sin(sigma)^2) + * sin(sigma)/2, + int:subst([tf(ep2)=subst([x=ep2],t), + tf(k2*sin(sigma)^2)=subst([x=k2*sin(sigma)^2],t)], + int), + int:subst([abs(sin(sigma))=sin(sigma)],int), + int:subst([k2=4*eps/(1-eps)^2,ep2=4*n/(1-n)^2],int), + intexp:jtaylor(int,n,eps,maxpow), + area:trigreduce(integrate(intexp,sigma)), + area:expand(area-subst(sigma=%pi/2,area)), + for i:0 thru maxpow do C4[i]:coeff(area,cos((2*i+1)*sigma)), + if expand(area-sum(C4[i]*cos((2*i+1)*sigma),i,0,maxpow)) # 0 + then error("left over terms in I4"), + 'done)$ + + printcode(maxpow):= + block([tab2:" ",tab3:" "], + print(" switch (SeriesOrder) {"), + for nn:1 thru maxpow do block([c], + print(concat(tab2,"case ",string(nn-1),":")), + c:0, + for m:0 thru nn-1 do block( + [q:jtaylor(subst([n=n],C4[m]),n,eps,nn-1), + linel:1200], + for j:m thru nn-1 do ( + print(concat(tab3,"coeffs_n[",c,"] = ", + string(horner(coeff(q,eps,j))),";")), + c:c+1) + ), + print(concat(tab3,"break;"))), + print(" }"), + 'done)$ + + maxpow:6$ + compute(maxpow)$ + printcode(maxpow)$ + // Maxima script end + + In the resulting code we should replace each number x by CT(x) + e.g. using the following scirpt: + sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g; + s/case\sCT(/case /g; s/):/:/g' + */ + + static inline void evaluate_coeffs_n(CT n, CT coeffs_n[]) + { + + switch (SeriesOrder) { + case 0: + coeffs_n[0] = CT(2)/CT(3); + break; + case 1: + coeffs_n[0] = (CT(10)-CT(4)*n)/CT(15); + coeffs_n[1] = -CT(1)/CT(5); + coeffs_n[2] = CT(1)/CT(45); + break; + case 2: + coeffs_n[0] = (n*(CT(8)*n-CT(28))+CT(70))/CT(105); + coeffs_n[1] = (CT(16)*n-CT(7))/CT(35); + coeffs_n[2] = -CT(2)/CT(105); + coeffs_n[3] = (CT(7)-CT(16)*n)/CT(315); + coeffs_n[4] = -CT(2)/CT(105); + coeffs_n[5] = CT(4)/CT(525); + break; + case 3: + coeffs_n[0] = (n*(n*(CT(4)*n+CT(24))-CT(84))+CT(210))/CT(315); + coeffs_n[1] = ((CT(48)-CT(32)*n)*n-CT(21))/CT(105); + coeffs_n[2] = (-CT(32)*n-CT(6))/CT(315); + coeffs_n[3] = CT(11)/CT(315); + coeffs_n[4] = (n*(CT(32)*n-CT(48))+CT(21))/CT(945); + coeffs_n[5] = (CT(64)*n-CT(18))/CT(945); + coeffs_n[6] = -CT(1)/CT(105); + coeffs_n[7] = (CT(12)-CT(32)*n)/CT(1575); + coeffs_n[8] = -CT(8)/CT(1575); + coeffs_n[9] = CT(8)/CT(2205); + break; + case 4: + coeffs_n[0] = (n*(n*(n*(CT(16)*n+CT(44))+CT(264))-CT(924))+CT(2310))/CT(3465); + coeffs_n[1] = (n*(n*(CT(48)*n-CT(352))+CT(528))-CT(231))/CT(1155); + coeffs_n[2] = (n*(CT(1088)*n-CT(352))-CT(66))/CT(3465); + coeffs_n[3] = (CT(121)-CT(368)*n)/CT(3465); + coeffs_n[4] = CT(4)/CT(1155); + coeffs_n[5] = (n*((CT(352)-CT(48)*n)*n-CT(528))+CT(231))/CT(10395); + coeffs_n[6] = ((CT(704)-CT(896)*n)*n-CT(198))/CT(10395); + coeffs_n[7] = (CT(80)*n-CT(99))/CT(10395); + coeffs_n[8] = CT(4)/CT(1155); + coeffs_n[9] = (n*(CT(320)*n-CT(352))+CT(132))/CT(17325); + coeffs_n[10] = (CT(384)*n-CT(88))/CT(17325); + coeffs_n[11] = -CT(8)/CT(1925); + coeffs_n[12] = (CT(88)-CT(256)*n)/CT(24255); + coeffs_n[13] = -CT(16)/CT(8085); + coeffs_n[14] = CT(64)/CT(31185); + break; + case 5: + coeffs_n[0] = (n*(n*(n*(n*(CT(100)*n+CT(208))+CT(572))+CT(3432))-CT(12012))+CT(30030)) + /CT(45045); + coeffs_n[1] = (n*(n*(n*(CT(64)*n+CT(624))-CT(4576))+CT(6864))-CT(3003))/CT(15015); + coeffs_n[2] = (n*((CT(14144)-CT(10656)*n)*n-CT(4576))-CT(858))/CT(45045); + coeffs_n[3] = ((-CT(224)*n-CT(4784))*n+CT(1573))/CT(45045); + coeffs_n[4] = (CT(1088)*n+CT(156))/CT(45045); + coeffs_n[5] = CT(97)/CT(15015); + coeffs_n[6] = (n*(n*((-CT(64)*n-CT(624))*n+CT(4576))-CT(6864))+CT(3003))/CT(135135); + coeffs_n[7] = (n*(n*(CT(5952)*n-CT(11648))+CT(9152))-CT(2574))/CT(135135); + coeffs_n[8] = (n*(CT(5792)*n+CT(1040))-CT(1287))/CT(135135); + coeffs_n[9] = (CT(468)-CT(2944)*n)/CT(135135); + coeffs_n[10] = CT(1)/CT(9009); + coeffs_n[11] = (n*((CT(4160)-CT(1440)*n)*n-CT(4576))+CT(1716))/CT(225225); + coeffs_n[12] = ((CT(4992)-CT(8448)*n)*n-CT(1144))/CT(225225); + coeffs_n[13] = (CT(1856)*n-CT(936))/CT(225225); + coeffs_n[14] = CT(8)/CT(10725); + coeffs_n[15] = (n*(CT(3584)*n-CT(3328))+CT(1144))/CT(315315); + coeffs_n[16] = (CT(1024)*n-CT(208))/CT(105105); + coeffs_n[17] = -CT(136)/CT(63063); + coeffs_n[18] = (CT(832)-CT(2560)*n)/CT(405405); + coeffs_n[19] = -CT(128)/CT(135135); + coeffs_n[20] = CT(128)/CT(99099); + break; + } + } + + /* + Expand in k2 and ep2. + */ + static inline void evaluate_coeffs_ep(CT ep, CT coeffs_n[]) + { + switch (SeriesOrder) { + case 0: + coeffs_n[0] = CT(2)/CT(3); + break; + case 1: + coeffs_n[0] = (CT(10)-ep)/CT(15); + coeffs_n[1] = -CT(1)/CT(20); + coeffs_n[2] = CT(1)/CT(180); + break; + case 2: + coeffs_n[0] = (ep*(CT(4)*ep-CT(7))+CT(70))/CT(105); + coeffs_n[1] = (CT(4)*ep-CT(7))/CT(140); + coeffs_n[2] = CT(1)/CT(42); + coeffs_n[3] = (CT(7)-CT(4)*ep)/CT(1260); + coeffs_n[4] = -CT(1)/CT(252); + coeffs_n[5] = CT(1)/CT(2100); + break; + case 3: + coeffs_n[0] = (ep*((CT(12)-CT(8)*ep)*ep-CT(21))+CT(210))/CT(315); + coeffs_n[1] = ((CT(12)-CT(8)*ep)*ep-CT(21))/CT(420); + coeffs_n[2] = (CT(3)-CT(2)*ep)/CT(126); + coeffs_n[3] = -CT(1)/CT(72); + coeffs_n[4] = (ep*(CT(8)*ep-CT(12))+CT(21))/CT(3780); + coeffs_n[5] = (CT(2)*ep-CT(3))/CT(756); + coeffs_n[6] = CT(1)/CT(360); + coeffs_n[7] = (CT(3)-CT(2)*ep)/CT(6300); + coeffs_n[8] = -CT(1)/CT(1800); + coeffs_n[9] = CT(1)/CT(17640); + break; + case 4: + coeffs_n[0] = (ep*(ep*(ep*(CT(64)*ep-CT(88))+CT(132))-CT(231))+CT(2310))/CT(3465); + coeffs_n[1] = (ep*(ep*(CT(64)*ep-CT(88))+CT(132))-CT(231))/CT(4620); + coeffs_n[2] = (ep*(CT(16)*ep-CT(22))+CT(33))/CT(1386); + coeffs_n[3] = (CT(8)*ep-CT(11))/CT(792); + coeffs_n[4] = CT(1)/CT(110); + coeffs_n[5] = (ep*((CT(88)-CT(64)*ep)*ep-CT(132))+CT(231))/CT(41580); + coeffs_n[6] = ((CT(22)-CT(16)*ep)*ep-CT(33))/CT(8316); + coeffs_n[7] = (CT(11)-CT(8)*ep)/CT(3960); + coeffs_n[8] = -CT(1)/CT(495); + coeffs_n[9] = (ep*(CT(16)*ep-CT(22))+CT(33))/CT(69300); + coeffs_n[10] = (CT(8)*ep-CT(11))/CT(19800); + coeffs_n[11] = CT(1)/CT(1925); + coeffs_n[12] = (CT(11)-CT(8)*ep)/CT(194040); + coeffs_n[13] = -CT(1)/CT(10780); + coeffs_n[14] = CT(1)/CT(124740); + break; + case 5: + coeffs_n[0] = (ep*(ep*(ep*((CT(832)-CT(640)*ep)*ep-CT(1144))+CT(1716))-CT(3003))+CT(30030))/CT(45045); + coeffs_n[1] = (ep*(ep*((CT(832)-CT(640)*ep)*ep-CT(1144))+CT(1716))-CT(3003))/CT(60060); + coeffs_n[2] = (ep*((CT(208)-CT(160)*ep)*ep-CT(286))+CT(429))/CT(18018); + coeffs_n[3] = ((CT(104)-CT(80)*ep)*ep-CT(143))/CT(10296); + coeffs_n[4] = (CT(13)-CT(10)*ep)/CT(1430); + coeffs_n[5] = -CT(1)/CT(156); + coeffs_n[6] = (ep*(ep*(ep*(CT(640)*ep-CT(832))+CT(1144))-CT(1716))+CT(3003))/CT(540540); + coeffs_n[7] = (ep*(ep*(CT(160)*ep-CT(208))+CT(286))-CT(429))/CT(108108); + coeffs_n[8] = (ep*(CT(80)*ep-CT(104))+CT(143))/CT(51480); + coeffs_n[9] = (CT(10)*ep-CT(13))/CT(6435); + coeffs_n[10] = CT(5)/CT(3276); + coeffs_n[11] = (ep*((CT(208)-CT(160)*ep)*ep-CT(286))+CT(429))/CT(900900); + coeffs_n[12] = ((CT(104)-CT(80)*ep)*ep-CT(143))/CT(257400); + coeffs_n[13] = (CT(13)-CT(10)*ep)/CT(25025); + coeffs_n[14] = -CT(1)/CT(2184); + coeffs_n[15] = (ep*(CT(80)*ep-CT(104))+CT(143))/CT(2522520); + coeffs_n[16] = (CT(10)*ep-CT(13))/CT(140140); + coeffs_n[17] = CT(5)/CT(45864); + coeffs_n[18] = (CT(13)-CT(10)*ep)/CT(1621620); + coeffs_n[19] = -CT(1)/CT(58968); + coeffs_n[20] = CT(1)/CT(792792); + break; + } + } + + /* + Given the set of coefficients coeffs1[] evaluate on var2 and return + the set of coefficients coeffs2[] + */ + static inline void evaluate_coeffs_var2(CT var2, + CT coeffs1[], + CT coeffs2[]){ + std::size_t begin(0), end(0); + for(std::size_t i = 0; i <= SeriesOrder; i++){ + end = begin + SeriesOrder + 1 - i; + coeffs2[i] = ((i==0) ? CT(1) : pow(var2,int(i))) + * horner_evaluate(var2, coeffs1 + begin, coeffs1 + end); + begin = end; + } + } + + /* + Compute the spherical excess of a geodesic (or shperical) segment + */ + template < + bool LongSegment, + typename PointOfSegment + > + static inline CT spherical(PointOfSegment const& p1, + PointOfSegment const& p2) + { + CT excess; + + if(LongSegment) // not for segments parallel to equator + { + CT cbet1 = cos(geometry::get_as_radian<1>(p1)); + CT sbet1 = sin(geometry::get_as_radian<1>(p1)); + CT cbet2 = cos(geometry::get_as_radian<1>(p2)); + CT sbet2 = sin(geometry::get_as_radian<1>(p2)); + + CT omg12 = geometry::get_as_radian<0>(p1) + - geometry::get_as_radian<0>(p2); + CT comg12 = cos(omg12); + CT somg12 = sin(omg12); + + CT alp1 = atan2(cbet1 * sbet2 + - sbet1 * cbet2 * comg12, + cbet2 * somg12); + + CT alp2 = atan2(cbet1 * sbet2 * comg12 + - sbet1 * cbet2, + cbet1 * somg12); + + excess = alp2 - alp1; + + } else { + + // Trapezoidal formula + + CT tan_lat1 = + tan(geometry::get_as_radian<1>(p1) / 2.0); + CT tan_lat2 = + tan(geometry::get_as_radian<1>(p2) / 2.0); + + excess = CT(2.0) + * atan(((tan_lat1 + tan_lat2) / (CT(1) + tan_lat1 * tan_lat2)) + * tan((geometry::get_as_radian<0>(p2) + - geometry::get_as_radian<0>(p1)) / 2)); + } + + return excess; + } + + struct return_type_ellipsoidal + { + return_type_ellipsoidal() + : spherical_term(0), + ellipsoidal_term(0) + {} + + CT spherical_term; + CT ellipsoidal_term; + }; + + /* + Compute the ellipsoidal correction of a geodesic (or shperical) segment + */ + template < + template <typename, bool, bool, bool, bool, bool> class Inverse, + //typename AzimuthStrategy, + typename PointOfSegment, + typename SpheroidConst + > + static inline return_type_ellipsoidal ellipsoidal(PointOfSegment const& p1, + PointOfSegment const& p2, + SpheroidConst spheroid_const) + { + return_type_ellipsoidal result; + + // Azimuth Approximation + + typedef Inverse<CT, false, true, true, false, false> inverse_type; + typedef typename inverse_type::result_type inverse_result; + + inverse_result i_res = inverse_type::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.m_spheroid); + + CT alp1 = i_res.azimuth; + CT alp2 = i_res.reverse_azimuth; + + // Constants + + CT const ep = spheroid_const.m_ep; + CT const f = formula::flattening<CT>(spheroid_const.m_spheroid); + CT const one_minus_f = CT(1) - f; + std::size_t const series_order_plus_one = SeriesOrder + 1; + std::size_t const series_order_plus_two = SeriesOrder + 2; + + // Basic trigonometric computations + + CT tan_bet1 = tan(get_as_radian<1>(p1)) * one_minus_f; + CT tan_bet2 = tan(get_as_radian<1>(p2)) * one_minus_f; + CT cos_bet1 = cos(atan(tan_bet1)); + CT cos_bet2 = cos(atan(tan_bet2)); + CT sin_bet1 = tan_bet1 * cos_bet1; + CT sin_bet2 = tan_bet2 * cos_bet2; + CT sin_alp1 = sin(alp1); + CT cos_alp1 = cos(alp1); + CT cos_alp2 = cos(alp2); + CT sin_alp0 = sin_alp1 * cos_bet1; + + // Spherical term computation + + CT sin_omg1 = sin_alp0 * sin_bet1; + CT cos_omg1 = cos_alp1 * cos_bet1; + CT sin_omg2 = sin_alp0 * sin_bet2; + CT cos_omg2 = cos_alp2 * cos_bet2; + CT cos_omg12 = cos_omg1 * cos_omg2 + sin_omg1 * sin_omg2; + CT excess; + + bool meridian = get<0>(p2) - get<0>(p1) == CT(0) + || get<1>(p1) == CT(90) || get<1>(p1) == -CT(90) + || get<1>(p2) == CT(90) || get<1>(p2) == -CT(90); + + if (!meridian && cos_omg12 > -CT(0.7) + && sin_bet2 - sin_bet1 < CT(1.75)) // short segment + { + CT sin_omg12 = cos_omg1 * sin_omg2 - sin_omg1 * cos_omg2; + normalize(sin_omg12, cos_omg12); + + CT cos_omg12p1 = CT(1) + cos_omg12; + CT cos_bet1p1 = CT(1) + cos_bet1; + CT cos_bet2p1 = CT(1) + cos_bet2; + excess = CT(2) * atan2(sin_omg12 * (sin_bet1 * cos_bet2p1 + sin_bet2 * cos_bet1p1), + cos_omg12p1 * (sin_bet1 * sin_bet2 + cos_bet1p1 * cos_bet2p1)); + } + else + { + /* + CT sin_alp2 = sin(alp2); + CT sin_alp12 = sin_alp2 * cos_alp1 - cos_alp2 * sin_alp1; + CT cos_alp12 = cos_alp2 * cos_alp1 + sin_alp2 * sin_alp1; + excess = atan2(sin_alp12, cos_alp12); + */ + excess = alp2 - alp1; + } + + result.spherical_term = excess; + + // Ellipsoidal term computation (uses integral approximation) + + CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); + CT cos_sig1 = cos_alp1 * cos_bet1; + CT cos_sig2 = cos_alp2 * cos_bet2; + CT sin_sig1 = sin_bet1; + CT sin_sig2 = sin_bet2; + + normalize(sin_sig1, cos_sig1); + normalize(sin_sig2, cos_sig2); + + CT coeffs[SeriesOrder + 1]; + const std::size_t coeffs_var_size = (series_order_plus_two + * series_order_plus_one) / 2; + CT coeffs_var[coeffs_var_size]; + + if(ExpandEpsN){ // expand by eps and n + + CT k2 = math::sqr(ep * cos_alp0); + CT sqrt_k2_plus_one = math::sqrt(CT(1) + k2); + CT eps = (sqrt_k2_plus_one - CT(1)) / (sqrt_k2_plus_one + CT(1)); + CT n = f / (CT(2) - f); + + // Generate and evaluate the polynomials on n + // to get the series coefficients (that depend on eps) + evaluate_coeffs_n(n, coeffs_var); + + // Generate and evaluate the polynomials on eps (i.e. var2 = eps) + // to get the final series coefficients + evaluate_coeffs_var2(eps, coeffs_var, coeffs); + + }else{ // expand by k2 and ep + + CT k2 = math::sqr(ep * cos_alp0); + CT ep2 = math::sqr(ep); + + // Generate and evaluate the polynomials on ep2 + evaluate_coeffs_ep(ep2, coeffs_var); + + // Generate and evaluate the polynomials on k2 (i.e. var2 = k2) + evaluate_coeffs_var2(k2, coeffs_var, coeffs); + + } + + // Evaluate the trigonometric sum + CT I12 = clenshaw_sum(cos_sig2, coeffs, coeffs + series_order_plus_one) + - clenshaw_sum(cos_sig1, coeffs, coeffs + series_order_plus_one); + + // The part of the ellipsodal correction that depends on + // point coordinates + result.ellipsoidal_term = cos_alp0 * sin_alp0 * I12; + + return result; + } + + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + template <typename PointOfSegment, typename StateType> + static inline int crosses_prime_meridian(PointOfSegment const& p1, + PointOfSegment const& p2, + StateType& state) + { + CT const pi + = geometry::math::pi<CT>(); + CT const two_pi + = geometry::math::two_pi<CT>(); + + CT p1_lon = get_as_radian<0>(p1) + - ( floor( get_as_radian<0>(p1) / two_pi ) + * two_pi ); + CT p2_lon = get_as_radian<0>(p2) + - ( floor( get_as_radian<0>(p2) / two_pi ) + * two_pi ); + + CT max_lon = (std::max)(p1_lon, p2_lon); + CT min_lon = (std::min)(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.m_crosses_prime_meridian++; + } + + return state.m_crosses_prime_meridian; + } + +}; + +}}} // namespace boost::geometry::formula + + +#endif // BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP diff --git a/boost/geometry/formulas/differential_quantities.hpp b/boost/geometry/formulas/differential_quantities.hpp index 9a92f14e18..ff2ec539db 100644 --- a/boost/geometry/formulas/differential_quantities.hpp +++ b/boost/geometry/formulas/differential_quantities.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2016 Oracle and/or its affiliates. +// Copyright (c) 2016-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -64,8 +64,8 @@ public: CT const c1 = 1; CT const one_minus_f = c1 - f; - CT const sin_bet1 = one_minus_f * sin_lat1; - CT const sin_bet2 = one_minus_f * sin_lat2; + CT sin_bet1 = one_minus_f * sin_lat1; + CT sin_bet2 = one_minus_f * sin_lat2; // equator if (math::equals(sin_bet1, c0) && math::equals(sin_bet2, c0)) @@ -89,14 +89,17 @@ public: CT const e2 = f * (c2 - f); CT const ep2 = e2 / math::sqr(one_minus_f); - CT const cos_bet1 = cos_lat1; - CT const cos_bet2 = cos_lat2; - CT const sin_alp1 = sin(azimuth); CT const cos_alp1 = cos(azimuth); //CT const sin_alp2 = sin(reverse_azimuth); CT const cos_alp2 = cos(reverse_azimuth); + CT cos_bet1 = cos_lat1; + CT cos_bet2 = cos_lat2; + + normalize(sin_bet1, cos_bet1); + normalize(sin_bet2, cos_bet2); + CT sin_sig1 = sin_bet1; CT cos_sig1 = cos_alp1 * cos_bet1; CT sin_sig2 = sin_bet2; @@ -112,8 +115,8 @@ public: J12_f(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f) : J12_ep_sqr(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, ep2) ; - CT const dn1 = math::sqrt(c1 + e2 * math::sqr(sin_lat1)); - CT const dn2 = math::sqrt(c1 + e2 * math::sqr(sin_lat2)); + CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_bet1)); + CT const dn2 = math::sqrt(c1 + ep2 * math::sqr(sin_bet2)); if (BOOST_GEOMETRY_CONDITION(EnableReducedLength)) { diff --git a/boost/geometry/formulas/eccentricity_sqr.hpp b/boost/geometry/formulas/eccentricity_sqr.hpp new file mode 100644 index 0000000000..01a9beacb9 --- /dev/null +++ b/boost/geometry/formulas/eccentricity_sqr.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry + +// Copyright (c) 2016 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_FORMULAS_ECCENCRICITY_SQR_HPP +#define BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_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 formula_dispatch +{ + +template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type> +struct eccentricity_sqr + : not_implemented<Tag> +{}; + +template <typename ResultType, typename Geometry> +struct eccentricity_sqr<ResultType, Geometry, srs_sphere_tag> +{ + static inline ResultType apply(Geometry const& /*geometry*/) + { + return ResultType(0); + } +}; + +template <typename ResultType, typename Geometry> +struct eccentricity_sqr<ResultType, Geometry, srs_spheroid_tag> +{ + static inline ResultType apply(Geometry const& geometry) + { + // 1 - (b / a)^2 + return ResultType(1) - math::sqr(ResultType(get_radius<2>(geometry)) + / ResultType(get_radius<0>(geometry))); + } +}; + +} // namespace formula_dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace formula +{ + +template <typename ResultType, typename Geometry> +ResultType eccentricity_sqr(Geometry const& geometry) +{ + return formula_dispatch::eccentricity_sqr<ResultType, Geometry>::apply(geometry); +} + +} // namespace formula +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP diff --git a/boost/geometry/algorithms/detail/flattening.hpp b/boost/geometry/formulas/flattening.hpp index 8ed5fd9a89..f94ead65b0 100644 --- a/boost/geometry/algorithms/detail/flattening.hpp +++ b/boost/geometry/formulas/flattening.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2014 Oracle and/or its affiliates. +// Copyright (c) 2014-2016 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -8,8 +8,8 @@ // Version 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 +#ifndef BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP +#define BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP #include <boost/geometry/core/radius.hpp> #include <boost/geometry/core/tag.hpp> @@ -21,7 +21,7 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH -namespace detail_dispatch +namespace formula_dispatch { template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type> @@ -43,27 +43,28 @@ struct flattening<ResultType, Geometry, srs_spheroid_tag> { static inline ResultType apply(Geometry const& geometry) { + // (a - b) / a return ResultType(get_radius<0>(geometry) - get_radius<2>(geometry)) / ResultType(get_radius<0>(geometry)); } }; -} // namespace detail_dispatch +} // namespace formula_dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL -namespace detail +namespace formula { template <typename ResultType, typename Geometry> ResultType flattening(Geometry const& geometry) { - return detail_dispatch::flattening<ResultType, Geometry>::apply(geometry); + return formula_dispatch::flattening<ResultType, Geometry>::apply(geometry); } -} // namespace detail +} // namespace formula #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP +#endif // BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP diff --git a/boost/geometry/formulas/geographic.hpp b/boost/geometry/formulas/geographic.hpp new file mode 100644 index 0000000000..f6feb66633 --- /dev/null +++ b/boost/geometry/formulas/geographic.hpp @@ -0,0 +1,457 @@ +// Boost.Geometry + +// Copyright (c) 2016, 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_FORMULAS_GEOGRAPHIC_HPP +#define BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_HPP + +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> + +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/arithmetic/cross_product.hpp> +#include <boost/geometry/arithmetic/dot_product.hpp> +#include <boost/geometry/arithmetic/normalize.hpp> + +#include <boost/geometry/formulas/eccentricity_sqr.hpp> +#include <boost/geometry/formulas/flattening.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + +namespace boost { namespace geometry { + +namespace formula { + +template <typename Point3d, typename PointGeo, typename Spheroid> +inline Point3d geo_to_cart3d(PointGeo const& point_geo, Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type calc_t; + + calc_t const c1 = 1; + calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid); + + calc_t const lon = get_as_radian<0>(point_geo); + calc_t const lat = get_as_radian<1>(point_geo); + + Point3d res; + + calc_t const sin_lat = sin(lat); + + // "unit" spheroid, a = 1 + calc_t const N = c1 / math::sqrt(c1 - e_sqr * math::sqr(sin_lat)); + calc_t const N_cos_lat = N * cos(lat); + + set<0>(res, N_cos_lat * cos(lon)); + set<1>(res, N_cos_lat * sin(lon)); + set<2>(res, N * (c1 - e_sqr) * sin_lat); + + return res; +} + +template <typename PointGeo, typename Spheroid, typename Point3d> +inline void geo_to_cart3d(PointGeo const& point_geo, Point3d & result, Point3d & north, Point3d & east, Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type calc_t; + + calc_t const c1 = 1; + calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid); + + calc_t const lon = get_as_radian<0>(point_geo); + calc_t const lat = get_as_radian<1>(point_geo); + + calc_t const sin_lon = sin(lon); + calc_t const cos_lon = cos(lon); + calc_t const sin_lat = sin(lat); + calc_t const cos_lat = cos(lat); + + // "unit" spheroid, a = 1 + calc_t const N = c1 / math::sqrt(c1 - e_sqr * math::sqr(sin_lat)); + calc_t const N_cos_lat = N * cos_lat; + + set<0>(result, N_cos_lat * cos_lon); + set<1>(result, N_cos_lat * sin_lon); + set<2>(result, N * (c1 - e_sqr) * sin_lat); + + set<0>(east, -sin_lon); + set<1>(east, cos_lon); + set<2>(east, 0); + + set<0>(north, -sin_lat * cos_lon); + set<1>(north, -sin_lat * sin_lon); + set<2>(north, cos_lat); +} + +template <typename PointGeo, typename Point3d, typename Spheroid> +inline PointGeo cart3d_to_geo(Point3d const& point_3d, Spheroid const& spheroid) +{ + typedef typename coordinate_type<PointGeo>::type coord_t; + typedef typename coordinate_type<Point3d>::type calc_t; + + calc_t const c1 = 1; + //calc_t const c2 = 2; + calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid); + + calc_t const x = get<0>(point_3d); + calc_t const y = get<1>(point_3d); + calc_t const z = get<2>(point_3d); + calc_t const xy_l = math::sqrt(math::sqr(x) + math::sqr(y)); + + calc_t const lonr = atan2(y, x); + + // NOTE: Alternative version + // http://www.iag-aig.org/attach/989c8e501d9c5b5e2736955baf2632f5/V60N2_5FT.pdf + // calc_t const lonr = c2 * atan2(y, x + xy_l); + + calc_t const latr = atan2(z, (c1 - e_sqr) * xy_l); + + // NOTE: If h is equal to 0 then there is no need to improve value of latitude + // because then N_i / (N_i + h_i) = 1 + // http://www.navipedia.net/index.php/Ellipsoidal_and_Cartesian_Coordinates_Conversion + + PointGeo res; + + set_from_radian<0>(res, lonr); + set_from_radian<1>(res, latr); + + coord_t lon = get<0>(res); + coord_t lat = get<1>(res); + + math::normalize_spheroidal_coordinates + < + typename coordinate_system<PointGeo>::type::units, + coord_t + >(lon, lat); + + set<0>(res, lon); + set<1>(res, lat); + + return res; +} + +template <typename Point3d, typename Spheroid> +inline Point3d projected_to_xy(Point3d const& point_3d, Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + // len_xy = sqrt(x^2 + y^2) + // r = len_xy - |z / tan(lat)| + // assuming h = 0 + // lat = atan2(z, (1 - e^2) * len_xy); + // |z / tan(lat)| = (1 - e^2) * len_xy + // r = e^2 * len_xy + // x_res = r * cos(lon) = e^2 * len_xy * x / len_xy = e^2 * x + // y_res = r * sin(lon) = e^2 * len_xy * y / len_xy = e^2 * y + + coord_t const c0 = 0; + coord_t const e_sqr = formula::eccentricity_sqr<coord_t>(spheroid); + + Point3d res; + + set<0>(res, e_sqr * get<0>(point_3d)); + set<1>(res, e_sqr * get<1>(point_3d)); + set<2>(res, c0); + + return res; +} + +template <typename Point3d, typename Spheroid> +inline Point3d projected_to_surface(Point3d const& direction, Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + //coord_t const c0 = 0; + coord_t const c2 = 2; + coord_t const c4 = 4; + + // calculate the point of intersection of a ray and spheroid's surface + // the origin is the origin of the coordinate system + //(x*x+y*y)/(a*a) + z*z/(b*b) = 1 + // x = d.x * t + // y = d.y * t + // z = d.z * t + coord_t const dx = get<0>(direction); + coord_t const dy = get<1>(direction); + coord_t const dz = get<2>(direction); + + //coord_t const a_sqr = math::sqr(get_radius<0>(spheroid)); + //coord_t const b_sqr = math::sqr(get_radius<2>(spheroid)); + // "unit" spheroid, a = 1 + coord_t const a_sqr = 1; + coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid)); + + coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr; + coord_t const delta = c4 * param_a; + // delta >= 0 + coord_t const t = math::sqrt(delta) / (c2 * param_a); + + // result = direction * t + Point3d result = direction; + multiply_value(result, t); + + return result; +} + +template <typename Point3d, typename Spheroid> +inline bool projected_to_surface(Point3d const& origin, Point3d const& direction, Point3d & result1, Point3d & result2, Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + coord_t const c0 = 0; + coord_t const c1 = 1; + coord_t const c2 = 2; + coord_t const c4 = 4; + + // calculate the point of intersection of a ray and spheroid's surface + //(x*x+y*y)/(a*a) + z*z/(b*b) = 1 + // x = o.x + d.x * t + // y = o.y + d.y * t + // z = o.z + d.z * t + coord_t const ox = get<0>(origin); + coord_t const oy = get<1>(origin); + coord_t const oz = get<2>(origin); + coord_t const dx = get<0>(direction); + coord_t const dy = get<1>(direction); + coord_t const dz = get<2>(direction); + + //coord_t const a_sqr = math::sqr(get_radius<0>(spheroid)); + //coord_t const b_sqr = math::sqr(get_radius<2>(spheroid)); + // "unit" spheroid, a = 1 + coord_t const a_sqr = 1; + coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid)); + + coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr; + coord_t const param_b = c2 * ((ox*dx + oy*dy) / a_sqr + oz*dz / b_sqr); + coord_t const param_c = (ox*ox + oy*oy) / a_sqr + oz*oz / b_sqr - c1; + + coord_t const delta = math::sqr(param_b) - c4 * param_a*param_c; + + // equals() ? + if (delta < c0 || param_a == 0) + { + return false; + } + + // result = origin + direction * t + + coord_t const sqrt_delta = math::sqrt(delta); + coord_t const two_a = c2 * param_a; + + coord_t const t1 = (-param_b + sqrt_delta) / two_a; + result1 = direction; + multiply_value(result1, t1); + add_point(result1, origin); + + coord_t const t2 = (-param_b - sqrt_delta) / two_a; + result2 = direction; + multiply_value(result2, t2); + add_point(result2, origin); + + return true; +} + +template <typename Point3d, typename Spheroid> +inline bool great_elliptic_intersection(Point3d const& a1, Point3d const& a2, + Point3d const& b1, Point3d const& b2, + Point3d & result, + Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + coord_t c0 = 0; + coord_t c1 = 1; + + Point3d n1 = cross_product(a1, a2); + Point3d n2 = cross_product(b1, b2); + + // intersection direction + Point3d id = cross_product(n1, n2); + coord_t id_len_sqr = dot_product(id, id); + + if (math::equals(id_len_sqr, c0)) + { + return false; + } + + // no need to normalize a1 and a2 because the intersection point on + // the opposite side of the globe is at the same distance from the origin + coord_t cos_a1i = dot_product(a1, id); + coord_t cos_a2i = dot_product(a2, id); + coord_t gri = math::detail::greatest(cos_a1i, cos_a2i); + Point3d neg_id = id; + multiply_value(neg_id, -c1); + coord_t cos_a1ni = dot_product(a1, neg_id); + coord_t cos_a2ni = dot_product(a2, neg_id); + coord_t grni = math::detail::greatest(cos_a1ni, cos_a2ni); + + if (gri >= grni) + { + result = projected_to_surface(id, spheroid); + } + else + { + result = projected_to_surface(neg_id, spheroid); + } + + return true; +} + +template <typename Point3d1, typename Point3d2> +static inline int elliptic_side_value(Point3d1 const& origin, Point3d1 const& norm, Point3d2 const& pt) +{ + typedef typename coordinate_type<Point3d1>::type calc_t; + calc_t c0 = 0; + + // vector oposite to pt - origin + // only for the purpose of assigning origin + Point3d1 vec = origin; + subtract_point(vec, pt); + + calc_t d = dot_product(norm, vec); + + // since the vector is opposite the signs are opposite + return math::equals(d, c0) ? 0 + : d < c0 ? 1 + : -1; // d > 0 +} + +template <typename Point3d, typename Spheroid> +inline bool planes_spheroid_intersection(Point3d const& o1, Point3d const& n1, + Point3d const& o2, Point3d const& n2, + Point3d & ip1, Point3d & ip2, + Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + coord_t c0 = 0; + coord_t c1 = 1; + + // Below + // n . (p - o) = 0 + // n . p - n . o = 0 + // n . p + d = 0 + // n . p = h + + // intersection direction + Point3d id = cross_product(n1, n2); + + if (math::equals(dot_product(id, id), c0)) + { + return false; + } + + coord_t dot_n1_n2 = dot_product(n1, n2); + coord_t dot_n1_n2_sqr = math::sqr(dot_n1_n2); + + coord_t h1 = dot_product(n1, o1); + coord_t h2 = dot_product(n2, o2); + + coord_t denom = c1 - dot_n1_n2_sqr; + coord_t C1 = (h1 - h2 * dot_n1_n2) / denom; + coord_t C2 = (h2 - h1 * dot_n1_n2) / denom; + + // C1 * n1 + C2 * n2 + Point3d C1_n1 = n1; + multiply_value(C1_n1, C1); + Point3d C2_n2 = n2; + multiply_value(C2_n2, C2); + Point3d io = C1_n1; + add_point(io, C2_n2); + + if (! projected_to_surface(io, id, ip1, ip2, spheroid)) + { + return false; + } + + return true; +} + + +template <typename Point3d, typename Spheroid> +inline void experimental_elliptic_plane(Point3d const& p1, Point3d const& p2, + Point3d & v1, Point3d & v2, + Point3d & origin, Point3d & normal, + Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + Point3d xy1 = projected_to_xy(p1, spheroid); + Point3d xy2 = projected_to_xy(p2, spheroid); + + // origin = (xy1 + xy2) / 2 + origin = xy1; + add_point(origin, xy2); + multiply_value(origin, coord_t(0.5)); + + // v1 = p1 - origin + v1 = p1; + subtract_point(v1, origin); + // v2 = p2 - origin + v2 = p2; + subtract_point(v2, origin); + + normal = cross_product(v1, v2); +} + +template <typename Point3d, typename Spheroid> +inline void experimental_elliptic_plane(Point3d const& p1, Point3d const& p2, + Point3d & origin, Point3d & normal, + Spheroid const& spheroid) +{ + Point3d v1, v2; + experimental_elliptic_plane(p1, p2, v1, v2, origin, normal, spheroid); +} + +template <typename Point3d, typename Spheroid> +inline bool experimental_elliptic_intersection(Point3d const& a1, Point3d const& a2, + Point3d const& b1, Point3d const& b2, + Point3d & result, + Spheroid const& spheroid) +{ + typedef typename coordinate_type<Point3d>::type coord_t; + + coord_t c0 = 0; + coord_t c1 = 1; + + Point3d a1v, a2v, o1, n1; + experimental_elliptic_plane(a1, a2, a1v, a2v, o1, n1, spheroid); + Point3d b1v, b2v, o2, n2; + experimental_elliptic_plane(b1, b2, b1v, b2v, o2, n2, spheroid); + + if (! detail::vec_normalize(n1) || ! detail::vec_normalize(n2)) + { + return false; + } + + Point3d ip1_s, ip2_s; + if (! planes_spheroid_intersection(o1, n1, o2, n2, ip1_s, ip2_s, spheroid)) + { + return false; + } + + // NOTE: simplified test, may not work in all cases + coord_t dot_a1i1 = dot_product(a1, ip1_s); + coord_t dot_a2i1 = dot_product(a2, ip1_s); + coord_t gri1 = math::detail::greatest(dot_a1i1, dot_a2i1); + coord_t dot_a1i2 = dot_product(a1, ip2_s); + coord_t dot_a2i2 = dot_product(a2, ip2_s); + coord_t gri2 = math::detail::greatest(dot_a1i2, dot_a2i2); + + result = gri1 >= gri2 ? ip1_s : ip2_s; + + return true; +} + +} // namespace formula + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_HPP diff --git a/boost/geometry/formulas/gnomonic_spheroid.hpp b/boost/geometry/formulas/gnomonic_spheroid.hpp index 3457397b0f..4710c6c063 100644 --- a/boost/geometry/formulas/gnomonic_spheroid.hpp +++ b/boost/geometry/formulas/gnomonic_spheroid.hpp @@ -14,12 +14,11 @@ #include <boost/geometry/core/radius.hpp> -#include <boost/geometry/algorithms/detail/flattening.hpp> - #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/formulas/andoyer_inverse.hpp> +#include <boost/geometry/formulas/flattening.hpp> #include <boost/geometry/formulas/thomas_inverse.hpp> #include <boost/geometry/formulas/vincenty_direct.hpp> #include <boost/geometry/formulas/vincenty_inverse.hpp> diff --git a/boost/geometry/formulas/sjoberg_intersection.hpp b/boost/geometry/formulas/sjoberg_intersection.hpp index 03bd4bc97e..92f9e8e78e 100644 --- a/boost/geometry/formulas/sjoberg_intersection.hpp +++ b/boost/geometry/formulas/sjoberg_intersection.hpp @@ -20,19 +20,606 @@ #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> -#include <boost/geometry/algorithms/detail/flattening.hpp> +#include <boost/geometry/formulas/flattening.hpp> +#include <boost/geometry/formulas/spherical.hpp> namespace boost { namespace geometry { namespace formula { /*! +\brief The intersection of two great circles as proposed by Sjoberg. +\see See + - [Sjoberg02] Lars E. Sjoberg, Intersections on the sphere and ellipsoid, 2002 + http://link.springer.com/article/10.1007/s00190-001-0230-9 +*/ +template <typename CT> +struct sjoberg_intersection_spherical_02 +{ + // TODO: if it will be used as standalone formula + // support segments on equator and endpoints on poles + + static inline bool apply(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2, + CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2, + CT & lon, CT & lat) + { + CT tan_lat = 0; + bool res = apply_alt(lon1, lat1, lon_a2, lat_a2, + lon2, lat2, lon_b2, lat_b2, + lon, tan_lat); + + if (res) + { + lat = atan(tan_lat); + } + + return res; + } + + static inline bool apply_alt(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2, + CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2, + CT & lon, CT & tan_lat) + { + CT const cos_lon1 = cos(lon1); + CT const sin_lon1 = sin(lon1); + CT const cos_lon2 = cos(lon2); + CT const sin_lon2 = sin(lon2); + CT const sin_lat1 = sin(lat1); + CT const sin_lat2 = sin(lat2); + CT const cos_lat1 = cos(lat1); + CT const cos_lat2 = cos(lat2); + + CT const tan_lat_a2 = tan(lat_a2); + CT const tan_lat_b2 = tan(lat_b2); + + return apply(lon1, lon_a2, lon2, lon_b2, + sin_lon1, cos_lon1, sin_lat1, cos_lat1, + sin_lon2, cos_lon2, sin_lat2, cos_lat2, + tan_lat_a2, tan_lat_b2, + lon, tan_lat); + } + +private: + static inline bool apply(CT const& lon1, CT const& lon_a2, CT const& lon2, CT const& lon_b2, + CT const& sin_lon1, CT const& cos_lon1, CT const& sin_lat1, CT const& cos_lat1, + CT const& sin_lon2, CT const& cos_lon2, CT const& sin_lat2, CT const& cos_lat2, + CT const& tan_lat_a2, CT const& tan_lat_b2, + CT & lon, CT & tan_lat) + { + // NOTE: + // cos_lat_ = 0 <=> segment on equator + // tan_alpha_ = 0 <=> segment vertical + + CT const tan_lat1 = sin_lat1 / cos_lat1; //tan(lat1); + CT const tan_lat2 = sin_lat2 / cos_lat2; //tan(lat2); + + CT const dlon1 = lon_a2 - lon1; + CT const sin_dlon1 = sin(dlon1); + CT const dlon2 = lon_b2 - lon2; + CT const sin_dlon2 = sin(dlon2); + + CT const c0 = 0; + bool const is_vertical1 = math::equals(sin_dlon1, c0); + bool const is_vertical2 = math::equals(sin_dlon2, c0); + + CT tan_alpha1 = 0; + CT tan_alpha2 = 0; + + if (is_vertical1 && is_vertical2) + { + // circles intersect at one of the poles or are collinear + return false; + } + else if (is_vertical1) + { + CT const cos_dlon2 = cos(dlon2); + CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2; + tan_alpha2 = sin_dlon2 / tan_alpha2_x; + + lon = lon1; + } + else if (is_vertical2) + { + CT const cos_dlon1 = cos(dlon1); + CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1; + tan_alpha1 = sin_dlon1 / tan_alpha1_x; + + lon = lon2; + } + else + { + CT const cos_dlon1 = cos(dlon1); + CT const cos_dlon2 = cos(dlon2); + + CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1; + CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2; + tan_alpha1 = sin_dlon1 / tan_alpha1_x; + tan_alpha2 = sin_dlon2 / tan_alpha2_x; + + CT const T1 = tan_alpha1 * cos_lat1; + CT const T2 = tan_alpha2 * cos_lat2; + CT const T1T2 = T1*T2; + CT const tan_lon_y = T1 * sin_lon2 - T2 * sin_lon1 + T1T2 * (tan_lat1 * cos_lon1 - tan_lat2 * cos_lon2); + CT const tan_lon_x = T1 * cos_lon2 - T2 * cos_lon1 - T1T2 * (tan_lat1 * sin_lon1 - tan_lat2 * sin_lon2); + + lon = atan2(tan_lon_y, tan_lon_x); + } + + // choose closer result + CT const pi = math::pi<CT>(); + CT const lon_2 = lon > c0 ? lon - pi : lon + pi; + CT const lon_dist1 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon), + math::longitude_difference<radian>(lon_a2, lon)), + (std::min)(math::longitude_difference<radian>(lon2, lon), + math::longitude_difference<radian>(lon_b2, lon))); + CT const lon_dist2 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon_2), + math::longitude_difference<radian>(lon_a2, lon_2)), + (std::min)(math::longitude_difference<radian>(lon2, lon_2), + math::longitude_difference<radian>(lon_b2, lon_2))); + if (lon_dist2 < lon_dist1) + { + lon = lon_2; + } + + CT const sin_lon = sin(lon); + CT const cos_lon = cos(lon); + + if (math::abs(tan_alpha1) >= math::abs(tan_alpha2)) // pick less vertical segment + { + CT const sin_dlon_1 = sin_lon * cos_lon1 - cos_lon * sin_lon1; + CT const cos_dlon_1 = cos_lon * cos_lon1 + sin_lon * sin_lon1; + CT const lat_y_1 = sin_dlon_1 + tan_alpha1 * sin_lat1 * cos_dlon_1; + CT const lat_x_1 = tan_alpha1 * cos_lat1; + tan_lat = lat_y_1 / lat_x_1; + } + else + { + CT const sin_dlon_2 = sin_lon * cos_lon2 - cos_lon * sin_lon2; + CT const cos_dlon_2 = cos_lon * cos_lon2 + sin_lon * sin_lon2; + CT const lat_y_2 = sin_dlon_2 + tan_alpha2 * sin_lat2 * cos_dlon_2; + CT const lat_x_2 = tan_alpha2 * cos_lat2; + tan_lat = lat_y_2 / lat_x_2; + } + + return true; + } +}; + + +/*! Approximation of dLambda_j [Sjoberg07], expanded into taylor series in e^2 + Maxima script: + dLI_j(c_j, sinB_j, sinB) := integrate(1 / (sqrt(1 - c_j ^ 2 - x ^ 2)*(1 + sqrt(1 - e2*(1 - x ^ 2)))), x, sinB_j, sinB); + dL_j(c_j, B_j, B) := -e2 * c_j * dLI_j(c_j, B_j, B); + S: taylor(dLI_j(c_j, sinB_j, sinB), e2, 0, 3); + assume(c_j < 1); + assume(c_j > 0); + L1: factor(integrate(sqrt(-x ^ 2 - c_j ^ 2 + 1) / (x ^ 2 + c_j ^ 2 - 1), x)); + L2: factor(integrate(((x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + L3: factor(integrate(((x ^ 4 - 2 * x ^ 2 + 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + L4: factor(integrate(((x ^ 6 - 3 * x ^ 4 + 3 * x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + +\see See + - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007 + http://link.springer.com/article/10.1007/s00190-007-0204-7 +*/ +template <unsigned int Order, typename CT> +inline CT sjoberg_d_lambda_e_sqr(CT const& sin_betaj, CT const& sin_beta, + CT const& Cj, CT const& sqrt_1_Cj_sqr, + CT const& e_sqr) +{ + using math::detail::bounded; + + if (Order == 0) + { + return 0; + } + + CT const c1 = 1; + CT const c2 = 2; + + CT const asin_B = asin(bounded(sin_beta / sqrt_1_Cj_sqr, -c1, c1)); + CT const asin_Bj = asin(sin_betaj / sqrt_1_Cj_sqr); + CT const L0 = (asin_B - asin_Bj) / c2; + + if (Order == 1) + { + return -Cj * e_sqr * L0; + } + + CT const c0 = 0; + CT const c16 = 16; + + CT const X = sin_beta; + CT const Xj = sin_betaj; + CT const X_sqr = math::sqr(X); + CT const Xj_sqr = math::sqr(Xj); + CT const Cj_sqr = math::sqr(Cj); + CT const Cj_sqr_plus_one = Cj_sqr + c1; + CT const one_minus_Cj_sqr = c1 - Cj_sqr; + CT const sqrt_Y = math::sqrt(bounded(-X_sqr + one_minus_Cj_sqr, c0)); + CT const sqrt_Yj = math::sqrt(-Xj_sqr + one_minus_Cj_sqr); + CT const L1 = (Cj_sqr_plus_one * (asin_B - asin_Bj) + X * sqrt_Y - Xj * sqrt_Yj) / c16; + + if (Order == 2) + { + return -Cj * e_sqr * (L0 + e_sqr * L1); + } + + CT const c3 = 3; + CT const c5 = 5; + CT const c128 = 128; + + CT const E = Cj_sqr * (c3 * Cj_sqr + c2) + c3; + CT const F = X * (-c2 * X_sqr + c3 * Cj_sqr + c5); + CT const Fj = Xj * (-c2 * Xj_sqr + c3 * Cj_sqr + c5); + CT const L2 = (E * (asin_B - asin_Bj) + F * sqrt_Y - Fj * sqrt_Yj) / c128; + + if (Order == 3) + { + return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * L2)); + } + + CT const c8 = 8; + CT const c9 = 9; + CT const c10 = 10; + CT const c15 = 15; + CT const c24 = 24; + CT const c26 = 26; + CT const c33 = 33; + CT const c6144 = 6144; + + CT const G = Cj_sqr * (Cj_sqr * (Cj_sqr * c15 + c9) + c9) + c15; + CT const H = -c10 * Cj_sqr - c26; + CT const I = Cj_sqr * (Cj_sqr * c15 + c24) + c33; + CT const J = X_sqr * (X * (c8 * X_sqr + H)) + X * I; + CT const Jj = Xj_sqr * (Xj * (c8 * Xj_sqr + H)) + Xj * I; + CT const L3 = (G * (asin_B - asin_Bj) + J * sqrt_Y - Jj * sqrt_Yj) / c6144; + + // Order 4 and higher + return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * (L2 + e_sqr * L3))); +} + +/*! +\brief The representation of geodesic as proposed by Sjoberg. +\see See + - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007 + http://link.springer.com/article/10.1007/s00190-007-0204-7 + - [Sjoberg12] Lars E. Sjoberg, Solutions to the ellipsoidal Clairaut constant + and the inverse geodetic problem by numerical integration, 2012 + https://www.degruyter.com/view/j/jogs.2012.2.issue-3/v10156-011-0037-4/v10156-011-0037-4.xml +*/ +template <typename CT, unsigned int Order> +class sjoberg_geodesic +{ + sjoberg_geodesic() {} + + static int sign_C(CT const& alphaj) + { + CT const c0 = 0; + CT const c2 = 2; + CT const pi = math::pi<CT>(); + CT const pi_half = pi / c2; + + return (pi_half < alphaj && alphaj < pi) || (-pi_half < alphaj && alphaj < c0) ? -1 : 1; + } + +public: + sjoberg_geodesic(CT const& lon, CT const& lat, CT const& alpha, CT const& f) + : lonj(lon) + , latj(lat) + , alphaj(alpha) + { + CT const c0 = 0; + CT const c1 = 1; + CT const c2 = 2; + //CT const pi = math::pi<CT>(); + //CT const pi_half = pi / c2; + + one_minus_f = c1 - f; + e_sqr = f * (c2 - f); + + tan_latj = tan(lat); + tan_betaj = one_minus_f * tan_latj; + betaj = atan(tan_betaj); + sin_betaj = sin(betaj); + + cos_betaj = cos(betaj); + sin_alphaj = sin(alphaj); + // Clairaut constant (lower-case in the paper) + Cj = sign_C(alphaj) * cos_betaj * sin_alphaj; + Cj_sqr = math::sqr(Cj); + sqrt_1_Cj_sqr = math::sqrt(c1 - Cj_sqr); + + sign_lon_diff = alphaj >= 0 ? 1 : -1; // || alphaj == -pi ? + //sign_lon_diff = 1; + + is_on_equator = math::equals(sqrt_1_Cj_sqr, c0); + is_Cj_zero = math::equals(Cj, c0); + + t0j = c0; + asin_tj_t0j = c0; + + if (! is_Cj_zero) + { + t0j = sqrt_1_Cj_sqr / Cj; + } + + if (! is_on_equator) + { + //asin_tj_t0j = asin(tan_betaj / t0j); + asin_tj_t0j = asin(tan_betaj * Cj / sqrt_1_Cj_sqr); + } + } + + struct vertex_data + { + //CT beta0j; + CT sin_beta0j; + CT dL0j; + CT lon0j; + }; + + vertex_data get_vertex_data() const + { + CT const c2 = 2; + CT const pi = math::pi<CT>(); + CT const pi_half = pi / c2; + + vertex_data res; + + if (! is_Cj_zero) + { + //res.beta0j = atan(t0j); + //res.sin_beta0j = sin(res.beta0j); + res.sin_beta0j = math::sign(t0j) * sqrt_1_Cj_sqr; + res.dL0j = d_lambda(res.sin_beta0j); + res.lon0j = lonj + sign_lon_diff * (pi_half - asin_tj_t0j + res.dL0j); + } + else + { + //res.beta0j = pi_half; + //res.sin_beta0j = betaj >= 0 ? 1 : -1; + res.sin_beta0j = 1; + res.dL0j = 0; + res.lon0j = lonj; + } + + return res; + } + + bool is_sin_beta_ok(CT const& sin_beta) const + { + CT const c1 = 1; + return math::abs(sin_beta / sqrt_1_Cj_sqr) <= c1; + } + + bool k_diff(CT const& sin_beta, + CT & delta_k) const + { + if (is_Cj_zero) + { + delta_k = 0; + return true; + } + + // beta out of bounds and not close + if (! (is_sin_beta_ok(sin_beta) + || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) ) + { + return false; + } + + // NOTE: beta may be slightly out of bounds here but d_lambda handles that + CT const dLj = d_lambda(sin_beta); + delta_k = sign_lon_diff * (/*asin_t_t0j*/ - asin_tj_t0j + dLj); + + return true; + } + + bool lon_diff(CT const& sin_beta, CT const& t, + CT & delta_lon) const + { + using math::detail::bounded; + CT const c1 = 1; + + if (is_Cj_zero) + { + delta_lon = 0; + return true; + } + + CT delta_k = 0; + if (! k_diff(sin_beta, delta_k)) + { + return false; + } + + CT const t_t0j = t / t0j; + // NOTE: t may be slightly out of bounds here + CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1)); + delta_lon = sign_lon_diff * asin_t_t0j + delta_k; + + return true; + } + + bool k_diffs(CT const& sin_beta, vertex_data const& vd, + CT & delta_k_before, CT & delta_k_behind, + bool check_sin_beta = true) const + { + CT const pi = math::pi<CT>(); + + if (is_Cj_zero) + { + delta_k_before = 0; + delta_k_behind = sign_lon_diff * pi; + return true; + } + + // beta out of bounds and not close + if (check_sin_beta + && ! (is_sin_beta_ok(sin_beta) + || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) ) + { + return false; + } + + // NOTE: beta may be slightly out of bounds here but d_lambda handles that + CT const dLj = d_lambda(sin_beta); + delta_k_before = sign_lon_diff * (/*asin_t_t0j*/ - asin_tj_t0j + dLj); + + // This version require no additional dLj calculation + delta_k_behind = sign_lon_diff * (pi /*- asin_t_t0j*/ - asin_tj_t0j + vd.dL0j + (vd.dL0j - dLj)); + + // [Sjoberg12] + //CT const dL101 = d_lambda(sin_betaj, vd.sin_beta0j); + // WARNING: the following call might not work if beta was OoB because only the second argument is bounded + //CT const dL_01 = d_lambda(sin_beta, vd.sin_beta0j); + //delta_k_behind = sign_lon_diff * (pi /*- asin_t_t0j*/ - asin_tj_t0j + dL101 + dL_01); + + return true; + } + + bool lon_diffs(CT const& sin_beta, CT const& t, vertex_data const& vd, + CT & delta_lon_before, CT & delta_lon_behind) const + { + using math::detail::bounded; + CT const c1 = 1; + CT const pi = math::pi<CT>(); + + if (is_Cj_zero) + { + delta_lon_before = 0; + delta_lon_behind = sign_lon_diff * pi; + return true; + } + + CT delta_k_before = 0, delta_k_behind = 0; + if (! k_diffs(sin_beta, vd, delta_k_before, delta_k_behind)) + { + return false; + } + + CT const t_t0j = t / t0j; + // NOTE: t may be slightly out of bounds here + CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1)); + CT const sign_asin_t_t0j = sign_lon_diff * asin_t_t0j; + delta_lon_before = sign_asin_t_t0j + delta_k_before; + delta_lon_behind = -sign_asin_t_t0j + delta_k_behind; + + return true; + } + + bool lon(CT const& sin_beta, CT const& t, vertex_data const& vd, + CT & lon_before, CT & lon_behind) const + { + using math::detail::bounded; + CT const c1 = 1; + CT const pi = math::pi<CT>(); + + if (is_Cj_zero) + { + lon_before = lonj; + lon_behind = lonj + sign_lon_diff * pi; + return true; + } + + if (! (is_sin_beta_ok(sin_beta) + || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) ) + { + return false; + } + + CT const t_t0j = t / t0j; + CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1)); + CT const dLj = d_lambda(sin_beta); + lon_before = lonj + sign_lon_diff * (asin_t_t0j - asin_tj_t0j + dLj); + lon_behind = vd.lon0j + (vd.lon0j - lon_before); + + return true; + } + + + CT lon(CT const& delta_lon) const + { + return lonj + delta_lon; + } + + CT lat(CT const& t) const + { + // t = tan(beta) = (1-f)tan(lat) + return atan(t / one_minus_f); + } + + void vertex(CT & lon, CT & lat) const + { + lon = get_vertex_data().lon0j; + if (! is_Cj_zero) + { + lat = sjoberg_geodesic::lat(t0j); + } + else + { + CT const c2 = 2; + lat = math::pi<CT>() / c2; + } + } + + CT lon_of_equator_intersection() const + { + CT const c0 = 0; + CT const dLj = d_lambda(c0); + CT const asin_tj_t0j = asin(Cj * tan_betaj / sqrt_1_Cj_sqr); + return lonj - asin_tj_t0j + dLj; + } + + CT d_lambda(CT const& sin_beta) const + { + return sjoberg_d_lambda_e_sqr<Order>(sin_betaj, sin_beta, Cj, sqrt_1_Cj_sqr, e_sqr); + } + + // [Sjoberg12] + /*CT d_lambda(CT const& sin_beta1, CT const& sin_beta2) const + { + return sjoberg_d_lambda_e_sqr<Order>(sin_beta1, sin_beta2, Cj, sqrt_1_Cj_sqr, e_sqr); + }*/ + + CT lonj; + CT latj; + CT alphaj; + + CT one_minus_f; + CT e_sqr; + + CT tan_latj; + CT tan_betaj; + CT betaj; + CT sin_betaj; + CT cos_betaj; + CT sin_alphaj; + CT Cj; + CT Cj_sqr; + CT sqrt_1_Cj_sqr; + + int sign_lon_diff; + + bool is_on_equator; + bool is_Cj_zero; + + CT t0j; + CT asin_tj_t0j; +}; + + +/*! \brief The intersection of two geodesics as proposed by Sjoberg. -\author See +\see See - [Sjoberg02] Lars E. Sjoberg, Intersections on the sphere and ellipsoid, 2002 http://link.springer.com/article/10.1007/s00190-001-0230-9 - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007 http://link.springer.com/article/10.1007/s00190-007-0204-7 + - [Sjoberg12] Lars E. Sjoberg, Solutions to the ellipsoidal Clairaut constant + and the inverse geodetic problem by numerical integration, 2012 + https://www.degruyter.com/view/j/jogs.2012.2.issue-3/v10156-011-0037-4/v10156-011-0037-4.xml */ template < @@ -42,9 +629,14 @@ template > class sjoberg_intersection { + typedef sjoberg_geodesic<CT, Order> geodesic_type; typedef Inverse<CT, false, true, false, false, false> inverse_type; typedef typename inverse_type::result_type inverse_result; + static bool const enable_02 = true; + static int const max_iterations_02 = 10; + static int const max_iterations_07 = 20; + public: template <typename T1, typename T2, typename Spheroid> static inline bool apply(T1 const& lona1, T1 const& lata1, @@ -63,320 +655,562 @@ public: CT const lon_b2 = lonb2; CT const lat_b2 = latb2; - CT const alpha1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid).azimuth; - CT const alpha2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid).azimuth; + inverse_result const res1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid); + inverse_result const res2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid); - return apply(lon_a1, lat_a1, alpha1, lon_b1, lat_b1, alpha2, lon, lat, spheroid); + return apply(lon_a1, lat_a1, lon_a2, lat_a2, res1.azimuth, + lon_b1, lat_b1, lon_b2, lat_b2, res2.azimuth, + lon, lat, spheroid); } - + + // TODO: Currently may not work correctly if one of the endpoints is the pole template <typename Spheroid> - static inline bool apply(CT const& lon1, CT const& lat1, CT const& alpha1, - CT const& lon2, CT const& lat2, CT const& alpha2, + static inline bool apply(CT const& lon_a1, CT const& lat_a1, CT const& lon_a2, CT const& lat_a2, CT const& alpha_a1, + CT const& lon_b1, CT const& lat_b1, CT const& lon_b2, CT const& lat_b2, CT const& alpha_b1, CT & lon, CT & lat, Spheroid const& spheroid) { // coordinates in radians - // TODO - handle special cases like degenerated segments, equator, poles, etc. - CT const c0 = 0; CT const c1 = 1; - CT const c2 = 2; - CT const pi = math::pi<CT>(); - CT const pi_half = pi / c2; - CT const f = detail::flattening<CT>(spheroid); + CT const f = formula::flattening<CT>(spheroid); CT const one_minus_f = c1 - f; - CT const e_sqr = f * (c2 - f); - - CT const sin_alpha1 = sin(alpha1); - CT const sin_alpha2 = sin(alpha2); - - CT const tan_beta1 = one_minus_f * tan(lat1); - CT const tan_beta2 = one_minus_f * tan(lat2); - CT const beta1 = atan(tan_beta1); - CT const beta2 = atan(tan_beta2); - CT const cos_beta1 = cos(beta1); - CT const cos_beta2 = cos(beta2); - CT const sin_beta1 = sin(beta1); - CT const sin_beta2 = sin(beta2); - - // Clairaut constants (lower-case in the paper) - int const sign_C1 = math::abs(alpha1) <= pi_half ? 1 : -1; - int const sign_C2 = math::abs(alpha2) <= pi_half ? 1 : -1; - // Cj = 1 if on equator - CT const C1 = sign_C1 * cos_beta1 * sin_alpha1; - CT const C2 = sign_C2 * cos_beta2 * sin_alpha2; - - CT const sqrt_1_C1_sqr = math::sqrt(c1 - math::sqr(C1)); - CT const sqrt_1_C2_sqr = math::sqrt(c1 - math::sqr(C2)); - - // handle special case: segments on the equator - bool const on_equator1 = math::equals(sqrt_1_C1_sqr, c0); - bool const on_equator2 = math::equals(sqrt_1_C2_sqr, c0); - if (on_equator1 && on_equator2) + + geodesic_type geod1(lon_a1, lat_a1, alpha_a1, f); + geodesic_type geod2(lon_b1, lat_b1, alpha_b1, f); + + // Cj = 1 if on equator <=> sqrt_1_Cj_sqr = 0 + // Cj = 0 if vertical <=> sqrt_1_Cj_sqr = 1 + + if (geod1.is_on_equator && geod2.is_on_equator) { return false; } - else if (on_equator1) + else if (geod1.is_on_equator) { - CT const dL2 = d_lambda_e_sqr(sin_beta2, c0, C2, sqrt_1_C2_sqr, e_sqr); - CT const asin_t2_t02 = asin(C2 * tan_beta2 / sqrt_1_C2_sqr); + lon = geod2.lon_of_equator_intersection(); lat = c0; - lon = lon2 - asin_t2_t02 + dL2; return true; } - else if (on_equator2) + else if (geod2.is_on_equator) { - CT const dL1 = d_lambda_e_sqr(sin_beta1, c0, C1, sqrt_1_C1_sqr, e_sqr); - CT const asin_t1_t01 = asin(C1 * tan_beta1 / sqrt_1_C1_sqr); + lon = geod1.lon_of_equator_intersection(); lat = c0; - lon = lon1 - asin_t1_t01 + dL1; return true; } - CT const t01 = sqrt_1_C1_sqr / C1; - CT const t02 = sqrt_1_C2_sqr / C2; + // (lon1 - lon2) normalized to (-180, 180] + CT const lon1_minus_lon2 = math::longitude_distance_signed<radian>(geod2.lonj, geod1.lonj); - CT const asin_t1_t01 = asin(tan_beta1 / t01); - CT const asin_t2_t02 = asin(tan_beta2 / t02); - CT const t01_t02 = t01 * t02; - CT const t01_t02_2 = c2 * t01_t02; - CT const sqr_t01_sqr_t02 = math::sqr(t01) + math::sqr(t02); + // vertical segments + if (geod1.is_Cj_zero && geod2.is_Cj_zero) + { + CT const pi = math::pi<CT>(); - CT t = tan_beta1; - int t_id = 0; + // the geodesics are parallel, the intersection point cannot be calculated + if ( math::equals(lon1_minus_lon2, c0) + || math::equals(lon1_minus_lon2 + (lon1_minus_lon2 < c0 ? pi : -pi), c0) ) + { + return false; + } - // find the initial t using simplified spherical solution - // though not entirely since the reduced latitudes and azimuths are spheroidal - // [Sjoberg07] - CT const k_base = lon1 - lon2 + asin_t2_t02 - asin_t1_t01; - + lon = c0; + + // the geodesics intersect at one of the poles + CT const pi_half = pi / CT(2); + CT const abs_lat_a1 = math::abs(lat_a1); + CT const abs_lat_a2 = math::abs(lat_a2); + if (math::equals(abs_lat_a1, abs_lat_a2)) + { + lat = pi_half; + } + else + { + // pick the pole closest to one of the points of the first segment + CT const& closer_lat = abs_lat_a1 > abs_lat_a2 ? lat_a1 : lat_a2; + lat = closer_lat >= 0 ? pi_half : -pi_half; + } + + return true; + } + + CT lon_sph = 0; + + // Starting tan(beta) + CT t = 0; + + /*if (geod1.is_Cj_zero) { - CT const K = sin(k_base); - CT const d1 = sqr_t01_sqr_t02; - //CT const d2 = t01_t02_2 * math::sqrt(c1 - math::sqr(K)); - CT const d2 = t01_t02_2 * cos(k_base); - CT const D1 = math::sqrt(d1 - d2); - CT const D2 = math::sqrt(d1 + d2); - CT const K_t01_t02 = K * t01_t02; - - CT const T1 = K_t01_t02 / D1; - CT const T2 = K_t01_t02 / D2; - CT asin_T1_t01 = 0; - CT asin_T1_t02 = 0; - CT asin_T2_t01 = 0; - CT asin_T2_t02 = 0; - - // test 4 possible results - CT l1 = 0, l2 = 0, dl = 0; - bool found = check_t<0>( T1, - lon1, asin_T1_t01 = asin(T1 / t01), asin_t1_t01, - lon2, asin_T1_t02 = asin(T1 / t02), asin_t2_t02, - t, l1, l2, dl, t_id) - || check_t<1>(-T1, - lon1, -asin_T1_t01 , asin_t1_t01, - lon2, -asin_T1_t02 , asin_t2_t02, - t, l1, l2, dl, t_id) - || check_t<2>( T2, - lon1, asin_T2_t01 = asin(T2 / t01), asin_t1_t01, - lon2, asin_T2_t02 = asin(T2 / t02), asin_t2_t02, - t, l1, l2, dl, t_id) - || check_t<3>(-T2, - lon1, -asin_T2_t01 , asin_t1_t01, - lon2, -asin_T2_t02 , asin_t2_t02, - t, l1, l2, dl, t_id); - - boost::ignore_unused(found); + CT const k_base = lon1_minus_lon2 + geod2.sign_lon_diff * geod2.asin_tj_t0j; + t = sin(k_base) * geod2.t0j; + lon_sph = vertical_intersection_longitude(geod1.lonj, lon_b1, lon_b2); } + else if (geod2.is_Cj_zero) + { + CT const k_base = lon1_minus_lon2 - geod1.sign_lon_diff * geod1.asin_tj_t0j; + t = sin(-k_base) * geod1.t0j; + lon_sph = vertical_intersection_longitude(geod2.lonj, lon_a1, lon_a2); + } + else*/ + { + // TODO: Consider using betas instead of latitudes. + // Some function calls might be saved this way. + CT tan_lat_sph = 0; + sjoberg_intersection_spherical_02<CT>::apply_alt(lon_a1, lat_a1, lon_a2, lat_a2, + lon_b1, lat_b1, lon_b2, lat_b2, + lon_sph, tan_lat_sph); + t = one_minus_f * tan_lat_sph; // tan(beta) + } + + // TODO: no need to calculate atan here if reduced latitudes were used + // instead of latitudes above, in sjoberg_intersection_spherical_02 + CT const beta = atan(t); + + if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon, lat)) + { + return true; + } + + return converge_07(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat); + } + +private: + static inline bool newton_method(geodesic_type const& geod1, geodesic_type const& geod2, // in + CT beta, CT t, CT const& lon1_minus_lon2, // in + CT & lon, CT & lat) // out + { + CT const c0 = 0; + CT const c1 = 1; + + CT const e_sqr = geod1.e_sqr; - // [Sjoberg07] - //int const d2_sign = t_id < 2 ? -1 : 1; - int const t_sign = (t_id % 2) ? -1 : 1; - // [Sjoberg02] - CT const C1_sqr = math::sqr(C1); - CT const C2_sqr = math::sqr(C2); - - CT beta = atan(t); - CT dL1 = 0, dL2 = 0; - CT asin_t_t01 = 0; - CT asin_t_t02 = 0; + CT lon1_diff = 0; + CT lon2_diff = 0; - for (int i = 0; i < 10; ++i) + CT abs_dbeta_last = 0; + + // [Sjoberg02] converges faster than solution in [Sjoberg07] + // Newton-Raphson method + for (int i = 0; i < max_iterations_02; ++i) { CT const sin_beta = sin(beta); - - // integrals approximation - dL1 = d_lambda_e_sqr(sin_beta1, sin_beta, C1, sqrt_1_C1_sqr, e_sqr); - dL2 = d_lambda_e_sqr(sin_beta2, sin_beta, C2, sqrt_1_C2_sqr, e_sqr); - - // [Sjoberg07] - /*CT const k = k_base + dL1 - dL2; - CT const K = sin(k); - CT const d1 = sqr_t01_sqr_t02; - //CT const d2 = t01_t02_2 * math::sqrt(c1 - math::sqr(K)); - CT const d2 = t01_t02_2 * cos(k); - CT const D = math::sqrt(d1 + d2_sign * d2); - CT const t_new = t_sign * K * t01_t02 / D; - CT const dt = math::abs(t_new - t); - t = t_new; - CT const new_beta = atan(t); - CT const dbeta = math::abs(new_beta - beta); - beta = new_beta;*/ - - // [Sjoberg02] - it converges faster - // Newton–Raphson method - asin_t_t01 = asin(t / t01); - asin_t_t02 = asin(t / t02); - CT const R1 = asin_t_t01 + dL1; - CT const R2 = asin_t_t02 + dL2; CT const cos_beta = cos(beta); CT const cos_beta_sqr = math::sqr(cos_beta); CT const G = c1 - e_sqr * cos_beta_sqr; - CT const f1 = C1 / cos_beta * math::sqrt(G / (cos_beta_sqr - C1_sqr)); - CT const f2 = C2 / cos_beta * math::sqrt(G / (cos_beta_sqr - C2_sqr)); - CT const abs_f1 = math::abs(f1); - CT const abs_f2 = math::abs(f2); - CT const dbeta = t_sign * (k_base - R2 + R1) / (abs_f1 + abs_f2); - - if (math::equals(dbeta, CT(0))) + + CT f1 = 0; + CT f2 = 0; + + if (!geod1.is_Cj_zero) + { + bool is_beta_ok = geod1.lon_diff(sin_beta, t, lon1_diff); + + if (is_beta_ok) + { + CT const H = cos_beta_sqr - geod1.Cj_sqr; + f1 = geod1.Cj / cos_beta * math::sqrt(G / H); + } + else + { + return false; + } + } + + if (!geod2.is_Cj_zero) + { + bool is_beta_ok = geod2.lon_diff(sin_beta, t, lon2_diff); + + if (is_beta_ok) + { + CT const H = cos_beta_sqr - geod2.Cj_sqr; + f2 = geod2.Cj / cos_beta * math::sqrt(G / H); + } + else + { + return false; + } + } + + // NOTE: Things may go wrong if the IP is near the vertex + // 1. May converge into the wrong direction (from the other way around). + // This happens when the starting point is on the other side than the vertex + // 2. During converging may "jump" into the other side of the vertex. + // In this case sin_beta/sqrt_1_Cj_sqr and t/t0j is not in [-1, 1] + // 3. f1-f2 may be 0 which means that the intermediate point is on the vertex + // In this case it's not possible to check if this is the correct result + + CT const dbeta_denom = f1 - f2; + //CT const dbeta_denom = math::abs(f1) + math::abs(f2); + + if (math::equals(dbeta_denom, c0)) + { + return false; + } + + // The sign of dbeta is changed WRT [Sjoberg02] + CT const dbeta = (lon1_minus_lon2 + lon1_diff - lon2_diff) / dbeta_denom; + + CT const abs_dbeta = math::abs(dbeta); + if (i > 0 && abs_dbeta > abs_dbeta_last) { + // The algorithm is not converging + // The intersection may be on the other side of the vertex + return false; + } + abs_dbeta_last = abs_dbeta; + + if (math::equals(dbeta, c0)) + { + // Result found break; } + // Because the sign of dbeta is changed WRT [Sjoberg02] dbeta is subtracted here beta = beta - dbeta; + t = tan(beta); } - - // t = tan(beta) = (1-f)tan(lat) - lat = atan(t / one_minus_f); - CT const l1 = lon1 + asin_t_t01 - asin_t1_t01 + dL1; - //CT const l2 = lon2 + asin_t_t02 - asin_t2_t02 + dL2; - lon = l1; + lat = geod1.lat(t); + // NOTE: if Cj is 0 then the result is lonj or lonj+180 + lon = ! geod1.is_Cj_zero + ? geod1.lon(lon1_diff) + : geod2.lon(lon2_diff); return true; } -private: - /*! Approximation of dLambda_j [Sjoberg07], expanded into taylor series in e^2 - Maxima script: - dLI_j(c_j, sinB_j, sinB) := integrate(1 / (sqrt(1 - c_j ^ 2 - x ^ 2)*(1 + sqrt(1 - e2*(1 - x ^ 2)))), x, sinB_j, sinB); - dL_j(c_j, B_j, B) := -e2 * c_j * dLI_j(c_j, B_j, B); - S: taylor(dLI_j(c_j, sinB_j, sinB), e2, 0, 3); - assume(c_j < 1); - assume(c_j > 0); - L1: factor(integrate(sqrt(-x ^ 2 - c_j ^ 2 + 1) / (x ^ 2 + c_j ^ 2 - 1), x)); - L2: factor(integrate(((x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); - L3: factor(integrate(((x ^ 4 - 2 * x ^ 2 + 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); - L4: factor(integrate(((x ^ 6 - 3 * x ^ 4 + 3 * x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); - */ - static inline CT d_lambda_e_sqr(CT const& sin_betaj, CT const& sin_beta, - CT const& Cj, CT const& sqrt_1_Cj_sqr, - CT const& e_sqr) - { - if (Order == 0) - { - return 0; - } + struct geodesics_type + { + geodesics_type(geodesic_type const& g1, geodesic_type const& g2) + : geod1(g1) + , geod2(g2) + , vertex1(geod1.get_vertex_data()) + , vertex2(geod2.get_vertex_data()) + {} - CT const c2 = 2; - - CT const asin_B = asin(sin_beta / sqrt_1_Cj_sqr); - CT const asin_Bj = asin(sin_betaj / sqrt_1_Cj_sqr); - CT const L0 = (asin_B - asin_Bj) / c2; + geodesic_type const& geod1; + geodesic_type const& geod2; + typename geodesic_type::vertex_data vertex1; + typename geodesic_type::vertex_data vertex2; + }; - if (Order == 1) + struct converge_07_result + { + converge_07_result() + : lon1(0), lon2(0), k1_diff(0), k2_diff(0), t1(0), t2(0) + {} + + CT lon1, lon2; + CT k1_diff, k2_diff; + CT t1, t2; + }; + + static inline bool converge_07(geodesic_type const& geod1, geodesic_type const& geod2, + CT beta, CT t, + CT const& lon1_minus_lon2, CT const& lon_sph, + CT & lon, CT & lat) + { + //CT const c0 = 0; + //CT const c1 = 1; + //CT const c2 = 2; + //CT const pi = math::pi<CT>(); + + geodesics_type geodesics(geod1, geod2); + converge_07_result result; + + // calculate first pair of longitudes + if (!converge_07_step_one(CT(sin(beta)), t, lon1_minus_lon2, geodesics, lon_sph, result, false)) { - return -Cj * e_sqr * L0; + return false; } - CT const c1 = 1; - CT const c16 = 16; + int t_direction = 0; - CT const X = sin_beta; - CT const Xj = sin_betaj; - CT const Cj_sqr = math::sqr(Cj); - CT const Cj_sqr_plus_one = Cj_sqr + c1; - CT const one_minus_Cj_sqr = c1 - Cj_sqr; - CT const sqrt_Y = math::sqrt(-math::sqr(X) + one_minus_Cj_sqr); - CT const sqrt_Yj = math::sqrt(-math::sqr(Xj) + one_minus_Cj_sqr); - CT const L1 = (Cj_sqr_plus_one * (asin_B - asin_Bj) + X * sqrt_Y - Xj * sqrt_Yj) / c16; + CT lon_diff_prev = math::longitude_difference<radian>(result.lon1, result.lon2); - if (Order == 2) + // [Sjoberg07] + for (int i = 2; i < max_iterations_07; ++i) { - return -Cj * e_sqr * (L0 + e_sqr * L1); + // pick t candidates from previous result based on dir + CT t_cand1 = result.t1; + CT t_cand2 = result.t2; + // if direction is 0 the closer one is the first + if (t_direction < 0) + { + t_cand1 = (std::min)(result.t1, result.t2); + t_cand2 = (std::max)(result.t1, result.t2); + } + else if (t_direction > 0) + { + t_cand1 = (std::max)(result.t1, result.t2); + t_cand2 = (std::min)(result.t1, result.t2); + } + else + { + t_direction = t_cand1 < t_cand2 ? -1 : 1; + } + + CT t1 = t; + CT beta1 = beta; + // check if the further calculation is needed + if (converge_07_update(t1, beta1, t_cand1)) + { + break; + } + + bool try_t2 = false; + converge_07_result result_curr; + if (converge_07_step_one(CT(sin(beta1)), t1, lon1_minus_lon2, geodesics, lon_sph, result_curr)) + { + CT const lon_diff1 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2); + if (lon_diff_prev > lon_diff1) + { + t = t1; + beta = beta1; + lon_diff_prev = lon_diff1; + result = result_curr; + } + else if (t_cand1 != t_cand2) + { + try_t2 = true; + } + else + { + // the result is not fully correct but it won't be more accurate + break; + } + } + // ! converge_07_step_one + else + { + if (t_cand1 != t_cand2) + { + try_t2 = true; + } + else + { + return false; + } + } + + + if (try_t2) + { + CT t2 = t; + CT beta2 = beta; + // check if the further calculation is needed + if (converge_07_update(t2, beta2, t_cand2)) + { + break; + } + + if (! converge_07_step_one(CT(sin(beta2)), t2, lon1_minus_lon2, geodesics, lon_sph, result_curr)) + { + return false; + } + + CT const lon_diff2 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2); + if (lon_diff_prev > lon_diff2) + { + t_direction *= -1; + t = t2; + beta = beta2; + lon_diff_prev = lon_diff2; + result = result_curr; + } + else + { + // the result is not fully correct but it won't be more accurate + break; + } + } } - CT const c3 = 3; - CT const c5 = 5; - CT const c128 = 128; + lat = geod1.lat(t); + lon = ! geod1.is_Cj_zero ? result.lon1 : result.lon2; + math::normalize_longitude<radian>(lon); + + return true; + } + + static inline bool converge_07_update(CT & t, CT & beta, CT const& t_new) + { + CT const c0 = 0; + + CT const beta_new = atan(t_new); + CT const dbeta = beta_new - beta; + beta = beta_new; + t = t_new; - CT const E = Cj_sqr * (c3 * Cj_sqr + c2) + c3; - CT const X_sqr = math::sqr(X); - CT const Xj_sqr = math::sqr(Xj); - CT const F = X * (-c2 * X_sqr + c3 * Cj_sqr + c5); - CT const Fj = Xj * (-c2 * Xj_sqr + c3 * Cj_sqr + c5); - CT const L2 = (E * (asin_B - asin_Bj) + F * sqrt_Y - Fj * sqrt_Yj) / c128; + return math::equals(dbeta, c0); + } - if (Order == 3) + static inline CT const& pick_t(CT const& t1, CT const& t2, int direction) + { + return direction < 0 ? (std::min)(t1, t2) : (std::max)(t1, t2); + } + + static inline bool converge_07_step_one(CT const& sin_beta, + CT const& t, + CT const& lon1_minus_lon2, + geodesics_type const& geodesics, + CT const& lon_sph, + converge_07_result & result, + bool check_sin_beta = true) + { + bool ok = converge_07_one_geod(sin_beta, t, geodesics.geod1, geodesics.vertex1, lon_sph, + result.lon1, result.k1_diff, check_sin_beta) + && converge_07_one_geod(sin_beta, t, geodesics.geod2, geodesics.vertex2, lon_sph, + result.lon2, result.k2_diff, check_sin_beta); + + if (!ok) { - return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * L2)); + return false; } - CT const c8 = 8; - CT const c9 = 9; - CT const c10 = 10; - CT const c15 = 15; - CT const c24 = 24; - CT const c26 = 26; - CT const c33 = 33; - CT const c6144 = 6144; + CT const k = lon1_minus_lon2 + result.k1_diff - result.k2_diff; - CT const G = Cj_sqr * (Cj_sqr * (Cj_sqr * c15 + c9) + c9) + c15; - CT const H = -c10 * Cj_sqr - c26; - CT const I = Cj_sqr * (Cj_sqr * c15 + c24) + c33; - CT const J = X_sqr * (X * (c8 * X_sqr + H)) + X * I; - CT const Jj = Xj_sqr * (Xj * (c8 * Xj_sqr + H)) + Xj * I; - CT const L3 = (G * (asin_B - asin_Bj) + J * sqrt_Y - Jj * sqrt_Yj) / c6144; + // get 2 possible ts one lesser and one greater than t + // t1 is the closer one + calc_ts(t, k, geodesics.geod1, geodesics.geod2, result.t1, result.t2); - // Order 4 and higher - return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * (L2 + e_sqr * L3))); + return true; } - static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr) + static inline bool converge_07_one_geod(CT const& sin_beta, CT const& t, + geodesic_type const& geod, + typename geodesic_type::vertex_data const& vertex, + CT const& lon_sph, + CT & lon, CT & k_diff, + bool check_sin_beta) { + using math::detail::bounded; CT const c1 = 1; - CT const Cj_sqr = math::sqr(Cj); - return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr)); + + CT k_diff_before = 0; + CT k_diff_behind = 0; + + bool is_beta_ok = geod.k_diffs(sin_beta, vertex, k_diff_before, k_diff_behind, check_sin_beta); + + if (! is_beta_ok) + { + return false; + } + + CT const asin_t_t0j = ! geod.is_Cj_zero ? asin(bounded(t / geod.t0j, -c1, c1)) : 0; + CT const sign_asin_t_t0j = geod.sign_lon_diff * asin_t_t0j; + + CT const lon_before = geod.lonj + sign_asin_t_t0j + k_diff_before; + CT const lon_behind = geod.lonj - sign_asin_t_t0j + k_diff_behind; + + CT const lon_dist_before = math::longitude_distance_signed<radian>(lon_before, lon_sph); + CT const lon_dist_behind = math::longitude_distance_signed<radian>(lon_behind, lon_sph); + if (math::abs(lon_dist_before) <= math::abs(lon_dist_behind)) + { + k_diff = k_diff_before; + lon = lon_before; + } + else + { + k_diff = k_diff_behind; + lon = lon_behind; + } + + return true; } - template <int TId> - static inline bool check_t(CT const& t, - CT const& lon_a1, CT const& asin_t_t01, CT const& asin_t1_t01, - CT const& lon_b1, CT const& asin_t_t02, CT const& asin_t2_t02, - CT & current_t, CT & current_lon1, CT & current_lon2, CT & current_dlon, - int & t_id) + static inline void calc_ts(CT const& t, CT const& k, + geodesic_type const& geod1, geodesic_type const& geod2, + CT & t1, CT& t2) { - CT const lon1 = lon_a1 + asin_t_t01 - asin_t1_t01; - CT const lon2 = lon_b1 + asin_t_t02 - asin_t2_t02; + CT const c1 = 1; + CT const c2 = 2; - // TODO - true angle difference - CT const dlon = math::abs(lon2 - lon1); + CT const K = sin(k); - bool are_equal = math::equals(dlon, CT(0)); - - if ((TId == 0) || are_equal || dlon < current_dlon) + BOOST_GEOMETRY_ASSERT(!geod1.is_Cj_zero || !geod2.is_Cj_zero); + if (geod1.is_Cj_zero) + { + t1 = K * geod2.t0j; + t2 = -t1; + } + else if (geod2.is_Cj_zero) { - current_t = t; - current_lon1 = lon1; - current_lon2 = lon2; - current_dlon = dlon; - t_id = TId; + t1 = -K * geod1.t0j; + t2 = -t1; } + else + { + CT const A = math::sqr(geod1.t0j) + math::sqr(geod2.t0j); + CT const B = c2 * geod1.t0j * geod2.t0j * math::sqrt(c1 - math::sqr(K)); + + CT const K_t01_t02 = K * geod1.t0j * geod2.t0j; + CT const D1 = math::sqrt(A + B); + CT const D2 = math::sqrt(A - B); + CT const t_new1 = K_t01_t02 / D1; + CT const t_new2 = K_t01_t02 / D2; + CT const t_new3 = -t_new1; + CT const t_new4 = -t_new2; - return are_equal; + // Pick 2 nearest t_new, one greater and one lesser than current t + CT const abs_t_new1 = math::abs(t_new1); + CT const abs_t_new2 = math::abs(t_new2); + CT const abs_t_max = (std::max)(abs_t_new1, abs_t_new2); + t1 = -abs_t_max; // lesser + t2 = abs_t_max; // greater + if (t1 < t) + { + if (t_new1 < t && t_new1 > t1) + t1 = t_new1; + if (t_new2 < t && t_new2 > t1) + t1 = t_new2; + if (t_new3 < t && t_new3 > t1) + t1 = t_new3; + if (t_new4 < t && t_new4 > t1) + t1 = t_new4; + } + if (t2 > t) + { + if (t_new1 > t && t_new1 < t2) + t2 = t_new1; + if (t_new2 > t && t_new2 < t2) + t2 = t_new2; + if (t_new3 > t && t_new3 < t2) + t2 = t_new3; + if (t_new4 > t && t_new4 < t2) + t2 = t_new4; + } + } + + // the first one is the closer one + if (math::abs(t - t2) < math::abs(t - t1)) + { + std::swap(t2, t1); + } + } + + static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr) + { + CT const c1 = 1; + CT const Cj_sqr = math::sqr(Cj); + return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr)); } + + /*static inline CT vertical_intersection_longitude(CT const& ip_lon, CT const& seg_lon1, CT const& seg_lon2) + { + CT const c0 = 0; + CT const lon_2 = ip_lon > c0 ? ip_lon - pi : ip_lon + pi; + + return (std::min)(math::longitude_difference<radian>(ip_lon, seg_lon1), + math::longitude_difference<radian>(ip_lon, seg_lon2)) + <= + (std::min)(math::longitude_difference<radian>(lon_2, seg_lon1), + math::longitude_difference<radian>(lon_2, seg_lon2)) + ? ip_lon : lon_2; + }*/ }; }}} // namespace boost::geometry::formula diff --git a/boost/geometry/formulas/spherical.hpp b/boost/geometry/formulas/spherical.hpp index 2195bbbe10..ff24c51a88 100644 --- a/boost/geometry/formulas/spherical.hpp +++ b/boost/geometry/formulas/spherical.hpp @@ -1,6 +1,7 @@ // Boost.Geometry // Copyright (c) 2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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, @@ -27,38 +28,67 @@ namespace boost { namespace geometry { namespace formula { +template <typename T> +struct result_spherical +{ + result_spherical() + : azimuth(0) + , reverse_azimuth(0) + {} + + T azimuth; + T reverse_azimuth; +}; + +template <typename T> +static inline void sph_to_cart3d(T const& lon, T const& lat, T & x, T & y, T & z) +{ + T const cos_lat = cos(lat); + x = cos_lat * cos(lon); + y = cos_lat * sin(lon); + z = sin(lat); +} + template <typename Point3d, typename PointSph> static inline Point3d sph_to_cart3d(PointSph const& point_sph) { typedef typename coordinate_type<Point3d>::type calc_t; - Point3d res; - - calc_t lon = get_as_radian<0>(point_sph); - calc_t lat = get_as_radian<1>(point_sph); + calc_t const lon = get_as_radian<0>(point_sph); + calc_t const lat = get_as_radian<1>(point_sph); + calc_t x, y, z; + sph_to_cart3d(lon, lat, x, y, z); - calc_t const cos_lat = cos(lat); - set<0>(res, cos_lat * cos(lon)); - set<1>(res, cos_lat * sin(lon)); - set<2>(res, sin(lat)); + Point3d res; + set<0>(res, x); + set<1>(res, y); + set<2>(res, z); return res; } +template <typename T> +static inline void cart3d_to_sph(T const& x, T const& y, T const& z, T & lon, T & lat) +{ + lon = atan2(y, x); + lat = asin(z); +} + template <typename PointSph, typename Point3d> static inline PointSph cart3d_to_sph(Point3d const& point_3d) { typedef typename coordinate_type<PointSph>::type coord_t; typedef typename coordinate_type<Point3d>::type calc_t; - PointSph res; - calc_t const x = get<0>(point_3d); calc_t const y = get<1>(point_3d); calc_t const z = get<2>(point_3d); + calc_t lonr, latr; + cart3d_to_sph(x, y, z, lonr, latr); - set_from_radian<0>(res, atan2(y, x)); - set_from_radian<1>(res, asin(z)); + PointSph res; + set_from_radian<0>(res, lonr); + set_from_radian<1>(res, latr); coord_t lon = get<0>(res); coord_t lat = get<1>(res); @@ -89,6 +119,104 @@ static inline int sph_side_value(Point3d1 const& norm, Point3d2 const& pt) : -1; // d < 0 } +template <typename CT, bool ReverseAzimuth, typename T1, typename T2> +static inline result_spherical<CT> spherical_azimuth(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2) +{ + typedef result_spherical<CT> result_type; + result_type result; + + // http://williams.best.vwh.net/avform.htm#Crs + // https://en.wikipedia.org/wiki/Great-circle_navigation + CT dlon = lon2 - lon1; + + // 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); + //} + + CT const cos_dlon = cos(dlon); + CT const sin_dlon = sin(dlon); + CT const cos_lat1 = cos(lat1); + CT const cos_lat2 = cos(lat2); + CT const sin_lat1 = sin(lat1); + CT const sin_lat2 = sin(lat2); + + { + // "An alternative formula, not requiring the pre-computation of d" + // In the formula below dlon is used as "d" + CT const y = sin_dlon * cos_lat2; + CT const x = cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon; + result.azimuth = atan2(y, x); + } + + if (ReverseAzimuth) + { + CT const y = sin_dlon * cos_lat1; + CT const x = sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1; + result.reverse_azimuth = atan2(y, x); + } + + return result; +} + +template <typename ReturnType, typename T1, typename T2> +inline ReturnType spherical_azimuth(T1 const& lon1, T1 const& lat1, + T2 const& lon2, T2 const& lat2) +{ + return spherical_azimuth<ReturnType, false>(lon1, lat1, lon2, lat2).azimuth; +} + +template <typename T> +inline T spherical_azimuth(T const& lon1, T const& lat1, T const& lon2, T const& lat2) +{ + return spherical_azimuth<T, false>(lon1, lat1, lon2, lat2).azimuth; +} + +template <typename T> +inline int azimuth_side_value(T const& azi_a1_p, T const& azi_a1_a2) +{ + T const pi = math::pi<T>(); + T const two_pi = math::two_pi<T>(); + + // instead of the formula from XTD + //calc_t a_diff = asin(sin(azi_a1_p - azi_a1_a2)); + + T a_diff = azi_a1_p - azi_a1_a2; + // normalize, angle in [-pi, pi] + while (a_diff > pi) + a_diff -= two_pi; + while (a_diff < -pi) + a_diff += two_pi; + + // NOTE: in general it shouldn't be required to support the pi/-pi case + // because in non-cartesian systems it makes sense to check the side + // only "between" the endpoints. + // However currently the winding strategy calls the side strategy + // for vertical segments to check if the point is "between the endpoints. + // This could be avoided since the side strategy is not required for that + // because meridian is the shortest path. So a difference of + // longitudes would be sufficient (of course normalized to [-pi, pi]). + + // NOTE: with the above said, the pi/-pi check is temporary + // however in case if this was required + // the geodesics on ellipsoid aren't "symmetrical" + // therefore instead of comparing a_diff to pi and -pi + // one should probably use inverse azimuths and compare + // the difference to 0 as well + + // positive azimuth is on the right side + return math::equals(a_diff, 0) + || math::equals(a_diff, pi) + || math::equals(a_diff, -pi) ? 0 + : a_diff > 0 ? -1 // right + : 1; // left +} + } // namespace formula }} // namespace boost::geometry diff --git a/boost/geometry/formulas/thomas_direct.hpp b/boost/geometry/formulas/thomas_direct.hpp index f8a7f83943..f208167cf5 100644 --- a/boost/geometry/formulas/thomas_direct.hpp +++ b/boost/geometry/formulas/thomas_direct.hpp @@ -20,9 +20,8 @@ #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> -#include <boost/geometry/algorithms/detail/flattening.hpp> - #include <boost/geometry/formulas/differential_quantities.hpp> +#include <boost/geometry/formulas/flattening.hpp> #include <boost/geometry/formulas/result_direct.hpp> @@ -82,7 +81,7 @@ public: CT const a = CT(get_radius<0>(spheroid)); CT const b = CT(get_radius<2>(spheroid)); - CT const f = detail::flattening<CT>(spheroid); + CT const f = formula::flattening<CT>(spheroid); CT const one_minus_f = c1 - f; CT const pi = math::pi<CT>(); diff --git a/boost/geometry/formulas/thomas_inverse.hpp b/boost/geometry/formulas/thomas_inverse.hpp index d68c9de054..0853a36980 100644 --- a/boost/geometry/formulas/thomas_inverse.hpp +++ b/boost/geometry/formulas/thomas_inverse.hpp @@ -20,9 +20,8 @@ #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> -#include <boost/geometry/algorithms/detail/flattening.hpp> - #include <boost/geometry/formulas/differential_quantities.hpp> +#include <boost/geometry/formulas/flattening.hpp> #include <boost/geometry/formulas/result_inverse.hpp> @@ -78,7 +77,7 @@ public: CT const c4 = 4; CT const pi_half = math::pi<CT>() / c2; - CT const f = detail::flattening<CT>(spheroid); + CT const f = formula::flattening<CT>(spheroid); CT const one_minus_f = c1 - f; // CT const tan_theta1 = one_minus_f * tan(lat1); diff --git a/boost/geometry/formulas/vertex_latitude.hpp b/boost/geometry/formulas/vertex_latitude.hpp new file mode 100644 index 0000000000..755067b08d --- /dev/null +++ b/bo |