Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
sphere.h
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : wwmath *
24 * *
25 * $Archive:: /Commando/Code/WWMath/sphere.h $*
26 * *
27 * Author:: Greg_h *
28 * *
29 * $Modtime:: 3/29/01 10:37a $*
30 * *
31 * $Revision:: 18 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * SphereClass::SphereClass -- constructor *
36 * SphereClass::Init -- assign a new center and radius to this sphere *
37 * SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
38 * SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
39 * SphereClass::Transform -- transforms this sphere *
40 * SphereClass::Volume -- returns the volume of this sphere *
41 * SphereClass::operator+= -- 'Add' a sphere to this one *
42 * SphereClass::operator *= -- transform this sphere by the given radius *
43 * Spheres_Intersect -- test whether two spheres intersect *
44 * Add_Spheres -- Add two spheres together, creating sphere which encloses both *
45 * operator + -- Add two spheres together, creating a sphere which encloses both *
46 * Transform Sphere -- transform a sphere *
47 * Transform_Sphere -- transform a sphere *
48 * operator * -- Transform a sphere *
49 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
50
51
52#if defined(_MSC_VER)
53#pragma once
54#endif
55
56#ifndef SPHERE_H
57#define SPHERE_H
58
59#include "always.h"
60#include "vector3.h"
61#include "matrix3d.h"
62
63
65// SphereClass
66//
67// Center - center of the sphere.
68// Radius - radius of the sphere
69//
72{
73public:
74 inline SphereClass(void) { };
75 inline SphereClass(const Vector3 & center,float radius) { Init(center,radius); }
76 inline SphereClass(const Matrix3D& mtx,const Vector3 & center,float radius) { Init(mtx,center,radius); }
77 inline SphereClass(const Vector3 & center,const SphereClass & s0);
78 inline SphereClass(const Vector3 *Position, const int VertCount);
79
80 inline void Init(const Vector3 & pos,float radius);
81 inline void Init(const Matrix3D& mtx,const Vector3 & pos,float radius);
82 inline void Re_Center(const Vector3 & center);
83 inline void Add_Sphere(const SphereClass & s);
84 inline void Transform(const Matrix3D & tm);
85 inline float Volume(void) const;
86
87 inline SphereClass & operator += (const SphereClass & s);
88 inline SphereClass & operator *= (const Matrix3D & m);
89
91 float Radius;
92};
93
94
95/***********************************************************************************************
96 * SphereClass::SphereClass -- constructor *
97 * *
98 * INPUT: *
99 * *
100 * OUTPUT: *
101 * *
102 * WARNINGS: *
103 * *
104 * HISTORY: *
105 * 8/12/98 GTH : Created. *
106 *=============================================================================================*/
107inline SphereClass::SphereClass(const Vector3 & center,const SphereClass & s0)
108{
109 float dist = (s0.Center - center).Length();
110 Center = center;
111 Radius = s0.Radius + dist;
112}
113
114inline SphereClass::SphereClass(const Vector3 *Position,const int VertCount)
115{
116 int i;
117 double dx,dy,dz;
118
119 // bounding sphere
120 // Using the algorithm described in Graphics Gems I page 301.
121 // This algorithm supposedly generates a bounding sphere within
122 // 5% of the optimal one but is much faster and simpler to implement.
123 Vector3 xmin(Position[0].X,Position[0].Y,Position[0].Z);
124 Vector3 xmax(Position[0].X,Position[0].Y,Position[0].Z);
125 Vector3 ymin(Position[0].X,Position[0].Y,Position[0].Z);
126 Vector3 ymax(Position[0].X,Position[0].Y,Position[0].Z);
127 Vector3 zmin(Position[0].X,Position[0].Y,Position[0].Z);
128 Vector3 zmax(Position[0].X,Position[0].Y,Position[0].Z);
129
130
131 // FIRST PASS:
132 // finding the 6 minima and maxima points
133 for (i=1; i<VertCount; i++) {
134 if (Position[i].X < xmin.X) {
135 xmin.X = Position[i].X; xmin.Y = Position[i].Y; xmin.Z = Position[i].Z;
136 }
137 if (Position[i].X > xmax.X) {
138 xmax.X = Position[i].X; xmax.Y = Position[i].Y; xmax.Z = Position[i].Z;
139 }
140 if (Position[i].Y < ymin.Y) {
141 ymin.X = Position[i].X; ymin.Y = Position[i].Y; ymin.Z = Position[i].Z;
142 }
143 if (Position[i].Y > ymax.Y) {
144 ymax.X = Position[i].X; ymax.Y = Position[i].Y; ymax.Z = Position[i].Z;
145 }
146 if (Position[i].Z < zmin.Z) {
147 zmin.X = Position[i].X; zmin.Y = Position[i].Y; zmin.Z = Position[i].Z;
148 }
149 if (Position[i].Z > zmax.Z) {
150 zmax.X = Position[i].X; zmax.Y = Position[i].Y; zmax.Z = Position[i].Z;
151 }
152 }
153
154 // xspan = distance between the 2 points xmin and xmax squared.
155 // same goes for yspan and zspan.
156 dx = xmax.X - xmin.X;
157 dy = xmax.Y - xmin.Y;
158 dz = xmax.Z - xmin.Z;
159 double xspan = dx*dx + dy*dy + dz*dz;
160
161 dx = ymax.X - ymin.X;
162 dy = ymax.Y - ymin.Y;
163 dz = ymax.Z - ymin.Z;
164 double yspan = dx*dx + dy*dy + dz*dz;
165
166 dx = zmax.X - zmin.X;
167 dy = zmax.Y - zmin.Y;
168 dz = zmax.Z - zmin.Z;
169 double zspan = dx*dx + dy*dy + dz*dz;
170
171
172 // Set points dia1 and dia2 to the maximally separated pair
173 // This will be the diameter of the initial sphere
174 Vector3 dia1 = xmin;
175 Vector3 dia2 = xmax;
176 double maxspan = xspan;
177
178 if (yspan > maxspan) {
179 maxspan = yspan;
180 dia1 = ymin;
181 dia2 = ymax;
182 }
183 if (zspan > maxspan) {
184 maxspan = zspan;
185 dia1 = zmin;
186 dia2 = zmax;
187 }
188
189
190 // Compute initial center and radius and radius squared
191 Vector3 center;
192 center.X = (dia1.X + dia2.X) / 2.0f;
193 center.Y = (dia1.Y + dia2.Y) / 2.0f;
194 center.Z = (dia1.Z + dia2.Z) / 2.0f;
195
196 dx = dia2.X - center.X;
197 dy = dia2.Y - center.Y;
198 dz = dia2.Z - center.Z;
199
200 double radsqr = dx*dx + dy*dy + dz*dz;
201 double radius = sqrt(radsqr);
202
203
204 // SECOND PASS:
205 // Increment current sphere if any points fall outside of it.
206 for (i=0; i<VertCount; i++) {
207
208 dx = Position[i].X - center.X;
209 dy = Position[i].Y - center.Y;
210 dz = Position[i].Z - center.Z;
211
212 double testrad2 = dx*dx + dy*dy + dz*dz;
213
214 if (testrad2 > radsqr) {
215
216 // this point was outside the old sphere, compute a new
217 // center point and radius which contains this point
218 double testrad = sqrt(testrad2);
219
220 // adjust center and radius
221 radius = (radius + testrad) / 2.0;
222 radsqr = radius * radius;
223
224 double oldtonew = testrad - radius;
225 center.X = (radius * center.X + oldtonew * Position[i].X) / testrad;
226 center.Y = (radius * center.Y + oldtonew * Position[i].Y) / testrad;
227 center.Z = (radius * center.Z + oldtonew * Position[i].Z) / testrad;
228 }
229 }
230
231 Center = center;
232 Radius = radius;
233}
234
235
236/***********************************************************************************************
237 * SphereClass::Init -- assign a new center and radius to this sphere *
238 * *
239 * INPUT: *
240 * *
241 * OUTPUT: *
242 * *
243 * WARNINGS: *
244 * *
245 * HISTORY: *
246 * 8/12/98 GTH : Created. *
247 *=============================================================================================*/
248inline void SphereClass::Init(const Vector3 & pos,float radius)
249{
250 Center = pos;
251 Radius = radius;
252}
253
254/***********************************************************************************************
255 * SphereClass::Init -- assign a new center and radius to this sphere *
256 * *
257 * INPUT: *
258 * *
259 * OUTPUT: *
260 * *
261 * WARNINGS: *
262 * *
263 * HISTORY: *
264 * 8/12/98 GTH : Created. *
265 *=============================================================================================*/
266inline void SphereClass::Init(const Matrix3D& mtx, const Vector3 & pos,float radius)
267{
268#ifdef ALLOW_TEMPORARIES
269 Center = mtx * pos;
270#else
271 mtx.mulVector3(pos, Center);
272#endif
273 Radius = radius;
274}
275
276
277/***********************************************************************************************
278 * SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
279 * *
280 * INPUT: *
281 * *
282 * OUTPUT: *
283 * *
284 * WARNINGS: *
285 * *
286 * HISTORY: *
287 * 8/12/98 GTH : Created. *
288 *=============================================================================================*/
289inline void SphereClass::Re_Center(const Vector3 & center)
290{
291 float dist = (Center - center).Length();
292 Center = center;
293 Radius += dist;
294}
295
296
297/***********************************************************************************************
298 * SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
299 * *
300 * INPUT: *
301 * *
302 * OUTPUT: *
303 * *
304 * WARNINGS: *
305 * *
306 * HISTORY: *
307 * 8/12/98 GTH : Created. *
308 *=============================================================================================*/
310{
311 if (s.Radius == 0.0f) return;
312
313 float dist = (s.Center - Center).Length();
314 if (dist == 0.0f) {
315 Radius = (Radius > s.Radius) ? Radius : s.Radius;
316 return;
317 }
318
319 float rnew = (dist + Radius + s.Radius) / 2.0f;
320
321 // If rnew is smaller than either of the two sphere radii (it can't be
322 // smaller than both of them), this means that the smaller sphere is
323 // completely inside the larger, and the result of adding the two is
324 // simply the larger sphere. If rnew isn't less than either of them, it is
325 // the new radius - calculate the new center.
326 if (rnew < Radius) {
327 // The existing sphere is the result - do nothing.
328 } else {
329 if (rnew < s.Radius) {
330 // The new sphere is the result:
331 Init(s.Center, s.Radius);
332 } else {
333 // Neither sphere is completely inside the other, so rnew is the new
334 // radius - calculate the new center
335 float lerp = (rnew - Radius) / dist;
336 Vector3 center = (s.Center - Center) * lerp + Center;
337 Init(center, rnew);
338 }
339 }
340}
341
342/***********************************************************************************************
343 * SphereClass::Transform -- transforms this sphere *
344 * *
345 * INPUT: *
346 * *
347 * OUTPUT: *
348 * *
349 * WARNINGS: *
350 * *
351 * HISTORY: *
352 * 3/12/99 GTH : Created. *
353 *=============================================================================================*/
354inline void SphereClass::Transform(const Matrix3D & tm)
355{
356 // warning, assumes Orthogonal matrix
357#ifdef ALLOW_TEMPORARIES
358 Center = tm * Center;
359#else
361#endif
362}
363
364
365/***********************************************************************************************
366 * SphereClass::Volume -- returns the volume of this sphere *
367 * *
368 * INPUT: *
369 * *
370 * OUTPUT: *
371 * *
372 * WARNINGS: *
373 * *
374 * HISTORY: *
375 * 3/22/99 GTH : Created. *
376 *=============================================================================================*/
377inline float SphereClass::Volume(void) const
378{
379 return (4.0 / 3.0) * WWMATH_PI * (Radius * Radius * Radius);
380}
381
382/***********************************************************************************************
383 * SphereClass::operator+= -- 'Add' a sphere to this one *
384 * *
385 * Expands 'this' sphere to also enclose the given sphere *
386 * *
387 * INPUT: *
388 * *
389 * OUTPUT: *
390 * *
391 * WARNINGS: *
392 * *
393 * HISTORY: *
394 * 8/12/98 GTH : Created. *
395 *=============================================================================================*/
397{
398 Add_Sphere(s);
399 return *this;
400}
401
402
403/***********************************************************************************************
404 * SphereClass::operator *= -- transform this sphere by the given radius *
405 * *
406 * INPUT: *
407 * *
408 * OUTPUT: *
409 * *
410 * WARNINGS: *
411 * *
412 * HISTORY: *
413 * 8/12/98 GTH : Created. *
414 *=============================================================================================*/
416{
417 Init(m, Center, Radius);
418 return *this;
419}
420
421
422/***********************************************************************************************
423 * Spheres_Intersect -- test whether two spheres intersect *
424 * *
425 * INPUT: *
426 * *
427 * OUTPUT: *
428 * *
429 * WARNINGS: *
430 * *
431 * HISTORY: *
432 * 8/12/98 GTH : Created. *
433 *=============================================================================================*/
434inline bool Spheres_Intersect(const SphereClass & s0,const SphereClass & s1)
435{
436 Vector3 delta = s0.Center - s1.Center;
437 float dist2 = Vector3::Dot_Product(delta, delta);
438
439 if (dist2 < (s0.Radius + s1.Radius) * (s0.Radius + s1.Radius)) {
440 return true;
441 } else {
442 return false;
443 }
444}
445
446
447/***********************************************************************************************
448 * Add_Spheres -- Add two spheres together, creating sphere which encloses both *
449 * *
450 * INPUT: *
451 * *
452 * OUTPUT: *
453 * *
454 * WARNINGS: *
455 * *
456 * HISTORY: *
457 * 8/12/98 GTH : Created. *
458 *=============================================================================================*/
459inline SphereClass Add_Spheres(const SphereClass & s0, const SphereClass & s1)
460{
461 if (s0.Radius == 0.0f) {
462 return s1;
463 } else {
464 SphereClass result(s0);
465 result.Add_Sphere(s1);
466 return result;
467 }
468}
469
470
471/***********************************************************************************************
472 * operator + -- Add two spheres together, creating a sphere which encloses both *
473 * *
474 * INPUT: *
475 * *
476 * OUTPUT: *
477 * *
478 * WARNINGS: *
479 * *
480 * HISTORY: *
481 * 8/12/98 GTH : Created. *
482 *=============================================================================================*/
483inline SphereClass operator + (const SphereClass & s0,const SphereClass & s1)
484{
485 return Add_Spheres(s0,s1);
486}
487
488
489/***********************************************************************************************
490 * Transform Sphere -- transform a sphere *
491 * *
492 * INPUT: *
493 * *
494 * OUTPUT: *
495 * *
496 * WARNINGS: *
497 * *
498 * HISTORY: *
499 * 8/12/98 GTH : Created. *
500 *=============================================================================================*/
502{
503 // Warning, assumes Orthogonal matrix
504 return SphereClass(m,s.Center,s.Radius);
505}
506
507
508/***********************************************************************************************
509 * Transform_Sphere -- transform a sphere *
510 * *
511 * INPUT: *
512 * *
513 * OUTPUT: *
514 * *
515 * WARNINGS: *
516 * *
517 * HISTORY: *
518 * 8/12/98 GTH : Created. *
519 *=============================================================================================*/
520inline void Transform_Sphere(const Matrix3D & m, const SphereClass & s,SphereClass & res)
521{
522 // warning, assumes Orthogonal matrix
523#ifdef ALLOW_TEMPORARIES
524 res.Center = m*s.Center;
525#else
526 m.mulVector3(s.Center, res.Center);
527#endif
528 res.Radius = s.Radius;
529}
530
531
532/***********************************************************************************************
533 * operator * -- Transform a sphere *
534 * *
535 * INPUT: *
536 * *
537 * OUTPUT: *
538 * *
539 * WARNINGS: *
540 * *
541 * HISTORY: *
542 * 8/12/98 GTH : Created. *
543 *=============================================================================================*/
544inline SphereClass operator * (const Matrix3D & m, const SphereClass & s)
545{
546 return Transform_Sphere(m,s);
547}
548
549
550
551#endif
552
#define WWMATH_PI
Definition wwmath.h:56
void mulVector3(const Vector3 &in, Vector3 &out) const
Definition matrix3d.h:1650
SphereClass(void)
Definition sphere.h:74
SphereClass & operator*=(const Matrix3D &m)
Definition sphere.h:415
SphereClass(const Vector3 &center, float radius)
Definition sphere.h:75
float Radius
Definition sphere.h:91
Vector3 Center
Definition sphere.h:90
void Init(const Vector3 &pos, float radius)
Definition sphere.h:248
SphereClass(const Matrix3D &mtx, const Vector3 &center, float radius)
Definition sphere.h:76
float Volume(void) const
Definition sphere.h:377
void Transform(const Matrix3D &tm)
Definition sphere.h:354
void Re_Center(const Vector3 &center)
Definition sphere.h:289
void Add_Sphere(const SphereClass &s)
Definition sphere.h:309
SphereClass & operator+=(const SphereClass &s)
Definition sphere.h:396
static WWINLINE float Dot_Product(const Vector3 &a, const Vector3 &b)
Definition vector3.h:293
float X
Definition vector3.h:90
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
SphereClass operator+(const SphereClass &s0, const SphereClass &s1)
Definition sphere.h:483
SphereClass Transform_Sphere(const Matrix3D &m, const SphereClass &s)
Definition sphere.h:501
SphereClass Add_Spheres(const SphereClass &s0, const SphereClass &s1)
Definition sphere.h:459
bool Spheres_Intersect(const SphereClass &s0, const SphereClass &s1)
Definition sphere.h:434
SphereClass operator*(const Matrix3D &m, const SphereClass &s)
Definition sphere.h:544