implementation.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2014-2022.
  7. // Modifications copyright (c) 2014-2022 Oracle and/or its affiliates.
  8. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  9. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  10. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  11. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  12. // Use, modification and distribution is subject to the Boost Software License,
  13. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  14. // http://www.boost.org/LICENSE_1_0.txt)
  15. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
  16. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
  17. #include <cstddef>
  18. #include <type_traits>
  19. #include <vector>
  20. #include <boost/range/size.hpp>
  21. #include <boost/geometry/core/access.hpp>
  22. #include <boost/geometry/core/tags.hpp>
  23. #include <boost/geometry/algorithms/area.hpp>
  24. #include <boost/geometry/algorithms/length.hpp>
  25. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  26. #include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
  27. #include <boost/geometry/algorithms/detail/equals/interface.hpp>
  28. #include <boost/geometry/algorithms/detail/relate/implementation.hpp>
  29. #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
  30. #include <boost/geometry/strategies/relate/cartesian.hpp>
  31. #include <boost/geometry/strategies/relate/geographic.hpp>
  32. #include <boost/geometry/strategies/relate/spherical.hpp>
  33. #include <boost/geometry/util/math.hpp>
  34. #include <boost/geometry/util/select_coordinate_type.hpp>
  35. #include <boost/geometry/util/select_most_precise.hpp>
  36. #include <boost/geometry/views/detail/indexed_point_view.hpp>
  37. namespace boost { namespace geometry
  38. {
  39. #ifndef DOXYGEN_NO_DETAIL
  40. namespace detail { namespace equals
  41. {
  42. template
  43. <
  44. std::size_t Dimension,
  45. std::size_t DimensionCount
  46. >
  47. struct point_point
  48. {
  49. template <typename Point1, typename Point2, typename Strategy>
  50. static inline bool apply(Point1 const& point1, Point2 const& point2,
  51. Strategy const& strategy)
  52. {
  53. typedef decltype(strategy.relate(point1, point2)) strategy_type;
  54. return strategy_type::apply(point1, point2);
  55. }
  56. };
  57. template
  58. <
  59. std::size_t Dimension,
  60. std::size_t DimensionCount
  61. >
  62. struct box_box
  63. {
  64. template <typename Box1, typename Box2, typename Strategy>
  65. static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
  66. {
  67. if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
  68. || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
  69. {
  70. return false;
  71. }
  72. return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy);
  73. }
  74. };
  75. template <std::size_t DimensionCount>
  76. struct box_box<DimensionCount, DimensionCount>
  77. {
  78. template <typename Box1, typename Box2, typename Strategy>
  79. static inline bool apply(Box1 const& , Box2 const& , Strategy const& )
  80. {
  81. return true;
  82. }
  83. };
  84. struct segment_segment
  85. {
  86. template <typename Segment1, typename Segment2, typename Strategy>
  87. static inline bool apply(Segment1 const& segment1, Segment2 const& segment2,
  88. Strategy const& strategy)
  89. {
  90. return equals::equals_point_point(
  91. indexed_point_view<Segment1 const, 0>(segment1),
  92. indexed_point_view<Segment2 const, 0>(segment2),
  93. strategy)
  94. ? equals::equals_point_point(
  95. indexed_point_view<Segment1 const, 1>(segment1),
  96. indexed_point_view<Segment2 const, 1>(segment2),
  97. strategy)
  98. : ( equals::equals_point_point(
  99. indexed_point_view<Segment1 const, 0>(segment1),
  100. indexed_point_view<Segment2 const, 1>(segment2),
  101. strategy)
  102. && equals::equals_point_point(
  103. indexed_point_view<Segment1 const, 1>(segment1),
  104. indexed_point_view<Segment2 const, 0>(segment2),
  105. strategy)
  106. );
  107. }
  108. };
  109. struct area_check
  110. {
  111. template <typename Geometry1, typename Geometry2, typename Strategy>
  112. static inline bool apply(Geometry1 const& geometry1,
  113. Geometry2 const& geometry2,
  114. Strategy const& strategy)
  115. {
  116. return geometry::math::equals(geometry::area(geometry1, strategy),
  117. geometry::area(geometry2, strategy));
  118. }
  119. };
  120. /*
  121. struct length_check
  122. {
  123. template <typename Geometry1, typename Geometry2, typename Strategy>
  124. static inline bool apply(Geometry1 const& geometry1,
  125. Geometry2 const& geometry2,
  126. Strategy const& strategy)
  127. {
  128. return geometry::math::equals(geometry::length(geometry1, strategy),
  129. geometry::length(geometry2, strategy));
  130. }
  131. };
  132. */
  133. // Small helper structure do decide to use collect_vectors, or not
  134. template <typename Strategy, typename CsTag>
  135. struct use_collect_vectors
  136. {
  137. static constexpr bool value = false;
  138. };
  139. template <typename Strategy>
  140. struct use_collect_vectors<Strategy, cartesian_tag>
  141. {
  142. static constexpr bool value = true;
  143. template <typename T, typename Point>
  144. using type = collected_vector_cartesian<T>;
  145. };
  146. template <typename CV>
  147. struct use_collect_vectors<strategy::side::spherical_side_formula<CV>, spherical_tag>
  148. {
  149. static constexpr bool value = true;
  150. template <typename T, typename Point>
  151. using type = collected_vector_spherical<T, Point>;
  152. };
  153. template <typename TrivialCheck>
  154. struct equals_by_collection
  155. {
  156. template <typename Geometry1, typename Geometry2, typename Strategy>
  157. static inline bool apply(Geometry1 const& geometry1,
  158. Geometry2 const& geometry2,
  159. Strategy const& strategy)
  160. {
  161. if (! TrivialCheck::apply(geometry1, geometry2, strategy))
  162. {
  163. return false;
  164. }
  165. using calculation_type = typename geometry::select_most_precise
  166. <
  167. typename select_coordinate_type
  168. <
  169. Geometry1, Geometry2
  170. >::type,
  171. double
  172. >::type;
  173. using collected_vector_type = typename use_collect_vectors
  174. <
  175. decltype(std::declval<Strategy>().side()),
  176. typename Strategy::cs_tag
  177. >::template type
  178. <
  179. calculation_type,
  180. typename geometry::point_type<Geometry1>::type
  181. >;
  182. std::vector<collected_vector_type> c1, c2;
  183. geometry::collect_vectors(c1, geometry1);
  184. geometry::collect_vectors(c2, geometry2);
  185. if (boost::size(c1) != boost::size(c2))
  186. {
  187. return false;
  188. }
  189. std::sort(c1.begin(), c1.end());
  190. std::sort(c2.begin(), c2.end());
  191. // Check if these vectors are equal.
  192. return std::equal(c1.begin(), c1.end(), c2.begin());
  193. }
  194. };
  195. template<typename Geometry1, typename Geometry2>
  196. struct equals_by_relate
  197. : detail::relate::relate_impl
  198. <
  199. detail::de9im::static_mask_equals_type,
  200. Geometry1,
  201. Geometry2
  202. >
  203. {};
  204. // Use either collect_vectors or relate
  205. // NOTE: the result could be conceptually different for invalid
  206. // geometries in different coordinate systems because collect_vectors
  207. // and relate treat invalid geometries differently.
  208. template<typename TrivialCheck>
  209. struct equals_by_collection_or_relate
  210. {
  211. template <typename Strategy>
  212. using use_vectors = use_collect_vectors
  213. <
  214. decltype(std::declval<Strategy>().side()),
  215. typename Strategy::cs_tag
  216. >;
  217. template
  218. <
  219. typename Geometry1, typename Geometry2, typename Strategy,
  220. std::enable_if_t<use_vectors<Strategy>::value, int> = 0
  221. >
  222. static inline bool apply(Geometry1 const& geometry1,
  223. Geometry2 const& geometry2,
  224. Strategy const& strategy)
  225. {
  226. return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
  227. }
  228. template
  229. <
  230. typename Geometry1, typename Geometry2, typename Strategy,
  231. std::enable_if_t<! use_vectors<Strategy>::value, int> = 0
  232. >
  233. static inline bool apply(Geometry1 const& geometry1,
  234. Geometry2 const& geometry2,
  235. Strategy const& strategy)
  236. {
  237. return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
  238. }
  239. };
  240. struct equals_always_false
  241. {
  242. template <typename Geometry1, typename Geometry2, typename Strategy>
  243. static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const& )
  244. {
  245. return false;
  246. }
  247. };
  248. }} // namespace detail::equals
  249. #endif // DOXYGEN_NO_DETAIL
  250. #ifndef DOXYGEN_NO_DISPATCH
  251. namespace dispatch
  252. {
  253. template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
  254. struct equals<P1, P2, point_tag, point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse>
  255. : detail::equals::point_point<0, DimensionCount>
  256. {};
  257. template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
  258. struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse>
  259. : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
  260. {};
  261. template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
  262. struct equals<Point, MultiPoint, point_tag, multi_point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse>
  263. : detail::equals::equals_by_relate<Point, MultiPoint>
  264. {};
  265. template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
  266. struct equals<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, DimensionCount, Reverse>
  267. : detail::equals::box_box<0, DimensionCount>
  268. {};
  269. template <typename Ring1, typename Ring2, bool Reverse>
  270. struct equals<Ring1, Ring2, ring_tag, ring_tag, areal_tag, areal_tag, 2, Reverse>
  271. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  272. {};
  273. template <typename Polygon1, typename Polygon2, bool Reverse>
  274. struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, areal_tag, areal_tag, 2, Reverse>
  275. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  276. {};
  277. template <typename Polygon, typename Ring, bool Reverse>
  278. struct equals<Polygon, Ring, polygon_tag, ring_tag, areal_tag, areal_tag, 2, Reverse>
  279. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  280. {};
  281. template <typename Ring, typename Box, bool Reverse>
  282. struct equals<Ring, Box, ring_tag, box_tag, areal_tag, areal_tag, 2, Reverse>
  283. : detail::equals::equals_by_collection<detail::equals::area_check>
  284. {};
  285. template <typename Polygon, typename Box, bool Reverse>
  286. struct equals<Polygon, Box, polygon_tag, box_tag, areal_tag, areal_tag, 2, Reverse>
  287. : detail::equals::equals_by_collection<detail::equals::area_check>
  288. {};
  289. template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
  290. struct equals<Segment1, Segment2, segment_tag, segment_tag, linear_tag, linear_tag, DimensionCount, Reverse>
  291. : detail::equals::segment_segment
  292. {};
  293. template <typename LineString1, typename LineString2, bool Reverse>
  294. struct equals<LineString1, LineString2, linestring_tag, linestring_tag, linear_tag, linear_tag, 2, Reverse>
  295. : detail::equals::equals_by_relate<LineString1, LineString2>
  296. {};
  297. template <typename LineString, typename MultiLineString, bool Reverse>
  298. struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, linear_tag, linear_tag, 2, Reverse>
  299. : detail::equals::equals_by_relate<LineString, MultiLineString>
  300. {};
  301. template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
  302. struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, linear_tag, linear_tag, 2, Reverse>
  303. : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
  304. {};
  305. template <typename LineString, typename Segment, bool Reverse>
  306. struct equals<LineString, Segment, linestring_tag, segment_tag, linear_tag, linear_tag, 2, Reverse>
  307. : detail::equals::equals_by_relate<LineString, Segment>
  308. {};
  309. template <typename MultiLineString, typename Segment, bool Reverse>
  310. struct equals<MultiLineString, Segment, multi_linestring_tag, segment_tag, linear_tag, linear_tag, 2, Reverse>
  311. : detail::equals::equals_by_relate<MultiLineString, Segment>
  312. {};
  313. template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
  314. struct equals
  315. <
  316. MultiPolygon1, MultiPolygon2,
  317. multi_polygon_tag, multi_polygon_tag,
  318. areal_tag, areal_tag,
  319. 2,
  320. Reverse
  321. >
  322. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  323. {};
  324. template <typename Polygon, typename MultiPolygon, bool Reverse>
  325. struct equals
  326. <
  327. Polygon, MultiPolygon,
  328. polygon_tag, multi_polygon_tag,
  329. areal_tag, areal_tag,
  330. 2,
  331. Reverse
  332. >
  333. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  334. {};
  335. template <typename MultiPolygon, typename Ring, bool Reverse>
  336. struct equals
  337. <
  338. MultiPolygon, Ring,
  339. multi_polygon_tag, ring_tag,
  340. areal_tag, areal_tag,
  341. 2,
  342. Reverse
  343. >
  344. : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
  345. {};
  346. // NOTE: degenerated linear geometries, e.g. segment or linestring containing
  347. // 2 equal points, are considered to be invalid. Though theoretically
  348. // degenerated segments and linestrings could be treated as points and
  349. // multi-linestrings as multi-points.
  350. // This reasoning could also be applied to boxes.
  351. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  352. struct equals<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, linear_tag, DimensionCount, false>
  353. : detail::equals::equals_always_false
  354. {};
  355. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  356. struct equals<Geometry1, Geometry2, Tag1, Tag2, linear_tag, pointlike_tag, DimensionCount, false>
  357. : detail::equals::equals_always_false
  358. {};
  359. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  360. struct equals<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, areal_tag, DimensionCount, false>
  361. : detail::equals::equals_always_false
  362. {};
  363. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  364. struct equals<Geometry1, Geometry2, Tag1, Tag2, areal_tag, pointlike_tag, DimensionCount, false>
  365. : detail::equals::equals_always_false
  366. {};
  367. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  368. struct equals<Geometry1, Geometry2, Tag1, Tag2, linear_tag, areal_tag, DimensionCount, false>
  369. : detail::equals::equals_always_false
  370. {};
  371. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount>
  372. struct equals<Geometry1, Geometry2, Tag1, Tag2, areal_tag, linear_tag, DimensionCount, false>
  373. : detail::equals::equals_always_false
  374. {};
  375. } // namespace dispatch
  376. #endif // DOXYGEN_NO_DISPATCH
  377. }} // namespace boost::geometry
  378. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP