[bmx] 3D Math Lib - BMax by Chroma [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:41

Previous topic - Next topic

BlitzBot

Title : 3D Math Lib - BMax
Author : Chroma
Posted : 1+ years ago

Description : Easy to use 3d math lib for BMax.  Can do complex equations on a single line.  Very handy for converting complex maths from C/C++.
Each command has a description of what it does and examples of exactly how to use it.

Updated 02Dec05: Added some Quaternions
Updated 04Dec05: Added Matrices


Code :
Code (blitzmax) Select
' 3D Math Library v2.0
' BlitzMAX Edition
' by Chroma

' You can do some lengthy equations with this Math Lib
' Just remember it does the maths in order of parenthesis
' So you have to write the equation accordingly (in reverse?)
' For example the equation: v=v1+v2*v3+v4
' It doesn't automatically do the multiplication first
' You have to engineer the equation manually like so:
' v = v1.Add( v4.Add( v2.Mul( v3 ) ) )
' Just be aware of the order they are calc'ed in

' Here's a physics example:
' vAcceleration = vForces.DivS( Mass )
' vVelocity.AddTimeStep( vAcceleration, dt )
' vPosition.AddTimeStep( vVelocity, dt )

'Test
'Graphics 800,600,32,85
'a:Vector = Vector.Create()
'b:Vector = Vector.Create(1,2,3)
'While Not KeyHit(KEY_ESCAPE)
'Cls
'a.AddTimeStep( b, .015)
'a.Show(5,5,"Test")
'Flip
'Wend
'End


' Constants
Const Tol:Float = 0.0001

'-------------------------------------------
'---- Vector Type and Functions/Methods ----
'-------------------------------------------
Type Vector

Field x:Float
Field y:Float
Field z:Float

' Purpose: Create a New Vector
' Returns: Vector
' Example1: v1:Vector = New Vector
' Example2: v1:Vector = Vector.Create()
' Example3: v1:Vector = Vector.Create(1,2,3)
Function Create:Vector( x:Float = 0, y:Float = 0, z:Float = 0 )
Local v:Vector = New Vector
v.x = x
v.y = y
v.z = z
Return v
End Function

' Purpose: Set a Vector with New XYZ Components
' Returns: Nothing
' Example: v1.Set(1,2,3)
' Example: v1.Set() will set a vector to (0,0,0)
Method Set( newx:Float = 0, newy:Float = 0, newz:Float = 0 )
x = newx
y = newy
z = newz
End Method

' Purpose: Add Two Vectors
' Returns: Vector
' Example1: v1=v1+v2 would be written v1 = v1.Add( v2 )
' Example2: v1=v2+v3 would be written v1 = v2.Add( v3 )
Method Add:Vector( v:Vector )
Local res:Vector = New Vector
res.x = x + v.x
res.y = y + v.y
res.z = z + v.z
Return res
End Method

' Purpose: Subtract Two Vectors
' Returns: Vector
' Example1: v1=v1-v2 would be written v1 = v1.Sub( v2 )
' Example2: v1=v2-v3 would be written v1 = v2.Sub( v3 )
Method Sub:Vector( v:Vector )
Local res:Vector = New Vector
res.x = x - v.x
res.y = y - v.y
res.z = z - v.z
Return res
End Method

' Purpose: Multiply Two Vectors
' Returns: Vector
' Example1: v1=v1*v2 would be written v1 = v1.Mul( v2 )
' Example2: v1=v2*v3 would be written v1 = v2.Mul( v3 )
Method Mul:Vector( v:Vector )
Local res:Vector = New Vector
res.x = x * v.x
res.y = y * v.y
res.z = z * v.z
Return res
End Method

' Purpose: Divide One Vector By Another
' Returns: Vector
' Example1: v1=v1/v2 would be written v1 = v1.Div( v2 )
' Example2: v1=v2/v3 would be written v1 = v2.Div( v3 )
Method Div:Vector( v:Vector )
Local res:Vector = New Vector
res.x = x / v.x
res.y = y / v.y
res.z = z / v.z
Return res
End Method

' Purpose: Add a Scalar to a Vector
' Returns: Vector
' Example1: v1=v1+1 would be written v1 = v1.AddS( 1 )
' Example2: v1=v2+1 would be written v1 = v2.AddS( 1 )
Method AddS:Vector( s:Float )
Local res:Vector = New Vector
res.x = x + s
res.y = y + s
res.z = z + s
Return res
End Method

' Purpose: Subtract a Scalar from a Vector
' Returns: Vector
' Example1: v1=v1-1 would be written v1 = v1.SubS( 1 )
' Example2: v1=v2-1 would be written v1 = v2.SubS( 1 )
Method SubS:Vector( s:Float )
Local res:Vector = New Vector
res.x = x - s
res.y = y - s
res.z = z - s
Return res
End Method

' Purpose: Multiply a Vector by a Scalar
' Returns: Vector
' Example1: v1=v1*2 would be written v1 = v1.MulS( 2 )
' Example2: v1=v2*2 would be written v1 = v2.MulS( 2 )
Method MulS:Vector( s:Float )
Local res:Vector = New Vector
res.x = x * s
res.y = y * s
res.z = z * s
Return res
End Method

' Purpose: Divide a Vector by a Scalar
' Returns: Vector
' Example1: v1=v1/2 would be written v1 = v1.DivS( 2 )
' Example2: v1=v2/2 would be written v1 = v2.DivS( 2 )
Method DivS:Vector( s:Float )
Local res:Vector = New Vector
res.x = x / s
res.y = y / s
res.z = z / s
Return res
End Method

' Purpose: Multiply a Vector by a Quaternion
' Returns: Quaternion
' Example: q1=v1*q1 would be written q1 = v1.MulQ ( q1 )
Method MulQ:Quaternion( q:Quaternion )
Local res:Quaternion = New Quaternion
res.n = -(q.v.x*x + q.v.y*y + q.v.z*z)
res.v.x = q.n*x + q.v.z*y - q.v.y*z
res.v.y = q.n*y + q.v.x*z - q.v.z*x
res.v.z = q.n*z + q.v.y*x - q.v.x*y
Return res
End Method

' Purpose: Multiply a Vector by a Matrix
' Returns: Vector
' Example: v1=v1*m1 would be written v1 = v1.MulM( m1 )
Method MulM:Vector ( m:Matrix )
Local res:Vector = New Vector
res.x = x*m.e11 + y*m.e21 + z*m.e31
res.y = x*m.e12 + y*m.e22 + z*m.e32
res.z = x*m.e13 + y*m.e23 + z*m.e33
Return res
End Method

' Purpose: Calculate the Magnitude of a Vector
' Returns: Float
' Example: Local a:Float = v1.Magnitude()
Method Magnitude:Float()
Return Sqr(x * x + y * y + z * z)
End Method

' Purpose: Normalize a Vector
' Returns: Nothing - Directly Normalizes Target Vector
' Example: v1.Normalize()
Method Normalize()
Local mag:Float = Magnitude()
If mag = 0.0 Then Set();Return
x :/ mag
y :/ mag
z :/ mag
If Abs( x ) < Tol x = 0.0
If Abs( y ) < Tol y = 0.0
If Abs( z ) < Tol z = 0.0
End Method

' Purpose: Calculate the Cross Product of Two Vectors
' Returns: Vector
' Example1: v1 = v1.CrossP( v2 )
' Example2: v1 = v2.CrossP( v3 )
Method CrossP:Vector( v:Vector )
Local res:Vector = New Vector
res.x =  y * v.z  -  z * v.y
res.y = -x * v.z  +  z * v.x
res.z =  x * v.y  -  y * v.x
Return res
EndMethod

' Purpose: Calculate the Dot Product Between Two Vectors
' Returns: Float
' Example: Local mydot:float = v1.DotP( v2 )
Method DotP:Float( v:Vector )
Return x * v.x + y * v.y + z * v.z
EndMethod

Method Inverse:Vector()
Return Vector.Create( -x, -y, -z )
End Method

' Purpose: Add Two Vectors and Multiply by a DeltaTime
' Returns: Nothing - Directly Changes the Target Vector
' Example: vPos=vPos+vVel*dt would be vPos.AddTimeStep( vVel, dt )
Method AddTimeStep( v:Vector, time_step:Float )
x :+ v.x * time_step
y :+ v.y * time_step
z :+ v.z * time_step
End Method

' Purpose: Show Vector Values for Debug Purposes
' Returns: Nothing
' Note: Graphics mode must be set for this command to work
' Example: v1.Show( 5, 5, "vPosition" )
Method Show( xpos:Int = 5, ypos:Int = 5, label:String = "", vspc:Int = 12 )
DrawText label + "_X: " + x, xpos, ypos
DrawText label + "_Y: " + y, xpos, ypos + vspc
DrawText label + "_Z: " + z, xpos, ypos + vspc * 2
End Method

End Type

' Degrees To Radians Conversion
Function DegreesToRadians:Float(deg:Float)
Return deg * Pi / 180.0
End Function

' Radians To Degrees Conversion
Function RadiansToDegrees:Float(rad:Float)
Return rad * 180.0 / Pi
End Function


'-------------------------------------------
'-- Quaternion Type and Functions/Methods --
'-------------------------------------------
Type Quaternion

Field n:Float
Field v:Vector = New Vector

' Purpose: Create a New Quaternion
' Returns: Quaternion
' Example1: q1:Quaternion = New Quaternion
' Example2: q1:Quaternion = Quaternion.Create( 1, 2, 3, 4 )
' Example3: q1:Quaternion = Quaternion.Create()
Function Create:Quaternion( n:Float = 0, x:Float = 0, y:Float = 0, z:Float = 0 )
Local q:Quaternion = New Quaternion
q.n = n
q.v.x = x
q.v.y = y
q.v.z = z
Return q
End Function

' Purpose: Add Two Quaternions
' Returns: Quaternion
' Example1: q1=q1+q2 would be q1 = q1.Add( q2 )
' Example2: q1=q2+q3 would be q1 = q2.Add( q3 )
Method Add:Quaternion( q:Quaternion )
Local res:Quaternion = New Quaternion
res.n = n + q.n
res.v.x = v.x + q.v.x
res.v.y = v.y + q.v.y
res.v.z = v.z + q.v.z
Return res
End Method

' Purpose: Subtract Two Quaternions
' Returns: Quaternion
' Example1: q1=q1-q2 would be q1 = q1.Sub( q2 )
' Example2: q1=q2-q3 would be q1 = q2.Sub( q3 )
Method Sub:Quaternion( q:Quaternion )
Local res:Quaternion = New Quaternion
res.n = n - q.n
res.v.x = v.x - q.v.x
res.v.y = v.y - q.v.y
res.v.z = v.z - q.v.z
Return res
End Method

' Purpose: Multiply Two Quaternions
' Returns: Quaternion
' Example1: q1=q1*q2 would be q1 = q1.Mul( q2 )
' Example2: q1=q2*q3 would be q1 = q2.Mul( q3 )
Method Mul:Quaternion( q:Quaternion )
Local res:Quaternion = New Quaternion
res.n = n*q.n - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
res.v.x = n*q.v.x + v.x*q.n + v.y*q.v.z - v.z*q.v.y
res.v.y = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
res.v.z = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
Return res
End Method

' Purpose: Multiply a Quaternion by a Scalar
' Returns: Quaternion
' Example1: q1=q1*2 would be q1 = q1.MulS( 2 )
' Example2: q1=q2*2 would be q1 = q2.MulS( 2 )
Method MulS:Quaternion( s:Float )
Local res:Quaternion = New Quaternion
res.n = n * s
res.v.x = v.x * s
res.v.y = v.y * s
res.v.z = v.z * s
Return res
End Method

' Purpose: Divide a Quaternion by a Scalar
' Returns: Quaternion
' Example1: q1=q1/2 would be q1 = q1.DivS( 2 )
' Example2: q1=q2/2 would be q1 = q2.DivS( 2 )
Method DivS:Quaternion( s:Float )
Local res:Quaternion = New Quaternion
res.n = n / s
res.v.x = v.x / s
res.v.y = v.y / s
res.v.z = v.z / s
Return res
End Method

' Purpose: Multiply a Quaternion by a Vector
' Returns: Quaternion
' Example1: q1=q1*v1 would be written q1 = q1.MulV( v1 )
Method MulV:Quaternion( v:Vector )
res:Quaternion = New Quaternion
res.n = -(self.v.x*v.x + self.v.y*v.y + self.v.z*v.z)
res.v.x = self.n*v.x + self.v.y*v.z - self.v.z*v.y
res.v.y = self.n*v.y + self.v.z*v.x - self.v.x*v.z
res.v.z = self.n*v.z + self.v.x*v.y - self.v.y*v.x
Return res
End Method

' Purpose: Calculate the Magnitude of a Quaternion
' Returns: Float
' Example: Local qmag:float = q1.Magnitude()
Method Magnitude:Float( q:Quaternion )
Return Float Sqr( n * n + v.x * v.x + v.y * v.y + v.z * v.z )
End Method

' Purpose: Gets the XYZ Component of a Quaternion
' Returns: Vector
' Example: v1 = q1.GetVector()
Method GetVector:Vector()
Return Vector.Create(v.x, v.y, v.z)
End Method

' Purpose: Inverse a Quaternion
' Returns: Quaternion
' Example1: q1=~q1 would be q1 = q1.Inverse()
' Example2: q1=~q2 would be q1 = q2.Inverse()
Method Inverse:Quaternion()
Return Quaternion.Create(n, -v.x, -v.y, -v.z)
End Method

' Purpose: Show Quaternion Values for Debug Purposes
' Returns: Nothing
' Note: Graphics mode must be set for this command to work
' Example: q1.Show( 5, 5, "qAngularVelocity" )
Method Show( xpos:Int, ypos:Int, label:String = "", vspc:Int = 12 )
DrawText n, xpos, ypos
DrawText v.x, xpos, ypos + vspc
DrawText v.y, xpos, ypos + vspc * 2
DrawText v.z, xpos, ypos + vspc * 3
End Method

' Purpose: Used in Physics
' Returns: Quaternion
' Example: q1 = q1.QRotate( q2 )
Method QRotate:Quaternion( q:Quaternion )
' q1*q2*(~q1)
Local t:Quaternion = New Quaternion
t = self.Mul( q )
Return t.Mul( self.Inverse() )
End Method

' Purpose: Used in Physics
' Returns: Vector
' Example: v1 = q1.QVRotate( v2 )
Method QVRotate:Vector( v )
Local t:Quaternion = New Quaternion
' t = q*v*(~q);
t = self.MulV( v )
t = t.Mul( self.Inverse() )
Return t.GetVector()
End Method

End Type


'-------------------------------------------
'---- Matrix Type and Functions/Methods ----
'-------------------------------------------

Type Matrix

Field e11:Float = 0, e12:Float = 0, e13:Float = 0
Field e21:Float = 0, e22:Float = 0, e23:Float = 0
Field e31:Float = 0, e32:Float = 0, e33:Float = 0

Function Create:Matrix(e11#=0,e12#=0,e13#=0,e21#=0,e22#=0,e23#=0,e31#=0,e32#=0,e33#=0)
Local m:Matrix = New Matrix
m.e11 = e11
m.e12 = e12
m.e13 = e13
m.e21 = e21
m.e22 = e22
m.e23 = e23
m.e31 = e31
m.e32 = e32
m.e33 = e33
Return m
End Function

Method Det:Float()
Return e11*e22*e33-e11*e32*e23+e21*e32*e13-e21*e12*e33+e31*e12*e23-e31*e22*e13
End Method

Method Transpose:Matrix()
Return Matrix.Create(e11,e21,e31,e12,e22,e32,e13,e23,e33)
End Method

Method Inverse:Matrix()
Local dd:Float = e11*e22*e33-e11*e32*e23+e21*e32*e13-e21*e12*e33+e31*e12*e23-e31*e22*e13
If dd = 0 Then dd = 1
Local a:Float = (e22*e33-e23*e32)/dd
Local b:Float = -(e12*e33-e13*e32)/dd
Local c:Float = (e12*e23-e13*e22)/dd
Local d:Float = -(e21*e33-e23*e31)/dd
Local e:Float = (e11*e33-e13*e31)/dd
Local f:Float = -(e11*e23-e13*e21)/dd
Local g:Float = (e21*e32-e22*e31)/dd
Local h:Float = -(e11*e32-e12*e31)/dd
Local i:Float = (e11*e22-e12*e21)/dd
Return Matrix.Create(a,b,c,d,e,f,g,h,i)
End Method

Method Add:Matrix( m:Matrix )
Local res:Matrix = New Matrix
res.e11 = e11 + m.e11
res.e12 = e12 + m.e12
res.e13 = e13 + m.e13
res.e21 = e21 + m.e21
res.e22 = e22 + m.e22
res.e23 = e23 + m.e23
res.e31 = e31 + m.e31
res.e32 = e32 + m.e32
res.e33 = e33 + m.e33
Return res
End Method

Method Sub:Matrix( m:Matrix )
Local res:Matrix = New Matrix
res.e11 = e11 - m.e11
res.e12 = e12 - m.e12
res.e13 = e13 - m.e13
res.e21 = e21 - m.e21
res.e22 = e22 - m.e22
res.e23 = e23 - m.e23
res.e31 = e31 - m.e31
res.e32 = e32 - m.e32
res.e33 = e33 - m.e33
Return res
End Method

Method Mul:Matrix( m:Matrix )
Local res:Matrix = New Matrix
res.e11 = e11*m.e11 + e12*m.e21 + e13*m.e31
res.e12 = e11*m.e12 + e12*m.e22 + e13*m.e32
res.e13 = e11*m.e13 + e12*m.e23 + e13*m.e33
res.e21 = e21*m.e11 + e22*m.e21 + e23*m.e31
res.e22 = e21*m.e12 + e22*m.e22 + e23*m.e32
res.e23 = e21*m.e13 + e22*m.e23 + e23*m.e33
res.e31 = e31*m.e11 + e32*m.e21 + e33*m.e31
res.e32 = e31*m.e12 + e32*m.e22 + e33*m.e32
res.e33 = e31*m.e13 + e32*m.e23 + e33*m.e33
Return res
End Method

Method MulS:Matrix( s:Float )
Local res:Matrix = New Matrix
res.e11 = e11 * s
res.e12 = e12 * s
res.e13 = e13 * s
res.e21 = e21 * s
res.e22 = e22 * s
res.e23 = e23 * s
res.e31 = e31 * s
res.e32 = e32 * s
res.e33 = e33 * s
Return res
End Method

Method DivS:Matrix( s:Float )
Local res:Matrix = New Matrix
res.e11 = e11 * s
res.e12 = e12 * s
res.e13 = e13 * s
res.e21 = e21 * s
res.e22 = e22 * s
res.e23 = e23 * s
res.e31 = e31 * s
res.e32 = e32 * s
res.e33 = e33 * s
Return res
End Method

' Purpose: Multiply a Matrix by a Vector and Return a Vector Result
' Example: v1=m1*v1 would be v1=m1.MulV( v1 )
Method MulV:Vector( v:Vector )
Local res:Vector = New Vector
res.x = e11*v.x + e12*v.y + e13*v.z
res.y = e21*v.x + e22*v.y + e23*v.z
res.z = e31*v.x + e32*v.y + e33*v.z
Return res
End Method

End Type


Comments :


Arowx(Posted 1+ years ago)

 Just what I needed to move my project up to the next level. Thank You


Pineapple(Posted 1+ years ago)

 Very nice indeed! :)Great work me auld fruitDabz


Vertex(Posted 1+ years ago)

 Hmm I think, this isn't the best way.
Global A : Vector
Global B : Vector
Global R : Vector

A = New Vector
A.Set(1.0, 2.0, 3.0)

B = New Vector
B.Set(3.0, 2.0, 1.0)

R = A.Add(B)
R = R.MulS(3.0)
R is firstly created by A.Add(B) than is R deleted by R.MulS (3.0) and is new created. This slowing the speed because the internel ressourcehandling.Better: Method Add( a:Vector, b:Vector )
Self.x = a.x + b.x
Self.y = a.y + b.y
Self.z = a.z + b.z
End Method
In practise:R.Add(A, B) ' R = A + BAlso I miss some methods like Slerp(Quanternion), this is a very important function to interpolate between to rotations and completly a plane type.Sorry, but there are certainly better libs :(cu olli


Chroma(Posted 1+ years ago)

 Hi Vertex...I'll check out the proposed changes. Thanks.


Gabriel(Posted 1+ years ago)

 Just checked this out because I was checking my maths on multiplying a vector by a quaternion. Your method returns a quaternion, which I don't understand. If you multiply a vector by a quaternion, surely you get a vector result? You are, after all, effectively rotating a vector. A rotated vector is still a vector. No?


Chroma(Posted 1+ years ago)

 No.


Bobysait(Posted 1+ years ago)

  ' Purpose: Multiply Two Quaternions
' Returns: Quaternion
' Example1: q1=q1*q2 would be q1 = q1.Mul( q2 )
' Example2: q1=q2*q3 would be q1 = q2.Mul( q3 )
Method Mul:Quaternion( q:Quaternion )
Local res:Quaternion = New Quaternion
res.n = n*q.n - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
res.v.x = n*q.v.x + v.x*q.n + v.y*q.v.z - v.z*q.v.y
res.v.y = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
res.v.z = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
Return res
End Method
Maybe I'm wrong, but it seems res.v.z is falsehere, v.y=v.z ...it should be something likeres.n   = n*q.n   - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
res.v.x = n*q.v.x + v.x*q.n   + v.y*q.v.z - v.z*q.v.y
res.v.y = n*q.v.y + v.x*q.v.z - v.y*q.n   + v.z*q.v.x
res.v.z = n*q.v.z - v.x*q.v.y + v.y*q.v.x + v.z*q.n
It's what I find when I developp Sibly's quaternion from its C++ lib '+> Original TQuat.Create( w*q.w-v.dot(q.v) , (q.v.cross(v)).Add(q.v.Multiply(w)).Add(v.Multiply(q.w)) )
' According v:{ x,y,z }
QF:tquat=New tquat

v0:tvector=(q.v.cross(v))
v0.x = q.y*z-q.z*y;
v0.y = q.z*x-q.x*z;
v0.z = q.x*y-q.y*x;

v1:tvector=q.v.Multiply(w) v1 = q.x*w
q.y*w
q.z*w

v2:tvector=v0.Add(v1) v2 = q.y*z - q.z*y + q.x*w
q.z*x - q.x*z + q.y*w
q.x*y - q.y*x + q.z*w

v3:tvector=v.Multiply(q.w) v3 = x*q.w
y*q.w
z*q.w

v4:tvector=v2.Add(v3) v4 = q.y*z - q.z*y + q.x*w + x*q.w
q.z*x - q.x*z + q.y*w + y*q.w
q.x*y - q.y*x + q.z*w + z*q.w


QF.w = w*q.w - x*q.x - y*q.y - z*q.z
QF.x = w*q.x + x*q.w - y*q.z + z*q.y
QF.y = w*q.y + x*q.z + y*q.w - z*q.x
QF.z = w*q.z - x*q.y + y*q.x + z*q.w

Of course, I have maybe made a mistake...


Chroma(Posted 1+ years ago)

 Geez, you probably just nailed why I could never get my flight sim working 3 years ago... [/i]