polygon.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2014-2019, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
  10. #include <cstddef>
  11. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  12. #include <iostream>
  13. #endif // BOOST_GEOMETRY_TEST_DEBUG
  14. #include <algorithm>
  15. #include <deque>
  16. #include <iterator>
  17. #include <set>
  18. #include <vector>
  19. #include <boost/core/ignore_unused.hpp>
  20. #include <boost/range.hpp>
  21. #include <boost/geometry/core/assert.hpp>
  22. #include <boost/geometry/core/exterior_ring.hpp>
  23. #include <boost/geometry/core/interior_rings.hpp>
  24. #include <boost/geometry/core/ring_type.hpp>
  25. #include <boost/geometry/core/tags.hpp>
  26. #include <boost/geometry/util/condition.hpp>
  27. #include <boost/geometry/util/range.hpp>
  28. #include <boost/geometry/geometries/box.hpp>
  29. #include <boost/geometry/iterators/point_iterator.hpp>
  30. #include <boost/geometry/algorithms/covered_by.hpp>
  31. #include <boost/geometry/algorithms/disjoint.hpp>
  32. #include <boost/geometry/algorithms/expand.hpp>
  33. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  34. #include <boost/geometry/algorithms/validity_failure_type.hpp>
  35. #include <boost/geometry/algorithms/detail/point_on_border.hpp>
  36. #include <boost/geometry/algorithms/within.hpp>
  37. #include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
  38. #include <boost/geometry/algorithms/detail/partition.hpp>
  39. #include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
  40. #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
  41. #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
  42. #include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
  43. #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
  44. #include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
  45. #include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp>
  46. #include <boost/geometry/algorithms/dispatch/is_valid.hpp>
  47. namespace boost { namespace geometry
  48. {
  49. #ifndef DOXYGEN_NO_DETAIL
  50. namespace detail { namespace is_valid
  51. {
  52. template <typename Polygon, bool CheckRingValidityOnly = false>
  53. class is_valid_polygon
  54. {
  55. protected:
  56. template <typename VisitPolicy, typename Strategy>
  57. struct per_ring
  58. {
  59. per_ring(VisitPolicy& policy, Strategy const& strategy)
  60. : m_policy(policy)
  61. , m_strategy(strategy)
  62. {}
  63. template <typename Ring>
  64. inline bool apply(Ring const& ring) const
  65. {
  66. return detail::is_valid::is_valid_ring
  67. <
  68. Ring, false, true
  69. >::apply(ring, m_policy, m_strategy);
  70. }
  71. VisitPolicy& m_policy;
  72. Strategy const& m_strategy;
  73. };
  74. template <typename InteriorRings, typename VisitPolicy, typename Strategy>
  75. static bool has_valid_interior_rings(InteriorRings const& interior_rings,
  76. VisitPolicy& visitor,
  77. Strategy const& strategy)
  78. {
  79. return
  80. detail::check_iterator_range
  81. <
  82. per_ring<VisitPolicy, Strategy>,
  83. true // allow for empty interior ring range
  84. >::apply(boost::begin(interior_rings),
  85. boost::end(interior_rings),
  86. per_ring<VisitPolicy, Strategy>(visitor, strategy));
  87. }
  88. struct has_valid_rings
  89. {
  90. template <typename VisitPolicy, typename Strategy>
  91. static inline bool apply(Polygon const& polygon,
  92. VisitPolicy& visitor,
  93. Strategy const& strategy)
  94. {
  95. typedef debug_validity_phase<Polygon> debug_phase;
  96. typedef typename ring_type<Polygon>::type ring_type;
  97. // check validity of exterior ring
  98. debug_phase::apply(1);
  99. if (! detail::is_valid::is_valid_ring
  100. <
  101. ring_type,
  102. false // do not check self intersections
  103. >::apply(exterior_ring(polygon), visitor, strategy))
  104. {
  105. return false;
  106. }
  107. // check validity of interior rings
  108. debug_phase::apply(2);
  109. return has_valid_interior_rings(geometry::interior_rings(polygon),
  110. visitor,
  111. strategy);
  112. }
  113. };
  114. // Iterator value_type is a Ring or Polygon
  115. template <typename Iterator, typename Box>
  116. struct partition_item
  117. {
  118. explicit partition_item(Iterator it)
  119. : m_it(it)
  120. , m_is_initialized(false)
  121. {}
  122. Iterator get() const
  123. {
  124. return m_it;
  125. }
  126. template <typename EnvelopeStrategy>
  127. Box const& get_envelope(EnvelopeStrategy const& strategy) const
  128. {
  129. if (! m_is_initialized)
  130. {
  131. m_box = geometry::return_envelope<Box>(*m_it, strategy);
  132. m_is_initialized = true;
  133. }
  134. return m_box;
  135. }
  136. private:
  137. Iterator m_it;
  138. mutable Box m_box;
  139. mutable bool m_is_initialized;
  140. };
  141. // structs for partition -- start
  142. template <typename EnvelopeStrategy>
  143. struct expand_box
  144. {
  145. explicit expand_box(EnvelopeStrategy const& strategy)
  146. : m_strategy(strategy)
  147. {}
  148. template <typename Box, typename Iterator>
  149. inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
  150. {
  151. geometry::expand(total,
  152. item.get_envelope(m_strategy),
  153. m_strategy.get_box_expand_strategy());
  154. }
  155. EnvelopeStrategy const& m_strategy;
  156. };
  157. template <typename EnvelopeStrategy, typename DisjointBoxBoxStrategy>
  158. struct overlaps_box
  159. {
  160. explicit overlaps_box(EnvelopeStrategy const& envelope_strategy,
  161. DisjointBoxBoxStrategy const& disjoint_strategy)
  162. : m_envelope_strategy(envelope_strategy)
  163. , m_disjoint_strategy(disjoint_strategy)
  164. {}
  165. template <typename Box, typename Iterator>
  166. inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
  167. {
  168. return ! geometry::disjoint(item.get_envelope(m_envelope_strategy),
  169. box,
  170. m_disjoint_strategy);
  171. }
  172. EnvelopeStrategy const& m_envelope_strategy;
  173. DisjointBoxBoxStrategy const& m_disjoint_strategy;
  174. };
  175. template <typename WithinStrategy>
  176. struct item_visitor_type
  177. {
  178. bool items_overlap;
  179. WithinStrategy const& m_strategy;
  180. explicit item_visitor_type(WithinStrategy const& strategy)
  181. : items_overlap(false)
  182. , m_strategy(strategy)
  183. {}
  184. template <typename Iterator, typename Box>
  185. inline bool apply(partition_item<Iterator, Box> const& item1,
  186. partition_item<Iterator, Box> const& item2)
  187. {
  188. typedef boost::mpl::vector
  189. <
  190. geometry::de9im::static_mask<'T'>,
  191. geometry::de9im::static_mask<'*', 'T'>,
  192. geometry::de9im::static_mask<'*', '*', '*', 'T'>
  193. > relate_mask_t;
  194. if ( ! items_overlap
  195. && geometry::relate(*item1.get(), *item2.get(), relate_mask_t(), m_strategy) )
  196. {
  197. items_overlap = true;
  198. return false; // interrupt
  199. }
  200. return true;
  201. }
  202. };
  203. // structs for partition -- end
  204. template
  205. <
  206. typename RingIterator,
  207. typename ExteriorRing,
  208. typename TurnIterator,
  209. typename VisitPolicy,
  210. typename Strategy
  211. >
  212. static inline bool are_holes_inside(RingIterator rings_first,
  213. RingIterator rings_beyond,
  214. ExteriorRing const& exterior_ring,
  215. TurnIterator turns_first,
  216. TurnIterator turns_beyond,
  217. VisitPolicy& visitor,
  218. Strategy const& strategy)
  219. {
  220. boost::ignore_unused(visitor);
  221. // collect the interior ring indices that have turns with the
  222. // exterior ring
  223. std::set<signed_size_type> ring_indices;
  224. for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
  225. {
  226. if (tit->operations[0].seg_id.ring_index == -1)
  227. {
  228. BOOST_GEOMETRY_ASSERT(tit->operations[1].seg_id.ring_index != -1);
  229. ring_indices.insert(tit->operations[1].seg_id.ring_index);
  230. }
  231. else if (tit->operations[1].seg_id.ring_index == -1)
  232. {
  233. BOOST_GEOMETRY_ASSERT(tit->operations[0].seg_id.ring_index != -1);
  234. ring_indices.insert(tit->operations[0].seg_id.ring_index);
  235. }
  236. }
  237. // prepare strategy
  238. typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type;
  239. typename Strategy::template point_in_geometry_strategy
  240. <
  241. inter_ring_type, ExteriorRing
  242. >::type const in_exterior_strategy
  243. = strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>();
  244. signed_size_type ring_index = 0;
  245. for (RingIterator it = rings_first; it != rings_beyond;
  246. ++it, ++ring_index)
  247. {
  248. // do not examine interior rings that have turns with the
  249. // exterior ring
  250. if (ring_indices.find(ring_index) == ring_indices.end()
  251. && ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy))
  252. {
  253. return visitor.template apply<failure_interior_rings_outside>();
  254. }
  255. }
  256. // collect all rings (exterior and/or interior) that have turns
  257. for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
  258. {
  259. ring_indices.insert(tit->operations[0].seg_id.ring_index);
  260. ring_indices.insert(tit->operations[1].seg_id.ring_index);
  261. }
  262. typedef geometry::model::box<typename point_type<Polygon>::type> box_type;
  263. typedef partition_item<RingIterator, box_type> item_type;
  264. // put iterators for interior rings without turns in a vector
  265. std::vector<item_type> ring_iterators;
  266. ring_index = 0;
  267. for (RingIterator it = rings_first; it != rings_beyond;
  268. ++it, ++ring_index)
  269. {
  270. if (ring_indices.find(ring_index) == ring_indices.end())
  271. {
  272. ring_iterators.push_back(item_type(it));
  273. }
  274. }
  275. // prepare strategies
  276. typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
  277. envelope_strategy_type const envelope_strategy
  278. = strategy.get_envelope_strategy();
  279. typedef typename Strategy::disjoint_box_box_strategy_type disjoint_box_box_strategy_type;
  280. disjoint_box_box_strategy_type const disjoint_strategy
  281. = strategy.get_disjoint_box_box_strategy();
  282. // call partition to check if interior rings are disjoint from
  283. // each other
  284. item_visitor_type<Strategy> item_visitor(strategy);
  285. geometry::partition
  286. <
  287. box_type
  288. >::apply(ring_iterators, item_visitor,
  289. expand_box
  290. <
  291. envelope_strategy_type
  292. >(envelope_strategy),
  293. overlaps_box
  294. <
  295. envelope_strategy_type,
  296. disjoint_box_box_strategy_type
  297. >(envelope_strategy, disjoint_strategy));
  298. if (item_visitor.items_overlap)
  299. {
  300. return visitor.template apply<failure_nested_interior_rings>();
  301. }
  302. else
  303. {
  304. return visitor.template apply<no_failure>();
  305. }
  306. }
  307. template
  308. <
  309. typename InteriorRings,
  310. typename ExteriorRing,
  311. typename TurnIterator,
  312. typename VisitPolicy,
  313. typename Strategy
  314. >
  315. static inline bool are_holes_inside(InteriorRings const& interior_rings,
  316. ExteriorRing const& exterior_ring,
  317. TurnIterator first,
  318. TurnIterator beyond,
  319. VisitPolicy& visitor,
  320. Strategy const& strategy)
  321. {
  322. return are_holes_inside(boost::begin(interior_rings),
  323. boost::end(interior_rings),
  324. exterior_ring,
  325. first,
  326. beyond,
  327. visitor,
  328. strategy);
  329. }
  330. struct has_holes_inside
  331. {
  332. template <typename TurnIterator, typename VisitPolicy, typename Strategy>
  333. static inline bool apply(Polygon const& polygon,
  334. TurnIterator first,
  335. TurnIterator beyond,
  336. VisitPolicy& visitor,
  337. Strategy const& strategy)
  338. {
  339. return are_holes_inside(geometry::interior_rings(polygon),
  340. geometry::exterior_ring(polygon),
  341. first,
  342. beyond,
  343. visitor,
  344. strategy);
  345. }
  346. };
  347. struct has_connected_interior
  348. {
  349. template <typename TurnIterator, typename VisitPolicy, typename Strategy>
  350. static inline bool apply(Polygon const& polygon,
  351. TurnIterator first,
  352. TurnIterator beyond,
  353. VisitPolicy& visitor,
  354. Strategy const& )
  355. {
  356. boost::ignore_unused(visitor);
  357. typedef typename std::iterator_traits
  358. <
  359. TurnIterator
  360. >::value_type turn_type;
  361. typedef complement_graph
  362. <
  363. typename turn_type::point_type,
  364. typename Strategy::cs_tag
  365. > graph;
  366. graph g(geometry::num_interior_rings(polygon) + 1);
  367. for (TurnIterator tit = first; tit != beyond; ++tit)
  368. {
  369. typename graph::vertex_handle v1 = g.add_vertex
  370. ( tit->operations[0].seg_id.ring_index + 1 );
  371. typename graph::vertex_handle v2 = g.add_vertex
  372. ( tit->operations[1].seg_id.ring_index + 1 );
  373. typename graph::vertex_handle vip = g.add_vertex(tit->point);
  374. g.add_edge(v1, vip);
  375. g.add_edge(v2, vip);
  376. }
  377. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  378. debug_print_complement_graph(std::cout, g);
  379. #endif // BOOST_GEOMETRY_TEST_DEBUG
  380. if (g.has_cycles())
  381. {
  382. return visitor.template apply<failure_disconnected_interior>();
  383. }
  384. else
  385. {
  386. return visitor.template apply<no_failure>();
  387. }
  388. }
  389. };
  390. public:
  391. template <typename VisitPolicy, typename Strategy>
  392. static inline bool apply(Polygon const& polygon,
  393. VisitPolicy& visitor,
  394. Strategy const& strategy)
  395. {
  396. if (! has_valid_rings::apply(polygon, visitor, strategy))
  397. {
  398. return false;
  399. }
  400. if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly))
  401. {
  402. return true;
  403. }
  404. // compute turns and check if all are acceptable
  405. typedef debug_validity_phase<Polygon> debug_phase;
  406. debug_phase::apply(3);
  407. typedef has_valid_self_turns<Polygon, typename Strategy::cs_tag> has_valid_turns;
  408. std::deque<typename has_valid_turns::turn_type> turns;
  409. bool has_invalid_turns
  410. = ! has_valid_turns::apply(polygon, turns, visitor, strategy);
  411. debug_print_turns(turns.begin(), turns.end());
  412. if (has_invalid_turns)
  413. {
  414. return false;
  415. }
  416. // check if all interior rings are inside the exterior ring
  417. debug_phase::apply(4);
  418. if (! has_holes_inside::apply(polygon,
  419. turns.begin(), turns.end(),
  420. visitor,
  421. strategy))
  422. {
  423. return false;
  424. }
  425. // check whether the interior of the polygon is a connected set
  426. debug_phase::apply(5);
  427. return has_connected_interior::apply(polygon,
  428. turns.begin(),
  429. turns.end(),
  430. visitor,
  431. strategy);
  432. }
  433. };
  434. }} // namespace detail::is_valid
  435. #endif // DOXYGEN_NO_DETAIL
  436. #ifndef DOXYGEN_NO_DISPATCH
  437. namespace dispatch
  438. {
  439. // A Polygon is always a simple geometric object provided that it is valid.
  440. //
  441. // Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
  442. template <typename Polygon, bool AllowEmptyMultiGeometries>
  443. struct is_valid
  444. <
  445. Polygon, polygon_tag, AllowEmptyMultiGeometries
  446. > : detail::is_valid::is_valid_polygon<Polygon>
  447. {};
  448. } // namespace dispatch
  449. #endif // DOXYGEN_NO_DISPATCH
  450. }} // namespace boost::geometry
  451. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP