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/boost/geometry/formulas/vertex_latitude.hpp @@ -0,0 +1,148 @@ +// Boost.Geometry + +// Copyright (c) 2016-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, +// 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_MAXIMUM_LATITUDE_HPP +#define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP + +#include <boost/geometry/core/srs.hpp> +#include <boost/geometry/formulas/flattening.hpp> +#include <boost/geometry/formulas/spherical.hpp> +#include <boost/mpl/assert.hpp> + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief Algorithm to compute the vertex latitude of a geodesic segment. Vertex is +a point on the geodesic that maximizes (or minimizes) the latitude. +\author See + [Wood96] Wood - Vertex Latitudes on Ellipsoid Geodesics, SIAM Rev., 38(4), + 637–644, 1996 +*/ + +template <typename CT> +class vertex_latitude_on_sphere +{ + +public: + template<typename T1, typename T2> + static inline CT apply(T1 const& lat1, + T2 const& alp1) + { + return std::acos( math::abs(cos(lat1) * sin(alp1)) ); + } +}; + +template <typename CT> +class vertex_latitude_on_spheroid +{ + +public: +/* + * formula based on paper + * [Wood96] Wood - Vertex Latitudes on Ellipsoid Geodesics, SIAM Rev., 38(4), + * 637–644, 1996 + template <typename T1, typename T2, typename Spheroid> + static inline CT apply(T1 const& lat1, + T2 const& alp1, + Spheroid const& spheroid) + { + CT const f = formula::flattening<CT>(spheroid); + + CT const e2 = f * (CT(2) - f); + CT const sin_alp1 = sin(alp1); + CT const sin2_lat1 = math::sqr(sin(lat1)); + CT const cos2_lat1 = CT(1) - sin2_lat1; + + CT const e2_sin2 = CT(1) - e2 * sin2_lat1; + CT const cos2_sin2 = cos2_lat1 * math::sqr(sin_alp1); + CT const vertex_lat = std::asin( math::sqrt((e2_sin2 - cos2_sin2) + / (e2_sin2 - e2 * cos2_sin2))); + return vertex_lat; + } +*/ + + // simpler formula based on Clairaut relation for spheroids + template <typename T1, typename T2, typename Spheroid> + static inline CT apply(T1 const& lat1, + T2 const& alp1, + Spheroid const& spheroid) + { + CT const f = formula::flattening<CT>(spheroid); + + CT const one_minus_f = (CT(1) - f); + + //get the reduced latitude + CT const bet1 = atan( one_minus_f * tan(lat1) ); + + //apply Clairaut relation + CT const betv = vertex_latitude_on_sphere<CT>::apply(bet1, alp1); + + //return the spheroid latitude + return atan( tan(betv) / one_minus_f ); + } + + /* + template <typename T> + inline static void sign_adjustment(CT lat1, CT lat2, CT vertex_lat, T& vrt_result) + { + // signbit returns a non-zero value (true) if the sign is negative; + // and zero (false) otherwise. + bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); + + vrt_result.north = sign ? std::max(lat1, lat2) : vertex_lat; + vrt_result.south = sign ? vertex_lat * CT(-1) : std::min(lat1, lat2); + } + + template <typename T> + inline static bool vertex_on_segment(CT alp1, CT alp2, CT lat1, CT lat2, T& vrt_result) + { + CT const half_pi = math::pi<CT>() / CT(2); + + // if the segment does not contain the vertex of the geodesic + // then return the endpoint of max (min) latitude + if ((alp1 < half_pi && alp2 < half_pi) + || (alp1 > half_pi && alp2 > half_pi)) + { + vrt_result.north = std::max(lat1, lat2); + vrt_result.south = std::min(lat1, lat2); + return false; + } + return true; + } + */ +}; + + +template <typename CT, typename CS_Tag> +struct vertex_latitude +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_COORDINATE_SYSTEM, (types<CS_Tag>) + ); + +}; + +template <typename CT> +struct vertex_latitude<CT, spherical_equatorial_tag> + : vertex_latitude_on_sphere<CT> +{}; + +template <typename CT> +struct vertex_latitude<CT, geographic_tag> + : vertex_latitude_on_spheroid<CT> +{}; + + +}}} // namespace boost::geometry::formula + +#endif // BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP diff --git a/boost/geometry/formulas/vincenty_direct.hpp b/boost/geometry/formulas/vincenty_direct.hpp index f3647ff4e6..1697e5fb63 100644 --- a/boost/geometry/formulas/vincenty_direct.hpp +++ b/boost/geometry/formulas/vincenty_direct.hpp @@ -23,9 +23,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> @@ -85,7 +84,7 @@ public: CT const radius_a = CT(get_radius<0>(spheroid)); CT const radius_b = CT(get_radius<2>(spheroid)); - CT const flattening = geometry::detail::flattening<CT>(spheroid); + CT const flattening = formula::flattening<CT>(spheroid); CT const sin_azimuth12 = sin(azimuth12); CT const cos_azimuth12 = cos(azimuth12); diff --git a/boost/geometry/formulas/vincenty_inverse.hpp b/boost/geometry/formulas/vincenty_inverse.hpp index bbda00036b..032e16e291 100644 --- a/boost/geometry/formulas/vincenty_inverse.hpp +++ b/boost/geometry/formulas/vincenty_inverse.hpp @@ -2,8 +2,8 @@ // 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 Adam Wulkiewicz, on behalf of Oracle @@ -23,9 +23,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> @@ -41,7 +40,7 @@ namespace boost { namespace geometry { namespace formula \brief The solution of the inverse problem of geodesics on latlong coordinates, after Vincenty, 1975 \author See - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf - - http://www.icsm.gov.au/gda/gdav2.3.pdf + - http://www.icsm.gov.au/gda/gda-v_2.4.pdf \author Adapted from various implementations to get it close to the original document - http://www.movable-type.co.uk/scripts/LatLongVincenty.html - http://exogen.case.edu/projects/geopy/source/geopy.distance.html @@ -99,10 +98,10 @@ public: CT const radius_a = CT(get_radius<0>(spheroid)); CT const radius_b = CT(get_radius<2>(spheroid)); - CT const flattening = geometry::detail::flattening<CT>(spheroid); + CT const f = formula::flattening<CT>(spheroid); // U: reduced latitude, defined by tan U = (1-f) tan phi - CT const one_min_f = c1 - flattening; + CT const one_min_f = c1 - f; CT const tan_U1 = one_min_f * tan(lat1); // above (1) CT const tan_U2 = one_min_f * tan(lat2); // above (1) @@ -113,8 +112,9 @@ public: CT const cos_U1 = c1 / temp_den_U1; CT const cos_U2 = c1 / temp_den_U2; // sin = tan / sqrt(1 + tan^2) - CT const sin_U1 = tan_U1 / temp_den_U1; - CT const sin_U2 = tan_U2 / temp_den_U2; + // sin = tan * cos + CT const sin_U1 = tan_U1 * cos_U1; + CT const sin_U2 = tan_U2 * cos_U2; // calculate sin U and cos U directly //CT const U1 = atan(tan_U1); @@ -130,7 +130,8 @@ public: CT sin_sigma; CT sin_alpha; CT cos2_alpha; - CT cos2_sigma_m; + CT cos_2sigma_m; + CT cos2_2sigma_m; CT sigma; int counter = 0; // robustness @@ -144,12 +145,13 @@ public: CT cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda; // (15) sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma; // (17) cos2_alpha = c1 - math::sqr(sin_alpha); - cos2_sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18) + cos_2sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18) + cos2_2sigma_m = math::sqr(cos_2sigma_m); - CT C = flattening/c16 * cos2_alpha * (c4 + flattening * (c4 - c3 * cos2_alpha)); // (10) + CT C = f/c16 * cos2_alpha * (c4 + f * (c4 - c3 * cos2_alpha)); // (10) sigma = atan2(sin_sigma, cos_sigma); // (16) - lambda = L + (c1 - C) * flattening * sin_alpha * - (sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * (-c1 + c2 * math::sqr(cos2_sigma_m)))); // (11) + lambda = L + (c1 - C) * f * sin_alpha * + (sigma + C * sin_sigma * (cos_2sigma_m + C * cos_sigma * (-c1 + c2 * cos2_2sigma_m))); // (11) ++counter; // robustness @@ -182,8 +184,10 @@ public: CT A = c1 + sqr_u/c16384 * (c4096 + sqr_u * (-c768 + sqr_u * (c320 - c175 * sqr_u))); // (3) CT B = sqr_u/c1024 * (c256 + sqr_u * ( -c128 + sqr_u * (c74 - c47 * sqr_u))); // (4) - CT delta_sigma = B * sin_sigma * ( cos2_sigma_m + (B/c4) * (cos(sigma)* (-c1 + c2 * cos2_sigma_m) - - (B/c6) * cos2_sigma_m * (-c3 + c4 * math::sqr(sin_sigma)) * (-c3 + c4 * cos2_sigma_m))); // (6) + CT const cos_sigma = cos(sigma); + CT const sin2_sigma = math::sqr(sin_sigma); + CT delta_sigma = B * sin_sigma * (cos_2sigma_m + (B/c4) * (cos_sigma* (-c1 + c2 * cos2_2sigma_m) + - (B/c6) * cos_2sigma_m * (-c3 + c4 * sin2_sigma) * (-c3 + c4 * cos2_2sigma_m))); // (6) result.distance = radius_b * A * (sigma - delta_sigma); // (19) } @@ -206,7 +210,7 @@ public: typedef differential_quantities<CT, EnableReducedLength, EnableGeodesicScale, 2> quantities; quantities::apply(lon1, lat1, lon2, lat2, result.azimuth, result.reverse_azimuth, - radius_b, flattening, + radius_b, f, result.reduced_length, result.geodesic_scale); } diff --git a/boost/geometry/index/detail/algorithms/nth_element.hpp b/boost/geometry/index/detail/algorithms/nth_element.hpp new file mode 100644 index 0000000000..201180ae3a --- /dev/null +++ b/boost/geometry/index/detail/algorithms/nth_element.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry Index +// +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP + +#include <algorithm> + +namespace boost { namespace geometry { namespace index { namespace detail { + +// See https://svn.boost.org/trac/boost/ticket/12861 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58800 +// https://gcc.gnu.org/develop.html#timeline +// 20120920 4.7.2 - no bug +// 20130322 4.8.0 - no bug +// 20130411 4.7.3 - no bug +// 20130531 4.8.1 - no bug +// 20131016 4.8.2 - bug +// 20140422 4.9.0 - fixed +// 20140522 4.8.3 - fixed +// 20140612 4.7.4 - fixed +// 20140716 4.9.1 - fixed +#if defined(__GLIBCXX__) && (__GLIBCXX__ == 20131016) + +#warning "std::nth_element replaced with std::sort, libstdc++ bug workaround."; + +template <typename RandomIt> +void nth_element(RandomIt first, RandomIt , RandomIt last) +{ + std::sort(first, last); +} + +template <typename RandomIt, typename Compare> +void nth_element(RandomIt first, RandomIt , RandomIt last, Compare comp) +{ + std::sort(first, last, comp); +} + +#else + +template <typename RandomIt> +void nth_element(RandomIt first, RandomIt nth, RandomIt last) +{ + std::nth_element(first, nth, last); +} + +template <typename RandomIt, typename Compare> +void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp) +{ + std::nth_element(first, nth, last, comp); +} + +#endif + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP diff --git a/boost/geometry/index/detail/rtree/pack_create.hpp b/boost/geometry/index/detail/rtree/pack_create.hpp index d1491b8d47..2d3903a7b4 100644 --- a/boost/geometry/index/detail/rtree/pack_create.hpp +++ b/boost/geometry/index/detail/rtree/pack_create.hpp @@ -2,7 +2,7 @@ // // R-tree initial packing // -// Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -13,6 +13,7 @@ #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/index/detail/algorithms/bounds.hpp> +#include <boost/geometry/index/detail/algorithms/nth_element.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> @@ -67,7 +68,7 @@ struct nth_element_and_half_boxes { if ( I == dim_index ) { - std::nth_element(first, median, last, point_entries_comparer<I>()); + index::detail::nth_element(first, median, last, point_entries_comparer<I>()); geometry::convert(box, left); geometry::convert(box, right); diff --git a/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp index 7a96986a27..89697b5947 100644 --- a/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp +++ b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp @@ -2,7 +2,7 @@ // // R-tree R*-tree next node choosing algorithm implementation // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -17,6 +17,7 @@ #include <boost/geometry/index/detail/algorithms/content.hpp> #include <boost/geometry/index/detail/algorithms/intersection_content.hpp> +#include <boost/geometry/index/detail/algorithms/nth_element.hpp> #include <boost/geometry/index/detail/algorithms/union_content.hpp> #include <boost/geometry/index/detail/rtree/node/node.hpp> @@ -112,7 +113,7 @@ private: first_n_children_count = overlap_cost_threshold; // rearrange by content_diff // in order to calculate nearly minimum overlap cost - std::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less); + index::detail::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less); } // calculate minimum or nearly minimum overlap cost diff --git a/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp index 8f270537fb..187d37facd 100644 --- a/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp +++ b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp @@ -2,7 +2,7 @@ // // R-tree R*-tree split algorithm implementation // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -12,8 +12,9 @@ #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP #include <boost/geometry/index/detail/algorithms/intersection_content.hpp> -#include <boost/geometry/index/detail/algorithms/union_content.hpp> #include <boost/geometry/index/detail/algorithms/margin.hpp> +#include <boost/geometry/index/detail/algorithms/nth_element.hpp> +#include <boost/geometry/index/detail/algorithms/union_content.hpp> #include <boost/geometry/index/detail/bounded_view.hpp> @@ -122,8 +123,9 @@ struct choose_split_axis_and_index_for_corner // { // typename Elements::iterator f = elements_copy.begin() + index_first; // typename Elements::iterator l = elements_copy.begin() + index_last; -// std::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) -// std::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) +// // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway +// index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) +// index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) // std::sort(f, l, elements_less); // MAY THROW, BASIC (copy) // } @@ -349,7 +351,7 @@ struct nth_element typedef typename tag<indexable_type>::type indexable_tag; element_axis_corner_less<element_type, Translator, indexable_tag, Corner, I> less(tr); - std::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) } } }; diff --git a/boost/geometry/index/equal_to.hpp b/boost/geometry/index/equal_to.hpp index b0cf098f1d..6b722a89fc 100644 --- a/boost/geometry/index/equal_to.hpp +++ b/boost/geometry/index/equal_to.hpp @@ -1,6 +1,6 @@ // Boost.Geometry Index // -// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2016 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -42,6 +42,15 @@ struct equals<T, void> } }; +template <typename T> +struct equals<T *, void> +{ + inline static bool apply(const T * v1, const T * v2) + { + return v1 == v2; + } +}; + template <typename Tuple, size_t I, size_t N> struct tuple_equals { diff --git a/boost/geometry/index/parameters.hpp b/boost/geometry/index/parameters.hpp index 2b94907686..1a9469c103 100644 --- a/boost/geometry/index/parameters.hpp +++ b/boost/geometry/index/parameters.hpp @@ -2,7 +2,7 @@ // // R-tree algorithms parameters // -// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -11,8 +11,14 @@ #ifndef BOOST_GEOMETRY_INDEX_PARAMETERS_HPP #define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP + #include <limits> +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/index/detail/exception.hpp> + + namespace boost { namespace geometry { namespace index { namespace detail { @@ -156,8 +162,8 @@ public: \param max_elements Maximum number of elements in nodes. \param min_elements Minimum number of elements in nodes. Default: 0.3*Max. */ - dynamic_linear(size_t max_elements, - size_t min_elements = detail::default_min_elements_d()) + explicit dynamic_linear(size_t max_elements, + size_t min_elements = detail::default_min_elements_d()) : m_max_elements(max_elements) , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) { @@ -185,8 +191,8 @@ public: \param max_elements Maximum number of elements in nodes. \param min_elements Minimum number of elements in nodes. Default: 0.3*Max. */ - dynamic_quadratic(size_t max_elements, - size_t min_elements = detail::default_min_elements_d()) + explicit dynamic_quadratic(size_t max_elements, + size_t min_elements = detail::default_min_elements_d()) : m_max_elements(max_elements) , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) { @@ -222,10 +228,10 @@ public: nearly minimum overlap cost, otherwise all leafs are analyzed and true minimum overlap cost is calculated. Default: 32. */ - dynamic_rstar(size_t max_elements, - size_t min_elements = detail::default_min_elements_d(), - size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(), - size_t overlap_cost_threshold = 32) + explicit dynamic_rstar(size_t max_elements, + size_t min_elements = detail::default_min_elements_d(), + size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(), + size_t overlap_cost_threshold = 32) : m_max_elements(max_elements) , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements)) , m_reinserted_elements(detail::default_rstar_reinserted_elements_d_calc(max_elements, reinserted_elements)) diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp index 148a5769dd..236690dc2c 100644 --- a/boost/geometry/io/wkt/read.hpp +++ b/boost/geometry/io/wkt/read.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2015. // Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. @@ -31,6 +32,7 @@ #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> +#include <boost/throw_exception.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_reference.hpp> @@ -139,15 +141,15 @@ struct parsing_assigner } catch(boost::bad_lexical_cast const& blc) { - throw read_wkt_exception(blc.what(), it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception(blc.what(), it, end, wkt)); } catch(std::exception const& e) { - throw read_wkt_exception(e.what(), it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception(e.what(), it, end, wkt)); } catch(...) { - throw read_wkt_exception("", it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("", it, end, wkt)); } parsing_assigner<Point, Dimension + 1, DimensionCount>::apply( @@ -175,7 +177,7 @@ inline void handle_open_parenthesis(Iterator& it, { if (it == end || *it != "(") { - throw read_wkt_exception("Expected '('", it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Expected '('", it, end, wkt)); } ++it; } @@ -192,7 +194,7 @@ inline void handle_close_parenthesis(Iterator& it, } else { - throw read_wkt_exception("Expected ')'", it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Expected ')'", it, end, wkt)); } } @@ -203,7 +205,7 @@ inline void check_end(Iterator& it, { if (it != end) { - throw read_wkt_exception("Too much tokens", it, end, wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Too many tokens", it, end, wkt)); } } @@ -529,7 +531,7 @@ inline bool initialize(tokenizer const& tokens, if (has_z && dimension<Geometry>::type::value < 3) { - throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt)); } #if defined(_MSC_VER) @@ -545,7 +547,7 @@ inline bool initialize(tokenizer const& tokens, return true; } - throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt)); } @@ -702,7 +704,7 @@ struct box_parser } else { - throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt)); } typedef typename point_type<Box>::type point_type; @@ -729,7 +731,7 @@ struct box_parser } else { - throw read_wkt_exception("Box should have 2,4 or 5 points", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt)); } geometry::detail::assign_point_to_index<min_corner>(points.front(), box); @@ -760,7 +762,7 @@ struct segment_parser } else { - throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt)); } typedef typename point_type<Segment>::type point_type; @@ -776,7 +778,7 @@ struct segment_parser } else { - throw read_wkt_exception("Segment should have 2 points", wkt); + BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt)); } } diff --git a/boost/geometry/policies/robustness/segment_ratio.hpp b/boost/geometry/policies/robustness/segment_ratio.hpp index f3dbabe70a..9b313fdfaf 100644 --- a/boost/geometry/policies/robustness/segment_ratio.hpp +++ b/boost/geometry/policies/robustness/segment_ratio.hpp @@ -145,11 +145,10 @@ public : m_approximation = m_denominator == 0 ? 0 - : boost::numeric_cast<double> - ( - boost::numeric_cast<fp_type>(m_numerator) * scale() - / boost::numeric_cast<fp_type>(m_denominator) - ); + : ( + boost::numeric_cast<fp_type>(m_numerator) * scale() + / boost::numeric_cast<fp_type>(m_denominator) + ); } inline bool is_zero() const { return math::equals(m_numerator, 0); } @@ -187,7 +186,7 @@ public : return false; } - static fp_type const small_part_of_scale = scale() / 100.0; + static fp_type const small_part_of_scale = scale() / 100; return m_approximation < small_part_of_scale || m_approximation > scale() - small_part_of_scale; } @@ -236,7 +235,14 @@ public : private : - typedef typename promote_floating_point<Type>::type fp_type; + // NOTE: if this typedef is used then fp_type is non-fundamental type + // if Type is non-fundamental type + //typedef typename promote_floating_point<Type>::type fp_type; + + typedef typename boost::mpl::if_c + < + boost::is_float<Type>::value, Type, double + >::type fp_type; Type m_numerator; Type m_denominator; diff --git a/boost/geometry/strategies/agnostic/point_in_point.hpp b/boost/geometry/strategies/agnostic/point_in_point.hpp index e4f9bec4c6..c6e2b63623 100644 --- a/boost/geometry/strategies/agnostic/point_in_point.hpp +++ b/boost/geometry/strategies/agnostic/point_in_point.hpp @@ -1,12 +1,13 @@ // 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 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_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP #define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP @@ -41,41 +42,12 @@ struct point_in_point namespace services { -template <typename Point1, typename Point2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2> -{ - typedef strategy::within::point_in_point<Point1, Point2> type; -}; - -template <typename Point1, typename Point2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2> -{ - typedef strategy::within::point_in_point<Point1, Point2> type; -}; - -template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2> +template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2> +struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2> { - typedef strategy::within::point_in_point<Point1, Point2> type; + typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type; }; -template <typename Point, typename MultiPoint> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint> -{ - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; -}; - -template <typename Point, typename MultiPoint> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint> -{ - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; -}; - -template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint> -{ - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; -}; } // namespace services @@ -85,45 +57,14 @@ struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, }} // namespace strategy::within - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS namespace strategy { namespace covered_by { namespace services { -template <typename Point1, typename Point2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2> -{ - typedef strategy::within::point_in_point<Point1, Point2> type; -}; - -template <typename Point1, typename Point2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2> -{ - typedef strategy::within::point_in_point<Point1, Point2> type; -}; - -template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2> -struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2> -{ - typedef strategy::within::point_in_point<Point1, Point2> type; -}; - -template <typename Point, typename MultiPoint> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint> -{ - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; -}; - -template <typename Point, typename MultiPoint> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint> -{ - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; -}; - -template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2> -struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint> +template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2> +struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2> { - typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type; + typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type; }; }}} // namespace strategy::covered_by::services diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp index 9e2ec2c4ff..3e7e258788 100644 --- a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2016. -// Modifications copyright (c) 2013-2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2016, 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 @@ -314,6 +314,7 @@ struct winding_calculate_count<Point, CalculationType, cartesian_tag> \ingroup strategies \tparam Point \tparam_point \tparam PointOfSegment \tparam_segment_point +\tparam SideStrategy Side strategy \tparam CalculationType \tparam_calculation \author Barend Gehrels \note The implementation is inspired by terralib http://www.terralib.org (LGPL) @@ -329,6 +330,10 @@ template < typename Point, typename PointOfSegment = Point, + typename SideStrategy = typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type, typename CalculationType = void > class winding @@ -339,14 +344,7 @@ class winding PointOfSegment, CalculationType >::type calculation_type; - - - typedef typename strategy::side::services::default_strategy - < - typename cs_tag<Point>::type - >::type strategy_side_type; - - + /*! subclass to keep state */ class counter { @@ -371,7 +369,6 @@ class winding }; - static inline int check_segment(Point const& point, PointOfSegment const& seg1, PointOfSegment const& seg2, counter& state, bool& eq1, bool& eq2) @@ -390,16 +387,22 @@ class winding } -public : +public: + winding() + {} + + explicit winding(SideStrategy const& side_strategy) + : m_side_strategy(side_strategy) + {} // Typedefs and static methods to fulfill the concept typedef Point point_type; typedef PointOfSegment segment_point_type; typedef counter state_type; - static inline bool apply(Point const& point, - PointOfSegment const& s1, PointOfSegment const& s2, - counter& state) + inline bool apply(Point const& point, + PointOfSegment const& s1, PointOfSegment const& s2, + counter& state) const { typedef typename cs_tag<Point>::type cs_t; @@ -418,7 +421,7 @@ public : else // count == 2 || count == -2 { // 1 left, -1 right - side = strategy_side_type::apply(s1, s2, point); + side = m_side_strategy.apply(s1, s2, point); } if (side == 0) @@ -445,6 +448,9 @@ public : { return state.code(); } + +private: + SideStrategy m_side_strategy; }; @@ -453,29 +459,26 @@ public : namespace services { -// Register using "areal_tag" for ring, polygon, multi-polygon -template <typename AnyTag, typename Point, typename Geometry> -struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, cartesian_tag, cartesian_tag, Point, Geometry> +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag> { typedef winding<Point, typename geometry::point_type<Geometry>::type> type; }; -template <typename AnyTag, typename Point, typename Geometry> -struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, spherical_tag, Point, Geometry> +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag> { typedef winding<Point, typename geometry::point_type<Geometry>::type> type; }; -// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used - template <typename Point, typename Geometry, typename AnyTag> -struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag> { typedef winding<Point, typename geometry::point_type<Geometry>::type> type; }; template <typename Point, typename Geometry, typename AnyTag> -struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag> { typedef winding<Point, typename geometry::point_type<Geometry>::type> type; }; @@ -488,34 +491,30 @@ struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, sph }} // namespace strategy::within - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS namespace strategy { namespace covered_by { namespace services { -// Register using "areal_tag" for ring, polygon, multi-polygon -template <typename AnyTag, typename Point, typename Geometry> -struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, cartesian_tag, cartesian_tag, Point, Geometry> +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag> { typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; }; -template <typename AnyTag, typename Point, typename Geometry> -struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag, spherical_tag, Point, Geometry> +template <typename Point, typename Geometry, typename AnyTag> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag> { typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; }; -// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used - template <typename Point, typename Geometry, typename AnyTag> -struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag> { typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; }; template <typename Point, typename Geometry, typename AnyTag> -struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry> +struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag> { typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type; }; diff --git a/boost/geometry/strategies/agnostic/relate.hpp b/boost/geometry/strategies/agnostic/relate.hpp deleted file mode 100644 index 676207694f..0000000000 --- a/boost/geometry/strategies/agnostic/relate.hpp +++ /dev/null @@ -1,122 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2014-2015 Oracle and/or its affiliates. - -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP -#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP - -#include <boost/geometry/algorithms/relate.hpp> - - -namespace boost { namespace geometry -{ - -namespace strategy { namespace relate -{ - -template <typename Geometry1, typename Geometry2, typename StaticMask> -struct relate -{ - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) - { - return geometry::relate(geometry1, geometry2, StaticMask()); - } -}; - -} // namespace relate - -namespace within -{ - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -namespace services -{ - - -template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> -struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2> -{ - typedef strategy::relate::relate - < - Geometry1, - Geometry2, - typename detail::de9im::static_mask_within_type - < - Geometry1, Geometry2 - >::type - > type; -}; - -template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> -struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2> -{ - typedef strategy::relate::relate - < - Geometry1, - Geometry2, - typename detail::de9im::static_mask_within_type - < - Geometry1, Geometry2 - >::type - > type; -}; - - -} // namespace services - -#endif - - -}} // namespace strategy::within - - - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS -namespace strategy { namespace covered_by { namespace services -{ - - -template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> -struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2> -{ - typedef strategy::relate::relate - < - Geometry1, - Geometry2, - typename detail::de9im::static_mask_covered_by_type - < - Geometry1, Geometry2 - >::type - > type; -}; - -template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS> -struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2> -{ - typedef strategy::relate::relate - < - Geometry1, - Geometry2, - typename detail::de9im::static_mask_covered_by_type - < - Geometry1, Geometry2 - >::type - > type; -}; - - -}}} // namespace strategy::covered_by::services -#endif - - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP diff --git a/boost/geometry/strategies/azimuth.hpp b/boost/geometry/strategies/azimuth.hpp new file mode 100644 index 0000000000..8044d3933b --- /dev/null +++ b/boost/geometry/strategies/azimuth.hpp @@ -0,0 +1,44 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP + +#include <boost/mpl/assert.hpp> + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace azimuth { namespace services +{ + +/*! +\brief Traits class binding a default azimuth strategy to a coordinate system +\ingroup util +\tparam CSTag tag of coordinate system +\tparam CalculationType \tparam_calculation +*/ +template <typename CSTag, typename CalculationType = void> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types<CSTag>) + ); +}; + +}}} // namespace strategy::azimuth::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP diff --git a/boost/geometry/strategies/cartesian/area_surveyor.hpp b/boost/geometry/strategies/cartesian/area_surveyor.hpp index ba76f67946..b3f19b1b1e 100644 --- a/boost/geometry/strategies/cartesian/area_surveyor.hpp +++ b/boost/geometry/strategies/cartesian/area_surveyor.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 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 @@ -25,6 +25,7 @@ //#include <boost/geometry/arithmetic/determinant.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/strategies/area.hpp> #include <boost/geometry/util/select_most_precise.hpp> diff --git a/boost/geometry/strategies/cartesian/azimuth.hpp b/boost/geometry/strategies/cartesian/azimuth.hpp new file mode 100644 index 0000000000..62f804e8f5 --- /dev/null +++ b/boost/geometry/strategies/cartesian/azimuth.hpp @@ -0,0 +1,49 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP + +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename CalculationType = void +> +class cartesian +{}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<cartesian_tag, CalculationType> +{ + typedef strategy::azimuth::cartesian<CalculationType> type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP diff --git a/boost/geometry/strategies/cartesian/box_in_box.hpp b/boost/geometry/strategies/cartesian/box_in_box.hpp index 28a6f29336..4641aafcb1 100644 --- a/boost/geometry/strategies/cartesian/box_in_box.hpp +++ b/boost/geometry/strategies/cartesian/box_in_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 2015, 2016. -// Modifications copyright (c) 2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017. +// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -238,10 +238,10 @@ namespace within { namespace services template <typename BoxContained, typename BoxContaining> struct default_strategy < + BoxContained, BoxContaining, box_tag, box_tag, - box_tag, areal_tag, - cartesian_tag, cartesian_tag, - BoxContained, BoxContaining + areal_tag, areal_tag, + cartesian_tag, cartesian_tag > { typedef within::box_in_box<BoxContained, BoxContaining> type; @@ -251,10 +251,10 @@ struct default_strategy template <typename BoxContained, typename BoxContaining> struct default_strategy < + BoxContained, BoxContaining, box_tag, box_tag, - box_tag, areal_tag, - spherical_tag, spherical_tag, - BoxContained, BoxContaining + areal_tag, areal_tag, + spherical_tag, spherical_tag > { typedef within::box_in_box<BoxContained, BoxContaining> type; @@ -269,10 +269,10 @@ namespace covered_by { namespace services template <typename BoxContained, typename BoxContaining> struct default_strategy < + BoxContained, BoxContaining, box_tag, box_tag, - box_tag, areal_tag, - cartesian_tag, cartesian_tag, - BoxContained, BoxContaining + areal_tag, areal_tag, + cartesian_tag, cartesian_tag > { typedef within::box_in_box @@ -286,10 +286,10 @@ struct default_strategy template <typename BoxContained, typename BoxContaining> struct default_strategy < + BoxContained, BoxContaining, box_tag, box_tag, - box_tag, areal_tag, - spherical_tag, spherical_tag, - BoxContained, BoxContaining + areal_tag, areal_tag, + spherical_tag, spherical_tag > { typedef within::box_in_box diff --git a/boost/geometry/strategies/cartesian/disjoint_segment_box.hpp b/boost/geometry/strategies/cartesian/disjoint_segment_box.hpp new file mode 100644 index 0000000000..4270803322 --- /dev/null +++ b/boost/geometry/strategies/cartesian/disjoint_segment_box.hpp @@ -0,0 +1,320 @@ +// Boost.Geometry + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-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 + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_SEGMENT_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_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/strategies/disjoint.hpp> + + +namespace boost { namespace geometry { namespace strategy { namespace disjoint +{ + +namespace detail +{ + +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; + } +}; + +} // namespace detail + +// NOTE: This may be temporary place for this or corresponding strategy +// It seems to be more appropriate to implement the opposite of it +// e.g. intersection::segment_box because in disjoint() algorithm +// other strategies that are used are intersection and covered_by strategies. +struct segment_box +{ + template <typename Segment, typename Box> + struct point_in_geometry_strategy + : services::default_strategy + < + typename point_type<Segment>::type, + Box + > + {}; + + template <typename Segment, typename Box> + static inline typename point_in_geometry_strategy<Segment, Box>::type + get_point_in_geometry_strategy() + { + typedef typename point_in_geometry_strategy<Segment, Box>::type strategy_type; + + return strategy_type(); + } + + template <typename Segment, typename Box> + static inline bool apply(Segment const& segment, Box const& box) + { + assert_dimension_equal<Segment, Box>(); + + typedef typename util::calculation_type::geometric::binary + < + Segment, Box, void + >::type relative_distance_type; + + typedef typename point_type<Segment>::type segment_point_type; + segment_point_type p0, p1; + geometry::detail::assign_point_from_index<0>(segment, p0); + geometry::detail::assign_point_from_index<1>(segment, p1); + + return detail::disjoint_segment_box_impl + < + relative_distance_type, segment_point_type, Box, + 0, dimension<Box>::value + >::apply(p0, p1, box); + } +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace services +{ + +// Currently used in all coordinate systems + +template <typename Linear, typename Box, typename LinearTag> +struct default_strategy<Linear, Box, LinearTag, box_tag, 1, 2> +{ + typedef disjoint::segment_box type; +}; + +template <typename Box, typename Linear, typename LinearTag> +struct default_strategy<Box, Linear, box_tag, LinearTag, 2, 1> +{ + typedef disjoint::segment_box type; +}; + + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}}} // namespace boost::geometry::strategy::disjoint + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_SEGMENT_BOX_HPP diff --git a/boost/geometry/strategies/cartesian/envelope_segment.hpp b/boost/geometry/strategies/cartesian/envelope_segment.hpp new file mode 100644 index 0000000000..0ddbf12a41 --- /dev/null +++ b/boost/geometry/strategies/cartesian/envelope_segment.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP + + +#include <boost/geometry/algorithms/detail/envelope/segment.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace envelope +{ + +template +< + typename CalculationType = void +> +class cartesian_segment +{ +public : + + template <typename Point1, typename Point2, typename Box> + inline void + apply(Point1 const& point1, Point2 const& point2, Box& box) const + { + geometry::detail::envelope::envelope_one_segment + < + 0, + dimension<Point1>::value + > + ::apply(point1, + point2, + box, + strategy::envelope::cartesian_segment<CalculationType>()); + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<cartesian_tag, CalculationType> +{ + typedef strategy::envelope::cartesian_segment<CalculationType> type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::envelope + +}} //namepsace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP diff --git a/boost/geometry/strategies/cartesian/cart_intersect.hpp b/boost/geometry/strategies/cartesian/intersection.hpp index 0cb5d75457..20b6b93367 100644 --- a/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/boost/geometry/strategies/cartesian/intersection.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 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 Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -33,13 +33,16 @@ #include <boost/geometry/util/promote_integral.hpp> #include <boost/geometry/util/select_calculation_type.hpp> -// Temporary / will be Strategy as template parameter -#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> +#include <boost/geometry/strategies/cartesian/area_surveyor.hpp> +#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp> #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> - -#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/strategies/covered_by.hpp> #include <boost/geometry/strategies/intersection.hpp> #include <boost/geometry/strategies/intersection_result.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/strategies/within.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> @@ -61,10 +64,74 @@ namespace strategy { namespace intersection /*! \see http://mathworld.wolfram.com/Line-LineIntersection.html */ -template <typename Policy, typename CalculationType = void> -struct relate_cartesian_segments +template +< + typename CalculationType = void +> +struct cartesian_segments { - typedef typename Policy::return_type return_type; + typedef side::side_by_triangle<CalculationType> side_strategy_type; + + static inline side_strategy_type get_side_strategy() + { + return side_strategy_type(); + } + + template <typename Geometry1, typename Geometry2> + struct point_in_geometry_strategy + { + typedef strategy::within::winding + < + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type, + side_strategy_type, + CalculationType + > type; + }; + + template <typename Geometry1, typename Geometry2> + static inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type + get_point_in_geometry_strategy() + { + typedef typename point_in_geometry_strategy + < + Geometry1, Geometry2 + >::type strategy_type; + return strategy_type(); + } + + template <typename Geometry> + struct area_strategy + { + typedef area::surveyor + < + typename point_type<Geometry>::type, + CalculationType + > type; + }; + + template <typename Geometry> + static inline typename area_strategy<Geometry>::type get_area_strategy() + { + typedef typename area_strategy<Geometry>::type strategy_type; + return strategy_type(); + } + + template <typename Geometry> + struct distance_strategy + { + typedef distance::pythagoras + < + CalculationType + > type; + }; + + template <typename Geometry> + static inline typename distance_strategy<Geometry>::type get_distance_strategy() + { + typedef typename distance_strategy<Geometry>::type strategy_type; + return strategy_type(); + } template <typename CoordinateType, typename SegmentRatio> struct segment_intersection_info @@ -144,9 +211,16 @@ struct relate_cartesian_segments // Relate segments a and b - template <typename Segment1, typename Segment2, typename RobustPolicy> - static inline return_type apply(Segment1 const& a, Segment2 const& b, - RobustPolicy const& robust_policy) + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy + > + static inline typename Policy::return_type + apply(Segment1 const& a, Segment2 const& b, + Policy const& policy, RobustPolicy const& robust_policy) { // type them all as in Segment1 - TODO reconsider this, most precise? typedef typename geometry::point_type<Segment1>::type point_type; @@ -169,18 +243,25 @@ struct relate_cartesian_segments geometry::recalculate(b0_rob, b0, robust_policy); geometry::recalculate(b1_rob, b1, robust_policy); - return apply(a, b, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob); + return apply(a, b, policy, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob); } // The main entry-routine, calculating intersections of segments a / b // NOTE: Robust* types may be the same as Segments' point types - template <typename Segment1, typename Segment2, - typename RobustPolicy, - typename RobustPoint1, typename RobustPoint2> - static inline return_type apply(Segment1 const& a, Segment2 const& b, - RobustPolicy const& /*robust_policy*/, - RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2, - RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2) + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy, + typename RobustPoint1, + typename RobustPoint2 + > + static inline typename Policy::return_type + apply(Segment1 const& a, Segment2 const& b, + Policy const&, RobustPolicy const& /*robust_policy*/, + RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2, + RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2) { BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) ); BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) ); @@ -197,14 +278,9 @@ struct relate_cartesian_segments ; } - typedef typename select_calculation_type - <Segment1, Segment2, CalculationType>::type coordinate_type; - - typedef side::side_by_triangle<coordinate_type> side; - side_info sides; - sides.set<0>(side::apply(robust_b1, robust_b2, robust_a1), - side::apply(robust_b1, robust_b2, robust_a2)); + sides.set<0>(side_strategy_type::apply(robust_b1, robust_b2, robust_a1), + side_strategy_type::apply(robust_b1, robust_b2, robust_a2)); if (sides.same<0>()) { @@ -212,8 +288,8 @@ struct relate_cartesian_segments return Policy::disjoint(); } - sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1), - side::apply(robust_a1, robust_a2, robust_b2)); + sides.set<1>(side_strategy_type::apply(robust_a1, robust_a2, robust_b1), + side_strategy_type::apply(robust_a1, robust_a2, robust_b2)); if (sides.same<1>()) { @@ -230,16 +306,16 @@ struct relate_cartesian_segments >::type robust_coordinate_type; typedef typename segment_ratio_type - < - typename geometry::point_type<Segment1>::type, // TODO: most precise point? - RobustPolicy - >::type ratio_type; + < + typename geometry::point_type<Segment1>::type, // TODO: most precise point? + RobustPolicy + >::type ratio_type; segment_intersection_info - < - coordinate_type, - ratio_type - > sinfo; + < + typename select_calculation_type<Segment1, Segment2, CalculationType>::type, + ratio_type + > sinfo; sinfo.dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir sinfo.dx_b = get<1, 0>(b) - get<0, 0>(b); @@ -303,14 +379,14 @@ struct relate_cartesian_segments if (collinear_use_first.first) { - return relate_collinear<0, ratio_type>(a, b, + return relate_collinear<0, Policy, ratio_type>(a, b, robust_a1, robust_a2, robust_b1, robust_b2, a_is_point, b_is_point); } else { // Y direction contains larger segments (maybe dx is zero) - return relate_collinear<1, ratio_type>(a, b, + return relate_collinear<1, Policy, ratio_type>(a, b, robust_a1, robust_a2, robust_b1, robust_b2, a_is_point, b_is_point); } @@ -358,33 +434,35 @@ private: template < std::size_t Dimension, + typename Policy, typename RatioType, typename Segment1, typename Segment2, typename RobustPoint1, typename RobustPoint2 > - static inline return_type relate_collinear(Segment1 const& a, - Segment2 const& b, - RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2, - RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2, - bool a_is_point, bool b_is_point) + static inline typename Policy::return_type + relate_collinear(Segment1 const& a, + Segment2 const& b, + RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2, + RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2, + bool a_is_point, bool b_is_point) { if (a_is_point) { - return relate_one_degenerate<RatioType>(a, + return relate_one_degenerate<Policy, RatioType>(a, get<Dimension>(robust_a1), get<Dimension>(robust_b1), get<Dimension>(robust_b2), true); } if (b_is_point) { - return relate_one_degenerate<RatioType>(b, + return relate_one_degenerate<Policy, RatioType>(b, get<Dimension>(robust_b1), get<Dimension>(robust_a1), get<Dimension>(robust_a2), false); } - return relate_collinear<RatioType>(a, b, + return relate_collinear<Policy, RatioType>(a, b, get<Dimension>(robust_a1), get<Dimension>(robust_a2), get<Dimension>(robust_b1), @@ -394,17 +472,17 @@ private: /// Relate segments known collinear template < + typename Policy, typename RatioType, typename Segment1, typename Segment2, typename RobustType1, typename RobustType2 > - static inline return_type relate_collinear(Segment1 const& a - , Segment2 const& b - , RobustType1 oa_1, RobustType1 oa_2 - , RobustType2 ob_1, RobustType2 ob_2 - ) + static inline typename Policy::return_type + relate_collinear(Segment1 const& a, Segment2 const& b, + RobustType1 oa_1, RobustType1 oa_2, + RobustType2 ob_1, RobustType2 ob_2) { // Calculate the ratios where a starts in b, b starts in a // a1--------->a2 (2..7) @@ -496,17 +574,16 @@ private: /// Relate segments where one is degenerate template < + typename Policy, typename RatioType, typename DegenerateSegment, typename RobustType1, typename RobustType2 > - static inline return_type relate_one_degenerate( - DegenerateSegment const& degenerate_segment - , RobustType1 d - , RobustType2 s1, RobustType2 s2 - , bool a_degenerate - ) + static inline typename Policy::return_type + relate_one_degenerate(DegenerateSegment const& degenerate_segment, + RobustType1 d, RobustType2 s1, RobustType2 s2, + bool a_degenerate) { // Calculate the ratios where ds starts in s // a1--------->a2 (2..6) @@ -546,10 +623,10 @@ private: namespace services { -template <typename Policy, typename CalculationType> -struct default_strategy<cartesian_tag, Policy, CalculationType> +template <typename CalculationType> +struct default_strategy<cartesian_tag, CalculationType> { - typedef relate_cartesian_segments<Policy, CalculationType> type; + typedef cartesian_segments<CalculationType> type; }; } // namespace services @@ -558,6 +635,69 @@ struct default_strategy<cartesian_tag, Policy, CalculationType> }} // namespace strategy::intersection +namespace strategy +{ + +namespace within { namespace services +{ + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +}} // within::services + +namespace covered_by { namespace services +{ + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, cartesian_tag, cartesian_tag> +{ + typedef strategy::intersection::cartesian_segments<> type; +}; + +}} // within::services + +} // strategy + }} // namespace boost::geometry diff --git a/boost/geometry/strategies/cartesian/point_in_box.hpp b/boost/geometry/strategies/cartesian/point_in_box.hpp index 227a98f2ad..1c14125a6d 100644 --- a/boost/geometry/strategies/cartesian/point_in_box.hpp +++ b/boost/geometry/strategies/cartesian/point_in_box.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 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 Adam Wulkiewicz, on behalf of Oracle @@ -219,10 +219,10 @@ namespace within { namespace services template <typename Point, typename Box> struct default_strategy < + Point, Box, point_tag, box_tag, - point_tag, areal_tag, - cartesian_tag, cartesian_tag, - Point, Box + pointlike_tag, areal_tag, + cartesian_tag, cartesian_tag > { typedef within::point_in_box<Point, Box> type; @@ -232,10 +232,10 @@ struct default_strategy template <typename Point, typename Box> struct default_strategy < + Point, Box, point_tag, box_tag, - point_tag, areal_tag, - spherical_tag, spherical_tag, - Point, Box + pointlike_tag, areal_tag, + spherical_tag, spherical_tag > { typedef within::point_in_box<Point, Box> type; @@ -252,10 +252,10 @@ namespace covered_by { namespace services template <typename Point, typename Box> struct default_strategy < + Point, Box, point_tag, box_tag, - point_tag, areal_tag, - cartesian_tag, cartesian_tag, - Point, Box + pointlike_tag, areal_tag, + cartesian_tag, cartesian_tag > { typedef within::point_in_box @@ -269,10 +269,10 @@ struct default_strategy template <typename Point, typename Box> struct default_strategy < + Point, Box, point_tag, box_tag, - point_tag, areal_tag, - spherical_tag, spherical_tag, - Point, Box + pointlike_tag, areal_tag, + spherical_tag, spherical_tag > { typedef within::point_in_box diff --git a/boost/geometry/strategies/covered_by.hpp b/boost/geometry/strategies/covered_by.hpp index a5aae7703b..363e34b68f 100644 --- a/boost/geometry/strategies/covered_by.hpp +++ b/boost/geometry/strategies/covered_by.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 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. @@ -16,6 +21,12 @@ #include <boost/mpl/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/tag_cast.hpp> + namespace boost { namespace geometry { @@ -31,23 +42,39 @@ namespace services /*! \brief Traits class binding a covered_by determination strategy to a coordinate system \ingroup covered_by -\tparam TagContained tag (possibly casted) of point-type -\tparam TagContained tag (possibly casted) of (possibly) containing type -\tparam CsTagContained tag of coordinate system of point-type -\tparam CsTagContaining tag of coordinate system of (possibly) containing type -\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContained geometry-type of input (possibly) contained type \tparam GeometryContaining geometry-type of input (possibly) containing type +\tparam TagContained casted tag of (possibly) contained type +\tparam TagContaining casted tag of (possibly) containing type +\tparam CsTagContained tag of coordinate system of (possibly) contained type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type */ template < - typename TagContained, - typename TagContaining, - typename CastedTagContained, - typename CastedTagContaining, - typename CsTagContained, - typename CsTagContaining, typename GeometryContained, - typename GeometryContaining + typename GeometryContaining, + typename TagContained = typename tag<GeometryContained>::type, + typename TagContaining = typename tag<GeometryContaining>::type, + typename CastedTagContained = typename tag_cast + < + typename tag<GeometryContained>::type, + pointlike_tag, linear_tag, polygonal_tag, areal_tag + >::type, + typename CastedTagContaining = typename tag_cast + < + typename tag<GeometryContaining>::type, + pointlike_tag, linear_tag, polygonal_tag, areal_tag + >::type, + typename CsTagContained = typename tag_cast + < + typename cs_tag<typename point_type<GeometryContained>::type>::type, + spherical_tag + >::type, + typename CsTagContaining = typename tag_cast + < + typename cs_tag<typename point_type<GeometryContaining>::type>::type, + spherical_tag + >::type > struct default_strategy { diff --git a/boost/geometry/strategies/disjoint.hpp b/boost/geometry/strategies/disjoint.hpp new file mode 100644 index 0000000000..f844cd86ad --- /dev/null +++ b/boost/geometry/strategies/disjoint.hpp @@ -0,0 +1,90 @@ +// Boost.Geometry + +// 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) + +#ifndef BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP +#define BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/topological_dimension.hpp> + +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/relate.hpp> + + +namespace boost { namespace geometry { namespace strategy { namespace disjoint +{ + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type, + int TopDim1 = geometry::topological_dimension<Geometry1>::value, + int TopDim2 = geometry::topological_dimension<Geometry2>::value +> +struct default_strategy + : relate::services::default_strategy + < + Geometry1, Geometry2 + > +{}; + +template <typename Point, typename Box> +struct default_strategy<Point, Box, point_tag, box_tag, 0, 2> + : strategy::covered_by::services::default_strategy<Point, Box> +{}; + +template <typename Box, typename Point> +struct default_strategy<Box, Point, box_tag, point_tag, 2, 0> + : strategy::covered_by::services::default_strategy<Point, Box> +{}; + +template <typename MultiPoint, typename Box> +struct default_strategy<MultiPoint, Box, multi_point_tag, box_tag, 0, 2> + : strategy::covered_by::services::default_strategy + < + typename point_type<MultiPoint>::type, + Box + > +{}; + +template <typename Box, typename MultiPoint> +struct default_strategy<Box, MultiPoint, box_tag, multi_point_tag, 2, 0> + : strategy::covered_by::services::default_strategy + < + typename point_type<MultiPoint>::type, + Box + > +{}; + +template <typename Box1, typename Box2> +struct default_strategy<Box1, Box2, box_tag, box_tag, 2, 2> +{ + // dummy strategy which will be ignored + typedef geometry::default_strategy type; +}; + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}}}} // namespace boost::geometry::strategy::disjoint + + +#endif // BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP diff --git a/boost/geometry/strategies/envelope.hpp b/boost/geometry/strategies/envelope.hpp new file mode 100644 index 0000000000..fde9c858a6 --- /dev/null +++ b/boost/geometry/strategies/envelope.hpp @@ -0,0 +1,45 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP +#define BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP + +#include <boost/mpl/assert.hpp> + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace envelope { namespace services +{ + +/*! +\brief Traits class binding a default envelope strategy to a coordinate system +\ingroup util +\tparam CSTag tag of coordinate system +\tparam CalculationType \tparam_calculation +*/ +template <typename CSTag, typename CalculationType = void> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types<CSTag>) + ); +}; + +}}} // namespace strategy::envelope::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP + diff --git a/boost/geometry/strategies/geographic/area.hpp b/boost/geometry/strategies/geographic/area.hpp new file mode 100644 index 0000000000..e1d3b09b5a --- /dev/null +++ b/boost/geometry/strategies/geographic/area.hpp @@ -0,0 +1,216 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP + + +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/formulas/area_formulas.hpp> +#include <boost/geometry/formulas/flattening.hpp> + +#include <boost/geometry/strategies/geographic/parameters.hpp> + +#include <boost/math/special_functions/atanh.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + +/*! +\brief Geographic area calculation +\ingroup strategies +\details Geographic area calculation by trapezoidal rule plus integral + approximation that gives the ellipsoidal correction +\tparam PointOfSegment \tparam_segment_point +\tparam FormulaPolicy Formula used to calculate azimuths +\tparam SeriesOrder The order of approximation of the geodesic integral +\tparam Spheroid The spheroid model +\tparam CalculationType \tparam_calculation +\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 + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] +} +*/ +template +< + typename PointOfSegment, + typename FormulaPolicy = strategy::andoyer, + std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value, + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +class geographic +{ + // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2) + static const bool ExpandEpsN = true; + // LongSegment Enables special handling of long segments + static const bool LongSegment = false; + + //Select default types in case they are not set + + typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename coordinate_type<PointOfSegment>::type, + double + >::type, + CalculationType + >::type CT; + +protected : + struct spheroid_constants + { + Spheroid m_spheroid; + CT const m_a2; // squared equatorial radius + CT const m_e2; // squared eccentricity + CT const m_ep2; // squared second eccentricity + CT const m_ep; // second eccentricity + CT const m_c2; // authalic radius + + inline spheroid_constants(Spheroid const& spheroid) + : m_spheroid(spheroid) + , m_a2(math::sqr(get_radius<0>(spheroid))) + , m_e2(formula::flattening<CT>(spheroid) + * (CT(2.0) - CT(formula::flattening<CT>(spheroid)))) + , m_ep2(m_e2 / (CT(1.0) - m_e2)) + , m_ep(math::sqrt(m_ep2)) + , m_c2((m_a2 / CT(2.0)) + + ((math::sqr(get_radius<2>(spheroid)) * boost::math::atanh(math::sqrt(m_e2))) + / (CT(2.0) * math::sqrt(m_e2)))) + {} + }; + + struct area_sums + { + CT m_excess_sum; + CT m_correction_sum; + + // Keep track if encircles some pole + std::size_t m_crosses_prime_meridian; + + inline area_sums() + : m_excess_sum(0) + , m_correction_sum(0) + , m_crosses_prime_meridian(0) + {} + inline CT area(spheroid_constants spheroid_const) const + { + CT result; + + CT sum = spheroid_const.m_c2 * m_excess_sum + + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum; + + // If encircles some pole + if (m_crosses_prime_meridian % 2 == 1) + { + std::size_t times_crosses_prime_meridian + = 1 + (m_crosses_prime_meridian / 2); + + result = CT(2.0) + * geometry::math::pi<CT>() + * spheroid_const.m_c2 + * CT(times_crosses_prime_meridian) + - geometry::math::abs(sum); + + if (geometry::math::sign<CT>(sum) == 1) + { + result = - result; + } + + } + else + { + result = sum; + } + + return result; + } + }; + +public : + typedef CT return_type; + typedef PointOfSegment segment_point_type; + typedef area_sums state_type; + + explicit inline geographic(Spheroid const& spheroid = Spheroid()) + : m_spheroid_constants(spheroid) + {} + + inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + area_sums& state) const + { + + if (! geometry::math::equals(get<0>(p1), get<0>(p2))) + { + + typedef geometry::formula::area_formulas + < + CT, SeriesOrder, ExpandEpsN + > area_formulas; + + typename area_formulas::return_type_ellipsoidal result = + area_formulas::template ellipsoidal<FormulaPolicy::template inverse> + (p1, p2, m_spheroid_constants); + + state.m_excess_sum += result.spherical_term; + state.m_correction_sum += result.ellipsoidal_term; + + // Keep track whenever a segment crosses the prime meridian + geometry::formula::area_formulas<CT> + ::crosses_prime_meridian(p1, p2, state); + } + } + + inline return_type result(area_sums const& state) const + { + return state.area(m_spheroid_constants); + } + +private: + spheroid_constants m_spheroid_constants; + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template <typename Point> +struct default_strategy<geographic_tag, Point> +{ + typedef strategy::area::geographic<Point> type; +}; + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +} + +}} // namespace strategy::area + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP diff --git a/boost/geometry/strategies/geographic/azimuth.hpp b/boost/geometry/strategies/geographic/azimuth.hpp new file mode 100644 index 0000000000..47f59d1033 --- /dev/null +++ b/boost/geometry/strategies/geographic/azimuth.hpp @@ -0,0 +1,103 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP + + +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/strategies/azimuth.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> + +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_void.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename FormulaPolicy = strategy::andoyer, + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +class geographic +{ +public : + + typedef Spheroid model_type; + + inline geographic() + : m_spheroid() + {} + + explicit inline geographic(Spheroid const& spheroid) + : m_spheroid(spheroid) + {} + + inline model_type const& model() const + { + return m_spheroid; + } + + template <typename T> + inline void apply(T const& lon1_rad, T const& lat1_rad, + T const& lon2_rad, T const& lat2_rad, + T& a1, T& a2) const + { + typedef typename boost::mpl::if_ + < + boost::is_void<CalculationType>, T, CalculationType + >::type calc_t; + + typedef typename FormulaPolicy::template inverse<calc_t, false, true, true, false, false> inverse_type; + typedef typename inverse_type::result_type inverse_result; + inverse_result i_res = inverse_type::apply(calc_t(lon1_rad), calc_t(lat1_rad), + calc_t(lon2_rad), calc_t(lat2_rad), + m_spheroid); + a1 = i_res.azimuth; + a2 = i_res.reverse_azimuth; + } + +private : + Spheroid m_spheroid; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<geographic_tag, CalculationType> +{ + typedef strategy::azimuth::geographic + < + strategy::andoyer, + srs::spheroid<double>, + CalculationType + > type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP diff --git a/boost/geometry/strategies/geographic/distance.hpp b/boost/geometry/strategies/geographic/distance.hpp new file mode 100644 index 0000000000..d3656f449c --- /dev/null +++ b/boost/geometry/strategies/geographic/distance.hpp @@ -0,0 +1,195 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands. + +// 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 + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP + + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/formulas/andoyer_inverse.hpp> +#include <boost/geometry/formulas/flattening.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace distance +{ + +template +< + typename FormulaPolicy = strategy::andoyer, + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +class geographic +{ +public : + template <typename Point1, typename Point2> + struct calculation_type + : promote_floating_point + < + typename select_calculation_type + < + Point1, + Point2, + CalculationType + >::type + > + {}; + + typedef Spheroid model_type; + + inline geographic() + : m_spheroid() + {} + + explicit inline geographic(Spheroid const& spheroid) + : m_spheroid(spheroid) + {} + + template <typename Point1, typename Point2> + inline typename calculation_type<Point1, Point2>::type + apply(Point1 const& point1, Point2 const& point2) const + { + return FormulaPolicy::template inverse + < + typename calculation_type<Point1, Point2>::type, + true, false, false, false, false + >::apply(get_as_radian<0>(point1), get_as_radian<1>(point1), + get_as_radian<0>(point2), get_as_radian<1>(point2), + m_spheroid).distance; + } + + inline Spheroid const& model() const + { + return m_spheroid; + } + +private : + Spheroid m_spheroid; +}; + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template +< + typename FormulaPolicy, + typename Spheroid, + typename CalculationType +> +struct tag<geographic<FormulaPolicy, Spheroid, CalculationType> > +{ + typedef strategy_tag_distance_point_point type; +}; + + +template +< + typename FormulaPolicy, + typename Spheroid, + typename CalculationType, + typename P1, + typename P2 +> +struct return_type<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2> + : geographic<FormulaPolicy, Spheroid, CalculationType>::template calculation_type<P1, P2> +{}; + + +template +< + typename FormulaPolicy, + typename Spheroid, + typename CalculationType +> +struct comparable_type<geographic<FormulaPolicy, Spheroid, CalculationType> > +{ + typedef geographic<FormulaPolicy, Spheroid, CalculationType> type; +}; + + +template +< + typename FormulaPolicy, + typename Spheroid, + typename CalculationType +> +struct get_comparable<geographic<FormulaPolicy, Spheroid, CalculationType> > +{ + static inline geographic<FormulaPolicy, Spheroid, CalculationType> + apply(geographic<FormulaPolicy, Spheroid, CalculationType> const& input) + { + return input; + } +}; + +template +< + typename FormulaPolicy, + typename Spheroid, + typename CalculationType, + typename P1, + typename P2 +> +struct result_from_distance<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2> +{ + template <typename T> + static inline typename return_type<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2>::type + apply(geographic<FormulaPolicy, Spheroid, CalculationType> const& , T const& value) + { + return value; + } +}; + + +template <typename Point1, typename Point2> +struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag> +{ + typedef strategy::distance::geographic + < + strategy::andoyer, + srs::spheroid + < + typename select_coordinate_type<Point1, Point2>::type + > + > type; +}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::distance + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP diff --git a/boost/geometry/strategies/geographic/distance_andoyer.hpp b/boost/geometry/strategies/geographic/distance_andoyer.hpp index 1946cd1090..d732951642 100644 --- a/boost/geometry/strategies/geographic/distance_andoyer.hpp +++ b/boost/geometry/strategies/geographic/distance_andoyer.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2016 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, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -11,24 +11,12 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP -#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/radian_access.hpp> -#include <boost/geometry/core/radius.hpp> -#include <boost/geometry/core/srs.hpp> - -#include <boost/geometry/algorithms/detail/flattening.hpp> - -#include <boost/geometry/formulas/andoyer_inverse.hpp> - -#include <boost/geometry/strategies/distance.hpp> - -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/promote_floating_point.hpp> -#include <boost/geometry/util/select_calculation_type.hpp> +#include <boost/geometry/strategies/geographic/distance.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> namespace boost { namespace geometry @@ -57,55 +45,28 @@ are about the same as Vincenty. In my (Barend's) testcases the results didn't di */ template < - typename Spheroid, + typename Spheroid = srs::spheroid<double>, typename CalculationType = void > class andoyer + : public strategy::distance::geographic + < + strategy::andoyer, Spheroid, CalculationType + > { -public : - template <typename Point1, typename Point2> - struct calculation_type - : promote_floating_point - < - typename select_calculation_type - < - Point1, - Point2, - CalculationType - >::type - > - {}; - - typedef Spheroid model_type; + typedef strategy::distance::geographic + < + strategy::andoyer, Spheroid, CalculationType + > base_type; +public : inline andoyer() - : m_spheroid() + : base_type() {} explicit inline andoyer(Spheroid const& spheroid) - : m_spheroid(spheroid) + : base_type(spheroid) {} - - template <typename Point1, typename Point2> - inline typename calculation_type<Point1, Point2>::type - apply(Point1 const& point1, Point2 const& point2) const - { - return geometry::formula::andoyer_inverse - < - typename calculation_type<Point1, Point2>::type, - true, false - >::apply(get_as_radian<0>(point1), get_as_radian<1>(point1), - get_as_radian<0>(point2), get_as_radian<1>(point2), - m_spheroid).distance; - } - - inline Spheroid const& model() const - { - return m_spheroid; - } - -private : - Spheroid m_spheroid; }; @@ -154,19 +115,6 @@ struct result_from_distance<andoyer<Spheroid, CalculationType>, P1, P2> }; -template <typename Point1, typename Point2> -struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag> -{ - typedef strategy::distance::andoyer - < - srs::spheroid - < - typename select_coordinate_type<Point1, Point2>::type - > - > type; -}; - - } // namespace services #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS @@ -177,4 +125,4 @@ struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, ge }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP diff --git a/boost/geometry/strategies/geographic/distance_thomas.hpp b/boost/geometry/strategies/geographic/distance_thomas.hpp index 39e0ecfa6f..490920c778 100644 --- a/boost/geometry/strategies/geographic/distance_thomas.hpp +++ b/boost/geometry/strategies/geographic/distance_thomas.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// 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 Adam Wulkiewicz, on behalf of Oracle @@ -15,15 +15,9 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_THOMAS_HPP -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/strategies/geographic/distance.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> -#include <boost/geometry/strategies/distance.hpp> - -#include <boost/geometry/util/promote_floating_point.hpp> -#include <boost/geometry/util/select_calculation_type.hpp> - -#include <boost/geometry/formulas/thomas_inverse.hpp> namespace boost { namespace geometry { @@ -45,57 +39,28 @@ namespace strategy { namespace distance */ template < - typename Spheroid, + typename Spheroid = srs::spheroid<double>, typename CalculationType = void > class thomas + : public strategy::distance::geographic + < + strategy::thomas, Spheroid, CalculationType + > { -public : - template <typename Point1, typename Point2> - struct calculation_type - : promote_floating_point - < - typename select_calculation_type - < - Point1, - Point2, - CalculationType - >::type - > - {}; - - typedef Spheroid model_type; + typedef strategy::distance::geographic + < + strategy::thomas, Spheroid, CalculationType + > base_type; +public : inline thomas() - : m_spheroid() + : base_type() {} explicit inline thomas(Spheroid const& spheroid) - : m_spheroid(spheroid) + : base_type(spheroid) {} - - template <typename Point1, typename Point2> - inline typename calculation_type<Point1, Point2>::type - apply(Point1 const& point1, Point2 const& point2) const - { - return geometry::formula::thomas_inverse - < - typename calculation_type<Point1, Point2>::type, - true, false - >::apply(get_as_radian<0>(point1), - get_as_radian<1>(point1), - get_as_radian<0>(point2), - get_as_radian<1>(point2), - m_spheroid).distance; - } - - inline Spheroid const& model() const - { - return m_spheroid; - } - -private : - Spheroid m_spheroid; }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/boost/geometry/strategies/geographic/distance_vincenty.hpp b/boost/geometry/strategies/geographic/distance_vincenty.hpp index e79e9aeb46..41146db9ff 100644 --- a/boost/geometry/strategies/geographic/distance_vincenty.hpp +++ b/boost/geometry/strategies/geographic/distance_vincenty.hpp @@ -2,8 +2,8 @@ // 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-2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,15 +15,9 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/strategies/geographic/distance.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> -#include <boost/geometry/strategies/distance.hpp> - -#include <boost/geometry/util/promote_floating_point.hpp> -#include <boost/geometry/util/select_calculation_type.hpp> - -#include <boost/geometry/formulas/vincenty_inverse.hpp> namespace boost { namespace geometry { @@ -47,57 +41,28 @@ namespace strategy { namespace distance */ template < - typename Spheroid, + typename Spheroid = srs::spheroid<double>, typename CalculationType = void > class vincenty + : public strategy::distance::geographic + < + strategy::vincenty, Spheroid, CalculationType + > { -public : - template <typename Point1, typename Point2> - struct calculation_type - : promote_floating_point - < - typename select_calculation_type - < - Point1, - Point2, - CalculationType - >::type - > - {}; - - typedef Spheroid model_type; + typedef strategy::distance::geographic + < + strategy::vincenty, Spheroid, CalculationType + > base_type; +public: inline vincenty() - : m_spheroid() + : base_type() {} explicit inline vincenty(Spheroid const& spheroid) - : m_spheroid(spheroid) + : base_type(spheroid) {} - - template <typename Point1, typename Point2> - inline typename calculation_type<Point1, Point2>::type - apply(Point1 const& point1, Point2 const& point2) const - { - return geometry::formula::vincenty_inverse - < - typename calculation_type<Point1, Point2>::type, - true, false - >::apply(get_as_radian<0>(point1), - get_as_radian<1>(point1), - get_as_radian<0>(point2), - get_as_radian<1>(point2), - m_spheroid).distance; - } - - inline Spheroid const& model() const - { - return m_spheroid; - } - -private : - Spheroid m_spheroid; }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/boost/geometry/strategies/geographic/envelope_segment.hpp b/boost/geometry/strategies/geographic/envelope_segment.hpp new file mode 100644 index 0000000000..3641b39428 --- /dev/null +++ b/boost/geometry/strategies/geographic/envelope_segment.hpp @@ -0,0 +1,104 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP + + +#include <boost/geometry/algorithms/detail/envelope/segment.hpp> +#include <boost/geometry/algorithms/detail/normalize.hpp> +#include <boost/geometry/core/srs.hpp> +#include <boost/geometry/strategies/envelope.hpp> +#include <boost/geometry/strategies/geographic/azimuth.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace envelope +{ + +template +< + typename FormulaPolicy = strategy::andoyer, + typename Spheroid = geometry::srs::spheroid<double>, + typename CalculationType = void +> +class geographic_segment +{ +public: + typedef Spheroid model_type; + + inline geographic_segment() + : m_spheroid() + {} + + explicit inline geographic_segment(Spheroid const& spheroid) + : m_spheroid(spheroid) + {} + + template <typename Point1, typename Point2, typename Box> + inline void apply(Point1 const& point1, Point2 const& point2, Box& box) const + { + Point1 p1_normalized = detail::return_normalized<Point1>(point1); + Point2 p2_normalized = detail::return_normalized<Point2>(point2); + + geometry::strategy::azimuth::geographic + < + FormulaPolicy, + Spheroid, + CalculationType + > azimuth_geographic(m_spheroid); + + typedef typename coordinate_system<Point1>::type::units units_type; + + detail::envelope::envelope_segment_impl + < + geographic_tag + >::template apply<units_type>(geometry::get<0>(p1_normalized), + geometry::get<1>(p1_normalized), + geometry::get<0>(p2_normalized), + geometry::get<1>(p2_normalized), + box, + azimuth_geographic); + + } + +private: + Spheroid m_spheroid; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<geographic_tag, CalculationType> +{ + typedef strategy::envelope::geographic_segment + < + strategy::andoyer, + srs::spheroid<double>, + CalculationType + > type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::envelope + +}} //namepsace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP diff --git a/boost/geometry/strategies/geographic/intersection.hpp b/boost/geometry/strategies/geographic/intersection.hpp new file mode 100644 index 0000000000..1708c274c0 --- /dev/null +++ b/boost/geometry/strategies/geographic/intersection.hpp @@ -0,0 +1,897 @@ +// Boost.Geometry + +// 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, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP + +#include <algorithm> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/srs.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/algorithms/detail/assign_values.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> + +#include <boost/geometry/formulas/andoyer_inverse.hpp> +#include <boost/geometry/formulas/sjoberg_intersection.hpp> +#include <boost/geometry/formulas/spherical.hpp> + +#include <boost/geometry/geometries/concepts/point_concept.hpp> +#include <boost/geometry/geometries/concepts/segment_concept.hpp> + +#include <boost/geometry/policies/robustness/segment_ratio.hpp> + +#include <boost/geometry/strategies/geographic/area.hpp> +#include <boost/geometry/strategies/geographic/distance.hpp> +#include <boost/geometry/strategies/geographic/parameters.hpp> +#include <boost/geometry/strategies/geographic/side.hpp> +#include <boost/geometry/strategies/intersection.hpp> +#include <boost/geometry/strategies/intersection_result.hpp> +#include <boost/geometry/strategies/side_info.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace intersection +{ + +// CONSIDER: Improvement of the robustness/accuracy/repeatability by +// moving all segments to 0 longitude +// picking latitudes closer to 0 +// etc. + +template +< + typename FormulaPolicy = strategy::andoyer, + unsigned int Order = strategy::default_order<FormulaPolicy>::value, + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +struct geographic_segments +{ + typedef side::geographic + < + FormulaPolicy, Spheroid, CalculationType + > side_strategy_type; + + inline side_strategy_type get_side_strategy() const + { + return side_strategy_type(m_spheroid); + } + + template <typename Geometry1, typename Geometry2> + struct point_in_geometry_strategy + { + typedef strategy::within::winding + < + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type, + side_strategy_type, + CalculationType + > type; + }; + + template <typename Geometry1, typename Geometry2> + inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type + get_point_in_geometry_strategy() const + { + typedef typename point_in_geometry_strategy + < + Geometry1, Geometry2 + >::type strategy_type; + return strategy_type(get_side_strategy()); + } + + template <typename Geometry> + struct area_strategy + { + typedef area::geographic + < + typename point_type<Geometry>::type, + FormulaPolicy, + Order, + Spheroid, + CalculationType + > type; + }; + + template <typename Geometry> + inline typename area_strategy<Geometry>::type get_area_strategy() const + { + typedef typename area_strategy<Geometry>::type strategy_type; + return strategy_type(m_spheroid); + } + + template <typename Geometry> + struct distance_strategy + { + typedef distance::geographic + < + FormulaPolicy, + Spheroid, + CalculationType + > type; + }; + + template <typename Geometry> + inline typename distance_strategy<Geometry>::type get_distance_strategy() const + { + typedef typename distance_strategy<Geometry>::type strategy_type; + return strategy_type(m_spheroid); + } + + enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 }; + + template <typename CoordinateType, typename SegmentRatio> + struct segment_intersection_info + { + typedef typename select_most_precise + < + CoordinateType, double + >::type promoted_type; + + promoted_type comparable_length_a() const + { + return robust_ra.denominator(); + } + + promoted_type comparable_length_b() const + { + return robust_rb.denominator(); + } + + template <typename Point, typename Segment1, typename Segment2> + void assign_a(Point& point, Segment1 const& a, Segment2 const& b) const + { + assign(point, a, b); + } + template <typename Point, typename Segment1, typename Segment2> + void assign_b(Point& point, Segment1 const& a, Segment2 const& b) const + { + assign(point, a, b); + } + + template <typename Point, typename Segment1, typename Segment2> + void assign(Point& point, Segment1 const& a, Segment2 const& b) const + { + if (ip_flag == ipi_inters) + { + // TODO: assign the rest of coordinates + set_from_radian<0>(point, lon); + set_from_radian<1>(point, lat); + } + else if (ip_flag == ipi_at_a1) + { + detail::assign_point_from_index<0>(a, point); + } + else if (ip_flag == ipi_at_a2) + { + detail::assign_point_from_index<1>(a, point); + } + else if (ip_flag == ipi_at_b1) + { + detail::assign_point_from_index<0>(b, point); + } + else // ip_flag == ipi_at_b2 + { + detail::assign_point_from_index<1>(b, point); + } + } + + CoordinateType lon; + CoordinateType lat; + SegmentRatio robust_ra; + SegmentRatio robust_rb; + intersection_point_flag ip_flag; + }; + + explicit geographic_segments(Spheroid const& spheroid = Spheroid()) + : m_spheroid(spheroid) + {} + + // Relate segments a and b + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy + > + inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b, + Policy const& policy, + RobustPolicy const& robust_policy) const + { + typedef typename point_type<Segment1>::type point1_t; + typedef typename point_type<Segment2>::type point2_t; + point1_t a1, a2; + point2_t b1, b2; + + detail::assign_point_from_index<0>(a, a1); + detail::assign_point_from_index<1>(a, a2); + detail::assign_point_from_index<0>(b, b1); + detail::assign_point_from_index<1>(b, b2); + + return apply(a, b, policy, robust_policy, a1, a2, b1, b2); + } + + // Relate segments a and b + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy, + typename Point1, + typename Point2 + > + inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b, + Policy const&, RobustPolicy const&, + Point1 a1, Point1 a2, Point2 b1, Point2 b2) const + { + bool is_a_reversed = get<1>(a1) > get<1>(a2); + bool is_b_reversed = get<1>(b1) > get<1>(b2); + + if (is_a_reversed) + { + std::swap(a1, a2); + } + + if (is_b_reversed) + { + std::swap(b1, b2); + } + + return apply<Policy>(a, b, a1, a2, b1, b2, is_a_reversed, is_b_reversed); + } + +private: + // Relate segments a and b + template + < + typename Policy, + typename Segment1, + typename Segment2, + typename Point1, + typename Point2 + > + inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b, + Point1 const& a1, Point1 const& a2, + Point2 const& b1, Point2 const& b2, + bool is_a_reversed, bool is_b_reversed) const + { + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) ); + + typedef typename select_calculation_type + <Segment1, Segment2, CalculationType>::type calc_t; + + // normalized spheroid + srs::spheroid<calc_t> spheroid = normalized_spheroid<calc_t>(m_spheroid); + + // TODO: check only 2 first coordinates here? + using geometry::detail::equals::equals_point_point; + bool a_is_point = equals_point_point(a1, a2); + bool b_is_point = equals_point_point(b1, b2); + + if(a_is_point && b_is_point) + { + return equals_point_point(a1, b2) + ? Policy::degenerate(a, true) + : Policy::disjoint() + ; + } + + calc_t const a1_lon = get_as_radian<0>(a1); + calc_t const a1_lat = get_as_radian<1>(a1); + calc_t const a2_lon = get_as_radian<0>(a2); + calc_t const a2_lat = get_as_radian<1>(a2); + calc_t const b1_lon = get_as_radian<0>(b1); + calc_t const b1_lat = get_as_radian<1>(b1); + calc_t const b2_lon = get_as_radian<0>(b2); + calc_t const b2_lat = get_as_radian<1>(b2); + + side_info sides; + + // NOTE: potential optimization, don't calculate distance at this point + // this would require to reimplement inverse strategy to allow + // calculation of distance if needed, probably also storing intermediate + // results somehow inside an object. + typedef typename FormulaPolicy::template inverse<calc_t, true, true, false, false, false> inverse_dist_azi; + typedef typename inverse_dist_azi::result_type inverse_result; + + // TODO: no need to call inverse formula if we know that the points are equal + // distance can be set to 0 in this case and azimuth may be not calculated + bool const is_equal_a1_b1 = equals_point_point(a1, b1); + bool const is_equal_a2_b1 = equals_point_point(a2, b1); + + inverse_result res_b1_b2 = inverse_dist_azi::apply(b1_lon, b1_lat, b2_lon, b2_lat, spheroid); + inverse_result res_b1_a1 = inverse_dist_azi::apply(b1_lon, b1_lat, a1_lon, a1_lat, spheroid); + inverse_result res_b1_a2 = inverse_dist_azi::apply(b1_lon, b1_lat, a2_lon, a2_lat, spheroid); + sides.set<0>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_b1_a1.azimuth, res_b1_b2.azimuth), + is_equal_a2_b1 ? 0 : formula::azimuth_side_value(res_b1_a2.azimuth, res_b1_b2.azimuth)); + if (sides.same<0>()) + { + // Both points are at the same side of other segment, we can leave + return Policy::disjoint(); + } + + bool const is_equal_a1_b2 = equals_point_point(a1, b2); + + inverse_result res_a1_a2 = inverse_dist_azi::apply(a1_lon, a1_lat, a2_lon, a2_lat, spheroid); + inverse_result res_a1_b1 = inverse_dist_azi::apply(a1_lon, a1_lat, b1_lon, b1_lat, spheroid); + inverse_result res_a1_b2 = inverse_dist_azi::apply(a1_lon, a1_lat, b2_lon, b2_lat, spheroid); + sides.set<1>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_a1_b1.azimuth, res_a1_a2.azimuth), + is_equal_a1_b2 ? 0 : formula::azimuth_side_value(res_a1_b2.azimuth, res_a1_a2.azimuth)); + if (sides.same<1>()) + { + // Both points are at the same side of other segment, we can leave + return Policy::disjoint(); + } + + // NOTE: at this point the segments may still be disjoint + // NOTE: at this point one of the segments may be degenerated + + bool collinear = sides.collinear(); + + if (! collinear) + { + // WARNING: the side strategy doesn't have the info about the other + // segment so it may return results inconsistent with this intersection + // strategy, as it checks both segments for consistency + + if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0) + { + collinear = true; + sides.set<1>(0, 0); + } + else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0) + { + collinear = true; + sides.set<0>(0, 0); + } + } + + if (collinear) + { + if (a_is_point) + { + return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, res_b1_b2, res_b1_a1, is_b_reversed); + } + else if (b_is_point) + { + return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, res_a1_a2, res_a1_b1, is_a_reversed); + } + else + { + calc_t dist_a1_a2, dist_a1_b1, dist_a1_b2; + calc_t dist_b1_b2, dist_b1_a1, dist_b1_a2; + // use shorter segment + if (res_a1_a2.distance <= res_b1_b2.distance) + { + calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b1, dist_a1_a2, dist_a1_b1); + calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b2, dist_a1_a2, dist_a1_b2); + dist_b1_b2 = dist_a1_b2 - dist_a1_b1; + dist_b1_a1 = -dist_a1_b1; + dist_b1_a2 = dist_a1_a2 - dist_a1_b1; + } + else + { + calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a1, dist_b1_b2, dist_b1_a1); + calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a2, dist_b1_b2, dist_b1_a2); + dist_a1_a2 = dist_b1_a2 - dist_b1_a1; + dist_a1_b1 = -dist_b1_a1; + dist_a1_b2 = dist_b1_b2 - dist_b1_a1; + } + + // NOTE: this is probably not needed + calc_t const c0 = 0; + int a1_on_b = position_value(c0, dist_a1_b1, dist_a1_b2); + int a2_on_b = position_value(dist_a1_a2, dist_a1_b1, dist_a1_b2); + int b1_on_a = position_value(c0, dist_b1_a1, dist_b1_a2); + int b2_on_a = position_value(dist_b1_b2, dist_b1_a1, dist_b1_a2); + + if ((a1_on_b < 1 && a2_on_b < 1) || (a1_on_b > 3 && a2_on_b > 3)) + { + return Policy::disjoint(); + } + + if (a1_on_b == 1) + { + dist_b1_a1 = 0; + dist_a1_b1 = 0; + } + else if (a1_on_b == 3) + { + dist_b1_a1 = dist_b1_b2; + dist_a1_b2 = 0; + } + + if (a2_on_b == 1) + { + dist_b1_a2 = 0; + dist_a1_b1 = dist_a1_a2; + } + else if (a2_on_b == 3) + { + dist_b1_a2 = dist_b1_b2; + dist_a1_b2 = dist_a1_a2; + } + + bool opposite = ! same_direction(res_a1_a2.azimuth, res_b1_b2.azimuth); + + // NOTE: If segment was reversed opposite, positions and segment ratios has to be altered + if (is_a_reversed) + { + // opposite + opposite = ! opposite; + // positions + std::swap(a1_on_b, a2_on_b); + b1_on_a = 4 - b1_on_a; + b2_on_a = 4 - b2_on_a; + // distances for ratios + std::swap(dist_b1_a1, dist_b1_a2); + dist_a1_b1 = dist_a1_a2 - dist_a1_b1; + dist_a1_b2 = dist_a1_a2 - dist_a1_b2; + } + if (is_b_reversed) + { + // opposite + opposite = ! opposite; + // positions + a1_on_b = 4 - a1_on_b; + a2_on_b = 4 - a2_on_b; + std::swap(b1_on_a, b2_on_a); + // distances for ratios + dist_b1_a1 = dist_b1_b2 - dist_b1_a1; + dist_b1_a2 = dist_b1_b2 - dist_b1_a2; + std::swap(dist_a1_b1, dist_a1_b2); + } + + segment_ratio<calc_t> ra_from(dist_b1_a1, dist_b1_b2); + segment_ratio<calc_t> ra_to(dist_b1_a2, dist_b1_b2); + segment_ratio<calc_t> rb_from(dist_a1_b1, dist_a1_a2); + segment_ratio<calc_t> rb_to(dist_a1_b2, dist_a1_a2); + + return Policy::segments_collinear(a, b, opposite, + a1_on_b, a2_on_b, b1_on_a, b2_on_a, + ra_from, ra_to, rb_from, rb_to); + } + } + else // crossing or touching + { + if (a_is_point || b_is_point) + { + return Policy::disjoint(); + } + + calc_t lon = 0, lat = 0; + intersection_point_flag ip_flag; + calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1; + if (calculate_ip_data(a1, a2, b1, b2, + a1_lon, a1_lat, a2_lon, a2_lat, + b1_lon, b1_lat, b2_lon, b2_lat, + res_a1_a2, res_a1_b1, res_a1_b2, + res_b1_b2, res_b1_a1, res_b1_a2, + sides, spheroid, + lon, lat, + dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1, + ip_flag)) + { + // NOTE: If segment was reversed sides and segment ratios has to be altered + if (is_a_reversed) + { + // sides + sides_reverse_segment<0>(sides); + // distance for ratio + dist_a1_i1 = dist_a1_a2 - dist_a1_i1; + // ip flag + ip_flag_reverse_segment(ip_flag, ipi_at_a1, ipi_at_a2); + } + if (is_b_reversed) + { + // sides + sides_reverse_segment<1>(sides); + // distance for ratio + dist_b1_i1 = dist_b1_b2 - dist_b1_i1; + // ip flag + ip_flag_reverse_segment(ip_flag, ipi_at_b1, ipi_at_b2); + } + + // intersects + segment_intersection_info + < + calc_t, + segment_ratio<calc_t> + > sinfo; + + sinfo.lon = lon; + sinfo.lat = lat; + sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2); + sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2); + sinfo.ip_flag = ip_flag; + + return Policy::segments_crosses(sides, sinfo, a, b); + } + else + { + return Policy::disjoint(); + } + } + } + + template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename ResultInverse> + static inline typename Policy::return_type + collinear_one_degenerated(Segment const& segment, bool degenerated_a, + Point1 const& a1, Point1 const& a2, + Point2 const& b1, Point2 const& b2, + ResultInverse const& res_a1_a2, + ResultInverse const& res_a1_bi, + bool is_other_reversed) + { + CalcT dist_1_2, dist_1_o; + if (! calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_bi, dist_1_2, dist_1_o)) + { + return Policy::disjoint(); + } + + // NOTE: If segment was reversed segment ratio has to be altered + if (is_other_reversed) + { + // distance for ratio + dist_1_o = dist_1_2 - dist_1_o; + } + + return Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a); + } + + // TODO: instead of checks below test bi against a1 and a2 here? + // in order to make this independent from is_near() + template <typename Point1, typename Point2, typename ResultInverse, typename CalcT> + static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in + Point2 const& b1, Point2 const& b2, // in + ResultInverse const& res_a1_a2, // in + ResultInverse const& res_a1_bi, // in + CalcT& dist_a1_a2, CalcT& dist_a1_bi) // out + { + dist_a1_a2 = res_a1_a2.distance; + + dist_a1_bi = res_a1_bi.distance; + if (! same_direction(res_a1_bi.azimuth, res_a1_a2.azimuth)) + { + dist_a1_bi = -dist_a1_bi; + } + + // if i1 is close to a1 and b1 or b2 is equal to a1 + if (is_endpoint_equal(dist_a1_bi, a1, b1, b2)) + { + dist_a1_bi = 0; + return true; + } + // or i1 is close to a2 and b1 or b2 is equal to a2 + else if (is_endpoint_equal(dist_a1_a2 - dist_a1_bi, a2, b1, b2)) + { + dist_a1_bi = dist_a1_a2; + return true; + } + + // or i1 is on b + return segment_ratio<CalcT>(dist_a1_bi, dist_a1_a2).on_segment(); + } + + template <typename Point1, typename Point2, typename CalcT, typename ResultInverse, typename Spheroid_> + static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in + Point2 const& b1, Point2 const& b2, // in + CalcT const& a1_lon, CalcT const& a1_lat, // in + CalcT const& a2_lon, CalcT const& a2_lat, // in + CalcT const& b1_lon, CalcT const& b1_lat, // in + CalcT const& b2_lon, CalcT const& b2_lat, // in + ResultInverse const& res_a1_a2, // in + ResultInverse const& res_a1_b1, // in + ResultInverse const& res_a1_b2, // in + ResultInverse const& res_b1_b2, // in + ResultInverse const& res_b1_a1, // in + ResultInverse const& res_b1_a2, // in + side_info const& sides, // in + Spheroid_ const& spheroid, // in + CalcT & lon, CalcT & lat, // out + CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out + CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out + intersection_point_flag& ip_flag) // out + { + dist_a1_a2 = res_a1_a2.distance; + dist_b1_b2 = res_b1_b2.distance; + + // assign the IP if some endpoints overlap + using geometry::detail::equals::equals_point_point; + if (equals_point_point(a1, b1)) + { + lon = a1_lon; + lat = a1_lat; + dist_a1_ip = 0; + dist_b1_ip = 0; + ip_flag = ipi_at_a1; + return true; + } + else if (equals_point_point(a1, b2)) + { + lon = a1_lon; + lat = a1_lat; + dist_a1_ip = 0; + dist_b1_ip = dist_b1_b2; + ip_flag = ipi_at_a1; + return true; + } + else if (equals_point_point(a2, b1)) + { + lon = a2_lon; + lat = a2_lat; + dist_a1_ip = dist_a1_a2; + dist_b1_ip = 0; + ip_flag = ipi_at_a2; + return true; + } + else if (equals_point_point(a2, b2)) + { + lon = a2_lon; + lat = a2_lat; + dist_a1_ip = dist_a1_a2; + dist_b1_ip = dist_b1_b2; + ip_flag = ipi_at_a2; + return true; + } + + // at this point we know that the endpoints doesn't overlap + // check cases when an endpoint lies on the other geodesic + if (sides.template get<0, 0>() == 0) // a1 wrt b + { + if (res_b1_a1.distance <= res_b1_b2.distance + && same_direction(res_b1_a1.azimuth, res_b1_b2.azimuth)) + { + lon = a1_lon; + lat = a1_lat; + dist_a1_ip = 0; + dist_b1_ip = res_b1_a1.distance; + ip_flag = ipi_at_a1; + return true; + } + else + { + return false; + } + } + else if (sides.template get<0, 1>() == 0) // a2 wrt b + { + if (res_b1_a2.distance <= res_b1_b2.distance + && same_direction(res_b1_a2.azimuth, res_b1_b2.azimuth)) + { + lon = a2_lon; + lat = a2_lat; + dist_a1_ip = res_a1_a2.distance; + dist_b1_ip = res_b1_a2.distance; + ip_flag = ipi_at_a2; + return true; + } + else + { + return false; + } + } + else if (sides.template get<1, 0>() == 0) // b1 wrt a + { + if (res_a1_b1.distance <= res_a1_a2.distance + && same_direction(res_a1_b1.azimuth, res_a1_a2.azimuth)) + { + lon = b1_lon; + lat = b1_lat; + dist_a1_ip = res_a1_b1.distance; + dist_b1_ip = 0; + ip_flag = ipi_at_b1; + return true; + } + else + { + return false; + } + } + else if (sides.template get<1, 1>() == 0) // b2 wrt a + { + if (res_a1_b2.distance <= res_a1_a2.distance + && same_direction(res_a1_b2.azimuth, res_a1_a2.azimuth)) + { + lon = b2_lon; + lat = b2_lat; + dist_a1_ip = res_a1_b2.distance; + dist_b1_ip = res_b1_b2.distance; + ip_flag = ipi_at_b2; + return true; + } + else + { + return false; + } + } + + // At this point neither the endpoints overlaps + // nor any andpoint lies on the other geodesic + // So the endpoints should lie on the opposite sides of both geodesics + + bool const ok = formula::sjoberg_intersection<CalcT, FormulaPolicy::template inverse, Order> + ::apply(a1_lon, a1_lat, a2_lon, a2_lat, res_a1_a2.azimuth, + b1_lon, b1_lat, b2_lon, b2_lat, res_b1_b2.azimuth, + lon, lat, spheroid); + + if (! ok) + { + return false; + } + + typedef typename FormulaPolicy::template inverse<CalcT, true, true, false, false, false> inverse_dist_azi; + typedef typename inverse_dist_azi::result_type inverse_result; + + inverse_result const res_a1_ip = inverse_dist_azi::apply(a1_lon, a1_lat, lon, lat, spheroid); + dist_a1_ip = res_a1_ip.distance; + if (! same_direction(res_a1_ip.azimuth, res_a1_a2.azimuth)) + { + dist_a1_ip = -dist_a1_ip; + } + + bool is_on_a = segment_ratio<CalcT>(dist_a1_ip, dist_a1_a2).on_segment(); + // NOTE: not fully consistent with equals_point_point() since radians are always used. + bool is_on_a1 = math::equals(lon, a1_lon) && math::equals(lat, a1_lat); + bool is_on_a2 = math::equals(lon, a2_lon) && math::equals(lat, a2_lat); + + if (! (is_on_a || is_on_a1 || is_on_a2)) + { + return false; + } + + inverse_result const res_b1_ip = inverse_dist_azi::apply(b1_lon, b1_lat, lon, lat, spheroid); + dist_b1_ip = res_b1_ip.distance; + if (! same_direction(res_b1_ip.azimuth, res_b1_b2.azimuth)) + { + dist_b1_ip = -dist_b1_ip; + } + + bool is_on_b = segment_ratio<CalcT>(dist_b1_ip, dist_b1_b2).on_segment(); + // NOTE: not fully consistent with equals_point_point() since radians are always used. + bool is_on_b1 = math::equals(lon, b1_lon) && math::equals(lat, b1_lat); + bool is_on_b2 = math::equals(lon, b2_lon) && math::equals(lat, b2_lat); + + if (! (is_on_b || is_on_b1 || is_on_b2)) + { + return false; + } + + ip_flag = ipi_inters; + + if (is_on_b1) + { + lon = b1_lon; + lat = b1_lat; + dist_b1_ip = 0; + ip_flag = ipi_at_b1; + } + else if (is_on_b2) + { + lon = b2_lon; + lat = b2_lat; + dist_b1_ip = res_b1_b2.distance; + ip_flag = ipi_at_b2; + } + + if (is_on_a1) + { + lon = a1_lon; + lat = a1_lat; + dist_a1_ip = 0; + ip_flag = ipi_at_a1; + } + else if (is_on_a2) + { + lon = a2_lon; + lat = a2_lat; + dist_a1_ip = res_a1_a2.distance; + ip_flag = ipi_at_a2; + } + + return true; + } + + template <typename CalcT, typename P1, typename P2> + static inline bool is_endpoint_equal(CalcT const& dist, + P1 const& ai, P2 const& b1, P2 const& b2) + { + using geometry::detail::equals::equals_point_point; + return is_near(dist) && (equals_point_point(ai, b1) || equals_point_point(ai, b2)); + } + + template <typename CalcT> + static inline bool is_near(CalcT const& dist) + { + // NOTE: This strongly depends on the Inverse method + CalcT const small_number = CalcT(boost::is_same<CalcT, float>::value ? 0.0001 : 0.00000001); + return math::abs(dist) <= small_number; + } + + template <typename ProjCoord1, typename ProjCoord2> + static inline int position_value(ProjCoord1 const& ca1, + ProjCoord2 const& cb1, + ProjCoord2 const& cb2) + { + // S1x 0 1 2 3 4 + // S2 |----------> + return math::equals(ca1, cb1) ? 1 + : math::equals(ca1, cb2) ? 3 + : cb1 < cb2 ? + ( ca1 < cb1 ? 0 + : ca1 > cb2 ? 4 + : 2 ) + : ( ca1 > cb1 ? 0 + : ca1 < cb2 ? 4 + : 2 ); + } + + template <typename CalcT> + static inline bool same_direction(CalcT const& azimuth1, CalcT const& azimuth2) + { + // distance between two angles normalized to (-180, 180] + CalcT const angle_diff = math::longitude_distance_signed<radian>(azimuth1, azimuth2); + return math::abs(angle_diff) <= math::half_pi<CalcT>(); + } + + template <int Which> + static inline void sides_reverse_segment(side_info & sides) + { + // names assuming segment A is reversed (Which == 0) + int a1_wrt_b = sides.template get<Which, 0>(); + int a2_wrt_b = sides.template get<Which, 1>(); + std::swap(a1_wrt_b, a2_wrt_b); + sides.template set<Which>(a1_wrt_b, a2_wrt_b); + int b1_wrt_a = sides.template get<1 - Which, 0>(); + int b2_wrt_a = sides.template get<1 - Which, 1>(); + sides.template set<1 - Which>(-b1_wrt_a, -b2_wrt_a); + } + + static inline void ip_flag_reverse_segment(intersection_point_flag & ip_flag, + intersection_point_flag const& ipi_at_p1, + intersection_point_flag const& ipi_at_p2) + { + ip_flag = ip_flag == ipi_at_p1 ? ipi_at_p2 : + ip_flag == ipi_at_p2 ? ipi_at_p1 : + ip_flag; + } + + template <typename CalcT, typename SpheroidT> + static inline srs::spheroid<CalcT> normalized_spheroid(SpheroidT const& spheroid) + { + return srs::spheroid<CalcT>(CalcT(1), + CalcT(get_radius<2>(spheroid)) // b/a + / CalcT(get_radius<0>(spheroid))); + } + +private: + Spheroid m_spheroid; +}; + + +}} // namespace strategy::intersection + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP diff --git a/boost/geometry/strategies/geographic/intersection_elliptic.hpp b/boost/geometry/strategies/geographic/intersection_elliptic.hpp new file mode 100644 index 0000000000..76e9940fe3 --- /dev/null +++ b/boost/geometry/strategies/geographic/intersection_elliptic.hpp @@ -0,0 +1,243 @@ +// Boost.Geometry + +// 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, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP + + +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/formulas/geographic.hpp> + +#include <boost/geometry/strategies/spherical/intersection.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace intersection +{ + +template <typename Spheroid> +struct great_elliptic_segments_calc_policy + : spherical_segments_calc_policy +{ + explicit great_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid()) + : m_spheroid(spheroid) + {} + + template <typename Point, typename Point3d> + Point from_cart3d(Point3d const& point_3d) const + { + return formula::cart3d_to_geo<Point>(point_3d, m_spheroid); + } + + template <typename Point3d, typename Point> + Point3d to_cart3d(Point const& point) const + { + return formula::geo_to_cart3d<Point3d>(point, m_spheroid); + } + + // relate_xxx_calc_policy must live londer than plane because it contains + // Spheroid object and plane keeps the reference to that object. + template <typename Point3d> + struct plane + { + typedef typename coordinate_type<Point3d>::type coord_t; + + // not normalized + plane(Point3d const& p1, Point3d const& p2) + : normal(cross_product(p1, p2)) + {} + + int side_value(Point3d const& pt) const + { + return formula::sph_side_value(normal, pt); + } + + coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const + { + Point3d v1 = p1; + detail::vec_normalize(v1); + Point3d v2 = p2; + detail::vec_normalize(v2); + + return dot_product(v1, v2); + } + + coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const + { + coord_t const c0 = 0; + + Point3d v1 = p1; + detail::vec_normalize(v1); + Point3d v2 = p2; + detail::vec_normalize(v2); + + is_forward = dot_product(normal, cross_product(v1, v2)) >= c0; + return dot_product(v1, v2); + } + + Point3d normal; + }; + + template <typename Point3d> + plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const + { + return plane<Point3d>(p1, p2); + } + + template <typename Point3d> + bool intersection_points(plane<Point3d> const& plane1, + plane<Point3d> const& plane2, + Point3d & ip1, Point3d & ip2) const + { + typedef typename coordinate_type<Point3d>::type coord_t; + + Point3d id = cross_product(plane1.normal, plane2.normal); + // NOTE: the length should be greater than 0 at this point + // NOTE: no need to normalize in this case + + ip1 = formula::projected_to_surface(id, m_spheroid); + + ip2 = ip1; + multiply_value(ip2, coord_t(-1)); + + return true; + } + +private: + Spheroid m_spheroid; +}; + +template <typename Spheroid> +struct experimental_elliptic_segments_calc_policy +{ + explicit experimental_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid()) + : m_spheroid(spheroid) + {} + + template <typename Point, typename Point3d> + Point from_cart3d(Point3d const& point_3d) const + { + return formula::cart3d_to_geo<Point>(point_3d, m_spheroid); + } + + template <typename Point3d, typename Point> + Point3d to_cart3d(Point const& point) const + { + return formula::geo_to_cart3d<Point3d>(point, m_spheroid); + } + + // relate_xxx_calc_policy must live londer than plane because it contains + // Spheroid object and plane keeps the reference to that object. + template <typename Point3d> + struct plane + { + typedef typename coordinate_type<Point3d>::type coord_t; + + // not normalized + plane(Point3d const& p1, Point3d const& p2, Spheroid const& spheroid) + : m_spheroid(spheroid) + { + formula::experimental_elliptic_plane(p1, p2, origin, normal, m_spheroid); + } + + int side_value(Point3d const& pt) const + { + return formula::elliptic_side_value(origin, normal, pt); + } + + coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const + { + Point3d const v1 = normalized_vec(p1); + Point3d const v2 = normalized_vec(p2); + return dot_product(v1, v2); + } + + coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const + { + coord_t const c0 = 0; + + Point3d const v1 = normalized_vec(p1); + Point3d const v2 = normalized_vec(p2); + + is_forward = dot_product(normal, cross_product(v1, v2)) >= c0; + return dot_product(v1, v2); + } + + Point3d origin; + Point3d normal; + + private: + Point3d normalized_vec(Point3d const& p) const + { + Point3d v = p; + subtract_point(v, origin); + detail::vec_normalize(v); + return v; + } + + Spheroid const& m_spheroid; + }; + + template <typename Point3d> + plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const + { + return plane<Point3d>(p1, p2, m_spheroid); + } + + template <typename Point3d> + bool intersection_points(plane<Point3d> const& plane1, + plane<Point3d> const& plane2, + Point3d & ip1, Point3d & ip2) const + { + return formula::planes_spheroid_intersection(plane1.origin, plane1.normal, + plane2.origin, plane2.normal, + ip1, ip2, m_spheroid); + } + +private: + Spheroid m_spheroid; +}; + + +template +< + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +struct great_elliptic_segments + : ecef_segments + < + great_elliptic_segments_calc_policy<Spheroid>, + CalculationType + > +{}; + +template +< + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +struct experimental_elliptic_segments + : ecef_segments + < + experimental_elliptic_segments_calc_policy<Spheroid>, + CalculationType + > +{}; + + +}} // namespace strategy::intersection + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP diff --git a/boost/geometry/strategies/geographic/mapping_ssf.hpp b/boost/geometry/strategies/geographic/mapping_ssf.hpp index 3beedc7809..20a0523616 100644 --- a/boost/geometry/strategies/geographic/mapping_ssf.hpp +++ b/boost/geometry/strategies/geographic/mapping_ssf.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// 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 @@ -136,7 +136,7 @@ public : {} template <typename P1, typename P2, typename P> - inline int apply(P1 const& p1, P2 const& p2, P const& p) + inline int apply(P1 const& p1, P2 const& p2, P const& p) const { typedef typename promote_floating_point < diff --git a/boost/geometry/strategies/geographic/parameters.hpp b/boost/geometry/strategies/geographic/parameters.hpp new file mode 100644 index 0000000000..5638db50fa --- /dev/null +++ b/boost/geometry/strategies/geographic/parameters.hpp @@ -0,0 +1,117 @@ +// Boost.Geometry + +// 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) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP + + +#include <boost/geometry/formulas/andoyer_inverse.hpp> +#include <boost/geometry/formulas/thomas_inverse.hpp> +#include <boost/geometry/formulas/vincenty_inverse.hpp> + +#include <boost/mpl/assert.hpp> +#include <boost/mpl/integral_c.hpp> + + +namespace boost { namespace geometry { namespace strategy +{ + +struct andoyer +{ + template + < + typename CT, + bool EnableDistance, + bool EnableAzimuth, + bool EnableReverseAzimuth = false, + bool EnableReducedLength = false, + bool EnableGeodesicScale = false + > + struct inverse + : formula::andoyer_inverse + < + CT, EnableDistance, + EnableAzimuth, EnableReverseAzimuth, + EnableReducedLength, EnableGeodesicScale + > + {}; +}; + +struct thomas +{ + template + < + typename CT, + bool EnableDistance, + bool EnableAzimuth, + bool EnableReverseAzimuth = false, + bool EnableReducedLength = false, + bool EnableGeodesicScale = false + > + struct inverse + : formula::thomas_inverse + < + CT, EnableDistance, + EnableAzimuth, EnableReverseAzimuth, + EnableReducedLength, EnableGeodesicScale + > + {}; +}; + +struct vincenty +{ + template + < + typename CT, + bool EnableDistance, + bool EnableAzimuth, + bool EnableReverseAzimuth = false, + bool EnableReducedLength = false, + bool EnableGeodesicScale = false + > + struct inverse + : formula::vincenty_inverse + < + CT, EnableDistance, + EnableAzimuth, EnableReverseAzimuth, + EnableReducedLength, EnableGeodesicScale + > + {}; +}; + + +template <typename FormulaPolicy> +struct default_order +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types<FormulaPolicy>) + ); +}; + +template<> +struct default_order<andoyer> + : boost::mpl::integral_c<unsigned int, 1> +{}; + +template<> +struct default_order<thomas> + : boost::mpl::integral_c<unsigned int, 2> +{}; + +template<> +struct default_order<vincenty> + : boost::mpl::integral_c<unsigned int, 4> +{}; + +}}} // namespace boost::geometry::strategy + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP diff --git a/boost/geometry/strategies/geographic/side.hpp b/boost/geometry/strategies/geographic/side.hpp new file mode 100644 index 0000000000..0d40e4da20 --- /dev/null +++ b/boost/geometry/strategies/geographic/side.hpp @@ -0,0 +1,113 @@ +// Boost.Geometry + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// 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 + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> + +#include <boost/geometry/formulas/spherical.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> +#include <boost/geometry/util/select_calculation_type.hpp> + +#include <boost/geometry/strategies/geographic/parameters.hpp> +#include <boost/geometry/strategies/side.hpp> +//#include <boost/geometry/strategies/concepts/side_concept.hpp> + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace side +{ + + +/*! +\brief Check at which side of a segment a point lies + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam FormulaPolicy Geodesic solution formula policy. +\tparam Spheroid Reference model of coordinate system. +\tparam CalculationType \tparam_calculation + */ +template +< + typename FormulaPolicy = strategy::andoyer, + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> +class geographic +{ +public: + geographic() + {} + + explicit geographic(Spheroid const& model) + : m_model(model) + {} + + template <typename P1, typename P2, typename P> + inline int apply(P1 const& p1, P2 const& p2, P const& p) const + { + typedef typename promote_floating_point + < + typename select_calculation_type_alt + < + CalculationType, + P1, P2, P + >::type + >::type calc_t; + + typedef typename FormulaPolicy::template inverse + <calc_t, false, true, false, false, false> inverse_formula; + + calc_t a1p = azimuth<calc_t, inverse_formula>(p1, p, m_model); + calc_t a12 = azimuth<calc_t, inverse_formula>(p1, p2, m_model); + + return formula::azimuth_side_value(a1p, a12); + } + +private: + template <typename ResultType, + typename InverseFormulaType, + typename Point1, + typename Point2, + typename ModelT> + static inline ResultType azimuth(Point1 const& point1, Point2 const& point2, + ModelT const& model) + { + return InverseFormulaType::apply(get_as_radian<0>(point1), + get_as_radian<1>(point1), + get_as_radian<0>(point2), + get_as_radian<1>(point2), + model).azimuth; + } + + Spheroid m_model; +}; + + +}} // namespace strategy::side + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP diff --git a/boost/geometry/strategies/geographic/side_andoyer.hpp b/boost/geometry/strategies/geographic/side_andoyer.hpp index c3e71cd1cd..204e45f6e2 100644 --- a/boost/geometry/strategies/geographic/side_andoyer.hpp +++ b/boost/geometry/strategies/geographic/side_andoyer.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// 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-2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,9 +15,7 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_ANDOYER_HPP -#include <boost/geometry/formulas/andoyer_inverse.hpp> - -#include <boost/geometry/strategies/geographic/side_detail.hpp> +#include <boost/geometry/strategies/geographic/side.hpp> namespace boost { namespace geometry @@ -31,17 +29,24 @@ namespace strategy { namespace side \brief Check at which side of a segment a point lies left of segment (> 0), right of segment (< 0), on segment (0) \ingroup strategies -\tparam Model Reference model of coordinate system. +\tparam Spheroid Reference model of coordinate system. \tparam CalculationType \tparam_calculation */ -template <typename Model, typename CalculationType = void> +template +< + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> class andoyer - : public detail::by_azimuth<geometry::formula::andoyer_inverse, Model, CalculationType> + : public side::geographic<strategy::andoyer, Spheroid, CalculationType> { - typedef detail::by_azimuth<geometry::formula::andoyer_inverse, Model, CalculationType> base_t; + typedef side::geographic<strategy::andoyer, Spheroid, CalculationType> base_t; public: - andoyer(Model const& model = Model()) + andoyer() + {} + + explicit andoyer(Spheroid const& model) : base_t(model) {} }; diff --git a/boost/geometry/strategies/geographic/side_detail.hpp b/boost/geometry/strategies/geographic/side_detail.hpp deleted file mode 100644 index ce1b47c88e..0000000000 --- a/boost/geometry/strategies/geographic/side_detail.hpp +++ /dev/null @@ -1,139 +0,0 @@ -// Boost.Geometry - -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. - -// This file was modified by Oracle on 2014, 2015, 2016. -// Modifications copyright (c) 2014-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_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP -#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP - -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/radian_access.hpp> -#include <boost/geometry/core/radius.hpp> - -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/promote_floating_point.hpp> -#include <boost/geometry/util/select_calculation_type.hpp> - -#include <boost/geometry/strategies/side.hpp> -//#include <boost/geometry/strategies/concepts/side_concept.hpp> - - -namespace boost { namespace geometry -{ - - -namespace strategy { namespace side -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail -{ - -/*! -\brief Check at which side of a segment a point lies - left of segment (> 0), right of segment (< 0), on segment (0) -\ingroup strategies -\tparam InverseFormula Geodesic inverse solution formula. -\tparam Model Reference model of coordinate system. -\tparam CalculationType \tparam_calculation - */ -template <template<typename, bool, bool, bool, bool, bool> class InverseFormula, - typename Model, - typename CalculationType = void> -class by_azimuth -{ -public: - by_azimuth(Model const& model = Model()) - : m_model(model) - {} - - template <typename P1, typename P2, typename P> - inline int apply(P1 const& p1, P2 const& p2, P const& p) - { - typedef typename promote_floating_point - < - typename select_calculation_type_alt - < - CalculationType, - P1, P2, P - >::type - >::type calc_t; - - typedef InverseFormula<calc_t, false, true, false, false, false> inverse_formula; - - calc_t a1p = azimuth<calc_t, inverse_formula>(p1, p, m_model); - calc_t a12 = azimuth<calc_t, inverse_formula>(p1, p2, m_model); - - calc_t const pi = math::pi<calc_t>(); - - // instead of the formula from XTD - //calc_t a_diff = asin(sin(a1p - a12)); - - calc_t a_diff = a1p - a12; - // normalize, angle in [-pi, pi] - while ( a_diff > pi ) - a_diff -= calc_t(2) * pi; - while ( a_diff < -pi ) - a_diff += calc_t(2) * 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 - } - -private: - template <typename ResultType, - typename InverseFormulaType, - typename Point1, - typename Point2, - typename ModelT> - static inline ResultType azimuth(Point1 const& point1, Point2 const& point2, ModelT const& model) - { - return InverseFormulaType::apply(get_as_radian<0>(point1), - get_as_radian<1>(point1), - get_as_radian<0>(point2), - get_as_radian<1>(point2), - model).azimuth; - } - - Model m_model; -}; - -} // detail -#endif // DOXYGEN_NO_DETAIL - -}} // namespace strategy::side - - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP diff --git a/boost/geometry/strategies/geographic/side_thomas.hpp b/boost/geometry/strategies/geographic/side_thomas.hpp index 96b0323307..e6f8d77b58 100644 --- a/boost/geometry/strategies/geographic/side_thomas.hpp +++ b/boost/geometry/strategies/geographic/side_thomas.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// 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-2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,9 +15,7 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_THOMAS_HPP -#include <boost/geometry/formulas/thomas_inverse.hpp> - -#include <boost/geometry/strategies/geographic/side_detail.hpp> +#include <boost/geometry/strategies/geographic/side.hpp> namespace boost { namespace geometry @@ -31,17 +29,24 @@ namespace strategy { namespace side \brief Check at which side of a segment a point lies left of segment (> 0), right of segment (< 0), on segment (0) \ingroup strategies -\tparam Model Reference model of coordinate system. +\tparam Spheroid Reference model of coordinate system. \tparam CalculationType \tparam_calculation */ -template <typename Model, typename CalculationType = void> +template +< + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> class thomas - : public detail::by_azimuth<geometry::formula::thomas_inverse, Model, CalculationType> + : public side::geographic<strategy::thomas, Spheroid, CalculationType> { - typedef detail::by_azimuth<geometry::formula::thomas_inverse, Model, CalculationType> base_t; + typedef side::geographic<strategy::thomas, Spheroid, CalculationType> base_t; public: - thomas(Model const& model = Model()) + thomas() + {} + + explicit thomas(Spheroid const& model) : base_t(model) {} }; diff --git a/boost/geometry/strategies/geographic/side_vincenty.hpp b/boost/geometry/strategies/geographic/side_vincenty.hpp index 103277a8bd..b2f51b0901 100644 --- a/boost/geometry/strategies/geographic/side_vincenty.hpp +++ b/boost/geometry/strategies/geographic/side_vincenty.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// 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-2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,9 +15,7 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_VINCENTY_HPP -#include <boost/geometry/formulas/vincenty_inverse.hpp> - -#include <boost/geometry/strategies/geographic/side_detail.hpp> +#include <boost/geometry/strategies/geographic/side.hpp> namespace boost { namespace geometry @@ -31,17 +29,24 @@ namespace strategy { namespace side \brief Check at which side of a segment a point lies left of segment (> 0), right of segment (< 0), on segment (0) \ingroup strategies -\tparam Model Reference model of coordinate system. +\tparam Spheroid Reference model of coordinate system. \tparam CalculationType \tparam_calculation */ -template <typename Model, typename CalculationType = void> +template +< + typename Spheroid = srs::spheroid<double>, + typename CalculationType = void +> class vincenty - : public detail::by_azimuth<geometry::formula::vincenty_inverse, Model, CalculationType> + : public side::geographic<strategy::vincenty, Spheroid, CalculationType> { - typedef detail::by_azimuth<geometry::formula::vincenty_inverse, Model, CalculationType> base_t; + typedef side::geographic<strategy::vincenty, Spheroid, CalculationType> base_t; public: - vincenty(Model const& model = Model()) + vincenty() + {} + + explicit vincenty(Spheroid const& model) : base_t(model) {} }; diff --git a/boost/geometry/strategies/intersection.hpp b/boost/geometry/strategies/intersection.hpp index f51c5cb206..e5662c9e46 100644 --- a/boost/geometry/strategies/intersection.hpp +++ b/boost/geometry/strategies/intersection.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 // Use, modification and distribution is subject to the Boost Software License, @@ -30,10 +30,9 @@ namespace services \brief Traits class binding a segments intersection strategy to a coordinate system \ingroup util \tparam CSTag tag of coordinate system of point-type -\tparam Policy intersection policy \tparam CalculationType \tparam_calculation */ -template <typename CSTag, typename Policy, typename CalculationType = void> +template <typename CSTag, typename CalculationType = void> struct default_strategy { BOOST_MPL_ASSERT_MSG diff --git a/boost/geometry/strategies/intersection_strategies.hpp b/boost/geometry/strategies/intersection_strategies.hpp index 0452c4692c..a173505804 100644 --- a/boost/geometry/strategies/intersection_strategies.hpp +++ b/boost/geometry/strategies/intersection_strategies.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 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, @@ -22,10 +22,10 @@ #include <boost/geometry/policies/relate/tupled.hpp> #include <boost/geometry/strategies/intersection.hpp> -#include <boost/geometry/strategies/side.hpp> #include <boost/geometry/strategies/intersection_result.hpp> +#include <boost/geometry/strategies/side.hpp> -#include <boost/geometry/strategies/cartesian/cart_intersect.hpp> +#include <boost/geometry/strategies/cartesian/intersection.hpp> #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> #include <boost/geometry/strategies/spherical/intersection.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> @@ -70,17 +70,18 @@ private : > ip_type; public: + typedef policies::relate::segments_tupled + < + policies::relate::segments_intersection_points + < + ip_type + > , + policies::relate::segments_direction + > intersection_policy_type; + typedef typename strategy::intersection::services::default_strategy < Tag, - policies::relate::segments_tupled - < - policies::relate::segments_intersection_points - < - ip_type - > , - policies::relate::segments_direction - >, CalculationType >::type segment_intersection_strategy_type; diff --git a/boost/geometry/strategies/relate.hpp b/boost/geometry/strategies/relate.hpp new file mode 100644 index 0000000000..ffeed78959 --- /dev/null +++ b/boost/geometry/strategies/relate.hpp @@ -0,0 +1,177 @@ +// Boost.Geometry + +// 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) + +#ifndef BOOST_GEOMETRY_STRATEGIES_RELATE_HPP +#define BOOST_GEOMETRY_STRATEGIES_RELATE_HPP + + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/topological_dimension.hpp> + +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/intersection.hpp> +#include <boost/geometry/strategies/within.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy +{ + +namespace point_in_geometry +{ + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template +< + typename Point, + typename Geometry, + typename Tag1 = typename tag<Point>::type, + typename Tag2 = typename tag<Geometry>::type +> +struct default_strategy + : strategy::within::services::default_strategy + < + Point, + Geometry + > +{ + typedef typename default_strategy::type within_strategy_type; + + typedef typename strategy::covered_by::services::default_strategy + < + Point, + Geometry + >::type covered_by_strategy_type; + + static const bool same_strategies = boost::is_same<within_strategy_type, covered_by_strategy_type>::value; + BOOST_MPL_ASSERT_MSG((same_strategies), + DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, + (within_strategy_type, covered_by_strategy_type)); +}; + +template<typename Point, typename Geometry> +struct default_strategy<Point, Geometry, point_tag, point_tag> + : strategy::within::services::default_strategy<Point, Geometry> +{}; + +template<typename Point, typename Geometry> +struct default_strategy<Point, Geometry, point_tag, multi_point_tag> + : strategy::within::services::default_strategy<Point, Geometry> +{}; + + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +} // namespace point_in_geometry + +namespace relate +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename Geometry> +struct default_intersection_strategy + : strategy::intersection::services::default_strategy + < + typename cs_tag<Geometry>::type + > +{}; + +template <typename PointLike, typename Geometry> +struct default_point_in_geometry_strategy + : point_in_geometry::services::default_strategy + < + typename point_type<PointLike>::type, + Geometry + > +{}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + +template +< + typename Geometry1, + typename Geometry2, + int TopDim1 = geometry::topological_dimension<Geometry1>::value, + int TopDim2 = geometry::topological_dimension<Geometry2>::value +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THESE_TYPES + , (types<Geometry1, Geometry2>) + ); +}; + +template <typename PointLike1, typename PointLike2> +struct default_strategy<PointLike1, PointLike2, 0, 0> + : detail::default_point_in_geometry_strategy<PointLike1, PointLike2> +{}; + +template <typename PointLike, typename Geometry, int TopDim2> +struct default_strategy<PointLike, Geometry, 0, TopDim2> + : detail::default_point_in_geometry_strategy<PointLike, Geometry> +{}; + +template <typename Geometry, typename PointLike, int TopDim1> +struct default_strategy<Geometry, PointLike, TopDim1, 0> + : detail::default_point_in_geometry_strategy<PointLike, Geometry> +{}; + +template <typename Geometry1, typename Geometry2> +struct default_strategy<Geometry1, Geometry2, 1, 1> + : detail::default_intersection_strategy<Geometry1> +{}; + +template <typename Geometry1, typename Geometry2> +struct default_strategy<Geometry1, Geometry2, 1, 2> + : detail::default_intersection_strategy<Geometry1> +{}; + +template <typename Geometry1, typename Geometry2> +struct default_strategy<Geometry1, Geometry2, 2, 1> + : detail::default_intersection_strategy<Geometry1> +{}; + +template <typename Geometry1, typename Geometry2> +struct default_strategy<Geometry1, Geometry2, 2, 2> + : detail::default_intersection_strategy<Geometry1> +{}; + +} // namespace services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +} // namespace relate + +} // namespace strategy + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_RELATE_HPP diff --git a/boost/geometry/strategies/side.hpp b/boost/geometry/strategies/side.hpp index 376f2fdf1b..9aaa2bdddc 100644 --- a/boost/geometry/strategies/side.hpp +++ b/boost/geometry/strategies/side.hpp @@ -30,16 +30,16 @@ namespace services /*! \brief Traits class binding a side determination strategy to a coordinate system \ingroup util -\tparam Tag tag of coordinate system of point-type +\tparam CSTag tag of coordinate system of point-type \tparam CalculationType \tparam_calculation */ -template <typename Tag, typename CalculationType = void> +template <typename CSTag, typename CalculationType = void> struct default_strategy { BOOST_MPL_ASSERT_MSG ( false, NOT_IMPLEMENTED_FOR_THIS_TYPE - , (types<Tag>) + , (types<CSTag>) ); }; diff --git a/boost/geometry/strategies/spherical/area.hpp b/boost/geometry/strategies/spherical/area.hpp new file mode 100644 index 0000000000..206b734548 --- /dev/null +++ b/boost/geometry/strategies/spherical/area.hpp @@ -0,0 +1,182 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP + + +#include <boost/geometry/formulas/area_formulas.hpp> +#include <boost/geometry/core/radius.hpp> +#include <boost/geometry/core/srs.hpp> +#include <boost/geometry/strategies/area.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + +/*! +\brief Spherical area calculation +\ingroup strategies +\details Calculates area on the surface of a sphere using the trapezoidal rule +\tparam PointOfSegment \tparam_segment_point +\tparam CalculationType \tparam_calculation + +\qbk{ +[heading See also] +[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] +} +*/ +template +< + typename PointOfSegment, + typename CalculationType = void +> +class spherical +{ + // Enables special handling of long segments + static const bool LongSegment = false; + +typedef typename boost::mpl::if_c + < + boost::is_void<CalculationType>::type::value, + typename select_most_precise + < + typename coordinate_type<PointOfSegment>::type, + double + >::type, + CalculationType + >::type CT; + +protected : + struct excess_sum + { + CT m_sum; + + // Keep track if encircles some pole + size_t m_crosses_prime_meridian; + + inline excess_sum() + : m_sum(0) + , m_crosses_prime_meridian(0) + {} + template <typename SphereType> + inline CT area(SphereType sphere) const + { + CT result; + CT radius = geometry::get_radius<0>(sphere); + + // Encircles pole + if(m_crosses_prime_meridian % 2 == 1) + { + size_t times_crosses_prime_meridian + = 1 + (m_crosses_prime_meridian / 2); + + result = CT(2) + * geometry::math::pi<CT>() + * times_crosses_prime_meridian + - geometry::math::abs(m_sum); + + if(geometry::math::sign<CT>(m_sum) == 1) + { + result = - result; + } + + } else { + result = m_sum; + } + + result *= radius * radius; + + return result; + } + }; + +public : + typedef CT return_type; + typedef PointOfSegment segment_point_type; + typedef excess_sum state_type; + typedef geometry::srs::sphere<CT> sphere_type; + + // For backward compatibility reasons the radius is set to 1 + inline spherical() + : m_sphere(1.0) + {} + + template <typename T> + explicit inline spherical(geometry::srs::sphere<T> const& sphere) + : m_sphere(geometry::get_radius<0>(sphere)) + {} + + explicit inline spherical(CT const& radius) + : m_sphere(radius) + {} + + inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + excess_sum& state) const + { + if (! geometry::math::equals(get<0>(p1), get<0>(p2))) + { + + state.m_sum += geometry::formula::area_formulas + <CT>::template spherical<LongSegment>(p1, p2); + + // Keep track whenever a segment crosses the prime meridian + geometry::formula::area_formulas + <CT>::crosses_prime_meridian(p1, p2, state); + + } + } + + inline return_type result(excess_sum const& state) const + { + return state.area(m_sphere); + } + +private : + /// srs Sphere + sphere_type m_sphere; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template <typename Point> +struct default_strategy<spherical_equatorial_tag, Point> +{ + typedef strategy::area::spherical<Point> type; +}; + +// Note: spherical polar coordinate system requires "get_as_radian_equatorial" +template <typename Point> +struct default_strategy<spherical_polar_tag, Point> +{ + typedef strategy::area::spherical<Point> type; +}; + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::area + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP diff --git a/boost/geometry/strategies/spherical/area_huiller.hpp b/boost/geometry/strategies/spherical/area_huiller.hpp deleted file mode 100644 index 37d8d20124..0000000000 --- a/boost/geometry/strategies/spherical/area_huiller.hpp +++ /dev/null @@ -1,214 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// 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. - -// 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 -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP -#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP - - - -#include <boost/geometry/strategies/spherical/distance_haversine.hpp> - -#include <boost/geometry/core/radian_access.hpp> -#include <boost/geometry/util/math.hpp> - - -namespace boost { namespace geometry -{ - -namespace strategy { namespace area -{ - - - -/*! -\brief Area calculation by spherical excess / Huiller's formula -\ingroup strategies -\tparam PointOfSegment point type of segments of rings/polygons -\tparam CalculationType \tparam_calculation -\author Barend Gehrels. Adapted from: -- http://webdocs.cs.ualberta.ca/~graphics/books/GraphicsGems/gemsiv/sph_poly.c -- http://tog.acm.org/resources/GraphicsGems/gemsiv/sph_poly.c -- http://williams.best.vwh.net/avform.htm -\note The version in Graphics Gems IV (page 132-137) didn't account for -polygons crossing the 0 and 180 meridians. The fix for this algorithm -can be found in Graphics Gems V (pages 45-46). See: -- http://kysmykseka.net/koti/wizardry/Game%20Development/Programming/Graphics%20Gems%204.pdf -- http://kysmykseka.net/koti/wizardry/Game%20Development/Programming/Graphics%20Gems%205.pdf -\note This version works for convex and non-convex polygons, for 180 meridian -crossing polygons and for polygons with holes. However, some cases (especially -180 meridian cases) must still be checked. -\note The version which sums angles, which is often seen, doesn't handle non-convex -polygons correctly. -\note The version which sums longitudes, see http://hdl.handle.net/2014/40409, -is simple and works well in most cases but not in 180 meridian crossing cases. -This probably could be solved. - -\note This version is made for spherical equatorial coordinate systems - -\qbk{ - -[heading Example] -[area_with_strategy] -[area_with_strategy_output] - - -[heading See also] -[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] -} - -*/ -template -< - typename PointOfSegment, - typename CalculationType = void -> -class huiller -{ -typedef typename boost::mpl::if_c - < - boost::is_void<CalculationType>::type::value, - typename select_most_precise - < - typename coordinate_type<PointOfSegment>::type, - double - >::type, - CalculationType - >::type calculation_type; - -protected : - struct excess_sum - { - calculation_type sum; - - // Distances are calculated on unit sphere here - strategy::distance::haversine<calculation_type> distance_over_unit_sphere; - - - inline excess_sum() - : sum(0) - , distance_over_unit_sphere(1) - {} - inline calculation_type area(calculation_type radius) const - { - return - sum * radius * radius; - } - }; - -public : - typedef calculation_type return_type; - typedef PointOfSegment segment_point_type; - typedef excess_sum state_type; - - inline huiller(calculation_type radius = 1.0) - : m_radius(radius) - {} - - inline void apply(PointOfSegment const& p1, - PointOfSegment const& p2, - excess_sum& state) const - { - if (! geometry::math::equals(get<0>(p1), get<0>(p2))) - { - calculation_type const half = 0.5; - calculation_type const two = 2.0; - calculation_type const four = 4.0; - calculation_type const pi - = geometry::math::pi<calculation_type>(); - calculation_type const two_pi - = geometry::math::two_pi<calculation_type>(); - calculation_type const half_pi - = geometry::math::half_pi<calculation_type>(); - - // Distance p1 p2 - calculation_type a = state.distance_over_unit_sphere.apply(p1, p2); - - // Sides on unit sphere to south pole - calculation_type b = half_pi - geometry::get_as_radian<1>(p2); - calculation_type c = half_pi - geometry::get_as_radian<1>(p1); - - // Semi parameter - calculation_type s = half * (a + b + c); - - // E: spherical excess, using l'Huiller's formula - // [tg(e / 4)]2 = tg[s / 2] tg[(s-a) / 2] tg[(s-b) / 2] tg[(s-c) / 2] - calculation_type excess = four - * atan(geometry::math::sqrt(geometry::math::abs(tan(s / two) - * tan((s - a) / two) - * tan((s - b) / two) - * tan((s - c) / two)))); - - excess = geometry::math::abs(excess); - - // In right direction: positive, add area. In left direction: negative, subtract area. - // Longitude comparisons are not so obvious. If one is negative and other is positive, - // we have to take the dateline into account. - - calculation_type lon_diff = geometry::get_as_radian<0>(p2) - - geometry::get_as_radian<0>(p1); - if (lon_diff <= 0) - { - lon_diff += two_pi; - } - - if (lon_diff > pi) - { - excess = -excess; - } - - state.sum += excess; - } - } - - inline return_type result(excess_sum const& state) const - { - return state.area(m_radius); - } - -private : - /// Radius of the sphere - calculation_type m_radius; -}; - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -namespace services -{ - - -template <typename Point> -struct default_strategy<spherical_equatorial_tag, Point> -{ - typedef strategy::area::huiller<Point> type; -}; - -// Note: spherical polar coordinate system requires "get_as_radian_equatorial" -/***template <typename Point> -struct default_strategy<spherical_polar_tag, Point> -{ - typedef strategy::area::huiller<Point> type; -};***/ - -} // namespace services - -#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - - -}} // namespace strategy::area - - - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP diff --git a/boost/geometry/strategies/spherical/azimuth.hpp b/boost/geometry/strategies/spherical/azimuth.hpp new file mode 100644 index 0000000000..3c208fe2e2 --- /dev/null +++ b/boost/geometry/strategies/spherical/azimuth.hpp @@ -0,0 +1,87 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016-2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP + + +#include <boost/geometry/strategies/azimuth.hpp> +#include <boost/geometry/formulas/spherical.hpp> + +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_void.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename CalculationType = void +> +class spherical +{ +public : + + inline spherical() + {} + + template <typename T> + static inline void apply(T const& lon1_rad, T const& lat1_rad, + T const& lon2_rad, T const& lat2_rad, + T& a1, T& a2) + { + typedef typename boost::mpl::if_ + < + boost::is_void<CalculationType>, T, CalculationType + >::type calc_t; + + geometry::formula::result_spherical<calc_t> + result = geometry::formula::spherical_azimuth<calc_t, true>( + calc_t(lon1_rad), calc_t(lat1_rad), + calc_t(lon2_rad), calc_t(lat2_rad)); + + a1 = result.azimuth; + a2 = result.reverse_azimuth; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<spherical_equatorial_tag, CalculationType> +{ + typedef strategy::azimuth::spherical<CalculationType> type; +}; + +/* +template <typename CalculationType> +struct default_strategy<spherical_polar_tag, CalculationType> +{ + typedef strategy::azimuth::spherical<CalculationType> type; +}; +*/ +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP diff --git a/boost/geometry/strategies/spherical/envelope_segment.hpp b/boost/geometry/strategies/spherical/envelope_segment.hpp new file mode 100644 index 0000000000..98f085fe73 --- /dev/null +++ b/boost/geometry/strategies/spherical/envelope_segment.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2017 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP + +#include <boost/geometry/algorithms/detail/envelope/segment.hpp> +#include <boost/geometry/algorithms/detail/normalize.hpp> +#include <boost/geometry/strategies/envelope.hpp> +#include <boost/geometry/strategies/spherical/azimuth.hpp> + +namespace boost { namespace geometry +{ + +namespace strategy { namespace envelope +{ + +template +< + typename CalculationType = void +> +class spherical_segment +{ +public : + + inline spherical_segment() + {} + + template <typename Point1, typename Point2, typename Box> + inline void + apply(Point1 const& point1, Point2 const& point2, Box& box) const + { + Point1 p1_normalized = detail::return_normalized<Point1>(point1); + Point2 p2_normalized = detail::return_normalized<Point2>(point2); + + geometry::strategy::azimuth::spherical<CalculationType> azimuth_spherical; + + typedef typename coordinate_system<Point1>::type::units units_type; + + geometry::detail::envelope::envelope_segment_impl<spherical_equatorial_tag> + ::template apply<units_type>(geometry::get<0>(p1_normalized), + geometry::get<1>(p1_normalized), + geometry::get<0>(p2_normalized), + geometry::get<1>(p2_normalized), + box, + azimuth_spherical); + + } +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template <typename CalculationType> +struct default_strategy<spherical_equatorial_tag, CalculationType> +{ + typedef strategy::envelope::spherical_segment<CalculationType> type; +}; + + +template <typename CalculationType> +struct default_strategy<spherical_polar_tag, CalculationType> +{ + typedef strategy::envelope::spherical_segment<CalculationType> type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::envelope + +}} //namepsace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP + diff --git a/boost/geometry/strategies/spherical/intersection.hpp b/boost/geometry/strategies/spherical/intersection.hpp index 4ffc853aad..5d37583333 100644 --- a/boost/geometry/strategies/spherical/intersection.hpp +++ b/boost/geometry/strategies/spherical/intersection.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 // Use, modification and distribution is subject to the Boost Software License, @@ -25,6 +25,7 @@ #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/spherical.hpp> #include <boost/geometry/geometries/concepts/point_concept.hpp> @@ -32,9 +33,16 @@ #include <boost/geometry/policies/robustness/segment_ratio.hpp> -#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> +#include <boost/geometry/strategies/covered_by.hpp> #include <boost/geometry/strategies/intersection.hpp> #include <boost/geometry/strategies/intersection_result.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/strategies/side_info.hpp> +#include <boost/geometry/strategies/spherical/area.hpp> +#include <boost/geometry/strategies/spherical/distance_haversine.hpp> +#include <boost/geometry/strategies/spherical/ssf.hpp> +#include <boost/geometry/strategies/within.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_calculation_type.hpp> @@ -68,13 +76,80 @@ namespace strategy { namespace intersection // For now, intersection points near the endpoints are checked explicitly if needed (if the IP is near the endpoint) // to generate precise result for them. Only the crossing (i) case may suffer from lower precision. -template <typename Policy, typename CalculationType = void> -struct relate_spherical_segments +template +< + typename CalcPolicy, + typename CalculationType = void +> +struct ecef_segments { - typedef typename Policy::return_type return_type; + typedef side::spherical_side_formula<CalculationType> side_strategy_type; + + static inline side_strategy_type get_side_strategy() + { + return side_strategy_type(); + } + + template <typename Geometry1, typename Geometry2> + struct point_in_geometry_strategy + { + typedef strategy::within::winding + < + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type, + side_strategy_type, + CalculationType + > type; + }; + + template <typename Geometry1, typename Geometry2> + static inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type + get_point_in_geometry_strategy() + { + typedef typename point_in_geometry_strategy + < + Geometry1, Geometry2 + >::type strategy_type; + return strategy_type(); + } + + template <typename Geometry> + struct area_strategy + { + typedef area::spherical + < + typename point_type<Geometry>::type, + CalculationType + > type; + }; + + template <typename Geometry> + static inline typename area_strategy<Geometry>::type get_area_strategy() + { + typedef typename area_strategy<Geometry>::type strategy_type; + return strategy_type(); + } + + template <typename Geometry> + struct distance_strategy + { + typedef distance::haversine + < + typename coordinate_type<Geometry>::type, + CalculationType + > type; + }; + + template <typename Geometry> + static inline typename distance_strategy<Geometry>::type get_distance_strategy() + { + typedef typename distance_strategy<Geometry>::type strategy_type; + return strategy_type(); + } enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 }; + // segment_intersection_info cannot outlive relate_ecef_segments template <typename CoordinateType, typename SegmentRatio, typename Vector3d> struct segment_intersection_info { @@ -83,6 +158,10 @@ struct relate_spherical_segments CoordinateType, double >::type promoted_type; + segment_intersection_info(CalcPolicy const& calc) + : calc_policy(calc) + {} + promoted_type comparable_length_a() const { return robust_ra.denominator(); @@ -110,7 +189,7 @@ struct relate_spherical_segments if (ip_flag == ipi_inters) { // TODO: assign the rest of coordinates - point = formula::cart3d_to_sph<Point>(intersection_point); + point = calc_policy.template from_cart3d<Point>(intersection_point); } else if (ip_flag == ipi_at_a1) { @@ -134,12 +213,21 @@ struct relate_spherical_segments SegmentRatio robust_ra; SegmentRatio robust_rb; intersection_point_flag ip_flag; + + CalcPolicy const& calc_policy; }; // Relate segments a and b - template <typename Segment1, typename Segment2, typename RobustPolicy> - static inline return_type apply(Segment1 const& a, Segment2 const& b, - RobustPolicy const& robust_policy) + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy + > + static inline typename Policy::return_type + apply(Segment1 const& a, Segment2 const& b, + Policy const& policy, RobustPolicy const& robust_policy) { typedef typename point_type<Segment1>::type point1_t; typedef typename point_type<Segment2>::type point2_t; @@ -152,15 +240,30 @@ struct relate_spherical_segments detail::assign_point_from_index<0>(b, b1); detail::assign_point_from_index<1>(b, b2); - return apply(a, b, robust_policy, a1, a2, b1, b2); + return apply(a, b, policy, robust_policy, a1, a2, b1, b2); } // Relate segments a and b - template <typename Segment1, typename Segment2, typename RobustPolicy, typename Point1, typename Point2> - static inline return_type apply(Segment1 const& a, Segment2 const& b, - RobustPolicy const&, - Point1 const& a1, Point1 const& a2, Point2 const& b1, Point2 const& b2) + template + < + typename Segment1, + typename Segment2, + typename Policy, + typename RobustPolicy, + typename Point1, + typename Point2 + > + static inline typename Policy::return_type + apply(Segment1 const& a, Segment2 const& b, + Policy const&, RobustPolicy const&, + Point1 const& a1, Point1 const& a2, Point2 const& b1, Point2 const& b2) { + // For now create it using default constructor. In the future it could + // be stored in strategy. However then apply() wouldn't be static and + // all relops and setops would have to take the strategy or model. + // Initialize explicitly to prevent compiler errors in case of PoD type + CalcPolicy const calc_policy = CalcPolicy(); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) ); BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) ); @@ -185,25 +288,29 @@ struct relate_spherical_segments typedef model::point<calc_t, 3, cs::cartesian> vec3d_t; - using namespace formula; - vec3d_t const a1v = sph_to_cart3d<vec3d_t>(a1); - vec3d_t const a2v = sph_to_cart3d<vec3d_t>(a2); - vec3d_t const b1v = sph_to_cart3d<vec3d_t>(b1); - vec3d_t const b2v = sph_to_cart3d<vec3d_t>(b2); + vec3d_t const a1v = calc_policy.template to_cart3d<vec3d_t>(a1); + vec3d_t const a2v = calc_policy.template to_cart3d<vec3d_t>(a2); + vec3d_t const b1v = calc_policy.template to_cart3d<vec3d_t>(b1); + vec3d_t const b2v = calc_policy.template to_cart3d<vec3d_t>(b2); - vec3d_t norm1 = cross_product(a1v, a2v); - vec3d_t norm2 = cross_product(b1v, b2v); - side_info sides; - // not normalized normals, the same as in SSF - sides.set<0>(sph_side_value(norm2, a1v), sph_side_value(norm2, a2v)); + + typename CalcPolicy::template plane<vec3d_t> + plane2 = calc_policy.get_plane(b1v, b2v); + + // not normalized normals, the same as in side strategy + sides.set<0>(plane2.side_value(a1v), plane2.side_value(a2v)); if (sides.same<0>()) { // Both points are at same side of other segment, we can leave return Policy::disjoint(); } - // not normalized normals, the same as in SSF - sides.set<1>(sph_side_value(norm1, b1v), sph_side_value(norm1, b2v)); + + typename CalcPolicy::template plane<vec3d_t> + plane1 = calc_policy.get_plane(a1v, a2v); + + // not normalized normals, the same as in side strategy + sides.set<1>(plane1.side_value(b1v), plane1.side_value(b2v)); if (sides.same<1>()) { // Both points are at same side of other segment, we can leave @@ -212,13 +319,10 @@ struct relate_spherical_segments // NOTE: at this point the segments may still be disjoint - bool collinear = sides.collinear(); - - calc_t const len1 = math::sqrt(dot_product(norm1, norm1)); - calc_t const len2 = math::sqrt(dot_product(norm2, norm2)); + calc_t len1, len2; - // point or opposite sides of a sphere, assume point - if (math::equals(len1, c0)) + // point or opposite sides of a sphere/spheroid, assume point + if (! detail::vec_normalize(plane1.normal, len1)) { a_is_point = true; if (sides.get<0, 0>() == 0 || sides.get<0, 1>() == 0) @@ -226,13 +330,8 @@ struct relate_spherical_segments sides.set<0>(0, 0); } } - else - { - // normalize - divide_value(norm1, len1); - } - if (math::equals(len2, c0)) + if (! detail::vec_normalize(plane2.normal, len2)) { b_is_point = true; if (sides.get<1, 0>() == 0 || sides.get<1, 1>() == 0) @@ -240,11 +339,6 @@ struct relate_spherical_segments sides.set<1>(0, 0); } } - else - { - // normalize - divide_value(norm2, len2); - } // check both degenerated once more if (a_is_point && b_is_point) @@ -255,16 +349,42 @@ struct relate_spherical_segments ; } + // NOTE: at this point the segments may still be disjoint // NOTE: at this point one of the segments may be degenerated - // and the segments may still be disjoint - calc_t dot_n1n2 = dot_product(norm1, norm2); + bool collinear = sides.collinear(); + + if (! collinear) + { + // NOTE: for some approximations it's possible that both points may lie + // on the same geodesic but still some of the sides may be != 0. + // This is e.g. true for long segments represented as elliptic arcs + // with origin different than the center of the coordinate system. + // So make the sides consistent + + // WARNING: the side strategy doesn't have the info about the other + // segment so it may return results inconsistent with this intersection + // strategy, as it checks both segments for consistency + + if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0) + { + collinear = true; + sides.set<1>(0, 0); + } + else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0) + { + collinear = true; + sides.set<0>(0, 0); + } + } + + calc_t dot_n1n2 = dot_product(plane1.normal, plane2.normal); // NOTE: this is technically not needed since theoretically above sides // are calculated, but just in case check the normals. // Have in mind that SSF side strategy doesn't check this. // collinear if normals are equal or opposite: cos(a) in {-1, 1} - if (!collinear && math::equals(math::abs(dot_n1n2), c1)) + if (! collinear && math::equals(math::abs(dot_n1n2), c1)) { collinear = true; sides.set<0>(0, 0); @@ -275,12 +395,12 @@ struct relate_spherical_segments { if (a_is_point) { - return collinear_one_degenerted<calc_t>(a, true, b1, b2, a1, a2, b1v, b2v, norm2, a1v); + return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, b1v, b2v, plane2, a1v); } else if (b_is_point) { // b2 used to be consistent with (degenerated) checks above (is it needed?) - return collinear_one_degenerted<calc_t>(b, false, a1, a2, b1, b2, a1v, a2v, norm1, b1v); + return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, a1v, a2v, plane1, b1v); } else { @@ -289,16 +409,16 @@ struct relate_spherical_segments // use shorter segment if (len1 <= len2) { - calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, norm1, b1v, dist_a1_a2, dist_a1_b1); - calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, norm1, b2v, dist_a1_a2, dist_a1_b2); + calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b1v, dist_a1_a2, dist_a1_b1); + calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b2v, dist_a1_a2, dist_a1_b2); dist_b1_b2 = dist_a1_b2 - dist_a1_b1; dist_b1_a1 = -dist_a1_b1; dist_b1_a2 = dist_a1_a2 - dist_a1_b1; } else { - calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, norm2, a1v, dist_b1_b2, dist_b1_a1); - calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, norm2, a2v, dist_b1_b2, dist_b1_a2); + calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a1v, dist_b1_b2, dist_b1_a1); + calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a2v, dist_b1_b2, dist_b1_a2); dist_a1_a2 = dist_b1_a2 - dist_b1_a1; dist_a1_b1 = -dist_b1_a1; dist_a1_b2 = dist_b1_b2 - dist_b1_a1; @@ -359,7 +479,8 @@ struct relate_spherical_segments vec3d_t i1; intersection_point_flag ip_flag; calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1; - if (calculate_ip_data(a1, a2, b1, b2, a1v, a2v, b1v, b2v, norm1, norm2, sides, + if (calculate_ip_data(a1, a2, b1, b2, a1v, a2v, b1v, b2v, + plane1, plane2, calc_policy, sides, i1, dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1, ip_flag)) { // intersects @@ -368,7 +489,7 @@ struct relate_spherical_segments calc_t, segment_ratio<calc_t>, vec3d_t - > sinfo; + > sinfo(calc_policy); sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2); sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2); @@ -385,30 +506,32 @@ struct relate_spherical_segments } private: - template <typename CalcT, typename Segment, typename Point1, typename Point2, typename Vec3d> - static inline return_type collinear_one_degenerted(Segment const& segment, bool degenerated_a, - Point1 const& a1, Point1 const& a2, - Point2 const& b1, Point2 const& b2, - Vec3d const& v1, Vec3d const& v2, Vec3d const& norm, - Vec3d const& vother) + template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename Vec3d, typename Plane> + static inline typename Policy::return_type + collinear_one_degenerated(Segment const& segment, bool degenerated_a, + Point1 const& a1, Point1 const& a2, + Point2 const& b1, Point2 const& b2, + Vec3d const& v1, Vec3d const& v2, + Plane const& plane, + Vec3d const& vother) { CalcT dist_1_2, dist_1_o; - return ! calculate_collinear_data(a1, a2, b1, b2, v1, v2, norm, vother, dist_1_2, dist_1_o) + return ! calculate_collinear_data(a1, a2, b1, b2, v1, v2, plane, vother, dist_1_2, dist_1_o) ? Policy::disjoint() : Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a); } - template <typename Point1, typename Point2, typename Vec3d, typename CalcT> - static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, - Point2 const& b1, Point2 const& b2, - Vec3d const& a1v, // in - Vec3d const& a2v, // in - Vec3d const& norm1, // in - Vec3d const& b1v_or_b2v, // in + template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT> + static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in + Point2 const& b1, Point2 const& b2, // in + Vec3d const& a1v, // in + Vec3d const& a2v, // in + Plane const& plane1, // in + Vec3d const& b1v_or_b2v, // in CalcT& dist_a1_a2, CalcT& dist_a1_i1) // out { // calculate dist_a1_a2 and dist_a1_i1 - calculate_dists(a1v, a2v, norm1, b1v_or_b2v, dist_a1_a2, dist_a1_i1); + calculate_dists(a1v, a2v, plane1, b1v_or_b2v, dist_a1_a2, dist_a1_i1); // if i1 is close to a1 and b1 or b2 is equal to a1 if (is_endpoint_equal(dist_a1_i1, a1, b1, b2)) @@ -427,54 +550,53 @@ private: return segment_ratio<CalcT>(dist_a1_i1, dist_a1_a2).on_segment(); } - template <typename Point1, typename Point2, typename Vec3d, typename CalcT> + template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT> static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in Point2 const& b1, Point2 const& b2, // in Vec3d const& a1v, Vec3d const& a2v, // in Vec3d const& b1v, Vec3d const& b2v, // in - Vec3d const& norm1, Vec3d const& norm2, // in - side_info const& sides, // in - Vec3d & i1, // in-out - CalcT& dist_a1_a2, CalcT& dist_a1_i1, // out - CalcT& dist_b1_b2, CalcT& dist_b1_i1, // out + Plane const& plane1, // in + Plane const& plane2, // in + CalcPolicy const& calc_policy, // in + side_info const& sides, // in + Vec3d & ip, // out + CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out + CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out intersection_point_flag& ip_flag) // out { - // great circles intersections - i1 = cross_product(norm1, norm2); - // NOTE: the length should be greater than 0 at this point - // if the normals were not normalized and their dot product - // not checked before this function is called the length - // should be checked here (math::equals(len, c0)) - CalcT const len = math::sqrt(dot_product(i1, i1)); - divide_value(i1, len); // normalize i1 - - calculate_dists(a1v, a2v, norm1, i1, dist_a1_a2, dist_a1_i1); + Vec3d ip1, ip2; + calc_policy.intersection_points(plane1, plane2, ip1, ip2); + calculate_dists(a1v, a2v, plane1, ip1, dist_a1_a2, dist_a1_ip); + ip = ip1; + // choose the opposite side of the globe if the distance is shorter { - CalcT const d = abs_distance(dist_a1_a2, dist_a1_i1); + CalcT const d = abs_distance(dist_a1_a2, dist_a1_ip); if (d > CalcT(0)) { - CalcT const dist_a1_i2 = dist_of_i2(dist_a1_i1); + // TODO: this should be ok not only for sphere + // but requires more investigation + CalcT const dist_a1_i2 = dist_of_i2(dist_a1_ip); CalcT const d2 = abs_distance(dist_a1_a2, dist_a1_i2); if (d2 < d) { - dist_a1_i1 = dist_a1_i2; - multiply_value(i1, CalcT(-1)); // the opposite intersection + dist_a1_ip = dist_a1_i2; + ip = ip2; } } } bool is_on_a = false, is_near_a1 = false, is_near_a2 = false; - if (! is_potentially_crossing(dist_a1_a2, dist_a1_i1, is_on_a, is_near_a1, is_near_a2)) + if (! is_potentially_crossing(dist_a1_a2, dist_a1_ip, is_on_a, is_near_a1, is_near_a2)) { return false; } - calculate_dists(b1v, b2v, norm2, i1, dist_b1_b2, dist_b1_i1); + calculate_dists(b1v, b2v, plane2, ip, dist_b1_b2, dist_b1_ip); bool is_on_b = false, is_near_b1 = false, is_near_b2 = false; - if (! is_potentially_crossing(dist_b1_b2, dist_b1_i1, is_on_b, is_near_b1, is_near_b2)) + if (! is_potentially_crossing(dist_b1_b2, dist_b1_ip, is_on_b, is_near_b1, is_near_b2)) { return false; } @@ -485,8 +607,8 @@ private: { if (is_near_b1 && equals_point_point(a1, b1)) { - dist_a1_i1 = 0; - dist_b1_i1 = 0; + dist_a1_ip = 0; + dist_b1_ip = 0; //i1 = a1v; ip_flag = ipi_at_a1; return true; @@ -494,8 +616,8 @@ private: if (is_near_b2 && equals_point_point(a1, b2)) { - dist_a1_i1 = 0; - dist_b1_i1 = dist_b1_b2; + dist_a1_ip = 0; + dist_b1_ip = dist_b1_b2; //i1 = a1v; ip_flag = ipi_at_a1; return true; @@ -506,8 +628,8 @@ private: { if (is_near_b1 && equals_point_point(a2, b1)) { - dist_a1_i1 = dist_a1_a2; - dist_b1_i1 = 0; + dist_a1_ip = dist_a1_a2; + dist_b1_ip = 0; //i1 = a2v; ip_flag = ipi_at_a2; return true; @@ -515,8 +637,8 @@ private: if (is_near_b2 && equals_point_point(a2, b2)) { - dist_a1_i1 = dist_a1_a2; - dist_b1_i1 = dist_b1_b2; + dist_a1_ip = dist_a1_a2; + dist_b1_ip = dist_b1_b2; //i1 = a2v; ip_flag = ipi_at_a2; return true; @@ -530,7 +652,7 @@ private: { if (is_near_b1 && sides.template get<1, 0>() == 0) // b1 wrt a { - dist_b1_i1 = 0; + dist_b1_ip = 0; //i1 = b1v; ip_flag = ipi_at_b1; return true; @@ -538,7 +660,7 @@ private: if (is_near_b2 && sides.template get<1, 1>() == 0) // b2 wrt a { - dist_b1_i1 = dist_b1_b2; + dist_b1_ip = dist_b1_b2; //i1 = b2v; ip_flag = ipi_at_b2; return true; @@ -549,7 +671,7 @@ private: { if (is_near_a1 && sides.template get<0, 0>() == 0) // a1 wrt b { - dist_a1_i1 = 0; + dist_a1_ip = 0; //i1 = a1v; ip_flag = ipi_at_a1; return true; @@ -557,7 +679,7 @@ private: if (is_near_a2 && sides.template get<0, 1>() == 0) // a2 wrt b { - dist_a1_i1 = dist_a1_a2; + dist_a1_ip = dist_a1_a2; //i1 = a2v; ip_flag = ipi_at_a2; return true; @@ -569,24 +691,26 @@ private: return is_on_a && is_on_b; } - template <typename Vec3d, typename CalcT> - static inline void calculate_dists(Vec3d const& a1v, // in - Vec3d const& a2v, // in - Vec3d const& norm1, // in - Vec3d const& i1, // in - CalcT& dist_a1_a2, CalcT& dist_a1_i1) // out + template <typename Vec3d, typename Plane, typename CalcT> + static inline void calculate_dists(Vec3d const& a1v, // in + Vec3d const& a2v, // in + Plane const& plane1, // in + Vec3d const& i1, // in + CalcT& dist_a1_a2, // out + CalcT& dist_a1_i1) // out { - CalcT const c0 = 0; + //CalcT const c0 = 0; CalcT const c1 = 1; CalcT const c2 = 2; CalcT const c4 = 4; - CalcT cos_a1_a2 = dot_product(a1v, a2v); + CalcT cos_a1_a2 = plane1.cos_angle_between(a1v, a2v); dist_a1_a2 = -cos_a1_a2 + c1; // [1, -1] -> [0, 2] representing [0, pi] - CalcT cos_a1_i1 = dot_product(a1v, i1); + bool is_forward = true; + CalcT cos_a1_i1 = plane1.cos_angle_between(a1v, i1, is_forward); dist_a1_i1 = -cos_a1_i1 + c1; // [0, 2] representing [0, pi] - if (dot_product(norm1, cross_product(a1v, i1)) < c0) // left or right of a1 on a + if (! is_forward) // left or right of a1 on a { dist_a1_i1 = -dist_a1_i1; // [0, 2] -> [0, -2] representing [0, -pi] } @@ -666,27 +790,117 @@ private: } }; +struct spherical_segments_calc_policy +{ + template <typename Point, typename Point3d> + static Point from_cart3d(Point3d const& point_3d) + { + return formula::cart3d_to_sph<Point>(point_3d); + } + + template <typename Point3d, typename Point> + static Point3d to_cart3d(Point const& point) + { + return formula::sph_to_cart3d<Point3d>(point); + } + + template <typename Point3d> + struct plane + { + typedef typename coordinate_type<Point3d>::type coord_t; + + // not normalized + plane(Point3d const& p1, Point3d const& p2) + : normal(cross_product(p1, p2)) + {} + + int side_value(Point3d const& pt) const + { + return formula::sph_side_value(normal, pt); + } + + static coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) + { + return dot_product(p1, p2); + } + + coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const + { + coord_t const c0 = 0; + is_forward = dot_product(normal, cross_product(p1, p2)) >= c0; + return dot_product(p1, p2); + } + + Point3d normal; + }; + + template <typename Point3d> + static plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) + { + return plane<Point3d>(p1, p2); + } + + template <typename Point3d> + static bool intersection_points(plane<Point3d> const& plane1, + plane<Point3d> const& plane2, + Point3d & ip1, Point3d & ip2) + { + typedef typename coordinate_type<Point3d>::type coord_t; + + ip1 = cross_product(plane1.normal, plane2.normal); + // NOTE: the length should be greater than 0 at this point + // if the normals were not normalized and their dot product + // not checked before this function is called the length + // should be checked here (math::equals(len, c0)) + coord_t const len = math::sqrt(dot_product(ip1, ip1)); + divide_value(ip1, len); // normalize i1 + + ip2 = ip1; + multiply_value(ip2, coord_t(-1)); + + return true; + } +}; + + +template +< + typename CalculationType = void +> +struct spherical_segments + : ecef_segments + < + spherical_segments_calc_policy, + CalculationType + > +{}; + #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS namespace services { -/*template <typename Policy, typename CalculationType> -struct default_strategy<spherical_polar_tag, Policy, CalculationType> +/*template <typename CalculationType> +struct default_strategy<spherical_polar_tag, CalculationType> { - typedef relate_spherical_segments<Policy, CalculationType> type; + typedef spherical_segments<CalculationType> type; };*/ -template <typename Policy, typename CalculationType> -struct default_strategy<spherical_equatorial_tag, Policy, CalculationType> +template <typename CalculationType> +struct default_strategy<spherical_equatorial_tag, CalculationType> { - typedef relate_spherical_segments<Policy, CalculationType> type; + typedef spherical_segments<CalculationType> type; }; -template <typename Policy, typename CalculationType> -struct default_strategy<geographic_tag, Policy, CalculationType> +template <typename CalculationType> +struct default_strategy<geographic_tag, CalculationType> { - typedef relate_spherical_segments<Policy, CalculationType> type; + // NOTE: Spherical strategy returns the same result as the geographic one + // representing segments as great elliptic arcs. If the elliptic arcs are + // not great elliptic arcs (the origin not in the center of the coordinate + // system) then there may be problems with consistency of the side and + // intersection strategies. + typedef spherical_segments<CalculationType> type; }; } // namespace services @@ -695,6 +909,71 @@ struct default_strategy<geographic_tag, Policy, CalculationType> }} // namespace strategy::intersection + +namespace strategy +{ + +namespace within { namespace services +{ + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +}} // within::services + +namespace covered_by { namespace services +{ + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2> +struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, spherical_tag, spherical_tag> +{ + typedef strategy::intersection::spherical_segments<> type; +}; + +}} // within::services + +} // strategy + + }} // namespace boost::geometry diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp index 342485cc4c..f3c6787a4b 100644 --- a/boost/geometry/strategies/strategies.hpp +++ b/boost/geometry/strategies/strategies.hpp @@ -4,9 +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 2014-2016. -// Modifications copyright (c) 2014-2016 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 Vissarion Fysikopoulos, 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 @@ -23,18 +24,24 @@ #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/strategies/area.hpp> +#include <boost/geometry/strategies/azimuth.hpp> #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/strategies/centroid.hpp> #include <boost/geometry/strategies/compare.hpp> #include <boost/geometry/strategies/convex_hull.hpp> +#include <boost/geometry/strategies/covered_by.hpp> +#include <boost/geometry/strategies/disjoint.hpp> #include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/envelope.hpp> #include <boost/geometry/strategies/intersection.hpp> #include <boost/geometry/strategies/intersection_strategies.hpp> // for backward compatibility +#include <boost/geometry/strategies/relate.hpp> #include <boost/geometry/strategies/side.hpp> #include <boost/geometry/strategies/transform.hpp> #include <boost/geometry/strategies/within.hpp> #include <boost/geometry/strategies/cartesian/area_surveyor.hpp> +#include <boost/geometry/strategies/cartesian/azimuth.hpp> #include <boost/geometry/strategies/cartesian/box_in_box.hpp> #include <boost/geometry/strategies/cartesian/buffer_end_flat.hpp> #include <boost/geometry/strategies/cartesian/buffer_end_round.hpp> @@ -47,30 +54,42 @@ #include <boost/geometry/strategies/cartesian/centroid_average.hpp> #include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp> #include <boost/geometry/strategies/cartesian/centroid_weighted_length.hpp> +#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp> #include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp> #include <boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp> #include <boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp> #include <boost/geometry/strategies/cartesian/distance_projected_point.hpp> #include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp> +#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> +#include <boost/geometry/strategies/cartesian/intersection.hpp> #include <boost/geometry/strategies/cartesian/point_in_box.hpp> #include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp> #include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp> #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> -#include <boost/geometry/strategies/spherical/area_huiller.hpp> +#include <boost/geometry/strategies/spherical/area.hpp> +#include <boost/geometry/strategies/spherical/azimuth.hpp> #include <boost/geometry/strategies/spherical/distance_haversine.hpp> #include <boost/geometry/strategies/spherical/distance_cross_track.hpp> #include <boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp> #include <boost/geometry/strategies/spherical/compare_circular.hpp> +#include <boost/geometry/strategies/spherical/envelope_segment.hpp> #include <boost/geometry/strategies/spherical/intersection.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> +#include <boost/geometry/strategies/geographic/area.hpp> +#include <boost/geometry/strategies/geographic/azimuth.hpp> +#include <boost/geometry/strategies/geographic/distance.hpp> #include <boost/geometry/strategies/geographic/distance_andoyer.hpp> #include <boost/geometry/strategies/geographic/distance_thomas.hpp> #include <boost/geometry/strategies/geographic/distance_vincenty.hpp> -//#include <boost/geometry/strategies/geographic/side_andoyer.hpp> -//#include <boost/geometry/strategies/geographic/side_thomas.hpp> -//#include <boost/geometry/strategies/geographic/side_vincenty.hpp> +#include <boost/geometry/strategies/geographic/envelope_segment.hpp> +#include <boost/geometry/strategies/geographic/intersection.hpp> +//#include <boost/geometry/strategies/geographic/intersection_elliptic.hpp> +#include <boost/geometry/strategies/geographic/side.hpp> +#include <boost/geometry/strategies/geographic/side_andoyer.hpp> +#include <boost/geometry/strategies/geographic/side_thomas.hpp> +#include <boost/geometry/strategies/geographic/side_vincenty.hpp> #include <boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp> #include <boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp> @@ -80,8 +99,6 @@ #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp> -#include <boost/geometry/strategies/agnostic/relate.hpp> - #include <boost/geometry/strategies/strategy_transform.hpp> #include <boost/geometry/strategies/transform/matrix_transformers.hpp> diff --git a/boost/geometry/strategies/transform/inverse_transformer.hpp b/boost/geometry/strategies/transform/inverse_transformer.hpp index e64a46e4a8..5213bce47a 100644 --- a/boost/geometry/strategies/transform/inverse_transformer.hpp +++ b/boost/geometry/strategies/transform/inverse_transformer.hpp @@ -14,15 +14,8 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP #define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP -// Remove the ublas checking, otherwise the inverse might fail -// (while nothing seems to be wrong) -#ifdef BOOST_UBLAS_TYPE_CHECK -#undef BOOST_UBLAS_TYPE_CHECK -#endif -#define BOOST_UBLAS_TYPE_CHECK 0 - -#include <boost/numeric/ublas/lu.hpp> -#include <boost/numeric/ublas/io.hpp> +#include <boost/qvm/mat.hpp> +#include <boost/qvm/mat_operations.hpp> #include <boost/geometry/strategies/transform/matrix_transformers.hpp> @@ -44,31 +37,13 @@ template std::size_t Dimension2 > class inverse_transformer - : public ublas_transformer<CalculationType, Dimension1, Dimension2> + : public matrix_transformer<CalculationType, Dimension1, Dimension2> { public : template <typename Transformer> inline inverse_transformer(Transformer const& input) { - typedef boost::numeric::ublas::matrix<CalculationType> matrix_type; - - // create a working copy of the input - matrix_type copy(input.matrix()); - - // create a permutation matrix for the LU-factorization - typedef boost::numeric::ublas::permutation_matrix<> permutation_matrix; - permutation_matrix pm(copy.size1()); - - // perform LU-factorization - int res = boost::numeric::ublas::lu_factorize<matrix_type>(copy, pm); - if( res == 0 ) - { - // create identity matrix - this->m_matrix.assign(boost::numeric::ublas::identity_matrix<CalculationType>(copy.size1())); - - // backsubstitute to get the inverse - boost::numeric::ublas::lu_substitute(copy, pm, this->m_matrix); - } + this->m_matrix = boost::qvm::inverse(input.matrix()); } }; diff --git a/boost/geometry/strategies/transform/map_transformer.hpp b/boost/geometry/strategies/transform/map_transformer.hpp index 1109e814b9..01ea6168c5 100644 --- a/boost/geometry/strategies/transform/map_transformer.hpp +++ b/boost/geometry/strategies/transform/map_transformer.hpp @@ -46,9 +46,10 @@ template bool SameScale = true > class map_transformer - : public ublas_transformer<CalculationType, Dimension1, Dimension2> + : public matrix_transformer<CalculationType, Dimension1, Dimension2> { - typedef boost::numeric::ublas::matrix<CalculationType> M; + typedef boost::qvm::mat<CalculationType, Dimension1 + 1, Dimension2 + 1> M; + typedef boost::qvm::mat<CalculationType, 3, 3> matrix33; public : template <typename B, typename D> @@ -76,26 +77,26 @@ private : { // Translate to a coordinate system centered on world coordinates (-wx, -wy) - M t1(3,3); - t1(0,0) = 1; t1(0,1) = 0; t1(0,2) = -wx; - t1(1,0) = 0; t1(1,1) = 1; t1(1,2) = -wy; - t1(2,0) = 0; t1(2,1) = 0; t1(2,2) = 1; + matrix33 t1; + qvm::A<0,0>(t1) = 1; qvm::A<0,1>(t1) = 0; qvm::A<0,2>(t1) = -wx; + qvm::A<1,0>(t1) = 0; qvm::A<1,1>(t1) = 1; qvm::A<1,2>(t1) = -wy; + qvm::A<2,0>(t1) = 0; qvm::A<2,1>(t1) = 0; qvm::A<2,2>(t1) = 1; // Scale the map - M s(3,3); - s(0,0) = scalex; s(0,1) = 0; s(0,2) = 0; - s(1,0) = 0; s(1,1) = scaley; s(1,2) = 0; - s(2,0) = 0; s(2,1) = 0; s(2,2) = 1; + matrix33 s; + qvm::A<0,0>(s) = scalex; qvm::A<0,1>(s) = 0; qvm::A<0,2>(s) = 0; + qvm::A<1,0>(s) = 0; qvm::A<1,1>(s) = scaley; qvm::A<1,2>(s) = 0; + qvm::A<2,0>(s) = 0; qvm::A<2,1>(s) = 0; qvm::A<2,2>(s) = 1; // Translate to a coordinate system centered on the specified pixels (+px, +py) - M t2(3, 3); - t2(0,0) = 1; t2(0,1) = 0; t2(0,2) = px; - t2(1,0) = 0; t2(1,1) = 1; t2(1,2) = py; - t2(2,0) = 0; t2(2,1) = 0; t2(2,2) = 1; + matrix33 t2; + qvm::A<0,0>(t2) = 1; qvm::A<0,1>(t2) = 0; qvm::A<0,2>(t2) = px; + qvm::A<1,0>(t2) = 0; qvm::A<1,1>(t2) = 1; qvm::A<1,2>(t2) = py; + qvm::A<2,0>(t2) = 0; qvm::A<2,1>(t2) = 0; qvm::A<2,2>(t2) = 1; // Calculate combination matrix in two steps - this->m_matrix = boost::numeric::ublas::prod(s, t1); - this->m_matrix = boost::numeric::ublas::prod(t2, this->m_matrix); + this->m_matrix = s * t1; + this->m_matrix = t2 * this->m_matrix; } @@ -140,20 +141,20 @@ private : if (Mirror) { // Mirror in y-direction - M m(3,3); - m(0,0) = 1; m(0,1) = 0; m(0,2) = 0; - m(1,0) = 0; m(1,1) = -1; m(1,2) = 0; - m(2,0) = 0; m(2,1) = 0; m(2,2) = 1; + matrix33 m; + qvm::A<0,0>(m) = 1; qvm::A<0,1>(m) = 0; qvm::A<0,2>(m) = 0; + qvm::A<1,0>(m) = 0; qvm::A<1,1>(m) = -1; qvm::A<1,2>(m) = 0; + qvm::A<2,0>(m) = 0; qvm::A<2,1>(m) = 0; qvm::A<2,2>(m) = 1; // Translate in y-direction such that it fits again - M y(3, 3); - y(0,0) = 1; y(0,1) = 0; y(0,2) = 0; - y(1,0) = 0; y(1,1) = 1; y(1,2) = height; - y(2,0) = 0; y(2,1) = 0; y(2,2) = 1; + matrix33 y; + qvm::A<0,0>(y) = 1; qvm::A<0,1>(y) = 0; qvm::A<0,2>(y) = 0; + qvm::A<1,0>(y) = 0; qvm::A<1,1>(y) = 1; qvm::A<1,2>(y) = height; + qvm::A<2,0>(y) = 0; qvm::A<2,1>(y) = 0; qvm::A<2,2>(y) = 1; // Calculate combination matrix in two steps - this->m_matrix = boost::numeric::ublas::prod(m, this->m_matrix); - this->m_matrix = boost::numeric::ublas::prod(y, this->m_matrix); + this->m_matrix = m * this->m_matrix; + this->m_matrix = y * this->m_matrix; } } }; diff --git a/boost/geometry/strategies/transform/matrix_transformers.hpp b/boost/geometry/strategies/transform/matrix_transformers.hpp index d891263a7d..e0ac6496f3 100644 --- a/boost/geometry/strategies/transform/matrix_transformers.hpp +++ b/boost/geometry/strategies/transform/matrix_transformers.hpp @@ -22,27 +22,9 @@ #include <cstddef> -// Remove the ublas checking, otherwise the inverse might fail -// (while nothing seems to be wrong) -#ifdef BOOST_UBLAS_TYPE_CHECK -#undef BOOST_UBLAS_TYPE_CHECK -#endif -#define BOOST_UBLAS_TYPE_CHECK 0 - -#include <boost/numeric/conversion/cast.hpp> - -#if defined(__clang__) -// Avoid warning about unused UBLAS function: boost_numeric_ublas_abs -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -#include <boost/numeric/ublas/vector.hpp> -#include <boost/numeric/ublas/matrix.hpp> - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif +#include <boost/qvm/mat.hpp> +#include <boost/qvm/mat_access.hpp> +#include <boost/qvm/mat_operations.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> @@ -75,38 +57,37 @@ template std::size_t Dimension1, std::size_t Dimension2 > -class ublas_transformer +class matrix_transformer { }; template <typename CalculationType> -class ublas_transformer<CalculationType, 2, 2> +class matrix_transformer<CalculationType, 2, 2> { protected : typedef CalculationType ct; - typedef boost::numeric::ublas::matrix<ct> matrix_type; + typedef boost::qvm::mat<ct, 3, 3> matrix_type; matrix_type m_matrix; public : - inline ublas_transformer( + inline matrix_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) - : m_matrix(3, 3) { - m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; - m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; - m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; + qvm::A<0,0>(m_matrix) = m_0_0; qvm::A<0,1>(m_matrix) = m_0_1; qvm::A<0,2>(m_matrix) = m_0_2; + qvm::A<1,0>(m_matrix) = m_1_0; qvm::A<1,1>(m_matrix) = m_1_1; qvm::A<1,2>(m_matrix) = m_1_2; + qvm::A<2,0>(m_matrix) = m_2_0; qvm::A<2,1>(m_matrix) = m_2_1; qvm::A<2,2>(m_matrix) = m_2_2; } - inline ublas_transformer(matrix_type const& matrix) + inline matrix_transformer(matrix_type const& matrix) : m_matrix(matrix) {} - inline ublas_transformer() : m_matrix(3, 3) {} + inline matrix_transformer() {} template <typename P1, typename P2> inline bool apply(P1 const& p1, P2& p2) const @@ -117,8 +98,8 @@ public : ct const& c1 = get<0>(p1); ct const& c2 = get<1>(p1); - ct p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2); - ct p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2); + ct p2x = c1 * qvm::A<0,0>(m_matrix) + c2 * qvm::A<0,1>(m_matrix) + qvm::A<0,2>(m_matrix); + ct p2y = c1 * qvm::A<1,0>(m_matrix) + c2 * qvm::A<1,1>(m_matrix) + qvm::A<1,2>(m_matrix); typedef typename geometry::coordinate_type<P2>::type ct2; set<0>(p2, boost::numeric_cast<ct2>(p2x)); @@ -133,51 +114,50 @@ public : // It IS possible to go from 3 to 2 coordinates template <typename CalculationType> -class ublas_transformer<CalculationType, 3, 2> : public ublas_transformer<CalculationType, 2, 2> +class matrix_transformer<CalculationType, 3, 2> : public matrix_transformer<CalculationType, 2, 2> { typedef CalculationType ct; public : - inline ublas_transformer( + inline matrix_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) - : ublas_transformer<CalculationType, 2, 2>( + : matrix_transformer<CalculationType, 2, 2>( m_0_0, m_0_1, m_0_2, m_1_0, m_1_1, m_1_2, m_2_0, m_2_1, m_2_2) {} - inline ublas_transformer() - : ublas_transformer<CalculationType, 2, 2>() + inline matrix_transformer() + : matrix_transformer<CalculationType, 2, 2>() {} }; template <typename CalculationType> -class ublas_transformer<CalculationType, 3, 3> +class matrix_transformer<CalculationType, 3, 3> { protected : typedef CalculationType ct; - typedef boost::numeric::ublas::matrix<ct> matrix_type; + typedef boost::qvm::mat<ct, 4, 4> matrix_type; matrix_type m_matrix; public : - inline ublas_transformer( + inline matrix_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2, ct const& m_2_3, ct const& m_3_0, ct const& m_3_1, ct const& m_3_2, ct const& m_3_3 ) - : m_matrix(4, 4) { - m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; m_matrix(0,3) = m_0_3; - m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; m_matrix(1,3) = m_1_3; - m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; m_matrix(2,3) = m_2_3; - m_matrix(3,0) = m_3_0; m_matrix(3,1) = m_3_1; m_matrix(3,2) = m_3_2; m_matrix(3,3) = m_3_3; + qvm::A<0,0>(m_matrix) = m_0_0; qvm::A<0,1>(m_matrix) = m_0_1; qvm::A<0,2>(m_matrix) = m_0_2; qvm::A<0,3>(m_matrix) = m_0_3; + qvm::A<1,0>(m_matrix) = m_1_0; qvm::A<1,1>(m_matrix) = m_1_1; qvm::A<1,2>(m_matrix) = m_1_2; qvm::A<1,3>(m_matrix) = m_1_3; + qvm::A<2,0>(m_matrix) = m_2_0; qvm::A<2,1>(m_matrix) = m_2_1; qvm::A<2,2>(m_matrix) = m_2_2; qvm::A<2,3>(m_matrix) = m_2_3; + qvm::A<3,0>(m_matrix) = m_3_0; qvm::A<3,1>(m_matrix) = m_3_1; qvm::A<3,2>(m_matrix) = m_3_2; qvm::A<3,3>(m_matrix) = m_3_3; } - inline ublas_transformer() : m_matrix(4, 4) {} + inline matrix_transformer() {} template <typename P1, typename P2> inline bool apply(P1 const& p1, P2& p2) const @@ -222,7 +202,7 @@ class translate_transformer template<typename CalculationType> -class translate_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2> +class translate_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2> { public : // To have translate transformers compatible for 2/3 dimensions, the @@ -230,7 +210,7 @@ public : inline translate_transformer(CalculationType const& translate_x, CalculationType const& translate_y, CalculationType const& = 0) - : ublas_transformer<CalculationType, 2, 2>( + : matrix_transformer<CalculationType, 2, 2>( 1, 0, translate_x, 0, 1, translate_y, 0, 0, 1) @@ -239,13 +219,13 @@ public : template <typename CalculationType> -class translate_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3> +class translate_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3> { public : inline translate_transformer(CalculationType const& translate_x, CalculationType const& translate_y, CalculationType const& translate_z) - : ublas_transformer<CalculationType, 3, 3>( + : matrix_transformer<CalculationType, 3, 3>( 1, 0, 0, translate_x, 0, 1, 0, translate_y, 0, 0, 1, translate_z, @@ -275,14 +255,14 @@ class scale_transformer template <typename CalculationType> -class scale_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2> +class scale_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2> { public : inline scale_transformer(CalculationType const& scale_x, CalculationType const& scale_y, CalculationType const& = 0) - : ublas_transformer<CalculationType, 2, 2>( + : matrix_transformer<CalculationType, 2, 2>( scale_x, 0, 0, 0, scale_y, 0, 0, 0, 1) @@ -290,7 +270,7 @@ public : inline scale_transformer(CalculationType const& scale) - : ublas_transformer<CalculationType, 2, 2>( + : matrix_transformer<CalculationType, 2, 2>( scale, 0, 0, 0, scale, 0, 0, 0, 1) @@ -299,13 +279,13 @@ public : template <typename CalculationType> -class scale_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3> +class scale_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3> { public : inline scale_transformer(CalculationType const& scale_x, CalculationType const& scale_y, CalculationType const& scale_z) - : ublas_transformer<CalculationType, 3, 3>( + : matrix_transformer<CalculationType, 3, 3>( scale_x, 0, 0, 0, 0, scale_y, 0, 0, 0, 0, scale_z, 0, @@ -314,7 +294,7 @@ public : inline scale_transformer(CalculationType const& scale) - : ublas_transformer<CalculationType, 3, 3>( + : matrix_transformer<CalculationType, 3, 3>( scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, @@ -363,11 +343,11 @@ template std::size_t Dimension2 > class rad_rotate_transformer - : public ublas_transformer<CalculationType, Dimension1, Dimension2> + : public matrix_transformer<CalculationType, Dimension1, Dimension2> { public : inline rad_rotate_transformer(CalculationType const& angle) - : ublas_transformer<CalculationType, Dimension1, Dimension2>( + : matrix_transformer<CalculationType, Dimension1, Dimension2>( cos(angle), sin(angle), 0, -sin(angle), cos(angle), 0, 0, 0, 1) diff --git a/boost/geometry/strategies/within.hpp b/boost/geometry/strategies/within.hpp index d625bc40e6..28a3283db0 100644 --- a/boost/geometry/strategies/within.hpp +++ b/boost/geometry/strategies/within.hpp @@ -4,6 +4,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 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. @@ -16,6 +21,12 @@ #include <boost/mpl/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/tag_cast.hpp> + namespace boost { namespace geometry { @@ -30,23 +41,39 @@ namespace services /*! \brief Traits class binding a within determination strategy to a coordinate system \ingroup within -\tparam TagContained tag (possibly casted) of point-type -\tparam TagContained tag (possibly casted) of (possibly) containing type -\tparam CsTagContained tag of coordinate system of point-type -\tparam CsTagContaining tag of coordinate system of (possibly) containing type -\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContained geometry-type of input (possibly) contained type \tparam GeometryContaining geometry-type of input (possibly) containing type +\tparam TagContained casted tag of (possibly) contained type +\tparam TagContaining casted tag of (possibly) containing type +\tparam CsTagContained tag of coordinate system of (possibly) contained type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type */ template < - typename TagContained, - typename TagContaining, - typename CastedTagContained, - typename CastedTagContaining, - typename CsTagContained, - typename CsTagContaining, typename GeometryContained, - typename GeometryContaining + typename GeometryContaining, + typename TagContained = typename tag<GeometryContained>::type, + typename TagContaining = typename tag<GeometryContaining>::type, + typename CastedTagContained = typename tag_cast + < + typename tag<GeometryContained>::type, + pointlike_tag, linear_tag, polygonal_tag, areal_tag + >::type, + typename CastedTagContaining = typename tag_cast + < + typename tag<GeometryContaining>::type, + pointlike_tag, linear_tag, polygonal_tag, areal_tag + >::type, + typename CsTagContained = typename tag_cast + < + typename cs_tag<typename point_type<GeometryContained>::type>::type, + spherical_tag + >::type, + typename CsTagContaining = typename tag_cast + < + typename cs_tag<typename point_type<GeometryContaining>::type>::type, + spherical_tag + >::type > struct default_strategy { diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp index 234cfa1ed0..b1c3648c98 100644 --- a/boost/geometry/util/math.hpp +++ b/boost/geometry/util/math.hpp @@ -71,6 +71,19 @@ inline T const& greatest(T const& v1, T const& v2, T const& v3, T const& v4, T c } +template <typename T> +inline T bounded(T const& v, T const& lower, T const& upper) +{ + return (std::min)((std::max)(v, lower), upper); +} + +template <typename T> +inline T bounded(T const& v, T const& lower) +{ + return (std::max)(v, lower); +} + + template <typename T, bool IsFloatingPoint = boost::is_floating_point<T>::value> struct abs @@ -518,7 +531,7 @@ inline T scaled_epsilon(T const& value) } -// Maybe replace this by boost equals or boost ublas numeric equals or so +// Maybe replace this by boost equals or so /*! \brief returns true if both arguments are equal. diff --git a/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/boost/geometry/util/normalize_spheroidal_coordinates.hpp index 377051eef1..19d4d33d28 100644 --- a/boost/geometry/util/normalize_spheroidal_coordinates.hpp +++ b/boost/geometry/util/normalize_spheroidal_coordinates.hpp @@ -282,6 +282,40 @@ inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitud return diff; } +/*! +\brief The abs difference between longitudes in range [0, 180]. +\tparam Units The units of the coordindate system in the spheroid +\tparam CoordinateType The type of the coordinates +\param longitude1 Longitude 1 +\param longitude2 Longitude 2 +\ingroup utility +*/ +template <typename Units, typename CoordinateType> +inline CoordinateType longitude_difference(CoordinateType const& longitude1, + CoordinateType const& longitude2) +{ + return math::abs(math::longitude_distance_signed<Units>(longitude1, longitude2)); +} + +template <typename Units, typename CoordinateType> +inline CoordinateType longitude_interval_distance_signed(CoordinateType const& longitude_a1, + CoordinateType const& longitude_a2, + CoordinateType const& longitude_b) +{ + CoordinateType const c0 = 0; + CoordinateType dist_a12 = longitude_distance_signed<Units>(longitude_a1, longitude_a2); + CoordinateType dist_a1b = longitude_distance_signed<Units>(longitude_a1, longitude_b); + if (dist_a12 < c0) + { + dist_a12 = -dist_a12; + dist_a1b = -dist_a1b; + } + + return dist_a1b < c0 ? dist_a1b + : dist_a1b > dist_a12 ? dist_a1b - dist_a12 + : c0; +} + } // namespace math |