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