1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 
5 // This file was modified by Oracle on 2013, 2014, 2015.
6 // Modifications copyright (c) 2013-2015 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_DETAIL_RELATE_INTERFACE_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP
16 
17 
18 #include <boost/type_traits/is_same.hpp>
19 #include <boost/variant/apply_visitor.hpp>
20 #include <boost/variant/static_visitor.hpp>
21 #include <boost/variant/variant_fwd.hpp>
22 
23 #include <boost/geometry/core/coordinate_dimension.hpp>
24 #include <boost/geometry/core/tag.hpp>
25 #include <boost/geometry/core/tags.hpp>
26 #include <boost/geometry/core/topological_dimension.hpp>
27 
28 #include <boost/geometry/algorithms/detail/relate/de9im.hpp>
29 #include <boost/geometry/algorithms/not_implemented.hpp>
30 #include <boost/geometry/geometries/concepts/check.hpp>
31 #include <boost/geometry/strategies/default_strategy.hpp>
32 
33 
34 namespace boost { namespace geometry {
35 
36 
37 #ifndef DOXYGEN_NO_DETAIL
38 namespace detail { namespace relate {
39 
40 // Those are used only to allow dispatch::relate to produce compile-time error
41 
42 template <typename Geometry,
43           typename Tag = typename geometry::tag<Geometry>::type>
44 struct is_supported_by_generic
45 {
46     static const bool value
47         = boost::is_same<Tag, linestring_tag>::value
48        || boost::is_same<Tag, multi_linestring_tag>::value
49        || boost::is_same<Tag, ring_tag>::value
50        || boost::is_same<Tag, polygon_tag>::value
51        || boost::is_same<Tag, multi_polygon_tag>::value;
52 };
53 
54 template <typename Geometry1,
55           typename Geometry2,
56           typename Tag1 = typename geometry::tag<Geometry1>::type,
57           typename Tag2 = typename geometry::tag<Geometry2>::type>
58 struct is_generic
59 {
60     static const bool value = is_supported_by_generic<Geometry1>::value
61                            && is_supported_by_generic<Geometry2>::value;
62 };
63 
64 
65 template <typename Point, typename Geometry, typename Tag>
66 struct is_generic<Point, Geometry, point_tag, Tag>
67 {
68     static const bool value = is_supported_by_generic<Geometry>::value;
69 };
70 
71 template <typename Geometry, typename Point, typename Tag>
72 struct is_generic<Geometry, Point, Tag, point_tag>
73 {
74     static const bool value = is_supported_by_generic<Geometry>::value;
75 };
76 
77 template <typename Point1, typename Point2>
78 struct is_generic<Point1, Point2, point_tag, point_tag>
79 {
80     static const bool value = false;
81 };
82 
83 
84 }} // namespace detail::relate
85 #endif // DOXYGEN_NO_DETAIL
86 
87 
88 #ifndef DOXYGEN_NO_DISPATCH
89 namespace dispatch {
90 
91 
92 template <typename Geometry1,
93           typename Geometry2,
94           typename Tag1 = typename geometry::tag<Geometry1>::type,
95           typename Tag2 = typename geometry::tag<Geometry2>::type,
96           int TopDim1 = geometry::topological_dimension<Geometry1>::value,
97           int TopDim2 = geometry::topological_dimension<Geometry2>::value,
98           bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value
99 >
100 struct relate : not_implemented<Tag1, Tag2>
101 {};
102 
103 } // namespace dispatch
104 #endif // DOXYGEN_NO_DISPATCH
105 
106 #ifndef DOXYGEN_NO_DETAIL
107 namespace detail { namespace relate {
108 
109 template <typename Geometry1, typename Geometry2>
110 struct interruption_enabled
111 {
112     static const bool value =
113         dispatch::relate<Geometry1, Geometry2>::interruption_enabled;
114 };
115 
116 template <typename Geometry1,
117           typename Geometry2,
118           typename Result,
119           bool IsSequence = boost::mpl::is_sequence<Result>::value>
120 struct result_handler_type
121     : not_implemented<Result>
122 {};
123 
124 template <typename Geometry1, typename Geometry2>
125 struct result_handler_type<Geometry1, Geometry2, geometry::de9im::mask, false>
126 {
127     typedef mask_handler
128         <
129             geometry::de9im::mask,
130             interruption_enabled
131                 <
132                     Geometry1,
133                     Geometry2
134                 >::value
135         > type;
136 };
137 
138 template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
139 struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false>
140 {
141     typedef mask_handler
142         <
143             boost::tuples::cons<Head, Tail>,
144             interruption_enabled
145                 <
146                     Geometry1,
147                     Geometry2
148                 >::value
149         > type;
150 };
151 
152 template <typename Geometry1, typename Geometry2,
153           char II, char IB, char IE,
154           char BI, char BB, char BE,
155           char EI, char EB, char EE>
156 struct result_handler_type
157     <
158         Geometry1,
159         Geometry2,
160         geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
161         false
162     >
163 {
164     typedef static_mask_handler
165         <
166             geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
167             interruption_enabled
168                 <
169                     Geometry1,
170                     Geometry2
171                 >::value
172         > type;
173 };
174 
175 template <typename Geometry1, typename Geometry2, typename StaticSequence>
176 struct result_handler_type<Geometry1, Geometry2, StaticSequence, true>
177 {
178     typedef static_mask_handler
179         <
180             StaticSequence,
181             interruption_enabled
182                 <
183                     Geometry1,
184                     Geometry2
185                 >::value
186         > type;
187 };
188 
189 }} // namespace detail::relate
190 #endif // DOXYGEN_NO_DETAIL
191 
192 namespace resolve_variant {
193 
194 template <typename Geometry1, typename Geometry2>
195 struct relate
196 {
197     template <typename Mask>
applyboost::geometry::resolve_variant::relate198     static inline bool apply(Geometry1 const& geometry1,
199                              Geometry2 const& geometry2,
200                              Mask const& mask)
201     {
202         concepts::check<Geometry1 const>();
203         concepts::check<Geometry2 const>();
204         assert_dimension_equal<Geometry1, Geometry2>();
205 
206         typename detail::relate::result_handler_type
207             <
208                 Geometry1,
209                 Geometry2,
210                 Mask
211             >::type handler(mask);
212 
213         dispatch::relate
214             <
215                 Geometry1,
216                 Geometry2
217             >::apply(geometry1, geometry2, handler);
218 
219         return handler.result();
220     }
221 };
222 
223 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
224 struct relate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
225 {
226     template <typename Mask>
227     struct visitor : boost::static_visitor<bool>
228     {
229         Geometry2 const& m_geometry2;
230         Mask const& m_mask;
231 
visitorboost::geometry::resolve_variant::relate::visitor232         visitor(Geometry2 const& geometry2, Mask const& mask)
233             : m_geometry2(geometry2), m_mask(mask) {}
234 
235         template <typename Geometry1>
operator ()boost::geometry::resolve_variant::relate::visitor236         bool operator()(Geometry1 const& geometry1) const
237         {
238             return relate<Geometry1, Geometry2>
239                    ::apply(geometry1, m_geometry2, m_mask);
240         }
241     };
242 
243     template <typename Mask>
244     static inline bool
applyboost::geometry::resolve_variant::relate245     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
246           Geometry2 const& geometry2,
247           Mask const& mask)
248     {
249         return boost::apply_visitor(visitor<Mask>(geometry2, mask), geometry1);
250     }
251 };
252 
253 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
254 struct relate<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
255 {
256     template <typename Mask>
257     struct visitor : boost::static_visitor<bool>
258     {
259         Geometry1 const& m_geometry1;
260         Mask const& m_mask;
261 
visitorboost::geometry::resolve_variant::relate::visitor262         visitor(Geometry1 const& geometry1, Mask const& mask)
263             : m_geometry1(geometry1), m_mask(mask) {}
264 
265         template <typename Geometry2>
operator ()boost::geometry::resolve_variant::relate::visitor266         bool operator()(Geometry2 const& geometry2) const
267         {
268             return relate<Geometry1, Geometry2>
269                    ::apply(m_geometry1, geometry2, m_mask);
270         }
271     };
272 
273     template <typename Mask>
274     static inline bool
applyboost::geometry::resolve_variant::relate275     apply(Geometry1 const& geometry1,
276           boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
277           Mask const& mask)
278     {
279         return boost::apply_visitor(visitor<Mask>(geometry1, mask), geometry2);
280     }
281 };
282 
283 template <
284     BOOST_VARIANT_ENUM_PARAMS(typename T1),
285     BOOST_VARIANT_ENUM_PARAMS(typename T2)
286 >
287 struct relate<
288     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
289     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
290 >
291 {
292     template <typename Mask>
293     struct visitor : boost::static_visitor<bool>
294     {
295         Mask const& m_mask;
296 
visitorboost::geometry::resolve_variant::relate::visitor297         visitor(Mask const& mask)
298             : m_mask(mask) {}
299 
300         template <typename Geometry1, typename Geometry2>
operator ()boost::geometry::resolve_variant::relate::visitor301         bool operator()(Geometry1 const& geometry1,
302                         Geometry2 const& geometry2) const
303         {
304             return relate<Geometry1, Geometry2>
305                    ::apply(geometry1, geometry2, m_mask);
306         }
307     };
308 
309     template <typename Mask>
310     static inline bool
applyboost::geometry::resolve_variant::relate311     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
312           boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
313           Mask const& mask)
314     {
315         return boost::apply_visitor(visitor<Mask>(mask), geometry1, geometry2);
316     }
317 };
318 
319 } // namespace resolve_variant
320 
321 /*!
322 \brief Checks relation between a pair of geometries defined by a mask.
323 \ingroup relate
324 \tparam Geometry1 \tparam_geometry
325 \tparam Geometry2 \tparam_geometry
326 \tparam Mask An intersection model Mask type.
327 \param geometry1 \param_geometry
328 \param geometry2 \param_geometry
329 \param mask An intersection model mask object.
330 \return true if the relation is compatible with the mask, false otherwise.
331 
332 \qbk{[include reference/algorithms/relate.qbk]}
333  */
334 template <typename Geometry1, typename Geometry2, typename Mask>
relate(Geometry1 const & geometry1,Geometry2 const & geometry2,Mask const & mask)335 inline bool relate(Geometry1 const& geometry1,
336                    Geometry2 const& geometry2,
337                    Mask const& mask)
338 {
339     return resolve_variant::relate
340             <
341                 Geometry1,
342                 Geometry2
343             >::apply(geometry1, geometry2, mask);
344 }
345 
346 }} // namespace boost::geometry
347 
348 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP
349