summaryrefslogtreecommitdiff
path: root/boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp')
-rw-r--r--boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp440
1 files changed, 440 insertions, 0 deletions
diff --git a/boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp b/boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp
new file mode 100644
index 0000000000..efa7a728a6
--- /dev/null
+++ b/boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp
@@ -0,0 +1,440 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2016-2018 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_DISTANCE_CROSS_TRACK_BOX_BOX_HPP
+#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_BOX_BOX_HPP
+
+#include <boost/config.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_void.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/assert.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/concepts/distance_concept.hpp>
+#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+namespace details
+{
+
+template <typename ReturnType>
+class cross_track_box_box_generic
+{
+public :
+
+ template <typename Point, typename Strategy>
+ ReturnType static inline diagonal_case(Point topA,
+ Point topB,
+ Point bottomA,
+ Point bottomB,
+ bool north_shortest,
+ bool non_overlap,
+ Strategy ps_strategy)
+ {
+ if (north_shortest && non_overlap)
+ {
+ return ps_strategy.get_distance_strategy().apply(topA, bottomB);
+ }
+ if (north_shortest && !non_overlap)
+ {
+ return ps_strategy.apply(topA, topB, bottomB);
+ }
+ if (!north_shortest && non_overlap)
+ {
+ return ps_strategy.get_distance_strategy().apply(bottomA, topB);
+ }
+ return ps_strategy.apply(bottomA, topB, bottomB);
+ }
+
+
+ template
+ <
+ typename Box1,
+ typename Box2,
+ typename Strategy
+ >
+ ReturnType static inline apply (Box1 const& box1,
+ Box2 const& box2,
+ Strategy ps_strategy)
+ {
+
+ // this method assumes that the coordinates of the point and
+ // the box are normalized
+
+ typedef typename point_type<Box1>::type box_point_type1;
+ typedef typename point_type<Box2>::type box_point_type2;
+
+ box_point_type1 bottom_left1, bottom_right1, top_left1, top_right1;
+ geometry::detail::assign_box_corners(box1,
+ bottom_left1, bottom_right1,
+ top_left1, top_right1);
+
+ box_point_type2 bottom_left2, bottom_right2, top_left2, top_right2;
+ geometry::detail::assign_box_corners(box2,
+ bottom_left2, bottom_right2,
+ top_left2, top_right2);
+
+ ReturnType lon_min1 = geometry::get_as_radian<0>(bottom_left1);
+ ReturnType const lat_min1 = geometry::get_as_radian<1>(bottom_left1);
+ ReturnType lon_max1 = geometry::get_as_radian<0>(top_right1);
+ ReturnType const lat_max1 = geometry::get_as_radian<1>(top_right1);
+
+ ReturnType lon_min2 = geometry::get_as_radian<0>(bottom_left2);
+ ReturnType const lat_min2 = geometry::get_as_radian<1>(bottom_left2);
+ ReturnType lon_max2 = geometry::get_as_radian<0>(top_right2);
+ ReturnType const lat_max2 = geometry::get_as_radian<1>(top_right2);
+
+ ReturnType const two_pi = math::two_pi<ReturnType>();
+
+ // Test which sides of the boxes are closer and if boxes cross
+ // antimeridian
+ bool right_wrap;
+
+ if (lon_min2 > 0 && lon_max2 < 0) // box2 crosses antimeridian
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(box2 crosses antimeridian)";
+#endif
+ right_wrap = lon_min2 - lon_max1 < lon_min1 - lon_max2;
+ lon_max2 += two_pi;
+ if (lon_min1 > 0 && lon_max1 < 0) // both boxes crosses antimeridian
+ {
+ lon_max1 += two_pi;
+ }
+ }
+ else if (lon_min1 > 0 && lon_max1 < 0) // only box1 crosses antimeridian
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(box1 crosses antimeridian)";
+#endif
+ return apply(box2, box1, ps_strategy);
+ }
+ else
+ {
+ right_wrap = lon_max1 <= lon_min2
+ ? lon_min2 - lon_max1 < two_pi - (lon_max2 - lon_min1)
+ : lon_min1 - lon_max2 > two_pi - (lon_max1 - lon_min2);
+
+ }
+
+ // Check1: if box2 crosses the band defined by the
+ // minimum and maximum longitude of box1; if yes, determine
+ // if the box2 is above, below or intersects/is inside box1 and compute
+ // the distance (easy in this case)
+
+ bool lon_min12 = lon_min1 <= lon_min2;
+ bool right = lon_max1 <= lon_min2;
+ bool left = lon_min1 >= lon_max2;
+ bool lon_max12 = lon_max1 <= lon_max2;
+
+ if ((lon_min12 && !right)
+ || (!left && !lon_max12)
+ || (!lon_min12 && lon_max12))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(up-down)\n";
+#endif
+ if (lat_min1 > lat_max2)
+ {
+ return geometry::strategy::distance::services::result_from_distance
+ <
+ Strategy, box_point_type1, box_point_type2
+ >::apply(ps_strategy, ps_strategy.get_distance_strategy()
+ .meridian(lat_min1, lat_max2));
+ }
+ else if (lat_max1 < lat_min2)
+ {
+ return geometry::strategy::distance::services::result_from_distance
+ <
+ Strategy, box_point_type1, box_point_type2
+ >::apply(ps_strategy, ps_strategy.get_distance_strategy().
+ meridian(lat_min2, lat_max1));
+ }
+ else
+ {
+ //BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
+ return ReturnType(0);
+ }
+ }
+
+ // Check2: if box2 is right/left of box1
+ // the max lat of box2 should be less than the max lat of box1
+ bool bottom_max;
+
+ ReturnType top_common = (std::min)(lat_max1, lat_max2);
+ ReturnType bottom_common = (std::max)(lat_min1, lat_min2);
+
+ // true if the closest points are on northern hemisphere
+ bool north_shortest = top_common + bottom_common > 0;
+ // true if box bands do not overlap
+ bool non_overlap = top_common < bottom_common;
+
+ if (north_shortest)
+ {
+ bottom_max = lat_max1 >= lat_max2;
+ }
+ else
+ {
+ bottom_max = lat_min1 <= lat_min2;
+ }
+
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(diagonal)";
+#endif
+ if (bottom_max && !right_wrap)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(bottom left)";
+#endif
+ return diagonal_case(top_right2, top_left1,
+ bottom_right2, bottom_left1,
+ north_shortest, non_overlap,
+ ps_strategy);
+ }
+ if (bottom_max && right_wrap)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(bottom right)";
+#endif
+ return diagonal_case(top_left2, top_right1,
+ bottom_left2, bottom_right1,
+ north_shortest, non_overlap,
+ ps_strategy);
+ }
+ if (!bottom_max && !right_wrap)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(top left)";
+#endif
+ return diagonal_case(top_left1, top_right2,
+ bottom_left1, bottom_right2,
+ north_shortest, non_overlap,
+ ps_strategy);
+ }
+ if (!bottom_max && right_wrap)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
+ std::cout << "(top right)";
+#endif
+ return diagonal_case(top_right1, top_left2,
+ bottom_right1, bottom_left2,
+ north_shortest, non_overlap,
+ ps_strategy);
+ }
+ return ReturnType(0);
+ }
+};
+
+} //namespace details
+
+/*!
+\brief Strategy functor for distance box to box calculation
+\ingroup strategies
+\details Class which calculates the distance of a box to a box, for
+boxes on a sphere or globe
+\tparam CalculationType \tparam_calculation
+\tparam Strategy underlying point-segment distance strategy, defaults
+to cross track
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
+}
+*/
+template
+<
+ typename CalculationType = void,
+ typename Strategy = cross_track<CalculationType>
+>
+class cross_track_box_box
+{
+public:
+ template <typename Box1, typename Box2>
+ struct return_type
+ : services::return_type<Strategy,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type>
+ {};
+
+ typedef typename Strategy::radius_type radius_type;
+
+ inline cross_track_box_box()
+ {}
+
+ explicit inline cross_track_box_box(typename Strategy::radius_type const& r)
+ : m_ps_strategy(r)
+ {}
+
+ inline cross_track_box_box(Strategy const& s)
+ : m_ps_strategy(s)
+ {}
+
+
+ // It might be useful in the future
+ // to overload constructor with strategy info.
+ // crosstrack(...) {}
+
+ template <typename Box1, typename Box2>
+ inline typename return_type<Box1, Box2>::type
+ apply(Box1 const& box1, Box2 const& box2) const
+ {
+#if !defined(BOOST_MSVC)
+ BOOST_CONCEPT_ASSERT
+ (
+ (concepts::PointSegmentDistanceStrategy
+ <
+ Strategy,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >)
+ );
+#endif
+ typedef typename return_type<Box1, Box2>::type return_type;
+ return details::cross_track_box_box_generic
+ <return_type>::apply(box1, box2, m_ps_strategy);
+ }
+
+ inline typename Strategy::radius_type radius() const
+ {
+ return m_ps_strategy.radius();
+ }
+
+private:
+ Strategy m_ps_strategy;
+};
+
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+template <typename CalculationType, typename Strategy>
+struct tag<cross_track_box_box<CalculationType, Strategy> >
+{
+ typedef strategy_tag_distance_box_box type;
+};
+
+
+template <typename CalculationType, typename Strategy, typename Box1, typename Box2>
+struct return_type<cross_track_box_box<CalculationType, Strategy>, Box1, Box2>
+ : cross_track_box_box
+ <
+ CalculationType, Strategy
+ >::template return_type<Box1, Box2>
+{};
+
+
+template <typename CalculationType, typename Strategy>
+struct comparable_type<cross_track_box_box<CalculationType, Strategy> >
+{
+ typedef cross_track_box_box
+ <
+ CalculationType, typename comparable_type<Strategy>::type
+ > type;
+};
+
+
+template <typename CalculationType, typename Strategy>
+struct get_comparable<cross_track_box_box<CalculationType, Strategy> >
+{
+ typedef cross_track_box_box<CalculationType, Strategy> this_strategy;
+ typedef typename comparable_type<this_strategy>::type comparable_type;
+
+public:
+ static inline comparable_type apply(this_strategy const& strategy)
+ {
+ return comparable_type(strategy.radius());
+ }
+};
+
+
+template <typename CalculationType, typename Strategy, typename Box1, typename Box2>
+struct result_from_distance
+ <
+ cross_track_box_box<CalculationType, Strategy>, Box1, Box2
+ >
+{
+private:
+ typedef cross_track_box_box<CalculationType, Strategy> this_strategy;
+
+ typedef typename this_strategy::template return_type
+ <
+ Box1, Box2
+ >::type return_type;
+
+public:
+ template <typename T>
+ static inline return_type apply(this_strategy const& strategy,
+ T const& distance)
+ {
+ Strategy s(strategy.radius());
+
+ return result_from_distance
+ <
+ Strategy,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >::apply(s, distance);
+ }
+};
+
+
+// define cross_track_box_box<default_point_segment_strategy> as
+// default box-box strategy for the spherical equatorial coordinate system
+template <typename Box1, typename Box2, typename Strategy>
+struct default_strategy
+ <
+ box_tag, box_tag, Box1, Box2,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >
+{
+ typedef cross_track_box_box
+ <
+ void,
+ typename boost::mpl::if_
+ <
+ boost::is_void<Strategy>,
+ typename default_strategy
+ <
+ point_tag, segment_tag,
+ typename point_type<Box1>::type, typename point_type<Box2>::type,
+ spherical_equatorial_tag, spherical_equatorial_tag
+ >::type,
+ Strategy
+ >::type
+ > type;
+};
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_BOX_BOX_HPP