20nov10

We begin with an attempt to first annotate and then rewrite this
counter-geometrical document. Annotation: ;; rather than # or ##
which are the python comment meta-symbols.  

From http://vpython.org/webdoc/visual/frame.html
Here is an example of inadequate documentation. Unadorned lines are
from this webdoc.

Composite Objects with frame
;;Can't tell a technical term from the vulgar use of the word. 
;;Even in ascii something sensible, like 'frame' could be used
;; r

You can group objects together to make a composite object 
;; I would say "articulated objects, e.g. a blobby man"
that can be moved and rotated as though it were a single object. 
Create a frame object, and associate objects with that frame
;; How does one discover ALL the attributes of an object? surely
;; A cylinder has an axis. And, what is the origin of a cylinder?
;; How to discover it without lenghty experimentation. 
>>>python2.4 (should use 2.6 since that's holds the current visual)
>>>from visual import *
>>>f = frame()   #screen opens up with the default scene, I presume
>>>cylinder(frame=f, pos=(0,0,0), radius=0.1, length=1, color=color.cyan)
;; Does not explain how to read the axis of the cylinder.
;; wait, the cylinder shouldn't have an axis...
;; How find out the attributes of cylinder? ANSWER 
>>> dir(cylinder) ;; reports, interalia, and axis afterall. 
sphere(frame=f, pos=(1,0,0), radius=0.2, color=color.red)
>>> f.axis  ;; reports "vector(1,0,0)
>>> f.axis = (1,1,0) ;; does
f.axis = (0,1,0)
f.pos = (-1,0,0)
;; wow, how confusing. There is a big difference between:
>>> f.pos ;; which reports the current frame position and 
>>> f.pos = (-1,0,0) ;; which changes it.

By default, frame() has a position of (0,0,0) and axis in the x 
direction (1,0,0). The cylinder and sphere are created within the frame. 
When any of the frame attributes are changed (pos, x, y, z, axis, or up), 
the composite object is reoriented and repositioned.

;; Let's try doing this in the right way. We need a 'frame' and an orientable
object. 

>>> cyl=cylinder(frame=f, pos=(0,1,0), axis(0,0,-1), radius=0.02, color=color.yellow)
SyntaxError: non-keyword arg after keyword arg

;;Doesn't make much sense. Anyway, a little experimentation reveals that
;;the frame has a 'pos, axis, up' and so does the frame, all of which can
;;be changed, and "used" for other objects after it was defined. 
;;the visual library is anything but minimalist. Kitchen sink present.
;;and some experimentation reveals that the origin of the cylinder, but 
;;known as its 'pos', is in the center of the base, or, better, the tail
;;of its 'axis' attribute. And 'up' must be where the head is. NO
;; 'up' can even be parallel to 'axis' .... WOW ... we need a glyph primitive
;; that isn't as symmetrical as a sphere, cylinder, or cone.
;; unfortunately, the 'pos' of a box seems to be at its centroid, like
;; a good physicist might do, but not much good for a blobby-bone.

Another frame attribute is objects, which is a list of currently visible 
objects contained in the frame (the list does not include objects that are 
currently invisible). If you want to make all the objects in a frame be 
red, do the following (assume the frame is named f):

for obj in f.objects:
obj.color = color.red

If you use this method to make all the objects invisible, the f.objects 
list will be empty. If you need a list containing all the objects, both 
visible and invisible, you need to maintain your own list of objects.

If ball is an object in a frame, ball.pos is the position local to the frame, 
not the actual position in "world space". Here is a routine that will 
calculate the position of a vector such as ball.pos in world space:

def world_space_pos(frame, local):
"""Returns the position of local in world space."""
x_axis = norm(frame.axis)
z_axis = norm(cross(frame.axis, frame.up))
y_axis = norm(cross(z_axis, x_axis))
return frame.pos+local.x*x_axis+local.y*y_axis+local.z*z_axis
