sectionalize.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  6. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
  12. #include <cstddef>
  13. #include <vector>
  14. #include <boost/mpl/assert.hpp>
  15. #include <boost/range.hpp>
  16. #include <boost/typeof/typeof.hpp>
  17. #include <boost/geometry/algorithms/assign.hpp>
  18. #include <boost/geometry/algorithms/expand.hpp>
  19. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  20. #include <boost/geometry/core/access.hpp>
  21. #include <boost/geometry/core/closure.hpp>
  22. #include <boost/geometry/core/exterior_ring.hpp>
  23. #include <boost/geometry/core/point_order.hpp>
  24. #include <boost/geometry/geometries/concepts/check.hpp>
  25. #include <boost/geometry/util/math.hpp>
  26. #include <boost/geometry/views/closeable_view.hpp>
  27. #include <boost/geometry/views/reversible_view.hpp>
  28. #include <boost/geometry/geometries/segment.hpp>
  29. namespace boost { namespace geometry
  30. {
  31. /*!
  32. \brief Structure containing section information
  33. \details Section information consists of a bounding box, direction
  34. information (if it is increasing or decreasing, per dimension),
  35. index information (begin-end, ring, multi) and the number of
  36. segments in this section
  37. \tparam Box box-type
  38. \tparam DimensionCount number of dimensions for this section
  39. \ingroup sectionalize
  40. */
  41. template <typename Box, std::size_t DimensionCount>
  42. struct section
  43. {
  44. typedef Box box_type;
  45. int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
  46. int directions[DimensionCount];
  47. ring_identifier ring_id;
  48. Box bounding_box;
  49. int begin_index;
  50. int end_index;
  51. std::size_t count;
  52. std::size_t range_count;
  53. bool duplicate;
  54. int non_duplicate_index;
  55. inline section()
  56. : id(-1)
  57. , begin_index(-1)
  58. , end_index(-1)
  59. , count(0)
  60. , range_count(0)
  61. , duplicate(false)
  62. , non_duplicate_index(-1)
  63. {
  64. assign_inverse(bounding_box);
  65. for (std::size_t i = 0; i < DimensionCount; i++)
  66. {
  67. directions[i] = 0;
  68. }
  69. }
  70. };
  71. /*!
  72. \brief Structure containing a collection of sections
  73. \note Derived from a vector, proves to be faster than of deque
  74. \note vector might be templated in the future
  75. \ingroup sectionalize
  76. */
  77. template <typename Box, std::size_t DimensionCount>
  78. struct sections : std::vector<section<Box, DimensionCount> >
  79. {
  80. typedef Box box_type;
  81. static std::size_t const value = DimensionCount;
  82. };
  83. #ifndef DOXYGEN_NO_DETAIL
  84. namespace detail { namespace sectionalize
  85. {
  86. template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
  87. struct get_direction_loop
  88. {
  89. typedef typename coordinate_type<Segment>::type coordinate_type;
  90. static inline void apply(Segment const& seg,
  91. int directions[DimensionCount])
  92. {
  93. coordinate_type const diff =
  94. geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
  95. coordinate_type zero = coordinate_type();
  96. directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
  97. get_direction_loop
  98. <
  99. Segment, Dimension + 1, DimensionCount
  100. >::apply(seg, directions);
  101. }
  102. };
  103. template <typename Segment, std::size_t DimensionCount>
  104. struct get_direction_loop<Segment, DimensionCount, DimensionCount>
  105. {
  106. static inline void apply(Segment const&, int [DimensionCount])
  107. {}
  108. };
  109. template <typename T, std::size_t Dimension, std::size_t DimensionCount>
  110. struct copy_loop
  111. {
  112. static inline void apply(T const source[DimensionCount],
  113. T target[DimensionCount])
  114. {
  115. target[Dimension] = source[Dimension];
  116. copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
  117. }
  118. };
  119. template <typename T, std::size_t DimensionCount>
  120. struct copy_loop<T, DimensionCount, DimensionCount>
  121. {
  122. static inline void apply(T const [DimensionCount], T [DimensionCount])
  123. {}
  124. };
  125. template <typename T, std::size_t Dimension, std::size_t DimensionCount>
  126. struct compare_loop
  127. {
  128. static inline bool apply(T const source[DimensionCount],
  129. T const target[DimensionCount])
  130. {
  131. bool const not_equal = target[Dimension] != source[Dimension];
  132. return not_equal
  133. ? false
  134. : compare_loop
  135. <
  136. T, Dimension + 1, DimensionCount
  137. >::apply(source, target);
  138. }
  139. };
  140. template <typename T, std::size_t DimensionCount>
  141. struct compare_loop<T, DimensionCount, DimensionCount>
  142. {
  143. static inline bool apply(T const [DimensionCount],
  144. T const [DimensionCount])
  145. {
  146. return true;
  147. }
  148. };
  149. template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
  150. struct check_duplicate_loop
  151. {
  152. typedef typename coordinate_type<Segment>::type coordinate_type;
  153. static inline bool apply(Segment const& seg)
  154. {
  155. if (! geometry::math::equals
  156. (
  157. geometry::get<0, Dimension>(seg),
  158. geometry::get<1, Dimension>(seg)
  159. )
  160. )
  161. {
  162. return false;
  163. }
  164. return check_duplicate_loop
  165. <
  166. Segment, Dimension + 1, DimensionCount
  167. >::apply(seg);
  168. }
  169. };
  170. template <typename Segment, std::size_t DimensionCount>
  171. struct check_duplicate_loop<Segment, DimensionCount, DimensionCount>
  172. {
  173. static inline bool apply(Segment const&)
  174. {
  175. return true;
  176. }
  177. };
  178. template <typename T, std::size_t Dimension, std::size_t DimensionCount>
  179. struct assign_loop
  180. {
  181. static inline void apply(T dims[DimensionCount], int const value)
  182. {
  183. dims[Dimension] = value;
  184. assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
  185. }
  186. };
  187. template <typename T, std::size_t DimensionCount>
  188. struct assign_loop<T, DimensionCount, DimensionCount>
  189. {
  190. static inline void apply(T [DimensionCount], int const)
  191. {
  192. }
  193. };
  194. /// @brief Helper class to create sections of a part of a range, on the fly
  195. template
  196. <
  197. typename Range, // Can be closeable_view
  198. typename Point,
  199. typename Sections,
  200. std::size_t DimensionCount,
  201. std::size_t MaxCount
  202. >
  203. struct sectionalize_part
  204. {
  205. typedef model::referring_segment<Point const> segment_type;
  206. typedef typename boost::range_value<Sections>::type section_type;
  207. typedef typename boost::range_iterator<Range const>::type iterator_type;
  208. static inline void apply(Sections& sections, section_type& section,
  209. int& index, int& ndi,
  210. Range const& range,
  211. ring_identifier ring_id)
  212. {
  213. if (int(boost::size(range)) <= index)
  214. {
  215. return;
  216. }
  217. if (index == 0)
  218. {
  219. ndi = 0;
  220. }
  221. iterator_type it = boost::begin(range);
  222. it += index;
  223. for(iterator_type previous = it++;
  224. it != boost::end(range);
  225. ++previous, ++it, index++)
  226. {
  227. segment_type segment(*previous, *it);
  228. int direction_classes[DimensionCount] = {0};
  229. get_direction_loop
  230. <
  231. segment_type, 0, DimensionCount
  232. >::apply(segment, direction_classes);
  233. // if "dir" == 0 for all point-dimensions, it is duplicate.
  234. // Those sections might be omitted, if wished, lateron
  235. bool duplicate = false;
  236. if (direction_classes[0] == 0)
  237. {
  238. // Recheck because ALL dimensions should be checked,
  239. // not only first one.
  240. // (DimensionCount might be < dimension<P>::value)
  241. if (check_duplicate_loop
  242. <
  243. segment_type, 0, geometry::dimension<Point>::type::value
  244. >::apply(segment)
  245. )
  246. {
  247. duplicate = true;
  248. // Change direction-info to force new section
  249. // Note that wo consecutive duplicate segments will generate
  250. // only one duplicate-section.
  251. // Actual value is not important as long as it is not -1,0,1
  252. assign_loop
  253. <
  254. int, 0, DimensionCount
  255. >::apply(direction_classes, -99);
  256. }
  257. }
  258. if (section.count > 0
  259. && (!compare_loop
  260. <
  261. int, 0, DimensionCount
  262. >::apply(direction_classes, section.directions)
  263. || section.count > MaxCount
  264. )
  265. )
  266. {
  267. sections.push_back(section);
  268. section = section_type();
  269. }
  270. if (section.count == 0)
  271. {
  272. section.begin_index = index;
  273. section.ring_id = ring_id;
  274. section.duplicate = duplicate;
  275. section.non_duplicate_index = ndi;
  276. section.range_count = boost::size(range);
  277. copy_loop
  278. <
  279. int, 0, DimensionCount
  280. >::apply(direction_classes, section.directions);
  281. geometry::expand(section.bounding_box, *previous);
  282. }
  283. geometry::expand(section.bounding_box, *it);
  284. section.end_index = index + 1;
  285. section.count++;
  286. if (! duplicate)
  287. {
  288. ndi++;
  289. }
  290. }
  291. }
  292. };
  293. template
  294. <
  295. typename Range, closure_selector Closure, bool Reverse,
  296. typename Point,
  297. typename Sections,
  298. std::size_t DimensionCount,
  299. std::size_t MaxCount
  300. >
  301. struct sectionalize_range
  302. {
  303. typedef typename closeable_view<Range const, Closure>::type cview_type;
  304. typedef typename reversible_view
  305. <
  306. cview_type const,
  307. Reverse ? iterate_reverse : iterate_forward
  308. >::type view_type;
  309. static inline void apply(Range const& range, Sections& sections,
  310. ring_identifier ring_id)
  311. {
  312. cview_type cview(range);
  313. view_type view(cview);
  314. std::size_t const n = boost::size(view);
  315. if (n == 0)
  316. {
  317. // Zero points, no section
  318. return;
  319. }
  320. if (n == 1)
  321. {
  322. // Line with one point ==> no sections
  323. return;
  324. }
  325. int index = 0;
  326. int ndi = 0; // non duplicate index
  327. typedef typename boost::range_value<Sections>::type section_type;
  328. section_type section;
  329. sectionalize_part
  330. <
  331. view_type, Point, Sections,
  332. DimensionCount, MaxCount
  333. >::apply(sections, section, index, ndi,
  334. view, ring_id);
  335. // Add last section if applicable
  336. if (section.count > 0)
  337. {
  338. sections.push_back(section);
  339. }
  340. }
  341. };
  342. template
  343. <
  344. typename Polygon,
  345. bool Reverse,
  346. typename Sections,
  347. std::size_t DimensionCount,
  348. std::size_t MaxCount
  349. >
  350. struct sectionalize_polygon
  351. {
  352. static inline void apply(Polygon const& poly, Sections& sections,
  353. ring_identifier ring_id)
  354. {
  355. typedef typename point_type<Polygon>::type point_type;
  356. typedef typename ring_type<Polygon>::type ring_type;
  357. typedef sectionalize_range
  358. <
  359. ring_type, closure<Polygon>::value, Reverse,
  360. point_type, Sections, DimensionCount, MaxCount
  361. > sectionalizer_type;
  362. ring_id.ring_index = -1;
  363. sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index);
  364. ring_id.ring_index++;
  365. typename interior_return_type<Polygon const>::type rings
  366. = interior_rings(poly);
  367. for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
  368. ++it, ++ring_id.ring_index)
  369. {
  370. sectionalizer_type::apply(*it, sections, ring_id);
  371. }
  372. }
  373. };
  374. template
  375. <
  376. typename Box,
  377. typename Sections,
  378. std::size_t DimensionCount,
  379. std::size_t MaxCount
  380. >
  381. struct sectionalize_box
  382. {
  383. static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id)
  384. {
  385. typedef typename point_type<Box>::type point_type;
  386. assert_dimension<Box, 2>();
  387. // Add all four sides of the 2D-box as separate section.
  388. // Easiest is to convert it to a polygon.
  389. // However, we don't have the polygon type
  390. // (or polygon would be a helper-type).
  391. // Therefore we mimic a linestring/std::vector of 5 points
  392. // TODO: might be replaced by assign_box_corners_oriented
  393. // or just "convert"
  394. point_type ll, lr, ul, ur;
  395. geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
  396. std::vector<point_type> points;
  397. points.push_back(ll);
  398. points.push_back(ul);
  399. points.push_back(ur);
  400. points.push_back(lr);
  401. points.push_back(ll);
  402. sectionalize_range
  403. <
  404. std::vector<point_type>, closed, false,
  405. point_type,
  406. Sections,
  407. DimensionCount,
  408. MaxCount
  409. >::apply(points, sections, ring_id);
  410. }
  411. };
  412. template <typename Sections>
  413. inline void set_section_unique_ids(Sections& sections)
  414. {
  415. // Set ID's.
  416. int index = 0;
  417. for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
  418. it != boost::end(sections);
  419. ++it)
  420. {
  421. it->id = index++;
  422. }
  423. }
  424. template <typename Sections>
  425. inline void enlargeSections(Sections& sections)
  426. {
  427. // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
  428. // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
  429. // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large,
  430. // which might cause (a small number) of more comparisons
  431. // TODO: make dimension-agnostic
  432. for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
  433. it != boost::end(sections);
  434. ++it)
  435. {
  436. typedef typename boost::range_value<Sections>::type section_type;
  437. typedef typename section_type::box_type box_type;
  438. typedef typename geometry::coordinate_type<box_type>::type coordinate_type;
  439. coordinate_type const reps = math::relaxed_epsilon(10.0);
  440. geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps);
  441. geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps);
  442. geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps);
  443. geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps);
  444. }
  445. }
  446. }} // namespace detail::sectionalize
  447. #endif // DOXYGEN_NO_DETAIL
  448. #ifndef DOXYGEN_NO_DISPATCH
  449. namespace dispatch
  450. {
  451. template
  452. <
  453. typename Tag,
  454. typename Geometry,
  455. bool Reverse,
  456. typename Sections,
  457. std::size_t DimensionCount,
  458. std::size_t MaxCount
  459. >
  460. struct sectionalize
  461. {
  462. BOOST_MPL_ASSERT_MSG
  463. (
  464. false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
  465. , (types<Geometry>)
  466. );
  467. };
  468. template
  469. <
  470. typename Box,
  471. bool Reverse,
  472. typename Sections,
  473. std::size_t DimensionCount,
  474. std::size_t MaxCount
  475. >
  476. struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount>
  477. : detail::sectionalize::sectionalize_box
  478. <
  479. Box,
  480. Sections,
  481. DimensionCount,
  482. MaxCount
  483. >
  484. {};
  485. template
  486. <
  487. typename LineString,
  488. typename Sections,
  489. std::size_t DimensionCount,
  490. std::size_t MaxCount
  491. >
  492. struct sectionalize
  493. <
  494. linestring_tag,
  495. LineString,
  496. false,
  497. Sections,
  498. DimensionCount,
  499. MaxCount
  500. >
  501. : detail::sectionalize::sectionalize_range
  502. <
  503. LineString, closed, false,
  504. typename point_type<LineString>::type,
  505. Sections,
  506. DimensionCount,
  507. MaxCount
  508. >
  509. {};
  510. template
  511. <
  512. typename Ring,
  513. bool Reverse,
  514. typename Sections,
  515. std::size_t DimensionCount,
  516. std::size_t MaxCount
  517. >
  518. struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount>
  519. : detail::sectionalize::sectionalize_range
  520. <
  521. Ring, geometry::closure<Ring>::value, Reverse,
  522. typename point_type<Ring>::type,
  523. Sections,
  524. DimensionCount,
  525. MaxCount
  526. >
  527. {};
  528. template
  529. <
  530. typename Polygon,
  531. bool Reverse,
  532. typename Sections,
  533. std::size_t DimensionCount,
  534. std::size_t MaxCount
  535. >
  536. struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount>
  537. : detail::sectionalize::sectionalize_polygon
  538. <
  539. Polygon, Reverse, Sections, DimensionCount, MaxCount
  540. >
  541. {};
  542. } // namespace dispatch
  543. #endif
  544. /*!
  545. \brief Split a geometry into monotonic sections
  546. \ingroup sectionalize
  547. \tparam Geometry type of geometry to check
  548. \tparam Sections type of sections to create
  549. \param geometry geometry to create sections from
  550. \param sections structure with sections
  551. \param source_index index to assign to the ring_identifiers
  552. */
  553. template<bool Reverse, typename Geometry, typename Sections>
  554. inline void sectionalize(Geometry const& geometry, Sections& sections, int source_index = 0)
  555. {
  556. concept::check<Geometry const>();
  557. // TODO: review use of this constant (see below) as causing problems with GCC 4.6 --mloskot
  558. // A maximum of 10 segments per section seems to give the fastest results
  559. //static std::size_t const max_segments_per_section = 10;
  560. typedef dispatch::sectionalize
  561. <
  562. typename tag<Geometry>::type,
  563. Geometry,
  564. Reverse,
  565. Sections,
  566. Sections::value,
  567. 10 // TODO: max_segments_per_section
  568. > sectionalizer_type;
  569. sections.clear();
  570. ring_identifier ring_id;
  571. ring_id.source_index = source_index;
  572. sectionalizer_type::apply(geometry, sections, ring_id);
  573. detail::sectionalize::set_section_unique_ids(sections);
  574. detail::sectionalize::enlargeSections(sections);
  575. }
  576. }} // namespace boost::geometry
  577. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP