from math import sqrt
from vpython import *
from matplotlib import pyplot
from __future__ import division, print_function
from ipywidgets import widgets
from IPython.display import display
from IPython.html import widgets
def sub(e1,e2):
return [e1[0]-e2[0],e1[1]-e2[1],e1[2]-e2[2]]
def add(e1,e2):
return [e1[0]+e2[0],e1[1]+e2[1],e1[2]+e2[2]]
def sMul(a,e1):
return ([a*e1[0],a*e1[1],a*e1[2]])
def norm(e1):
return sqrt(e1[0]**2+e1[1]**2+e1[2]**2)
def unit(e1):
try:
return sMul(1.0/norm(e1),e1)
except ZeroDivisionError:
return [0,0,0]
def fl(string,m=0):
try:
return float(string)
except ValueError:
if(m):
return 1.0
else:
return 0.0
def i(string): #prevent incorrect limits? on integers for fixed toggle and spring indexing
try:
return int(string)
except ValueError:
return 0
def conVec(e1):
vec=vector(0.0,0.0,0.0)
vec.x=e1[0]
vec.y=e1[1]
vec.z=e1[2]
return vec
points=[]
springs=[]
DELTAt=0.001
tMAX=100.0
GRAVITY=0
g=-9.81
HELICES=1
flag=0 #start 1, end -1, or 0 if not attached to spring
class point:
def __init__(self,r0,v0=[0.0,0.0,0.0],m0=1.0,fixed=0):
self.r=r0
self.v=v0
if m0==0.0:
self.m=0.0001
else:
self.m=m0
self.F=[0.0,0.0,0.0]
self.FIXED=fixed
if(self.FIXED):
self.v=[0.0,0.0,0.0]
def vUpdate(self):
self.v=add(self.v,sMul(DELTAt/self.m,self.F))
def rUpdate(self):
self.r = add(self.r,add(sMul(DELTAt,self.v),sMul(0.5*(DELTAt**2)/self.m,self.F)))
ERROR! Session/line number was not unique in database. History logging moved to new session 100
class spring:
def length(self):
return norm(sub(points[self.start].r,points[self.end].r))
def force(self):
return self.k*(self.L-self.L0)
def __init__(self,point1,point2,l0,K):
self.start=point1
self.end=point2
self.L0=l0
self.L=self.length()
self.k=K
self.F=self.force()
self.rs=unit(sub(points[self.end].r,points[self.start].r))
self.re=unit(sub(points[self.start].r,points[self.end].r))
def update(self):
self.L=self.length()
self.F=self.force()
self.rs=unit(sub(points[self.end].r,points[self.start].r))
self.re=unit(sub(points[self.start].r,points[self.end].r))
def updatePoints():
for i in range(0,len(points)):
points[i].F=[0.0,0.0,0.0]
for j in range(0,len(springs)):
if(springs[j].start==i):
flag=1
elif(springs[j].end==i):
flag=-1
else:
flag=0
if(points[i].FIXED):
points[i].F=[0.0,0.0,0.0]
else:
if(flag==1):
points[i].F=add(points[i].F,sMul(springs[j].F,springs[j].rs))
elif(flag==-1):
points[i].F=add(points[i].F,sMul(springs[j].F,springs[j].re))
else:
pass
if (GRAVITY and (not points[i].FIXED)):
points[i].F=add(points[i].F,sMul(g*points[i].m,[0,1,0]))
points[i].vUpdate()
points[i].rUpdate()
for i in range(0,len(springs)):
springs[i].update()
class vis3D:
def __init__(self):
self.BALL=[]
self.scene = canvas()
for i in range(0,len(points)):
self.BALL.append(sphere(pos=conVec(points[i].r), radius=0.4, color=color.red))
if HELICES:
self.HELIX=[]
for i in range(0,len(springs)):
self.HELIX.append(helix(pos=conVec(points[springs[i].start].r),axis=conVec(sMul(springs[i].L,springs[i].rs)), radius=0.4, color=color.blue))
def update(self):
updatePoints()
for i in range(0,len(points)):
self.BALL[i].pos=conVec(points[i].r)
if HELICES:
for i in range(0,len(springs)):
self.HELIX[i].pos=conVec(points[springs[i].start].r)
self.HELIX[i].axis=conVec(sMul(springs[i].L,springs[i].rs))
def run(self):
t=0.0
self.scene.background=color.white
display(self.scene)
while t<tMAX:
rate(int(1.0/DELTAt))
self.update()
t+=DELTAt
class gui:
def __init__(self):
self.pos = [widgets.Text(description='X',width=100),widgets.Text(description='Y',width=100 ),widgets.Text(description='Z',width=100)]
self.POS = widgets.HBox(children=self.pos)
self.vel=[widgets.Text(description='Vx',width=100),widgets.Text(description='Vy',width=100 ),widgets.Text(description='Vz',width=100)]
self.VEL=widgets.HBox(children=self.vel)
self.misc=[widgets.Text(description='Mass',width=100),widgets.widget_bool.Checkbox(description='Fixed',width=100)]
self.MISC=widgets.HBox(children=self.misc)
self.create=widgets.Button(description="Create Point",width=100)
self.NEXT = widgets.Button(description="Next",width=100)
self.sprAtt = [widgets.Text(description='Start',width=100),widgets.Text(description='End',width=100 )]
self.SPRATT = widgets.HBox(children=self.sprAtt)
self.sprProp = [widgets.Text(description='L0',width=100),widgets.Text(description='K',width=100 )]
self.SPRPROP = widgets.HBox(children=self.sprProp)
self.createSpr=widgets.Button(description="Create Spring",width=100)
self.grav=[widgets.widget_bool.Checkbox(description='Gravity',width=100)]
self.GRAV=widgets.HBox(children=self.grav)
self.START=widgets.Button(description="Start",width=100)
self.create.on_click(self.addPoint)
self.NEXT.on_click(self.nxt)
self.createSpr.on_click(self.addSpring)
self.START.on_click(self.start)
def display(self):
display(self.POS,self.VEL,self.MISC,self.create,self.NEXT)
def addPoint(self,b):
points.append(point([fl(self.pos[0].value),fl(self.pos[1].value),fl(self.pos[2].value)],[fl(self.vel[0].value),fl(self.vel[1].value),fl(self.vel[2].value)],fl(self.misc[0].value,m=1),i(self.misc[1].value)))
print("Point " +str(int(len(points)))+" Created.")
def nxt(self,b):
display(self.SPRATT,self.SPRPROP,self.GRAV,self.createSpr,self.START)
#make plot of point location numbered
def addSpring(self,b):
springs.append(spring(i(self.sprAtt[0].value)-1,i(self.sprAtt[1].value)-1,fl(self.sprProp[0].value),fl(self.sprProp[1].value)))
print("Spring Created Between Points " +str(i(self.sprAtt[0].value))+" and " + str(i(self.sprAtt[1].value))+".")
def start(self,b):
if self.grav[0].value:
global GRAVITY
GRAVITY = 1
self.visual=vis3D()
self.visual.run()
GUI=gui()
GUI.display()
Point 1 Created. Point 2 Created. Point 3 Created. Spring Created Between Points 1 and 3. Spring Created Between Points 2 and 3.