Hi all,
 I'm putting together a simple movable object class for 3d objects
(see file) with orientations etc. using euclid.py.  It essentially
defines an anchor position and orientation for some object and does
the math to move and rotate them.  I left a hook for subclasses to
update their coordinates based on the orientation of the object. My
goal is to have a program that draws simple objects (nodes, lines,
rectangles) and allow the user to move and rotate them (think a very
simple CAD program).  My other goal is to grok 3D graphics concepts.

With that in mind 2 Questions:
 - I plan to add a hook for drawing the object.  Any recommendations
for how to best incorporate this with pyglet (i.e. draw will draw to a
pyglet window).  My only thought is to put the glBegin glEnd block in
the draw function and try to leave it general.
 - I plan to have a mesh for the rectangle class which stores all the
coordinates which make up the rectangle mesh.  Is there a common way
to store these bunch of points that will move and rotate together.  I
could have a for loop iterate over all the coordinates and rotate/move
each one at a time but it seems logical to use a 4 x nCoordintes
matrix and do matrix multiplication.  Downside is this will require a
nd_array class (probably from numpy).  I'm leaning toward just
importing numpy.   Is this overkill or is this common?

Thank you all

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pyglet-users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/pyglet-users?hl=en
-~----------~----~----~----~------~----~------~--~---

#!/usr/bin/env python
#
# [email protected]
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
# 
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
# for more details.
# 
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA


from euclid import Point3, Vector3, Matrix4, Quaternion
import math

class MovableObject3():
    '''A movable, rotatable 3D object with local axes. ''' 
#    some ideas borrowed from Ogre3D's Vector3 and Node class

#    some class constants
    ZERO = Vector3(0, 0, 0)
    UNIT_X = Vector3(1, 0, 0)
    UNIT_Y = Vector3(0, 1, 0)
    UNIT_Z = Vector3(0, 0, 1)
    UNIT_SCALE = Vector3(1, 1, 1)
    DEFAULT_UP = UNIT_Y

    def __init__(self, x, y, z):
        '''Return MovableObject3 object at position x y z with default orientation'''
        self.position = Point3(x, y, z)
        self.local_1_vector = self.UNIT_X
        self.local_1_position = self.position + self.local_1_vector
        self.up_vector = self.DEFAULT_UP
        self.up_position = self.position + self.up_vector

        # get orientation
        self.new_look_at(self.position, self.local_1_position, self.up_position)
       
    def __repr__(self):
        return 'MovableObject(position %s, local_1 %s, up %s)' % \
        (str(self.position),str(self.local_1_position),str(self.up_position))

    def update_coordinates(self):
        '''Hook for subclasses to update the coordinates as the object moves.'''
        raise NotImplementedError 
    
    def new_look_at(self, position, local_1_position, up_position):
        '''Rotate orientation to new positition ala glulookat.'''
#        define u1 as local 1; define u3 based on u1 and up; 
#        find u2 based on u3 and u1
        u1 = local_1_position - position
        up = up_position - position
        u1.normalize()
        up.normalize()
        u3 = u1.cross(up)
        u3.normalize()
        u2 = u3.cross(u1)
        u2.normalize()

        orientation = Matrix4()
#        orientation.identity()
        orientation.a, orientation.e, orientation.i = u1.x, u1.y, u1.z
        orientation.b, orientation.f, orientation.j = u2.x, u2.y, u2.z
        orientation.c, orientation.g, orientation.k = u3.x, u3.y, u3.z
        orientation.d, orientation.h, orientation.l = position.x, position.y, position.z
        self.position = position
        self.orientation = orientation
        self.local_1_position = local_1_position
        self.local_1_vector = u1
        self.up_position = up_position
        self.up_vector = u2
        self.update_coordinates()

    def move_position_by(self, position_delta):
        '''Move object by a distance delta.'''
        assert isinstance(position_delta, Vector3)
        trans_matrix = Matrix4()
#        trans_matrix.identity()
        trans_matrix.d, trans_matrix.h, trans_matrix.l = position_delta.x, position_delta.y, position_delta.z
        self.orientation = trans_matrix * self.orientation
        self.position = trans_matrix * self.position
        self.local_1_position = trans_matrix * self.local_1_position
        self.up_position = trans_matrix * self.up_position
