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