get_rescale_policy.hpp 10 KB

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