distance_projected_point.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
  3. // Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
  5. // This file was modified by Oracle on 2014, 2018, 2019.
  6. // Modifications copyright (c) 2014-2019, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  8. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  9. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  10. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  11. // Use, modification and distribution is subject to the Boost Software License,
  12. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  13. // http://www.boost.org/LICENSE_1_0.txt)
  14. #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
  15. #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
  16. #include <boost/concept_check.hpp>
  17. #include <boost/core/ignore_unused.hpp>
  18. #include <boost/mpl/if.hpp>
  19. #include <boost/type_traits/is_void.hpp>
  20. #include <boost/geometry/core/access.hpp>
  21. #include <boost/geometry/core/point_type.hpp>
  22. #include <boost/geometry/algorithms/convert.hpp>
  23. #include <boost/geometry/arithmetic/arithmetic.hpp>
  24. #include <boost/geometry/arithmetic/dot_product.hpp>
  25. #include <boost/geometry/strategies/tags.hpp>
  26. #include <boost/geometry/strategies/distance.hpp>
  27. #include <boost/geometry/strategies/default_distance_result.hpp>
  28. #include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
  29. #include <boost/geometry/strategies/cartesian/point_in_point.hpp>
  30. #include <boost/geometry/strategies/cartesian/intersection.hpp>
  31. #include <boost/geometry/util/select_coordinate_type.hpp>
  32. // Helper geometry (projected point on line)
  33. #include <boost/geometry/geometries/point.hpp>
  34. namespace boost { namespace geometry
  35. {
  36. namespace strategy { namespace distance
  37. {
  38. /*!
  39. \brief Strategy for distance point to segment
  40. \ingroup strategies
  41. \details Calculates distance using projected-point method, and (optionally) Pythagoras
  42. \author Adapted from: http://geometryalgorithms.com/Archive/algorithm_0102/algorithm_0102.htm
  43. \tparam CalculationType \tparam_calculation
  44. \tparam Strategy underlying point-point distance strategy
  45. \par Concepts for Strategy:
  46. - cartesian_distance operator(Point,Point)
  47. \note If the Strategy is a "comparable::pythagoras", this strategy
  48. automatically is a comparable projected_point strategy (so without sqrt)
  49. \qbk{
  50. [heading See also]
  51. [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
  52. }
  53. */
  54. template
  55. <
  56. typename CalculationType = void,
  57. typename Strategy = pythagoras<CalculationType>
  58. >
  59. class projected_point
  60. {
  61. public :
  62. typedef within::cartesian_point_point equals_point_point_strategy_type;
  63. typedef intersection::cartesian_segments
  64. <
  65. CalculationType
  66. > relate_segment_segment_strategy_type;
  67. static inline relate_segment_segment_strategy_type get_relate_segment_segment_strategy()
  68. {
  69. return relate_segment_segment_strategy_type();
  70. }
  71. typedef within::cartesian_winding
  72. <
  73. void, void, CalculationType
  74. > point_in_geometry_strategy_type;
  75. static inline point_in_geometry_strategy_type get_point_in_geometry_strategy()
  76. {
  77. return point_in_geometry_strategy_type();
  78. }
  79. // The three typedefs below are necessary to calculate distances
  80. // from segments defined in integer coordinates.
  81. // Integer coordinates can still result in FP distances.
  82. // There is a division, which must be represented in FP.
  83. // So promote.
  84. template <typename Point, typename PointOfSegment>
  85. struct calculation_type
  86. : promote_floating_point
  87. <
  88. typename strategy::distance::services::return_type
  89. <
  90. Strategy,
  91. Point,
  92. PointOfSegment
  93. >::type
  94. >
  95. {};
  96. template <typename Point, typename PointOfSegment>
  97. inline typename calculation_type<Point, PointOfSegment>::type
  98. apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
  99. {
  100. assert_dimension_equal<Point, PointOfSegment>();
  101. typedef typename calculation_type<Point, PointOfSegment>::type calculation_type;
  102. // A projected point of points in Integer coordinates must be able to be
  103. // represented in FP.
  104. typedef model::point
  105. <
  106. calculation_type,
  107. dimension<PointOfSegment>::value,
  108. typename coordinate_system<PointOfSegment>::type
  109. > fp_point_type;
  110. // For convenience
  111. typedef fp_point_type fp_vector_type;
  112. /*
  113. Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)]
  114. VECTOR v(x2 - x1, y2 - y1)
  115. VECTOR w(px - x1, py - y1)
  116. c1 = w . v
  117. c2 = v . v
  118. b = c1 / c2
  119. RETURN POINT(x1 + b * vx, y1 + b * vy)
  120. */
  121. // v is multiplied below with a (possibly) FP-value, so should be in FP
  122. // For consistency we define w also in FP
  123. fp_vector_type v, w, projected;
  124. geometry::convert(p2, v);
  125. geometry::convert(p, w);
  126. geometry::convert(p1, projected);
  127. subtract_point(v, projected);
  128. subtract_point(w, projected);
  129. Strategy strategy;
  130. boost::ignore_unused(strategy);
  131. calculation_type const zero = calculation_type();
  132. calculation_type const c1 = dot_product(w, v);
  133. if (c1 <= zero)
  134. {
  135. return strategy.apply(p, p1);
  136. }
  137. calculation_type const c2 = dot_product(v, v);
  138. if (c2 <= c1)
  139. {
  140. return strategy.apply(p, p2);
  141. }
  142. // See above, c1 > 0 AND c2 > c1 so: c2 != 0
  143. calculation_type const b = c1 / c2;
  144. multiply_value(v, b);
  145. add_point(projected, v);
  146. return strategy.apply(p, projected);
  147. }
  148. template <typename CT>
  149. inline CT vertical_or_meridian(CT const& lat1, CT const& lat2) const
  150. {
  151. return lat1 - lat2;
  152. }
  153. };
  154. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  155. namespace services
  156. {
  157. template <typename CalculationType, typename Strategy>
  158. struct tag<projected_point<CalculationType, Strategy> >
  159. {
  160. typedef strategy_tag_distance_point_segment type;
  161. };
  162. template <typename CalculationType, typename Strategy, typename P, typename PS>
  163. struct return_type<projected_point<CalculationType, Strategy>, P, PS>
  164. : projected_point<CalculationType, Strategy>::template calculation_type<P, PS>
  165. {};
  166. template <typename CalculationType, typename Strategy>
  167. struct comparable_type<projected_point<CalculationType, Strategy> >
  168. {
  169. // Define a projected_point strategy with its underlying point-point-strategy
  170. // being comparable
  171. typedef projected_point
  172. <
  173. CalculationType,
  174. typename comparable_type<Strategy>::type
  175. > type;
  176. };
  177. template <typename CalculationType, typename Strategy>
  178. struct get_comparable<projected_point<CalculationType, Strategy> >
  179. {
  180. typedef typename comparable_type
  181. <
  182. projected_point<CalculationType, Strategy>
  183. >::type comparable_type;
  184. public :
  185. static inline comparable_type apply(projected_point<CalculationType, Strategy> const& )
  186. {
  187. return comparable_type();
  188. }
  189. };
  190. template <typename CalculationType, typename Strategy, typename P, typename PS>
  191. struct result_from_distance<projected_point<CalculationType, Strategy>, P, PS>
  192. {
  193. private :
  194. typedef typename return_type<projected_point<CalculationType, Strategy>, P, PS>::type return_type;
  195. public :
  196. template <typename T>
  197. static inline return_type apply(projected_point<CalculationType, Strategy> const& , T const& value)
  198. {
  199. Strategy s;
  200. return result_from_distance<Strategy, P, PS>::apply(s, value);
  201. }
  202. };
  203. // Get default-strategy for point-segment distance calculation
  204. // while still have the possibility to specify point-point distance strategy (PPS)
  205. // It is used in algorithms/distance.hpp where users specify PPS for distance
  206. // of point-to-segment or point-to-linestring.
  207. // Convenient for geographic coordinate systems especially.
  208. template <typename Point, typename PointOfSegment, typename Strategy>
  209. struct default_strategy
  210. <
  211. point_tag, segment_tag, Point, PointOfSegment,
  212. cartesian_tag, cartesian_tag, Strategy
  213. >
  214. {
  215. typedef strategy::distance::projected_point
  216. <
  217. void,
  218. typename boost::mpl::if_
  219. <
  220. boost::is_void<Strategy>,
  221. typename default_strategy
  222. <
  223. point_tag, point_tag, Point, PointOfSegment,
  224. cartesian_tag, cartesian_tag
  225. >::type,
  226. Strategy
  227. >::type
  228. > type;
  229. };
  230. template <typename PointOfSegment, typename Point, typename Strategy>
  231. struct default_strategy
  232. <
  233. segment_tag, point_tag, PointOfSegment, Point,
  234. cartesian_tag, cartesian_tag, Strategy
  235. >
  236. {
  237. typedef typename default_strategy
  238. <
  239. point_tag, segment_tag, Point, PointOfSegment,
  240. cartesian_tag, cartesian_tag, Strategy
  241. >::type type;
  242. };
  243. } // namespace services
  244. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  245. }} // namespace strategy::distance
  246. }} // namespace boost::geometry
  247. #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP