VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "Mass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'Spring List
Dim Spring(1 To 16) As Spring

'Spring Count
Dim LinkCount As Long

'Possition Vector
Public X As Double
Public Y As Double
Public Z As Double

'Draw Possition Vector
Public dXt As Double
Public dYt As Double
Public dZt As Double

Public dX As Double
Public dY As Double
Public dZ As Double

'Velocity Vector
Public Vx As Double
Public Vy As Double
Public Vz As Double

'Acceleration Vector
Public Ax As Double
Public Ay As Double
Public Az As Double

'Force Vector
Public Fx As Double
Public Fy As Double
Public Fz As Double

'Mass Scalar
Public M As Double
Public zm As Double
Public Vr As Double

'Object states
Public Fixed As Boolean 'Can it move?

'Simulation Properties
Public Gc As Double
Public Fc As Double
Public dt As Double

'Misc
Public Caption As String

'Constants
Private Const Pi As Double = 3.1415926535 '[circ/diam]
Private Const Ac As Double = Pi / 180 '[rad/deg]
Function AddSpring() As Long
'Adds a new empty spring
    LinkCount = LinkCount + 1
    Set Spring(LinkCount) = New Spring
    Set Spring(LinkCount).fromMass = Me
    AddSpring = LinkCount
End Function
Sub ConnectTo(ByRef obj As Mass, ByVal kk1 As Double, ByVal kk2 As Double, ByVal sf As Double, ByVal bf As Double)
'Connects a mass to this one, sets the spring constant, breaking force
    Dim n As Long
    n = AddSpring
    GetSpring(n).AddMass obj
    GetSpring(n).k1 = kk1
    GetSpring(n).k2 = kk2
    GetSpring(n).StateF = sf
    GetSpring(n).BreakF = bf
End Sub
Sub Draw(ByRef obj As Object, ByVal zm As Double)
'Draws itself and conected links on the given canvas
    
    'Draw Springs
    For a = 1 To LinkCount
        If (Not Spring(a).Broken) Then
            If Spring(a).State = 1 Then
                col = RGB(0, 255, 100)
            End If
            If Spring(a).State = 2 Then
                col = RGB(0, 100, 100)
            End If
            obj.Line (dX * zm, dY * zm)-(Spring(a).toMass.dX * zm, Spring(a).toMass.dY * zm), col
        End If
    Next a

    rr = Int(30 * M * zm)
    If Fixed Then
        obj.Circle (dX * zm, dY * zm), rr, vbBlue
    Else
        obj.Circle (dX * zm, dY * zm), rr, vbRed
    End If
    If Len(Trim(Caption)) > 0 Then
        obj.Print Caption
    End If
End Sub
Public Sub Forces()
'Computes the forces applied to me and other masses through links
    
    'If has spring(s), then compute force between their mass
    If HasSpring() Then
        Dim c1, SpAGetForce As Double
        For a = 1 To LinkCount 'scan all existing springs
            
            'If one of my springs is in the plastic regeion make it plastic state
            If (Spring(a).State = 1) And (Spring(a).GetForce > Spring(a).StateF) Then
                Spring(a).Plastic
            End If
            
            'If one of my springs has reached a limit, break it
            If (Spring(a).State = 2) And (Spring(a).GetForce > Spring(a).BreakF) Then
                Spring(a).Break
            End If
            
            'If the spring is not broken do the rest
            If Not Spring(a).Broken Then
                
                'Constant representing compression or elongation
                If Spring(a).oLength > Spring(a).GetLength Then
                    c1 = -1 'Compression
                Else
                    c1 = 1 'Elongation
                End If
                
                'Generate constant, (Force / OriginalLength) * directional vector
                'Full formula is (dX/oL) * F * Direction
                SpAGetForce = (Spring(a).GetForce / Spring(a).oLength) * c1
                
                'Forces on me
                Fx = Fx + (Spring(a).GetDeltaX * SpAGetForce)
                Fy = Fy + (Spring(a).GetDeltaY * SpAGetForce)
                Fz = Fz + (Spring(a).GetDeltaZ * SpAGetForce)
                
                'Forces on others
                Spring(a).toMass.Fx = Spring(a).toMass.Fx - (Spring(a).GetDeltaX * SpAGetForce)
                Spring(a).toMass.Fy = Spring(a).toMass.Fy - (Spring(a).GetDeltaY * SpAGetForce)
                Spring(a).toMass.Fz = Spring(a).toMass.Fz - (Spring(a).GetDeltaZ * SpAGetForce)
            
            End If
            
        Next a
    End If
    
    'Computer Gravitational Effects
    Fy = Fy + (Gc * M)
    
    'Compute Acceleration
    Ax = Fx / M
    Ay = Fy / M
    Az = Fz / M
    
    'Compute Velocity; this is where Dampening occurs w/ Fc
    Vx = ((Vx + (Ax * dt)) * Fc)
    Vy = ((Vy + (Ay * dt)) * Fc)
    Vz = ((Vz + (Az * dt)) * Fc)

