File: avatar.pyx

package info (click to toggle)
pyepl 1.1.0-3.1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,120 kB
  • sloc: cpp: 7,986; python: 6,026; makefile: 360; ansic: 132
file content (148 lines) | stat: -rw-r--r-- 4,853 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# PyEPL: hardware/vr/avatar.pyx
#
# Copyright (C) 2003-2005 Michael J. Kahana
# Authors: Ian Schleifer, Per Sederberg, Aaron Geller, Josh Jacobs
# URL: http://memory.psych.upenn.edu/programming/pyepl
#
# Distributed under the terms of the GNU Lesser General Public License
# (LGPL). See the license.txt that came with this file.

"""
This modules contains the LowVAvatar class.
"""

import pyepl.hardware.vr
import eyes
import itertools
import math
import ode
import numpy

cdef object unitz
unitz = numpy.array((0.0, 0.0, 1.0))

cdef extern from "ode/ode.h":
    ctypedef double dReal
    ctypedef dReal dMatrix3[4*3]
    void dRFromEulerAngles(dMatrix3 R, dReal phi, dReal theta, dReal psi)

def RFromEulerAngles(phi, theta, psi):
    """
    Calculate the rotation matrix for the given Euler angles. 
    """
    cdef dMatrix3 R
    dRFromEulerAngles(R, phi, theta, psi)
    return [R[0], R[1], R[2], R[4], R[5], R[6], R[8], R[9], R[10]]

class LowVAvatar:
    """
    A LowVAvatar represents a user's position, orientation, and body
    shape in the virtual environment.
    """
    def __init__(self, env, posorient = None):
        """
        Create a LowVAvatar.
        """
        self.env = env
        self.eyevector = (0, 0, 0)
        self.eyes = []
        if posorient is not None:
            self.posorient = posorient
        else:
            self.posorient = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
    def travel(self, **controls):
        """
        """
        self.posorient = self.getNewPosOrient(**controls)
        if controls.has_key("view_pitch"):
            vp = controls["view_pitch"]
        else:
            vp = 0.0
        self.posorient = (self.posorient[0] + self.eyevector[0], self.posorient[1] + self.eyevector[1], self.posorient[2] + self.eyevector[2],
                          self.posorient[3], self.posorient[4] + vp, self.posorient[5])
        for eye in self.eyes:
            eye.reposition(*self.posorient)
    def getNewPosOrient(self):  # To be overridden
        """
        """
        pass
    def positionOrientation(self):
        """
        Return a 6-tuple of position and orientation data: x, y, z,
        yaw, pitch, roll.
        """
        return self.posorient
    def teleport(self, pos = None, angle = None, tilt = None, roll = None):#FIX!!
        """
        Set the absolute position, angle, tilt, and roll.
        """
        pass #...
    def attachEye(self, eye):
        """
        Lock motion of eye with the position of this avatar.
        """
        self.eyes.append(eye)
    def dettachEye(self, eye):
        """
        Unlock motion of eye.
        """
        self.eyes.remove(eye)

class LowVAvatarSpeedBubble(LowVAvatar):
    """
    A LowVAvatar represents a user's position, orientation, and body
    shape in the virtual environment.
    """
    def __init__(self, env, posorient = None, radius = 0.5, eyeheight = 3.8, density = 1.0):
        """
        Create a LowVAvatar.
        """
        LowVAvatar.__init__(self, env, posorient)
        self.eyevector = (0, eyeheight - radius, 0)
        self.body = ode.Body(env.world)
        M = ode.Mass()
        M.setSphere(density, radius)
        self.body.setMass(M)
        self.geom = ode.GeomSphere(env.space, radius)
        self.geom.setBody(self.body)
        self.body.setPosition((self.posorient[0], self.posorient[1] + radius, self.posorient[2]))
        self.body.setRotation(RFromEulerAngles(self.posorient[4] * (numpy.pi / 180.0),
                                               self.posorient[3] * (numpy.pi / 180.0),
                                               self.posorient[5] * (numpy.pi / 180.0)
                                               )  # order...?  Only sure about yaw...
                              )
        self.geom.mu = 0
    def getNewPosOrient(self, forward_speed = 0.0, yaw_speed = 0.0):
        """
        """
        global unitz
        cdef float x
        cdef float y
        cdef float z
        cdef float yaw
        cdef float pitch
        cdef float roll

        rot = numpy.reshape(numpy.array(self.body.getRotation()), (3, 3))
        unitdir = -numpy.dot(rot, unitz)
        self.body.setLinearVel(unitdir * forward_speed)
        self.body.setAngularVel((0.0, -yaw_speed, 0.0))
        self.env.dynamicStep(30)

        rot = numpy.reshape(numpy.array(self.body.getRotation()), (3, 3))
        unitdir = numpy.dot(rot, unitz)

	# NB. for now all this only works for yaw

        xunit, yunit, zunit = unitdir

	# the following gives yaw values ranging from -90 to 270 deg.,
	# with 90 directly ahead, and -90 directly behind
        yaw = numpy.arctan(xunit/zunit) * (180.0 / numpy.pi)
        if zunit < 0.0:
            yaw = yaw + 180.0

        roll=0
        pitch=0
        x, y, z = self.body.getPosition()
        return (x, y, z, yaw, pitch, roll)