You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
349 lines
9.5 KiB
349 lines
9.5 KiB
// Boost.Geometry (aka GGL, Generic Geometry Library) |
|
|
|
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. |
|
|
|
// 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 <boost/concept_check.hpp> |
|
#include <boost/mpl/if.hpp> |
|
#include <boost/type_traits.hpp> |
|
|
|
#include <boost/geometry/core/cs.hpp> |
|
#include <boost/geometry/core/access.hpp> |
|
#include <boost/geometry/core/radian_access.hpp> |
|
|
|
|
|
#include <boost/geometry/strategies/distance.hpp> |
|
#include <boost/geometry/strategies/concepts/distance_concept.hpp> |
|
|
|
#include <boost/geometry/util/promote_floating_point.hpp> |
|
#include <boost/geometry/util/math.hpp> |
|
|
|
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK |
|
# include <boost/geometry/util/write_dsv.hpp> |
|
#endif |
|
|
|
|
|
|
|
namespace boost { namespace geometry |
|
{ |
|
|
|
namespace strategy { namespace distance |
|
{ |
|
|
|
/*! |
|
\brief Strategy functor for distance point to segment calculation |
|
\ingroup strategies |
|
\details Class which calculates the distance of a point to a segment, using latlong points |
|
\see http://williams.best.vwh.net/avform.htm |
|
\tparam Point point type |
|
\tparam PointOfSegment \tparam_segment_point |
|
\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 Point, |
|
typename PointOfSegment = Point, |
|
typename CalculationType = void, |
|
typename Strategy = typename services::default_strategy<point_tag, Point>::type |
|
> |
|
class cross_track |
|
{ |
|
public : |
|
typedef typename promote_floating_point |
|
< |
|
typename select_calculation_type |
|
< |
|
Point, |
|
PointOfSegment, |
|
CalculationType |
|
>::type |
|
>::type return_type; |
|
|
|
inline cross_track() |
|
{ |
|
m_strategy = Strategy(); |
|
m_radius = m_strategy.radius(); |
|
} |
|
|
|
inline cross_track(return_type const& r) |
|
: m_radius(r) |
|
, m_strategy(r) |
|
{} |
|
|
|
inline cross_track(Strategy const& s) |
|
: m_strategy(s) |
|
{ |
|
m_radius = m_strategy.radius(); |
|
} |
|
|
|
|
|
// It might be useful in the future |
|
// to overload constructor with strategy info. |
|
// crosstrack(...) {} |
|
|
|
|
|
inline return_type apply(Point const& p, |
|
PointOfSegment const& sp1, PointOfSegment const& sp2) const |
|
{ |
|
// http://williams.best.vwh.net/avform.htm#XTE |
|
return_type d1 = m_strategy.apply(sp1, p); |
|
|
|
// Actually, calculation of d2 not necessary if we know that the projected point is on the great circle... |
|
return_type d2 = m_strategy.apply(sp2, p); |
|
|
|
return_type crs_AD = course(sp1, p); |
|
return_type crs_AB = course(sp1, sp2); |
|
return_type XTD = m_radius * geometry::math::abs(asin(sin(d1 / m_radius) * sin(crs_AD - crs_AB))); |
|
|
|
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK |
|
std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; |
|
std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; |
|
std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; |
|
#endif |
|
|
|
|
|
// Return shortest distance, either to projected point on segment sp1-sp2, or to sp1, or to sp2 |
|
return return_type((std::min)((std::min)(d1, d2), XTD)); |
|
} |
|
|
|
inline return_type radius() const { return m_radius; } |
|
|
|
private : |
|
BOOST_CONCEPT_ASSERT |
|
( |
|
(geometry::concept::PointDistanceStrategy<Strategy >) |
|
); |
|
|
|
|
|
return_type m_radius; |
|
|
|
// Point-point distances are calculated in radians, on the unit sphere |
|
Strategy m_strategy; |
|
|
|
/// Calculate course (bearing) between two points. Might be moved to a "course formula" ... |
|
inline return_type course(Point const& p1, Point const& p2) const |
|
{ |
|
// http://williams.best.vwh.net/avform.htm#Crs |
|
return_type dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1); |
|
return_type cos_p2lat = cos(get_as_radian<1>(p2)); |
|
|
|
// "An alternative formula, not requiring the pre-computation of d" |
|
return atan2(sin(dlon) * cos_p2lat, |
|
cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2)) |
|
- sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon)); |
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS |
|
namespace services |
|
{ |
|
|
|
template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> |
|
struct tag<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
typedef strategy_tag_distance_point_segment type; |
|
}; |
|
|
|
|
|
template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> |
|
struct return_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type type; |
|
}; |
|
|
|
|
|
template |
|
< |
|
typename Point, |
|
typename PointOfSegment, |
|
typename CalculationType, |
|
typename Strategy, |
|
typename P, |
|
typename PS |
|
> |
|
struct similar_type<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS> |
|
{ |
|
typedef cross_track<Point, PointOfSegment, CalculationType, Strategy> type; |
|
}; |
|
|
|
|
|
template |
|
< |
|
typename Point, |
|
typename PointOfSegment, |
|
typename CalculationType, |
|
typename Strategy, |
|
typename P, |
|
typename PS |
|
> |
|
struct get_similar<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS> |
|
{ |
|
static inline typename similar_type |
|
< |
|
cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS |
|
>::type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy) |
|
{ |
|
return cross_track<P, PS, CalculationType, Strategy>(strategy.radius()); |
|
} |
|
}; |
|
|
|
|
|
template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy> |
|
struct comparable_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
// Comparable type is here just the strategy |
|
typedef typename similar_type |
|
< |
|
cross_track |
|
< |
|
Point, PointOfSegment, CalculationType, Strategy |
|
>, Point, PointOfSegment |
|
>::type type; |
|
}; |
|
|
|
|
|
template |
|
< |
|
typename Point, typename PointOfSegment, |
|
typename CalculationType, |
|
typename Strategy |
|
> |
|
struct get_comparable<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
typedef typename comparable_type |
|
< |
|
cross_track<Point, PointOfSegment, CalculationType, Strategy> |
|
>::type comparable_type; |
|
public : |
|
static inline comparable_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy) |
|
{ |
|
return comparable_type(strategy.radius()); |
|
} |
|
}; |
|
|
|
|
|
template |
|
< |
|
typename Point, typename PointOfSegment, |
|
typename CalculationType, |
|
typename Strategy |
|
> |
|
struct result_from_distance<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
private : |
|
typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type return_type; |
|
public : |
|
template <typename T> |
|
static inline return_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& , T const& distance) |
|
{ |
|
return distance; |
|
} |
|
}; |
|
|
|
|
|
template |
|
< |
|
typename Point, typename PointOfSegment, |
|
typename CalculationType, |
|
typename Strategy |
|
> |
|
struct strategy_point_point<cross_track<Point, PointOfSegment, CalculationType, Strategy> > |
|
{ |
|
typedef Strategy type; |
|
}; |
|
|
|
|
|
|
|
/* |
|
|
|
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 |
|
< |
|
Point, |
|
PointOfSegment, |
|
void, |
|
typename boost::mpl::if_ |
|
< |
|
boost::is_void<Strategy>, |
|
typename default_strategy |
|
< |
|
point_tag, Point, PointOfSegment, |
|
spherical_polar_tag, spherical_polar_tag |
|
>::type, |
|
Strategy |
|
>::type |
|
> type; |
|
}; |
|
*/ |
|
|
|
template <typename Point, typename PointOfSegment, typename Strategy> |
|
struct default_strategy |
|
< |
|
segment_tag, Point, PointOfSegment, |
|
spherical_equatorial_tag, spherical_equatorial_tag, |
|
Strategy |
|
> |
|
{ |
|
typedef cross_track |
|
< |
|
Point, |
|
PointOfSegment, |
|
void, |
|
typename boost::mpl::if_ |
|
< |
|
boost::is_void<Strategy>, |
|
typename default_strategy |
|
< |
|
point_tag, Point, PointOfSegment, |
|
spherical_equatorial_tag, spherical_equatorial_tag |
|
>::type, |
|
Strategy |
|
>::type |
|
> type; |
|
}; |
|
|
|
|
|
|
|
} // namespace services |
|
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS |
|
|
|
|
|
}} // namespace strategy::distance |
|
|
|
|
|
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS |
|
|
|
|
|
#endif |
|
|
|
|
|
}} // namespace boost::geometry |
|
|
|
|
|
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
|
|
|