1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SbSphere SbSphere.h Inventor/SbSphere.h
35   \brief The SbSphere class is a representation of a sphere.
36 
37   \ingroup base
38 
39   This class is used within many other classes in Coin. It contains
40   the data neccessary to represent a sphere (a 3D point and a radius).
41 
42   \sa SbCylinder */
43 
44 #include <cassert>
45 #include <Inventor/SbSphere.h>
46 #include <Inventor/SbBox3f.h>
47 #include <Inventor/SbLine.h>
48 #if COIN_DEBUG
49 #include <Inventor/errors/SoDebugError.h>
50 #endif // COIN_DEBUG
51 
52 /*!
53   The default constructor does nothing. The center point and the radius
54   will be uninitialized.
55  */
SbSphere(void)56 SbSphere::SbSphere(void)
57 {
58 }
59 
60 /*!
61   Construct an SbSphere instance with the given center point and radius.
62  */
SbSphere(const SbVec3f & centerarg,const float radiusarg)63 SbSphere::SbSphere(const SbVec3f &centerarg, const float radiusarg)
64 {
65 #if COIN_DEBUG
66   if (radiusarg<0.0f)
67     SoDebugError::postWarning("SbSphere::SbSphere",
68                               "Radius should be >= 0.0f.");
69 #endif // COIN_DEBUG
70 
71   this->setValue(centerarg, radiusarg);
72 }
73 
74 /*!
75   Set the sphere's center point and radius.
76 
77   \sa getCenter(), getRadius().
78  */
79 void
setValue(const SbVec3f & centerarg,const float radiusarg)80 SbSphere::setValue(const SbVec3f &centerarg, const float radiusarg)
81 {
82 #if COIN_DEBUG
83   if (radiusarg<0.0f)
84     SoDebugError::postWarning("SbSphere::setValue",
85                               "Radius should be >= 0.0f.");
86 #endif // COIN_DEBUG
87   this->setCenter(centerarg);
88   this->setRadius(radiusarg);
89 }
90 
91 /*!
92   Set the sphere's center point.
93 
94   \sa setValue(), setRadius() and getCenter().
95  */
96 void
setCenter(const SbVec3f & centerarg)97 SbSphere::setCenter(const SbVec3f &centerarg)
98 {
99   this->center = centerarg;
100 }
101 
102 /*!
103   Set the sphere's radius.
104 
105   \sa setValue(), setCenter() and getRadius().
106  */
107 void
setRadius(const float radiusarg)108 SbSphere::setRadius(const float radiusarg)
109 {
110 #if COIN_DEBUG
111   if (radiusarg<0.0f)
112     SoDebugError::postWarning("SbSphere::setRadius",
113                               "Radius should be >= 0.0f.");
114 #endif // COIN_DEBUG
115   this->radius = radiusarg;
116 }
117 
118 /*!
119   Returns an SbVec3f with the sphere's center point.
120 
121   \sa setCenter(), getRadius().
122  */
123 const SbVec3f &
getCenter(void) const124 SbSphere::getCenter(void) const
125 {
126   return this->center;
127 }
128 
129 /*!
130   Returns the sphere's radius.
131 
132   \sa setRadius(), getCenter().
133  */
134 float
getRadius(void) const135 SbSphere::getRadius(void) const
136 {
137   return this->radius;
138 }
139 
140 /*!
141   Make the sphere exactly contain \a box, i.e. the sphere center point
142   will be the same as that of the box, and the radius will be the distance
143   from the box center point to any of the corners.
144  */
145 void
circumscribe(const SbBox3f & box)146 SbSphere::circumscribe(const SbBox3f &box)
147 {
148 #if COIN_DEBUG
149   if (box.isEmpty()) {
150     SoDebugError::postWarning("SbSphere::circumscribe",
151                               "The box is empty.");
152     return;
153   }
154 #endif // COIN_DEBUG
155 
156   this->setCenter(box.getCenter());
157 
158   float dx, dy, dz;
159   box.getSize(dx, dy, dz);
160 
161   this->setRadius(float(sqrt(dx*dx + dy*dy + dz*dz)) / 2.0f);
162 }
163 
164 /*!
165   Finds the intersection enter point for the given line \a l
166   on the sphere.
167 
168   If the line does not intersect the sphere, \a FALSE is returned.
169  */
170 SbBool
intersect(const SbLine & l,SbVec3f & intersection) const171 SbSphere::intersect(const SbLine &l, SbVec3f &intersection) const
172 {
173   SbVec3f dummy;
174   return this->intersect(l, intersection, dummy);
175 }
176 
177 /*!
178   Find the intersection points of the ray \a l on the sphere and
179   return these in \a enter and \a exit. If the ray just "grazes"
180   the sphere, the \a enter and \a exit points have equal values.
181 
182   If the ray does not intersect the sphere, \a FALSE is returned, otherwise
183   we will return \a TRUE.
184  */
185 SbBool
intersect(const SbLine & l,SbVec3f & enter,SbVec3f & exit) const186 SbSphere::intersect(const SbLine &l, SbVec3f &enter, SbVec3f &exit) const
187 {
188 #if COIN_DEBUG
189   if (!(l.getDirection().length()>0.0f))
190     SoDebugError::postWarning("SbSphere::intersect",
191                               "The line 'l' has no direction.");
192 #endif // COIN_DEBUG
193 
194   // Compute point on the line that is closest to the sphere center.
195   SbVec3f closestpt = l.getClosestPoint(this->getCenter());
196 
197   // Sphere center, closest point on the line and intersection
198   // point(s) form a right-angled triangle. The distance between closest point
199   // and intersection point(s) can be computed using Pythagoras' theorem.
200   float sqrradius = this->getRadius() * this->getRadius();
201   float sqrdistcenter = (this->getCenter() - closestpt).sqrLength();
202   float sqrdistintersect = sqrradius - sqrdistcenter;
203 
204   if (sqrdistintersect < 0) {
205     // no intersection of sphere and line exists
206     return FALSE;
207   }
208   else {
209     float t = sqrtf(sqrdistintersect);
210     enter = closestpt - t * l.getDirection();
211     exit  = closestpt + t * l.getDirection();
212     return TRUE;
213   }
214 }
215 
216 /*!
217   Returns \a TRUE of the given point \a p lies within the sphere.
218  */
219 SbBool
pointInside(const SbVec3f & p) const220 SbSphere::pointInside(const SbVec3f &p) const
221 {
222   return (p - center).length() < radius;
223 }
224 
225 /*!
226   Dump the state of this object to the \a file stream. Only works in
227   debug version of library, method does nothing in an optimized compile.
228  */
229 void
print(FILE * fp) const230 SbSphere::print(FILE * fp) const
231 {
232 #if COIN_DEBUG
233   fprintf( fp, "center: " );
234   this->getCenter().print(fp);
235   fprintf( fp, "  radius: %f ", this->getRadius() );
236 #endif // COIN_DEBUG
237 }
238