sectionalize.hpp 30 KB

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