1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2015, Oracle and/or its affiliates.
4 
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_ALGORITHMS_IS_EMPTY_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_IS_EMPTY_HPP
12 
13 #include <boost/range.hpp>
14 
15 #include <boost/variant/apply_visitor.hpp>
16 #include <boost/variant/static_visitor.hpp>
17 #include <boost/variant/variant_fwd.hpp>
18 
19 #include <boost/geometry/core/exterior_ring.hpp>
20 #include <boost/geometry/core/interior_rings.hpp>
21 #include <boost/geometry/core/tag.hpp>
22 #include <boost/geometry/core/tags.hpp>
23 
24 #include <boost/geometry/algorithms/not_implemented.hpp>
25 
26 #include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
27 
28 #include <boost/geometry/geometries/concepts/check.hpp>
29 
30 
31 namespace boost { namespace geometry
32 {
33 
34 
35 #ifndef DOXYGEN_NO_DETAIL
36 namespace detail { namespace is_empty
37 {
38 
39 struct always_not_empty
40 {
41     template <typename Geometry>
applyboost::geometry::detail::is_empty::always_not_empty42     static inline bool apply(Geometry const&)
43     {
44         return false;
45     }
46 };
47 
48 struct range_is_empty
49 {
50     template <typename Range>
applyboost::geometry::detail::is_empty::range_is_empty51     static inline bool apply(Range const& range)
52     {
53         return boost::empty(range);
54     }
55 };
56 
57 class polygon_is_empty
58 {
59     template <typename InteriorRings>
check_interior_rings(InteriorRings const & interior_rings)60     static inline bool check_interior_rings(InteriorRings const& interior_rings)
61     {
62         return check_iterator_range
63             <
64                 range_is_empty, true // allow empty range
65             >::apply(boost::begin(interior_rings), boost::end(interior_rings));
66     }
67 
68 public:
69     template <typename Polygon>
apply(Polygon const & polygon)70     static inline bool apply(Polygon const& polygon)
71     {
72         return boost::empty(exterior_ring(polygon))
73             && check_interior_rings(interior_rings(polygon));
74     }
75 };
76 
77 template <typename Policy = range_is_empty>
78 struct multi_is_empty
79 {
80     template <typename MultiGeometry>
applyboost::geometry::detail::is_empty::multi_is_empty81     static inline bool apply(MultiGeometry const& multigeometry)
82     {
83         return check_iterator_range
84             <
85                 Policy, true // allow empty range
86             >::apply(boost::begin(multigeometry), boost::end(multigeometry));
87     }
88 
89 };
90 
91 }} // namespace detail::is_empty
92 #endif // DOXYGEN_NO_DETAIL
93 
94 
95 #ifndef DOXYGEN_NO_DISPATCH
96 namespace dispatch
97 {
98 
99 template <typename Geometry, typename Tag =  typename tag<Geometry>::type>
100 struct is_empty : not_implemented<Tag>
101 {};
102 
103 template <typename Geometry>
104 struct is_empty<Geometry, point_tag>
105     : detail::is_empty::always_not_empty
106 {};
107 
108 template <typename Geometry>
109 struct is_empty<Geometry, box_tag>
110     : detail::is_empty::always_not_empty
111 {};
112 
113 template <typename Geometry>
114 struct is_empty<Geometry, segment_tag>
115     : detail::is_empty::always_not_empty
116 {};
117 
118 template <typename Geometry>
119 struct is_empty<Geometry, linestring_tag>
120     : detail::is_empty::range_is_empty
121 {};
122 
123 template <typename Geometry>
124 struct is_empty<Geometry, ring_tag>
125     : detail::is_empty::range_is_empty
126 {};
127 
128 template <typename Geometry>
129 struct is_empty<Geometry, polygon_tag>
130     : detail::is_empty::polygon_is_empty
131 {};
132 
133 template <typename Geometry>
134 struct is_empty<Geometry, multi_point_tag>
135     : detail::is_empty::range_is_empty
136 {};
137 
138 template <typename Geometry>
139 struct is_empty<Geometry, multi_linestring_tag>
140     : detail::is_empty::multi_is_empty<>
141 {};
142 
143 template <typename Geometry>
144 struct is_empty<Geometry, multi_polygon_tag>
145     : detail::is_empty::multi_is_empty<detail::is_empty::polygon_is_empty>
146 {};
147 
148 } // namespace dispatch
149 #endif // DOXYGEN_NO_DISPATCH
150 
151 
152 namespace resolve_variant
153 {
154 
155 template <typename Geometry>
156 struct is_empty
157 {
applyboost::geometry::resolve_variant::is_empty158     static inline bool apply(Geometry const& geometry)
159     {
160         concepts::check<Geometry const>();
161 
162         return dispatch::is_empty<Geometry>::apply(geometry);
163     }
164 };
165 
166 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
167 struct is_empty<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
168 {
169     struct visitor : boost::static_visitor<bool>
170     {
171         template <typename Geometry>
operator ()boost::geometry::resolve_variant::is_empty::visitor172         inline bool operator()(Geometry const& geometry) const
173         {
174             return is_empty<Geometry>::apply(geometry);
175         }
176     };
177 
178     static bool
applyboost::geometry::resolve_variant::is_empty179     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
180     {
181         return boost::apply_visitor(visitor(), geometry);
182     }
183 };
184 
185 } // namespace resolve_variant
186 
187 
188 /*!
189 \brief \brief_check{is the empty set}
190 \ingroup is_empty
191 \tparam Geometry \tparam_geometry
192 \param geometry \param_geometry
193 \return \return_check{is the empty set}
194 
195 \qbk{[include reference/algorithms/is_empty.qbk]}
196 */
197 template <typename Geometry>
is_empty(Geometry const & geometry)198 inline bool is_empty(Geometry const& geometry)
199 {
200     return resolve_variant::is_empty<Geometry>::apply(geometry);
201 }
202 
203 
204 }} // namespace boost::geometry
205 
206 
207 #endif // BOOST_GEOMETRY_ALGORITHMS_IS_EMPTY_HPP
208