1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
6 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
7 // Copyright (c) 2014 Samuel Debionne, Grenoble, France.
8 
9 // This file was modified by Oracle on 2014, 2018.
10 // Modifications copyright (c) 2014-2018, Oracle and/or its affiliates.
11 
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
14 
15 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
16 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
17 
18 // Use, modification and distribution is subject to the Boost Software License,
19 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
20 // http://www.boost.org/LICENSE_1_0.txt)
21 
22 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
23 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
24 
25 #include <boost/concept_check.hpp>
26 
27 #include <boost/mpl/always.hpp>
28 #include <boost/mpl/bool.hpp>
29 #include <boost/mpl/vector.hpp>
30 
31 #include <boost/geometry/core/point_type.hpp>
32 
33 #include <boost/geometry/geometries/concepts/check.hpp>
34 
35 #include <boost/geometry/strategies/default_strategy.hpp>
36 #include <boost/geometry/strategies/distance.hpp>
37 #include <boost/geometry/strategies/default_distance_result.hpp>
38 #include <boost/geometry/strategies/distance_result.hpp>
39 
40 #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
41 #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
42 
43 #include <boost/geometry/algorithms/dispatch/distance.hpp>
44 
45 
46 namespace boost { namespace geometry
47 {
48 
49 
50 #ifndef DOXYGEN_NO_DISPATCH
51 namespace dispatch
52 {
53 
54 
55 // If reversal is needed, perform it
56 template
57 <
58     typename Geometry1, typename Geometry2, typename Strategy,
59     typename Tag1, typename Tag2, typename StrategyTag
60 >
61 struct distance
62 <
63     Geometry1, Geometry2, Strategy,
64     Tag1, Tag2, StrategyTag,
65     true
66 >
67     : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
68 {
69     typedef typename strategy::distance::services::return_type
70                      <
71                          Strategy,
72                          typename point_type<Geometry2>::type,
73                          typename point_type<Geometry1>::type
74                      >::type return_type;
75 
76     static inline return_type apply(
77         Geometry1 const& g1,
78         Geometry2 const& g2,
79         Strategy const& strategy)
80     {
81         return distance
82             <
83                 Geometry2, Geometry1, Strategy,
84                 Tag2, Tag1, StrategyTag,
85                 false
86             >::apply(g2, g1, strategy);
87     }
88 };
89 
90 
91 } // namespace dispatch
92 #endif // DOXYGEN_NO_DISPATCH
93 
94 
95 namespace resolve_strategy
96 {
97 
98 struct distance
99 {
100     template <typename Geometry1, typename Geometry2, typename Strategy>
101     static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
102     apply(Geometry1 const& geometry1,
103           Geometry2 const& geometry2,
104           Strategy const& strategy)
105     {
106         return dispatch::distance
107             <
108                 Geometry1, Geometry2, Strategy
109             >::apply(geometry1, geometry2, strategy);
110     }
111 
112     template <typename Geometry1, typename Geometry2>
113     static inline
114     typename distance_result<Geometry1, Geometry2, default_strategy>::type
115     apply(Geometry1 const& geometry1,
116           Geometry2 const& geometry2,
117           default_strategy)
118     {
119         typedef typename detail::distance::default_strategy
120             <
121                 Geometry1, Geometry2
122             >::type strategy_type;
123 
124         return dispatch::distance
125             <
126                 Geometry1, Geometry2, strategy_type
127             >::apply(geometry1, geometry2, strategy_type());
128     }
129 };
130 
131 } // namespace resolve_strategy
132 
133 
134 namespace resolve_variant
135 {
136 
137 
138 template <typename Geometry1, typename Geometry2>
139 struct distance
140 {
141     template <typename Strategy>
142     static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
143     apply(Geometry1 const& geometry1,
144           Geometry2 const& geometry2,
145           Strategy const& strategy)
146     {
147         return
148             resolve_strategy::distance::apply(geometry1, geometry2, strategy);
149     }
150 };
151 
152 
153 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
154 struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
155 {
156     template <typename Strategy>
157     struct visitor: static_visitor
158         <
159             typename distance_result
160                 <
161                     variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
162                     Geometry2,
163                     Strategy
164                 >::type
165         >
166     {
167         Geometry2 const& m_geometry2;
168         Strategy const& m_strategy;
169 
170         visitor(Geometry2 const& geometry2,
171                 Strategy const& strategy)
172             : m_geometry2(geometry2),
173               m_strategy(strategy)
174         {}
175 
176         template <typename Geometry1>
177         typename distance_result<Geometry1, Geometry2, Strategy>::type
178         operator()(Geometry1 const& geometry1) const
179         {
180             return distance
181                 <
182                     Geometry1,
183                     Geometry2
184                 >::template apply
185                     <
186                         Strategy
187                     >(geometry1, m_geometry2, m_strategy);
188         }
189     };
190 
191     template <typename Strategy>
192     static inline typename distance_result
193         <
194             variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
195             Geometry2,
196             Strategy
197         >::type
198     apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
199           Geometry2 const& geometry2,
200           Strategy const& strategy)
201     {
202         return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
203     }
204 };
205 
206 
207 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
208 struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
209 {
210     template <typename Strategy>
211     struct visitor: static_visitor
212         <
213             typename distance_result
214                 <
215                     Geometry1,
216                     variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
217                     Strategy
218                 >::type
219         >
220     {
221         Geometry1 const& m_geometry1;
222         Strategy const& m_strategy;
223 
224         visitor(Geometry1 const& geometry1,
225                 Strategy const& strategy)
226             : m_geometry1(geometry1),
227               m_strategy(strategy)
228         {}
229 
230         template <typename Geometry2>
231         typename distance_result<Geometry1, Geometry2, Strategy>::type
232         operator()(Geometry2 const& geometry2) const
233         {
234             return distance
235                 <
236                     Geometry1,
237                     Geometry2
238                 >::template apply
239                 <
240                     Strategy
241                 >(m_geometry1, geometry2, m_strategy);
242         }
243     };
244 
245     template <typename Strategy>
246     static inline typename distance_result
247         <
248             Geometry1,
249             variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
250             Strategy
251         >::type
252     apply(
253         Geometry1 const& geometry1,
254         const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
255         Strategy const& strategy)
256     {
257         return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
258     }
259 };
260 
261 
262 template
263 <
264     BOOST_VARIANT_ENUM_PARAMS(typename T1),
265     BOOST_VARIANT_ENUM_PARAMS(typename T2)
266 >
267 struct distance
268     <
269         boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
270         boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
271     >
272 {
273     template <typename Strategy>
274     struct visitor: static_visitor
275         <
276             typename distance_result
277                 <
278                     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
279                     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
280                     Strategy
281                 >::type
282         >
283     {
284         Strategy const& m_strategy;
285 
286         visitor(Strategy const& strategy)
287             : m_strategy(strategy)
288         {}
289 
290         template <typename Geometry1, typename Geometry2>
291         typename distance_result<Geometry1, Geometry2, Strategy>::type
292         operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
293         {
294             return distance
295                 <
296                     Geometry1,
297                     Geometry2
298                 >::template apply
299                 <
300                     Strategy
301                 >(geometry1, geometry2, m_strategy);
302         }
303     };
304 
305     template <typename Strategy>
306     static inline typename distance_result
307         <
308             boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
309             boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
310             Strategy
311         >::type
312     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
313           boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
314           Strategy const& strategy)
315     {
316         return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
317     }
318 };
319 
320 } // namespace resolve_variant
321 
322 
323 /*!
324 \brief Calculate the distance between two geometries \brief_strategy
325 \ingroup distance
326 \details
327 \details The free function distance calculates the distance between two geometries \brief_strategy. \details_strategy_reasons
328 
329 \tparam Geometry1 \tparam_geometry
330 \tparam Geometry2 \tparam_geometry
331 \tparam Strategy \tparam_strategy{Distance}
332 \param geometry1 \param_geometry
333 \param geometry2 \param_geometry
334 \param strategy \param_strategy{distance}
335 \return \return_calc{distance}
336 \note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
337     it may also be a point-segment strategy.
338 
339 \qbk{distinguish,with strategy}
340 
341 \qbk{
342 [heading Available Strategies]
343 \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
344 \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
345 \* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
346 \* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
347 \* more (currently extensions): Vincenty\, Andoyer (geographic)
348 }
349  */
350 
351 /*
352 Note, in case of a Compilation Error:
353 if you get:
354  - "Failed to specialize function template ..."
355  - "error: no matching function for call to ..."
356 for distance, it is probably so that there is no specialization
357 for return_type<...> for your strategy.
358 */
359 template <typename Geometry1, typename Geometry2, typename Strategy>
360 inline typename distance_result<Geometry1, Geometry2, Strategy>::type
361 distance(Geometry1 const& geometry1,
362          Geometry2 const& geometry2,
363          Strategy const& strategy)
364 {
365     concepts::check<Geometry1 const>();
366     concepts::check<Geometry2 const>();
367 
368     detail::throw_on_empty_input(geometry1);
369     detail::throw_on_empty_input(geometry2);
370 
371     return resolve_variant::distance
372                <
373                    Geometry1,
374                    Geometry2
375                >::apply(geometry1, geometry2, strategy);
376 }
377 
378 
379 /*!
380 \brief Calculate the distance between two geometries.
381 \ingroup distance
382 \details The free function distance calculates the distance between two geometries. \details_default_strategy
383 
384 \tparam Geometry1 \tparam_geometry
385 \tparam Geometry2 \tparam_geometry
386 \param geometry1 \param_geometry
387 \param geometry2 \param_geometry
388 \return \return_calc{distance}
389 
390 \qbk{[include reference/algorithms/distance.qbk]}
391  */
392 template <typename Geometry1, typename Geometry2>
393 inline typename default_distance_result<Geometry1, Geometry2>::type
394 distance(Geometry1 const& geometry1,
395          Geometry2 const& geometry2)
396 {
397     concepts::check<Geometry1 const>();
398     concepts::check<Geometry2 const>();
399 
400     return geometry::distance(geometry1, geometry2, default_strategy());
401 }
402 
403 }} // namespace boost::geometry
404 
405 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
406