123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // Boost.Geometry
- // Copyright (c) 2021, Oracle and/or its affiliates.
- // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
- // Licensed under the Boost Software License version 1.0.
- // http://www.boost.org/users/license.html
- #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_CLOSEST_POINTS_CROSS_TRACK_HPP
- #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_CLOSEST_POINTS_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/distance_cross_track.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 closest_points
- {
- template
- <
- typename CalculationType = void,
- typename Strategy = distance::comparable::haversine<double, CalculationType>
- >
- class cross_track
- {
- public:
- template <typename Point, typename PointOfSegment>
- struct calculation_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)
- {}
- template <typename Point, typename PointOfSegment>
- inline auto apply(Point const& p,
- PointOfSegment const& sp1,
- PointOfSegment const& sp2) const
- {
- using CT = typename calculation_type<Point, PointOfSegment>::type;
- // http://williams.best.vwh.net/avform.htm#XTE
- CT d3 = m_strategy.apply(sp1, sp2);
- if (geometry::math::equals(d3, 0.0))
- {
- // "Degenerate" segment, return either d1 or d2
- return sp1;
- }
- CT d1 = m_strategy.apply(sp1, p);
- CT d2 = m_strategy.apply(sp2, p);
- auto d_crs_pair = distance::detail::compute_cross_track_pair<CT>::apply(
- p, sp1, sp2);
- // d1, d2, d3 are in principle not needed, only the sign matters
- CT projection1 = cos(d_crs_pair.first) * d1 / d3;
- CT 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<CT>() << std::endl;
- std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
- << crs_AB * geometry::math::r2d<CT>() << std::endl;
- std::cout << "Course " << dsv(sp2) << " to " << dsv(sp1) << " "
- << crs_BA * geometry::math::r2d<CT>() << std::endl;
- std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
- << crs_BD * geometry::math::r2d<CT>() << std::endl;
- std::cout << "Projection AD-AB " << projection1 << " : "
- << d_crs1 * geometry::math::r2d<CT>() << std::endl;
- std::cout << "Projection BD-BA " << projection2 << " : "
- << d_crs2 * geometry::math::r2d<CT>() << std::endl;
- std::cout << " d1: " << (d1 )
- << " d2: " << (d2 )
- << std::endl;
- #endif
- if (projection1 > 0.0 && projection2 > 0.0)
- {
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- CT 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
- auto distance = distance::detail::compute_cross_track_distance::apply(
- d_crs_pair.first, d1);
- CT lon1 = geometry::get_as_radian<0>(sp1);
- CT lat1 = geometry::get_as_radian<1>(sp1);
- CT lon2 = geometry::get_as_radian<0>(sp2);
- CT lat2 = geometry::get_as_radian<1>(sp2);
- CT dist = CT(2) * asin(math::sqrt(distance)) * m_strategy.radius();
- CT dist_d1 = CT(2) * asin(math::sqrt(d1)) * m_strategy.radius();
- // Note: this is similar to spherical computation in geographic
- // point_segment_distance formula
- CT earth_radius = m_strategy.radius();
- CT cos_frac = cos(dist_d1 / earth_radius) / cos(dist / earth_radius);
- CT s14_sph = cos_frac >= 1
- ? CT(0) : cos_frac <= -1 ? math::pi<CT>() * earth_radius
- : acos(cos_frac) * earth_radius;
- CT a12 = geometry::formula::spherical_azimuth<>(lon1, lat1, lon2, lat2);
- auto res_direct = geometry::formula::spherical_direct
- <
- true,
- false
- >(lon1, lat1, s14_sph, a12, srs::sphere<CT>(earth_radius));
- model::point
- <
- CT,
- dimension<PointOfSegment>::value,
- typename coordinate_system<PointOfSegment>::type
- > cp;
- geometry::set_from_radian<0>(cp, res_direct.lon2);
- geometry::set_from_radian<1>(cp, res_direct.lat2);
- return cp;
- }
- else
- {
- #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- std::cout << "Projection OUTSIDE the segment" << std::endl;
- #endif
- return d1 < d2 ? sp1 : sp2;
- }
- }
- 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 strategy::closest_points
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_CLOSEST_POINTS_CROSS_TRACK_HPP
|