Change of scene.center in while loop, by using keys

148 views
Skip to first unread message

Dolph

unread,
Sep 17, 2013, 8:54:09 AM9/17/13
to vpytho...@googlegroups.com
I am creating a small solar system simulation, using Euler method to solve differential equation. I would like to be able to push  "1" and the center of the window changes to the sun, and constantly follows the sun - if I push 2 the center is mercury and the camera constantly follows mercury's orbit, if 3 venus it follows venus and so on... I am, however, having some problems, I am using this definition to control the keyboard:

def movecam(evt):
        if evt.key=='4':
            scene.center=jorden.pos  #changes center to earth

while True:
    scene.bind('keydown',movecam)

When I push 4, it changes the position the earth, but is does not follow the earth, it stays at the coordinate the earth had when I pushed the key.

So here is my question, what do I have to do, so that a push on number 4, constantly follows the earth on its orbit, and not stays on earths coordinate at the time of the push.

I have copied the code below, but it is also attached as a file - I hope you can help, and thanks in advance :)
code:

from visual import *
import numpy as np
#position of planets and the sun
posi=np.float64([\
    [0,0,0],\
    [42161413.069884,-45995795.417714,-7626631.231823],\
    [27147052.840386,104324965.191569,-137545.717835],\
    [72912485.034296,128492107.836503,-3783.683563],\
    [3286927.595137,-217382103.987480,-4635816.911123],\
    [738897153.289695,51086053.832088,-16747248.921749],\
    [-1411857466.793479,-232625088.363710,60249379.843517],\
    [3004884271.398590,-46357351.039465,-39096065.105145],\
    [3795632708.220229,-2398654825.391835,-38068199.817074],\
    ])*10**3 #m
# velocities of planets and sun
vel=np.float64([\
    [0,0,0],\
    [26.237808,35.243482,0.472058],\
    [-34.009215,8.649499,2.081264],\
    [-26.380326,14.586547,0.000771],\
    [25.139808,2.447809,-0.566022],\
    [-1.064385,13.661247,-0.032978],\
    [1.048692,-9.540695,0.124877],\
    [0.054384,6.502420,0.023651],\
    [2.866484,4.636743,-0.161617],\
    ])*10**3 #m/s
#mass of planets and sun
m=np.float64([1.98855*10**30,3.3022*10**23,4.8685*10**24,5.9736*10**24,\
              6.4185*10**23,1.8986*10**27,5.6846*10**26,8.6810*10**25,\
              10.243*10**25]) #kg
fors=10**5 #magnification of planets
fors_sol=10**0 #magnification of the sun
#the following defines sphere of planets, and there trails
sol=sphere(pos=posi[0],radius=fors_sol*6.96342*10**8) #sol
sol.trail=curve()

merkur=sphere(pos=posi[1],radius=fors*2.438*10**3) #merkur
merkur.trail=curve()

venus=sphere(pos=posi[2],radius=fors*6.059*10**3) #venus
venus.trail=curve()

jorden=sphere(pos=posi[3],radius=fors*6.371*10**3,color=(0.9,0.1,0.1)) #jorden
jorden.trail=curve()

mars=sphere(pos=posi[4],radius=fors*3.396*10**3,color=(0.4,0.2,0.7)) #mars
mars.trail=curve()

jupiter=sphere(pos=posi[5],radius=fors*69.911*10**3) #jupiter
jupiter.trail=curve()

saturn=sphere(pos=posi[6],radius=fors*60.268*10**3) #saturn
saturn.trail=curve()

uranus=sphere(pos=posi[7],radius=fors*25.559*10**3) #uranus
uranus.trail=curve()

neptun=sphere(pos=posi[8],radius=fors*24.764*10**3) #neptun
neptun.trail=curve()

# some constants
G=-6.674*(10**-11)
a=np.zeros([9,3])
dt=60*60*24*10

#definition to move camera
def movecam(evt):
        if evt.key=='f':
            scene.center=jorden.pos

while True:
    scene.bind('keydown',movecam) #should move camera
    rate(60)
    F=np.zeros([9,3]) #define for matrix to zeroes
    #the following 2 for loops calculate the force each body
    #inact upon each other
    for i in range(0,9):
        for j in range(0,9):            
            if i==j:
                continue
            else:                
                r=posi[i,:]-posi[j,:]
                F[i,:]=F[i,:]+G*m[i]*m[j]*r/(np.linalg.norm(r)**3)                            
    for i in range(0,9): #Calculate the acceleration for each body
        a[i,:]=F[i,:]/m[i]
    vel=vel+dt*a #calcualte velocity
    posi=posi+dt*vel #calculate position

    #Updates position for each body
    sol.pos=posi[0]
    merkur.pos=posi[1]
    venus.pos=posi[2]
    jorden.pos=posi[3]
    mars.pos=posi[4]
    jupiter.pos=posi[5]
    saturn.pos=posi[6]
    uranus.pos=posi[7]
    neptun.pos=posi[8]
    
    #shows trail for each body
##    sol.trail.append(pos=sol.pos,color=sol.color)      
##    merkur.trail.append(pos=merkur.pos,color=merkur.color)
##    venus.trail.append(pos=venus.pos,color=venus.color)
    jorden.trail.append(pos=jorden.pos,color=jorden.color)
