How to modify a variable when a while loop is running Python

1.1k views Asked by At

I am using wx.python along with VPython to make an orbit simulator, however i'm having trouble trying to get the sliders in the GUI to effect the simulation, I assume it's because I am trying to get the number associated with the slider button to go into a while loop when it is running.

So my question is, how do i get the function SetRate to update in the while loop located at the bottom of the code? (I have checked to see that the slider is retuning values)

Here is my code for reference:

Value = 1.0
dt = 100.0

def InputValue(Value):
    dt = Value

def SetRate(evt):
    global Value
    Value = SpeedOfSimulation.GetValue()
    return Value


    w = window(menus=True, title="Planetary Orbits",x=0, y=0, width = 1000, height = 1000)
    Screen = display(window = w, x = 30, y = 30, width = 700, height = 500)
    gdisplay(window = w, x = 80, y = 80 , width = 40, height = 20)

    p = w.panel # Refers to the full region of the window in which to place widgets

    SpeedOfSimulation = wx.Slider(p, pos=(800,10), size=(200,100), minValue=0, maxValue=1000)
    SpeedOfSimulation.Bind(wx.EVT_SCROLL, SetRate)


    TestData = [2, 0, 0, 0, 6371e3, 5.98e24, 0, 0, 0, 384400e3, 0, 0, 1737e3, 7.35e22, 0, 1e3, 0]
    Nstars = TestData[0]  # change this to have more or fewer stars

    G = 6.7e-11 # Universal gravitational constant

    # Typical values
    Msun = 2E30
    Rsun = 2E9
    vsun = 0.8*sqrt(G*Msun/Rsun)

    Stars = []
    colors = [color.red, color.green, color.blue,
              color.yellow, color.cyan, color.magenta]
    PositionList = []
    MomentumList = []
    MassList = []
    RadiusList = []

    for i in range(0,Nstars):
        s=i*8
        x = TestData[s+1]
        y = TestData[s+2]
        z = TestData[s+3]
        Radius = TestData[s+4]
        Stars = Stars+[sphere(pos=(x,y,z), radius=Radius, color=colors[i % 6],
                       make_trail=True, interval=10)]
        Mass = TestData[s+5]
        SpeedX = TestData[s+6]
        SpeedY = TestData[s+7]
        SpeedZ = TestData[s+8]
        px = Mass*(SpeedX)
        py = Mass*(SpeedY)
        pz = Mass*(SpeedZ)
        PositionList.append((x,y,z))
        MomentumList.append((px,py,pz))
        MassList.append(Mass)
        RadiusList.append(Radius)

    pos = array(PositionList)
    Momentum = array(MomentumList)
    Mass = array(MassList)
    Mass.shape = (Nstars,1) # Numeric Python: (1 by Nstars) vs. (Nstars by 1)
    Radii = array(RadiusList)

    vcm = sum(Momentum)/sum(Mass) # velocity of center of mass
    Momentum = Momentum-Mass*vcm # make total initial momentum equal zero


    Nsteps = 0
    time = clock()
    Nhits = 0

    while True:
        InputValue(Value)  #Reprensents the change in time 
        rate(100000)   #No more than 100 loops per second on fast computers

        # Compute all forces on all stars
        r = pos-pos[:,newaxis] # all pairs of star-to-star vectors (Where r is the Relative Position Vector
        for n in range(Nstars):
            r[n,n] = 1e6  # otherwise the self-forces are infinite
        rmag = sqrt(sum(square(r),-1)) # star-to-star scalar distances
        hit = less_equal(rmag,Radii+Radii[:,newaxis])-identity(Nstars)
        hitlist = sort(nonzero(hit.flat)[0]).tolist() # 1,2 encoded as 1*Nstars+2
        F = G*Mass*Mass[:,newaxis]*r/rmag[:,:,newaxis]**3 # all force pairs

        for n in range(Nstars):
            F[n,n] = 0  # no self-forces
        Momentum = Momentum+sum(F,1)*dt

        # Having updated all momenta, now update all positions         
        pos = pos+(Momentum/Mass)*dt

        # Update positions of display objects; add trail
        for i in range(Nstars):
            Stars[i].pos = pos[i]
1

There are 1 answers

0
otterb On

I know nothing about vpython but in a normal wxPython app, you will use wx.Timer instead of while loop.

here is an example of wx.Timer modified from https://www.blog.pythonlibrary.org/2009/08/25/wxpython-using-wx-timers/

You will want to separate the while loop part from your SetRate class method and put it in update.

import wx

class MyForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Timer Tutorial 1", 
                                   size=(500,500))

        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.update, self.timer)

        SpeedOfSimulation = wx.Slider(p, pos=(800,10), size=(200,100), minValue=0, maxValue=1000)
        SpeedOfSimulation.Bind(wx.EVT_SCROLL, SetRate)
        self.SpeedOfSimulation = SpeedOfSimulation

    def update(self, event):

      # Compute all forces on all stars

      SpeedOfSimulation = self.SpeedOfSimulation.GetValue()