Version
menu_open
link

include/AK/Tools/Common/AkVectors.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
00003 released in source code form as part of the SDK installer package.
00004 
00005 Commercial License Usage
00006 
00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
00008 may use this file in accordance with the end user license agreement provided 
00009 with the software or, alternatively, in accordance with the terms contained in a
00010 written agreement between you and Audiokinetic Inc.
00011 
00012 Apache License Usage
00013 
00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the 
00015 "Apache License"); you may not use this file except in compliance with the 
00016 Apache License. You may obtain a copy of the Apache License at 
00017 http://www.apache.org/licenses/LICENSE-2.0.
00018 
00019 Unless required by applicable law or agreed to in writing, software distributed
00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
00022 the specific language governing permissions and limitations under the License.
00023 
00024   Version: <VERSION>  Build: <BUILDNUMBER>
00025   Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc.
00026 *******************************************************************************/
00027 
00028 // AkVectors.h
00029 //
00030 
00031 #pragma once
00032 
00033 #include <AK/SoundEngine/Common/AkTypes.h>
00034 #include <AK/SoundEngine/Common/AkSimd.h>
00035 #include <AK/SoundEngine/Common/AkSpeakerVolumes.h>
00036 #include <AK/SoundEngine/Common/IAkPluginMemAlloc.h>
00037 #include <AK/Tools/Common/AkArray.h>
00038 #include <AK/Tools/Common/AkObject.h>
00039 
00040 #include <math.h>
00041 #include <stdio.h>
00042 #include <float.h>
00043 
00044 //#define AKVBAP_DEBUG 1
00045 //#define AKPORTALS_DEBUG
00046 
00047 #define AKVECTORS_PI                (3.1415926535897932384626433832795f)
00048 #define AKVECTORS_TWOPI             (6.283185307179586476925286766559f)
00049 #define AKVECTORS_PIOVERTWO         (1.5707963267948966192313216916398f)
00050 #define AKVECTORS_EPSILON           (1.0e-38f)                                  // epsilon value for fast log(0)
00051 
00052 
00053 class AkMatrix4x4
00054 {
00055     static const int MAX_SIZE = 16;
00056 
00057     public:
00058     //-----------------------------------------------------------
00059     // Constructor/Destructor functions
00060     AkMatrix4x4(){}
00061     ~AkMatrix4x4(){}
00062 
00063     //-----------------------------------------------------------
00064     // Basic vector operators
00065     AkMatrix4x4 operator/=(const AkReal32 f)
00066     {
00067         for (int i = 0; i < MAX_SIZE; i++)
00068             m_Data[i] /= f;
00069 
00070         return *this;
00071     }
00072 
00073     AkMatrix4x4 operator=(AkReal32 * in_Data)
00074     {
00075         for (int i = 0; i < MAX_SIZE; i++)
00076         {
00077             m_Data[i] = in_Data[i];
00078         }
00079 
00080         return *this;
00081     }
00082 
00083     AkReal32 m_Data[MAX_SIZE];
00084 };
00085 
00086 class AkMatrix3x3
00087 {
00088 
00089 public:
00090     //-----------------------------------------------------------
00091     // Constructor/Destructor functions
00092     AkMatrix3x3(){}
00093     ~AkMatrix3x3(){}
00094 
00095     //-----------------------------------------------------------
00096     // Basic vector operators
00097     AkMatrix3x3 operator/=(const AkReal32 f)
00098     {
00099         for (int i = 0; i < 3; i++)
00100         {
00101             for (int j = 0; j < 3; j++)
00102             {
00103                 m_Data[i][j] /= f;
00104             }
00105         }
00106         return *this;
00107     }
00108 
00109     AkReal32 m_Data[3][3];
00110 };
00111 
00112 class Ak4DVector
00113 {
00114 public:
00115     //-----------------------------------------------------------
00116     // Constructor/Destructor functions
00117     Ak4DVector()
00118     {
00119         v[0] = 0.0f;
00120         v[1] = 0.0f;
00121         v[2] = 0.0f;
00122         v[3] = 0.0f;
00123     }
00124 
00125     Ak4DVector(const AkVector& b)
00126     {
00127         v[0] = b.X;
00128         v[1] = b.Y;
00129         v[2] = b.Z;
00130         v[3] = 1;
00131     }
00132 
00133     ~Ak4DVector(){}
00134 
00135     //-----------------------------------------------------------
00136     // Basic vector operators
00137     Ak4DVector operator=(const Ak4DVector& b)
00138     {
00139         v[0] = b.v[0];
00140         v[1] = b.v[1];
00141         v[2] = b.v[2];
00142         v[3] = b.v[3];
00143 
00144         return *this;
00145     }
00146 
00147     Ak4DVector operator/=(const AkReal32 f)
00148     {
00149         v[0] = v[0] / f;
00150         v[1] = v[1] / f;
00151         v[2] = v[2] / f;
00152         v[3] = v[3] / f;
00153 
00154         return *this;
00155     }
00156 
00157     Ak4DVector operator-(const Ak4DVector& b) const
00158     {
00159         Ak4DVector p;
00160 
00161         p.v[0] = v[0] - b.v[0];
00162         p.v[1] = v[1] - b.v[1];
00163         p.v[2] = v[2] - b.v[2];
00164         p.v[3] = v[3] - b.v[3];
00165 
00166         return p;
00167     }
00168 
00169     AkReal32    v[4];
00170 };
00171 
00172 struct Ak3DIntVector
00173 {
00174 public:
00175     Ak3DIntVector(){}
00176     Ak3DIntVector(AkInt32 x, AkInt32 y, AkInt32 z)
00177     {
00178         X = x;
00179         Y = y;
00180         Z = z;
00181     }
00182 
00183     ~Ak3DIntVector(){}
00184 
00185     AkInt32     X;  ///< X Position
00186     AkInt32     Y;  ///< Y Position
00187     AkInt32     Z;  ///< Z Position
00188 };
00189 
00190 class Ak3DVector
00191 {
00192 public:
00193     //-----------------------------------------------------------
00194     // Constructor/Destructor functions
00195     Ak3DVector() :
00196         X(0.f),
00197         Y(0.f),
00198         Z(0.f)
00199     {}
00200 
00201     Ak3DVector(
00202         AkReal32                    x,
00203         AkReal32                    y,
00204         AkReal32                    z)
00205     {
00206         X = x;
00207         Y = y;
00208         Z = z;
00209     }
00210     Ak3DVector(const AkVector& b)
00211     {
00212         X = b.X;
00213         Y = b.Y;
00214         Z = b.Z;
00215     }
00216     explicit Ak3DVector(const AKSIMD_V4F32& in_v4f32)
00217     {
00218         X = AKSIMD_GETELEMENT_V4F32(in_v4f32, 0);
00219         Y = AKSIMD_GETELEMENT_V4F32(in_v4f32, 1);
00220         Z = AKSIMD_GETELEMENT_V4F32(in_v4f32, 2);
00221     }
00222     AkForceInline AKSIMD_V4F32 PointV4F32() const
00223     {
00224         AKSIMD_V4F32 v4f32;
00225         AKSIMD_GETELEMENT_V4F32(v4f32, 0) = X;
00226         AKSIMD_GETELEMENT_V4F32(v4f32, 1) = Y;
00227         AKSIMD_GETELEMENT_V4F32(v4f32, 2) = Z;
00228         AKSIMD_GETELEMENT_V4F32(v4f32, 3) = 1.f;
00229         return v4f32;
00230     }
00231     AkForceInline AKSIMD_V4F32 VectorV4F32() const
00232     {
00233         AKSIMD_V4F32 v4f32;
00234         AKSIMD_GETELEMENT_V4F32(v4f32, 0) = X;
00235         AKSIMD_GETELEMENT_V4F32(v4f32, 1) = Y;
00236         AKSIMD_GETELEMENT_V4F32(v4f32, 2) = Z;
00237         AKSIMD_GETELEMENT_V4F32(v4f32, 3) = 0.f;
00238         return v4f32;
00239     }
00240     ~Ak3DVector() {}
00241 
00242     void Zero()
00243     {
00244         X = 0.f;
00245         Y = 0.f;
00246         Z = 0.f;
00247     }
00248 
00249 
00250     //-----------------------------------------------------------
00251     // Basic vector operators
00252     AkForceInline bool operator==(const Ak3DVector& b) const
00253     {
00254         return X == b.X && Y == b.Y && Z == b.Z;
00255     }
00256 
00257     AkForceInline bool operator!=(const Ak3DVector& b) const
00258     {
00259         return X != b.X || Y != b.Y || Z != b.Z;
00260     }
00261 
00262     AkForceInline Ak3DVector operator=(const Ak3DVector& b)
00263     {
00264         X = b.X;
00265         Y = b.Y;
00266         Z = b.Z;
00267 
00268         return *this;
00269     }
00270 
00271     AkForceInline Ak3DVector operator=(const AkVector& b)
00272     {
00273         X = b.X;
00274         Y = b.Y;
00275         Z = b.Z;
00276 
00277         return *this;
00278     }
00279 
00280     AkForceInline bool operator<(const Ak3DVector& b) const
00281     {
00282         return X < b.X && Y < b.Y && Z < b.Z;
00283     }
00284 
00285     AkForceInline bool operator<=(const Ak3DVector& b) const
00286     {
00287         return X <= b.X && Y <= b.Y && Z <= b.Z;
00288     }
00289 
00290     AkForceInline bool operator>(const Ak3DVector b) const
00291     {
00292         return X > b.X && Y > b.Y && Z > b.Z;
00293     }
00294 
00295     AkForceInline bool operator>=(const Ak3DVector& b) const
00296     {
00297         return X >= b.X && Y >= b.Y && Z >= b.Z;
00298     }
00299 
00300     AkForceInline Ak3DVector operator*=(const AkReal32 f)
00301     {
00302         X = X * f;
00303         Y = Y * f;
00304         Z = Z * f;
00305 
00306         return *this;
00307     }
00308 
00309     AkForceInline Ak3DVector operator/=(const AkReal32 f)
00310     {
00311         AkReal32 oneoverf = 1.f / f;
00312         X = X * oneoverf;
00313         Y = Y * oneoverf;
00314         Z = Z * oneoverf;
00315 
00316         return *this;
00317     }
00318 
00319     AkForceInline Ak3DVector operator*(const Ak3DVector v2) const
00320     {
00321         Ak3DVector v;
00322 
00323         v.X = X * v2.X;
00324         v.Y = Y * v2.Y;
00325         v.Z = Z * v2.Z;
00326 
00327         return v;
00328     }
00329 
00330     AkForceInline Ak3DVector operator*(const AkReal32 f) const
00331     {
00332         Ak3DVector v;
00333 
00334         v.X = X * f;
00335         v.Y = Y * f;
00336         v.Z = Z * f;
00337 
00338         return v;
00339     }
00340 
00341     AkForceInline Ak3DVector operator/(const AkReal32 f) const
00342     {
00343         Ak3DVector v;
00344         AkReal32 oneoverf = 1.f / f;
00345 
00346         v.X = X * oneoverf;
00347         v.Y = Y * oneoverf;
00348         v.Z = Z * oneoverf;
00349 
00350         return v;
00351     }
00352 
00353     AkForceInline Ak3DVector operator+(const AkReal32 f) const
00354     {
00355         Ak3DVector v;
00356 
00357         v.X = X + f;
00358         v.Y = Y + f;
00359         v.Z = Z + f;
00360 
00361         return v;
00362     }
00363 
00364     AkForceInline Ak3DVector operator-(const AkReal32 f) const
00365     {
00366         Ak3DVector v;
00367 
00368         v.X = X - f;
00369         v.Y = Y - f;
00370         v.Z = Z - f;
00371 
00372         return v;
00373     }
00374 
00375     AkForceInline Ak3DVector operator+(const Ak3DVector& b) const
00376     {
00377         Ak3DVector v;
00378 
00379         v.X = X + b.X;
00380         v.Y = Y + b.Y;
00381         v.Z = Z + b.Z;
00382 
00383         return v;
00384     }
00385 
00386     AkForceInline Ak3DVector operator-(const Ak3DVector& b) const
00387     {
00388         Ak3DVector v;
00389 
00390         v.X = X - b.X;
00391         v.Y = Y - b.Y;
00392         v.Z = Z - b.Z;
00393 
00394         return v;
00395     }
00396 
00397     AkForceInline operator AkVector()
00398     {
00399         AkVector v;
00400         v.X = X; v.Y = Y; v.Z = Z;
00401 
00402         return v;
00403     }
00404 
00405 
00406     AkForceInline static Ak3DVector Min(const Ak3DVector& A, const Ak3DVector& B)
00407     {
00408         Ak3DVector min;
00409 
00410         min.X = AkMin(A.X, B.X);
00411         min.Y = AkMin(A.Y, B.Y);
00412         min.Z = AkMin(A.Z, B.Z);
00413 
00414         return min;
00415     }
00416 
00417     AkForceInline static Ak3DVector Max(const Ak3DVector& A, const Ak3DVector& B)
00418     {
00419         Ak3DVector max;
00420 
00421         max.X = AkMax(A.X, B.X);
00422         max.Y = AkMax(A.Y, B.Y);
00423         max.Z = AkMax(A.Z, B.Z);
00424 
00425         return max;
00426     }
00427 
00428     //-----------------------------------------------------------
00429     // Conversion functions
00430     AkForceInline Ak3DVector Rotate180X_90Y() const
00431     {
00432         Ak3DVector v;
00433 
00434         v.X = -X;
00435         v.Y = Z;
00436         v.Z = -Y;
00437 
00438         return v;
00439     }
00440 
00441     AkForceInline Ak3DVector SphericalToCartesian(
00442         const AkReal32              azimuth,
00443         const AkReal32              elevation)
00444     {
00445         AkReal32 cosElevation = cosf(elevation);
00446         X = cosf(azimuth) * cosElevation;
00447         Y = sinf(azimuth) * cosElevation;
00448         Z = sinf(elevation);
00449 
00450         return *this;
00451     }
00452 
00453     // Determinant of 3 column vectors.
00454     static AkReal32 Determinant(
00455         const Ak3DVector &          a,
00456         const Ak3DVector &          b,
00457         const Ak3DVector &          c)
00458     {
00459         return  (a.X*b.Y*c.Z + a.Y*b.Z*c.X + a.Z*b.X*c.Y) -
00460             (a.Z*b.Y*c.X + a.Y*b.X*c.Z + a.X*b.Z*c.Y);
00461     }
00462 
00463     // Convert a vector to a different base
00464     AkForceInline Ak3DVector LinearCombination(
00465         const Ak3DVector&           A,
00466         const Ak3DVector&           B,
00467         const Ak3DVector&           C) const
00468     {
00469         Ak3DVector v;
00470 
00471         AkReal32 d = Determinant(A, B, C);
00472 
00473         if (d < AKVECTORS_EPSILON && d > -AKVECTORS_EPSILON)
00474         {
00475             v.X = 0.0f; v.Y = 0.0f; v.Z = 0.0f;
00476             return v;
00477         }
00478 
00479         // http://mathworld.wolfram.com/MatrixInverse.html
00480         Ak3DVector invA = Ak3DVector(B.Y*C.Z - B.Z*C.Y, A.Z*C.Y - A.Y*C.Z, A.Y*B.Z - A.Z*B.Y);
00481         Ak3DVector invB = Ak3DVector(B.Z*C.X - B.X*C.Z, A.X*C.Z - A.Z*C.X, A.Z*B.X - A.X*B.Z);
00482         Ak3DVector invC = Ak3DVector(B.X*C.Y - B.Y*C.X, A.Y*C.X - A.X*C.Y, A.X*B.Y - A.Y*B.X);
00483 
00484         AkReal32 oneover_d = 1.f / d;
00485         invA *= oneover_d;
00486         invB *= oneover_d;
00487         invC *= oneover_d;
00488 
00489         // Project coordinates using a vector to matrix multiplication
00490         v.X = X * invA.X + Y * invB.X + Z * invC.X;
00491         v.Y = X * invA.Y + Y * invB.Y + Z * invC.Y;
00492         v.Z = X * invA.Z + Y * invB.Z + Z * invC.Z;
00493 
00494         // v /= v.Length();
00495 
00496         return v;
00497     }
00498 
00499     AkForceInline void Normalize()
00500     {
00501         AkReal32 l = Length();
00502         //AKASSERT(l != 0.0f);
00503 
00504         if (l == 0.f)
00505             X = Y = Z = 0;
00506 
00507         X /= l;
00508         Y /= l;
00509         Z /= l;
00510     }
00511 
00512     AkForceInline AkReal32 L2_Norm() const
00513     {
00514         return sqrtf(X*X + Y*Y + Z*Z);
00515     }
00516 
00517     AkForceInline AkReal32 DotProduct(const Ak3DVector& v2) const
00518     {
00519         return X*v2.X + Y*v2.Y + Z*v2.Z;
00520     }
00521 
00522     AkForceInline AkReal32 Dot(const Ak3DVector& v2) const
00523     {
00524         return DotProduct(v2);
00525     }
00526 
00527     AkForceInline Ak3DVector Cross(const Ak3DVector& v) const
00528     {
00529         Ak3DVector uxv;
00530         const Ak3DVector& u = *this;
00531 
00532         uxv.X = u.Y*v.Z - u.Z*v.Y;
00533         uxv.Y = u.Z*v.X - u.X*v.Z;
00534         uxv.Z = u.X*v.Y - u.Y*v.X;
00535 
00536         return uxv;
00537     }
00538     //
00539     AkForceInline AkReal32 Length() const
00540     {
00541         return sqrtf(X*X + Y*Y + Z*Z);
00542     }
00543 
00544     AkForceInline AkReal32 LengthSquared() const
00545     {
00546         return X*X + Y*Y + Z*Z;
00547     }
00548 
00549     // Usefull in VBAP algorithm, only points that are a positive linear composition matters.
00550     AkForceInline bool IsAllPositive() const
00551     {
00552         const AkReal32 POSITIVE_TEST_EPSILON = 0.00001f;
00553         return X >= -POSITIVE_TEST_EPSILON &&
00554             Y >= -POSITIVE_TEST_EPSILON &&
00555             Z >= -POSITIVE_TEST_EPSILON;
00556     }
00557 
00558     AkForceInline Ak3DVector Abs() const
00559     {
00560         Ak3DVector abs = *this;
00561         abs.X = (AkReal32)fabs(abs.X);
00562         abs.Y = (AkReal32)fabs(abs.Y);
00563         abs.Z = (AkReal32)fabs(abs.Z);
00564         return abs;
00565     }
00566 
00567     AkReal32                        X;
00568     AkReal32                        Y;
00569     AkReal32                        Z;
00570 };
00571 
00572 class Ak2DVector
00573 {
00574 public:
00575     //-----------------------------------------------------------
00576     // Constructor/Destructor functions
00577     Ak2DVector(){}
00578     ~Ak2DVector(){}
00579 
00580     Ak2DVector(
00581         AkReal32                    x,
00582         AkReal32                    y)
00583     {
00584         X = x;
00585         Y = y;
00586     }
00587 
00588     //-----------------------------------------------------------
00589     // Basic vector operators
00590     AkForceInline Ak2DVector operator=(const Ak2DVector& b)
00591     {
00592         X = b.X;
00593         Y = b.Y;
00594 
00595         return *this;
00596     }
00597 
00598     AkForceInline Ak2DVector operator=(const AkSphericalCoord& b)
00599     {
00600         X = b.theta;
00601         Y = b.phi;
00602 
00603         return *this;
00604     }
00605 
00606     Ak2DVector operator-(const Ak2DVector& b) const
00607     {
00608         Ak2DVector v;
00609 
00610         v.X = X - b.X;
00611         v.Y = Y - b.Y;
00612 
00613         return v;
00614     }
00615 
00616     Ak2DVector operator*=(const AkReal32 f)
00617     {
00618         X = X * f;
00619         Y = Y * f;
00620 
00621         return *this;
00622     }
00623 
00624     Ak2DVector operator/=(const AkReal32 f)
00625     {
00626         AkReal32 oneoverf = 1.f / f;
00627         X = X * oneoverf;
00628         Y = Y * oneoverf;
00629 
00630         return *this;
00631     }
00632 
00633     AkForceInline bool operator==(const Ak2DVector& b) const
00634     {
00635         return b.X == X && b.Y == Y;
00636     }
00637 
00638     AkForceInline bool operator!=(const Ak2DVector& b) const
00639     {
00640         return b.X != X && b.Y != Y;
00641     }
00642 
00643     AkForceInline AkReal32 Length() const
00644     {
00645         return sqrtf(X*X+Y*Y);
00646     }
00647 
00648     //-----------------------------------------------------------
00649     // Conversion functions
00650     AkForceInline Ak2DVector CartesianToSpherical( const Ak3DVector& in_Cartesian )
00651     {
00652         // (radial, azimuth, elevation)
00653         AkReal32 r = sqrtf( in_Cartesian.X*in_Cartesian.X + in_Cartesian.Y*in_Cartesian.Y + in_Cartesian.Z*in_Cartesian.Z);
00654         AKASSERT( r != 0);
00655 
00656         X = atan2f(in_Cartesian.Y, in_Cartesian.X);
00657         Y = asinf(in_Cartesian.Z / r);
00658 
00659         NormalizeSpherical();
00660 
00661         return *this;
00662     }
00663 
00664     AkForceInline Ak2DVector LinearCombination(
00665         const Ak2DVector&           A,
00666         const Ak2DVector&           B) const
00667     {
00668         Ak2DVector v;
00669 
00670         // Project coordinates using a vector to matrix multiplication
00671         AkReal32 d = (A.X*B.Y - A.Y*B.X);
00672 
00673         if (d < AKVECTORS_EPSILON && d > -AKVECTORS_EPSILON)
00674         {
00675             v.X = 0.0f; v.Y = 0.0f;
00676             return v;
00677         }
00678 
00679         Ak2DVector invA = Ak2DVector( B.Y, -A.Y );
00680         Ak2DVector invB = Ak2DVector( -B.X, A.X );
00681 
00682         AkReal32 oneover_d = 1.f / d;
00683         invA *= oneover_d;
00684         invB *= oneover_d;
00685 
00686         v.X = X * invA.X + Y * invB.X;
00687         v.Y = X * invA.Y + Y * invB.Y;
00688         // v /= v.Length();
00689 
00690         return v;
00691     }
00692 
00693     AkForceInline Ak2DVector NormalizeSpherical() const
00694     {
00695         /*
00696             Normalise spherical coordinates.
00697                 X (azimuthal)   -> [-PI, PI],       circle lies on xy plan,         0 is on X axix
00698                 Y (elevation)   -> [-PI/2, PI/2],   half circle on Z axis,          0 on XY plan, PI/2 straigt up on Z axis.
00699         */
00700 
00701         Ak2DVector v;
00702 
00703         v.X = X;
00704         v.Y = Y;
00705 
00706         if (X > AKVECTORS_PI)
00707             v.X = X - AKVECTORS_TWOPI;
00708 
00709         if (X < -AKVECTORS_PI)
00710             v.X = X + AKVECTORS_TWOPI;
00711 
00712         if (Y > AKVECTORS_PIOVERTWO)
00713             v.Y = Y - AKVECTORS_PI;
00714 
00715         if (Y < -AKVECTORS_PIOVERTWO)
00716             v.Y = Y + AKVECTORS_PI;
00717 
00718         AKASSERT(X<AKVECTORS_PI);
00719         AKASSERT(Y<AKVECTORS_PIOVERTWO);
00720 
00721         return v;
00722     }
00723 
00724     AkForceInline void NormalizeSpherical()
00725     {
00726         /*
00727             Normalise spherical coordinates.
00728                 X (azimuthal)   -> [-PI, PI],       circle lies on xy plan,     0 is on X axix
00729                 Y (elevation)   -> [-PI/2, PI/2],   half circle on Z axis,      0 on XY plan, PI/2 straigt up on Z axis.
00730         */
00731 
00732         if (X > AKVECTORS_PI)
00733             X = X - AKVECTORS_TWOPI;
00734 
00735         if (X < -AKVECTORS_PI)
00736             X = X + AKVECTORS_TWOPI;
00737 
00738         if (Y > AKVECTORS_PIOVERTWO)
00739             Y = Y - AKVECTORS_PI;
00740 
00741         if (Y < -AKVECTORS_PIOVERTWO)
00742             Y = Y + AKVECTORS_PI;
00743     }
00744 
00745     // Useful in VBAP algorithm, only points that are a positive linear composition matters.
00746     AkForceInline bool IsAllPositive() const
00747     {
00748         const AkReal32 POSITIVE_TEST_EPSILON = 0.00001f; //0.005f;
00749         return X >= -POSITIVE_TEST_EPSILON &&
00750             Y >= -POSITIVE_TEST_EPSILON;
00751     }
00752 
00753     AkReal32                        X;
00754     AkReal32                        Y;
00755 };
00756 
00757 struct AkIntersectionPoints
00758 {
00759     Ak3DVector points[2];
00760     AkUInt32 count;
00761 };
00762 
00763 class AkLine
00764 {
00765 public:
00766     AkLine()
00767     {
00768         mint = 1.175494351e-38F;
00769         maxt = 3.402823466e+38F;
00770     }
00771 
00772     AkLine(
00773         Ak3DVector                  in_L,
00774         Ak3DVector                  in_P
00775         )
00776     {
00777         L = in_L;
00778         P = in_P;
00779         mint = 1.175494351e-38F;
00780         maxt = 3.402823466e+38F;
00781     }
00782 
00783     Ak3DVector PointAt(AkReal32 t) const
00784     {
00785         return P + L*t;
00786     }
00787 
00788     bool Intersect(
00789         Ak3DVector A,
00790         Ak3DVector B)
00791     {
00792         Ak3DVector L2 = B - A;
00793 
00794         /*
00795         a (V1 X V2) = (P2 - P1) X V2
00796         If the lines intersect at a single point, then the resultant vectors
00797         on each side of this equation must be parallel, and the left side must
00798         not be the zero vector. We should check to make sure that this is
00799         true. Once we have checked this, we can solve for 'a' by taking the
00800         magnitude of each side and dividing. If the resultant vectors are
00801         parallel, but in opposite directions, then 'a' is the negative of the
00802         ratio of magnitudes. Once we have 'a' we can go back to the equation
00803         for L1 to find the intersection point.
00804         */
00805         Ak3DVector V1 = L;
00806         Ak3DVector V2 = B - A;
00807         Ak3DVector P1 = P;
00808         Ak3DVector P2 = A;
00809 
00810         // k(V1 X V2) = (A - P) X V2
00811 
00812         Ak3DVector v1CrossV2 = V1.Cross(V2);
00813         AkReal32 det = Ak3DVector::Determinant(
00814             P2 - P1,
00815             V2,
00816             v1CrossV2
00817             );
00818         AkReal32 t = det / v1CrossV2.LengthSquared();
00819 
00820         det = Ak3DVector::Determinant(
00821             P2 - P1,
00822             V1,
00823             v1CrossV2
00824             );
00825         AkReal32 s = det / v1CrossV2.LengthSquared();
00826 
00827         AkReal32 distsqrd = ((P2 + V2*s) - (P1 + V1*t)).LengthSquared();
00828 
00829         if ((AkReal32)fabs(v1CrossV2.L2_Norm()) >= AKVECTORS_EPSILON
00830             && distsqrd < 0.001
00831             && s <= 1.0f )
00832         {
00833 #ifdef AKPORTALS_DEBUG
00834             Ak3DVector minPoint = PointAt(t);
00835 
00836             char msg[256];
00837             sprintf(msg, "L1a=[%0.2f,%0.2f,%0.2f];\n", P.X, P.Y, P.Z); AKPLATFORM::OutputDebugMsg(msg);
00838             sprintf(msg, "L1b=[%0.2f,%0.2f,%0.2f];\n", V1.X + P.X, V1.Y + P.Y, V1.Z + P.Z); AKPLATFORM::OutputDebugMsg(msg);
00839             sprintf(msg, "L2a=[%0.2f,%0.2f,%0.2f];\n", A.X, A.Y, A.Z); AKPLATFORM::OutputDebugMsg(msg);
00840             sprintf(msg, "L2b=[%0.2f,%0.2f,%0.2f];\n", B.X, B.Y, B.Z); AKPLATFORM::OutputDebugMsg(msg);
00841             sprintf(msg, "%% t=%0.2f Min t=%0.2f, Max t=%0.2f\n", t, mint, maxt); AKPLATFORM::OutputDebugMsg(msg);
00842             sprintf(msg, "intrPoint=[%0.2f,%0.2f,%0.2f];\n", minPoint.X, minPoint.Y, minPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
00843             sprintf(msg, "\n"); AKPLATFORM::OutputDebugMsg(msg);
00844 #endif
00845 
00846             mint = AkMin(mint, t);
00847             maxt = AkMax(maxt, t);
00848             
00849             return true;
00850         }
00851 
00852 #ifdef AKPORTALS_DEBUG
00853     //  char msg[256];
00854     //  sprintf(msg, "%% DISCARTED t=%0.2f Min t=%0.2f, Max t=%0.2f\n", t, mint, maxt); AKPLATFORM::OutputDebugMsg(msg);
00855 #endif
00856         return false;
00857     }
00858 
00859     Ak3DVector L;
00860     Ak3DVector P;
00861 
00862     AkReal32 mint;
00863     AkReal32 maxt;
00864 };
00865 
00866 class AkPlane
00867 {
00868 public:
00869     AkPlane()
00870     {
00871     }
00872 
00873     AkPlane(
00874         Ak3DVector                  in_p1,
00875         Ak3DVector                  in_p2,
00876         Ak3DVector                  in_p4
00877         )
00878     {
00879         SetPlane(
00880             in_p1,
00881             in_p2,
00882             in_p4);
00883     }
00884 
00885     ~AkPlane()
00886     {
00887     }
00888 
00889     void SetPlane(
00890         Ak3DVector                  in_p1,
00891         Ak3DVector                  in_p2,
00892         Ak3DVector                  in_p4
00893         )
00894     {
00895         // Reorder A-B-C to clockwwise if necessary
00896         AKASSERT(in_p1.X < 100000 && in_p1.X > -100000);
00897         AKASSERT(in_p1.Y < 100000 && in_p1.Y > -100000);
00898         AKASSERT(in_p1.Z < 100000 && in_p1.Z > -100000);
00899 
00900         AKASSERT(in_p2.X < 100000 && in_p2.X > -100000);
00901         AKASSERT(in_p2.Y < 100000 && in_p2.Y > -100000);
00902         AKASSERT(in_p2.Z < 100000 && in_p2.Z > -100000);
00903 
00904         AKASSERT(in_p4.X < 100000 && in_p4.X > -100000);
00905         AKASSERT(in_p4.Y < 100000 && in_p4.Y > -100000);
00906         AKASSERT(in_p4.Z < 100000 && in_p4.Z > -100000);
00907 
00908         p1 = in_p1;
00909         p2 = in_p2;
00910         p4 = in_p4;
00911 
00912         SetNormal();
00913 
00914         // Ax + By + Cz + D = 0
00915         // Find D using the normal and a point
00916         D = -(N.X*p1.X) - (N.Y*p1.Y) - (N.Z*p1.Z);
00917     }
00918 
00919 #define EPSILON 0.01f
00920     bool DoesRayIntersect(
00921         const Ak3DVector&           in_Origin,
00922         const Ak3DVector&           in_Destination,
00923         Ak3DVector&                 out_Intersection
00924         ) const
00925     {
00926         AkReal32 A = N.X;
00927         AkReal32 B = N.Y;
00928         AkReal32 C = N.Z;
00929 
00930         Ak3DVector ray = in_Destination - in_Origin;
00931         AkReal32 rayLength = ray.Length();
00932 
00933         Ak3DVector intersect;
00934 
00935         // If ray is < EPSILON, use on of the point directly for the test and skip the linear projection
00936         if (rayLength <= EPSILON)
00937         {
00938             Ak3DVector temp = in_Origin - p1;
00939             AkReal32 dot = temp.DotProduct(N);
00940             if (dot < EPSILON && dot > -EPSILON)
00941             {
00942                 intersect = in_Origin;
00943             }
00944             else
00945             {
00946                 // For debug only, to remove
00947                 out_Intersection = p1;
00948                 return false;
00949             }
00950 
00951         }
00952         else
00953         {
00954             // Normalize ray
00955             ray.Normalize();
00956 
00957             // TODO: possible fix for all edge cases
00958             // 1) if ray len ~= 0, only check if one of the point is on target, ie: assign the intersect point
00959 
00960             // Is ray parallel to the plane?
00961             if ((A*ray.X + B*ray.Y + C*ray.Z) == 0.0f)
00962             {
00963                 // For debug only, to remove
00964                 AkReal32 t = -(A*in_Origin.X + B*in_Origin.Y + C*in_Origin.Z + D) / (A*ray.X + B*ray.Y + C*ray.Z);
00965                 intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
00966                 out_Intersection = intersect; // For debugging
00967                 return false;
00968             }
00969 
00970 
00971             // Distance along the ray where reflector is hit
00972             AkReal32 t = -(A*in_Origin.X + B*in_Origin.Y + C*in_Origin.Z + D) / (A*ray.X + B*ray.Y + C*ray.Z);
00973 
00974             // Is the ray going towards the plane? Is it long enough?
00975             if (t < -EPSILON || t >(rayLength + EPSILON))
00976             {
00977                 // For debug only, to remove
00978                 intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
00979                 out_Intersection = intersect; // For debugging
00980                 return false; // The ray doesn't intersect
00981             }
00982 
00983             // Find the coordinate of intersection on the plane
00984             intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
00985         }
00986         ///////////////////////////////////////
00987         //
00988         //      p2____v3____p3
00989         //      |     .     |
00990         //      ^   inter   v4
00991         //      v1          v
00992         //      |           |
00993         //      p1__ v2>___p4
00994 
00995         Ak3DVector v1 = p2 - p1;
00996         Ak3DVector v2 = p4 - p1;
00997         Ak3DVector vInter1 = intersect - p1;
00998 
00999         Ak3DVector p3 = p4 + v1;
01000         Ak3DVector v3 = p2 - p3;
01001         Ak3DVector v4 = p4 - p3;
01002         Ak3DVector vInter2 = intersect - p3;
01003 
01004         v1.Normalize(); v2.Normalize(); v3.Normalize(); v4.Normalize(); vInter1.Normalize(); vInter2.Normalize();
01005 
01006         // Since it's a square, the angle between the point of intersection and any segment of the pannel should be < 90 degree,
01007         // therefore the dot product of the two normalized vectors should be > 0
01008         AkReal32 dot1 = v1.DotProduct(vInter1);
01009         AkReal32 dot2 = v2.DotProduct(vInter1);
01010         AkReal32 dot3 = v3.DotProduct(vInter2);
01011         AkReal32 dot4 = v4.DotProduct(vInter2);
01012 
01013         out_Intersection = intersect;
01014 
01015         return dot1 >= -EPSILON && dot2 >= -EPSILON && dot3 >= -EPSILON && dot4 >= -EPSILON;
01016     }
01017 
01018     AkReal32 DistPoint_to_Plane(
01019         Ak3DVector          in_P,
01020         Ak3DVector&         out_B) const
01021     {
01022         AkReal32 distance = (AkReal32)(AkReal32)fabs(N.X * in_P.X + N.Y * in_P.Y + N.Z * in_P.Z + D);
01023 
01024         Ak3DVector pointToPlane = N;
01025         pointToPlane *= distance;
01026 
01027         out_B = in_P + pointToPlane;
01028 
01029         return (AkReal32)fabs(distance);
01030     }
01031 
01032     void SetReflection(
01033         AkReal32*           out_mat) const
01034     {
01035         // http://ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pd
01036         /* m_pReflectionMatrix
01037         reflection on z axis
01038 
01039         P0 (x0, y0, z0), P1 (x1, y1, z1) and P2 (x2, y2, z2),
01040         normal = (cx, cy, cz)
01041         d = -CxX0 - CyY0 - CzZ0
01042 
01043         Reflect =   1-2Cx^2     -2CxCy      -2CxCz      -2Cxd
01044         -2CxCy      1-2Cy^2     -2CyCz      -2Cyd
01045         -2CxCz      -2CyCz      1-2Cz^2     -2Czd
01046         0           0           0           1
01047         */
01048 
01049         AkReal32 d = -(N.X*p1.X) - (N.Y*p1.Y) - (N.Z*p1.Z);
01050 
01051         out_mat[0] = 1 - 2 * N.X*N.X;       out_mat[1] = -2 * N.X*N.Y;              out_mat[2] = -2 * N.X*N.Z;              out_mat[3] = -2 * N.X*d;
01052         out_mat[0 + 4] = -2 * N.X*N.Y;      out_mat[1 + 4] = 1 - 2 * N.Y*N.Y;       out_mat[2 + 4] = -2 * N.Y*N.Z;          out_mat[3 + 4] = -2 * N.Y*d;
01053         out_mat[0 + 8] = -2 * N.X*N.Z;      out_mat[1 + 8] = -2 * N.Y*N.Z;          out_mat[2 + 8] = 1 - 2 * N.Z*N.Z;       out_mat[3 + 8] = -2 * N.Z*d;
01054         out_mat[0 + 12] = 0;                out_mat[1 + 12] = 0;                    out_mat[2 + 12] = 0;                    out_mat[3 + 12] = 1;
01055     }
01056 
01057     Ak3DVector GetN() const { return N; }
01058     AkReal32 GetD() const { return D; }
01059 
01060     bool FindIntersectionPoints(
01061         const AkPlane& in_PlaneB,
01062         AkIntersectionPoints& out_Intrs) const
01063     {
01064         out_Intrs.count = 0;
01065 
01066         // Use vector to solve A
01067 
01068         Ak3DVector point;
01069 
01070         Ak3DVector N1 = N;
01071         Ak3DVector N2 = in_PlaneB.GetN();
01072         AkReal32 D1 = D;
01073         AkReal32 D2 = in_PlaneB.GetD();
01074 
01075         Ak3DVector L = N1.Cross(N2);
01076         if (L.Length() < 0.001f)
01077         {
01078             return false; // The two planes are parallel
01079         }
01080 
01081         AkUInt8 pivotAxis = 0;
01082 
01083         if ((AkReal32)fabs(L.Y) > (AkReal32)fabs(L.X))
01084         {
01085             pivotAxis = 1;
01086             if ((AkReal32)fabs(L.Z) > (AkReal32)fabs(L.Y))
01087             {
01088                 pivotAxis = 2;
01089             }
01090         }
01091         else if ((AkReal32)fabs(L.Z) > (AkReal32)fabs(L.X))
01092         {
01093             pivotAxis = 2;
01094         }
01095 
01096         /*
01097         Pu = ( N1v*D2 - N2v*D1 ) / Lw
01098         Pv = ( N2u*D1 - N1u*D2 ) / Lw
01099         Pz = 0
01100         */
01101 
01102         switch (pivotAxis)
01103         {
01104         case 0:
01105             AKASSERT((AkReal32)fabs(L.X) > AKVECTORS_EPSILON);
01106             point.X = 0.f;
01107             point.Y = (N1.Z*D2 - N2.Z*D1) / L.X;
01108             point.Z = (N2.Y*D1 - N1.Y*D2) / L.X;
01109             break;
01110         case 1:
01111             AKASSERT((AkReal32)fabs(L.Y) > AKVECTORS_EPSILON);
01112             point.X = (N1.Z*D2 - N2.Z*D1) / L.Y;
01113             point.Y = 0.f;
01114             point.Z = (N2.X*D1 - N1.X*D2) / L.Y;
01115             break;
01116         case 2:
01117             AKASSERT((AkReal32)fabs(L.Z) > AKVECTORS_EPSILON);
01118             point.X = (N1.Y*D2 - N2.Y*D1) / L.Z;
01119             point.Y = (N2.X*D1 - N1.X*D2) / L.Z;
01120             point.Z = 0.f;
01121             break;
01122         };
01123 
01124 
01125 
01126         L.Normalize();
01127 
01128         AkLine intrLine = AkLine(L, point);
01129         AkLine intrLine2 = AkLine(L, point);
01130 
01131         //in_PlaneB.GetP1()
01132 
01133         // find min max
01134         AkUInt32 cpt = 0;
01135         AkUInt32 cpt2 = 0;
01136         Ak3DVector p3 = GetP2() + (GetP4() - GetP1());
01137 
01138 #ifdef AKPORTALS_DEBUG
01139         char msg[256];
01140         sprintf(msg, "P1a=[%0.2f,%0.2f,%0.2f];\n", GetP1().X, GetP1().Y, GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01141         sprintf(msg, "P2a=[%0.2f,%0.2f,%0.2f];\n", GetP2().X, GetP2().Y, GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01142         sprintf(msg, "P4a=[%0.2f,%0.2f,%0.2f];\n", GetP4().X, GetP4().Y, GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01143 
01144         sprintf(msg, "P1b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP1().X, in_PlaneB.GetP1().Y, in_PlaneB.GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01145         sprintf(msg, "P2b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP2().X, in_PlaneB.GetP2().Y, in_PlaneB.GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01146         sprintf(msg, "P4b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP4().X, in_PlaneB.GetP4().Y, in_PlaneB.GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01147 
01148         sprintf(msg, "line1=[%0.2f,%0.2f,%0.2f];\n", point.X + L.X*1000.f, point.Y + L.Y*1000.f, point.Z + L.Z*1000.f); AKPLATFORM::OutputDebugMsg(msg);
01149         sprintf(msg, "line2=[%0.2f,%0.2f,%0.2f];\n", point.X - L.X*1000.f, point.Y - L.Y*500.f, point.Z - L.Z*500.f); AKPLATFORM::OutputDebugMsg(msg);
01150 
01151 
01152         sprintf(msg, "%% Plane intersec\n"); AKPLATFORM::OutputDebugMsg(msg);
01153 #endif
01154         // for the four lines in rectangle
01155         // Find where the line is crossing with plane A
01156         if (intrLine.Intersect(GetP1(), GetP2())) cpt++;
01157         if (intrLine.Intersect(GetP1(), GetP4())) cpt++;
01158         if (intrLine.Intersect(GetP2(), p3)) cpt++;
01159         if (intrLine.Intersect(p3, GetP4())) cpt++;
01160         //AKASSERT(cpt == 2);
01161 
01162 #ifdef AKPORTALS_DEBUG
01163         sprintf(msg, "%% Portal intersec\n"); AKPLATFORM::OutputDebugMsg(msg);
01164 #endif
01165 
01166         // Find where the line is crossing with plane B
01167         p3 = in_PlaneB.GetP2() + (in_PlaneB.GetP4() - in_PlaneB.GetP1());
01168         if (intrLine2.Intersect(in_PlaneB.GetP1(), in_PlaneB.GetP2())) cpt2++;
01169         if (intrLine2.Intersect(in_PlaneB.GetP1(), in_PlaneB.GetP4())) cpt2++;
01170         if (intrLine2.Intersect(in_PlaneB.GetP2(), p3)) cpt2++;
01171         if (intrLine2.Intersect(p3, in_PlaneB.GetP4())) cpt2++;
01172         // **AKASSERT(cpt2 == 2 || cpt == 2);
01173 
01174         if (cpt < 2 || cpt2 < 2)
01175         {
01176 #ifdef AKPORTALS_DEBUG
01177             sprintf(msg, "%% NON \n"); AKPLATFORM::OutputDebugMsg(msg);
01178             sprintf(msg, "%% _______________________\n"); AKPLATFORM::OutputDebugMsg(msg);
01179 #endif
01180             return false;
01181         }
01182 
01183         AkReal32 start = AkMax(intrLine.mint, intrLine2.mint);
01184         AkReal32 end = AkMin(intrLine.maxt, intrLine2.maxt);
01185 
01186         Ak3DVector minPoint = intrLine.PointAt(start);
01187         Ak3DVector maxPoint = intrLine.PointAt(end);
01188 #ifdef AKPORTALS_DEBUG
01189         sprintf(msg, "P1a=[%0.2f,%0.2f,%0.2f];\n", GetP1().X, GetP1().Y, GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01190         sprintf(msg, "P2a=[%0.2f,%0.2f,%0.2f];\n", GetP2().X, GetP2().Y, GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01191         sprintf(msg, "P4a=[%0.2f,%0.2f,%0.2f];\n", GetP4().X, GetP4().Y, GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01192 
01193         sprintf(msg, "P1b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP1().X, in_PlaneB.GetP1().Y, in_PlaneB.GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01194         sprintf(msg, "P2b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP2().X, in_PlaneB.GetP2().Y, in_PlaneB.GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01195         sprintf(msg, "P4b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP4().X, in_PlaneB.GetP4().Y, in_PlaneB.GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01196 
01197         sprintf(msg, "line1=[%0.2f,%0.2f,%0.2f];\n", point.X + L.X*1000.f, point.Y + L.Y*1000.f, point.Z + L.Z*1000.f); AKPLATFORM::OutputDebugMsg(msg);
01198         sprintf(msg, "line2=[%0.2f,%0.2f,%0.2f];\n", point.X - L.X*1000.f, point.Y - L.Y*500.f, point.Z - L.Z*500.f); AKPLATFORM::OutputDebugMsg(msg);
01199 
01200         sprintf(msg, "intr1=[%0.2f,%0.2f,%0.2f];\n", minPoint.X, minPoint.Y, minPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
01201         sprintf(msg, "intr2=[%0.2f,%0.2f,%0.2f];\n", maxPoint.X, maxPoint.Y, maxPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
01202 
01203         sprintf(msg, "%% _______________________\n"); AKPLATFORM::OutputDebugMsg(msg);
01204 #endif
01205         out_Intrs.points[0] = minPoint;
01206         out_Intrs.points[1] = maxPoint;
01207         out_Intrs.count = 2;
01208 
01209         return true;
01210     }
01211 
01212     Ak3DVector GetP1() const { return p1; }
01213     Ak3DVector GetP2() const { return p2; }
01214     Ak3DVector GetP4() const { return p4; }
01215 
01216 private:
01217     bool SetNormal()
01218     {
01219         //m_pNormal = (B-A) cross (C-A); normalize
01220         Ak3DVector a = p2 - p1;
01221         Ak3DVector b = p4 - p1;
01222 
01223         N = Ak3DVector(a.Y*b.Z - a.Z*b.Y, -(a.X*b.Z - a.Z*b.X), a.X*b.Y - a.Y*b.X);
01224 
01225         AkReal32 len = N.Length();
01226         AKASSERT(len > 0.f);
01227 
01228         if (len > 0)
01229         {
01230             N /= len;
01231         }
01232         else
01233         {
01234             // TODO handle invalid reflectors
01235             return false;
01236         }
01237 
01238         return true;
01239     };
01240 
01241     /*
01242     p2__________p3
01243     |     .     |
01244     ^   inter   v3
01245     v1          v
01246     |           |
01247     p1__ v2>___p4
01248     */
01249 
01250     Ak3DVector                      p1;     // Bottom left
01251     Ak3DVector                      p2;     // Top left
01252     Ak3DVector                      p4;     // Tottom right
01253     Ak3DVector                      N;      // Normal vector
01254     AkReal32                        D;      // Plane equation: Ax + By + Cz = D => N.Xx + N.Yy + N.Zz = D
01255 };
01256 
01257 struct AkBoundingBox
01258 {
01259     AkBoundingBox() :
01260         m_Min(Ak3DVector(FLT_MAX, FLT_MAX, FLT_MAX)),
01261         m_Max(Ak3DVector(-FLT_MAX, -FLT_MAX, -FLT_MAX))
01262     {}
01263 
01264     void Update(
01265         const Ak3DVector &      in_point
01266         )
01267     {
01268         if (m_Min.X > in_point.X)
01269             m_Min.X = in_point.X;
01270 
01271         if (m_Min.Y > in_point.Y)
01272             m_Min.Y = in_point.Y;
01273 
01274         if (m_Min.Z > in_point.Z)
01275             m_Min.Z = in_point.Z;
01276 
01277         if (m_Max.X < in_point.X)
01278             m_Max.X = in_point.X;
01279 
01280         if (m_Max.Y < in_point.Y)
01281             m_Max.Y = in_point.Y;
01282 
01283         if (m_Max.Z < in_point.Z)
01284             m_Max.Z = in_point.Z;
01285     }
01286 
01287     AkForceInline bool IsWithin(
01288         const Ak3DVector &      in_Point
01289         ) const
01290     {
01291         return in_Point >= m_Min && in_Point <= m_Max;
01292     }
01293 
01294     AkForceInline bool IsWithin(
01295         const AkBoundingBox &   in_BB
01296         ) const
01297     {
01298         return (m_Min.X <= in_BB.m_Max.X && m_Max.X >= in_BB.m_Min.X) &&
01299             (m_Min.Y <= in_BB.m_Max.Y && m_Max.Y >= in_BB.m_Min.Y) &&
01300             (m_Min.Z <= in_BB.m_Max.Z && m_Max.Z >= in_BB.m_Min.Z);
01301     }
01302 
01303     AkBoundingBox Intersect(
01304         const AkBoundingBox &   in_BB
01305     ) const
01306     {
01307         AkBoundingBox result;
01308         
01309         result.m_Max.X = AkMin(m_Max.X, in_BB.m_Max.X);
01310         result.m_Max.Y = AkMin(m_Max.Y, in_BB.m_Max.Y);
01311         result.m_Max.Z = AkMin(m_Max.Z, in_BB.m_Max.Z);
01312 
01313         result.m_Min.X = AkMax(m_Min.X, in_BB.m_Min.X);
01314         result.m_Min.Y = AkMax(m_Min.Y, in_BB.m_Min.Y);
01315         result.m_Min.Z = AkMax(m_Min.Z, in_BB.m_Min.Z);
01316         
01317         return result;
01318     }
01319 
01320     // returns acos(in_fAngle)
01321     AkForceInline AkReal32 ACos(
01322         AkReal32            in_fAngle
01323         ) const
01324     {
01325         AKASSERT((in_fAngle <= 1.0f) && (in_fAngle >= -1.0f));
01326         return acosf(in_fAngle);
01327     }
01328 
01329     AkForceInline bool IsEmpty() const
01330     {
01331         return (m_Min.X >= m_Max.X) || (m_Min.Y >= m_Max.Y) || (m_Min.Z >= m_Max.Z);
01332     }
01333 
01334     Ak3DVector                      m_Min;
01335     Ak3DVector                      m_Max;
01336 };
01337 
01338 class AkBox
01339 {
01340 public:
01341     AkBox()
01342     {
01343     }
01344 
01345     ~AkBox()
01346     {
01347     }
01348 
01349     void Init(
01350         const Ak3DVector &      in_center,
01351         const Ak3DVector &      in_extent,
01352         const Ak3DVector &      in_Front,
01353         const Ak3DVector &      in_Up)
01354     {
01355         AKASSERT(fabs(in_Front.Length() - 1.f) < 0.001 && fabs(in_Up.Length() - 1.f) < 0.001);//Must be unit vectors.
01356         AKASSERT(fabs(in_Front.Dot(in_Up) - 0.f) < 0.001); //Must be orthogonal.
01357 
01358         m_Center = in_center;
01359         m_Extent = in_extent;
01360 
01361         m_Z = in_Front,
01362         m_Y = in_Up;
01363         m_X = m_Z.Cross(m_Y);
01364     }
01365 
01366     bool IsPointInBox(
01367         const Ak3DVector &      in_Point
01368         ) const
01369     {
01370         Ak3DVector pt = in_Point - m_Center;
01371         return  fabs(pt.Dot(m_X)) <= m_Extent.X && fabs(pt.Dot(m_Y)) <= m_Extent.Y && fabs(pt.Dot(m_Z)) <= m_Extent.Z;
01372     }
01373 
01374     Ak3DVector GetSize() const { return m_Extent*2.f; }
01375     Ak3DVector GetCenter() const { return m_Center; }
01376 
01377     Ak3DVector GetUx() const { return m_X; }
01378     Ak3DVector GetUy() const { return m_Y; }
01379     Ak3DVector GetUz() const { return m_Z; }
01380 
01381     Ak3DVector GetFront() const { return m_Z; }
01382     Ak3DVector GetUp() const { return m_Y; }
01383     Ak3DVector GetSide() const { return m_X; }
01384 
01385     AkReal32 GetVolume() const
01386     {
01387         Ak3DVector size = GetSize();
01388         return size.X * size.Y * size.Z;
01389     }
01390 
01391     bool SeparatingAxisExists(
01392         const Ak3DVector&       L,
01393         const AkBox&            B
01394         ) const
01395     {
01396         // Separating Axis Theorem for Oriented Bounding Boxes by Johnny Huynh
01397         const AkBox& A = *this;
01398         Ak3DVector T = B.GetCenter() - A.GetCenter();
01399 
01400         AkReal32 WA = A.m_Extent.X;
01401         AkReal32 HA = A.m_Extent.Y;
01402         AkReal32 DA = A.m_Extent.Z;
01403 
01404         AkReal32 WB = B.m_Extent.X;
01405         AkReal32 HB = B.m_Extent.Y;
01406         AkReal32 DB = B.m_Extent.Z;
01407 
01408         Ak3DVector Ax = A.GetUx();
01409         Ak3DVector Ay = A.GetUy();
01410         Ak3DVector Az = A.GetUz();
01411 
01412         Ak3DVector Bx = B.GetUx();
01413         Ak3DVector By = B.GetUy();
01414         Ak3DVector Bz = B.GetUz();
01415 
01416         /*
01417         | T • L | > | (WA*Ax) • L | + | (HA*Ay) • L | + |(DA*Az) • L | +
01418                     | (WB*Bx) • L | +| (HB*By) • L | +| (DB*Bz) • L |*/
01419 
01420         AkReal32 left = (AkReal32)fabs(T.DotProduct(L));
01421         AkReal32 dpax = (AkReal32)fabs((Ax*WA).DotProduct(L));
01422         AkReal32 dpay = (AkReal32)fabs((Ay*HA).DotProduct(L));
01423         AkReal32 dpaz = (AkReal32)fabs((Az*DA).DotProduct(L));
01424         AkReal32 dpbx = (AkReal32)fabs((Bx*WB).DotProduct(L));
01425         AkReal32 dpby = (AkReal32)fabs((By*HB).DotProduct(L));
01426         AkReal32 dpbz = (AkReal32)fabs((Bz*DB).DotProduct(L));
01427 
01428         AkReal32 right = dpax + dpay + dpaz + dpbx + dpby + dpbz;
01429 
01430         return left > right;
01431     }
01432 
01433     void UpdateBoundingBox(AkBoundingBox& out_aabb) const
01434     {
01435         Ak3DVector x = m_X * m_Extent.X;
01436         out_aabb.Update(m_Center + x);
01437         out_aabb.Update(m_Center - x);
01438         Ak3DVector y = m_Y * m_Extent.Y;
01439         out_aabb.Update(m_Center + y);
01440         out_aabb.Update(m_Center - y);
01441         Ak3DVector Z = m_Z * m_Extent.Z;
01442         out_aabb.Update(m_Center + Z);
01443         out_aabb.Update(m_Center - Z);
01444     }
01445 
01446 
01447 private:
01448 
01449     Ak3DVector                      m_Center;
01450     Ak3DVector                      m_Extent;
01451 
01452     //Orthonormal Axes
01453     Ak3DVector                      m_X;
01454     Ak3DVector                      m_Y;
01455     Ak3DVector                      m_Z;
01456 };

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise