sectionalize.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  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 2013, 2014, 2015, 2017, 2018, 2019.
  7. // Modifications copyright (c) 2013-2019 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_SECTIONS_SECTIONALIZE_HPP
  16. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
  17. #include <cstddef>
  18. #include <vector>
  19. #include <boost/concept/requires.hpp>
  20. #include <boost/core/ignore_unused.hpp>
  21. #include <boost/mpl/assert.hpp>
  22. #include <boost/mpl/vector_c.hpp>
  23. #include <boost/range.hpp>
  24. #include <boost/static_assert.hpp>
  25. #include <boost/type_traits/is_same.hpp>
  26. #include <boost/type_traits/is_fundamental.hpp>
  27. #include <boost/geometry/core/config.hpp>
  28. #include <boost/geometry/algorithms/assign.hpp>
  29. #include <boost/geometry/algorithms/envelope.hpp>
  30. #include <boost/geometry/algorithms/expand.hpp>
  31. #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
  32. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  33. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  34. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  35. #include <boost/geometry/core/access.hpp>
  36. #include <boost/geometry/core/closure.hpp>
  37. #include <boost/geometry/core/exterior_ring.hpp>
  38. #include <boost/geometry/core/point_order.hpp>
  39. #include <boost/geometry/core/tags.hpp>
  40. #include <boost/geometry/geometries/concepts/check.hpp>
  41. #include <boost/geometry/util/math.hpp>
  42. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  43. #include <boost/geometry/policies/robustness/robust_point_type.hpp>
  44. #include <boost/geometry/views/closeable_view.hpp>
  45. #include <boost/geometry/views/reversible_view.hpp>
  46. #include <boost/geometry/geometries/segment.hpp>
  47. #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
  48. #include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
  49. #include <boost/geometry/strategies/envelope.hpp>
  50. #include <boost/geometry/strategies/expand.hpp>
  51. namespace boost { namespace geometry
  52. {
  53. /*!
  54. \brief Structure containing section information
  55. \details Section information consists of a bounding box, direction
  56. information (if it is increasing or decreasing, per dimension),
  57. index information (begin-end, ring, multi) and the number of
  58. segments in this section
  59. \tparam Box box-type
  60. \tparam DimensionCount number of dimensions for this section
  61. \ingroup sectionalize
  62. */
  63. template
  64. <
  65. typename Box,
  66. std::size_t DimensionCount
  67. >
  68. struct section
  69. {
  70. typedef Box box_type;
  71. static std::size_t const dimension_count = DimensionCount;
  72. int directions[DimensionCount];
  73. ring_identifier ring_id;
  74. Box bounding_box;
  75. // NOTE: size_type could be passed as template parameter
  76. // NOTE: these probably also could be of type std::size_t
  77. signed_size_type begin_index;
  78. signed_size_type end_index;
  79. std::size_t count;
  80. std::size_t range_count;
  81. bool duplicate;
  82. signed_size_type non_duplicate_index;
  83. bool is_non_duplicate_first;
  84. bool is_non_duplicate_last;
  85. inline section()
  86. : begin_index(-1)
  87. , end_index(-1)
  88. , count(0)
  89. , range_count(0)
  90. , duplicate(false)
  91. , non_duplicate_index(-1)
  92. , is_non_duplicate_first(false)
  93. , is_non_duplicate_last(false)
  94. {
  95. assign_inverse(bounding_box);
  96. for (std::size_t i = 0; i < DimensionCount; i++)
  97. {
  98. directions[i] = 0;
  99. }
  100. }
  101. };
  102. /*!
  103. \brief Structure containing a collection of sections
  104. \note Derived from a vector, proves to be faster than of deque
  105. \note vector might be templated in the future
  106. \ingroup sectionalize
  107. */
  108. template <typename Box, std::size_t DimensionCount>
  109. struct sections : std::vector<section<Box, DimensionCount> >
  110. {
  111. typedef Box box_type;
  112. static std::size_t const value = DimensionCount;
  113. };
  114. #ifndef DOXYGEN_NO_DETAIL
  115. namespace detail { namespace sectionalize
  116. {
  117. // NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
  118. // and geographic coordinate system because in these coordinate systems
  119. // e.g. a segment on northern hemisphere may go towards greater latitude
  120. // and then towards lesser latitude.
  121. template
  122. <
  123. typename Point,
  124. typename DimensionVector,
  125. std::size_t Index,
  126. std::size_t Count,
  127. typename CastedCSTag = typename tag_cast
  128. <
  129. typename cs_tag<Point>::type,
  130. spherical_tag
  131. >::type
  132. >
  133. struct get_direction_loop
  134. {
  135. typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension;
  136. template <typename Segment>
  137. static inline void apply(Segment const& seg,
  138. int directions[Count])
  139. {
  140. typedef typename coordinate_type<Segment>::type coordinate_type;
  141. coordinate_type const c0 = geometry::get<0, dimension::value>(seg);
  142. coordinate_type const c1 = geometry::get<1, dimension::value>(seg);
  143. directions[Index] = c1 > c0 ? 1 : c1 < c0 ? -1 : 0;
  144. get_direction_loop
  145. <
  146. Point,
  147. DimensionVector,
  148. Index + 1,
  149. Count,
  150. CastedCSTag
  151. >::apply(seg, directions);
  152. }
  153. };
  154. template
  155. <
  156. typename Point,
  157. typename DimensionVector,
  158. std::size_t Count
  159. >
  160. struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
  161. {
  162. typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
  163. template <typename Segment>
  164. static inline void apply(Segment const& seg,
  165. int directions[Count])
  166. {
  167. typedef typename coordinate_type<Segment>::type coordinate_type;
  168. typedef typename coordinate_system<Point>::type::units units_t;
  169. coordinate_type const diff = math::longitude_distance_signed
  170. <
  171. units_t, coordinate_type
  172. >(geometry::get<0, 0>(seg),
  173. geometry::get<1, 0>(seg));
  174. coordinate_type zero = coordinate_type();
  175. directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
  176. get_direction_loop
  177. <
  178. Point,
  179. DimensionVector,
  180. 1,
  181. Count,
  182. spherical_tag
  183. >::apply(seg, directions);
  184. }
  185. };
  186. template
  187. <
  188. typename Point,
  189. typename DimensionVector,
  190. std::size_t Count,
  191. typename CastedCSTag
  192. >
  193. struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
  194. {
  195. template <typename Segment>
  196. static inline void apply(Segment const&, int [Count])
  197. {}
  198. };
  199. //! Copy one static array to another
  200. template <typename T, std::size_t Index, std::size_t Count>
  201. struct copy_loop
  202. {
  203. static inline void apply(T const source[Count], T target[Count])
  204. {
  205. target[Index] = source[Index];
  206. copy_loop<T, Index + 1, Count>::apply(source, target);
  207. }
  208. };
  209. template <typename T, std::size_t Count>
  210. struct copy_loop<T, Count, Count>
  211. {
  212. static inline void apply(T const [Count], T [Count])
  213. {}
  214. };
  215. //! Compare two static arrays
  216. template <typename T, std::size_t Index, std::size_t Count>
  217. struct compare_loop
  218. {
  219. static inline bool apply(T const array1[Count], T const array2[Count])
  220. {
  221. return array1[Index] != array2[Index]
  222. ? false
  223. : compare_loop
  224. <
  225. T, Index + 1, Count
  226. >::apply(array1, array2);
  227. }
  228. };
  229. template <typename T, std::size_t Count>
  230. struct compare_loop<T, Count, Count>
  231. {
  232. static inline bool apply(T const [Count], T const [Count])
  233. {
  234. return true;
  235. }
  236. };
  237. template <std::size_t Dimension, std::size_t DimensionCount>
  238. struct check_duplicate_loop
  239. {
  240. template <typename Segment>
  241. static inline bool apply(Segment const& seg)
  242. {
  243. if (! geometry::math::equals
  244. (
  245. geometry::get<0, Dimension>(seg),
  246. geometry::get<1, Dimension>(seg)
  247. )
  248. )
  249. {
  250. return false;
  251. }
  252. return check_duplicate_loop
  253. <
  254. Dimension + 1, DimensionCount
  255. >::apply(seg);
  256. }
  257. };
  258. template <std::size_t DimensionCount>
  259. struct check_duplicate_loop<DimensionCount, DimensionCount>
  260. {
  261. template <typename Segment>
  262. static inline bool apply(Segment const&)
  263. {
  264. return true;
  265. }
  266. };
  267. //! Assign a value to a static array
  268. template <typename T, std::size_t Index, std::size_t Count>
  269. struct assign_loop
  270. {
  271. static inline void apply(T dims[Count], T const value)
  272. {
  273. dims[Index] = value;
  274. assign_loop<T, Index + 1, Count>::apply(dims, value);
  275. }
  276. };
  277. template <typename T, std::size_t Count>
  278. struct assign_loop<T, Count, Count>
  279. {
  280. static inline void apply(T [Count], T const)
  281. {
  282. }
  283. };
  284. template <typename CSTag>
  285. struct box_first_in_section
  286. {
  287. template <typename Box, typename Point, typename EnvelopeStrategy>
  288. static inline void apply(Box & box, Point const& prev, Point const& curr,
  289. EnvelopeStrategy const& strategy)
  290. {
  291. geometry::model::referring_segment<Point const> seg(prev, curr);
  292. geometry::envelope(seg, box, strategy);
  293. }
  294. };
  295. template <>
  296. struct box_first_in_section<cartesian_tag>
  297. {
  298. template <typename Box, typename Point, typename ExpandStrategy>
  299. static inline void apply(Box & box, Point const& prev, Point const& curr,
  300. ExpandStrategy const& )
  301. {
  302. geometry::envelope(prev, box);
  303. geometry::expand(box, curr);
  304. }
  305. };
  306. template <typename CSTag>
  307. struct box_next_in_section
  308. {
  309. template <typename Box, typename Point, typename Strategy>
  310. static inline void apply(Box & box, Point const& prev, Point const& curr,
  311. Strategy const& strategy)
  312. {
  313. geometry::model::referring_segment<Point const> seg(prev, curr);
  314. geometry::expand(box, seg, strategy);
  315. }
  316. };
  317. template <>
  318. struct box_next_in_section<cartesian_tag>
  319. {
  320. template <typename Box, typename Point, typename Strategy>
  321. static inline void apply(Box & box, Point const& , Point const& curr,
  322. Strategy const& )
  323. {
  324. geometry::expand(box, curr);
  325. }
  326. };
  327. /// @brief Helper class to create sections of a part of a range, on the fly
  328. template
  329. <
  330. typename Point,
  331. typename DimensionVector
  332. >
  333. struct sectionalize_part
  334. {
  335. static const std::size_t dimension_count
  336. = boost::mpl::size<DimensionVector>::value;
  337. template
  338. <
  339. typename Iterator,
  340. typename RobustPolicy,
  341. typename Sections
  342. >
  343. static inline void apply(Sections& sections,
  344. Iterator begin, Iterator end,
  345. RobustPolicy const& robust_policy,
  346. ring_identifier ring_id,
  347. std::size_t max_count)
  348. {
  349. typedef typename strategy::envelope::services::default_strategy
  350. <
  351. segment_tag,
  352. typename cs_tag<typename Sections::box_type>::type
  353. >::type envelope_strategy_type;
  354. typedef typename strategy::expand::services::default_strategy
  355. <
  356. segment_tag,
  357. typename cs_tag<typename Sections::box_type>::type
  358. >::type expand_strategy_type;
  359. apply(sections, begin, end,
  360. robust_policy,
  361. envelope_strategy_type(),
  362. expand_strategy_type(),
  363. ring_id, max_count);
  364. }
  365. template
  366. <
  367. typename Iterator,
  368. typename RobustPolicy,
  369. typename Sections,
  370. typename EnvelopeStrategy,
  371. typename ExpandStrategy
  372. >
  373. static inline void apply(Sections& sections,
  374. Iterator begin, Iterator end,
  375. RobustPolicy const& robust_policy,
  376. EnvelopeStrategy const& envelope_strategy,
  377. ExpandStrategy const& expand_strategy,
  378. ring_identifier ring_id,
  379. std::size_t max_count)
  380. {
  381. boost::ignore_unused(robust_policy);
  382. typedef typename boost::range_value<Sections>::type section_type;
  383. BOOST_STATIC_ASSERT
  384. (
  385. (static_cast<std::size_t>(section_type::dimension_count)
  386. == static_cast<std::size_t>(boost::mpl::size<DimensionVector>::value))
  387. );
  388. typedef typename geometry::robust_point_type
  389. <
  390. Point,
  391. RobustPolicy
  392. >::type robust_point_type;
  393. std::size_t const count = std::distance(begin, end);
  394. if (count == 0)
  395. {
  396. return;
  397. }
  398. signed_size_type index = 0;
  399. signed_size_type ndi = 0; // non duplicate index
  400. section_type section;
  401. bool mark_first_non_duplicated = true;
  402. std::size_t last_non_duplicate_index = sections.size();
  403. Iterator it = begin;
  404. robust_point_type previous_robust_point;
  405. geometry::recalculate(previous_robust_point, *it, robust_policy);
  406. for(Iterator previous = it++;
  407. it != end;
  408. ++previous, ++it, index++)
  409. {
  410. robust_point_type current_robust_point;
  411. geometry::recalculate(current_robust_point, *it, robust_policy);
  412. model::referring_segment<robust_point_type> robust_segment(
  413. previous_robust_point, current_robust_point);
  414. int direction_classes[dimension_count] = {0};
  415. get_direction_loop
  416. <
  417. Point, DimensionVector, 0, dimension_count
  418. >::apply(robust_segment, direction_classes);
  419. // if "dir" == 0 for all point-dimensions, it is duplicate.
  420. // Those sections might be omitted, if wished, lateron
  421. bool duplicate = false;
  422. if (direction_classes[0] == 0)
  423. {
  424. // Recheck because ALL dimensions should be checked,
  425. // not only first one.
  426. // (dimension_count might be < dimension<P>::value)
  427. if (check_duplicate_loop
  428. <
  429. 0, geometry::dimension<Point>::type::value
  430. >::apply(robust_segment)
  431. )
  432. {
  433. duplicate = true;
  434. // Change direction-info to force new section
  435. // Note that wo consecutive duplicate segments will generate
  436. // only one duplicate-section.
  437. // Actual value is not important as long as it is not -1,0,1
  438. assign_loop
  439. <
  440. int, 0, dimension_count
  441. >::apply(direction_classes, -99);
  442. }
  443. }
  444. if (section.count > 0
  445. && (! compare_loop
  446. <
  447. int, 0, dimension_count
  448. >::apply(direction_classes, section.directions)
  449. || section.count > max_count)
  450. )
  451. {
  452. if (! section.duplicate)
  453. {
  454. last_non_duplicate_index = sections.size();
  455. }
  456. sections.push_back(section);
  457. section = section_type();
  458. }
  459. if (section.count == 0)
  460. {
  461. section.begin_index = index;
  462. section.ring_id = ring_id;
  463. section.duplicate = duplicate;
  464. section.non_duplicate_index = ndi;
  465. section.range_count = count;
  466. if (mark_first_non_duplicated && ! duplicate)
  467. {
  468. section.is_non_duplicate_first = true;
  469. mark_first_non_duplicated = false;
  470. }
  471. copy_loop
  472. <
  473. int, 0, dimension_count
  474. >::apply(direction_classes, section.directions);
  475. // In cartesian this is envelope of previous point expanded with current point
  476. // in non-cartesian this is envelope of a segment
  477. box_first_in_section<typename cs_tag<robust_point_type>::type>
  478. ::apply(section.bounding_box, previous_robust_point, current_robust_point, envelope_strategy);
  479. }
  480. else
  481. {
  482. // In cartesian this is expand with current point
  483. // in non-cartesian this is expand with a segment
  484. box_next_in_section<typename cs_tag<robust_point_type>::type>
  485. ::apply(section.bounding_box, previous_robust_point, current_robust_point, expand_strategy);
  486. }
  487. section.end_index = index + 1;
  488. section.count++;
  489. if (! duplicate)
  490. {
  491. ndi++;
  492. }
  493. previous_robust_point = current_robust_point;
  494. }
  495. // Add last section if applicable
  496. if (section.count > 0)
  497. {
  498. if (! section.duplicate)
  499. {
  500. last_non_duplicate_index = sections.size();
  501. }
  502. sections.push_back(section);
  503. }
  504. if (last_non_duplicate_index < sections.size()
  505. && ! sections[last_non_duplicate_index].duplicate)
  506. {
  507. sections[last_non_duplicate_index].is_non_duplicate_last = true;
  508. }
  509. }
  510. };
  511. template
  512. <
  513. closure_selector Closure,
  514. bool Reverse,
  515. typename Point,
  516. typename DimensionVector
  517. >
  518. struct sectionalize_range
  519. {
  520. template
  521. <
  522. typename Range,
  523. typename RobustPolicy,
  524. typename Sections,
  525. typename EnvelopeStrategy,
  526. typename ExpandStrategy
  527. >
  528. static inline void apply(Range const& range,
  529. RobustPolicy const& robust_policy,
  530. Sections& sections,
  531. EnvelopeStrategy const& envelope_strategy,
  532. ExpandStrategy const& expand_strategy,
  533. ring_identifier ring_id,
  534. std::size_t max_count)
  535. {
  536. typedef typename closeable_view<Range const, Closure>::type cview_type;
  537. typedef typename reversible_view
  538. <
  539. cview_type const,
  540. Reverse ? iterate_reverse : iterate_forward
  541. >::type view_type;
  542. cview_type cview(range);
  543. view_type view(cview);
  544. std::size_t const n = boost::size(view);
  545. if (n == 0)
  546. {
  547. // Zero points, no section
  548. return;
  549. }
  550. if (n == 1)
  551. {
  552. // Line with one point ==> no sections
  553. return;
  554. }
  555. sectionalize_part<Point, DimensionVector>::apply(sections,
  556. boost::begin(view), boost::end(view),
  557. robust_policy, envelope_strategy, expand_strategy,
  558. ring_id, max_count);
  559. }
  560. };
  561. template
  562. <
  563. bool Reverse,
  564. typename DimensionVector
  565. >
  566. struct sectionalize_polygon
  567. {
  568. template
  569. <
  570. typename Polygon,
  571. typename RobustPolicy,
  572. typename Sections,
  573. typename EnvelopeStrategy,
  574. typename ExpandStrategy
  575. >
  576. static inline void apply(Polygon const& poly,
  577. RobustPolicy const& robust_policy,
  578. Sections& sections,
  579. EnvelopeStrategy const& envelope_strategy,
  580. ExpandStrategy const& expand_strategy,
  581. ring_identifier ring_id,
  582. std::size_t max_count)
  583. {
  584. typedef typename point_type<Polygon>::type point_type;
  585. typedef sectionalize_range
  586. <
  587. closure<Polygon>::value, Reverse,
  588. point_type, DimensionVector
  589. > per_range;
  590. ring_id.ring_index = -1;
  591. per_range::apply(exterior_ring(poly), robust_policy, sections,
  592. envelope_strategy, expand_strategy, ring_id, max_count);
  593. ring_id.ring_index++;
  594. typename interior_return_type<Polygon const>::type
  595. rings = interior_rings(poly);
  596. for (typename detail::interior_iterator<Polygon const>::type
  597. it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
  598. {
  599. per_range::apply(*it, robust_policy, sections,
  600. envelope_strategy, expand_strategy, ring_id, max_count);
  601. }
  602. }
  603. };
  604. template <typename DimensionVector>
  605. struct sectionalize_box
  606. {
  607. template
  608. <
  609. typename Box,
  610. typename RobustPolicy,
  611. typename Sections,
  612. typename EnvelopeStrategy,
  613. typename ExpandStrategy
  614. >
  615. static inline void apply(Box const& box,
  616. RobustPolicy const& robust_policy,
  617. Sections& sections,
  618. EnvelopeStrategy const& envelope_strategy,
  619. ExpandStrategy const& expand_strategy,
  620. ring_identifier const& ring_id, std::size_t max_count)
  621. {
  622. typedef typename point_type<Box>::type point_type;
  623. assert_dimension<Box, 2>();
  624. // Add all four sides of the 2D-box as separate section.
  625. // Easiest is to convert it to a polygon.
  626. // However, we don't have the polygon type
  627. // (or polygon would be a helper-type).
  628. // Therefore we mimic a linestring/std::vector of 5 points
  629. // TODO: might be replaced by assign_box_corners_oriented
  630. // or just "convert"
  631. point_type ll, lr, ul, ur;
  632. geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
  633. std::vector<point_type> points;
  634. points.push_back(ll);
  635. points.push_back(ul);
  636. points.push_back(ur);
  637. points.push_back(lr);
  638. points.push_back(ll);
  639. // NOTE: Use cartesian envelope strategy in all coordinate systems
  640. // because edges of a box are not geodesic segments
  641. sectionalize_range
  642. <
  643. closed, false,
  644. point_type,
  645. DimensionVector
  646. >::apply(points, robust_policy, sections,
  647. envelope_strategy, expand_strategy,
  648. ring_id, max_count);
  649. }
  650. };
  651. template <typename DimensionVector, typename Policy>
  652. struct sectionalize_multi
  653. {
  654. template
  655. <
  656. typename MultiGeometry,
  657. typename RobustPolicy,
  658. typename Sections,
  659. typename EnvelopeStrategy,
  660. typename ExpandStrategy
  661. >
  662. static inline void apply(MultiGeometry const& multi,
  663. RobustPolicy const& robust_policy,
  664. Sections& sections,
  665. EnvelopeStrategy const& envelope_strategy,
  666. ExpandStrategy const& expand_strategy,
  667. ring_identifier ring_id,
  668. std::size_t max_count)
  669. {
  670. ring_id.multi_index = 0;
  671. for (typename boost::range_iterator<MultiGeometry const>::type
  672. it = boost::begin(multi);
  673. it != boost::end(multi);
  674. ++it, ++ring_id.multi_index)
  675. {
  676. Policy::apply(*it, robust_policy, sections,
  677. envelope_strategy, expand_strategy,
  678. ring_id, max_count);
  679. }
  680. }
  681. };
  682. // TODO: If it depends on CS it should probably be made into strategy.
  683. // For now implemented here because of ongoing work on robustness
  684. // the fact that it interferes with detail::buffer::buffer_box
  685. // and that we probably need a general strategy for defining epsilon in
  686. // various coordinate systems, e.g. for point comparison, enlargement of
  687. // bounding boxes, etc.
  688. template <typename CSTag>
  689. struct expand_by_epsilon
  690. : not_implemented<CSTag>
  691. {};
  692. template <>
  693. struct expand_by_epsilon<cartesian_tag>
  694. {
  695. template <typename Box>
  696. static inline void apply(Box & box)
  697. {
  698. detail::expand_by_epsilon(box);
  699. }
  700. };
  701. template <>
  702. struct expand_by_epsilon<spherical_tag>
  703. {
  704. template <typename Box>
  705. static inline void apply(Box & box)
  706. {
  707. typedef typename coordinate_type<Box>::type coord_t;
  708. static const coord_t eps = boost::is_same<coord_t, float>::value
  709. ? coord_t(1e-6)
  710. : coord_t(1e-12);
  711. detail::expand_by_epsilon(box, eps);
  712. }
  713. };
  714. // TODO: In geographic CS it should probably also depend on FormulaPolicy.
  715. template <>
  716. struct expand_by_epsilon<geographic_tag>
  717. : expand_by_epsilon<spherical_tag>
  718. {};
  719. template <typename Sections, typename Strategy>
  720. inline void enlarge_sections(Sections& sections, Strategy const&)
  721. {
  722. // Enlarge sections slightly, this should be consistent with math::equals()
  723. // and with the tolerances used in general_form intersections.
  724. // This avoids missing turns.
  725. // Points and Segments are equal-compared WRT machine epsilon, but Boxes aren't
  726. // Enlarging Boxes ensures that they correspond to the bound objects,
  727. // Segments in this case, since Sections are collections of Segments.
  728. // It makes section a tiny bit too large, which might cause (a small number)
  729. // of more comparisons
  730. for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
  731. it != boost::end(sections);
  732. ++it)
  733. {
  734. #if defined(BOOST_GEOMETRY_USE_RESCALING)
  735. detail::sectionalize::expand_by_epsilon
  736. <
  737. typename Strategy::cs_tag
  738. >::apply(it->bounding_box);
  739. #else
  740. // Expand the box to avoid missing any intersection. The amount is
  741. // should be larger than epsilon. About the value itself: the smaller
  742. // it is, the higher the risk to miss intersections. The larger it is,
  743. // the more comparisons are made. So it should be on the high side.
  744. detail::buffer::buffer_box(it->bounding_box, 0.001, it->bounding_box);
  745. #endif
  746. }
  747. }
  748. }} // namespace detail::sectionalize
  749. #endif // DOXYGEN_NO_DETAIL
  750. #ifndef DOXYGEN_NO_DISPATCH
  751. namespace dispatch
  752. {
  753. template
  754. <
  755. typename Tag,
  756. typename Geometry,
  757. bool Reverse,
  758. typename DimensionVector
  759. >
  760. struct sectionalize
  761. {
  762. BOOST_MPL_ASSERT_MSG
  763. (
  764. false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
  765. , (types<Geometry>)
  766. );
  767. };
  768. template
  769. <
  770. typename Box,
  771. bool Reverse,
  772. typename DimensionVector
  773. >
  774. struct sectionalize<box_tag, Box, Reverse, DimensionVector>
  775. : detail::sectionalize::sectionalize_box<DimensionVector>
  776. {};
  777. template
  778. <
  779. typename LineString,
  780. typename DimensionVector
  781. >
  782. struct sectionalize
  783. <
  784. linestring_tag,
  785. LineString,
  786. false,
  787. DimensionVector
  788. >
  789. : detail::sectionalize::sectionalize_range
  790. <
  791. closed, false,
  792. typename point_type<LineString>::type,
  793. DimensionVector
  794. >
  795. {};
  796. template
  797. <
  798. typename Ring,
  799. bool Reverse,
  800. typename DimensionVector
  801. >
  802. struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
  803. : detail::sectionalize::sectionalize_range
  804. <
  805. geometry::closure<Ring>::value, Reverse,
  806. typename point_type<Ring>::type,
  807. DimensionVector
  808. >
  809. {};
  810. template
  811. <
  812. typename Polygon,
  813. bool Reverse,
  814. typename DimensionVector
  815. >
  816. struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
  817. : detail::sectionalize::sectionalize_polygon
  818. <
  819. Reverse, DimensionVector
  820. >
  821. {};
  822. template
  823. <
  824. typename MultiPolygon,
  825. bool Reverse,
  826. typename DimensionVector
  827. >
  828. struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
  829. : detail::sectionalize::sectionalize_multi
  830. <
  831. DimensionVector,
  832. detail::sectionalize::sectionalize_polygon
  833. <
  834. Reverse,
  835. DimensionVector
  836. >
  837. >
  838. {};
  839. template
  840. <
  841. typename MultiLinestring,
  842. bool Reverse,
  843. typename DimensionVector
  844. >
  845. struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
  846. : detail::sectionalize::sectionalize_multi
  847. <
  848. DimensionVector,
  849. detail::sectionalize::sectionalize_range
  850. <
  851. closed, false,
  852. typename point_type<MultiLinestring>::type,
  853. DimensionVector
  854. >
  855. >
  856. {};
  857. } // namespace dispatch
  858. #endif
  859. /*!
  860. \brief Split a geometry into monotonic sections
  861. \ingroup sectionalize
  862. \tparam Geometry type of geometry to check
  863. \tparam Sections type of sections to create
  864. \param geometry geometry to create sections from
  865. \param robust_policy policy to handle robustness issues
  866. \param sections structure with sections
  867. \param envelope_strategy strategy for envelope calculation
  868. \param expand_strategy strategy for partitions
  869. \param source_index index to assign to the ring_identifiers
  870. \param max_count maximal number of points per section
  871. (defaults to 10, this seems to give the fastest results)
  872. */
  873. template
  874. <
  875. bool Reverse,
  876. typename DimensionVector,
  877. typename Geometry,
  878. typename Sections,
  879. typename RobustPolicy,
  880. typename EnvelopeStrategy,
  881. typename ExpandStrategy
  882. >
  883. inline void sectionalize(Geometry const& geometry,
  884. RobustPolicy const& robust_policy,
  885. Sections& sections,
  886. EnvelopeStrategy const& envelope_strategy,
  887. ExpandStrategy const& expand_strategy,
  888. int source_index = 0,
  889. std::size_t max_count = 10)
  890. {
  891. BOOST_STATIC_ASSERT((! boost::is_fundamental<EnvelopeStrategy>::value));
  892. concepts::check<Geometry const>();
  893. typedef typename boost::range_value<Sections>::type section_type;
  894. // Compiletime check for point type of section boxes
  895. // and point type related to robust policy
  896. typedef typename geometry::coordinate_type
  897. <
  898. typename section_type::box_type
  899. >::type ctype1;
  900. typedef typename geometry::coordinate_type
  901. <
  902. typename geometry::robust_point_type
  903. <
  904. typename geometry::point_type<Geometry>::type,
  905. RobustPolicy
  906. >::type
  907. >::type ctype2;
  908. BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>));
  909. sections.clear();
  910. ring_identifier ring_id;
  911. ring_id.source_index = source_index;
  912. dispatch::sectionalize
  913. <
  914. typename tag<Geometry>::type,
  915. Geometry,
  916. Reverse,
  917. DimensionVector
  918. >::apply(geometry, robust_policy, sections,
  919. envelope_strategy, expand_strategy,
  920. ring_id, max_count);
  921. detail::sectionalize::enlarge_sections(sections, envelope_strategy);
  922. }
  923. template
  924. <
  925. bool Reverse,
  926. typename DimensionVector,
  927. typename Geometry,
  928. typename Sections,
  929. typename RobustPolicy
  930. >
  931. inline void sectionalize(Geometry const& geometry,
  932. RobustPolicy const& robust_policy,
  933. Sections& sections,
  934. int source_index = 0,
  935. std::size_t max_count = 10)
  936. {
  937. typedef typename strategy::envelope::services::default_strategy
  938. <
  939. typename tag<Geometry>::type,
  940. typename cs_tag<Geometry>::type
  941. >::type envelope_strategy_type;
  942. typedef typename strategy::expand::services::default_strategy
  943. <
  944. typename boost::mpl::if_c
  945. <
  946. boost::is_same<typename tag<Geometry>::type, box_tag>::value,
  947. box_tag,
  948. segment_tag
  949. >::type,
  950. typename cs_tag<Geometry>::type
  951. >::type expand_strategy_type;
  952. boost::geometry::sectionalize
  953. <
  954. Reverse, DimensionVector
  955. >(geometry, robust_policy, sections,
  956. envelope_strategy_type(),
  957. expand_strategy_type(),
  958. source_index, max_count);
  959. }
  960. }} // namespace boost::geometry
  961. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP