Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:48

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
0004 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
0005 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
0006 
0007 // This file was modified by Oracle on 2014-2020.
0008 // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates.
0009 
0010 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0011 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0012 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0013 
0014 // Use, modification and distribution is subject to the Boost Software License,
0015 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0016 // http://www.boost.org/LICENSE_1_0.txt)
0017 
0018 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
0019 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
0020 
0021 
0022 #include <type_traits>
0023 
0024 #include <boost/config.hpp>
0025 #include <boost/concept_check.hpp>
0026 
0027 #include <boost/geometry/core/access.hpp>
0028 #include <boost/geometry/core/assert.hpp>
0029 #include <boost/geometry/core/point_type.hpp>
0030 #include <boost/geometry/core/radian_access.hpp>
0031 #include <boost/geometry/core/tags.hpp>
0032 
0033 #include <boost/geometry/strategies/distance.hpp>
0034 #include <boost/geometry/strategies/concepts/distance_concept.hpp>
0035 #include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
0036 
0037 #include <boost/geometry/util/math.hpp>
0038 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
0039 
0040 
0041 namespace boost { namespace geometry
0042 {
0043 
0044 namespace strategy { namespace distance
0045 {
0046 
0047 namespace details
0048 {
0049 
0050 template <typename ReturnType>
0051 class cross_track_point_box_generic
0052 {
0053 public :
0054 
0055     template
0056     <
0057             typename Point,
0058             typename Box,
0059             typename Strategy
0060     >
0061     ReturnType static inline apply (Point const& point,
0062                                     Box const& box,
0063                                     Strategy ps_strategy)
0064     {
0065         // this method assumes that the coordinates of the point and
0066         // the box are normalized
0067 
0068         typedef typename point_type<Box>::type box_point_type;
0069 
0070         box_point_type bottom_left, bottom_right, top_left, top_right;
0071         geometry::detail::assign_box_corners(box,
0072                                              bottom_left, bottom_right,
0073                                              top_left, top_right);
0074 
0075         ReturnType const plon = geometry::get_as_radian<0>(point);
0076         ReturnType const plat = geometry::get_as_radian<1>(point);
0077 
0078         ReturnType const lon_min = geometry::get_as_radian<0>(bottom_left);
0079         ReturnType const lat_min = geometry::get_as_radian<1>(bottom_left);
0080         ReturnType const lon_max = geometry::get_as_radian<0>(top_right);
0081         ReturnType const lat_max = geometry::get_as_radian<1>(top_right);
0082 
0083         ReturnType const pi = math::pi<ReturnType>();
0084         ReturnType const two_pi = math::two_pi<ReturnType>();
0085 
0086         typedef typename point_type<Box>::type box_point_type;
0087 
0088         // First check if the point is within the band defined by the
0089         // minimum and maximum longitude of the box; if yes, determine
0090         // if the point is above, below or inside the box and compute
0091         // the distance (easy in this case)
0092         //
0093         // Notice that the point may not be inside the longitude range
0094         // of the box, but the shifted point may be inside the
0095         // longitude range of the box; in this case the point is still
0096         // considered as inside the longitude range band of the box
0097         if ((plon >= lon_min && plon <= lon_max) || plon + two_pi <= lon_max)
0098         {
0099             if (plat > lat_max)
0100             {
0101                 return geometry::strategy::distance::services::result_from_distance
0102                         <
0103                             Strategy, Point, box_point_type
0104                         >::apply(ps_strategy, ps_strategy
0105                                  .vertical_or_meridian(plat, lat_max));
0106             }
0107             else if (plat < lat_min)
0108             {
0109                 return geometry::strategy::distance::services::result_from_distance
0110                         <
0111                             Strategy, Point, box_point_type
0112                         >::apply(ps_strategy, ps_strategy
0113                                  .vertical_or_meridian(lat_min, plat));
0114             }
0115             else
0116             {
0117                 BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
0118                 return ReturnType(0);
0119             }
0120         }
0121 
0122         // Otherwise determine which among the two medirian segments of the
0123         // box the point is closest to, and compute the distance of
0124         // the point to this closest segment
0125 
0126         // Below lon_midway is the longitude of the meridian that:
0127         // (1) is midway between the meridians of the left and right
0128         //     meridians of the box, and
0129         // (2) does not intersect the box
0130         ReturnType const two = 2.0;
0131         bool use_left_segment;
0132         if (lon_max > pi)
0133         {
0134             // the box crosses the antimeridian
0135 
0136             // midway longitude = lon_min - (lon_min + (lon_max - 2 * pi)) / 2;
0137             ReturnType const lon_midway = (lon_min - lon_max) / two + pi;
0138             BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
0139 
0140             use_left_segment = plon > lon_midway;
0141         }
0142         else
0143         {
0144             // the box does not cross the antimeridian
0145 
0146             ReturnType const lon_sum = lon_min + lon_max;
0147             if (math::equals(lon_sum, ReturnType(0)))
0148             {
0149                 // special case: the box is symmetric with respect to
0150                 // the prime meridian; the midway meridian is the antimeridian
0151 
0152                 use_left_segment = plon < lon_min;
0153             }
0154             else
0155             {
0156                 // midway long. = lon_min - (2 * pi - (lon_max - lon_min)) / 2;
0157                 ReturnType lon_midway = (lon_min + lon_max) / two - pi;
0158 
0159                 // normalize the midway longitude
0160                 if (lon_midway > pi)
0161                 {
0162                     lon_midway -= two_pi;
0163                 }
0164                 else if (lon_midway < -pi)
0165                 {
0166                     lon_midway += two_pi;
0167                 }
0168                 BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
0169 
0170                 // if lon_sum is positive the midway meridian is left
0171                 // of the box, or right of the box otherwise
0172                 use_left_segment = lon_sum > 0
0173                         ? (plon < lon_min && plon >= lon_midway)
0174                         : (plon <= lon_max || plon > lon_midway);
0175             }
0176         }
0177 
0178         return use_left_segment
0179                 ? ps_strategy.apply(point, bottom_left, top_left)
0180                 : ps_strategy.apply(point, bottom_right, top_right);
0181     }
0182 };
0183 
0184 }  //namespace details
0185 
0186 /*!
0187 \brief Strategy functor for distance point to box calculation
0188 \ingroup strategies
0189 \details Class which calculates the distance of a point to a box, for
0190 points and boxes on a sphere or globe
0191 \tparam CalculationType \tparam_calculation
0192 \tparam Strategy underlying point-point distance strategy
0193 \qbk{
0194 [heading See also]
0195 [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
0196 }
0197 */
0198 template
0199 <
0200     typename CalculationType = void,
0201     typename Strategy = haversine<double, CalculationType>
0202 >
0203 class cross_track_point_box
0204 {
0205 public:
0206     template <typename Point, typename Box>
0207     struct return_type
0208         : services::return_type<Strategy, Point, typename point_type<Box>::type>
0209     {};
0210 
0211     typedef typename Strategy::radius_type radius_type;
0212 
0213     // strategy getters
0214 
0215     // point-segment strategy getters
0216     struct distance_ps_strategy
0217     {
0218         typedef cross_track<CalculationType, Strategy> type;
0219     };
0220 
0221     typedef typename strategy::distance::services::comparable_type
0222         <
0223             Strategy
0224         >::type pp_comparable_strategy;
0225 
0226     typedef std::conditional_t
0227         <
0228             std::is_same
0229                 <
0230                     pp_comparable_strategy,
0231                     Strategy
0232                 >::value,
0233             typename strategy::distance::services::comparable_type
0234                 <
0235                     typename distance_ps_strategy::type
0236                 >::type,
0237             typename distance_ps_strategy::type
0238         > ps_strategy_type;
0239 
0240     // constructors
0241 
0242     inline cross_track_point_box()
0243     {}
0244 
0245     explicit inline cross_track_point_box(typename Strategy::radius_type const& r)
0246         : m_strategy(r)
0247     {}
0248 
0249     inline cross_track_point_box(Strategy const& s)
0250         : m_strategy(s)
0251     {}
0252 
0253 
0254     // methods
0255 
0256     // It might be useful in the future
0257     // to overload constructor with strategy info.
0258     // crosstrack(...) {}
0259 
0260     template <typename Point, typename Box>
0261     inline typename return_type<Point, Box>::type
0262     apply(Point const& point, Box const& box) const
0263     {
0264 #if !defined(BOOST_MSVC)
0265         BOOST_CONCEPT_ASSERT
0266             (
0267                 (concepts::PointDistanceStrategy
0268                     <
0269                         Strategy, Point, typename point_type<Box>::type
0270                     >)
0271             );
0272 #endif
0273         typedef typename return_type<Point, Box>::type return_type;
0274         return details::cross_track_point_box_generic
0275                     <return_type>::apply(point, box,
0276                                          ps_strategy_type(m_strategy));
0277     }
0278 
0279     inline typename Strategy::radius_type radius() const
0280     {
0281         return m_strategy.radius();
0282     }
0283 
0284 private:
0285     Strategy m_strategy;
0286 };
0287 
0288 
0289 
0290 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0291 namespace services
0292 {
0293 
0294 template <typename CalculationType, typename Strategy>
0295 struct tag<cross_track_point_box<CalculationType, Strategy> >
0296 {
0297     typedef strategy_tag_distance_point_box type;
0298 };
0299 
0300 
0301 template <typename CalculationType, typename Strategy, typename P, typename Box>
0302 struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box>
0303     : cross_track_point_box
0304         <
0305             CalculationType, Strategy
0306         >::template return_type<P, Box>
0307 {};
0308 
0309 
0310 template <typename CalculationType, typename Strategy>
0311 struct comparable_type<cross_track_point_box<CalculationType, Strategy> >
0312 {
0313     typedef cross_track_point_box
0314         <
0315             CalculationType, typename comparable_type<Strategy>::type
0316         > type;
0317 };
0318 
0319 
0320 template <typename CalculationType, typename Strategy>
0321 struct get_comparable<cross_track_point_box<CalculationType, Strategy> >
0322 {
0323     typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
0324     typedef typename comparable_type<this_strategy>::type comparable_type;
0325 
0326 public:
0327     static inline comparable_type apply(this_strategy const& strategy)
0328     {
0329         return comparable_type(strategy.radius());
0330     }
0331 };
0332 
0333 
0334 template <typename CalculationType, typename Strategy, typename P, typename Box>
0335 struct result_from_distance
0336     <
0337         cross_track_point_box<CalculationType, Strategy>, P, Box
0338     >
0339 {
0340 private:
0341     typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
0342 
0343     typedef typename this_strategy::template return_type
0344         <
0345             P, Box
0346         >::type return_type;
0347 
0348 public:
0349     template <typename T>
0350     static inline return_type apply(this_strategy const& strategy,
0351                                     T const& distance)
0352     {
0353         Strategy s(strategy.radius());
0354 
0355         return result_from_distance
0356             <
0357                 Strategy, P, typename point_type<Box>::type
0358             >::apply(s, distance);
0359     }
0360 };
0361 
0362 
0363 // define cross_track_point_box<default_point_segment_strategy> as
0364 // default point-box strategy for the spherical equatorial coordinate system
0365 template <typename Point, typename Box, typename Strategy>
0366 struct default_strategy
0367     <
0368         point_tag, box_tag, Point, Box,
0369         spherical_equatorial_tag, spherical_equatorial_tag,
0370         Strategy
0371     >
0372 {
0373     typedef cross_track_point_box
0374         <
0375             void,
0376             std::conditional_t
0377                 <
0378                     std::is_void<Strategy>::value,
0379                     typename default_strategy
0380                         <
0381                             point_tag, point_tag,
0382                             Point, typename point_type<Box>::type,
0383                             spherical_equatorial_tag, spherical_equatorial_tag
0384                         >::type,
0385                     Strategy
0386                 >
0387         > type;
0388 };
0389 
0390 
0391 template <typename Box, typename Point, typename Strategy>
0392 struct default_strategy
0393     <
0394         box_tag, point_tag, Box, Point,
0395         spherical_equatorial_tag, spherical_equatorial_tag,
0396         Strategy
0397     >
0398 {
0399     typedef typename default_strategy
0400         <
0401             point_tag, box_tag, Point, Box,
0402             spherical_equatorial_tag, spherical_equatorial_tag,
0403             Strategy
0404         >::type type;
0405 };
0406 
0407 
0408 } // namespace services
0409 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0410 
0411 
0412 }} // namespace strategy::distance
0413 
0414 
0415 }} // namespace boost::geometry
0416 
0417 
0418 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP