| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : wwmath *
- * *
- * $Archive:: /Commando/Code/WWMath/sphere.h $*
- * *
- * Author:: Greg_h *
- * *
- * $Modtime:: 3/29/01 10:37a $*
- * *
- * $Revision:: 18 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * SphereClass::SphereClass -- constructor *
- * SphereClass::Init -- assign a new center and radius to this sphere *
- * SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
- * SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
- * SphereClass::Transform -- transforms this sphere *
- * SphereClass::Volume -- returns the volume of this sphere *
- * SphereClass::operator+= -- 'Add' a sphere to this one *
- * SphereClass::operator *= -- transform this sphere by the given radius *
- * Spheres_Intersect -- test whether two spheres intersect *
- * Add_Spheres -- Add two spheres together, creating sphere which encloses both *
- * operator + -- Add two spheres together, creating a sphere which encloses both *
- * Transform Sphere -- transform a sphere *
- * Transform_Sphere -- transform a sphere *
- * operator * -- Transform a sphere *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #ifndef SPHERE_H
- #define SPHERE_H
- #include "always.h"
- #include "vector3.h"
- #include "matrix3d.h"
- /////////////////////////////////////////////////////////////////////
- // SphereClass
- //
- // Center - center of the sphere.
- // Radius - radius of the sphere
- //
- /////////////////////////////////////////////////////////////////////
- class SphereClass
- {
- public:
- inline SphereClass(void) { };
- inline SphereClass(const Vector3 & center,float radius) { Init(center,radius); }
- inline SphereClass(const Matrix3D& mtx,const Vector3 & center,float radius) { Init(mtx,center,radius); }
- inline SphereClass(const Vector3 & center,const SphereClass & s0);
- inline SphereClass(const Vector3 *Position, const int VertCount);
- inline void Init(const Vector3 & pos,float radius);
- inline void Init(const Matrix3D& mtx,const Vector3 & pos,float radius);
- inline void Re_Center(const Vector3 & center);
- inline void Add_Sphere(const SphereClass & s);
- inline void Transform(const Matrix3D & tm);
- inline float Volume(void) const;
-
- inline SphereClass & operator += (const SphereClass & s);
- inline SphereClass & operator *= (const Matrix3D & m);
- Vector3 Center;
- float Radius;
- };
- /***********************************************************************************************
- * SphereClass::SphereClass -- constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass::SphereClass(const Vector3 & center,const SphereClass & s0)
- {
- float dist = (s0.Center - center).Length();
- Center = center;
- Radius = s0.Radius + dist;
- }
- inline SphereClass::SphereClass(const Vector3 *Position,const int VertCount)
- {
- int i;
- double dx,dy,dz;
- // bounding sphere
- // Using the algorithm described in Graphics Gems I page 301.
- // This algorithm supposedly generates a bounding sphere within
- // 5% of the optimal one but is much faster and simpler to implement.
- Vector3 xmin(Position[0].X,Position[0].Y,Position[0].Z);
- Vector3 xmax(Position[0].X,Position[0].Y,Position[0].Z);
- Vector3 ymin(Position[0].X,Position[0].Y,Position[0].Z);
- Vector3 ymax(Position[0].X,Position[0].Y,Position[0].Z);
- Vector3 zmin(Position[0].X,Position[0].Y,Position[0].Z);
- Vector3 zmax(Position[0].X,Position[0].Y,Position[0].Z);
- // FIRST PASS:
- // finding the 6 minima and maxima points
- for (i=1; i<VertCount; i++) {
- if (Position[i].X < xmin.X) {
- xmin.X = Position[i].X; xmin.Y = Position[i].Y; xmin.Z = Position[i].Z;
- }
- if (Position[i].X > xmax.X) {
- xmax.X = Position[i].X; xmax.Y = Position[i].Y; xmax.Z = Position[i].Z;
- }
- if (Position[i].Y < ymin.Y) {
- ymin.X = Position[i].X; ymin.Y = Position[i].Y; ymin.Z = Position[i].Z;
- }
- if (Position[i].Y > ymax.Y) {
- ymax.X = Position[i].X; ymax.Y = Position[i].Y; ymax.Z = Position[i].Z;
- }
- if (Position[i].Z < zmin.Z) {
- zmin.X = Position[i].X; zmin.Y = Position[i].Y; zmin.Z = Position[i].Z;
- }
- if (Position[i].Z > zmax.Z) {
- zmax.X = Position[i].X; zmax.Y = Position[i].Y; zmax.Z = Position[i].Z;
- }
- }
-
- // xspan = distance between the 2 points xmin and xmax squared.
- // same goes for yspan and zspan.
- dx = xmax.X - xmin.X;
- dy = xmax.Y - xmin.Y;
- dz = xmax.Z - xmin.Z;
- double xspan = dx*dx + dy*dy + dz*dz;
- dx = ymax.X - ymin.X;
- dy = ymax.Y - ymin.Y;
- dz = ymax.Z - ymin.Z;
- double yspan = dx*dx + dy*dy + dz*dz;
- dx = zmax.X - zmin.X;
- dy = zmax.Y - zmin.Y;
- dz = zmax.Z - zmin.Z;
- double zspan = dx*dx + dy*dy + dz*dz;
- // Set points dia1 and dia2 to the maximally separated pair
- // This will be the diameter of the initial sphere
- Vector3 dia1 = xmin;
- Vector3 dia2 = xmax;
- double maxspan = xspan;
- if (yspan > maxspan) {
- maxspan = yspan;
- dia1 = ymin;
- dia2 = ymax;
- }
- if (zspan > maxspan) {
- maxspan = zspan;
- dia1 = zmin;
- dia2 = zmax;
- }
-
- // Compute initial center and radius and radius squared
- Vector3 center;
- center.X = (dia1.X + dia2.X) / 2.0f;
- center.Y = (dia1.Y + dia2.Y) / 2.0f;
- center.Z = (dia1.Z + dia2.Z) / 2.0f;
- dx = dia2.X - center.X;
- dy = dia2.Y - center.Y;
- dz = dia2.Z - center.Z;
- double radsqr = dx*dx + dy*dy + dz*dz;
- double radius = sqrt(radsqr);
-
- // SECOND PASS:
- // Increment current sphere if any points fall outside of it.
- for (i=0; i<VertCount; i++) {
- dx = Position[i].X - center.X;
- dy = Position[i].Y - center.Y;
- dz = Position[i].Z - center.Z;
-
- double testrad2 = dx*dx + dy*dy + dz*dz;
- if (testrad2 > radsqr) {
-
- // this point was outside the old sphere, compute a new
- // center point and radius which contains this point
- double testrad = sqrt(testrad2);
-
- // adjust center and radius
- radius = (radius + testrad) / 2.0;
- radsqr = radius * radius;
- double oldtonew = testrad - radius;
- center.X = (radius * center.X + oldtonew * Position[i].X) / testrad;
- center.Y = (radius * center.Y + oldtonew * Position[i].Y) / testrad;
- center.Z = (radius * center.Z + oldtonew * Position[i].Z) / testrad;
- }
- }
- Center = center;
- Radius = radius;
- }
- /***********************************************************************************************
- * SphereClass::Init -- assign a new center and radius to this sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline void SphereClass::Init(const Vector3 & pos,float radius)
- {
- Center = pos;
- Radius = radius;
- }
- /***********************************************************************************************
- * SphereClass::Init -- assign a new center and radius to this sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline void SphereClass::Init(const Matrix3D& mtx, const Vector3 & pos,float radius)
- {
- #ifdef ALLOW_TEMPORARIES
- Center = mtx * pos;
- #else
- mtx.mulVector3(pos, Center);
- #endif
- Radius = radius;
- }
- /***********************************************************************************************
- * SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline void SphereClass::Re_Center(const Vector3 & center)
- {
- float dist = (Center - center).Length();
- Center = center;
- Radius += dist;
- }
- /***********************************************************************************************
- * SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline void SphereClass::Add_Sphere(const SphereClass & s)
- {
- if (s.Radius == 0.0f) return;
- float dist = (s.Center - Center).Length();
- if (dist == 0.0f) {
- Radius = (Radius > s.Radius) ? Radius : s.Radius;
- return;
- }
- float rnew = (dist + Radius + s.Radius) / 2.0f;
- // If rnew is smaller than either of the two sphere radii (it can't be
- // smaller than both of them), this means that the smaller sphere is
- // completely inside the larger, and the result of adding the two is
- // simply the larger sphere. If rnew isn't less than either of them, it is
- // the new radius - calculate the new center.
- if (rnew < Radius) {
- // The existing sphere is the result - do nothing.
- } else {
- if (rnew < s.Radius) {
- // The new sphere is the result:
- Init(s.Center, s.Radius);
- } else {
- // Neither sphere is completely inside the other, so rnew is the new
- // radius - calculate the new center
- float lerp = (rnew - Radius) / dist;
- Vector3 center = (s.Center - Center) * lerp + Center;
- Init(center, rnew);
- }
- }
- }
- /***********************************************************************************************
- * SphereClass::Transform -- transforms this sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/12/99 GTH : Created. *
- *=============================================================================================*/
- inline void SphereClass::Transform(const Matrix3D & tm)
- {
- // warning, assumes Orthogonal matrix
- #ifdef ALLOW_TEMPORARIES
- Center = tm * Center;
- #else
- tm.mulVector3(Center, Center);
- #endif
- }
- /***********************************************************************************************
- * SphereClass::Volume -- returns the volume of this sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/22/99 GTH : Created. *
- *=============================================================================================*/
- inline float SphereClass::Volume(void) const
- {
- return (4.0 / 3.0) * WWMATH_PI * (Radius * Radius * Radius);
- }
- /***********************************************************************************************
- * SphereClass::operator+= -- 'Add' a sphere to this one *
- * *
- * Expands 'this' sphere to also enclose the given sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass & SphereClass::operator += (const SphereClass & s)
- {
- Add_Sphere(s);
- return *this;
- }
- /***********************************************************************************************
- * SphereClass::operator *= -- transform this sphere by the given radius *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass & SphereClass::operator *= (const Matrix3D & m)
- {
- Init(m, Center, Radius);
- return *this;
- }
- /***********************************************************************************************
- * Spheres_Intersect -- test whether two spheres intersect *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline bool Spheres_Intersect(const SphereClass & s0,const SphereClass & s1)
- {
- Vector3 delta = s0.Center - s1.Center;
- float dist2 = Vector3::Dot_Product(delta, delta);
- if (dist2 < (s0.Radius + s1.Radius) * (s0.Radius + s1.Radius)) {
- return true;
- } else {
- return false;
- }
- }
- /***********************************************************************************************
- * Add_Spheres -- Add two spheres together, creating sphere which encloses both *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass Add_Spheres(const SphereClass & s0, const SphereClass & s1)
- {
- if (s0.Radius == 0.0f) {
- return s1;
- } else {
- SphereClass result(s0);
- result.Add_Sphere(s1);
- return result;
- }
- }
- /***********************************************************************************************
- * operator + -- Add two spheres together, creating a sphere which encloses both *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass operator + (const SphereClass & s0,const SphereClass & s1)
- {
- return Add_Spheres(s0,s1);
- }
- /***********************************************************************************************
- * Transform Sphere -- transform a sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass Transform_Sphere(const Matrix3D & m, const SphereClass & s)
- {
- // Warning, assumes Orthogonal matrix
- return SphereClass(m,s.Center,s.Radius);
- }
- /***********************************************************************************************
- * Transform_Sphere -- transform a sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline void Transform_Sphere(const Matrix3D & m, const SphereClass & s,SphereClass & res)
- {
- // warning, assumes Orthogonal matrix
- #ifdef ALLOW_TEMPORARIES
- res.Center = m*s.Center;
- #else
- m.mulVector3(s.Center, res.Center);
- #endif
- res.Radius = s.Radius;
- }
- /***********************************************************************************************
- * operator * -- Transform a sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/12/98 GTH : Created. *
- *=============================================================================================*/
- inline SphereClass operator * (const Matrix3D & m, const SphereClass & s)
- {
- return Transform_Sphere(m,s);
- }
- #endif
|