class Transform(object): '''Class to represent transform operations. Note that the operations provided are isolated from each other, in the sense that the sequence of operations is always: rotation, scale and translation. That means that an operation add to itself and the final outcome will always be in the following order: accumulated scale, accumulated rotation and accumulated translation.''' def __init__(self): self.quaternion = Quaternion((1, 0, 0, 0)) self.translation = Vector3(0.0, 0.0, 0.0) self.scale_factor = 1.0 def scale(self, scale): self.scale_factor *= scale def rotation_quaternion(self, vector, angle): if not vector.length(): return None c = math.cos(angle / 2.0) v = math.sin(angle / 2.0) * vector.normalized() q = Quaternion((c, v.x, v.y, v.z)) q.normalize() return q def rotate(self, vector, angle): q = self.rotation_quaternion(vector, angle) if not q: return self.quaternion = q * self.quaternion self.quaternion.normalize() def set_rotation(self, vector, angle): q = self.rotation_quaternion(vector, angle) if not q: return self.quaternion = q def set_euler(self, roll, pitch, yaw): self.quaternion = Quaternion((roll, pitch, yaw)) self.quaternion.normalize() def translate(self, d): self.translation += d def mat4(self): s = self.scale_factor m = self.quaternion.dcm d = self.translation return (c_float * 16)( s * m.a.x, s * m.b.x, s * m.c.x, 0, s * m.a.y, s * m.b.y, s * m.c.y, 0, s * m.a.z, s * m.b.z, s * m.c.z, 0, d.x, d.y, d.z, 1 ) def apply(self, v): v = self.quaternion.transform(v) * self.scale_factor v += self.translation return v
def rotation_quaternion(self, vector, angle): if not vector.length(): return None c = math.cos(angle / 2.0) v = math.sin(angle / 2.0) * vector.normalized() q = Quaternion((c, v.x, v.y, v.z)) q.normalize() return q