1 // Copyright (c) 1999
2 // Utrecht University (The Netherlands),
3 // ETH Zurich (Switzerland),
4 // INRIA Sophia-Antipolis (France),
5 // Max-Planck-Institute Saarbruecken (Germany),
6 // and Tel-Aviv University (Israel). All rights reserved.
7 //
8 // This file is part of CGAL (www.cgal.org)
9 //
10 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Kernel_23/include/CGAL/Sphere_3.h $
11 // $Id: Sphere_3.h 4e519a3 2021-05-05T13:15:37+02:00 Sébastien Loriot
12 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
13 //
14 //
15 // Author(s) : Stefan Schirra
16
17 #ifndef CGAL_SPHERE_3_H
18 #define CGAL_SPHERE_3_H
19
20 #include <CGAL/assertions.h>
21 #include <boost/type_traits/is_same.hpp>
22 #include <CGAL/Kernel/Return_base_tag.h>
23 #include <CGAL/Bbox_3.h>
24 #include <CGAL/representation_tags.h>
25 #include <CGAL/Dimension.h>
26
27 namespace CGAL {
28
29 template <class R_>
30 class Sphere_3 : public R_::Kernel_base::Sphere_3
31 {
32 typedef typename R_::FT FT;
33 // https://doc.cgal.org/latest/Manual/devman_code_format.html#secprogramming_conventions
34 typedef typename R_::Point_3 Point_3_;
35 typedef typename R_::Circle_3 Circle_3;
36 typedef typename R_::Aff_transformation_3 Aff_transformation_3;
37
38 typedef Sphere_3 Self;
39 CGAL_static_assertion((boost::is_same<Self, typename R_::Sphere_3>::value));
40
41 public:
42
43 typedef Dimension_tag<3> Ambient_dimension;
44 typedef Dimension_tag<2> Feature_dimension;
45
46 typedef typename R_::Kernel_base::Sphere_3 Rep;
47
rep()48 const Rep& rep() const
49 {
50 return *this;
51 }
52
rep()53 Rep& rep()
54 {
55 return *this;
56 }
57
58 typedef R_ R;
59
Sphere_3()60 Sphere_3() {}
61
Sphere_3(const Rep & s)62 Sphere_3(const Rep& s)
63 : Rep(s) {}
64
65 Sphere_3(const Point_3_& p, const FT& sq_rad,
66 const Orientation& o = COUNTERCLOCKWISE)
Rep(typename R::Construct_sphere_3 ()(Return_base_tag (),p,sq_rad,o))67 : Rep(typename R::Construct_sphere_3()(Return_base_tag(), p, sq_rad, o)) {}
68
Sphere_3(const Point_3_ & p,const Point_3_ & q,const Point_3_ & r,const Point_3_ & u)69 Sphere_3(const Point_3_& p, const Point_3_& q,
70 const Point_3_& r, const Point_3_& u)
71 : Rep(typename R::Construct_sphere_3()(Return_base_tag(), p, q, r, u)) {}
72
73 Sphere_3(const Point_3_& p, const Point_3_& q, const Point_3_& r,
74 const Orientation& o = COUNTERCLOCKWISE)
Rep(typename R::Construct_sphere_3 ()(Return_base_tag (),p,q,r,o))75 : Rep(typename R::Construct_sphere_3()(Return_base_tag(), p, q, r, o)) {}
76
77 Sphere_3(const Point_3_& p, const Point_3_& q,
78 const Orientation& o = COUNTERCLOCKWISE)
Rep(typename R::Construct_sphere_3 ()(Return_base_tag (),p,q,o))79 : Rep(typename R::Construct_sphere_3()(Return_base_tag(), p, q, o)) {}
80
81 explicit Sphere_3(const Point_3_& p, const Orientation& o = COUNTERCLOCKWISE)
Rep(typename R::Construct_sphere_3 ()(Return_base_tag (),p,o))82 : Rep(typename R::Construct_sphere_3()(Return_base_tag(), p, o)) {}
83
Sphere_3(const Circle_3 & c)84 explicit Sphere_3(const Circle_3& c)
85 : Rep(typename R::Construct_sphere_3()(c)) {}
86
87 Sphere_3 orthogonal_transform(const Aff_transformation_3 &t) const;
88
89 decltype(auto)
center()90 center() const
91 {
92 return R().construct_center_3_object()(*this);
93 }
94
95 FT
squared_radius()96 squared_radius() const
97 {
98 return R().compute_squared_radius_3_object()(*this);
99 }
100
101 // Returns a circle with opposite orientation
opposite()102 Sphere_3 opposite() const
103 {
104 return R().construct_opposite_sphere_3_object()(*this);
105 }
106
orientation()107 typename R::Orientation orientation() const
108 {
109 return R().orientation_3_object()(*this);
110 }
111
112 typename R::Bounded_side
bounded_side(const Point_3_ & p)113 bounded_side(const Point_3_ &p) const
114 {
115 return R().bounded_side_3_object()(*this, p);
116 }
117
118 typename R::Oriented_side
oriented_side(const Point_3_ & p)119 oriented_side(const Point_3_ &p) const
120 {
121 return R().oriented_side_3_object()(*this, p);
122 }
123
124 typename R::Boolean
has_on(const Point_3_ & p)125 has_on(const Point_3_ &p) const
126 {
127 return R().has_on_3_object()(*this, p);
128 }
129
130 typename R::Boolean
has_on(const Circle_3 & c)131 has_on(const Circle_3 &c) const
132 {
133 return R().has_on_3_object()(*this, c);
134 }
135
136 typename R::Boolean
has_on_boundary(const Point_3_ & p)137 has_on_boundary(const Point_3_ &p) const
138 {
139 return R().has_on_boundary_3_object()(*this, p);
140 //return bounded_side(p) == ON_BOUNDARY;
141 }
142
143 typename R::Boolean
has_on_bounded_side(const Point_3_ & p)144 has_on_bounded_side(const Point_3_ &p) const
145 {
146 return bounded_side(p) == ON_BOUNDED_SIDE;
147 }
148
149 typename R::Boolean
has_on_unbounded_side(const Point_3_ & p)150 has_on_unbounded_side(const Point_3_ &p) const
151 {
152 return bounded_side(p) == ON_UNBOUNDED_SIDE;
153 }
154
155 typename R::Boolean
has_on_negative_side(const Point_3_ & p)156 has_on_negative_side(const Point_3_ &p) const
157 {
158 if (orientation() == COUNTERCLOCKWISE)
159 return has_on_unbounded_side(p);
160 return has_on_bounded_side(p);
161 }
162
163 typename R::Boolean
has_on_positive_side(const Point_3_ & p)164 has_on_positive_side(const Point_3_ &p) const
165 {
166 if (orientation() == COUNTERCLOCKWISE)
167 return has_on_bounded_side(p);
168 return has_on_unbounded_side(p);
169 }
170
171 typename R::Boolean
is_degenerate()172 is_degenerate() const
173 {
174 return R().is_degenerate_3_object()(*this);
175 //return CGAL_NTS is_zero(squared_radius());
176 }
177
178 Bbox_3
bbox()179 bbox() const
180 {
181 return R().construct_bbox_3_object()(*this);
182 }
183
184 };
185
186 template <class R_>
187 Sphere_3<R_>
188 Sphere_3<R_>::
orthogonal_transform(const typename R_::Aff_transformation_3 & t)189 orthogonal_transform(const typename R_::Aff_transformation_3& t) const
190 {
191 typedef typename R_::RT RT;
192 typedef typename R_::FT FT;
193 typedef typename R_::Vector_3 Vector_3;
194
195 // FIXME: precond: t.is_orthogonal() (*UNDEFINED*)
196 Vector_3 vec(RT(1), RT(0), RT(0)); // unit vector
197 vec = vec.transform(t); // transformed
198 FT sq_scale = vec.squared_length(); // squared scaling factor
199
200 return Sphere_3(t.transform(this->center()),
201 sq_scale * this->squared_radius(),
202 t.is_even() ? this->orientation()
203 : CGAL::opposite(this->orientation()));
204 }
205
206
207 template <class R >
208 std::ostream&
insert(std::ostream & os,const Sphere_3<R> & c,const Cartesian_tag &)209 insert(std::ostream& os, const Sphere_3<R>& c,const Cartesian_tag&)
210 {
211 switch(IO::get_mode(os)) {
212 case IO::ASCII :
213 os << c.center() << ' ' << c.squared_radius() << ' '
214 << static_cast<int>(c.orientation());
215 break;
216 case IO::BINARY :
217 os << c.center();
218 write(os, c.squared_radius());
219 write(os, static_cast<int>(c.orientation()));
220 break;
221 default:
222 os << "SphereC3(" << c.center() << ", " << c.squared_radius();
223 switch (c.orientation()) {
224 case CLOCKWISE:
225 os << ", clockwise)";
226 break;
227 case COUNTERCLOCKWISE:
228 os << ", counterclockwise)";
229 break;
230 default:
231 os << ", collinear)";
232 break;
233 }
234 break;
235 }
236 return os;
237 }
238
239 template <class R >
240 std::ostream&
insert(std::ostream & os,const Sphere_3<R> & c,const Homogeneous_tag &)241 insert(std::ostream& os, const Sphere_3<R>& c, const Homogeneous_tag&)
242 {
243 switch(IO::get_mode(os)) {
244 case IO::ASCII :
245 os << c.center() << ' ' << c.squared_radius() << ' '
246 << static_cast<int>(c.orientation());
247 break;
248 case IO::BINARY :
249 os << c.center();
250 write(os, c.squared_radius());
251 write(os, static_cast<int>(c.orientation()));
252 break;
253 default:
254 os << "SphereH3(" << c.center() << ", " << c.squared_radius();
255 switch (c.orientation()) {
256 case CLOCKWISE:
257 os << ", clockwise)";
258 break;
259 case COUNTERCLOCKWISE:
260 os << ", counterclockwise)";
261 break;
262 default:
263 os << ", collinear)";
264 break;
265 }
266 break;
267 }
268 return os;
269 }
270
271 template < class R >
272 std::ostream&
273 operator<<(std::ostream& os, const Sphere_3<R>& c)
274 {
275 return insert(os, c, typename R::Kernel_tag() );
276 }
277
278
279 template <class R >
280 std::istream&
extract(std::istream & is,Sphere_3<R> & c,const Cartesian_tag &)281 extract(std::istream& is, Sphere_3<R>& c, const Cartesian_tag&)
282 {
283 typename R::Point_3 center;
284 typename R::FT squared_radius(0);
285 int o=0;
286 switch(IO::get_mode(is)) {
287 case IO::ASCII :
288 is >> center >> squared_radius >> o;
289 break;
290 case IO::BINARY :
291 is >> center;
292 read(is, squared_radius);
293 is >> o;
294 break;
295 default:
296 is.setstate(std::ios::failbit);
297 std::cerr << "" << std::endl;
298 std::cerr << "Stream must be in ascii or binary mode" << std::endl;
299 break;
300 }
301 if (is)
302 c = Sphere_3<R>(center, squared_radius, static_cast<Orientation>(o));
303 return is;
304 }
305
306
307 template <class R >
308 std::istream&
extract(std::istream & is,Sphere_3<R> & c,const Homogeneous_tag &)309 extract(std::istream& is, Sphere_3<R>& c, const Homogeneous_tag&)
310 {
311 typename R::Point_3 center;
312 typename R::FT squared_radius;
313 int o=0;
314 switch(IO::get_mode(is)) {
315 case IO::ASCII :
316 is >> center >> squared_radius >> o;
317 break;
318 case IO::BINARY :
319 is >> center;
320 read(is, squared_radius);
321 is >> o;
322 break;
323 default:
324 is.setstate(std::ios::failbit);
325 std::cerr << "" << std::endl;
326 std::cerr << "Stream must be in ascii or binary mode" << std::endl;
327 break;
328 }
329 if (is)
330 c = Sphere_3<R>(center, squared_radius, static_cast<Orientation>(o));
331 return is;
332 }
333
334 template < class R >
335 std::istream&
336 operator>>(std::istream& is, Sphere_3<R>& c)
337 {
338 return extract(is, c, typename R::Kernel_tag() );
339 }
340
341 } //namespace CGAL
342
343 #endif // CGAL_SPHERE_3_H
344