[Edu-sig] And now for something completely different...

Kirby Urner pdx4d@teleport.com
Thu, 19 Apr 2001 09:28:06 -0700


At 03:31 PM 4/18/2001 -0400, you wrote:
>From: "Kirby Urner" <pdx4d@teleport.com>
>> I've taught my polyhedra to display themselves in .m format, via
>> a lg3d.py module, so now I can provide browsers with interactive
>> views such as found at:
>>
>>        http://www.inetarena.com/~pdx4d/ocn/lvmviews.html
>
>Kirby
>
>This is great news!
>
>I would love to see and try your lg3d.py module. Is it posted anywhere?
>

Jason -- I've bundled lg3d.py inside of python101.zip, which is linked
from each of my 'Numeracy + Computer Literacy' pages e.g.
http://www.inetarena.com/~pdx4d/ocn/numeracy0.html -- this zip also
contains vrml.py.  

Both lg3d.py and vrml.py are designed to mimic the interface exported 
by povray.py, and that's pretty well documented in numeracy1.html -- 
except that I'm in the process of upgrading povray.py slightly to 
make it easier to use textures.  

All of these modules work in complement with coords.py, which contains
my general vector classes, e.g. they all give you shaft(v), edge(v1,v2), 
point(v), and face(vlist), where v,v1,v2 are vectors and vlist is a 
list of vectors.  

   * shaft(v) draws from the origin to vector tip v, 
   * edge(v1,v2) draws an edge between the tips of v1 and v2, 
   * point(v) draws a sphere at the tip of v, and 
   * face(vlist) makes a polygon going around the points defined 
     by the vectors in vlist (which should all be coplanar).

The above methods all belong to whatever output object you've chosen,
i.e. some povray or LiveGraphics3D object.

So, for example, you could do something like this:

  >>> import povray, coords, lg3d
  >>> myfile = povray.Povray("coolgraphic.pov") # instantiate povray object
  >>> v1 = coords.Vector((1,0,0))               # define a vector
  >>> v2 = coords.Vector((-3,3,0))              # ...and another
  >>> myfile.edge(v1,v2)                        # use vectors to make an edge
  >>> myfile.close()                            # close the povray file

You would now have a file called "coolgraphic.pov" on your disk 
ready for rendering in povray, and containing the information
for displaying an edge running from (1,0,0) to (-3,3,0).  You could
have instantiated the Povray object with more parameters (e.g.
background color), but just a filename is sufficient.

Or, you might have gone:

  >>> myfile = lg3d.Lg3d("coolgraphic.m")
  >>> v1 = coords.Vector((1,0,0))
  >>> v2 = coords.Vector((-3,3,0))
  >>> myfile.edge(v1,v2)
  >>> myfile.close()

...which is essentially the same thing, except you've made myfile an 
Lg3d object vs. a Povray object -- same methods, but you're creating 
"coolgraphic.m" on your disk, suitable for embedding as the 
INPUT_FILE in the applet HTML for LiveGraphics3D.

My process for creating the various polyhedra at my website, in LG3D, 
Povray or VRML formats, is to use the above technology under a 
Polyhedron or Shape class which pre-assigns all the critical vertex 
information to vectors, and lists faces as tuples.  For example, 
my Cube class looks like this:

class Cube(Shape):
    """
                           Labels of   Numbers of
    Shape          Volume  Vertices    Vertices, Edges, Faces
    ---------------------------------------------------------   
    Duo-tet Cube       3      A-H           8      12      6
    """

    faces = [('A','H','C','F'),('A','H','B','G'),('B','E','C','H'),
             ('B','E','D','G'),('D','G','A','F'),('C','E','D','F')]

    sphcolor = cylcolor = "Green"

    def __init__(self):
        Shape.__init__(self)
        self.volume   = 3.0

You can see that 'A' must be the name of some vector, which in
this case is actually stored in the module itself as a global 
variable.  That's the entire cube class definition, as all the
code for translating, scaling and rotating is in the superclass,
i.e. part of Shape's definition (from which Cube inherits).

Note:  I don't explicitly give the edges, as these are implied
in the faces list, i.e. I have code that builds a list of 
vertex-pairs (edges) from a face-tuple such that ('A','H','C','F')
nets me ('A','H'),('H','C'),('C','F'),('F','A') -- just traveling
around the perimeter.  Of doing all the faces this way nets you
each edge twice, so I need to screen for duplications as I build
my edges list.  The method looks like this:

    def getedges(self):
        """Extract edges from the faces list.

        Face lists contain consecutive vertices, so build and edge
        list by taking pairs, with the last vertex connecting back
        to the first.  Use sort() to assure each edge is specified
        uniquely
        """        
        edges = []  # locally scoped
        for face in self.faces:    # e.g. ['A','B','C']
            for j in range(len(face)):
                candidate = [face[j],face[j-1]]
                candidate.sort()   # assure uniqueness
                if not tuple(candidate) in edges:
                    edges.append(tuple(candidate)) # add if new
        self.edges = edges

Anyway, that's the kind of stuff I'm doing on the back end.

Kirby