get_rescale_policy.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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-2020.
  7. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. // Use, modification and distribution is subject to the Boost Software License,
  11. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  12. // http://www.boost.org/LICENSE_1_0.txt)
  13. #ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
  14. #define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
  15. #include <cstddef>
  16. #include <type_traits>
  17. #include <boost/geometry/core/assert.hpp>
  18. #include <boost/geometry/core/config.hpp>
  19. #include <boost/geometry/core/coordinate_promotion.hpp>
  20. #include <boost/geometry/core/tag_cast.hpp>
  21. #include <boost/geometry/algorithms/envelope.hpp>
  22. #include <boost/geometry/algorithms/expand.hpp>
  23. #include <boost/geometry/algorithms/is_empty.hpp>
  24. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  25. #include <boost/geometry/algorithms/detail/get_max_size.hpp>
  26. #include <boost/geometry/core/static_assert.hpp>
  27. #include <boost/geometry/geometries/point.hpp>
  28. #include <boost/geometry/geometries/box.hpp>
  29. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  30. #include <boost/geometry/policies/robustness/rescale_policy.hpp>
  31. #include <boost/geometry/policies/robustness/robust_type.hpp>
  32. #include <boost/geometry/util/type_traits.hpp>
  33. // TEMP
  34. #include <boost/geometry/strategies/envelope/cartesian.hpp>
  35. #include <boost/geometry/strategies/envelope/geographic.hpp>
  36. #include <boost/geometry/strategies/envelope/spherical.hpp>
  37. namespace boost { namespace geometry
  38. {
  39. #ifndef DOXYGEN_NO_DETAIL
  40. namespace detail { namespace get_rescale_policy
  41. {
  42. template
  43. <
  44. typename Box,
  45. typename Point,
  46. typename RobustPoint,
  47. typename Factor
  48. >
  49. inline void scale_box_to_integer_range(Box const& box,
  50. Point& min_point,
  51. RobustPoint& min_robust_point,
  52. Factor& factor)
  53. {
  54. // Scale box to integer-range
  55. typedef typename promote_floating_point
  56. <
  57. typename geometry::coordinate_type<Point>::type
  58. >::type num_type;
  59. num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(box));
  60. num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
  61. num_type const half = 0.5;
  62. if (math::equals(diff, num_type())
  63. || diff >= range
  64. || ! boost::math::isfinite(diff))
  65. {
  66. factor = 1;
  67. }
  68. else
  69. {
  70. factor = boost::numeric_cast<num_type>(
  71. boost::numeric_cast<boost::long_long_type>(half + range / diff));
  72. BOOST_GEOMETRY_ASSERT(factor >= 1);
  73. }
  74. // Assign input/output minimal points
  75. detail::assign_point_from_index<0>(box, min_point);
  76. num_type const two = 2;
  77. boost::long_long_type const min_coordinate
  78. = boost::numeric_cast<boost::long_long_type>(-range / two);
  79. assign_values(min_robust_point, min_coordinate, min_coordinate);
  80. }
  81. template
  82. <
  83. typename Point, typename RobustPoint, typename Geometry,
  84. typename Factor, typename Strategy
  85. >
  86. static inline void init_rescale_policy(Geometry const& geometry,
  87. Point& min_point,
  88. RobustPoint& min_robust_point,
  89. Factor& factor,
  90. Strategy const& strategy)
  91. {
  92. if (geometry::is_empty(geometry))
  93. {
  94. return;
  95. }
  96. // Get bounding box
  97. model::box<Point> env = geometry::return_envelope
  98. <
  99. model::box<Point>
  100. >(geometry, strategy);
  101. scale_box_to_integer_range(env, min_point, min_robust_point, factor);
  102. }
  103. // NOTE: Actually it should take 2 separate strategies, one for each geometry
  104. // in case one of them was e.g. a Box
  105. template
  106. <
  107. typename Point, typename RobustPoint, typename Geometry1, typename Geometry2,
  108. typename Factor, typename Strategy1, typename Strategy2
  109. >
  110. static inline void init_rescale_policy(Geometry1 const& geometry1,
  111. Geometry2 const& geometry2,
  112. Point& min_point,
  113. RobustPoint& min_robust_point,
  114. Factor& factor,
  115. Strategy1 const& strategy1,
  116. Strategy2 const& strategy2)
  117. {
  118. // Get bounding boxes (when at least one of the geometries is not empty)
  119. bool const is_empty1 = geometry::is_empty(geometry1);
  120. bool const is_empty2 = geometry::is_empty(geometry2);
  121. if (is_empty1 && is_empty2)
  122. {
  123. return;
  124. }
  125. model::box<Point> env;
  126. if (is_empty1)
  127. {
  128. geometry::envelope(geometry2, env, strategy2);
  129. }
  130. else if (is_empty2)
  131. {
  132. geometry::envelope(geometry1, env, strategy1);
  133. }
  134. else
  135. {
  136. // The following approach (envelope + expand) may not give the
  137. // optimal MBR when then two geometries are in the spherical
  138. // equatorial or geographic coordinate systems.
  139. // TODO: implement envelope for two (or possibly more geometries)
  140. geometry::envelope(geometry1, env, strategy1);
  141. model::box<Point> env2 = geometry::return_envelope
  142. <
  143. model::box<Point>
  144. >(geometry2, strategy2);
  145. geometry::expand(env, env2, strategy1);
  146. }
  147. scale_box_to_integer_range(env, min_point, min_robust_point, factor);
  148. }
  149. template
  150. <
  151. typename Point,
  152. bool IsFloatingPoint
  153. >
  154. struct rescale_policy_type
  155. {
  156. typedef no_rescale_policy type;
  157. };
  158. // We rescale only all FP types
  159. template
  160. <
  161. typename Point
  162. >
  163. struct rescale_policy_type<Point, true>
  164. {
  165. typedef typename geometry::coordinate_type<Point>::type coordinate_type;
  166. typedef model::point
  167. <
  168. typename detail::robust_type<coordinate_type>::type,
  169. geometry::dimension<Point>::value,
  170. typename geometry::coordinate_system<Point>::type
  171. > robust_point_type;
  172. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  173. typedef detail::robust_policy<Point, robust_point_type, factor_type> type;
  174. };
  175. template <typename Policy>
  176. struct get_rescale_policy
  177. {
  178. template <typename Geometry, typename Strategy>
  179. static inline Policy apply(Geometry const& geometry,
  180. Strategy const& strategy)
  181. {
  182. typedef typename point_type<Geometry>::type point_type;
  183. typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
  184. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  185. typedef model::point
  186. <
  187. typename detail::robust_type<coordinate_type>::type,
  188. geometry::dimension<point_type>::value,
  189. typename geometry::coordinate_system<point_type>::type
  190. > robust_point_type;
  191. point_type min_point;
  192. robust_point_type min_robust_point;
  193. factor_type factor;
  194. init_rescale_policy(geometry, min_point, min_robust_point,
  195. factor, strategy);
  196. return Policy(min_point, min_robust_point, factor);
  197. }
  198. template <typename Geometry1, typename Geometry2, typename Strategy1, typename Strategy2>
  199. static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  200. Strategy1 const& strategy1,
  201. Strategy2 const& strategy2)
  202. {
  203. typedef typename point_type<Geometry1>::type point_type;
  204. typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type;
  205. typedef typename promote_floating_point<coordinate_type>::type factor_type;
  206. typedef model::point
  207. <
  208. typename detail::robust_type<coordinate_type>::type,
  209. geometry::dimension<point_type>::value,
  210. typename geometry::coordinate_system<point_type>::type
  211. > robust_point_type;
  212. point_type min_point;
  213. robust_point_type min_robust_point;
  214. factor_type factor;
  215. init_rescale_policy(geometry1, geometry2, min_point, min_robust_point,
  216. factor, strategy1, strategy2);
  217. return Policy(min_point, min_robust_point, factor);
  218. }
  219. };
  220. // Specialization for no-rescaling
  221. template <>
  222. struct get_rescale_policy<no_rescale_policy>
  223. {
  224. template <typename Geometry, typename EnvelopeStrategy>
  225. static inline no_rescale_policy apply(Geometry const& , EnvelopeStrategy const&)
  226. {
  227. return no_rescale_policy();
  228. }
  229. template <typename Geometry1, typename Geometry2, typename EnvelopeStrategy1, typename EnvelopeStrategy2>
  230. static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& ,
  231. EnvelopeStrategy1 const& , EnvelopeStrategy2 const& )
  232. {
  233. return no_rescale_policy();
  234. }
  235. };
  236. }} // namespace detail::get_rescale_policy
  237. #endif // DOXYGEN_NO_DETAIL
  238. template
  239. <
  240. typename Point,
  241. typename CSTag = typename geometry::cs_tag<Point>::type
  242. >
  243. struct rescale_policy_type
  244. : public detail::get_rescale_policy::rescale_policy_type
  245. <
  246. Point,
  247. #if defined(BOOST_GEOMETRY_USE_RESCALING)
  248. std::is_floating_point
  249. <
  250. typename geometry::coordinate_type<Point>::type
  251. >::type::value
  252. &&
  253. std::is_same
  254. <
  255. CSTag,
  256. geometry::cartesian_tag
  257. >::value
  258. #else
  259. false
  260. #endif
  261. >
  262. {
  263. BOOST_GEOMETRY_STATIC_ASSERT(
  264. (util::is_point<Point>::value),
  265. "Point type expected.",
  266. Point);
  267. };
  268. template
  269. <
  270. typename Geometry1,
  271. typename Geometry2,
  272. typename CSTag = typename geometry::cs_tag<Geometry1>::type,
  273. typename Tag1 = typename tag_cast
  274. <
  275. typename tag<Geometry1>::type,
  276. box_tag,
  277. pointlike_tag,
  278. linear_tag,
  279. areal_tag
  280. >::type,
  281. typename Tag2 = typename tag_cast
  282. <
  283. typename tag<Geometry2>::type,
  284. box_tag,
  285. pointlike_tag,
  286. linear_tag,
  287. areal_tag
  288. >::type
  289. >
  290. struct rescale_overlay_policy_type
  291. // Default: no rescaling
  292. : public detail::get_rescale_policy::rescale_policy_type
  293. <
  294. typename geometry::point_type<Geometry1>::type,
  295. false
  296. >
  297. {};
  298. // Areal/areal: get rescale policy based on coordinate type
  299. template
  300. <
  301. typename Geometry1,
  302. typename Geometry2,
  303. typename CSTag
  304. >
  305. struct rescale_overlay_policy_type<Geometry1, Geometry2, CSTag, areal_tag, areal_tag>
  306. : public rescale_policy_type
  307. <
  308. typename geometry::point_type<Geometry1>::type,
  309. CSTag
  310. >
  311. {};
  312. template <typename Policy, typename Geometry>
  313. inline Policy get_rescale_policy(Geometry const& geometry)
  314. {
  315. typename geometry::strategies::envelope::services::default_strategy
  316. <
  317. Geometry,
  318. model::box<typename point_type<Geometry>::type>
  319. >::type strategy;
  320. return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry, strategy);
  321. }
  322. template
  323. <
  324. typename Policy, typename Geometry, typename Strategy,
  325. std::enable_if_t<std::is_void<typename geometry::tag<Strategy>::type>::value, int> = 0
  326. >
  327. inline Policy get_rescale_policy(Geometry const& geometry, Strategy const& strategy)
  328. {
  329. return detail::get_rescale_policy::get_rescale_policy
  330. <
  331. Policy
  332. >::apply(geometry, strategy);
  333. }
  334. template
  335. <
  336. typename Policy, typename Geometry1, typename Geometry2,
  337. std::enable_if_t<! std::is_void<typename geometry::tag<Geometry2>::type>::value, int> = 0
  338. >
  339. inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2)
  340. {
  341. typename geometry::strategies::envelope::services::default_strategy
  342. <
  343. Geometry1,
  344. model::box<typename point_type<Geometry1>::type>
  345. >::type strategy1;
  346. typename geometry::strategies::envelope::services::default_strategy
  347. <
  348. Geometry2,
  349. model::box<typename point_type<Geometry2>::type>
  350. >::type strategy2;
  351. return detail::get_rescale_policy::get_rescale_policy
  352. <
  353. Policy
  354. >::apply(geometry1, geometry2, strategy1, strategy2);
  355. }
  356. template <typename Policy, typename Geometry1, typename Geometry2, typename Strategy>
  357. inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2,
  358. Strategy const& strategy)
  359. {
  360. return detail::get_rescale_policy::get_rescale_policy
  361. <
  362. Policy
  363. >::apply(geometry1, geometry2, strategy, strategy);
  364. }
  365. }} // namespace boost::geometry
  366. #endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP