1 // Boost.Geometry
2 
3 // Copyright (c) 2020, Oracle and/or its affiliates.
4 
5 // Contributed and/or modified by Adam Wulkiewicz, 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_STRATEGIES_RELATE_CARTESIAN_HPP
11 #define BOOST_GEOMETRY_STRATEGIES_RELATE_CARTESIAN_HPP
12 
13 
14 // TEMP - move to strategy
15 #include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp>
16 #include <boost/geometry/strategies/cartesian/intersection.hpp>
17 #include <boost/geometry/strategies/cartesian/box_in_box.hpp>
18 #include <boost/geometry/strategies/cartesian/point_in_point.hpp>
19 #include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
20 #include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>
21 #include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
22 #include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
23 
24 #include <boost/geometry/strategies/envelope/cartesian.hpp>
25 #include <boost/geometry/strategies/relate/services.hpp>
26 #include <boost/geometry/strategies/detail.hpp>
27 
28 #include <boost/geometry/strategy/cartesian/area.hpp>
29 #include <boost/geometry/strategy/cartesian/side_robust.hpp>
30 #include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
31 #include <boost/geometry/strategy/cartesian/area_box.hpp>
32 
33 #include <boost/geometry/util/type_traits.hpp>
34 
35 
36 namespace boost { namespace geometry
37 {
38 
39 namespace strategies { namespace relate
40 {
41 
42 template <typename CalculationType = void>
43 class cartesian
44     : public strategies::envelope::cartesian<CalculationType>
45 {
46 public:
47     //area
48 
49     template <typename Geometry>
area(Geometry const &,std::enable_if_t<!util::is_box<Geometry>::value> * =nullptr)50     static auto area(Geometry const&,
51                      std::enable_if_t<! util::is_box<Geometry>::value> * = nullptr)
52     {
53         return strategy::area::cartesian<CalculationType>();
54     }
55 
56     template <typename Geometry>
area(Geometry const &,std::enable_if_t<util::is_box<Geometry>::value> * =nullptr)57     static auto area(Geometry const&,
58                      std::enable_if_t<util::is_box<Geometry>::value> * = nullptr)
59     {
60         return strategy::area::cartesian_box<CalculationType>();
61     }
62 
63     // covered_by
64 
65     template <typename Geometry1, typename Geometry2>
covered_by(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_pointlike<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)66     static auto covered_by(Geometry1 const&, Geometry2 const&,
67                            std::enable_if_t
68                                 <
69                                     util::is_pointlike<Geometry1>::value
70                                  && util::is_box<Geometry2>::value
71                                 > * = nullptr)
72     {
73         return strategy::covered_by::cartesian_point_box();
74     }
75 
76     template <typename Geometry1, typename Geometry2>
covered_by(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_box<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)77     static auto covered_by(Geometry1 const&, Geometry2 const&,
78                            std::enable_if_t
79                             <
80                                 util::is_box<Geometry1>::value
81                              && util::is_box<Geometry2>::value
82                             > * = nullptr)
83     {
84         return strategy::covered_by::cartesian_box_box();
85     }
86 
87     // disjoint
88 
89     template <typename Geometry1, typename Geometry2>
disjoint(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_box<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)90     static auto disjoint(Geometry1 const&, Geometry2 const&,
91                          std::enable_if_t
92                             <
93                                 util::is_box<Geometry1>::value
94                              && util::is_box<Geometry2>::value
95                             > * = nullptr)
96     {
97         return strategy::disjoint::cartesian_box_box();
98     }
99 
100     template <typename Geometry1, typename Geometry2>
disjoint(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_segment<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)101     static auto disjoint(Geometry1 const&, Geometry2 const&,
102                          std::enable_if_t
103                             <
104                                 util::is_segment<Geometry1>::value
105                              && util::is_box<Geometry2>::value
106                             > * = nullptr)
107     {
108         // NOTE: Inconsistent name.
109         return strategy::disjoint::segment_box();
110     }
111 
112     // relate
113 
114     template <typename Geometry1, typename Geometry2>
relate(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_pointlike<Geometry1>::value && util::is_pointlike<Geometry2>::value> * =nullptr)115     static auto relate(Geometry1 const&, Geometry2 const&,
116                        std::enable_if_t
117                             <
118                                 util::is_pointlike<Geometry1>::value
119                              && util::is_pointlike<Geometry2>::value
120                             > * = nullptr)
121     {
122         return strategy::within::cartesian_point_point();
123     }
124 
125     template <typename Geometry1, typename Geometry2>
relate(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_pointlike<Geometry1>::value && (util::is_linear<Geometry2>::value||util::is_polygonal<Geometry2>::value)> * =nullptr)126     static auto relate(Geometry1 const&, Geometry2 const&,
127                        std::enable_if_t
128                             <
129                                 util::is_pointlike<Geometry1>::value
130                              && ( util::is_linear<Geometry2>::value
131                                || util::is_polygonal<Geometry2>::value )
132                             > * = nullptr)
133     {
134         return strategy::within::cartesian_winding<void, void, CalculationType>();
135     }
136 
137     // The problem is that this strategy is often used with non-geometry ranges.
138     // So dispatching only by geometry categories is impossible.
139     // In the past it was taking two segments, now it takes 3-point sub-ranges.
140     // So dispatching by segments is impossible.
141     // It could be dispatched by (linear || polygonal || non-geometry point range).
142     // For now implement as 0-parameter, special case relate.
143 
144     //template <typename Geometry1, typename Geometry2>
relate()145     static auto relate(/*Geometry1 const&, Geometry2 const&,
146                        std::enable_if_t
147                             <
148                                 ( util::is_linear<Geometry1>::value
149                                || util::is_polygonal<Geometry1>::value )
150                              && ( util::is_linear<Geometry2>::value
151                                || util::is_polygonal<Geometry2>::value )
152                             > * = nullptr*/)
153     {
154         return strategy::intersection::cartesian_segments<CalculationType>();
155     }
156 
157     // side
158 
side()159     static auto side()
160     {
161         using side_strategy_type
162             = typename strategy::side::services::default_strategy
163                 <cartesian_tag, CalculationType>::type;
164         return side_strategy_type();
165     }
166 
167     // within
168 
169     template <typename Geometry1, typename Geometry2>
within(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_pointlike<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)170     static auto within(Geometry1 const&, Geometry2 const&,
171                        std::enable_if_t
172                             <
173                                 util::is_pointlike<Geometry1>::value
174                                 && util::is_box<Geometry2>::value
175                             > * = nullptr)
176     {
177         return strategy::within::cartesian_point_box();
178     }
179 
180     template <typename Geometry1, typename Geometry2>
within(Geometry1 const &,Geometry2 const &,std::enable_if_t<util::is_box<Geometry1>::value && util::is_box<Geometry2>::value> * =nullptr)181     static auto within(Geometry1 const&, Geometry2 const&,
182                        std::enable_if_t
183                             <
184                                 util::is_box<Geometry1>::value
185                              && util::is_box<Geometry2>::value
186                             > * = nullptr)
187     {
188         return strategy::within::cartesian_box_box();
189     }
190 };
191 
192 
193 namespace services
194 {
195 
196 template <typename Geometry1, typename Geometry2>
197 struct default_strategy<Geometry1, Geometry2, cartesian_tag, cartesian_tag>
198 {
199     using type = strategies::relate::cartesian<>;
200 };
201 
202 
203 template <>
204 struct strategy_converter<strategy::within::cartesian_point_point>
205 {
getboost::geometry::strategies::relate::services::strategy_converter206     static auto get(strategy::within::cartesian_point_point const& )
207     {
208         return strategies::relate::cartesian<>();
209     }
210 };
211 
212 template <>
213 struct strategy_converter<strategy::within::cartesian_point_box>
214 {
getboost::geometry::strategies::relate::services::strategy_converter215     static auto get(strategy::within::cartesian_point_box const&)
216     {
217         return strategies::relate::cartesian<>();
218     }
219 };
220 
221 template <>
222 struct strategy_converter<strategy::covered_by::cartesian_point_box>
223 {
getboost::geometry::strategies::relate::services::strategy_converter224     static auto get(strategy::covered_by::cartesian_point_box const&)
225     {
226         return strategies::relate::cartesian<>();
227     }
228 };
229 
230 template <>
231 struct strategy_converter<strategy::covered_by::cartesian_box_box>
232 {
getboost::geometry::strategies::relate::services::strategy_converter233     static auto get(strategy::covered_by::cartesian_box_box const&)
234     {
235         return strategies::relate::cartesian<>();
236     }
237 };
238 
239 template <>
240 struct strategy_converter<strategy::disjoint::cartesian_box_box>
241 {
getboost::geometry::strategies::relate::services::strategy_converter242     static auto get(strategy::disjoint::cartesian_box_box const&)
243     {
244         return strategies::relate::cartesian<>();
245     }
246 };
247 
248 template <>
249 struct strategy_converter<strategy::disjoint::segment_box>
250 {
getboost::geometry::strategies::relate::services::strategy_converter251     static auto get(strategy::disjoint::segment_box const&)
252     {
253         return strategies::relate::cartesian<>();
254     }
255 };
256 
257 template <>
258 struct strategy_converter<strategy::within::cartesian_box_box>
259 {
getboost::geometry::strategies::relate::services::strategy_converter260     static auto get(strategy::within::cartesian_box_box const&)
261     {
262         return strategies::relate::cartesian<>();
263     }
264 };
265 
266 template <typename P1, typename P2, typename CalculationType>
267 struct strategy_converter<strategy::within::cartesian_winding<P1, P2, CalculationType>>
268 {
getboost::geometry::strategies::relate::services::strategy_converter269     static auto get(strategy::within::cartesian_winding<P1, P2, CalculationType> const& )
270     {
271         return strategies::relate::cartesian<CalculationType>();
272     }
273 };
274 
275 template <typename CalculationType>
276 struct strategy_converter<strategy::intersection::cartesian_segments<CalculationType>>
277 {
getboost::geometry::strategies::relate::services::strategy_converter278     static auto get(strategy::intersection::cartesian_segments<CalculationType> const& )
279     {
280         return strategies::relate::cartesian<CalculationType>();
281     }
282 };
283 
284 template <typename CalculationType>
285 struct strategy_converter<strategy::within::cartesian_point_box_by_side<CalculationType>>
286 {
287     struct altered_strategy
288         : strategies::relate::cartesian<CalculationType>
289     {
290         template <typename Geometry1, typename Geometry2>
covered_byboost::geometry::strategies::relate::services::strategy_converter::altered_strategy291         static auto covered_by(Geometry1 const&, Geometry2 const&,
292                                std::enable_if_t
293                                     <
294                                         util::is_pointlike<Geometry1>::value
295                                      && util::is_box<Geometry2>::value
296                                     > * = nullptr)
297         {
298             return strategy::covered_by::cartesian_point_box_by_side<CalculationType>();
299         }
300 
301         template <typename Geometry1, typename Geometry2>
withinboost::geometry::strategies::relate::services::strategy_converter::altered_strategy302         static auto within(Geometry1 const&, Geometry2 const&,
303                            std::enable_if_t
304                                 <
305                                     util::is_pointlike<Geometry1>::value
306                                     && util::is_box<Geometry2>::value
307                                 > * = nullptr)
308         {
309             return strategy::within::cartesian_point_box_by_side<CalculationType>();
310         }
311     };
312 
getboost::geometry::strategies::relate::services::strategy_converter313     static auto get(strategy::covered_by::cartesian_point_box_by_side<CalculationType> const&)
314     {
315         return altered_strategy();
316     }
317 
getboost::geometry::strategies::relate::services::strategy_converter318     static auto get(strategy::within::cartesian_point_box_by_side<CalculationType> const&)
319     {
320         return altered_strategy();
321     }
322 };
323 
324 template <typename CalculationType>
325 struct strategy_converter<strategy::covered_by::cartesian_point_box_by_side<CalculationType>>
326     : strategy_converter<strategy::within::cartesian_point_box_by_side<CalculationType>>
327 {};
328 
329 template <typename P1, typename P2, typename CalculationType>
330 struct strategy_converter<strategy::within::franklin<P1, P2, CalculationType>>
331 {
332     struct altered_strategy
333         : strategies::relate::cartesian<CalculationType>
334     {
335         template <typename Geometry1, typename Geometry2>
relateboost::geometry::strategies::relate::services::strategy_converter::altered_strategy336         static auto relate(Geometry1 const&, Geometry2 const&,
337                            std::enable_if_t
338                                 <
339                                     util::is_pointlike<Geometry1>::value
340                                  && ( util::is_linear<Geometry2>::value
341                                    || util::is_polygonal<Geometry2>::value )
342                                 > * = nullptr)
343         {
344             return strategy::within::franklin<void, void, CalculationType>();
345         }
346     };
347 
getboost::geometry::strategies::relate::services::strategy_converter348     static auto get(strategy::within::franklin<P1, P2, CalculationType> const&)
349     {
350         return altered_strategy();
351     }
352 };
353 
354 template <typename P1, typename P2, typename CalculationType>
355 struct strategy_converter<strategy::within::crossings_multiply<P1, P2, CalculationType>>
356 {
357     struct altered_strategy
358         : strategies::relate::cartesian<CalculationType>
359     {
360         template <typename Geometry1, typename Geometry2>
relateboost::geometry::strategies::relate::services::strategy_converter::altered_strategy361         static auto relate(Geometry1 const&, Geometry2 const&,
362                            std::enable_if_t
363                                 <
364                                     util::is_pointlike<Geometry1>::value
365                                  && ( util::is_linear<Geometry2>::value
366                                    || util::is_polygonal<Geometry2>::value )
367                                 > * = nullptr)
368         {
369             return strategy::within::crossings_multiply<void, void, CalculationType>();
370         }
371     };
372 
getboost::geometry::strategies::relate::services::strategy_converter373     static auto get(strategy::within::crossings_multiply<P1, P2, CalculationType> const&)
374     {
375         return altered_strategy();
376     }
377 };
378 
379 // TEMP used in distance segment/box
380 template <typename CalculationType>
381 struct strategy_converter<strategy::side::side_by_triangle<CalculationType>>
382 {
getboost::geometry::strategies::relate::services::strategy_converter383     static auto get(strategy::side::side_by_triangle<CalculationType> const&)
384     {
385         return strategies::relate::cartesian<CalculationType>();
386     }
387 };
388 
389 template <typename CalculationType>
390 struct strategy_converter<strategy::side::side_robust<CalculationType>>
391 {
getboost::geometry::strategies::relate::services::strategy_converter392     static auto get(strategy::side::side_robust<CalculationType> const&)
393     {
394         return strategies::relate::cartesian<CalculationType>();
395     }
396 };
397 
398 
399 } // namespace services
400 
401 }} // namespace strategies::relate
402 
403 }} // namespace boost::geometry
404 
405 #endif // BOOST_GEOMETRY_STRATEGIES_RELATE_CARTESIAN_HPP
406