C:\> Rostislav Persion's Projects

.:: Spring Mass Library In Python ::.
Ported form my C# Spring Mass Library


This program is a Python Spring Mass System library that I ported over from my C# version.

WARNING: for some reason the Python version connects every Mass together when you connect just one of them. I am still trying to figure out why it isn't working right. If you figure it out please help. Looks like Python and C# have some differences.



This graphic was generated by creating three connected masses. The left one has a downward velocity, the right one has an upward velocity, and the center mass is stationaty. When letting them run their course, they go into orbit around the center mass.



Testing collision detection.

METHODS AND VARIABLES OF MASS OBJECT


def Distance(self, mass1, mass2): #internal function for calculating distance between two Mass objects

def ConnectTo(self, mass2, k=1.0, MaxLengthFactor=2.0): #connect this mass to another one

def CollideWith(self, mass2, k=1.0): #turn on collision detection between this mass and another

def Move(self, dt=0.1,gravity=0.0): #translate the mass based on forces applied to it with Forces() and Collide()

def Forces(self): #calculate forces on the current mass based on its connections to other masses

def Collide(self): #calculate forces on the current mass based on its collision with other masses



Fixed = False #if True then the mass object does not move

x = 0.0 #x coordinate of mass in meters

y = 0.0 #y coordinate of mass in meters

vx = 0.0 #x velocity in m/s

vy = 0.0 #y velocity in m/s

mass = 10.0 #mass of the mass object in kilograms

diameter = 80.0 #diameter of mass object in meters

SPRING MASS LIBRARY


 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
import math#DEFINE MASS CLASSclass Mass:    #INITIALIZE VARIABLES    Fixed = False    x = 0.0    y = 0.0    vx = 0.0    vy = 0.0    ax = 0.0    ay = 0.0    fx = 0.0    fy = 0.0    mass = 10.0    diameter = 20.0    #INITIALIZE SPRING AND COLLIDER COLLECTION    Springs = []    Colliders = []    #COMPUTE DISTANCE BETWEEN TWO MASSES    def Distance(self, mass1, mass2):        return math.sqrt(math.pow(mass1.x - mass2.x, 2) + math.pow(mass1.y - mass2.y, 2))    #CREARE SPRING CONNECTION BETWEEN SELF AND OTHER MASS    def ConnectTo(self, mass2, k=1.0, MaxLengthFactor=2.0):        newSpring = Spring()        newSpring.k = k        newSpring.node = mass2        newSpring.length = self.Distance(self, mass2)        newSpring.maxlength = MaxLengthFactor * newSpring.length        self.Springs.append(newSpring)    #CREATE COLLIDER BETWEEN SELF AND OTHER MASS    def CollideWith(self, mass2, k=1.0):        newCollider = Collider()        newCollider.k = k        newCollider.node = mass2        newCollider.length = (self.diameter/2) + (mass2.diameter/2)        self.Colliders.append(newCollider)    #MOVE MASS ONE STEP    def Move(self, dt=0.1,gravity=0.0):        if self.Fixed == False:            self.ax = self.fx / self.mass            self.ay = (self.fy / self.mass) + gravity            self.vx += (self.ax * dt)            self.vy += (self.ay * dt)            self.x += (self.vx * dt)            self.y += (self.vy * dt)        self.fx = 0.0        self.fy = 0.0    #COMPUTE FORCES BETWEEN SELF AND CONNECTED    def Forces(self):        for sp in self.Springs:            if self.Distance(self, sp.node) >= sp.maxlength:                sp.broken = True                        if sp.broken == False:                self.fx += (((self.Distance(self, sp.node) - sp.length) * sp.k) / sp.length) * (sp.node.x - self.x)                self.fy += (((self.Distance(self, sp.node) - sp.length) * sp.k) / sp.length) * (sp.node.y - self.y)                sp.node.fx += (((self.Distance(self, sp.node) - sp.length) * sp.k) / sp.length) * (self.x - sp.node.x)                sp.node.fy += (((self.Distance(self, sp.node) - sp.length) * sp.k) / sp.length) * (self.y - sp.node.y)    #COMPUTE COLLISION BETWEEN SELF AND CONNECTED    def Collide(self):        for cl in self.Colliders:            if (self.Distance(self, cl.node) <= ((self.diameter / 2) + (cl.node.diameter / 2))):                self.fx += (((self.Distance(self, cl.node) - cl.length) * cl.k) / cl.length) * (cl.node.x - self.x)                self.fy += (((self.Distance(self, cl.node) - cl.length) * cl.k) / cl.length) * (cl.node.y - self.y)                cl.node.fx += (((self.Distance(self, cl.node) - cl.length) * cl.k) / cl.length) * (self.x - cl.node.x)                cl.node.fy += (((self.Distance(self, cl.node) - cl.length) * cl.k) / cl.length) * (self.y - cl.node.y) #DEFINE SPRING CLASSclass Spring:    k = 1.0    length = 1    maxlength = 2.0    broken = False    node = Mass()#DEFINE COLLIDER CLASSclass Collider:    k = 1.0    length = 1.0    node = Mass()


SPRING MASS TESTER


 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
import cv2  import timefrom numpy import zerosimport SpringMasswidth = 800height = 500img1 = zeros([height,width,3])#CREATE MASSESm1 = SpringMass.Mass()m1.x = 250m1.y = 200m1.vx = 3m1.vy = 0m1.diameter = 100m1.mass = 20m2 = SpringMass.Mass()m2.x = 450m2.y = 200m2.vx = -3m2.vy = 0m2.diameter = 100m1.mass = 20m3 = SpringMass.Mass()m3.x = 600m3.y = 200m3.vx = -3m3.vy = 0m3.diameter = 100m3.mass = 20#CONNECT MASSESm1.CollideWith(m2,5)m2.CollideWith(m3,5)while True:      m1.Forces()    m2.Forces()    m3.Forces()    m1.Collide()    m2.Collide()    m3.Collide()    m1.Move(0.1,0.01)    m2.Move(0.1,0.01)    m3.Move(0.1,0.01)    rad1 = m1.diameter / 2    rad2 = m2.diameter / 2    rad3 = m3.diameter / 2    img1 = cv2.rectangle(img1, (0,0), (width,height), (255,255,255), cv2.FILLED)     img1 = cv2.circle(img1, (int(m1.x),int(m1.y)), int(rad1), (255,0,0), cv2.FILLED)    img1 = cv2.circle(img1, (int(m2.x),int(m2.y)), int(rad2), (0,0,255), cv2.FILLED)    img1 = cv2.circle(img1, (int(m3.x),int(m3.y)), int(rad2), (0,255,0), cv2.FILLED)        #time.sleep(0.5)        cv2.imshow('SPRING MASS TESTER',img1)     #cv2.imwrite("temp.jpg", img)    #DO EVENTS    k = cv2.waitKey(1) & 0xff    if k == 27:         break