VPython 7 Keyboard Input

73 views
Skip to first unread message

Sarah Kim

unread,
Apr 16, 2018, 1:03:16 PM4/16/18
to VPython-users
Hi, 

I'm trying to create a module where a 3D bent atom is portrayed, and users can rotate the atom by pressing left/right arrows and increase the angle between the outer atoms by pressing up/down arrows. This is the code I have so far:

def bentStructure():

#angle between two outer atoms

angle = math.pi/2.5

singleBondLen = 1

centralAtom = sphere(pos = vector(0, 0, 0), radius = 0.25, color = color.red)

atom1 = sphere(pos = vector(singleBondLen*math.sin(angle/2),

singleBondLen*math.cos(angle/2), 0), radius = 0.15,

color = color.blue)

atom2 = sphere(pos = vector(-singleBondLen*math.sin(angle/2),

singleBondLen*math.cos(angle/2), 0), radius = 0.2,

color = color.green)

bond1 = cylinder(pos = atom1.pos, radius = 0.07,

axis = centralAtom.pos - atom1.pos,

color = vector(0.3, 0.3, 0.3))

bond1 = cylinder(pos = atom2.pos, radius = 0.07,

axis = centralAtom.pos - atom2.pos,

color = vector(0.3, 0.3, 0.3))

#accept user input: keyboard right/left/up/down arrows

ev = scene.waitfor('keydown')

if ev.event == "left":

atom1.rotate(angle = math.pi/8, axis = vec(0, 1, 0))

atom2.rotate(angle = math.pi/8, axis = vec(0, 1, 0))

elif ev.event == "right":

atom1.rotate(angle = -math.pi/8, axis = vec(0, 1, 0))

atom2.rotate(angle = -math.pi/8, axis = vec(0, 1, 0))

elif ev.event == "up":

angle += math.pi/8

elif ev.event == "down":

angle -= math.pi/8


 When I run this, the screen opens in a browser and I'm unable to press any keys to make the user interact with the graphics. Is there a way I can get this to work?

Bruce Sherwood

unread,
Apr 16, 2018, 5:16:19 PM4/16/18
to VPython-users
You need to test ev.key, not ev.event (which is "keydown"). See

    http://www.glowscript.org/docs/VPythonDocs/keyboard.html

Also, you need to specify an origin for the rotation of atom1 and atom2, because the default is to rotate about the object's origin, which isn't what you want to do with these sphere objects.

I'm guessing that you want the entire molecule to rotate. If so, it's very convenient to create a "compound" object:

    c = compound([centralAtom, atom1, atom2, bond1, bond2)

c.pos will be at the geometrical center of the molecule, which means that you won't have to specify an origin in the rotations.

Since you reference sphere, not vpython.sphere, presumably you are using from vpython import *, and this import also imports all of math, clock(), random(), and arange(). So you can say cos instead of math.cos.

Bruce

P.S. Currently keyboard events are swallowed by a Jupyter notebook, so your program won't run there. Of course you could also just rely on the builtin rotations available with the mouse.

Sarah Kim

unread,
Apr 17, 2018, 1:19:52 PM4/17/18
to VPython-users
Thank you so much!

On a separate note, is there a way I can type long text and display it on the screen? I used 

part1Text = text(text = """With this option, you will be able to simulate a

molecule with a chemical formula of your choice.

It needs to be an existing compound, of course.

First, select an element from the provided

selection. Then, select a number corresponding

to the number of atoms of the chosen element.

Repeat until you have the chemical formula you

wish to simulate.""")

so far, but VPython doesn't seem to display the whole text. It gets cut off at the third line.

Bruce Sherwood

unread,
Apr 17, 2018, 3:37:04 PM4/17/18
to VPython-users
If you open the browser console (Ctrl-Shift-j) you'll see this error message, due to a limitation of WebGL, the 3D graphics library built into the browser, to indexes being only 16 bits:

     Uncaught Error: Currently the number of vertices is limited to 65536.

You are trying to display a very long passage of 3D text, which requires a huge number of triangles to render (an isolated triangle is made of 3 vertex objects, but if the colors and normals of adjacent triangles are identical, vertex objects can be shared).

You could break up the display into several text statements, but the characters will be so small and indistinguishable from 2D text that it doesn't make sense to use such an extremely heavyweight object. Instead, set scene.caption = your text, which will display the text below the 3D canvas. Of if for some reason it is essential that the text be displayed on the canvas itself, use a label object.

Bruce

Reply all
Reply to author
Forward
0 new messages