##    mars.trail.append(pos=mars.pos,color=mars.color)
##    jupiter.trail.append(pos=jupiter.pos)
##    saturn.trail.append(pos=saturn.pos)
##    uranus.trail.append(pos=uranus.pos)
##    neptun.trail.append(pos=neptun.pos)


sf.py

Bruce Sherwood

unread,
Sep 17, 2013, 12:20:56 PM9/17/13
to vpytho...@googlegroups.com
It's insufficient to set scene.center = jorden.pos just once; you need to set it continually in the loop. An appropriate data structure would be to put your planet spheres in a list, use your movecam function to specify one of the planets as an entry in the list (in a global variable "centering", say), and inside your loop continually set scene.center = planets[centering].pos. Note too that with a list of planets you could update the pos attributes more simply with

for i, planet in enumerate(planets):
    planet.pos = posi[i]

I encourage you to look at the documentation on Leaving a Trail (under Work with 3D objects), where you'll find easier-to-use ways of leaving a trail and options for specifying an interval (which is useful because the curve object starts interpolating when there are more than 1000 points).

Dolph

unread,
Sep 17, 2013, 1:22:50 PM9/17/13
to vpytho...@googlegroups.com
Thanks a lot :) it helped using a global variable, don't why I had not thought of that, I think I spend like 4 hours on this problem. I will take a look at Leaving a Trail, it seems a lot smarter than what I am doing at the moment. thanks again :)

Bruce Sherwood

unread,
Sep 17, 2013, 2:38:38 PM9/17/13
to vpytho...@googlegroups.com
Note that in Python to set a global variable from inside a def, you need to say

def f(x,y):
    global myvar

An alternative is to put the variable inside a list or other structure, like this:

A = [20, 30, 40]

def setA(i, x):
    A[i] = x

setA(1, -5)
print(A) # prints [20, -5, 40]

The value could for example be the first element in a list whose remaining elements are the spheres representing the planets.

You could also make your variable be an attribute of a class instance.


--
You received this message because you are subscribed to the Google Groups "VPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vpython-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Dolph

unread,
Sep 18, 2013, 2:42:24 PM9/18/13
to vpytho...@googlegroups.com
Using that global variable really helped :) I got an another question, maybe you know the anwser... I am using keys to change scene.range, so that I can zoom in/out - but when I zoom in at the earth (or any other body), I sometimes see it disappear when I zoom in, even though it only fills half the screen (or less), do you know why? It really puzzles me, because when I zoom in with the mouse, the planets does not disappear - it only does that when I zoom with buttons i.e. using scene.range. I might try using scene.scale instead, but I don't see why it should make a difference, and at any case, the plantes should not disappear. I hope you can help with this too, at any case thanks for your help so far :) I have attached the new file, and translating some variables into English, which might help.
sf.py

Dolph

unread,
Sep 18, 2013, 3:28:01 PM9/18/13
to vpytho...@googlegroups.com
On Wednesday, September 18, 2013 8:42:24 PM UTC+2, Dolph wrote:
Using that global variable really helped :) I got an another question, maybe you know the answer... I am using keys to change scene.range, so that I can zoom in/out - but when I zoom in at the earth (or any other body), I sometimes see it disappear when I zoom in, even though it only fills half the screen (or less), do you know why? It really puzzles me, because when I zoom in with the mouse, the planets does not disappear - it only does that when I zoom with buttons i.e. using scene.range. I have tried using scale, and same problem occurs. I hope you can help with this too, at any case thanks for your help so far :) I have attached the new file, and translating some variables into English, which might help.

Bruce Sherwood

unread,
Sep 18, 2013, 5:20:38 PM9/18/13
to vpytho...@googlegroups.com
It's not possible to run your program because you have your own .tga files for materials, and the program won't run without those files. But in any case it would be far easier to help you if you would post a short test routine that demonstrates the problem, rather than giving us a large program to wade through.

Dolph

unread,
Sep 19, 2013, 6:35:04 AM9/19/13
to vpytho...@googlegroups.com
I have tried recreating my code, but in the new simple file the problem does not occur. I have recorded the problem, and uploaded it on youtube: http://www.youtube.com/watch?v=Ns8EwDYWOgs There is an small update, which is also mentioned in the movie: The zoom function with the keyboard does not work, unless I zoom in with the mouse first - after that I can zoom in with the keyboard just fine. I have made a file which does not use any external pictures, but I am afraid it is not any simpler - if its too much work don't bother, I was just hoping it was a simple-question-simple-answer kind of thing, and you have been a great help so far.
solarsystemcopytestfile.py

Bruce Sherwood

unread,
Sep 19, 2013, 12:48:38 PM9/19/13
to vpytho...@googlegroups.com
Okay, I'm now able to see the effect. I'm guessing that this has something to do with the possible range of z in OpenGL (back to front), but like you I don't see why this works with the mouse and not with manipulating scene.range. I'll try to create a simple test case and post it to the bug list.

A couple of minor comments:

It is prudent to start VPython programs with this statement, which makes the program run the same way on Python 2 and Python 3:

from __future__ import division, print_function

Also, I'll not that 

        scene.center=posi[viewplnt]

is exactly the same as

        scene.center=posi[viewplnt,:]

Note that for the Earth there does exist materials.earth.
Reply all
Reply to author
Forward
0 new messages