• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Boost.Geometry (aka GGL, Generic Geometry Library)
2  
3  // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
4  
5  // This file was modified by Oracle on 2017, 2018.
6  // Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
7  
8  // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9  
10  // Use, modification and distribution is subject to the Boost Software License,
11  // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12  // http://www.boost.org/LICENSE_1_0.txt)
13  
14  #ifndef BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
15  #define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
16  
17  
18  #include <boost/variant/apply_visitor.hpp>
19  #include <boost/variant/static_visitor.hpp>
20  #include <boost/variant/variant_fwd.hpp>
21  
22  #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
23  #include <boost/geometry/core/access.hpp>
24  #include <boost/geometry/core/closure.hpp>
25  #include <boost/geometry/core/cs.hpp>
26  #include <boost/geometry/core/coordinate_dimension.hpp>
27  #include <boost/geometry/core/point_type.hpp>
28  #include <boost/geometry/geometries/concepts/check.hpp>
29  #include <boost/geometry/iterators/ever_circling_iterator.hpp>
30  #include <boost/geometry/strategies/default_strategy.hpp>
31  #include <boost/geometry/strategies/side.hpp>
32  #include <boost/geometry/views/detail/normalized_view.hpp>
33  
34  
35  namespace boost { namespace geometry
36  {
37  
38  
39  #ifndef DOXYGEN_NO_DETAIL
40  namespace detail { namespace is_convex
41  {
42  
43  struct ring_is_convex
44  {
45      template <typename Ring, typename SideStrategy>
applyboost::geometry::detail::is_convex::ring_is_convex46      static inline bool apply(Ring const& ring, SideStrategy const& strategy)
47      {
48          typename SideStrategy::equals_point_point_strategy_type
49              eq_pp_strategy = strategy.get_equals_point_point_strategy();
50  
51          std::size_t n = boost::size(ring);
52          if (boost::size(ring) < core_detail::closure::minimum_ring_size
53                                      <
54                                          geometry::closure<Ring>::value
55                                      >::value)
56          {
57              // (Too) small rings are considered as non-concave, is convex
58              return true;
59          }
60  
61          // Walk in clockwise direction, consider ring as closed
62          // (though closure is not important in this algorithm - any dupped
63          //  point is skipped)
64          typedef detail::normalized_view<Ring const> view_type;
65          view_type view(ring);
66  
67          typedef geometry::ever_circling_range_iterator<view_type const> it_type;
68          it_type previous(view);
69          it_type current(view);
70          current++;
71  
72          std::size_t index = 1;
73          while (equals::equals_point_point(*current, *previous, eq_pp_strategy)
74              && index < n)
75          {
76              current++;
77              index++;
78          }
79  
80          if (index == n)
81          {
82              // All points are apparently equal
83              return true;
84          }
85  
86          it_type next = current;
87          next++;
88          while (equals::equals_point_point(*current, *next, eq_pp_strategy))
89          {
90              next++;
91          }
92  
93          // We have now three different points on the ring
94          // Walk through all points, use a counter because of the ever-circling
95          // iterator
96          for (std::size_t i = 0; i < n; i++)
97          {
98              int const side = strategy.apply(*previous, *current, *next);
99              if (side == 1)
100              {
101                  // Next is on the left side of clockwise ring:
102                  // the piece is not convex
103                  return false;
104              }
105  
106              previous = current;
107              current = next;
108  
109              // Advance next to next different point
110              // (because there are non-equal points, this loop is not infinite)
111              next++;
112              while (equals::equals_point_point(*current, *next, eq_pp_strategy))
113              {
114                  next++;
115              }
116          }
117          return true;
118      }
119  };
120  
121  
122  }} // namespace detail::is_convex
123  #endif // DOXYGEN_NO_DETAIL
124  
125  
126  #ifndef DOXYGEN_NO_DISPATCH
127  namespace dispatch
128  {
129  
130  template
131  <
132      typename Geometry,
133      typename Tag = typename tag<Geometry>::type
134  >
135  struct is_convex : not_implemented<Tag>
136  {};
137  
138  template <typename Box>
139  struct is_convex<Box, box_tag>
140  {
141      template <typename Strategy>
applyboost::geometry::dispatch::is_convex142      static inline bool apply(Box const& , Strategy const& )
143      {
144          // Any box is convex (TODO: consider spherical boxes)
145          return true;
146      }
147  };
148  
149  template <typename Box>
150  struct is_convex<Box, ring_tag> : detail::is_convex::ring_is_convex
151  {};
152  
153  
154  } // namespace dispatch
155  #endif // DOXYGEN_NO_DISPATCH
156  
157  namespace resolve_variant {
158  
159  template <typename Geometry>
160  struct is_convex
161  {
162      template <typename Strategy>
applyboost::geometry::resolve_variant::is_convex163      static bool apply(Geometry const& geometry, Strategy const& strategy)
164      {
165          concepts::check<Geometry>();
166          return dispatch::is_convex<Geometry>::apply(geometry, strategy);
167      }
168  
applyboost::geometry::resolve_variant::is_convex169      static bool apply(Geometry const& geometry, geometry::default_strategy const&)
170      {
171          typedef typename strategy::side::services::default_strategy
172              <
173                  typename cs_tag<Geometry>::type
174              >::type side_strategy;
175  
176          return apply(geometry, side_strategy());
177      }
178  };
179  
180  template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
181  struct is_convex<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
182  {
183      template <typename Strategy>
184      struct visitor: boost::static_visitor<bool>
185      {
186          Strategy const& m_strategy;
187  
visitorboost::geometry::resolve_variant::is_convex::visitor188          visitor(Strategy const& strategy) : m_strategy(strategy) {}
189  
190          template <typename Geometry>
operator ()boost::geometry::resolve_variant::is_convex::visitor191          bool operator()(Geometry const& geometry) const
192          {
193              return is_convex<Geometry>::apply(geometry, m_strategy);
194          }
195      };
196  
197      template <typename Strategy>
applyboost::geometry::resolve_variant::is_convex198      static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
199                               Strategy const& strategy)
200      {
201          return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
202      }
203  };
204  
205  } // namespace resolve_variant
206  
207  // TODO: documentation / qbk
208  template<typename Geometry>
is_convex(Geometry const & geometry)209  inline bool is_convex(Geometry const& geometry)
210  {
211      return resolve_variant::is_convex
212              <
213                  Geometry
214              >::apply(geometry, geometry::default_strategy());
215  }
216  
217  // TODO: documentation / qbk
218  template<typename Geometry, typename Strategy>
is_convex(Geometry const & geometry,Strategy const & strategy)219  inline bool is_convex(Geometry const& geometry, Strategy const& strategy)
220  {
221      return resolve_variant::is_convex<Geometry>::apply(geometry, strategy);
222  }
223  
224  
225  }} // namespace boost::geometry
226  
227  
228  #endif // BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
229