comparison DEPENDENCIES/generic/include/boost/geometry/algorithms/distance.hpp @ 101:c530137014c0

Update Boost headers (1.58.0)
author Chris Cannam
date Mon, 07 Sep 2015 11:12:49 +0100
parents 2665513ce2d3
children
comparison
equal deleted inserted replaced
100:793467b5e61c 101:c530137014c0
1 // Boost.Geometry (aka GGL, Generic Geometry Library) 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. 3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. 4 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. 5 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
6 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
7
8 // This file was modified by Oracle on 2014.
9 // Modifications copyright (c) 2014, Oracle and/or its affiliates.
10
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 12
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library 13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. 14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
9 15
10 // Use, modification and distribution is subject to the Boost Software License, 16 // Use, modification and distribution is subject to the Boost Software License,
12 // http://www.boost.org/LICENSE_1_0.txt) 18 // http://www.boost.org/LICENSE_1_0.txt)
13 19
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP 20 #ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP 21 #define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
16 22
17 23 #include <boost/geometry/algorithms/detail/distance/interface.hpp>
18 #include <boost/concept_check.hpp> 24 #include <boost/geometry/algorithms/detail/distance/implementation.hpp>
19 #include <boost/mpl/if.hpp>
20 #include <boost/range.hpp>
21 #include <boost/typeof/typeof.hpp>
22
23 #include <boost/geometry/core/cs.hpp>
24 #include <boost/geometry/core/closure.hpp>
25 #include <boost/geometry/core/reverse_dispatch.hpp>
26 #include <boost/geometry/core/tag_cast.hpp>
27
28 #include <boost/geometry/algorithms/not_implemented.hpp>
29 #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
30
31 #include <boost/geometry/geometries/segment.hpp>
32 #include <boost/geometry/geometries/concepts/check.hpp>
33
34 #include <boost/geometry/strategies/distance.hpp>
35 #include <boost/geometry/strategies/default_distance_result.hpp>
36 #include <boost/geometry/algorithms/assign.hpp>
37 #include <boost/geometry/algorithms/within.hpp>
38
39 #include <boost/geometry/views/closeable_view.hpp>
40 #include <boost/geometry/util/math.hpp>
41
42
43 namespace boost { namespace geometry
44 {
45
46 #ifndef DOXYGEN_NO_DETAIL
47 namespace detail { namespace distance
48 {
49
50 // To avoid spurious namespaces here:
51 using strategy::distance::services::return_type;
52
53 template <typename P1, typename P2, typename Strategy>
54 struct point_to_point
55 {
56 static inline typename return_type<Strategy, P1, P2>::type
57 apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
58 {
59 boost::ignore_unused_variable_warning(strategy);
60 return strategy.apply(p1, p2);
61 }
62 };
63
64
65 template<typename Point, typename Segment, typename Strategy>
66 struct point_to_segment
67 {
68 static inline typename return_type<Strategy, Point, typename point_type<Segment>::type>::type
69 apply(Point const& point, Segment const& segment, Strategy const& )
70 {
71 typename strategy::distance::services::default_strategy
72 <
73 segment_tag,
74 Point,
75 typename point_type<Segment>::type,
76 typename cs_tag<Point>::type,
77 typename cs_tag<typename point_type<Segment>::type>::type,
78 Strategy
79 >::type segment_strategy;
80
81 typename point_type<Segment>::type p[2];
82 geometry::detail::assign_point_from_index<0>(segment, p[0]);
83 geometry::detail::assign_point_from_index<1>(segment, p[1]);
84 return segment_strategy.apply(point, p[0], p[1]);
85 }
86 };
87
88
89 template
90 <
91 typename Point,
92 typename Range,
93 closure_selector Closure,
94 typename PPStrategy,
95 typename PSStrategy
96 >
97 struct point_to_range
98 {
99 typedef typename return_type<PSStrategy, Point, typename point_type<Range>::type>::type return_type;
100
101 static inline return_type apply(Point const& point, Range const& range,
102 PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
103 {
104 return_type const zero = return_type(0);
105
106 if (boost::size(range) == 0)
107 {
108 return zero;
109 }
110
111 typedef typename closeable_view<Range const, Closure>::type view_type;
112
113 view_type view(range);
114
115 // line of one point: return point distance
116 typedef typename boost::range_iterator<view_type const>::type iterator_type;
117 iterator_type it = boost::begin(view);
118 iterator_type prev = it++;
119 if (it == boost::end(view))
120 {
121 return pp_strategy.apply(point, *boost::begin(view));
122 }
123
124 // Create comparable (more efficient) strategy
125 typedef typename strategy::distance::services::comparable_type<PSStrategy>::type eps_strategy_type;
126 eps_strategy_type eps_strategy = strategy::distance::services::get_comparable<PSStrategy>::apply(ps_strategy);
127
128 // start with first segment distance
129 return_type d = eps_strategy.apply(point, *prev, *it);
130 return_type rd = ps_strategy.apply(point, *prev, *it);
131
132 // check if other segments are closer
133 for (++prev, ++it; it != boost::end(view); ++prev, ++it)
134 {
135 return_type const ds = eps_strategy.apply(point, *prev, *it);
136 if (geometry::math::equals(ds, zero))
137 {
138 return ds;
139 }
140 else if (ds < d)
141 {
142 d = ds;
143 rd = ps_strategy.apply(point, *prev, *it);
144 }
145 }
146
147 return rd;
148 }
149 };
150
151
152 template
153 <
154 typename Point,
155 typename Ring,
156 closure_selector Closure,
157 typename PPStrategy,
158 typename PSStrategy
159 >
160 struct point_to_ring
161 {
162 typedef std::pair
163 <
164 typename return_type<PPStrategy, Point, typename point_type<Ring>::type>::type, bool
165 > distance_containment;
166
167 static inline distance_containment apply(Point const& point,
168 Ring const& ring,
169 PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
170 {
171 return distance_containment
172 (
173 point_to_range
174 <
175 Point,
176 Ring,
177 Closure,
178 PPStrategy,
179 PSStrategy
180 >::apply(point, ring, pp_strategy, ps_strategy),
181 geometry::within(point, ring)
182 );
183 }
184 };
185
186
187
188 template
189 <
190 typename Point,
191 typename Polygon,
192 closure_selector Closure,
193 typename PPStrategy,
194 typename PSStrategy
195 >
196 struct point_to_polygon
197 {
198 typedef typename return_type<PPStrategy, Point, typename point_type<Polygon>::type>::type return_type;
199 typedef std::pair<return_type, bool> distance_containment;
200
201 static inline distance_containment apply(Point const& point,
202 Polygon const& polygon,
203 PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
204 {
205 // Check distance to all rings
206 typedef point_to_ring
207 <
208 Point,
209 typename ring_type<Polygon>::type,
210 Closure,
211 PPStrategy,
212 PSStrategy
213 > per_ring;
214
215 distance_containment dc = per_ring::apply(point,
216 exterior_ring(polygon), pp_strategy, ps_strategy);
217
218 typename interior_return_type<Polygon const>::type rings
219 = interior_rings(polygon);
220 for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
221 {
222 distance_containment dcr = per_ring::apply(point,
223 *it, pp_strategy, ps_strategy);
224 if (dcr.first < dc.first)
225 {
226 dc.first = dcr.first;
227 }
228 // If it was inside, and also inside inner ring,
229 // turn off the inside-flag, it is outside the polygon
230 if (dc.second && dcr.second)
231 {
232 dc.second = false;
233 }
234 }
235 return dc;
236 }
237 };
238
239
240 // Helper metafunction for default strategy retrieval
241 template <typename Geometry1, typename Geometry2>
242 struct default_strategy
243 : strategy::distance::services::default_strategy
244 <
245 point_tag,
246 typename point_type<Geometry1>::type,
247 typename point_type<Geometry2>::type
248 >
249 {};
250
251
252 }} // namespace detail::distance
253 #endif // DOXYGEN_NO_DETAIL
254
255
256 #ifndef DOXYGEN_NO_DISPATCH
257 namespace dispatch
258 {
259
260
261 using strategy::distance::services::return_type;
262
263
264 template
265 <
266 typename Geometry1, typename Geometry2,
267 typename Strategy = typename detail::distance::default_strategy<Geometry1, Geometry2>::type,
268 typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
269 typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
270 typename StrategyTag = typename strategy::distance::services::tag<Strategy>::type,
271 bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
272 >
273 struct distance: not_implemented<Tag1, Tag2>
274 {};
275
276
277 // If reversal is needed, perform it
278 template
279 <
280 typename Geometry1, typename Geometry2, typename Strategy,
281 typename Tag1, typename Tag2, typename StrategyTag
282 >
283 struct distance
284 <
285 Geometry1, Geometry2, Strategy,
286 Tag1, Tag2, StrategyTag,
287 true
288 >
289 : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
290 {
291 typedef typename strategy::distance::services::return_type
292 <
293 Strategy,
294 typename point_type<Geometry2>::type,
295 typename point_type<Geometry1>::type
296 >::type return_type;
297
298 static inline return_type apply(
299 Geometry1 const& g1,
300 Geometry2 const& g2,
301 Strategy const& strategy)
302 {
303 return distance
304 <
305 Geometry2, Geometry1, Strategy,
306 Tag2, Tag1, StrategyTag,
307 false
308 >::apply(g2, g1, strategy);
309 }
310 };
311
312
313 // Point-point
314 template <typename P1, typename P2, typename Strategy>
315 struct distance
316 <
317 P1, P2, Strategy,
318 point_tag, point_tag, strategy_tag_distance_point_point,
319 false
320 >
321 : detail::distance::point_to_point<P1, P2, Strategy>
322 {};
323
324
325 // Point-line version 1, where point-point strategy is specified
326 template <typename Point, typename Linestring, typename Strategy>
327 struct distance
328 <
329 Point, Linestring, Strategy,
330 point_tag, linestring_tag, strategy_tag_distance_point_point,
331 false
332 >
333 {
334
335 static inline typename return_type<Strategy, Point, typename point_type<Linestring>::type>::type
336 apply(Point const& point,
337 Linestring const& linestring,
338 Strategy const& strategy)
339 {
340 typedef typename strategy::distance::services::default_strategy
341 <
342 segment_tag,
343 Point,
344 typename point_type<Linestring>::type,
345 typename cs_tag<Point>::type,
346 typename cs_tag<typename point_type<Linestring>::type>::type,
347 Strategy
348 >::type ps_strategy_type;
349
350 return detail::distance::point_to_range
351 <
352 Point, Linestring, closed, Strategy, ps_strategy_type
353 >::apply(point, linestring, strategy, ps_strategy_type());
354 }
355 };
356
357
358 // Point-line version 2, where point-segment strategy is specified
359 template <typename Point, typename Linestring, typename Strategy>
360 struct distance
361 <
362 Point, Linestring, Strategy,
363 point_tag, linestring_tag, strategy_tag_distance_point_segment,
364 false
365 >
366 {
367 static inline typename return_type<Strategy, Point, typename point_type<Linestring>::type>::type
368 apply(Point const& point,
369 Linestring const& linestring,
370 Strategy const& strategy)
371 {
372 typedef typename Strategy::point_strategy_type pp_strategy_type;
373 return detail::distance::point_to_range
374 <
375 Point, Linestring, closed, pp_strategy_type, Strategy
376 >::apply(point, linestring, pp_strategy_type(), strategy);
377 }
378 };
379
380 // Point-ring , where point-segment strategy is specified
381 template <typename Point, typename Ring, typename Strategy>
382 struct distance
383 <
384 Point, Ring, Strategy,
385 point_tag, ring_tag, strategy_tag_distance_point_point,
386 false
387 >
388 {
389 typedef typename return_type<Strategy, Point, typename point_type<Ring>::type>::type return_type;
390
391 static inline return_type apply(Point const& point,
392 Ring const& ring,
393 Strategy const& strategy)
394 {
395 typedef typename strategy::distance::services::default_strategy
396 <
397 segment_tag,
398 Point,
399 typename point_type<Ring>::type
400 >::type ps_strategy_type;
401
402 std::pair<return_type, bool>
403 dc = detail::distance::point_to_ring
404 <
405 Point, Ring,
406 geometry::closure<Ring>::value,
407 Strategy, ps_strategy_type
408 >::apply(point, ring, strategy, ps_strategy_type());
409
410 return dc.second ? return_type(0) : dc.first;
411 }
412 };
413
414
415 // Point-polygon , where point-segment strategy is specified
416 template <typename Point, typename Polygon, typename Strategy>
417 struct distance
418 <
419 Point, Polygon, Strategy,
420 point_tag, polygon_tag, strategy_tag_distance_point_point,
421 false
422 >
423 {
424 typedef typename return_type<Strategy, Point, typename point_type<Polygon>::type>::type return_type;
425
426 static inline return_type apply(Point const& point,
427 Polygon const& polygon,
428 Strategy const& strategy)
429 {
430 typedef typename strategy::distance::services::default_strategy
431 <
432 segment_tag,
433 Point,
434 typename point_type<Polygon>::type
435 >::type ps_strategy_type;
436
437 std::pair<return_type, bool>
438 dc = detail::distance::point_to_polygon
439 <
440 Point, Polygon,
441 geometry::closure<Polygon>::value,
442 Strategy, ps_strategy_type
443 >::apply(point, polygon, strategy, ps_strategy_type());
444
445 return dc.second ? return_type(0) : dc.first;
446 }
447 };
448
449
450
451 // Point-segment version 1, with point-point strategy
452 template <typename Point, typename Segment, typename Strategy>
453 struct distance
454 <
455 Point, Segment, Strategy,
456 point_tag, segment_tag, strategy_tag_distance_point_point,
457 false
458 > : detail::distance::point_to_segment<Point, Segment, Strategy>
459 {};
460
461 // Point-segment version 2, with point-segment strategy
462 template <typename Point, typename Segment, typename Strategy>
463 struct distance
464 <
465 Point, Segment, Strategy,
466 point_tag, segment_tag, strategy_tag_distance_point_segment,
467 false
468 >
469 {
470 static inline typename return_type<Strategy, Point, typename point_type<Segment>::type>::type
471 apply(Point const& point,
472 Segment const& segment,
473 Strategy const& strategy)
474 {
475
476 typename point_type<Segment>::type p[2];
477 geometry::detail::assign_point_from_index<0>(segment, p[0]);
478 geometry::detail::assign_point_from_index<1>(segment, p[1]);
479 return strategy.apply(point, p[0], p[1]);
480 }
481 };
482
483
484
485 } // namespace dispatch
486 #endif // DOXYGEN_NO_DISPATCH
487
488 /*!
489 \brief \brief_calc2{distance} \brief_strategy
490 \ingroup distance
491 \details
492 \details \details_calc{area}. \brief_strategy. \details_strategy_reasons
493
494 \tparam Geometry1 \tparam_geometry
495 \tparam Geometry2 \tparam_geometry
496 \tparam Strategy \tparam_strategy{Distance}
497 \param geometry1 \param_geometry
498 \param geometry2 \param_geometry
499 \param strategy \param_strategy{distance}
500 \return \return_calc{distance}
501 \note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
502 it may also be a point-segment strategy.
503
504 \qbk{distinguish,with strategy}
505
506 \qbk{
507 [heading Available Strategies]
508 \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
509 \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
510 \* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
511 \* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
512 \* more (currently extensions): Vincenty\, Andoyer (geographic)
513 }
514 */
515
516 /*
517 Note, in case of a Compilation Error:
518 if you get:
519 - "Failed to specialize function template ..."
520 - "error: no matching function for call to ..."
521 for distance, it is probably so that there is no specialization
522 for return_type<...> for your strategy.
523 */
524 template <typename Geometry1, typename Geometry2, typename Strategy>
525 inline typename strategy::distance::services::return_type
526 <
527 Strategy,
528 typename point_type<Geometry1>::type,
529 typename point_type<Geometry2>::type
530 >::type
531 distance(Geometry1 const& geometry1,
532 Geometry2 const& geometry2,
533 Strategy const& strategy)
534 {
535 concept::check<Geometry1 const>();
536 concept::check<Geometry2 const>();
537
538 detail::throw_on_empty_input(geometry1);
539 detail::throw_on_empty_input(geometry2);
540
541 return dispatch::distance
542 <
543 Geometry1,
544 Geometry2,
545 Strategy
546 >::apply(geometry1, geometry2, strategy);
547 }
548
549
550 /*!
551 \brief \brief_calc2{distance}
552 \ingroup distance
553 \details The default strategy is used, corresponding to the coordinate system of the geometries
554 \tparam Geometry1 \tparam_geometry
555 \tparam Geometry2 \tparam_geometry
556 \param geometry1 \param_geometry
557 \param geometry2 \param_geometry
558 \return \return_calc{distance}
559
560 \qbk{[include reference/algorithms/distance.qbk]}
561 */
562 template <typename Geometry1, typename Geometry2>
563 inline typename default_distance_result<Geometry1, Geometry2>::type distance(
564 Geometry1 const& geometry1, Geometry2 const& geometry2)
565 {
566 concept::check<Geometry1 const>();
567 concept::check<Geometry2 const>();
568
569 return distance(geometry1, geometry2,
570 typename detail::distance::default_strategy<Geometry1, Geometry2>::type());
571 }
572
573 }} // namespace boost::geometry
574 25
575 #endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP 26 #endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP