MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mathtool.cpp
1 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _mathtool_cpp
41 #define _mathtool_cpp
42 
43 #include "mathtool.h"
44 #include "sphere.h"
45 #include "axisalignedbox.h"
46 #include "ray.h"
47 #include "plane.h"
48 
49 #include <cmath>
50 #include <limits>
51 #include <algorithm>
52 
53 /// @cond 0
54 namespace
55 {
56  /// @typedef SegmentPosPair
57  /// @brief This is an std::pair that stores the near and far segement points for ray-aabb intersections.
58  typedef std::pair<Mezzanine::Real,Mezzanine::Real> SegmentPosPair;
59 
60  /// @brief Helper fucntion for calculating ray-aabb intersections.
61  /// @param Axis The axis to be calculated.
62  /// @param Cast The ray being casted for the intersection.
63  /// @param Box The AABB to check for intersection.
64  /// @param PosPair A pair for the near and far distances in the check so far.
65  /// @return Returns false if the check has succeeded in ruling out an intersection, true otherwise.
66  Mezzanine::Boolean CalculateAxis(const Mezzanine::Whole Axis, const Mezzanine::Ray& Cast, const Mezzanine::AxisAlignedBox& Box, SegmentPosPair& PosPair)
67  {
68  Mezzanine::Vector3 RayDir = Cast.GetDirection();
69  Mezzanine::Real Denom = 1 / RayDir[Axis];
70  Mezzanine::Real NewStart = ( Box.MinExt[Axis] - Cast.Origin[Axis] ) * Denom;
71  Mezzanine::Real NewEnd = ( Box.MaxExt[Axis] - Cast.Origin[Axis] ) * Denom;
72 
73  if( NewStart > NewEnd )
74  std::swap(NewStart,NewEnd);
75 
76  if( NewStart > PosPair.second || NewEnd < PosPair.first )
77  return false;
78 
79  if( NewStart > PosPair.first )
80  PosPair.first = NewStart;
81 
82  if( NewEnd < PosPair.second )
83  PosPair.second = NewEnd;
84 
85  return true;
86  }
87 
89  const Mezzanine::Real TwoPi = ( Mezzanine::Real( 4.0 * Mezzanine::MathTools::ATan(1.0) ) ) * 2.0;
90  const Mezzanine::Real HalfPi = ( Mezzanine::Real( 4.0 * Mezzanine::MathTools::ATan(1.0) ) ) * 0.5;
91  const Mezzanine::Real QuarterPi = ( Mezzanine::Real( 4.0 * Mezzanine::MathTools::ATan(1.0) ) ) * 0.25;
92  const Mezzanine::Real RadToDegMult = Mezzanine::Real( Mezzanine::Real(180.0) / Mezzanine::Real( 4.0 * Mezzanine::MathTools::ATan(1.0) ) );
93  const Mezzanine::Real DegToRadMult = Mezzanine::Real( Mezzanine::Real( 4.0 * Mezzanine::MathTools::ATan(1.0) ) / Mezzanine::Real(180.0) );
94 }
95 /// @endcond
96 
97 namespace Mezzanine
98 {
99  namespace MathTools
100  {
101  ///////////////////////////////////////////////////////////////////////////////
102  // Predefined Constants
103 
105  { return Pi; }
106 
108  { return TwoPi; }
109 
111  { return HalfPi; }
112 
114  { return QuarterPi; }
115 
117  { return RadToDegMult; }
118 
120  { return DegToRadMult; }
121 
122  ///////////////////////////////////////////////////////////////////////////////
123  // Real Math & Check Functions
124 
125  Real Ceil(const Real& Val)
126  { return std::ceil(Val); }
127 
128  Real Floor(const Real& Val)
129  { return std::floor(Val); }
130 
131  Real Pow(const Real& Val, const Real& Power)
132  { return std::pow(Val,Power); }
133 
134  Real Sqrt(const Real& Val)
135  { return std::sqrt(Val); }
136 
137  Real Fabs(const Real& Val)
138  { return std::fabs(Val); }
139 
140  Real Fmod(const Real& Numerator, const Real& Denominator)
141  { return std::fmod(Numerator,Denominator); }
142 
143  bool WithinTolerance(const Real& First, const Real& Second, const Real& Tolerance)
144  { return ( MathTools::Fabs(Second - First) <= Tolerance ); }
145 
146  ///////////////////////////////////////////////////////////////////////////////
147  // Angle Calculation Functions
148 
149  Real Cos(const Real& Radians)
150  { return std::cos(Radians); }
151 
152  Real Sin(const Real& Radians)
153  { return std::sin(Radians); }
154 
155  Real Tan(const Real& Radians)
156  { return std::tan(Radians); }
157 
158  Real ACos(const Real& Interval)
159  { return std::acos(Interval); }
160 
161  Real ASin(const Real& Interval)
162  { return std::asin(Interval); }
163 
164  Real ATan(const Real& Interval)
165  { return std::atan(Interval); }
166 
167  ///////////////////////////////////////////////////////////////////////////////
168  // Angle Conversion Functions
169 
170  Real DegreesToRadians(const Real& Degrees)
171  { return Degrees * DegToRadMult; }
172 
173  Real RadiansToDegrees(const Real& Radians)
174  { return Radians * RadToDegMult; }
175 
176  ///////////////////////////////////////////////////////////////////////////////
177  // Geometry Math
178 
179  ///////////////////////////////////////////////////////////////////////////////
180  // Intersection Query
181 
182  Boolean IsInside(const AxisAlignedBox& Box, const Vector3& Point)
183  {
184  return ( Box.MinExt.X <= Point.X && Box.MaxExt.X >= Point.X &&
185  Box.MinExt.Y <= Point.Y && Box.MaxExt.Y >= Point.Y &&
186  Box.MinExt.Z <= Point.Z && Box.MaxExt.Z >= Point.Z );
187  }
188 
189  Boolean IsInside(const Sphere& Ball, const Vector3& Point)
190  {
191  return ( Ball.Center.Distance(Point) <= Ball.Radius );
192  }
193 
194  Boolean Overlap(const AxisAlignedBox& Box, const Sphere& Ball)
195  {
196  // Arvo's algorithm
197  Real SquareVar, Dist = 0;
198  for( Whole X = 0 ; X < 3 ; ++X )
199  {
200  if ( Ball.Center[X] < Box.MinExt[X] ) {
201  SquareVar = Ball.Center[X] - Box.MinExt[X];
202  Dist += SquareVar * SquareVar;
203  }else if( Ball.Center[X] > Box.MaxExt[X] ) {
204  SquareVar = Ball.Center[X] - Box.MaxExt[X];
205  Dist += SquareVar * SquareVar;
206  }
207  }
208  return ( Dist <= Ball.Radius * Ball.Radius );
209  }
210 
211  Boolean Overlap(const AxisAlignedBox& Box, const Plane& Surface)
212  {
213  return ( Plane::S_Both == Surface.GetSide(Box.GetCenter(),Box.GetHalfSize()) );
214  }
215 
216  Boolean Overlap(const Plane& Surface, const Sphere& Ball)
217  {
218  return ( MathTools::Fabs( Surface.GetDistance( Ball.Center ) ) <= Ball.Radius );
219  }
220 
221  Boolean Overlap(const AxisAlignedBox& Box1, const AxisAlignedBox& Box2)
222  {
223  return !( Box1.MinExt.X > Box2.MaxExt.X || Box1.MinExt.Y > Box2.MaxExt.Y || Box1.MinExt.Z > Box2.MaxExt.Z ||
224  Box1.MaxExt.X < Box2.MinExt.X || Box1.MaxExt.Y < Box2.MinExt.Y || Box1.MaxExt.Z < Box2.MinExt.Z );
225  }
226 
227  Boolean Overlap(const Sphere& Ball1, const Sphere& Ball2)
228  {
229  Real Dist = Ball1.Center.Distance(Ball2.Center);
230  return ( Dist <= Ball1.Radius + Ball2.Radius );
231  }
232 
233  Boolean Overlap(const Plane& Surface1, const Plane& Surface2)
234  {
235  return ( ( Surface1.Normal == Surface2.Normal ? ( Surface1.Distance == Surface2.Distance ) : true ) );
236  }
237 
238  PlaneRayTestResult Intersects(const Plane& Surface, const Ray& Cast)
239  {
240  // Code in this function is based on the equivalent in Ogre
241  Real Denom = Surface.Normal.DotProduct( Cast.GetDirection() );// + Surface.Distance;
242  if( MathTools::Fabs(Denom) < std::numeric_limits<Real>::epsilon() ) {
243  return PlaneRayTestResult( false, Vector3() );
244  }else{
245  Real Nom = Surface.Normal.DotProduct( Cast.Origin ) + Surface.Distance;
246  Real Distance = -( Nom / Denom );
247  if( Distance > Cast.Length() ) {
248  return PlaneRayTestResult( false, Vector3() );
249  }else{
250  return PlaneRayTestResult( true, Cast.Origin + ( Cast.GetDirection() * Distance) );
251  }
252  }
253  }
254 
256  {
257  // Code in this function is based on the equivalent in Ogre
258  Vector3 CastDir = Cast.GetDirection();
259  Vector3 AbsoluteDir = CastDir;
260  AbsoluteDir.X = MathTools::Fabs( AbsoluteDir.X );
261  AbsoluteDir.Y = MathTools::Fabs( AbsoluteDir.Y );
262  AbsoluteDir.Z = MathTools::Fabs( AbsoluteDir.Z );
263 
264  Whole MaxAxis = 0, MidAxis = 1, MinAxis = 2;
265  if( AbsoluteDir[0] < AbsoluteDir[2] ) {
266  MaxAxis = 2;
267  MinAxis = 1;
268  }else if( AbsoluteDir[1] < AbsoluteDir[MinAxis] ) {
269  MidAxis = MinAxis;
270  MinAxis = 1;
271  }else if( AbsoluteDir[1] > AbsoluteDir[MaxAxis] ) {
272  MidAxis = MaxAxis;
273  MaxAxis = 1;
274  }
275 
276  SegmentPosPair Distances(0,std::numeric_limits<Real>::infinity());
277 
278  ::CalculateAxis(MaxAxis,Cast,Box,Distances);
279  if( AbsoluteDir[MidAxis] < std::numeric_limits<Real>::epsilon() ) {
280  if( Cast.Origin[MidAxis] < Box.MinExt[MidAxis] || Cast.Origin[MidAxis] > Box.MaxExt[MidAxis] ||
281  Cast.Origin[MinAxis] < Box.MinExt[MinAxis] || Cast.Origin[MinAxis] > Box.MaxExt[MinAxis] )
282  {
283  return GeometryRayTestResult(false,Ray());
284  }
285  }else{
286  ::CalculateAxis(MidAxis,Cast,Box,Distances);
287  if( AbsoluteDir[MinAxis] < std::numeric_limits<Real>::epsilon() ) {
288  if( Cast.Origin[MinAxis] < Box.MinExt[MinAxis] || Cast.Origin[MinAxis] > Box.MaxExt[MinAxis] ) {
289  return GeometryRayTestResult(false,Ray());
290  }
291  }else{
292  ::CalculateAxis(MinAxis,Cast,Box,Distances);
293  }
294  }
295 
296  Ray Ret( Cast.Origin + (CastDir * Distances.first), Cast.Origin + (CastDir * Distances.second) );
297  return GeometryRayTestResult(true,Ret);
298  }
299 
300  GeometryRayTestResult Intersects(const Sphere& Ball, const Ray& Cast)
301  {
302  // Code in this function is based on the equivalent in Ogre
303  const Vector3 CastDir = Cast.GetDirection();
304  const Vector3 CastOrigin = Cast.Origin - Ball.Center; // Makes math easier to do this in sphere local coordinates
305  const Real Radius = Ball.Radius;
306 
307  // Build coefficients for our formula
308  // t = (-b +/- sqrt(b*b + 4ac)) / 2a
309  Real ACoEff = CastDir.DotProduct(CastDir);
310  Real BCoEff = 2 * CastOrigin.DotProduct(CastDir);
311  Real CCoEff = CastOrigin.DotProduct(CastOrigin) - ( Radius * Radius );
312 
313  // Get the Determinate
314  Real Determinate = ( BCoEff * BCoEff ) - ( 4 * ACoEff * CCoEff );
315  if( Determinate < 0 ) {
316  return GeometryRayTestResult(false,Ray());
317  }else{
318  Real NearDist = ( -BCoEff - MathTools::Sqrt( Determinate ) ) / ( 2 * ACoEff );
319  Real FarDist = ( -BCoEff + MathTools::Sqrt( Determinate ) ) / ( 2 * ACoEff );
320 
321  Ray Ret( Cast.Origin + (CastDir * NearDist), Cast.Origin + (CastDir * FarDist) );
322  return GeometryRayTestResult(true,Ret);
323  }
324  }
325  }//MathTools
326 }//Mezzanine
327 
328 #endif