boundary_checker.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2018 Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
  8. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
  9. #include <boost/core/ignore_unused.hpp>
  10. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  11. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  12. #include <boost/geometry/algorithms/num_points.hpp>
  13. #include <boost/geometry/policies/compare.hpp>
  14. #include <boost/geometry/util/has_nan_coordinate.hpp>
  15. #include <boost/geometry/util/range.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. #ifndef DOXYGEN_NO_DETAIL
  19. namespace detail { namespace relate {
  20. enum boundary_query { boundary_front, boundary_back, boundary_any };
  21. template <typename Geometry,
  22. typename WithinStrategy, // Point/Point equals (within) strategy
  23. typename Tag = typename geometry::tag<Geometry>::type>
  24. class boundary_checker {};
  25. template <typename Geometry, typename WithinStrategy>
  26. class boundary_checker<Geometry, WithinStrategy, linestring_tag>
  27. {
  28. typedef typename point_type<Geometry>::type point_type;
  29. public:
  30. typedef WithinStrategy equals_strategy_type;
  31. boundary_checker(Geometry const& g)
  32. : has_boundary( boost::size(g) >= 2
  33. && !detail::equals::equals_point_point(range::front(g),
  34. range::back(g),
  35. equals_strategy_type()) )
  36. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  37. , geometry(g)
  38. #endif
  39. {}
  40. template <boundary_query BoundaryQuery>
  41. bool is_endpoint_boundary(point_type const& pt) const
  42. {
  43. boost::ignore_unused(pt);
  44. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  45. // may give false positives for INT
  46. BOOST_GEOMETRY_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
  47. && detail::equals::equals_point_point(pt, range::front(geometry), WithinStrategy())
  48. || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
  49. && detail::equals::equals_point_point(pt, range::back(geometry), WithinStrategy()) );
  50. #endif
  51. return has_boundary;
  52. }
  53. private:
  54. bool has_boundary;
  55. #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
  56. Geometry const& geometry;
  57. #endif
  58. };
  59. template <typename Geometry, typename WithinStrategy>
  60. class boundary_checker<Geometry, WithinStrategy, multi_linestring_tag>
  61. {
  62. typedef typename point_type<Geometry>::type point_type;
  63. public:
  64. typedef WithinStrategy equals_strategy_type;
  65. boundary_checker(Geometry const& g)
  66. : is_filled(false), geometry(g)
  67. {}
  68. // First call O(NlogN)
  69. // Each next call O(logN)
  70. template <boundary_query BoundaryQuery>
  71. bool is_endpoint_boundary(point_type const& pt) const
  72. {
  73. typedef geometry::less<point_type, -1, typename WithinStrategy::cs_tag> less_type;
  74. typedef typename boost::range_size<Geometry>::type size_type;
  75. size_type multi_count = boost::size(geometry);
  76. if ( multi_count < 1 )
  77. return false;
  78. if ( ! is_filled )
  79. {
  80. //boundary_points.clear();
  81. boundary_points.reserve(multi_count * 2);
  82. typedef typename boost::range_iterator<Geometry const>::type multi_iterator;
  83. for ( multi_iterator it = boost::begin(geometry) ;
  84. it != boost::end(geometry) ; ++ it )
  85. {
  86. typename boost::range_reference<Geometry const>::type
  87. ls = *it;
  88. // empty or point - no boundary
  89. if (boost::size(ls) < 2)
  90. {
  91. continue;
  92. }
  93. typedef typename boost::range_reference
  94. <
  95. typename boost::range_value<Geometry const>::type const
  96. >::type point_reference;
  97. point_reference front_pt = range::front(ls);
  98. point_reference back_pt = range::back(ls);
  99. // linear ring or point - no boundary
  100. if (! equals::equals_point_point(front_pt, back_pt, equals_strategy_type()))
  101. {
  102. // do not add points containing NaN coordinates
  103. // because they cannot be reasonably compared, e.g. with MSVC
  104. // an assertion failure is reported in std::equal_range()
  105. if (! geometry::has_nan_coordinate(front_pt))
  106. {
  107. boundary_points.push_back(front_pt);
  108. }
  109. if (! geometry::has_nan_coordinate(back_pt))
  110. {
  111. boundary_points.push_back(back_pt);
  112. }
  113. }
  114. }
  115. std::sort(boundary_points.begin(),
  116. boundary_points.end(),
  117. less_type());
  118. is_filled = true;
  119. }
  120. std::size_t equal_points_count
  121. = boost::size(
  122. std::equal_range(boundary_points.begin(),
  123. boundary_points.end(),
  124. pt,
  125. less_type())
  126. );
  127. return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
  128. }
  129. private:
  130. mutable bool is_filled;
  131. // TODO: store references/pointers instead of points?
  132. mutable std::vector<point_type> boundary_points;
  133. Geometry const& geometry;
  134. };
  135. }} // namespace detail::relate
  136. #endif // DOXYGEN_NO_DETAIL
  137. }} // namespace boost::geometry
  138. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP