sectionalize.hpp 29 KB

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