#        update Coordinates 
        self.update_coordinates()

    def move_position_to(self, new_position):
        '''Move object to new position.'''
        assert isinstance(new_position,Vector3) # point3 are vectors3
        position_delta = new_position - self.position
        self.move_position_by(position_delta)

    def rotate_by_angle_axis(self, angle, axis, angle_in_degrees=True, origin=None):
        '''Rotate object by angle about axis. if origin is provided the object is moved, rotated then moved back'''

        assert isinstance(axis, Vector3) 

        if origin:
            assert isinstance(origin, Vector3)
#            move to origin
            self.move_position_by(-origin)

#        convert to radians
        if angle_in_degrees is True:
            angle *= math.pi/180.0

        rot_matrix = Matrix4()
        rot_matrix = rot_matrix.new_rotate_axis(angle, axis)
        self.orientation = rot_matrix * self.orientation
        self.position = rot_matrix * self.position
        self.local_1_position = rot_matrix * self.local_1_position
        self.local_1_vector = self.local_1_position - self.position
        self.up_position = rot_matrix * self.up_position
        self.up_vector = rot_matrix * self.up_vector
#        update Coordinates (not implemented) 
        self.update_coordinates()

        if origin:
#            move back
            self.move_position_by(origin)

    def rotate_to_angle_axis(self, angle, axis, angle_in_degrees=True, origin=None):
        '''Rotate object to angle about axis.'''
#        reset object local_1 and up to the default
        self.local_1_vector = self.UNIT_X
        self.local_1_position = self.position + self.local_1_vector
        self.up_vector = self.DEFAULT_UP
        self.up_position = self.position + self.up_vector
        self.new_look_at(self.position, self.local_1_position, self.up_position)

#        rotate to angle axis
        self.rotate_by_angle_axis(angle, axis, angle_in_degrees, origin)


    def new_orientation(self, orientation):
        '''Define a new orientation for the object.'''
        assert isinstance(orientation, Matrix4)
        self.orientation = orientation
        self.position = self.orientation * self.ZERO
        self.local_1_position = self.orientation * self.local_1_position
        self.local_1_vector = self.local_1_position - self.position
        self.up_position = self.orientation * self.up_position
        self.up_vector = self.up_position - self.position
        self.update_coordinates()
 

class Node3(MovableObject3):
    '''A rotatable movable 3D node with local axes.'''
#    Node3 extends MovableObject3 with a coordinates attribute defined
    def __init__(self, x, y, z):
        MovableObject3.__init__(self, x, y, z)
        self.coordinates = self.position

    def __repr__(self):
        return 'Node3(coordinates %s, local_1 %s, up %s)' % (str(self.position), str(self.local_1_position), str(self.up_position))
    
    def update_coordinates(self):
        self.coordinates = self.position


#class Rectangle3(MovableObject3):
#    '''A rotatable, movable rectangle in 3space.
#    def __init__(self, x, y, z, len_dir_1, len_dir_2, nElements_1, nElements_2):
#        MovableObject3.__init__(self, x, y, z)
#        self.len_dir_1 = len_dir_1
#        self.len_dir_2 = len_dir_2
#        self.nElements_1 = nElements_1
#        self.nElements_2 = nElements_2
#        self.coordinates = self.mesh_grid()

#    def update_coordinates(self):
#        self.mesh_grid()

#    def mesh_grid():
#        pass
        
    
if __name__=='__main__':
    print "new node at 1,2,3"
    n1=Node3(1,2,3)
    print n1

    print "move node by 20,20,-3"
    n1.move_position_by(Vector3(20,20,-3))
    print n1
    
    print "move node to 2,2,3"
    n1.move_position_to(Point3(2,2,3))
    print n1
    
    print "rotate by angle 30deg about z axis 0,0,1 origin at zero"
    n1.rotate_by_angle_axis(30, Vector3(0, 0, 1), angle_in_degrees=True)
    print n1

    print "rotate by angle 30deg about 1,1,1 origin at point"
    n1.rotate_by_angle_axis(30, Vector3(1, 1, 1), angle_in_degrees=True, origin=n1.position)
    print n1
#    coordinate 0.73, 2.72, 3.00
#    local 1 1.40, 3.48, 2.96
#    up 0.07, 3.35, 3.41

    print "rotate by angle 1.2 radians about 1,4,2 axis origin at node"
    n1.rotate_by_angle_axis(1.2, Vector3(1,4,2), angle_in_degrees=False, origin=n1.position)
    print n1
#    coordinate 0.73, 2.72, 3.00
#    local 1 0.74, 3.71, 2.81
#    up 0.65, 2.92, 3.98

Reply via email to