annotate DEPENDENCIES/generic/include/boost/geometry/strategies/spherical/distance_cross_track.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
Chris@16 2
Chris@101 3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
Chris@101 4
Chris@101 5 // This file was modified by Oracle on 2014.
Chris@101 6 // Modifications copyright (c) 2014, Oracle and/or its affiliates.
Chris@101 7
Chris@101 8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Chris@16 9
Chris@16 10 // Use, modification and distribution is subject to the Boost Software License,
Chris@16 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 12 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 13
Chris@16 14 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
Chris@16 15 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
Chris@16 16
Chris@101 17 #include <algorithm>
Chris@16 18
Chris@16 19 #include <boost/config.hpp>
Chris@16 20 #include <boost/concept_check.hpp>
Chris@16 21 #include <boost/mpl/if.hpp>
Chris@101 22 #include <boost/type_traits/is_void.hpp>
Chris@16 23
Chris@16 24 #include <boost/geometry/core/cs.hpp>
Chris@16 25 #include <boost/geometry/core/access.hpp>
Chris@16 26 #include <boost/geometry/core/radian_access.hpp>
Chris@101 27 #include <boost/geometry/core/tags.hpp>
Chris@16 28
Chris@101 29 #include <boost/geometry/algorithms/detail/course.hpp>
Chris@16 30
Chris@16 31 #include <boost/geometry/strategies/distance.hpp>
Chris@16 32 #include <boost/geometry/strategies/concepts/distance_concept.hpp>
Chris@16 33 #include <boost/geometry/strategies/spherical/distance_haversine.hpp>
Chris@16 34
Chris@101 35 #include <boost/geometry/util/math.hpp>
Chris@16 36 #include <boost/geometry/util/promote_floating_point.hpp>
Chris@101 37 #include <boost/geometry/util/select_calculation_type.hpp>
Chris@16 38
Chris@16 39 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
Chris@16 40 # include <boost/geometry/io/dsv/write.hpp>
Chris@16 41 #endif
Chris@16 42
Chris@16 43
Chris@16 44 namespace boost { namespace geometry
Chris@16 45 {
Chris@16 46
Chris@16 47 namespace strategy { namespace distance
Chris@16 48 {
Chris@16 49
Chris@101 50
Chris@101 51 namespace comparable
Chris@101 52 {
Chris@101 53
Chris@101 54 /*
Chris@101 55 Given a spherical segment AB and a point D, we are interested in
Chris@101 56 computing the distance of D from AB. This is usually known as the
Chris@101 57 cross track distance.
Chris@101 58
Chris@101 59 If the projection (along great circles) of the point D lies inside
Chris@101 60 the segment AB, then the distance (cross track error) XTD is given
Chris@101 61 by the formula (see http://williams.best.vwh.net/avform.htm#XTE):
Chris@101 62
Chris@101 63 XTD = asin( sin(dist_AD) * sin(crs_AD-crs_AB) )
Chris@101 64
Chris@101 65 where dist_AD is the great circle distance between the points A and
Chris@101 66 B, and crs_AD, crs_AB is the course (bearing) between the points A,
Chris@101 67 D and A, B, respectively.
Chris@101 68
Chris@101 69 If the point D does not project inside the arc AB, then the distance
Chris@101 70 of D from AB is the minimum of the two distances dist_AD and dist_BD.
Chris@101 71
Chris@101 72 Our reference implementation for this procedure is listed below
Chris@101 73 (this was the old Boost.Geometry implementation of the cross track distance),
Chris@101 74 where:
Chris@101 75 * The member variable m_strategy is the underlying haversine strategy.
Chris@101 76 * p stands for the point D.
Chris@101 77 * sp1 stands for the segment endpoint A.
Chris@101 78 * sp2 stands for the segment endpoint B.
Chris@101 79
Chris@101 80 ================= reference implementation -- start =================
Chris@101 81
Chris@101 82 return_type d1 = m_strategy.apply(sp1, p);
Chris@101 83 return_type d3 = m_strategy.apply(sp1, sp2);
Chris@101 84
Chris@101 85 if (geometry::math::equals(d3, 0.0))
Chris@101 86 {
Chris@101 87 // "Degenerate" segment, return either d1 or d2
Chris@101 88 return d1;
Chris@101 89 }
Chris@101 90
Chris@101 91 return_type d2 = m_strategy.apply(sp2, p);
Chris@101 92
Chris@101 93 return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
Chris@101 94 return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
Chris@101 95 return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
Chris@101 96 return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
Chris@101 97 return_type d_crs1 = crs_AD - crs_AB;
Chris@101 98 return_type d_crs2 = crs_BD - crs_BA;
Chris@101 99
Chris@101 100 // d1, d2, d3 are in principle not needed, only the sign matters
Chris@101 101 return_type projection1 = cos( d_crs1 ) * d1 / d3;
Chris@101 102 return_type projection2 = cos( d_crs2 ) * d2 / d3;
Chris@101 103
Chris@101 104 if (projection1 > 0.0 && projection2 > 0.0)
Chris@101 105 {
Chris@101 106 return_type XTD
Chris@101 107 = radius() * math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) ));
Chris@101 108
Chris@101 109 // Return shortest distance, projected point on segment sp1-sp2
Chris@101 110 return return_type(XTD);
Chris@101 111 }
Chris@101 112 else
Chris@101 113 {
Chris@101 114 // Return shortest distance, project either on point sp1 or sp2
Chris@101 115 return return_type( (std::min)( d1 , d2 ) );
Chris@101 116 }
Chris@101 117
Chris@101 118 ================= reference implementation -- end =================
Chris@101 119
Chris@101 120
Chris@101 121 Motivation
Chris@101 122 ----------
Chris@101 123 In what follows we develop a comparable version of the cross track
Chris@101 124 distance strategy, that meets the following goals:
Chris@101 125 * It is more efficient than the original cross track strategy (less
Chris@101 126 operations and less calls to mathematical functions).
Chris@101 127 * Distances using the comparable cross track strategy can not only
Chris@101 128 be compared with other distances using the same strategy, but also with
Chris@101 129 distances computed with the comparable version of the haversine strategy.
Chris@101 130 * It can serve as the basis for the computation of the cross track distance,
Chris@101 131 as it is more efficient to compute its comparable version and
Chris@101 132 transform that to the actual cross track distance, rather than
Chris@101 133 follow/use the reference implementation listed above.
Chris@101 134
Chris@101 135 Major idea
Chris@101 136 ----------
Chris@101 137 The idea here is to use the comparable haversine strategy to compute
Chris@101 138 the distances d1, d2 and d3 in the above listing. Once we have done
Chris@101 139 that we need also to make sure that instead of returning XTD (as
Chris@101 140 computed above) that we return a distance CXTD that is compatible
Chris@101 141 with the comparable haversine distance. To achieve this CXTD must satisfy
Chris@101 142 the relation:
Chris@101 143 XTD = 2 * R * asin( sqrt(XTD) )
Chris@101 144 where R is the sphere's radius.
Chris@101 145
Chris@101 146 Below we perform the mathematical analysis that show how to compute CXTD.
Chris@101 147
Chris@101 148
Chris@101 149 Mathematical analysis
Chris@101 150 ---------------------
Chris@101 151 Below we use the following trigonometric identities:
Chris@101 152 sin(2 * x) = 2 * sin(x) * cos(x)
Chris@101 153 cos(asin(x)) = sqrt(1 - x^2)
Chris@101 154
Chris@101 155 Observation:
Chris@101 156 The distance d1 needed when the projection of the point D is within the
Chris@101 157 segment must be the true distance. However, comparable::haversine<>
Chris@101 158 returns a comparable distance instead of the one needed.
Chris@101 159 To remedy this, we implicitly compute what is needed.
Chris@101 160 More precisely, we need to compute sin(true_d1):
Chris@101 161
Chris@101 162 sin(true_d1) = sin(2 * asin(sqrt(d1)))
Chris@101 163 = 2 * sin(asin(sqrt(d1)) * cos(asin(sqrt(d1)))
Chris@101 164 = 2 * sqrt(d1) * sqrt(1-(sqrt(d1))^2)
Chris@101 165 = 2 * sqrt(d1 - d1 * d1)
Chris@101 166 This relation is used below.
Chris@101 167
Chris@101 168 As we mentioned above the goal is to find CXTD (named "a" below for
Chris@101 169 brevity) such that ("b" below stands for "d1", and "c" for "d_crs1"):
Chris@101 170
Chris@101 171 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
Chris@101 172
Chris@101 173 Analysis:
Chris@101 174 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
Chris@101 175 <=> 2 * asin(sqrt(a)) == asin(sqrt(b-b^2) * sin(c))
Chris@101 176 <=> sin(2 * asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
Chris@101 177 <=> 2 * sin(asin(sqrt(a))) * cos(asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
Chris@101 178 <=> 2 * sqrt(a) * sqrt(1-a) == 2 * sqrt(b-b^2) * sin(c)
Chris@101 179 <=> sqrt(a) * sqrt(1-a) == sqrt(b-b^2) * sin(c)
Chris@101 180 <=> sqrt(a-a^2) == sqrt(b-b^2) * sin(c)
Chris@101 181 <=> a-a^2 == (b-b^2) * (sin(c))^2
Chris@101 182
Chris@101 183 Consider the quadratic equation: x^2-x+p^2 == 0,
Chris@101 184 where p = sqrt(b-b^2) * sin(c); its discriminant is:
Chris@101 185 d = 1 - 4 * p^2 = 1 - 4 * (b-b^2) * (sin(c))^2
Chris@101 186
Chris@101 187 The two solutions are:
Chris@101 188 a_1 = (1 - sqrt(d)) / 2
Chris@101 189 a_2 = (1 + sqrt(d)) / 2
Chris@101 190
Chris@101 191 Which one to choose?
Chris@101 192 "a" refers to the distance (on the unit sphere) of D from the
Chris@101 193 supporting great circle Circ(A,B) of the segment AB.
Chris@101 194 The two different values for "a" correspond to the lengths of the two
Chris@101 195 arcs delimited D and the points of intersection of Circ(A,B) and the
Chris@101 196 great circle perperdicular to Circ(A,B) passing through D.
Chris@101 197 Clearly, the value we want is the smallest among these two distances,
Chris@101 198 hence the root we must choose is the smallest root among the two.
Chris@101 199
Chris@101 200 So the answer is:
Chris@101 201 CXTD = ( 1 - sqrt(1 - 4 * (b-b^2) * (sin(c))^2) ) / 2
Chris@101 202
Chris@101 203 Therefore, in order to implement the comparable version of the cross
Chris@101 204 track strategy we need to:
Chris@101 205 (1) Use the comparable version of the haversine strategy instead of
Chris@101 206 the non-comparable one.
Chris@101 207 (2) Instead of return XTD when D projects inside the segment AB, we
Chris@101 208 need to return CXTD, given by the following formula:
Chris@101 209 CXTD = ( 1 - sqrt(1 - 4 * (d1-d1^2) * (sin(d_crs1))^2) ) / 2;
Chris@101 210
Chris@101 211
Chris@101 212 Complexity Analysis
Chris@101 213 -------------------
Chris@101 214 In the analysis that follows we refer to the actual implementation below.
Chris@101 215 In particular, instead of computing CXTD as above, we use the more
Chris@101 216 efficient (operation-wise) computation of CXTD shown here:
Chris@101 217
Chris@101 218 return_type sin_d_crs1 = sin(d_crs1);
Chris@101 219 return_type d1_x_sin = d1 * sin_d_crs1;
Chris@101 220 return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
Chris@101 221 return d / (0.5 + math::sqrt(0.25 - d));
Chris@101 222
Chris@101 223 Notice that instead of computing:
Chris@101 224 0.5 - 0.5 * sqrt(1 - 4 * d) = 0.5 - sqrt(0.25 - d)
Chris@101 225 we use the following formula instead:
Chris@101 226 d / (0.5 + sqrt(0.25 - d)).
Chris@101 227 This is done for numerical robustness. The expression 0.5 - sqrt(0.25 - x)
Chris@101 228 has large numerical errors for values of x close to 0 (if using doubles
Chris@101 229 the error start to become large even when d is as large as 0.001).
Chris@101 230 To remedy that, we re-write 0.5 - sqrt(0.25 - x) as:
Chris@101 231 0.5 - sqrt(0.25 - d)
Chris@101 232 = (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d)) / (0.5 + sqrt(0.25 - d)).
Chris@101 233 The numerator is the difference of two squares:
Chris@101 234 (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d))
Chris@101 235 = 0.5^2 - (sqrt(0.25 - d))^ = 0.25 - (0.25 - d) = d,
Chris@101 236 which gives the expression we use.
Chris@101 237
Chris@101 238 For the complexity analysis, we distinguish between two cases:
Chris@101 239 (A) The distance is realized between the point D and an
Chris@101 240 endpoint of the segment AB
Chris@101 241
Chris@101 242 Gains:
Chris@101 243 Since we are using comparable::haversine<> which is called
Chris@101 244 3 times, we gain:
Chris@101 245 -> 3 calls to sqrt
Chris@101 246 -> 3 calls to asin
Chris@101 247 -> 6 multiplications
Chris@101 248
Chris@101 249 Loses: None
Chris@101 250
Chris@101 251 So the net gain is:
Chris@101 252 -> 6 function calls (sqrt/asin)
Chris@101 253 -> 6 arithmetic operations
Chris@101 254
Chris@101 255 If we use comparable::cross_track<> to compute
Chris@101 256 cross_track<> we need to account for a call to sqrt, a call
Chris@101 257 to asin and 2 multiplications. In this case the net gain is:
Chris@101 258 -> 4 function calls (sqrt/asin)
Chris@101 259 -> 4 arithmetic operations
Chris@101 260
Chris@101 261
Chris@101 262 (B) The distance is realized between the point D and an
Chris@101 263 interior point of the segment AB
Chris@101 264
Chris@101 265 Gains:
Chris@101 266 Since we are using comparable::haversine<> which is called
Chris@101 267 3 times, we gain:
Chris@101 268 -> 3 calls to sqrt
Chris@101 269 -> 3 calls to asin
Chris@101 270 -> 6 multiplications
Chris@101 271 Also we gain the operations used to compute XTD:
Chris@101 272 -> 2 calls to sin
Chris@101 273 -> 1 call to asin
Chris@101 274 -> 1 call to abs
Chris@101 275 -> 2 multiplications
Chris@101 276 -> 1 division
Chris@101 277 So the total gains are:
Chris@101 278 -> 9 calls to sqrt/sin/asin
Chris@101 279 -> 1 call to abs
Chris@101 280 -> 8 multiplications
Chris@101 281 -> 1 division
Chris@101 282
Chris@101 283 Loses:
Chris@101 284 To compute a distance compatible with comparable::haversine<>
Chris@101 285 we need to perform a few more operations, namely:
Chris@101 286 -> 1 call to sin
Chris@101 287 -> 1 call to sqrt
Chris@101 288 -> 2 multiplications
Chris@101 289 -> 1 division
Chris@101 290 -> 1 addition
Chris@101 291 -> 2 subtractions
Chris@101 292
Chris@101 293 So roughly speaking the net gain is:
Chris@101 294 -> 8 fewer function calls and 3 fewer arithmetic operations
Chris@101 295
Chris@101 296 If we were to implement cross_track directly from the
Chris@101 297 comparable version (much like what haversine<> does using
Chris@101 298 comparable::haversine<>) we need additionally
Chris@101 299 -> 2 function calls (asin/sqrt)
Chris@101 300 -> 2 multiplications
Chris@101 301
Chris@101 302 So it pays off to re-implement cross_track<> to use
Chris@101 303 comparable::cross_track<>; in this case the net gain would be:
Chris@101 304 -> 6 function calls
Chris@101 305 -> 1 arithmetic operation
Chris@101 306
Chris@101 307 Summary/Conclusion
Chris@101 308 ------------------
Chris@101 309 Following the mathematical and complexity analysis above, the
Chris@101 310 comparable cross track strategy (as implemented below) satisfies
Chris@101 311 all the goal mentioned in the beginning:
Chris@101 312 * It is more efficient than its non-comparable counter-part.
Chris@101 313 * Comparable distances using this new strategy can also be compared
Chris@101 314 with comparable distances computed with the comparable haversine
Chris@101 315 strategy.
Chris@101 316 * It turns out to be more efficient to compute the actual cross
Chris@101 317 track distance XTD by first computing CXTD, and then computing
Chris@101 318 XTD by means of the formula:
Chris@101 319 XTD = 2 * R * asin( sqrt(CXTD) )
Chris@101 320 */
Chris@101 321
Chris@101 322 template
Chris@101 323 <
Chris@101 324 typename CalculationType = void,
Chris@101 325 typename Strategy = comparable::haversine<double, CalculationType>
Chris@101 326 >
Chris@101 327 class cross_track
Chris@101 328 {
Chris@101 329 public :
Chris@101 330 template <typename Point, typename PointOfSegment>
Chris@101 331 struct return_type
Chris@101 332 : promote_floating_point
Chris@101 333 <
Chris@101 334 typename select_calculation_type
Chris@101 335 <
Chris@101 336 Point,
Chris@101 337 PointOfSegment,
Chris@101 338 CalculationType
Chris@101 339 >::type
Chris@101 340 >
Chris@101 341 {};
Chris@101 342
Chris@101 343 inline cross_track()
Chris@101 344 {}
Chris@101 345
Chris@101 346 explicit inline cross_track(typename Strategy::radius_type const& r)
Chris@101 347 : m_strategy(r)
Chris@101 348 {}
Chris@101 349
Chris@101 350 inline cross_track(Strategy const& s)
Chris@101 351 : m_strategy(s)
Chris@101 352 {}
Chris@101 353
Chris@101 354
Chris@101 355 // It might be useful in the future
Chris@101 356 // to overload constructor with strategy info.
Chris@101 357 // crosstrack(...) {}
Chris@101 358
Chris@101 359
Chris@101 360 template <typename Point, typename PointOfSegment>
Chris@101 361 inline typename return_type<Point, PointOfSegment>::type
Chris@101 362 apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
Chris@101 363 {
Chris@101 364
Chris@101 365 #if !defined(BOOST_MSVC)
Chris@101 366 BOOST_CONCEPT_ASSERT
Chris@101 367 (
Chris@101 368 (concept::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
Chris@101 369 );
Chris@101 370 #endif
Chris@101 371
Chris@101 372 typedef typename return_type<Point, PointOfSegment>::type return_type;
Chris@101 373
Chris@101 374 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
Chris@101 375 std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl;
Chris@101 376 std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl;
Chris@101 377 std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " " << crs_BD * geometry::math::r2d << std::endl;
Chris@101 378 std::cout << "Projection AD-AB " << projection1 << " : " << d_crs1 * geometry::math::r2d << std::endl;
Chris@101 379 std::cout << "Projection BD-BA " << projection2 << " : " << d_crs2 * geometry::math::r2d << std::endl;
Chris@101 380 #endif
Chris@101 381
Chris@101 382 // http://williams.best.vwh.net/avform.htm#XTE
Chris@101 383 return_type d1 = m_strategy.apply(sp1, p);
Chris@101 384 return_type d3 = m_strategy.apply(sp1, sp2);
Chris@101 385
Chris@101 386 if (geometry::math::equals(d3, 0.0))
Chris@101 387 {
Chris@101 388 // "Degenerate" segment, return either d1 or d2
Chris@101 389 return d1;
Chris@101 390 }
Chris@101 391
Chris@101 392 return_type d2 = m_strategy.apply(sp2, p);
Chris@101 393
Chris@101 394 return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
Chris@101 395 return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
Chris@101 396 return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
Chris@101 397 return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
Chris@101 398 return_type d_crs1 = crs_AD - crs_AB;
Chris@101 399 return_type d_crs2 = crs_BD - crs_BA;
Chris@101 400
Chris@101 401 // d1, d2, d3 are in principle not needed, only the sign matters
Chris@101 402 return_type projection1 = cos( d_crs1 ) * d1 / d3;
Chris@101 403 return_type projection2 = cos( d_crs2 ) * d2 / d3;
Chris@101 404
Chris@101 405 if (projection1 > 0.0 && projection2 > 0.0)
Chris@101 406 {
Chris@101 407 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
Chris@101 408 return_type XTD = radius() * geometry::math::abs( asin( sin( d1 ) * sin( d_crs1 ) ));
Chris@101 409
Chris@101 410 std::cout << "Projection ON the segment" << std::endl;
Chris@101 411 std::cout << "XTD: " << XTD
Chris@101 412 << " d1: " << (d1 * radius())
Chris@101 413 << " d2: " << (d2 * radius())
Chris@101 414 << std::endl;
Chris@101 415 #endif
Chris@101 416 return_type const half(0.5);
Chris@101 417 return_type const quarter(0.25);
Chris@101 418
Chris@101 419 return_type sin_d_crs1 = sin(d_crs1);
Chris@101 420 /*
Chris@101 421 This is the straightforward obvious way to continue:
Chris@101 422
Chris@101 423 return_type discriminant
Chris@101 424 = 1.0 - 4.0 * (d1 - d1 * d1) * sin_d_crs1 * sin_d_crs1;
Chris@101 425 return 0.5 - 0.5 * math::sqrt(discriminant);
Chris@101 426
Chris@101 427 Below we optimize the number of arithmetic operations
Chris@101 428 and account for numerical robustness:
Chris@101 429 */
Chris@101 430 return_type d1_x_sin = d1 * sin_d_crs1;
Chris@101 431 return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
Chris@101 432 return d / (half + math::sqrt(quarter - d));
Chris@101 433 }
Chris@101 434 else
Chris@101 435 {
Chris@101 436 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
Chris@101 437 std::cout << "Projection OUTSIDE the segment" << std::endl;
Chris@101 438 #endif
Chris@101 439
Chris@101 440 // Return shortest distance, project either on point sp1 or sp2
Chris@101 441 return return_type( (std::min)( d1 , d2 ) );
Chris@101 442 }
Chris@101 443 }
Chris@101 444
Chris@101 445 inline typename Strategy::radius_type radius() const
Chris@101 446 { return m_strategy.radius(); }
Chris@101 447
Chris@101 448 private :
Chris@101 449 Strategy m_strategy;
Chris@101 450 };
Chris@101 451
Chris@101 452 } // namespace comparable
Chris@101 453
Chris@101 454
Chris@16 455 /*!
Chris@16 456 \brief Strategy functor for distance point to segment calculation
Chris@16 457 \ingroup strategies
Chris@16 458 \details Class which calculates the distance of a point to a segment, for points on a sphere or globe
Chris@16 459 \see http://williams.best.vwh.net/avform.htm
Chris@16 460 \tparam CalculationType \tparam_calculation
Chris@16 461 \tparam Strategy underlying point-point distance strategy, defaults to haversine
Chris@16 462
Chris@16 463 \qbk{
Chris@16 464 [heading See also]
Chris@16 465 [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
Chris@16 466 }
Chris@16 467
Chris@16 468 */
Chris@16 469 template
Chris@16 470 <
Chris@16 471 typename CalculationType = void,
Chris@16 472 typename Strategy = haversine<double, CalculationType>
Chris@16 473 >
Chris@16 474 class cross_track
Chris@16 475 {
Chris@16 476 public :
Chris@16 477 template <typename Point, typename PointOfSegment>
Chris@16 478 struct return_type
Chris@16 479 : promote_floating_point
Chris@16 480 <
Chris@16 481 typename select_calculation_type
Chris@16 482 <
Chris@16 483 Point,
Chris@16 484 PointOfSegment,
Chris@16 485 CalculationType
Chris@16 486 >::type
Chris@16 487 >
Chris@16 488 {};
Chris@16 489
Chris@16 490 inline cross_track()
Chris@16 491 {}
Chris@16 492
Chris@16 493 explicit inline cross_track(typename Strategy::radius_type const& r)
Chris@16 494 : m_strategy(r)
Chris@16 495 {}
Chris@16 496
Chris@16 497 inline cross_track(Strategy const& s)
Chris@16 498 : m_strategy(s)
Chris@16 499 {}
Chris@16 500
Chris@16 501
Chris@16 502 // It might be useful in the future
Chris@16 503 // to overload constructor with strategy info.
Chris@16 504 // crosstrack(...) {}
Chris@16 505
Chris@16 506
Chris@16 507 template <typename Point, typename PointOfSegment>
Chris@16 508 inline typename return_type<Point, PointOfSegment>::type
Chris@16 509 apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
Chris@16 510 {
Chris@16 511
Chris@16 512 #if !defined(BOOST_MSVC)
Chris@16 513 BOOST_CONCEPT_ASSERT
Chris@16 514 (
Chris@16 515 (concept::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
Chris@16 516 );
Chris@16 517 #endif
Chris@101 518 typedef typename return_type<Point, PointOfSegment>::type return_type;
Chris@101 519 typedef cross_track<CalculationType, Strategy> this_type;
Chris@16 520
Chris@101 521 typedef typename services::comparable_type
Chris@101 522 <
Chris@101 523 this_type
Chris@101 524 >::type comparable_type;
Chris@16 525
Chris@101 526 comparable_type cstrategy
Chris@101 527 = services::get_comparable<this_type>::apply(m_strategy);
Chris@16 528
Chris@101 529 return_type const a = cstrategy.apply(p, sp1, sp2);
Chris@101 530 return_type const c = return_type(2.0) * asin(math::sqrt(a));
Chris@101 531 return c * radius();
Chris@16 532 }
Chris@16 533
Chris@16 534 inline typename Strategy::radius_type radius() const
Chris@16 535 { return m_strategy.radius(); }
Chris@16 536
Chris@16 537 private :
Chris@16 538
Chris@16 539 Strategy m_strategy;
Chris@16 540 };
Chris@16 541
Chris@16 542
Chris@16 543
Chris@16 544 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
Chris@16 545 namespace services
Chris@16 546 {
Chris@16 547
Chris@16 548 template <typename CalculationType, typename Strategy>
Chris@16 549 struct tag<cross_track<CalculationType, Strategy> >
Chris@16 550 {
Chris@16 551 typedef strategy_tag_distance_point_segment type;
Chris@16 552 };
Chris@16 553
Chris@16 554
Chris@16 555 template <typename CalculationType, typename Strategy, typename P, typename PS>
Chris@16 556 struct return_type<cross_track<CalculationType, Strategy>, P, PS>
Chris@16 557 : cross_track<CalculationType, Strategy>::template return_type<P, PS>
Chris@16 558 {};
Chris@16 559
Chris@16 560
Chris@16 561 template <typename CalculationType, typename Strategy>
Chris@16 562 struct comparable_type<cross_track<CalculationType, Strategy> >
Chris@16 563 {
Chris@101 564 typedef comparable::cross_track
Chris@101 565 <
Chris@101 566 CalculationType, typename comparable_type<Strategy>::type
Chris@101 567 > type;
Chris@16 568 };
Chris@16 569
Chris@16 570
Chris@16 571 template
Chris@16 572 <
Chris@16 573 typename CalculationType,
Chris@16 574 typename Strategy
Chris@16 575 >
Chris@16 576 struct get_comparable<cross_track<CalculationType, Strategy> >
Chris@16 577 {
Chris@16 578 typedef typename comparable_type
Chris@16 579 <
Chris@16 580 cross_track<CalculationType, Strategy>
Chris@16 581 >::type comparable_type;
Chris@16 582 public :
Chris@101 583 static inline comparable_type
Chris@101 584 apply(cross_track<CalculationType, Strategy> const& strategy)
Chris@16 585 {
Chris@16 586 return comparable_type(strategy.radius());
Chris@16 587 }
Chris@16 588 };
Chris@16 589
Chris@16 590
Chris@16 591 template
Chris@16 592 <
Chris@16 593 typename CalculationType,
Chris@16 594 typename Strategy,
Chris@101 595 typename P,
Chris@101 596 typename PS
Chris@16 597 >
Chris@16 598 struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS>
Chris@16 599 {
Chris@16 600 private :
Chris@101 601 typedef typename cross_track
Chris@101 602 <
Chris@101 603 CalculationType, Strategy
Chris@101 604 >::template return_type<P, PS>::type return_type;
Chris@16 605 public :
Chris@16 606 template <typename T>
Chris@101 607 static inline return_type
Chris@101 608 apply(cross_track<CalculationType, Strategy> const& , T const& distance)
Chris@16 609 {
Chris@16 610 return distance;
Chris@16 611 }
Chris@16 612 };
Chris@16 613
Chris@16 614
Chris@101 615 // Specializations for comparable::cross_track
Chris@101 616 template <typename RadiusType, typename CalculationType>
Chris@101 617 struct tag<comparable::cross_track<RadiusType, CalculationType> >
Chris@101 618 {
Chris@101 619 typedef strategy_tag_distance_point_segment type;
Chris@101 620 };
Chris@101 621
Chris@101 622
Chris@16 623 template
Chris@16 624 <
Chris@101 625 typename RadiusType,
Chris@16 626 typename CalculationType,
Chris@101 627 typename P,
Chris@101 628 typename PS
Chris@16 629 >
Chris@101 630 struct return_type<comparable::cross_track<RadiusType, CalculationType>, P, PS>
Chris@101 631 : comparable::cross_track
Chris@101 632 <
Chris@101 633 RadiusType, CalculationType
Chris@101 634 >::template return_type<P, PS>
Chris@101 635 {};
Chris@101 636
Chris@101 637
Chris@101 638 template <typename RadiusType, typename CalculationType>
Chris@101 639 struct comparable_type<comparable::cross_track<RadiusType, CalculationType> >
Chris@16 640 {
Chris@101 641 typedef comparable::cross_track<RadiusType, CalculationType> type;
Chris@101 642 };
Chris@101 643
Chris@101 644
Chris@101 645 template <typename RadiusType, typename CalculationType>
Chris@101 646 struct get_comparable<comparable::cross_track<RadiusType, CalculationType> >
Chris@101 647 {
Chris@101 648 private :
Chris@101 649 typedef comparable::cross_track<RadiusType, CalculationType> this_type;
Chris@101 650 public :
Chris@101 651 static inline this_type apply(this_type const& input)
Chris@101 652 {
Chris@101 653 return input;
Chris@101 654 }
Chris@101 655 };
Chris@101 656
Chris@101 657
Chris@101 658 template
Chris@101 659 <
Chris@101 660 typename RadiusType,
Chris@101 661 typename CalculationType,
Chris@101 662 typename P,
Chris@101 663 typename PS
Chris@101 664 >
Chris@101 665 struct result_from_distance
Chris@101 666 <
Chris@101 667 comparable::cross_track<RadiusType, CalculationType>, P, PS
Chris@101 668 >
Chris@101 669 {
Chris@101 670 private :
Chris@101 671 typedef comparable::cross_track<RadiusType, CalculationType> strategy_type;
Chris@101 672 typedef typename return_type<strategy_type, P, PS>::type return_type;
Chris@101 673 public :
Chris@101 674 template <typename T>
Chris@101 675 static inline return_type apply(strategy_type const& strategy,
Chris@101 676 T const& distance)
Chris@101 677 {
Chris@101 678 return_type const s
Chris@101 679 = sin( (distance / strategy.radius()) / return_type(2.0) );
Chris@101 680 return s * s;
Chris@101 681 }
Chris@16 682 };
Chris@16 683
Chris@16 684
Chris@16 685
Chris@16 686 /*
Chris@16 687
Chris@16 688 TODO: spherical polar coordinate system requires "get_as_radian_equatorial<>"
Chris@16 689
Chris@16 690 template <typename Point, typename PointOfSegment, typename Strategy>
Chris@16 691 struct default_strategy
Chris@16 692 <
Chris@16 693 segment_tag, Point, PointOfSegment,
Chris@16 694 spherical_polar_tag, spherical_polar_tag,
Chris@16 695 Strategy
Chris@16 696 >
Chris@16 697 {
Chris@16 698 typedef cross_track
Chris@16 699 <
Chris@16 700 void,
Chris@16 701 typename boost::mpl::if_
Chris@16 702 <
Chris@16 703 boost::is_void<Strategy>,
Chris@16 704 typename default_strategy
Chris@16 705 <
Chris@16 706 point_tag, Point, PointOfSegment,
Chris@16 707 spherical_polar_tag, spherical_polar_tag
Chris@16 708 >::type,
Chris@16 709 Strategy
Chris@16 710 >::type
Chris@16 711 > type;
Chris@16 712 };
Chris@16 713 */
Chris@16 714
Chris@16 715 template <typename Point, typename PointOfSegment, typename Strategy>
Chris@16 716 struct default_strategy
Chris@16 717 <
Chris@101 718 point_tag, segment_tag, Point, PointOfSegment,
Chris@16 719 spherical_equatorial_tag, spherical_equatorial_tag,
Chris@16 720 Strategy
Chris@16 721 >
Chris@16 722 {
Chris@16 723 typedef cross_track
Chris@16 724 <
Chris@16 725 void,
Chris@16 726 typename boost::mpl::if_
Chris@16 727 <
Chris@16 728 boost::is_void<Strategy>,
Chris@16 729 typename default_strategy
Chris@16 730 <
Chris@101 731 point_tag, point_tag, Point, PointOfSegment,
Chris@16 732 spherical_equatorial_tag, spherical_equatorial_tag
Chris@16 733 >::type,
Chris@16 734 Strategy
Chris@16 735 >::type
Chris@16 736 > type;
Chris@16 737 };
Chris@16 738
Chris@16 739
Chris@101 740 template <typename PointOfSegment, typename Point, typename Strategy>
Chris@101 741 struct default_strategy
Chris@101 742 <
Chris@101 743 segment_tag, point_tag, PointOfSegment, Point,
Chris@101 744 spherical_equatorial_tag, spherical_equatorial_tag,
Chris@101 745 Strategy
Chris@101 746 >
Chris@101 747 {
Chris@101 748 typedef typename default_strategy
Chris@101 749 <
Chris@101 750 point_tag, segment_tag, Point, PointOfSegment,
Chris@101 751 spherical_equatorial_tag, spherical_equatorial_tag,
Chris@101 752 Strategy
Chris@101 753 >::type type;
Chris@101 754 };
Chris@101 755
Chris@16 756
Chris@16 757 } // namespace services
Chris@16 758 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
Chris@16 759
Chris@16 760 }} // namespace strategy::distance
Chris@16 761
Chris@16 762 }} // namespace boost::geometry
Chris@16 763
Chris@16 764 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP