1 // Boost.Geometry
2 
3 // Copyright (c) 2021, Oracle and/or its affiliates.
4 
5 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
6 
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_STRATEGIES_DISTANCE_GEOGRAPHIC_HPP
11 #define BOOST_GEOMETRY_STRATEGIES_DISTANCE_GEOGRAPHIC_HPP
12 
13 
14 #include <boost/geometry/strategies/distance/comparable.hpp>
15 #include <boost/geometry/strategies/distance/detail.hpp>
16 #include <boost/geometry/strategies/distance/services.hpp>
17 #include <boost/geometry/strategies/detail.hpp>
18 
19 #include <boost/geometry/strategies/geographic/azimuth.hpp>
20 
21 #include <boost/geometry/strategies/geographic/distance.hpp>
22 #include <boost/geometry/strategies/geographic/distance_cross_track.hpp>
23 #include <boost/geometry/strategies/geographic/distance_cross_track_box_box.hpp>
24 #include <boost/geometry/strategies/geographic/distance_cross_track_point_box.hpp>
25 #include <boost/geometry/strategies/geographic/distance_segment_box.hpp>
26 // TODO - for backwards compatibility, remove?
27 #include <boost/geometry/strategies/geographic/distance_andoyer.hpp>
28 #include <boost/geometry/strategies/geographic/distance_thomas.hpp>
29 #include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
30 
31 #include <boost/geometry/strategies/normalize.hpp>
32 #include <boost/geometry/strategies/relate/geographic.hpp>
33 
34 
35 namespace boost { namespace geometry
36 {
37 
38 namespace strategies { namespace distance
39 {
40 
41 // TODO: azimuth and normalize getters would not be needed if distance_segment_box was implemented differently
42 //       right now it calls disjoint algorithm details.
43 
44 template
45 <
46     typename FormulaPolicy = strategy::andoyer,
47     typename Spheroid = srs::spheroid<double>,
48     typename CalculationType = void
49 >
50 class geographic
51     : public strategies::relate::geographic<FormulaPolicy, Spheroid, CalculationType>
52 {
53     using base_t = strategies::relate::geographic<FormulaPolicy, Spheroid, CalculationType>;
54 
55 public:
56     geographic() = default;
57 
geographic(Spheroid const & spheroid)58     explicit geographic(Spheroid const& spheroid)
59         : base_t(spheroid)
60     {}
61 
62     // azimuth
63 
azimuth() const64     auto azimuth() const
65     {
66         return strategy::azimuth::geographic
67             <
68                 FormulaPolicy, Spheroid, CalculationType
69             >(base_t::m_spheroid);
70     }
71 
72     // distance
73 
74     template <typename Geometry1, typename Geometry2>
distance(Geometry1 const &,Geometry2 const &,detail::enable_if_pp_t<Geometry1,Geometry2> * =nullptr) const75     auto distance(Geometry1 const&, Geometry2 const&,
76                   detail::enable_if_pp_t<Geometry1, Geometry2> * = nullptr) const
77     {
78         return strategy::distance::geographic
79                 <
80                     FormulaPolicy, Spheroid, CalculationType
81                 >(base_t::m_spheroid);
82     }
83 
84     template <typename Geometry1, typename Geometry2>
distance(Geometry1 const &,Geometry2 const &,detail::enable_if_ps_t<Geometry1,Geometry2> * =nullptr) const85     auto distance(Geometry1 const&, Geometry2 const&,
86                   detail::enable_if_ps_t<Geometry1, Geometry2> * = nullptr) const
87     {
88         return strategy::distance::geographic_cross_track
89             <
90                 FormulaPolicy, Spheroid, CalculationType
91             >(base_t::m_spheroid);
92     }
93 
94     template <typename Geometry1, typename Geometry2>
distance(Geometry1 const &,Geometry2 const &,detail::enable_if_pb_t<Geometry1,Geometry2> * =nullptr) const95     auto distance(Geometry1 const&, Geometry2 const&,
96                   detail::enable_if_pb_t<Geometry1, Geometry2> * = nullptr) const
97     {
98         return strategy::distance::geographic_cross_track_point_box
99             <
100                 FormulaPolicy, Spheroid, CalculationType
101             >(base_t::m_spheroid);
102     }
103 
104     template <typename Geometry1, typename Geometry2>
distance(Geometry1 const &,Geometry2 const &,detail::enable_if_sb_t<Geometry1,Geometry2> * =nullptr) const105     auto distance(Geometry1 const&, Geometry2 const&,
106                   detail::enable_if_sb_t<Geometry1, Geometry2> * = nullptr) const
107     {
108         return strategy::distance::geographic_segment_box
109             <
110                 FormulaPolicy, Spheroid, CalculationType
111             >(base_t::m_spheroid);
112     }
113 
114     template <typename Geometry1, typename Geometry2>
distance(Geometry1 const &,Geometry2 const &,detail::enable_if_bb_t<Geometry1,Geometry2> * =nullptr) const115     auto distance(Geometry1 const&, Geometry2 const&,
116                   detail::enable_if_bb_t<Geometry1, Geometry2> * = nullptr) const
117     {
118         return strategy::distance::geographic_cross_track_box_box
119             <
120                 FormulaPolicy, Spheroid, CalculationType
121             >(base_t::m_spheroid);
122     }
123 
124     // normalize
125 
126     template <typename Geometry>
normalize(Geometry const &,std::enable_if_t<util::is_point<Geometry>::value> * =nullptr)127     static auto normalize(Geometry const&,
128                           std::enable_if_t
129                             <
130                                 util::is_point<Geometry>::value
131                             > * = nullptr)
132     {
133         return strategy::normalize::spherical_point();
134     }
135 };
136 
137 
138 namespace services
139 {
140 
141 template <typename Geometry1, typename Geometry2>
142 struct default_strategy<Geometry1, Geometry2, geographic_tag, geographic_tag>
143 {
144     using type = strategies::distance::geographic<>;
145 };
146 
147 
148 template <typename FP, typename S, typename CT>
149 struct strategy_converter<strategy::distance::geographic<FP, S, CT> >
150 {
getboost::geometry::strategies::distance::services::strategy_converter151     static auto get(strategy::distance::geographic<FP, S, CT> const& s)
152     {
153         return strategies::distance::geographic<FP, S, CT>(s.model());
154     }
155 };
156 // TODO - for backwards compatibility, remove?
157 template <typename S, typename CT>
158 struct strategy_converter<strategy::distance::andoyer<S, CT> >
159 {
getboost::geometry::strategies::distance::services::strategy_converter160     static auto get(strategy::distance::andoyer<S, CT> const& s)
161     {
162         return strategies::distance::geographic<strategy::andoyer, S, CT>(s.model());
163     }
164 };
165 // TODO - for backwards compatibility, remove?
166 template <typename S, typename CT>
167 struct strategy_converter<strategy::distance::thomas<S, CT> >
168 {
getboost::geometry::strategies::distance::services::strategy_converter169     static auto get(strategy::distance::thomas<S, CT> const& s)
170     {
171         return strategies::distance::geographic<strategy::thomas, S, CT>(s.model());
172     }
173 };
174 // TODO - for backwards compatibility, remove?
175 template <typename S, typename CT>
176 struct strategy_converter<strategy::distance::vincenty<S, CT> >
177 {
getboost::geometry::strategies::distance::services::strategy_converter178     static auto get(strategy::distance::vincenty<S, CT> const& s)
179     {
180         return strategies::distance::geographic<strategy::vincenty, S, CT>(s.model());
181     }
182 };
183 
184 template <typename FP, typename S, typename CT>
185 struct strategy_converter<strategy::distance::geographic_cross_track<FP, S, CT> >
186 {
getboost::geometry::strategies::distance::services::strategy_converter187     static auto get(strategy::distance::geographic_cross_track<FP, S, CT> const& s)
188     {
189         return strategies::distance::geographic<FP, S, CT>(s.model());
190     }
191 };
192 
193 template <typename FP, typename S, typename CT>
194 struct strategy_converter<strategy::distance::geographic_cross_track_point_box<FP, S, CT> >
195 {
getboost::geometry::strategies::distance::services::strategy_converter196     static auto get(strategy::distance::geographic_cross_track_point_box<FP, S, CT> const& s)
197     {
198         return strategies::distance::geographic<FP, S, CT>(s.model());
199     }
200 };
201 
202 template <typename FP, typename S, typename CT>
203 struct strategy_converter<strategy::distance::geographic_segment_box<FP, S, CT> >
204 {
getboost::geometry::strategies::distance::services::strategy_converter205     static auto get(strategy::distance::geographic_segment_box<FP, S, CT> const& s)
206     {
207         return strategies::distance::geographic<FP, S, CT>(s.model());
208     }
209 };
210 
211 template <typename FP, typename S, typename CT>
212 struct strategy_converter<strategy::distance::geographic_cross_track_box_box<FP, S, CT> >
213 {
getboost::geometry::strategies::distance::services::strategy_converter214     static auto get(strategy::distance::geographic_cross_track_box_box<FP, S, CT> const& s)
215     {
216         return strategies::distance::geographic<FP, S, CT>(s.model());
217     }
218 };
219 
220 
221 // details
222 
223 // TODO: This specialization wouldn't be needed if strategy::distance::geographic_cross_track was implemented as an alias
224 template <typename FP, typename S, typename CT, bool B, bool ECP>
225 struct strategy_converter<strategy::distance::detail::geographic_cross_track<FP, S, CT, B, ECP> >
226 {
227     struct altered_strategy
228         : strategies::distance::geographic<FP, S, CT>
229     {
230         typedef strategies::distance::geographic<FP, S, CT> base_t;
231 
altered_strategyboost::geometry::strategies::distance::services::strategy_converter::altered_strategy232         explicit altered_strategy(S const& s) : base_t(s) {}
233 
234         using base_t::distance;
235 
236         template <typename Geometry1, typename Geometry2>
distanceboost::geometry::strategies::distance::services::strategy_converter::altered_strategy237         auto distance(Geometry1 const&, Geometry2 const&,
238                       detail::enable_if_ps_t<Geometry1, Geometry2> * = nullptr) const
239         {
240             return strategy::distance::detail::geographic_cross_track
241                 <
242                     FP, S, CT, B, ECP
243                 >(base_t::m_spheroid);
244         }
245     };
246 
getboost::geometry::strategies::distance::services::strategy_converter247     static auto get(strategy::distance::detail::geographic_cross_track<FP, S, CT, B, ECP> const& s)
248     {
249         return altered_strategy(s.model());
250     }
251 };
252 
253 
254 } // namespace services
255 
256 }} // namespace strategies::distance
257 
258 }} // namespace boost::geometry
259 
260 #endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_GEOGRAPHIC_HPP
261