1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 
7 // This file was modified by Oracle on 2013-2021.
8 // Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
13 
14 // Use, modification and distribution is subject to the Boost Software License,
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
16 // http://www.boost.org/LICENSE_1_0.txt)
17 
18 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
19 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
20 
21 
22 #include <boost/concept_check.hpp>
23 
24 #include <boost/variant/apply_visitor.hpp>
25 #include <boost/variant/static_visitor.hpp>
26 #include <boost/variant/variant_fwd.hpp>
27 
28 #include <boost/geometry/algorithms/not_implemented.hpp>
29 
30 #include <boost/geometry/core/tag.hpp>
31 #include <boost/geometry/core/tag_cast.hpp>
32 
33 #include <boost/geometry/geometries/concepts/check.hpp>
34 #include <boost/geometry/strategies/concepts/within_concept.hpp>
35 #include <boost/geometry/strategies/default_strategy.hpp>
36 #include <boost/geometry/strategies/detail.hpp>
37 #include <boost/geometry/strategies/relate/services.hpp>
38 
39 
40 namespace boost { namespace geometry
41 {
42 
43 #ifndef DOXYGEN_NO_DISPATCH
44 namespace dispatch
45 {
46 
47 template
48 <
49     typename Geometry1,
50     typename Geometry2,
51     typename Tag1 = typename tag<Geometry1>::type,
52     typename Tag2 = typename tag<Geometry2>::type
53 >
54 struct within
55     : not_implemented<Tag1, Tag2>
56 {};
57 
58 
59 } // namespace dispatch
60 #endif // DOXYGEN_NO_DISPATCH
61 
62 
63 namespace resolve_strategy
64 {
65 
66 template
67 <
68     typename Strategy,
69     bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
70 >
71 struct within
72 {
73     template <typename Geometry1, typename Geometry2>
applyboost::geometry::resolve_strategy::within74     static inline bool apply(Geometry1 const& geometry1,
75                              Geometry2 const& geometry2,
76                              Strategy const& strategy)
77     {
78         concepts::within::check<Geometry1, Geometry2, Strategy>();
79 
80         return dispatch::within
81             <
82                 Geometry1, Geometry2
83             >::apply(geometry1, geometry2, strategy);
84     }
85 };
86 
87 template <typename Strategy>
88 struct within<Strategy, false>
89 {
90     template <typename Geometry1, typename Geometry2>
applyboost::geometry::resolve_strategy::within91     static inline bool apply(Geometry1 const& geometry1,
92                              Geometry2 const& geometry2,
93                              Strategy const& strategy)
94     {
95         using strategies::relate::services::strategy_converter;
96 
97         return within
98             <
99                 decltype(strategy_converter<Strategy>::get(strategy))
100             >::apply(geometry1, geometry2,
101                      strategy_converter<Strategy>::get(strategy));
102     }
103 };
104 
105 template <>
106 struct within<default_strategy, false>
107 {
108     template <typename Geometry1, typename Geometry2>
applyboost::geometry::resolve_strategy::within109     static inline bool apply(Geometry1 const& geometry1,
110                              Geometry2 const& geometry2,
111                              default_strategy)
112     {
113         typedef typename strategies::relate::services::default_strategy
114             <
115                 Geometry1,
116                 Geometry2
117             >::type strategy_type;
118 
119         return within
120             <
121                 strategy_type
122             >::apply(geometry1, geometry2, strategy_type());
123     }
124 };
125 
126 } // namespace resolve_strategy
127 
128 
129 namespace resolve_variant
130 {
131 
132 template <typename Geometry1, typename Geometry2>
133 struct within
134 {
135     template <typename Strategy>
applyboost::geometry::resolve_variant::within136     static inline bool apply(Geometry1 const& geometry1,
137                              Geometry2 const& geometry2,
138                              Strategy const& strategy)
139     {
140         concepts::check<Geometry1 const>();
141         concepts::check<Geometry2 const>();
142         assert_dimension_equal<Geometry1, Geometry2>();
143 
144         return resolve_strategy::within
145             <
146                 Strategy
147             >::apply(geometry1, geometry2, strategy);
148     }
149 };
150 
151 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
152 struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
153 {
154     template <typename Strategy>
155     struct visitor: boost::static_visitor<bool>
156     {
157         Geometry2 const& m_geometry2;
158         Strategy const& m_strategy;
159 
visitorboost::geometry::resolve_variant::within::visitor160         visitor(Geometry2 const& geometry2, Strategy const& strategy)
161             : m_geometry2(geometry2)
162             , m_strategy(strategy)
163         {}
164 
165         template <typename Geometry1>
operator ()boost::geometry::resolve_variant::within::visitor166         bool operator()(Geometry1 const& geometry1) const
167         {
168             return within<Geometry1, Geometry2>::apply(geometry1,
169                                                        m_geometry2,
170                                                        m_strategy);
171         }
172     };
173 
174     template <typename Strategy>
175     static inline bool
applyboost::geometry::resolve_variant::within176     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
177           Geometry2 const& geometry2,
178           Strategy const& strategy)
179     {
180         return boost::apply_visitor(visitor<Strategy>(geometry2, strategy),
181                                     geometry1);
182     }
183 };
184 
185 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
186 struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
187 {
188     template <typename Strategy>
189     struct visitor: boost::static_visitor<bool>
190     {
191         Geometry1 const& m_geometry1;
192         Strategy const& m_strategy;
193 
visitorboost::geometry::resolve_variant::within::visitor194         visitor(Geometry1 const& geometry1, Strategy const& strategy)
195             : m_geometry1(geometry1)
196             , m_strategy(strategy)
197         {}
198 
199         template <typename Geometry2>
operator ()boost::geometry::resolve_variant::within::visitor200         bool operator()(Geometry2 const& geometry2) const
201         {
202             return within<Geometry1, Geometry2>::apply(m_geometry1,
203                                                        geometry2,
204                                                        m_strategy);
205         }
206     };
207 
208     template <typename Strategy>
209     static inline bool
applyboost::geometry::resolve_variant::within210     apply(Geometry1 const& geometry1,
211           boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
212           Strategy const& strategy)
213     {
214         return boost::apply_visitor(visitor<Strategy>(geometry1, strategy),
215                                     geometry2
216         );
217     }
218 };
219 
220 template <
221     BOOST_VARIANT_ENUM_PARAMS(typename T1),
222     BOOST_VARIANT_ENUM_PARAMS(typename T2)
223 >
224 struct within<
225     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
226     boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
227 >
228 {
229     template <typename Strategy>
230     struct visitor: boost::static_visitor<bool>
231     {
232         Strategy const& m_strategy;
233 
visitorboost::geometry::resolve_variant::within::visitor234         visitor(Strategy const& strategy): m_strategy(strategy) {}
235 
236         template <typename Geometry1, typename Geometry2>
operator ()boost::geometry::resolve_variant::within::visitor237         bool operator()(Geometry1 const& geometry1,
238                         Geometry2 const& geometry2) const
239         {
240             return within<Geometry1, Geometry2>::apply(geometry1,
241                                                        geometry2,
242                                                        m_strategy);
243         }
244     };
245 
246     template <typename Strategy>
247     static inline bool
applyboost::geometry::resolve_variant::within248     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
249           boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
250           Strategy const& strategy)
251     {
252         return boost::apply_visitor(visitor<Strategy>(strategy),
253                                     geometry1,
254                                     geometry2);
255     }
256 };
257 
258 }
259 
260 
261 /*!
262 \brief \brief_check12{is completely inside}
263 \ingroup within
264 \details \details_check12{within, is completely inside}.
265 \tparam Geometry1 \tparam_geometry
266 \tparam Geometry2 \tparam_geometry
267 \param geometry1 \param_geometry which might be within the second geometry
268 \param geometry2 \param_geometry which might contain the first geometry
269 \return true if geometry1 is completely contained within geometry2,
270     else false
271 \note The default strategy is used for within detection
272 
273 
274 \qbk{[include reference/algorithms/within.qbk]}
275 
276 \qbk{
277 [heading Example]
278 [within]
279 [within_output]
280 }
281  */
282 template<typename Geometry1, typename Geometry2>
within(Geometry1 const & geometry1,Geometry2 const & geometry2)283 inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
284 {
285     return resolve_variant::within
286         <
287             Geometry1,
288             Geometry2
289         >::apply(geometry1, geometry2, default_strategy());
290 }
291 
292 /*!
293 \brief \brief_check12{is completely inside} \brief_strategy
294 \ingroup within
295 \details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons
296 \tparam Geometry1 \tparam_geometry
297 \tparam Geometry2 \tparam_geometry
298 \param geometry1 \param_geometry which might be within the second geometry
299 \param geometry2 \param_geometry which might contain the first geometry
300 \param strategy strategy to be used
301 \return true if geometry1 is completely contained within geometry2,
302     else false
303 
304 \qbk{distinguish,with strategy}
305 \qbk{[include reference/algorithms/within.qbk]}
306 \qbk{
307 [heading Available Strategies]
308 \* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)]
309 \* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)]
310 \* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)]
311 
312 [heading Example]
313 [within_strategy]
314 [within_strategy_output]
315 
316 }
317 */
318 template<typename Geometry1, typename Geometry2, typename Strategy>
within(Geometry1 const & geometry1,Geometry2 const & geometry2,Strategy const & strategy)319 inline bool within(Geometry1 const& geometry1,
320                    Geometry2 const& geometry2,
321                    Strategy const& strategy)
322 {
323     return resolve_variant::within
324         <
325             Geometry1,
326             Geometry2
327         >::apply(geometry1, geometry2, strategy);
328 }
329 
330 }} // namespace boost::geometry
331 
332 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
333