get_rescale_policy.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2014-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2014-2015 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2015.
  7. // Modifications copyright (c) 2015, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  9. // Use, modification and distribution is subject to the Boost Software License,
  10. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
  13. #define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
  14. #include <cstddef>
  15. #include <boost/mpl/assert.hpp>
  16. #include <boost/type_traits/is_floating_point.hpp>
  17. #include <boost/type_traits/is_same.hpp>
  18. #include <boost/geometry/core/assert.hpp>
  19. #include <boost/geometry/core/tag_cast.hpp>
  20. #include <boost/geometry/algorithms/envelope.hpp>
  21. #include <boost/geometry/algorithms/expand.hpp>
  22. #include <boost/geometry/algorithms/is_empty.hpp>
  23. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  24. #include <boost/geometry/algorithms/detail/get_max_size.hpp>
  25. #include <boost/geometry/policies/robustness/robust_type.hpp>
  26. #include <boost/geometry/geometries/point.hpp>
  27. #include <boost/geometry/geometries/box.hpp>
  28. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  29. #include <boost/geometry/policies/robustness/rescale_policy.hpp>
  30. #include <boost/geometry/util/promote_floating_point.hpp>
  31. namespace boost { namespace geometry
  32. {
  33. #ifndef DOXYGEN_NO_DETAIL
  34. namespace detail { namespace get_rescale_policy
  35. {
  36. template
  37. <
  38. typename Box,
  39. typename Point,
  40. typename RobustPoint,
  41. typename Factor
  42. >
  43. inline void scale_box_to_integer_range(Box const& box,
  44. Point& min_point,
  45. RobustPoint& min_robust_point,
  46. Factor& factor)
  47. {
  48. // Scale box to integer-range
  49. typedef typename promote_floating_point
  50. <
  51. typename geometry::coordinate_type<Point>::type
  52. >::type num_type;
  53. num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(box));
  54. num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
  55. num_type const half = 0.5;
  56. if (math::equals(diff, num_type())
  57. || diff >= range
  58. || ! boost::math::isfinite(diff))
  59. {
  60. factor = 1;
  61. }
  62. else
  63. {
  64. factor = boost::numeric_cast<num_type>(
  65. boost::numeric_cast<boost::long_long_type>(half + range / diff));
  66. BOOST_GEOMETRY_ASSERT(factor >= 1);
  67. }
  68. // Assign input/output minimal points
  69. detail::assign_point_from_index<0>(box, min_point);
  70. num_type const two = 2;
  71. boost::long_long_type const min_coordinate
  72. = boost::numeric_cast<boost::long_long_type>(-range / two);
  73. assign_values(min_robust_point, min_coordinate, min_coordinate);
  74. }
  75. template <typename Point, typename RobustPoint, typename Geometry, typename Factor>
  76. static inline void init_rescale_policy(Geometry const& geometry,
  77. Point& min_point,
  78. RobustPoint& min_robust_point,
  79. Factor& factor)
  80. {
  81. if (geometry::is_empty(geometry))
  82. {
  83. return;
  84. }
  85. // Get bounding boxes
  86. model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry);
  87. scale_box_to_integer_range(env, min_point, min_robust_point, factor);
  88. }
  89. template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor>
  90. static inline void init_rescale_policy(Geometry1 const& geometry1,
  91. Geometry2 const& geometry2,
  92. Point& min_point,
  93. RobustPoint& min_robust_point,
  94. Factor& factor)
  95. {
  96. // Get bounding boxes (when at least one of the geometries is not empty)
  97. bool const is_empty1 = geometry::is_empty(geometry1);
  98. bool const is_empty2 = geometry::is_empty(geometry2);
  99. if (is_empty1 && is_empty2)
  100. {
  101. return;
  102. }
  103. model::box<Point> env;
  104. if (is_empty1)
  105. {
  106. geometry::envelope(geometry2, env);
  107. }
  108. else if (is_empty2)
  109. {
  110. geometry::envelope(geometry1, env);
  111. }
  112. else
  113. {
  114. // The following approach (envelope + expand) may not give the
  115. // optimal MBR when then two geometries are in the spherical
  116. // equatorial or geographic coordinate systems.
  117. // TODO: implement envelope for two (or possibly more geometries)
  118. geometry::envelope(geometry1, env);
  119. model::box<Point> env2 = geometry::return_envelope
  120. <
  121. model::box<Point>
  122. >(geometry2);
  123. geometry::expand(env, env2);
  124. }
  125. scale_box_to_integer_range(env, min_point, min_robust_point, factor);
  126. }
  127. template
  128. <
  129. typename Point,
  130. bool IsFloatingPoint
  131. >
  132. struct rescale_policy_type
  133. {
  134. typedef no_rescale_policy type;
  135. };
  136. // We rescale only all FP types
  137. template
  138. <
  139. typename Point
  140. >
  141. struct rescale_policy_type<Point, true>
  142. {
  143. typedef typename geometry::coordinate_type<Point>::type coordinate_type;
  144. typedef model::point
  145. <
  146. typename detail::robust_type<coordinate_type>::type,
  147. geometry::dimension<Point>::value,
  148. typename geometry::coordinate_system<Point>::type
  149. > robust_point_type;
  150. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  151. typedef detail::robust_policy<Point, robust_point_type, factor_type> type;
  152. };
  153. template <typename Policy>
  154. struct get_rescale_policy
  155. {
  156. template <typename Geometry>
  157. static inline Policy apply(Geometry const& geometry)
  158. {
  159. typedef typename point_type<Geometry>::type point_type;
  160. typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
  161. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  162. typedef model::point
  163. <
  164. typename detail::robust_type<coordinate_type>::type,
  165. geometry::dimension<point_type>::value,
  166. typename geometry::coordinate_system<point_type>::type
  167. > robust_point_type;
  168. point_type min_point;
  169. robust_point_type min_robust_point;
  170. factor_type factor;
  171. init_rescale_policy(geometry, min_point, min_robust_point, factor);
  172. return Policy(min_point, min_robust_point, factor);
  173. }
  174. template <typename Geometry1, typename Geometry2>
  175. static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
  176. {
  177. typedef typename point_type<Geometry1>::type point_type;
  178. typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type;
  179. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  180. typedef model::point
  181. <
  182. typename detail::robust_type<coordinate_type>::type,
  183. geometry::dimension<point_type>::value,
  184. typename geometry::coordinate_system<point_type>::type
  185. > robust_point_type;
  186. point_type min_point;
  187. robust_point_type min_robust_point;
  188. factor_type factor;
  189. init_rescale_policy(geometry1, geometry2, min_point, min_robust_point, factor);
  190. return Policy(min_point, min_robust_point, factor);
  191. }
  192. };
  193. // Specialization for no-rescaling
  194. template <>
  195. struct get_rescale_policy<no_rescale_policy>
  196. {
  197. template <typename Geometry>
  198. static inline no_rescale_policy apply(Geometry const& )
  199. {
  200. return no_rescale_policy();
  201. }
  202. template <typename Geometry1, typename Geometry2>
  203. static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& )
  204. {
  205. return no_rescale_policy();
  206. }
  207. };
  208. }} // namespace detail::get_rescale_policy
  209. #endif // DOXYGEN_NO_DETAIL
  210. template<typename Point>
  211. struct rescale_policy_type
  212. : public detail::get_rescale_policy::rescale_policy_type
  213. <
  214. Point,
  215. #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
  216. false
  217. #else
  218. boost::is_floating_point
  219. <
  220. typename geometry::coordinate_type<Point>::type
  221. >::type::value
  222. &&
  223. boost::is_same
  224. <
  225. typename geometry::coordinate_system<Point>::type,
  226. geometry::cs::cartesian
  227. >::value
  228. #endif
  229. >
  230. {
  231. static const bool is_point
  232. = boost::is_same
  233. <
  234. typename geometry::tag<Point>::type,
  235. geometry::point_tag
  236. >::type::value;
  237. BOOST_MPL_ASSERT_MSG((is_point),
  238. INVALID_INPUT_GEOMETRY,
  239. (typename geometry::tag<Point>::type));
  240. };
  241. template
  242. <
  243. typename Geometry1,
  244. typename Geometry2,
  245. typename Tag1 = typename tag_cast
  246. <
  247. typename tag<Geometry1>::type,
  248. box_tag,
  249. pointlike_tag,
  250. linear_tag,
  251. areal_tag
  252. >::type,
  253. typename Tag2 = typename tag_cast
  254. <
  255. typename tag<Geometry2>::type,
  256. box_tag,
  257. pointlike_tag,
  258. linear_tag,
  259. areal_tag
  260. >::type
  261. >
  262. struct rescale_overlay_policy_type
  263. // Default: no rescaling
  264. : public detail::get_rescale_policy::rescale_policy_type
  265. <
  266. typename geometry::point_type<Geometry1>::type,
  267. false
  268. >
  269. {};
  270. // Areal/areal: get rescale policy based on coordinate type
  271. template
  272. <
  273. typename Geometry1,
  274. typename Geometry2
  275. >
  276. struct rescale_overlay_policy_type<Geometry1, Geometry2, areal_tag, areal_tag>
  277. : public rescale_policy_type
  278. <
  279. typename geometry::point_type<Geometry1>::type
  280. >
  281. {};
  282. template <typename Policy, typename Geometry>
  283. inline Policy get_rescale_policy(Geometry const& geometry)
  284. {
  285. return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry);
  286. }
  287. template <typename Policy, typename Geometry1, typename Geometry2>
  288. inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2)
  289. {
  290. return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry1, geometry2);
  291. }
  292. }} // namespace boost::geometry
  293. #endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP