1 // Copyright (c) 2011 GeometryFactory (France). All rights reserved.
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org)
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Intersections_2/include/CGAL/Intersection_traits.h $
7 // $Id: Intersection_traits.h 209513d 2020-07-31T15:58:38+02:00 Dmitry Anisimov
8 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 //
11 // Author(s)     : Philipp Möller
12 
13 #ifndef CGAL_INTERSECTION_TRAITS_H
14 #define CGAL_INTERSECTION_TRAITS_H
15 
16 #include <CGAL/Kernel_traits.h>
17 #include <CGAL/Object.h>
18 #include <CGAL/assertions.h>
19 #include <CGAL/Dimension.h>
20 
21 #include <boost/type_traits/is_same.hpp>
22 #include <boost/variant.hpp>
23 
24 #define CGAL_INTERSECTION_TRAITS_2(A, B, R1, R2)                \
25   template<typename K>     \
26   struct Intersection_traits<K, typename K::A, typename K::B>  { \
27     typedef typename boost::variant<typename K::R1, typename K::R2 >    \
28                      variant_type;                                      \
29     typedef typename boost::optional< variant_type > result_type;       \
30   };
31 
32 #define CGAL_INTERSECTION_TRAITS_3(A, B, R1, R2, R3)            \
33   template<typename K>     \
34   struct Intersection_traits<K, typename K::A, typename K::B>  { \
35     typedef typename boost::variant<typename K::R1, typename K::R2,     \
36                                     typename K::R3> variant_type;       \
37     typedef typename boost::optional< variant_type > result_type;       \
38   };
39 
40 #define CGAL_INTERSECTION_FUNCTION(A, B, DIM)                           \
41   template<typename K>                                                  \
42   inline                                                                \
43   decltype(auto) \
44   intersection(const A<K>& a, const B<K>& b) {                          \
45     return BOOST_PP_CAT(K().intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
46   }                                                                     \
47   template<typename K>                                                  \
48   inline                                                                \
49   decltype(auto) \
50   intersection(const B<K>& a, const A<K>& b) {                          \
51     return BOOST_PP_CAT(K().intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
52   }
53 
54 #define CGAL_INTERSECTION_FUNCTION_SELF(A, DIM)                         \
55   template<typename K>                                                  \
56   inline                                                                \
57   decltype(auto) \
58   intersection(const A<K> & a, const A<K> & b) {                          \
59     return BOOST_PP_CAT(K().intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
60   }
61 
62 #define CGAL_DO_INTERSECT_FUNCTION(A, B, DIM)              \
63   template<typename K>                                     \
64   inline bool                                              \
65   do_intersect(const A<K>& a, const B<K>& b) {             \
66     return BOOST_PP_CAT(K().do_intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
67   }                                                        \
68   template<typename K>                                     \
69   inline bool                                              \
70   do_intersect(const B<K>& a, const A<K>& b) {             \
71     return BOOST_PP_CAT(K().do_intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
72   }
73 
74 #define CGAL_DO_INTERSECT_FUNCTION_SELF(A, DIM)                         \
75   template<typename K>                                                  \
76   inline bool                                                           \
77   do_intersect(const A<K> & a, const A<K> & b) {                          \
78     return BOOST_PP_CAT(K().do_intersect_, BOOST_PP_CAT(DIM, _object()(a, b))); \
79   }
80 
81 namespace CGAL {
82 
83 // only declarationn
84 template<typename, typename, typename>
85 struct Intersection_traits {
86   // This defaults to Object, if we use VERSION < 2 and do nothing
87   // otherwise.
88 };
89 
90 
91 // Alias that gets the Kernel automatically and does some error checking.
92 // Including corresponding specialization for Bbox, as it has no Kernel.
93 template<typename A, typename B>
94 class IT : public Intersection_traits< typename Kernel_traits<A>::Kernel, A, B > {
95   typedef typename Kernel_traits<A>::Kernel A_Kernel;
96   typedef typename Kernel_traits<B>::Kernel B_Kernel;
97   // CGAL_static_assertion_msg( (boost::is_same< A_Kernel, B_Kernel>::value),
98   //                            "IT instantiated with objects from two different Kernels");
99 };
100 
101 class Bbox_2;
102 class Bbox_3;
103 
104 template<typename B>
105 class IT<Bbox_2, B> : public Intersection_traits< typename Kernel_traits<B>::Kernel, CGAL::Bbox_2, B >
106 { };
107 
108 template<typename B>
109 class IT<Bbox_3, B> : public Intersection_traits< typename Kernel_traits<B>::Kernel, CGAL::Bbox_3, B >
110 { };
111 
112 
113 namespace Intersections {
114 namespace internal {
115 
116 // this function is used to call either make_object or a
117 // Intersection_traits::result_type constructor to create return
118 // values. The Object version takes some dummy template arguments
119 // that are needed for the return of the Intersection_traits. In
120 // theory a one parameter variant could be returned, but this
121 // _could_ come with conversion overhead and so we rather go for
122 // the real type.
123 // Overloads for empty returns are also provided.
124   template<typename F, typename A, typename B, typename T>
decltype(auto)125   decltype(auto)
126   intersection_return(T&& t) { return decltype(std::declval<F>()(std::declval<A>(), std::declval<B>()))(std::forward<T>(t)); }
127   template<typename F, typename A, typename B>
decltype(auto)128   decltype(auto)
129   intersection_return() { return decltype(std::declval<F>()(std::declval<A>(), std::declval<B>()))(); }
130 
131 // Something similar to wrap around boost::get and object_cast to
132 // prevent ifdefing too much. Another way could be to introduce an
133 // overload of boost::get for Object.  We only provide the pointer
134 // casts here. But use references to const as parameters. This makes
135 // it somewhat nicer.
136 template<typename T>
137 inline
intersect_get(const CGAL::Object & o)138 const T* intersect_get(const CGAL::Object& o) {
139   return CGAL::object_cast<T>(&o);
140 }
141 
142 template<typename T, BOOST_VARIANT_ENUM_PARAMS(typename U)>
143 inline
intersect_get(const boost::optional<boost::variant<BOOST_VARIANT_ENUM_PARAMS (U)>> & v)144 const T* intersect_get(const boost::optional< boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)> >& v) {
145   return boost::get<T>(&*v);
146 }
147 
148 template<typename T, BOOST_VARIANT_ENUM_PARAMS(typename U)>
149 inline
intersect_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS (U)> & v)150 const T* intersect_get(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)> & v) {
151   return boost::get<T>(&v);
152 }
153 
154 template<typename A, typename B>
decltype(auto)155 decltype(auto)
156 intersection_impl(const A& a, const B& b, CGAL::Dimension_tag<2>) {
157   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
158   return Kernel().intersect_2_object()(a, b);
159 }
160 
161 template<typename A, typename B>
decltype(auto)162 decltype(auto)
163 intersection_impl(const A& a, const B& b, Dimension_tag<3>) {
164   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
165   return Kernel().intersect_3_object()(a, b);
166 }
167 
168 template<typename A, typename B>
169 typename Intersection_traits< typename CGAL::Kernel_traits<A>::Kernel, A, B>::result_type
intersection_impl(const A & a,const B & b,Dynamic_dimension_tag)170 intersection_impl(const A& a, const B& b, Dynamic_dimension_tag) {
171   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
172   return Kernel().intersect_d_object()(a, b);
173 }
174 
175 template<typename A, typename B>
176 inline bool
do_intersect_impl(const A & a,const B & b,CGAL::Dimension_tag<2>)177 do_intersect_impl(const A& a, const B& b, CGAL::Dimension_tag<2>) {
178   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
179   return Kernel().do_intersect_2_object()(a, b);
180 }
181 
182 template<typename A, typename B>
183 inline bool
do_intersect_impl(const A & a,const B & b,Dimension_tag<3>)184 do_intersect_impl(const A& a, const B& b, Dimension_tag<3>) {
185   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
186   return Kernel().do_intersect_3_object()(a, b);
187 }
188 
189 template<typename A, typename B>
190 inline bool
do_intersect_impl(const A & a,const B & b,Dynamic_dimension_tag)191 do_intersect_impl(const A& a, const B& b, Dynamic_dimension_tag) {
192   typedef typename CGAL::Kernel_traits<A>::Kernel Kernel;
193   return Kernel().do_intersect_d_object()(a, b);
194 }
195 
196 } // namespace internal
197 } // namespace Intersections
198 
199 // See overloads in the respective header files
200 
201 // template<typename A, typename B>
202 // inline
203 // typename Intersection_traits< typename Kernel_traits<A>::Kernel, A, B>::result_type >::type
204 // intersection(const A& a, const B& b) {
205 //   CGAL_static_assertion_msg( (boost::is_same<typename A::Ambient_dimension, typename B::Ambient_dimension>::value),
206 //                               "intersection with objects of different dimensions not supported");
207 //   return internal::intersection_impl(a, b, typename A::Ambient_dimension());
208 // }
209 
210 // template<typename A, typename B>
211 // inline
212 // bool
213 // do_intersect(const A& a, const B& b) {
214 //   CGAL_static_assertion_msg((boost::is_same<typename A::Ambient_dimension, typename B::Ambient_dimension>::value),
215 //                         "do_intersect with objects of different dimensions not supported");
216 //   return internal::do_intersect_impl(a, b, typename A::Ambient_dimension());
217 // }
218 
219 } // CGAL
220 
221 #endif /* CGAL_INTERSECTION_TRAITS_H */
222