boundary_checker.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2023, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  4. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
  10. #include <boost/core/ignore_unused.hpp>
  11. #include <boost/range/size.hpp>
  12. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  13. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  14. #include <boost/geometry/algorithms/num_points.hpp>
  15. #include <boost/geometry/geometries/helper_geometry.hpp>
  16. #include <boost/geometry/policies/compare.hpp>
  17. #include <boost/geometry/strategies/relate/cartesian.hpp>
  18. #include <boost/geometry/strategies/relate/geographic.hpp>
  19. #include <boost/geometry/strategies/relate/spherical.hpp>
  20. #include <boost/geometry/util/has_nan_coordinate.hpp>
  21. #include <boost/geometry/util/range.hpp>
  22. namespace boost { namespace geometry
  23. {
  24. #ifndef DOXYGEN_NO_DETAIL
  25. namespace detail { namespace relate
  26. {
  27. template
  28. <
  29. typename Geometry,
  30. typename Strategy,
  31. typename Tag = typename geometry::tag<Geometry>::type
  32. >
  33. class boundary_checker {};
  34. template <typename Geometry, typename Strategy>
  35. class boundary_checker<Geometry, Strategy, linestring_tag>
  36. {
  37. public:
  38. boundary_checker(Geometry const& g, Strategy const& s)
  39. : m_has_boundary(
  40. boost::size(g) >= 2
  41. && ! detail::equals::equals_point_point(range::front(g), range::back(g), s))
  42. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  43. , m_geometry(g)
  44. #endif
  45. , m_strategy(s)
  46. {}
  47. template <typename Point>
  48. bool is_endpoint_boundary(Point const& pt) const
  49. {
  50. boost::ignore_unused(pt);
  51. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  52. // may give false positives for INT
  53. BOOST_GEOMETRY_ASSERT(
  54. detail::equals::equals_point_point(pt, range::front(m_geometry), m_strategy)
  55. || detail::equals::equals_point_point(pt, range::back(m_geometry), m_strategy));
  56. #endif
  57. return m_has_boundary;
  58. }
  59. Strategy const& strategy() const
  60. {
  61. return m_strategy;
  62. }
  63. private:
  64. bool m_has_boundary;
  65. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  66. Geometry const& m_geometry;
  67. #endif
  68. Strategy const& m_strategy;
  69. };
  70. template <typename Point, typename Strategy, typename Out>
  71. inline void copy_boundary_points(Point const& front_pt, Point const& back_pt,
  72. Strategy const& strategy, Out & boundary_points)
  73. {
  74. using mutable_point_type = typename Out::value_type;
  75. // linear ring or point - no boundary
  76. if (! equals::equals_point_point(front_pt, back_pt, strategy))
  77. {
  78. // do not add points containing NaN coordinates
  79. // because they cannot be reasonably compared, e.g. with MSVC
  80. // an assertion failure is reported in std::equal_range()
  81. if (! geometry::has_nan_coordinate(front_pt))
  82. {
  83. mutable_point_type pt;
  84. geometry::convert(front_pt, pt);
  85. boundary_points.push_back(pt);
  86. }
  87. if (! geometry::has_nan_coordinate(back_pt))
  88. {
  89. mutable_point_type pt;
  90. geometry::convert(back_pt, pt);
  91. boundary_points.push_back(pt);
  92. }
  93. }
  94. }
  95. template <typename Segment, typename Strategy, typename Out>
  96. inline void copy_boundary_points_of_seg(Segment const& seg, Strategy const& strategy,
  97. Out & boundary_points)
  98. {
  99. typename Out::value_type front_pt, back_pt;
  100. assign_point_from_index<0>(seg, front_pt);
  101. assign_point_from_index<1>(seg, back_pt);
  102. copy_boundary_points(front_pt, back_pt, strategy, boundary_points);
  103. }
  104. template <typename Linestring, typename Strategy, typename Out>
  105. inline void copy_boundary_points_of_ls(Linestring const& ls, Strategy const& strategy,
  106. Out & boundary_points)
  107. {
  108. // empty or point - no boundary
  109. if (boost::size(ls) >= 2)
  110. {
  111. auto const& front_pt = range::front(ls);
  112. auto const& back_pt = range::back(ls);
  113. copy_boundary_points(front_pt, back_pt, strategy, boundary_points);
  114. }
  115. }
  116. template <typename MultiLinestring, typename Strategy, typename Out>
  117. inline void copy_boundary_points_of_mls(MultiLinestring const& mls, Strategy const& strategy,
  118. Out & boundary_points)
  119. {
  120. for (auto it = boost::begin(mls); it != boost::end(mls); ++it)
  121. {
  122. copy_boundary_points_of_ls(*it, strategy, boundary_points);
  123. }
  124. }
  125. template <typename Geometry, typename Strategy>
  126. class boundary_checker<Geometry, Strategy, multi_linestring_tag>
  127. {
  128. using point_type = typename point_type<Geometry>::type;
  129. using mutable_point_type = typename helper_geometry<point_type>::type;
  130. public:
  131. boundary_checker(Geometry const& g, Strategy const& s)
  132. : m_is_filled(false), m_geometry(g), m_strategy(s)
  133. {}
  134. // First call O(NlogN)
  135. // Each next call O(logN)
  136. template <typename Point>
  137. bool is_endpoint_boundary(Point const& pt) const
  138. {
  139. using less_type = geometry::less<mutable_point_type, -1, Strategy>;
  140. auto const multi_count = boost::size(m_geometry);
  141. if (multi_count < 1)
  142. {
  143. return false;
  144. }
  145. if (! m_is_filled)
  146. {
  147. //boundary_points.clear();
  148. m_boundary_points.reserve(multi_count * 2);
  149. copy_boundary_points_of_mls(m_geometry, m_strategy, m_boundary_points);
  150. std::sort(m_boundary_points.begin(), m_boundary_points.end(), less_type());
  151. m_is_filled = true;
  152. }
  153. mutable_point_type mpt;
  154. geometry::convert(pt, mpt);
  155. auto const equal_range = std::equal_range(m_boundary_points.begin(),
  156. m_boundary_points.end(),
  157. mpt,
  158. less_type());
  159. std::size_t const equal_points_count = boost::size(equal_range);
  160. return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
  161. }
  162. Strategy const& strategy() const
  163. {
  164. return m_strategy;
  165. }
  166. private:
  167. mutable bool m_is_filled;
  168. // TODO: store references/pointers instead of converted points?
  169. mutable std::vector<mutable_point_type> m_boundary_points;
  170. Geometry const& m_geometry;
  171. Strategy const& m_strategy;
  172. };
  173. }} // namespace detail::relate
  174. #endif // DOXYGEN_NO_DETAIL
  175. }} // namespace boost::geometry
  176. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP