Rotating a frame object. PROBLEM

424 views
Skip to first unread message

Geoff Tovey

unread,
May 7, 2014, 1:02:27 PM5/7/14
to vpytho...@googlegroups.com
"""
I have a problem with a VPython script which rotates a frame object about its
Z axis.  I do not want to use rotate(), as I want to set the orientation
absolutely, not relative to its current orientation.  So I alter the axis
attribute of the frame.  The result is that the frame rotates correctly,
but the problem is that for some orientations the frame reverses its Z
direction.  What causes it, how can I stop it happening, or is there a
"work around"?  Any help would  be appreciated.  I do not want to use
rotate().  The following script is a distillation of my script, and running
it demonstrates the problem.

========================================"""
import visual as vs

frame1 = vs.frame()
vs.box() # marks frame origin (centre of rotation)  

vs.curve( frame=frame1, pos=[(0,0,0),(8,0,0),(8,0,4),(8,2,4)] ) # the "hook"

while True:
    for angle in range( 0, 360, 20):  # FOR EACH VIDEO FRAME, Degrees
        angleR = vs.radians(angle)
        frame1.axis = ( vs.cos(angleR), vs.sin(angleR), 0) # set its orientation
        if frame1.frame_to_world( (0,0,10)).z < 0:
            print "ERROR at",
        else: print "OKAY at",
        print angle ,"degrees"
        vs.scene.waitfor('click')

Bruce Sherwood

unread,
May 7, 2014, 6:01:24 PM5/7/14
to vpytho...@googlegroups.com
Thanks much for the clear test case showing a problem with setting the axis of a frame, which I've posted to the VPython issues on GitHub. Unfortunately I don't know of any workaround other than using frame.rotate, which I realize may not be feasible in your application.

Bruce Sherwood

unread,
May 8, 2014, 3:09:01 PM5/8/14
to vpytho...@googlegroups.com
I'll share that in this particular case Tovey found that setting the frame axis to (0,0,1) fixed the problem, but of course the bug needs to be addressed.

Geoff Tovey

unread,
May 9, 2014, 2:09:10 AM5/9/14
to vpytho...@googlegroups.com
"""
I think I may have come nearer to a solution to my own problem.  This is my guess at the way
VPython handles orientation.
It considers that an object (such as a frame) has a major axis and a minor one.  In the case
of a frame the major axis is X, and the minor axis is Y.  You can set the major axis using
the axis attribute.   But doing that does not fix the orientation completely; the frame can
still rotate about its major axis.  VPython provides the up attribute to fix that.  It rotates the
frame so that its minor axis aligns as nearly as possible with frame.up. 

Consider the above guesswork applied to the demo script.  The script rotates the frame about
the z axis. At angle 0 its X axis is horizontal, and  frame.up being (0,1,0) causes the Y axis to
be upwards.  As angle increases both X and Y axes rotate about the Z axis until at 90 the
Y axis is horizontal. If angle then increased the Y axis would point slightly downwards.
But that disagrees with the frame.up value, so VPython rotates the frame by 180 degrees
about its major axis.  This has the effect of reversing both the Y and Z directions.
The frame.up value is satisfied because the minor axis now points slightly upwards.
The same thing happens when angle reaches 270:  VPython rotates the frame a further 180 degrees.

In summary the demo script has an error of omission: it sets the axis attribute but fails
to set the up attribute.  Both are needed to completely specify the orientation.  Not intuitive!

But there is still a problem. I inserted code which sets the up attribute according to the above
guesswork - and the animation is still wrong (although better).  It goes wrong when angle is near
270.  Any ideas?

Below is the updated demo script.   I am unsure how to post this correctly - so I will guess. 

========================================"""
import visual as vs

frame1 = vs.frame()
vs.box() # marks frame origin (centre of rotation)  

vs.curve( frame=frame1, pos=[(0,0,0),(8,0,0),(8,0,4),(8,2,4)] ) # the "hook"

while True:
    for angle in range( 0, 360, 10):  # FOR EACH VIDEO FRAME, Degrees
        angleR = vs.radians(angle)
        if angle > 90 and angle < 270: frame1.up = (0,-1,0)  ############# NEW
        else: frame1.up = (0,1,0)                            ############# NEW
        frame1.axis = ( vs.cos(angleR), vs.sin(angleR),0 ) # set its orientation
Reply all
Reply to author
Forward
0 new messages