sectionalize.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  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-2021.
  7. // Modifications copyright (c) 2013-2021 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 <type_traits>
  19. #include <vector>
  20. #include <boost/concept/requires.hpp>
  21. #include <boost/core/ignore_unused.hpp>
  22. #include <boost/range/begin.hpp>
  23. #include <boost/range/end.hpp>
  24. #include <boost/range/size.hpp>
  25. #include <boost/range/value_type.hpp>
  26. #include <boost/geometry/core/config.hpp>
  27. #include <boost/geometry/algorithms/assign.hpp>
  28. #include <boost/geometry/algorithms/envelope.hpp>
  29. #include <boost/geometry/algorithms/expand.hpp>
  30. #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
  31. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  32. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  33. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  34. #include <boost/geometry/core/access.hpp>
  35. #include <boost/geometry/core/closure.hpp>
  36. #include <boost/geometry/core/exterior_ring.hpp>
  37. #include <boost/geometry/core/point_order.hpp>
  38. #include <boost/geometry/core/static_assert.hpp>
  39. #include <boost/geometry/core/tags.hpp>
  40. #include <boost/geometry/geometries/concepts/check.hpp>
  41. #include <boost/geometry/geometries/box.hpp>
  42. #include <boost/geometry/geometries/segment.hpp>
  43. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  44. #include <boost/geometry/policies/robustness/robust_point_type.hpp>
  45. #include <boost/geometry/util/math.hpp>
  46. #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
  47. #include <boost/geometry/util/sequence.hpp>
  48. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  49. // TEMP
  50. #include <boost/geometry/strategy/envelope.hpp>
  51. #include <boost/geometry/strategy/expand.hpp>
  52. namespace boost { namespace geometry
  53. {
  54. /*!
  55. \brief Structure containing section information
  56. \details Section information consists of a bounding box, direction
  57. information (if it is increasing or decreasing, per dimension),
  58. index information (begin-end, ring, multi) and the number of
  59. segments in this section
  60. \tparam Box box-type
  61. \tparam DimensionCount number of dimensions for this section
  62. \ingroup sectionalize
  63. */
  64. template
  65. <
  66. typename Box,
  67. std::size_t DimensionCount
  68. >
  69. struct section
  70. {
  71. using box_type = Box;
  72. static std::size_t const dimension_count = DimensionCount;
  73. int directions[DimensionCount];
  74. ring_identifier ring_id;
  75. Box bounding_box;
  76. // NOTE: size_type could be passed as template parameter
  77. // NOTE: these probably also could be of type std::size_t
  78. signed_size_type begin_index;
  79. signed_size_type end_index;
  80. std::size_t count;
  81. std::size_t range_count;
  82. bool duplicate;
  83. signed_size_type non_duplicate_index;
  84. bool is_non_duplicate_first;
  85. bool is_non_duplicate_last;
  86. inline section()
  87. : begin_index(-1)
  88. , end_index(-1)
  89. , count(0)
  90. , range_count(0)
  91. , duplicate(false)
  92. , non_duplicate_index(-1)
  93. , is_non_duplicate_first(false)
  94. , is_non_duplicate_last(false)
  95. {
  96. assign_inverse(bounding_box);
  97. for (std::size_t i = 0; i < DimensionCount; i++)
  98. {
  99. directions[i] = 0;
  100. }
  101. }
  102. };
  103. /*!
  104. \brief Structure containing a collection of sections
  105. \note Derived from a vector, proves to be faster than of deque
  106. \note vector might be templated in the future
  107. \ingroup sectionalize
  108. */
  109. template <typename Box, std::size_t DimensionCount>
  110. struct sections : std::vector<section<Box, DimensionCount> >
  111. {
  112. using box_type = Box;
  113. static std::size_t const value = DimensionCount;
  114. };
  115. #ifndef DOXYGEN_NO_DETAIL
  116. namespace detail { namespace sectionalize
  117. {
  118. // NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
  119. // and geographic coordinate system because in these coordinate systems
  120. // e.g. a segment on northern hemisphere may go towards greater latitude
  121. // and then towards lesser latitude.
  122. template
  123. <
  124. typename Point,
  125. typename DimensionVector,
  126. std::size_t Index,
  127. std::size_t Count,
  128. typename CastedCSTag = typename tag_cast
  129. <
  130. typename cs_tag<Point>::type,
  131. spherical_tag
  132. >::type
  133. >
  134. struct get_direction_loop
  135. {
  136. using dimension = typename util::sequence_element<Index, DimensionVector>::type;
  137. template <typename Segment>
  138. static inline void apply(Segment const& seg,
  139. int directions[Count])
  140. {
  141. auto const& c0 = geometry::get<0, dimension::value>(seg);
  142. auto 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. using dimension = typename util::sequence_element<0, DimensionVector>::type;
  163. template <typename Segment>
  164. static inline void apply(Segment const& seg,
  165. int directions[Count])
  166. {
  167. using coordinate_type = typename coordinate_type<Segment>::type;
  168. using units_t = typename coordinate_system<Point>::type::units;
  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 Strategy>
  288. static inline void apply(Box & box, Point const& prev, Point const& curr,
  289. Strategy 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 Strategy>
  299. static inline void apply(Box & box, Point const& prev, Point const& curr,
  300. Strategy const& strategy)
  301. {
  302. geometry::envelope(prev, box, strategy);
  303. geometry::expand(box, curr, strategy);
  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& strategy)
  323. {
  324. geometry::expand(box, curr, strategy);
  325. }
  326. };
  327. /// @brief Helper class to create sections of a part of a range, on the fly
  328. template<typename DimensionVector>
  329. struct sectionalize_part
  330. {
  331. static const std::size_t dimension_count
  332. = util::sequence_size<DimensionVector>::value;
  333. template
  334. <
  335. typename Iterator,
  336. typename RobustPolicy,
  337. typename Sections,
  338. typename Strategy
  339. >
  340. static inline void apply(Sections& sections,
  341. Iterator begin, Iterator end,
  342. RobustPolicy const& robust_policy,
  343. Strategy const& strategy,
  344. ring_identifier ring_id,
  345. std::size_t max_count)
  346. {
  347. boost::ignore_unused(robust_policy);
  348. using section_type = typename boost::range_value<Sections>::type;
  349. using box_type = typename section_type::box_type;
  350. using point_type = typename geometry::point_type<box_type>::type;
  351. BOOST_STATIC_ASSERT
  352. (
  353. section_type::dimension_count
  354. == util::sequence_size<DimensionVector>::value
  355. );
  356. using robust_point_type = typename geometry::robust_point_type
  357. <
  358. point_type,
  359. RobustPolicy
  360. >::type;
  361. std::size_t const count = std::distance(begin, end);
  362. if (count == 0)
  363. {
  364. return;
  365. }
  366. signed_size_type index = 0;
  367. signed_size_type ndi = 0; // non duplicate index
  368. section_type section;
  369. bool mark_first_non_duplicated = true;
  370. std::size_t last_non_duplicate_index = sections.size();
  371. Iterator it = begin;
  372. robust_point_type previous_robust_point;
  373. geometry::recalculate(previous_robust_point, *it, robust_policy);
  374. for(Iterator previous = it++;
  375. it != end;
  376. ++previous, ++it, index++)
  377. {
  378. robust_point_type current_robust_point;
  379. geometry::recalculate(current_robust_point, *it, robust_policy);
  380. model::referring_segment<robust_point_type> robust_segment(
  381. previous_robust_point, current_robust_point);
  382. int direction_classes[dimension_count] = {0};
  383. get_direction_loop
  384. <
  385. point_type, DimensionVector, 0, dimension_count
  386. >::apply(robust_segment, direction_classes);
  387. // if "dir" == 0 for all point-dimensions, it is duplicate.
  388. // Those sections might be omitted, if wished, lateron
  389. bool duplicate = false;
  390. if (direction_classes[0] == 0)
  391. {
  392. // Recheck because ALL dimensions should be checked,
  393. // not only first one.
  394. // (dimension_count might be < dimension<P>::value)
  395. if (check_duplicate_loop
  396. <
  397. 0, geometry::dimension<point_type>::type::value
  398. >::apply(robust_segment)
  399. )
  400. {
  401. duplicate = true;
  402. // Change direction-info to force new section
  403. // Note that wo consecutive duplicate segments will generate
  404. // only one duplicate-section.
  405. // Actual value is not important as long as it is not -1,0,1
  406. assign_loop
  407. <
  408. int, 0, dimension_count
  409. >::apply(direction_classes, -99);
  410. }
  411. }
  412. if (section.count > 0
  413. && (! compare_loop
  414. <
  415. int, 0, dimension_count
  416. >::apply(direction_classes, section.directions)
  417. || section.count > max_count)
  418. )
  419. {
  420. if (! section.duplicate)
  421. {
  422. last_non_duplicate_index = sections.size();
  423. }
  424. sections.push_back(section);
  425. section = section_type();
  426. }
  427. if (section.count == 0)
  428. {
  429. section.begin_index = index;
  430. section.ring_id = ring_id;
  431. section.duplicate = duplicate;
  432. section.non_duplicate_index = ndi;
  433. section.range_count = count;
  434. if (mark_first_non_duplicated && ! duplicate)
  435. {
  436. section.is_non_duplicate_first = true;
  437. mark_first_non_duplicated = false;
  438. }
  439. copy_loop
  440. <
  441. int, 0, dimension_count
  442. >::apply(direction_classes, section.directions);
  443. // In cartesian this is envelope of previous point expanded with current point
  444. // in non-cartesian this is envelope of a segment
  445. box_first_in_section<typename cs_tag<robust_point_type>::type>
  446. ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
  447. }
  448. else
  449. {
  450. // In cartesian this is expand with current point
  451. // in non-cartesian this is expand with a segment
  452. box_next_in_section<typename cs_tag<robust_point_type>::type>
  453. ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
  454. }
  455. section.end_index = index + 1;
  456. section.count++;
  457. if (! duplicate)
  458. {
  459. ndi++;
  460. }
  461. previous_robust_point = current_robust_point;
  462. }
  463. // Add last section if applicable
  464. if (section.count > 0)
  465. {
  466. if (! section.duplicate)
  467. {
  468. last_non_duplicate_index = sections.size();
  469. }
  470. sections.push_back(section);
  471. }
  472. if (last_non_duplicate_index < sections.size()
  473. && ! sections[last_non_duplicate_index].duplicate)
  474. {
  475. sections[last_non_duplicate_index].is_non_duplicate_last = true;
  476. }
  477. }
  478. };
  479. template
  480. <
  481. closure_selector Closure,
  482. bool Reverse,
  483. typename DimensionVector
  484. >
  485. struct sectionalize_range
  486. {
  487. template
  488. <
  489. typename Range,
  490. typename RobustPolicy,
  491. typename Sections,
  492. typename Strategy
  493. >
  494. static inline void apply(Range const& range,
  495. RobustPolicy const& robust_policy,
  496. Sections& sections,
  497. Strategy const& strategy,
  498. ring_identifier ring_id,
  499. std::size_t max_count)
  500. {
  501. detail::closed_clockwise_view
  502. <
  503. Range const,
  504. Closure,
  505. Reverse ? counterclockwise : clockwise
  506. > const view(range);
  507. std::size_t const n = boost::size(view);
  508. if (n == 0)
  509. {
  510. // Zero points, no section
  511. return;
  512. }
  513. if (n == 1)
  514. {
  515. // Line with one point ==> no sections
  516. return;
  517. }
  518. sectionalize_part<DimensionVector>::apply(sections,
  519. boost::begin(view), boost::end(view),
  520. robust_policy, strategy,
  521. ring_id, max_count);
  522. }
  523. };
  524. template
  525. <
  526. bool Reverse,
  527. typename DimensionVector
  528. >
  529. struct sectionalize_polygon
  530. {
  531. template
  532. <
  533. typename Polygon,
  534. typename RobustPolicy,
  535. typename Sections,
  536. typename Strategy
  537. >
  538. static inline void apply(Polygon const& poly,
  539. RobustPolicy const& robust_policy,
  540. Sections& sections,
  541. Strategy const& strategy,
  542. ring_identifier ring_id,
  543. std::size_t max_count)
  544. {
  545. using sectionalizer = sectionalize_range
  546. <
  547. closure<Polygon>::value, Reverse, DimensionVector
  548. >;
  549. ring_id.ring_index = -1;
  550. sectionalizer::apply(exterior_ring(poly), robust_policy, sections,
  551. strategy, ring_id, max_count);
  552. ring_id.ring_index++;
  553. auto const& rings = interior_rings(poly);
  554. for (auto it = boost::begin(rings); it != boost::end(rings);
  555. ++it, ++ring_id.ring_index)
  556. {
  557. sectionalizer::apply(*it, robust_policy, sections,
  558. strategy, ring_id, max_count);
  559. }
  560. }
  561. };
  562. template <typename DimensionVector>
  563. struct sectionalize_box
  564. {
  565. template
  566. <
  567. typename Box,
  568. typename RobustPolicy,
  569. typename Sections,
  570. typename Strategy
  571. >
  572. static inline void apply(Box const& box,
  573. RobustPolicy const& robust_policy,
  574. Sections& sections,
  575. Strategy const& strategy,
  576. ring_identifier const& ring_id, std::size_t max_count)
  577. {
  578. using point_type = typename point_type<Box>::type;
  579. assert_dimension<Box, 2>();
  580. // Add all four sides of the 2D-box as separate section.
  581. // Easiest is to convert it to a polygon.
  582. // However, we don't have the polygon type
  583. // (or polygon would be a helper-type).
  584. // Therefore we mimic a linestring/std::vector of 5 points
  585. // TODO: might be replaced by assign_box_corners_oriented
  586. // or just "convert"
  587. point_type ll, lr, ul, ur;
  588. geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
  589. std::vector<point_type> points;
  590. points.push_back(ll);
  591. points.push_back(ul);
  592. points.push_back(ur);
  593. points.push_back(lr);
  594. points.push_back(ll);
  595. // NOTE: Use cartesian envelope strategy in all coordinate systems
  596. // because edges of a box are not geodesic segments
  597. sectionalize_range
  598. <
  599. closed, false, DimensionVector
  600. >::apply(points, robust_policy, sections,
  601. strategy, ring_id, max_count);
  602. }
  603. };
  604. template <typename DimensionVector, typename Policy>
  605. struct sectionalize_multi
  606. {
  607. template
  608. <
  609. typename MultiGeometry,
  610. typename RobustPolicy,
  611. typename Sections,
  612. typename Strategy
  613. >
  614. static inline void apply(MultiGeometry const& multi,
  615. RobustPolicy const& robust_policy,
  616. Sections& sections,
  617. Strategy const& strategy,
  618. ring_identifier ring_id,
  619. std::size_t max_count)
  620. {
  621. ring_id.multi_index = 0;
  622. for (auto it = boost::begin(multi); it != boost::end(multi); ++it, ++ring_id.multi_index)
  623. {
  624. Policy::apply(*it, robust_policy, sections,
  625. strategy,
  626. ring_id, max_count);
  627. }
  628. }
  629. };
  630. template <typename Sections, typename Strategy>
  631. inline void enlarge_sections(Sections& sections, Strategy const&)
  632. {
  633. // Expand the box to avoid missing any intersection.
  634. // About the value itself: the smaller it is,
  635. // the higher the risk to miss intersections.
  636. // The larger it is, the more comparisons are made,
  637. // which is not harmful for the result,
  638. // but it might be for the performance.
  639. // So it should be on the higher side.
  640. //
  641. // The current value:
  642. // - for double :~ 2.22e-13
  643. // - for float :~ 1e-4
  644. // - for Boost.Multiprecision (50) :~ 5.35e-48
  645. // - for Boost.Rational : 0/1
  646. // WARNING: don't use decltype here.
  647. // Earlier code used decltype(section.bonding_box) below,
  648. // but that somehow is not accepted by the NVCC (CUDA 12.4) compiler.
  649. using section_t = typename boost::range_value<Sections>::type;
  650. using box_t = typename section_t::box_type;
  651. using coor_t = typename geometry::coordinate_type<box_t>::type;
  652. static auto const eps = math::scaled_epsilon<coor_t>(1000);
  653. for (auto& section : sections)
  654. {
  655. expand_by_epsilon(section.bounding_box, eps);
  656. }
  657. }
  658. }} // namespace detail::sectionalize
  659. #endif // DOXYGEN_NO_DETAIL
  660. #ifndef DOXYGEN_NO_DISPATCH
  661. namespace dispatch
  662. {
  663. template
  664. <
  665. typename Tag,
  666. typename Geometry,
  667. bool Reverse,
  668. typename DimensionVector
  669. >
  670. struct sectionalize
  671. {
  672. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  673. "Not or not yet implemented for this Geometry type.",
  674. Tag, Geometry);
  675. };
  676. template
  677. <
  678. typename Box,
  679. bool Reverse,
  680. typename DimensionVector
  681. >
  682. struct sectionalize<box_tag, Box, Reverse, DimensionVector>
  683. : detail::sectionalize::sectionalize_box<DimensionVector>
  684. {};
  685. template
  686. <
  687. typename LineString,
  688. typename DimensionVector
  689. >
  690. struct sectionalize
  691. <
  692. linestring_tag,
  693. LineString,
  694. false,
  695. DimensionVector
  696. >
  697. : detail::sectionalize::sectionalize_range<closed, false, DimensionVector>
  698. {};
  699. template
  700. <
  701. typename Ring,
  702. bool Reverse,
  703. typename DimensionVector
  704. >
  705. struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
  706. : detail::sectionalize::sectionalize_range
  707. <
  708. geometry::closure<Ring>::value, Reverse,
  709. DimensionVector
  710. >
  711. {};
  712. template
  713. <
  714. typename Polygon,
  715. bool Reverse,
  716. typename DimensionVector
  717. >
  718. struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
  719. : detail::sectionalize::sectionalize_polygon
  720. <
  721. Reverse, DimensionVector
  722. >
  723. {};
  724. template
  725. <
  726. typename MultiPolygon,
  727. bool Reverse,
  728. typename DimensionVector
  729. >
  730. struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
  731. : detail::sectionalize::sectionalize_multi
  732. <
  733. DimensionVector,
  734. detail::sectionalize::sectionalize_polygon
  735. <
  736. Reverse,
  737. DimensionVector
  738. >
  739. >
  740. {};
  741. template
  742. <
  743. typename MultiLinestring,
  744. bool Reverse,
  745. typename DimensionVector
  746. >
  747. struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
  748. : detail::sectionalize::sectionalize_multi
  749. <
  750. DimensionVector,
  751. detail::sectionalize::sectionalize_range<closed, false, DimensionVector>
  752. >
  753. {};
  754. } // namespace dispatch
  755. #endif
  756. /*!
  757. \brief Split a geometry into monotonic sections
  758. \ingroup sectionalize
  759. \tparam Geometry type of geometry to check
  760. \tparam Sections type of sections to create
  761. \param geometry geometry to create sections from
  762. \param robust_policy policy to handle robustness issues
  763. \param sections structure with sections
  764. \param strategy strategy for envelope calculation
  765. \param expand_strategy strategy for partitions
  766. \param source_index index to assign to the ring_identifiers
  767. \param max_count maximal number of points per section
  768. (defaults to 10, this seems to give the fastest results)
  769. */
  770. template
  771. <
  772. bool Reverse,
  773. typename DimensionVector,
  774. typename Geometry,
  775. typename Sections,
  776. typename RobustPolicy,
  777. typename Strategy
  778. >
  779. inline void sectionalize(Geometry const& geometry,
  780. RobustPolicy const& robust_policy,
  781. Sections& sections,
  782. Strategy const& strategy,
  783. int source_index = 0,
  784. std::size_t max_count = 10)
  785. {
  786. concepts::check<Geometry const>();
  787. sections.clear();
  788. ring_identifier ring_id;
  789. ring_id.source_index = source_index;
  790. dispatch::sectionalize
  791. <
  792. typename tag<Geometry>::type,
  793. Geometry,
  794. Reverse,
  795. DimensionVector
  796. >::apply(geometry, robust_policy, sections,
  797. strategy,
  798. ring_id, max_count);
  799. detail::sectionalize::enlarge_sections(sections, strategy);
  800. }
  801. template
  802. <
  803. bool Reverse,
  804. typename DimensionVector,
  805. typename Geometry,
  806. typename Sections,
  807. typename RobustPolicy
  808. >
  809. inline void sectionalize(Geometry const& geometry,
  810. RobustPolicy const& robust_policy,
  811. Sections& sections,
  812. int source_index = 0,
  813. std::size_t max_count = 10)
  814. {
  815. using box_type = typename Sections::box_type;
  816. using strategy_type = typename strategies::envelope::services::default_strategy
  817. <
  818. Geometry,
  819. box_type
  820. >::type;
  821. boost::geometry::sectionalize
  822. <
  823. Reverse, DimensionVector
  824. >(geometry, robust_policy, sections,
  825. strategy_type(),
  826. source_index, max_count);
  827. }
  828. }} // namespace boost::geometry
  829. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP