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 ¢erarg, 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 ¢erarg, 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 ¢erarg)
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