123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
- // This file was modified by Oracle on 2015, 2017, 2019.
- // Modifications copyright (c) 2015-2019 Oracle and/or its affiliates.
- // 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_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
- #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
- #include <boost/geometry/core/access.hpp>
- #include <boost/geometry/arithmetic/infinite_line_functions.hpp>
- #include <boost/geometry/algorithms/detail/make/make.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/util/select_coordinate_type.hpp>
- #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
- #include <boost/mpl/assert.hpp>
- namespace boost { namespace geometry
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- template <typename CSTag>
- struct direction_code_impl
- {
- BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
- };
- template <>
- struct direction_code_impl<cartesian_tag>
- {
- template <typename Point1, typename Point2>
- static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
- Point2 const& point)
- {
- typedef typename geometry::select_coordinate_type
- <
- Point1, Point2
- >::type calc_t;
- typedef model::infinite_line<calc_t> line_type;
- // point b is often equal to the specified point, check that first
- line_type const q = detail::make::make_infinite_line<calc_t>(segment_b, point);
- if (arithmetic::is_degenerate(q))
- {
- return 0;
- }
- line_type const p = detail::make::make_infinite_line<calc_t>(segment_a, segment_b);
- if (arithmetic::is_degenerate(p))
- {
- return 0;
- }
- // p extends a-b if direction is similar
- return arithmetic::similar_direction(p, q) ? 1 : -1;
- }
- };
- template <>
- struct direction_code_impl<spherical_equatorial_tag>
- {
- template <typename Point1, typename Point2>
- static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
- Point2 const& p)
- {
- typedef typename coordinate_type<Point1>::type coord1_t;
- typedef typename coordinate_type<Point2>::type coord2_t;
- typedef typename cs_angular_units<Point1>::type units_t;
- typedef typename cs_angular_units<Point2>::type units2_t;
- BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
- NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
- (units_t, units2_t));
- typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
- typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
- typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
- static coord1_t const pi_half1 = constants1::max_latitude();
- static coord2_t const pi_half2 = constants2::max_latitude();
- static calc_t const c0 = 0;
- coord1_t const a0 = geometry::get<0>(segment_a);
- coord1_t const a1 = geometry::get<1>(segment_a);
- coord1_t const b0 = geometry::get<0>(segment_b);
- coord1_t const b1 = geometry::get<1>(segment_b);
- coord2_t const p0 = geometry::get<0>(p);
- coord2_t const p1 = geometry::get<1>(p);
-
- if ( (math::equals(b0, a0) && math::equals(b1, a1))
- || (math::equals(b0, p0) && math::equals(b1, p1)) )
- {
- return 0;
- }
- bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
- bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
- bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
- if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
- || (is_p_pole && math::sign(b1) == math::sign(p1))) )
- {
- return 0;
- }
- // NOTE: as opposed to the implementation for cartesian CS
- // here point b is the origin
- calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0);
- calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0);
- bool is_antilon1 = false, is_antilon2 = false;
- calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
- calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
- calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
- c0 :
- (std::min)(is_antilon1 ? c0 : math::abs(dlon1),
- is_antilon2 ? c0 : math::abs(dlon2));
- calc_t my = (std::min)(math::abs(dlat1),
- math::abs(dlat2));
- int s1 = 0, s2 = 0;
- if (mx >= my)
- {
- s1 = dlon1 > 0 ? 1 : -1;
- s2 = dlon2 > 0 ? 1 : -1;
- }
- else
- {
- s1 = dlat1 > 0 ? 1 : -1;
- s2 = dlat2 > 0 ? 1 : -1;
- }
- return s1 == s2 ? -1 : 1;
- }
- template <typename Units, typename T>
- static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
- {
- typedef math::detail::constants_on_spheroid<T, Units> constants;
- static T const pi = constants::half_period();
- static T const c0 = 0;
- T res = lat2 - lat1;
- is_antilon = math::equals(math::abs(lon_ds), pi);
- if (is_antilon)
- {
- res = lat2 + lat1;
- if (res >= c0)
- res = pi - res;
- else
- res = -pi - res;
- }
- return res;
- }
- };
- template <>
- struct direction_code_impl<spherical_polar_tag>
- {
- template <typename Point1, typename Point2>
- static inline int apply(Point1 segment_a, Point1 segment_b,
- Point2 p)
- {
- typedef math::detail::constants_on_spheroid
- <
- typename coordinate_type<Point1>::type,
- typename cs_angular_units<Point1>::type
- > constants1;
- typedef math::detail::constants_on_spheroid
- <
- typename coordinate_type<Point2>::type,
- typename cs_angular_units<Point2>::type
- > constants2;
- geometry::set<1>(segment_a,
- constants1::max_latitude() - geometry::get<1>(segment_a));
- geometry::set<1>(segment_b,
- constants1::max_latitude() - geometry::get<1>(segment_b));
- geometry::set<1>(p,
- constants2::max_latitude() - geometry::get<1>(p));
- return direction_code_impl
- <
- spherical_equatorial_tag
- >::apply(segment_a, segment_b, p);
- }
- };
- // if spherical_tag is passed then pick cs_tag based on Point1 type
- // with spherical_equatorial_tag as the default
- template <>
- struct direction_code_impl<spherical_tag>
- {
- template <typename Point1, typename Point2>
- static inline int apply(Point1 segment_a, Point1 segment_b,
- Point2 p)
- {
- return direction_code_impl
- <
- typename boost::mpl::if_c
- <
- boost::is_same
- <
- typename geometry::cs_tag<Point1>::type,
- spherical_polar_tag
- >::value,
- spherical_polar_tag,
- spherical_equatorial_tag
- >::type
- >::apply(segment_a, segment_b, p);
- }
- };
- template <>
- struct direction_code_impl<geographic_tag>
- : direction_code_impl<spherical_equatorial_tag>
- {};
- // Gives sense of direction for point p, collinear w.r.t. segment (a,b)
- // Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
- // Returns 1 if p goes forward, so extends (a,b)
- // Returns 0 if p is equal with b, or if (a,b) is degenerate
- // Note that it does not do any collinearity test, that should be done before
- template <typename CSTag, typename Point1, typename Point2>
- inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
- Point2 const& p)
- {
- return direction_code_impl<CSTag>::apply(segment_a, segment_b, p);
- }
- } // namespace detail
- #endif //DOXYGEN_NO_DETAIL
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
|