End Sub
Function HasSpring() As Boolean
'Do I have any outgoing springs?
    Dim ret As Boolean
    If LinkCount > 0 Then
        ret = True
    Else
        ret = False
    End If
    HasSpring = ret
End Function

Public Sub Move()
'Perform coordinate incrementation
    Fx = 0
    Fy = 0
    Fz = 0
    If Not Fixed Then
        X = X + (Vx * dt)
        Y = Y + (Vy * dt)
        Z = Z + (Vz * dt)
    End If
End Sub
Function GetSpring(ByVal n As Long) As Spring
'Return the spring bellonging to index n
    Dim ret As Spring
    Set ret = New Spring
    If (n <= LinkCount) And (LinkCount > 0) Then
        Set ret = Spring(n)
    End If
    Set GetSpring = ret
End Function
Sub RenderDraw(ByVal xo As Double, ByVal yo As Double, ByVal tDelta As Double, ByVal sDelta As Double)
    Dim nx, ny, Angle As Double

    tDelta = (Pi / 180) * tDelta
    sDelta = (Pi / 180) * sDelta
    
    'top view rotation
    Rotate 0, 0, X, Z, tDelta, nx, ny
    dXt = nx
    dZt = ny
    dYt = Y
    
    'side view rotation
    Rotate 0, 0, dYt, dZt, sDelta, nx, ny
    dY = nx
    dZ = ny
    dX = dXt
    
    'slide it over
    dX = dX + xo
    dY = dY + yo
    
End Sub

Public Sub Rotate(ByVal xo As Double, ByVal yo As Double, ByVal x1 As Double, ByVal y1 As Double, ByVal dt As Double, ByRef x2, ByRef y2)
    Dim Mag, ot As Double
    
    'calculate magnitude scalar for displacement
    Mag = Sqr(((xo - x1) ^ 2) + ((yo - y1) ^ 2))
    
    'prevent division by zero
    If (xo - x1) <> 0 Then
        ot = Atn((yo - y1) / (xo - x1))
    Else
        ot = Atn(1E+20)
    End If
    
    'add code to orient the angle propperly
    
    'generate new coords after rotation has been applied
    x2 = (Mag * Cos(ot + dt)) + xo
    y2 = (Mag * Sin(ot + dt)) + yo
End Sub

Private Sub Class_Initialize()
    LinkCount = 0
    
    X = 0
    Y = 0
    Z = 0
    Vx = 0
    Vy = 0
    Vz = 0
    Ax = 0
    Ay = 0
    Az = 0
    Fx = 0
    Fy = 0
    Fz = 0

    M = 1
    zm = 5000
    Fixed = False
    
    Gc = 5 '[m/s^2] Gravity
    Fc = 0.999 '[N/A] Motion Dampening
    dt = 0.3 '[N/A] Itteration Timestep
    
End Sub


