123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
- // This file was modified by Oracle on 2014-2021.
- // Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
- // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
- // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Use, modification and distribution is subject to the Boost Software License,
- // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
- #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
- #include <algorithm>
- #include <type_traits>
- #include <boost/config.hpp>
- #include <boost/concept_check.hpp>
- #include <boost/geometry/core/cs.hpp>
- #include <boost/geometry/core/access.hpp>
- #include <boost/geometry/core/coordinate_promotion.hpp>
- #include <boost/geometry/core/radian_access.hpp>
- #include <boost/geometry/core/tags.hpp>
- #include <boost/geometry/formulas/spherical.hpp>
- #include <boost/geometry/strategies/distance.hpp>
- #include <boost/geometry/strategies/concepts/distance_concept.hpp>
- #include <boost/geometry/strategies/spherical/distance_haversine.hpp>
- #include <boost/geometry/strategies/spherical/point_in_point.hpp>
- #include <boost/geometry/strategies/spherical/intersection.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/util/select_calculation_type.hpp>
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- # include <boost/geometry/io/dsv/write.hpp>
- #endif
- namespace boost { namespace geometry
- {
- namespace strategy { namespace distance
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- template <typename CalculationType>
- struct compute_cross_track_pair
- {
- template <typename Point, typename PointOfSegment>
- static inline auto apply(Point const& p,
- PointOfSegment const& sp1,
- PointOfSegment const& sp2)
- {
- CalculationType lon1 = geometry::get_as_radian<0>(sp1);
- CalculationType lat1 = geometry::get_as_radian<1>(sp1);
- CalculationType lon2 = geometry::get_as_radian<0>(sp2);
- CalculationType lat2 = geometry::get_as_radian<1>(sp2);
- CalculationType lon = geometry::get_as_radian<0>(p);
- CalculationType lat = geometry::get_as_radian<1>(p);
- CalculationType const crs_AD = geometry::formula::spherical_azimuth
- <
- CalculationType,
- false
- >(lon1, lat1, lon, lat).azimuth;
- auto result = geometry::formula::spherical_azimuth
- <
- CalculationType,
- true
- >(lon1, lat1, lon2, lat2);
- CalculationType crs_AB = result.azimuth;
- CalculationType crs_BA = result.reverse_azimuth -
- geometry::math::pi<CalculationType>();
- CalculationType crs_BD = geometry::formula::spherical_azimuth
- <
- CalculationType,
- false
- >(lon2, lat2, lon, lat).azimuth;
- CalculationType d_crs1 = crs_AD - crs_AB;
- CalculationType d_crs2 = crs_BD - crs_BA;
- return std::pair<CalculationType, CalculationType>(d_crs1, d_crs2);
- }
- };
- struct compute_cross_track_distance
- {
- template <typename CalculationType>
- static inline auto apply(CalculationType const& d_crs1,
- CalculationType const& d1)
- {
- CalculationType const half(0.5);
- CalculationType const quarter(0.25);
- CalculationType sin_d_crs1 = sin(d_crs1);
- /*
- This is the straightforward obvious way to continue:
- return_type discriminant
- = 1.0 - 4.0 * (d1 - d1 * d1) * sin_d_crs1 * sin_d_crs1;
- return 0.5 - 0.5 * math::sqrt(discriminant);
- Below we optimize the number of arithmetic operations
- and account for numerical robustness:
- */
- CalculationType d1_x_sin = d1 * sin_d_crs1;
- CalculationType d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
- return d / (half + math::sqrt(quarter - d));
- }
- };
- }
- #endif // DOXYGEN_NO_DETAIL
- namespace comparable
- {
- /*
- Given a spherical segment AB and a point D, we are interested in
- computing the distance of D from AB. This is usually known as the
- cross track distance.
- If the projection (along great circles) of the point D lies inside
- the segment AB, then the distance (cross track error) XTD is given
- by the formula (see http://williams.best.vwh.net/avform.htm#XTE):
- XTD = asin( sin(dist_AD) * sin(crs_AD-crs_AB) )
- where dist_AD is the great circle distance between the points A and
- B, and crs_AD, crs_AB is the course (bearing) between the points A,
- D and A, B, respectively.
- If the point D does not project inside the arc AB, then the distance
- of D from AB is the minimum of the two distances dist_AD and dist_BD.
- Our reference implementation for this procedure is listed below
- (this was the old Boost.Geometry implementation of the cross track distance),
- where:
- * The member variable m_strategy is the underlying haversine strategy.
- * p stands for the point D.
- * sp1 stands for the segment endpoint A.
- * sp2 stands for the segment endpoint B.
- ================= reference implementation -- start =================
- return_type d1 = m_strategy.apply(sp1, p);
- return_type d3 = m_strategy.apply(sp1, sp2);
- if (geometry::math::equals(d3, 0.0))
- {
- // "Degenerate" segment, return either d1 or d2
- return d1;
- }
- return_type d2 = m_strategy.apply(sp2, p);
- return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
- return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
- return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
- return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
- return_type d_crs1 = crs_AD - crs_AB;
- return_type d_crs2 = crs_BD - crs_BA;
- // d1, d2, d3 are in principle not needed, only the sign matters
- return_type projection1 = cos( d_crs1 ) * d1 / d3;
- return_type projection2 = cos( d_crs2 ) * d2 / d3;
- if (projection1 > 0.0 && projection2 > 0.0)
- {
- return_type XTD
- = radius() * math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) ));
- // Return shortest distance, projected point on segment sp1-sp2
- return return_type(XTD);
- }
- else
- {
- // Return shortest distance, project either on point sp1 or sp2
- return return_type( (std::min)( d1 , d2 ) );
- }
- ================= reference implementation -- end =================
- Motivation
- ----------
- In what follows we develop a comparable version of the cross track
- distance strategy, that meets the following goals:
- * It is more efficient than the original cross track strategy (less
- operations and less calls to mathematical functions).
- * Distances using the comparable cross track strategy can not only
- be compared with other distances using the same strategy, but also with
- distances computed with the comparable version of the haversine strategy.
- * It can serve as the basis for the computation of the cross track distance,
- as it is more efficient to compute its comparable version and
- transform that to the actual cross track distance, rather than
- follow/use the reference implementation listed above.
- Major idea
- ----------
- The idea here is to use the comparable haversine strategy to compute
- the distances d1, d2 and d3 in the above listing. Once we have done
- that we need also to make sure that instead of returning XTD (as
- computed above) that we return a distance CXTD that is compatible
- with the comparable haversine distance. To achieve this CXTD must satisfy
- the relation:
- XTD = 2 * R * asin( sqrt(XTD) )
- where R is the sphere's radius.
- Below we perform the mathematical analysis that show how to compute CXTD.
- Mathematical analysis
- ---------------------
- Below we use the following trigonometric identities:
- sin(2 * x) = 2 * sin(x) * cos(x)
- cos(asin(x)) = sqrt(1 - x^2)
- Observation:
- The distance d1 needed when the projection of the point D is within the
- segment must be the true distance. However, comparable::haversine<>
- returns a comparable distance instead of the one needed.
- To remedy this, we implicitly compute what is needed.
- More precisely, we need to compute sin(true_d1):
- sin(true_d1) = sin(2 * asin(sqrt(d1)))
- = 2 * sin(asin(sqrt(d1)) * cos(asin(sqrt(d1)))
- = 2 * sqrt(d1) * sqrt(1-(sqrt(d1))^2)
- = 2 * sqrt(d1 - d1 * d1)
- This relation is used below.
- As we mentioned above the goal is to find CXTD (named "a" below for
- brevity) such that ("b" below stands for "d1", and "c" for "d_crs1"):
- 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
- Analysis:
- 2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
- <=> 2 * asin(sqrt(a)) == asin(sqrt(b-b^2) * sin(c))
- <=> sin(2 * asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
- <=> 2 * sin(asin(sqrt(a))) * cos(asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
- <=> 2 * sqrt(a) * sqrt(1-a) == 2 * sqrt(b-b^2) * sin(c)
- <=> sqrt(a) * sqrt(1-a) == sqrt(b-b^2) * sin(c)
- <=> sqrt(a-a^2) == sqrt(b-b^2) * sin(c)
- <=> a-a^2 == (b-b^2) * (sin(c))^2
- Consider the quadratic equation: x^2-x+p^2 == 0,
- where p = sqrt(b-b^2) * sin(c); its discriminant is:
- d = 1 - 4 * p^2 = 1 - 4 * (b-b^2) * (sin(c))^2
- The two solutions are:
- a_1 = (1 - sqrt(d)) / 2
- a_2 = (1 + sqrt(d)) / 2
- Which one to choose?
- "a" refers to the distance (on the unit sphere) of D from the
- supporting great circle Circ(A,B) of the segment AB.
- The two different values for "a" correspond to the lengths of the two
- arcs delimited D and the points of intersection of Circ(A,B) and the
- great circle perperdicular to Circ(A,B) passing through D.
- Clearly, the value we want is the smallest among these two distances,
- hence the root we must choose is the smallest root among the two.
- So the answer is:
- CXTD = ( 1 - sqrt(1 - 4 * (b-b^2) * (sin(c))^2) ) / 2
- Therefore, in order to implement the comparable version of the cross
- track strategy we need to:
- (1) Use the comparable version of the haversine strategy instead of
- the non-comparable one.
- (2) Instead of return XTD when D projects inside the segment AB, we
- need to return CXTD, given by the following formula:
- CXTD = ( 1 - sqrt(1 - 4 * (d1-d1^2) * (sin(d_crs1))^2) ) / 2;
- Complexity Analysis
- -------------------
- In the analysis that follows we refer to the actual implementation below.
- In particular, instead of computing CXTD as above, we use the more
- efficient (operation-wise) computation of CXTD shown here:
- return_type sin_d_crs1 = sin(d_crs1);
- return_type d1_x_sin = d1 * sin_d_crs1;
- return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
- return d / (0.5 + math::sqrt(0.25 - d));
- Notice that instead of computing:
- 0.5 - 0.5 * sqrt(1 - 4 * d) = 0.5 - sqrt(0.25 - d)
- we use the following formula instead:
- d / (0.5 + sqrt(0.25 - d)).
- This is done for numerical robustness. The expression 0.5 - sqrt(0.25 - x)
- has large numerical errors for values of x close to 0 (if using doubles
- the error start to become large even when d is as large as 0.001).
- To remedy that, we re-write 0.5 - sqrt(0.25 - x) as:
- 0.5 - sqrt(0.25 - d)
- = (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d)) / (0.5 + sqrt(0.25 - d)).
- The numerator is the difference of two squares:
- (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d))
- = 0.5^2 - (sqrt(0.25 - d))^ = 0.25 - (0.25 - d) = d,
- which gives the expression we use.
- For the complexity analysis, we distinguish between two cases:
- (A) The distance is realized between the point D and an
- endpoint of the segment AB
- Gains:
- Since we are using comparable::haversine<> which is called
- 3 times, we gain:
- -> 3 calls to sqrt
- -> 3 calls to asin
- -> 6 multiplications
- Loses: None
- So the net gain is:
- -> 6 function calls (sqrt/asin)
- -> 6 arithmetic operations
- If we use comparable::cross_track<> to compute
- cross_track<> we need to account for a call to sqrt, a call
- to asin and 2 multiplications. In this case the net gain is:
- -> 4 function calls (sqrt/asin)
- -> 4 arithmetic operations
- (B) The distance is realized between the point D and an
- interior point of the segment AB
- Gains:
- Since we are using comparable::haversine<> which is called
- 3 times, we gain:
- -> 3 calls to sqrt
- -> 3 calls to asin
- -> 6 multiplications
- Also we gain the operations used to compute XTD:
- -> 2 calls to sin
- -> 1 call to asin
- -> 1 call to abs
- -> 2 multiplications
- -> 1 division
- So the total gains are:
- -> 9 calls to sqrt/sin/asin
- -> 1 call to abs
- -> 8 multiplications
- -> 1 division
- Loses:
- To compute a distance compatible with comparable::haversine<>
- we need to perform a few more operations, namely:
- -> 1 call to sin
- -> 1 call to sqrt
- -> 2 multiplications
- -> 1 division
- -> 1 addition
- -> 2 subtractions
- So roughly speaking the net gain is:
- -> 8 fewer function calls and 3 fewer arithmetic operations
- If we were to implement cross_track directly from the
- comparable version (much like what haversine<> does using
- comparable::haversine<>) we need additionally
- -> 2 function calls (asin/sqrt)
- -> 2 multiplications
- So it pays off to re-implement cross_track<> to use
- comparable::cross_track<>; in this case the net gain would be:
- -> 6 function calls
- -> 1 arithmetic operation
- Summary/Conclusion
- ------------------
- Following the mathematical and complexity analysis above, the
- comparable cross track strategy (as implemented below) satisfies
- all the goal mentioned in the beginning:
- * It is more efficient than its non-comparable counter-part.
- * Comparable distances using this new strategy can also be compared
- with comparable distances computed with the comparable haversine
- strategy.
- * It turns out to be more efficient to compute the actual cross
- track distance XTD by first computing CXTD, and then computing
- XTD by means of the formula:
- XTD = 2 * R * asin( sqrt(CXTD) )
- */
- template
- <
- typename CalculationType = void,
- typename Strategy = comparable::haversine<double, CalculationType>
- >
- class cross_track
- {
- public:
- template <typename Point, typename PointOfSegment>
- struct return_type
- : promote_floating_point
- <
- typename select_calculation_type
- <
- Point,
- PointOfSegment,
- CalculationType
- >::type
- >
- {};
- using radius_type = typename Strategy::radius_type;
- cross_track() = default;
- explicit inline cross_track(typename Strategy::radius_type const& r)
- : m_strategy(r)
- {}
- inline cross_track(Strategy const& s)
- : m_strategy(s)
- {}
- // It might be useful in the future
- // to overload constructor with strategy info.
- // crosstrack(...) {}
- template <typename Point, typename PointOfSegment>
- inline typename return_type<Point, PointOfSegment>::type
- apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
- {
- #if !defined(BOOST_MSVC)
- BOOST_CONCEPT_ASSERT
- (
- (concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
- );
- #endif
- using return_type = typename return_type<Point, PointOfSegment>::type;
- // http://williams.best.vwh.net/avform.htm#XTE
- return_type d1 = m_strategy.apply(sp1, p);
- return_type d3 = m_strategy.apply(sp1, sp2);
- if (geometry::math::equals(d3, 0.0))
- {
- // "Degenerate" segment, return either d1 or d2
- return d1;
- }
- return_type d2 = m_strategy.apply(sp2, p);
- auto d_crs_pair = detail::compute_cross_track_pair<return_type>::apply(
- p, sp1, sp2);
- // d1, d2, d3 are in principle not needed, only the sign matters
- return_type projection1 = cos(d_crs_pair.first) * d1 / d3;
- return_type projection2 = cos(d_crs_pair.second) * d2 / d3;
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " "
- << crs_AD * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
- << crs_AB * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Course " << dsv(sp2) << " to " << dsv(sp1) << " "
- << crs_BA * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
- << crs_BD * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Projection AD-AB " << projection1 << " : "
- << d_crs1 * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Projection BD-BA " << projection2 << " : "
- << d_crs2 * geometry::math::r2d<return_type>() << std::endl;
- std::cout << " d1: " << (d1 )
- << " d2: " << (d2 )
- << std::endl;
- #endif
- if (projection1 > 0.0 && projection2 > 0.0)
- {
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- return_type XTD = radius() * geometry::math::abs( asin( sin( d1 ) * sin( d_crs1 ) ));
- std::cout << "Projection ON the segment" << std::endl;
- std::cout << "XTD: " << XTD
- << " d1: " << (d1 * radius())
- << " d2: " << (d2 * radius())
- << std::endl;
- #endif
- return detail::compute_cross_track_distance::apply(
- d_crs_pair.first, d1);
- }
- else
- {
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- std::cout << "Projection OUTSIDE the segment" << std::endl;
- #endif
- // Return shortest distance, project either on point sp1 or sp2
- return return_type( (std::min)( d1 , d2 ) );
- }
- }
- template <typename T1, typename T2>
- inline radius_type vertical_or_meridian(T1 lat1, T2 lat2) const
- {
- return m_strategy.radius() * (lat1 - lat2);
- }
- inline typename Strategy::radius_type radius() const
- { return m_strategy.radius(); }
- private :
- Strategy m_strategy;
- };
- } // namespace comparable
- /*!
- \brief Strategy functor for distance point to segment calculation
- \ingroup strategies
- \details Class which calculates the distance of a point to a segment, for points on a sphere or globe
- \see http://williams.best.vwh.net/avform.htm
- \tparam CalculationType \tparam_calculation
- \tparam Strategy underlying point-point distance strategy, defaults to haversine
- \qbk{
- [heading See also]
- [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
- }
- */
- template
- <
- typename CalculationType = void,
- typename Strategy = haversine<double, CalculationType>
- >
- class cross_track
- {
- public :
- template <typename Point, typename PointOfSegment>
- struct return_type
- : promote_floating_point
- <
- typename select_calculation_type
- <
- Point,
- PointOfSegment,
- CalculationType
- >::type
- >
- {};
- using radius_type = typename Strategy::radius_type;
- inline cross_track()
- {}
- explicit inline cross_track(typename Strategy::radius_type const& r)
- : m_strategy(r)
- {}
- inline cross_track(Strategy const& s)
- : m_strategy(s)
- {}
- // It might be useful in the future
- // to overload constructor with strategy info.
- // crosstrack(...) {}
- template <typename Point, typename PointOfSegment>
- inline auto apply(Point const& p,
- PointOfSegment const& sp1,
- PointOfSegment const& sp2) const
- {
- #if !defined(BOOST_MSVC)
- BOOST_CONCEPT_ASSERT
- (
- (concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
- );
- #endif
- using return_type = typename return_type<Point, PointOfSegment>::type;
- using this_type = cross_track<CalculationType, Strategy>;
- using comparable_type = typename services::comparable_type
- <
- this_type
- >::type;
- comparable_type cstrategy
- = services::get_comparable<this_type>::apply(m_strategy);
- return_type const a = cstrategy.apply(p, sp1, sp2);
- return_type const c = return_type(2.0) * asin(math::sqrt(a));
- return c * radius();
- }
- template <typename T1, typename T2>
- inline radius_type vertical_or_meridian(T1 lat1, T2 lat2) const
- {
- return m_strategy.radius() * (lat1 - lat2);
- }
- inline typename Strategy::radius_type radius() const
- { return m_strategy.radius(); }
- private :
- Strategy m_strategy;
- };
- #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
- namespace services
- {
- template <typename CalculationType, typename Strategy>
- struct tag<cross_track<CalculationType, Strategy> >
- {
- using type = strategy_tag_distance_point_segment;
- };
- template <typename CalculationType, typename Strategy, typename P, typename PS>
- struct return_type<cross_track<CalculationType, Strategy>, P, PS>
- : cross_track<CalculationType, Strategy>::template return_type<P, PS>
- {};
- template <typename CalculationType, typename Strategy>
- struct comparable_type<cross_track<CalculationType, Strategy> >
- {
- using type = comparable::cross_track
- <
- CalculationType, typename comparable_type<Strategy>::type
- > ;
- };
- template
- <
- typename CalculationType,
- typename Strategy
- >
- struct get_comparable<cross_track<CalculationType, Strategy> >
- {
- using comparable_type = typename comparable_type
- <
- cross_track<CalculationType, Strategy>
- >::type;
- public :
- static inline comparable_type
- apply(cross_track<CalculationType, Strategy> const& strategy)
- {
- return comparable_type(strategy.radius());
- }
- };
- template
- <
- typename CalculationType,
- typename Strategy,
- typename P,
- typename PS
- >
- struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS>
- {
- private :
- using return_type = typename cross_track
- <
- CalculationType, Strategy
- >::template return_type<P, PS>::type;
- public :
- template <typename T>
- static inline return_type
- apply(cross_track<CalculationType, Strategy> const& , T const& distance)
- {
- return distance;
- }
- };
- // Specializations for comparable::cross_track
- template <typename RadiusType, typename CalculationType>
- struct tag<comparable::cross_track<RadiusType, CalculationType> >
- {
- using type = strategy_tag_distance_point_segment;
- };
- template
- <
- typename RadiusType,
- typename CalculationType,
- typename P,
- typename PS
- >
- struct return_type<comparable::cross_track<RadiusType, CalculationType>, P, PS>
- : comparable::cross_track
- <
- RadiusType, CalculationType
- >::template return_type<P, PS>
- {};
- template <typename RadiusType, typename CalculationType>
- struct comparable_type<comparable::cross_track<RadiusType, CalculationType> >
- {
- using type = comparable::cross_track<RadiusType, CalculationType>;
- };
- template <typename RadiusType, typename CalculationType>
- struct get_comparable<comparable::cross_track<RadiusType, CalculationType> >
- {
- private :
- using this_type = comparable::cross_track<RadiusType, CalculationType>;
- public :
- static inline this_type apply(this_type const& input)
- {
- return input;
- }
- };
- template
- <
- typename RadiusType,
- typename CalculationType,
- typename P,
- typename PS
- >
- struct result_from_distance
- <
- comparable::cross_track<RadiusType, CalculationType>, P, PS
- >
- {
- private :
- using strategy_type = comparable::cross_track<RadiusType, CalculationType>;
- using return_type = typename return_type<strategy_type, P, PS>::type;
- public :
- template <typename T>
- static inline return_type apply(strategy_type const& strategy,
- T const& distance)
- {
- return_type const s
- = sin( (distance / strategy.radius()) / return_type(2.0) );
- return s * s;
- }
- };
- /*
- TODO: spherical polar coordinate system requires "get_as_radian_equatorial<>"
- template <typename Point, typename PointOfSegment, typename Strategy>
- struct default_strategy
- <
- segment_tag, Point, PointOfSegment,
- spherical_polar_tag, spherical_polar_tag,
- Strategy
- >
- {
- typedef cross_track
- <
- void,
- std::conditional_t
- <
- std::is_void<Strategy>::value,
- typename default_strategy
- <
- point_tag, Point, PointOfSegment,
- spherical_polar_tag, spherical_polar_tag
- >::type,
- Strategy
- >
- > type;
- };
- */
- template <typename Point, typename PointOfSegment, typename Strategy>
- struct default_strategy
- <
- point_tag, segment_tag, Point, PointOfSegment,
- spherical_equatorial_tag, spherical_equatorial_tag,
- Strategy
- >
- {
- using type = cross_track
- <
- void,
- std::conditional_t
- <
- std::is_void<Strategy>::value,
- typename default_strategy
- <
- point_tag, point_tag, Point, PointOfSegment,
- spherical_equatorial_tag, spherical_equatorial_tag
- >::type,
- Strategy
- >
- >;
- };
- template <typename PointOfSegment, typename Point, typename Strategy>
- struct default_strategy
- <
- segment_tag, point_tag, PointOfSegment, Point,
- spherical_equatorial_tag, spherical_equatorial_tag,
- Strategy
- >
- {
- using type = typename default_strategy
- <
- point_tag, segment_tag, Point, PointOfSegment,
- spherical_equatorial_tag, spherical_equatorial_tag,
- Strategy
- >::type;
- };
- } // namespace services
- #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
- }} // namespace strategy::distance
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
|