mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-25 16:48:10 +00:00
Added thirdparty: boost library
This commit is contained in:
+848
@@ -0,0 +1,848 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user