| 1 |
# standard python libs |
|---|
| 2 |
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG |
|---|
| 3 |
import uuid |
|---|
| 4 |
import struct |
|---|
| 5 |
import math |
|---|
| 6 |
|
|---|
| 7 |
# pyogp |
|---|
| 8 |
from pyogp.lib.base.exc import DataParsingError |
|---|
| 9 |
|
|---|
| 10 |
# pyogp messaging |
|---|
| 11 |
|
|---|
| 12 |
# initialize logging |
|---|
| 13 |
logger = getLogger('pyogp.lib.base.datatypes') |
|---|
| 14 |
log = logger.log |
|---|
| 15 |
|
|---|
| 16 |
class Vector3(object): |
|---|
| 17 |
""" represents a vector as a tuple""" |
|---|
| 18 |
|
|---|
| 19 |
def __init__(self, bytes = None, offset = 0, X = 0.0, Y = 0.0, Z = 0.0): |
|---|
| 20 |
|
|---|
| 21 |
if bytes != None: |
|---|
| 22 |
|
|---|
| 23 |
self.unpack_from_bytes(bytes, offset) |
|---|
| 24 |
|
|---|
| 25 |
else: |
|---|
| 26 |
|
|---|
| 27 |
if type(X) != float: |
|---|
| 28 |
self.X = float(X) |
|---|
| 29 |
else: |
|---|
| 30 |
self.X = X |
|---|
| 31 |
if type(Y) != float: |
|---|
| 32 |
self.Y = float(Y) |
|---|
| 33 |
else: |
|---|
| 34 |
self.Y = Y |
|---|
| 35 |
if type(Z) != float: |
|---|
| 36 |
self.Z = float(Z) |
|---|
| 37 |
else: |
|---|
| 38 |
self.Z = Z |
|---|
| 39 |
|
|---|
| 40 |
def unpack_from_bytes(self, bytes, offset): |
|---|
| 41 |
""" unpack floats from binary """ |
|---|
| 42 |
|
|---|
| 43 |
# unpack from binary as Little Endian |
|---|
| 44 |
self.X = struct.unpack("<f", bytes[offset:offset+4])[0] |
|---|
| 45 |
self.Y = struct.unpack("<f", bytes[offset+4:offset+8])[0] |
|---|
| 46 |
self.Z = struct.unpack("<f", bytes[offset+8:offset+12])[0] |
|---|
| 47 |
|
|---|
| 48 |
def get_bytes(self): |
|---|
| 49 |
""" get bytes """ |
|---|
| 50 |
|
|---|
| 51 |
return struct.pack("<3f", self.X, self.Y, self.Z) |
|---|
| 52 |
|
|---|
| 53 |
def data(self): |
|---|
| 54 |
|
|---|
| 55 |
return ((self.X, self.Y, self.Z)) |
|---|
| 56 |
|
|---|
| 57 |
def copy(self): |
|---|
| 58 |
return Vector3( X = self.X, Y = self.Y, Z = self.Z ) |
|---|
| 59 |
|
|---|
| 60 |
def __repr__(self): |
|---|
| 61 |
""" represent a vector as a string """ |
|---|
| 62 |
|
|---|
| 63 |
return str((self.X, self.Y, self.Z)) |
|---|
| 64 |
|
|---|
| 65 |
def __call__(self): |
|---|
| 66 |
""" represent a vector as a tuple """ |
|---|
| 67 |
|
|---|
| 68 |
return ((self.X, self.Y, self.Z)) |
|---|
| 69 |
|
|---|
| 70 |
def dist_squared(a, b): |
|---|
| 71 |
x = a.X - b.X |
|---|
| 72 |
y = a.Y - b.Y |
|---|
| 73 |
z = a.Z - b.Z |
|---|
| 74 |
return x*x + y*y + z*z |
|---|
| 75 |
dist_squared = staticmethod(dist_squared) |
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 |
class Quaternion(object): |
|---|
| 79 |
""" represents a quaternion as a tuple""" |
|---|
| 80 |
|
|---|
| 81 |
def __init__(self, bytes = None, offset = 0, length = 4, X = 0.0, Y = 0.0, Z = 0.0, W = 0.0): |
|---|
| 82 |
|
|---|
| 83 |
if bytes != None: |
|---|
| 84 |
|
|---|
| 85 |
self.unpack_from_bytes(bytes, offset, length) |
|---|
| 86 |
|
|---|
| 87 |
else: |
|---|
| 88 |
|
|---|
| 89 |
if type(X) != float: |
|---|
| 90 |
self.X = float(X) |
|---|
| 91 |
else: |
|---|
| 92 |
self.X = X |
|---|
| 93 |
if type(Y) != float: |
|---|
| 94 |
self.Y = float(Y) |
|---|
| 95 |
else: |
|---|
| 96 |
self.Y = Y |
|---|
| 97 |
if type(Z) != float: |
|---|
| 98 |
self.Z = float(Z) |
|---|
| 99 |
else: |
|---|
| 100 |
self.Z = Z |
|---|
| 101 |
if type(W) != float: |
|---|
| 102 |
self.W = float(W) |
|---|
| 103 |
else: |
|---|
| 104 |
self.W = W |
|---|
| 105 |
|
|---|
| 106 |
def unpack_from_bytes(self, bytes, offset, length=4): |
|---|
| 107 |
""" unpack floats from binary """ |
|---|
| 108 |
|
|---|
| 109 |
# unpack from binary as Little Endian |
|---|
| 110 |
self.X = struct.unpack("<f", bytes[offset:offset+4])[0] |
|---|
| 111 |
self.Y = struct.unpack("<f", bytes[offset+4:offset+8])[0] |
|---|
| 112 |
self.Z = struct.unpack("<f", bytes[offset+8:offset+12])[0] |
|---|
| 113 |
|
|---|
| 114 |
if length == 4: |
|---|
| 115 |
self.W = struct.unpack("<f", bytes[offset+12:offset+16])[0] |
|---|
| 116 |
|
|---|
| 117 |
else: |
|---|
| 118 |
# Unpack from vector3 |
|---|
| 119 |
t = 1.0 - (self.X*self.X + self.Y*self.Y + self.Z*self.Z) |
|---|
| 120 |
if t > 0: |
|---|
| 121 |
self.W = math.sqrt(t) |
|---|
| 122 |
else: |
|---|
| 123 |
# Avoid sqrt(-episilon) |
|---|
| 124 |
self.W = 0 |
|---|
| 125 |
|
|---|
| 126 |
def get_bytes(self): |
|---|
| 127 |
""" get bytes """ |
|---|
| 128 |
|
|---|
| 129 |
return struct.pack("<4f", self.X, self.Y, self.Z, self.W) |
|---|
| 130 |
|
|---|
| 131 |
def data(self): |
|---|
| 132 |
|
|---|
| 133 |
return ((self.X, self.Y, self.Z, self.W)) |
|---|
| 134 |
|
|---|
| 135 |
def copy(self): |
|---|
| 136 |
return Quaternion(X=self.X, Y=self.Y, Z=self.Z, W=self.W) |
|---|
| 137 |
|
|---|
| 138 |
def __repr__(self): |
|---|
| 139 |
""" represent a quaternion as a string """ |
|---|
| 140 |
|
|---|
| 141 |
return str((self.X, self.Y, self.Z, self.W)) |
|---|
| 142 |
|
|---|
| 143 |
def __call__(self): |
|---|
| 144 |
""" represent a quaternion as a tuple """ |
|---|
| 145 |
|
|---|
| 146 |
return ((self.X, self.Y, self.Z, self.W)) |
|---|
| 147 |
|
|---|
| 148 |
class UUID(object): |
|---|
| 149 |
""" represents a uuid as, well, a uuid |
|---|
| 150 |
|
|---|
| 151 |
inbound LLUUID data from packets is already UUID(), they are |
|---|
| 152 |
already the same 'datatype' |
|---|
| 153 |
""" |
|---|
| 154 |
|
|---|
| 155 |
def __init__(self, string = '00000000-0000-0000-0000-000000000000', bytes = None, offset = 0): |
|---|
| 156 |
|
|---|
| 157 |
if bytes != None: |
|---|
| 158 |
|
|---|
| 159 |
self.unpack_from_bytes(bytes, offset) |
|---|
| 160 |
|
|---|
| 161 |
else: |
|---|
| 162 |
|
|---|
| 163 |
self.uuid = uuid.UUID(string) |
|---|
| 164 |
|
|---|
| 165 |
def random(self): |
|---|
| 166 |
|
|---|
| 167 |
if str(self.uuid) == '00000000-0000-0000-0000-000000000000': |
|---|
| 168 |
self.uuid = uuid.uuid4() |
|---|
| 169 |
return self.uuid |
|---|
| 170 |
|
|---|
| 171 |
else: |
|---|
| 172 |
log(WARNING, "Attempted to overwrite a stored uuid %s with a random, that is a bad idea..." % (str(self.uuid))) |
|---|
| 173 |
|
|---|
| 174 |
def unpack_from_bytes(self, bytes, offset): |
|---|
| 175 |
""" unpack uuid from binary """ |
|---|
| 176 |
|
|---|
| 177 |
# unpack from binary |
|---|
| 178 |
self.uuid = uuid.UUID(bytes = bytes[offset:offset+16]) |
|---|
| 179 |
|
|---|
| 180 |
def get_bytes(self): |
|---|
| 181 |
""" get bytes """ |
|---|
| 182 |
|
|---|
| 183 |
return str(self.uuid.bytes) |
|---|
| 184 |
|
|---|
| 185 |
def data(self): |
|---|
| 186 |
""" represent a uuid as, well, a uuid """ |
|---|
| 187 |
|
|---|
| 188 |
return self.uuid |
|---|
| 189 |
|
|---|
| 190 |
def copy(self): |
|---|
| 191 |
return UUID(string=str(self.uuid)) |
|---|
| 192 |
|
|---|
| 193 |
def __repr__(self): |
|---|
| 194 |
""" represent a uuid as a string """ |
|---|
| 195 |
|
|---|
| 196 |
return str(self.uuid) |
|---|
| 197 |
|
|---|
| 198 |
def __call__(self): |
|---|
| 199 |
""" represent a uuid as, well, a uuid """ |
|---|
| 200 |
|
|---|
| 201 |
return self.uuid |
|---|
| 202 |
|
|---|
| 203 |
|
|---|
| 204 |
def __eq__(self, other): |
|---|
| 205 |
if hasattr(other,'uuid'): |
|---|
| 206 |
return self.uuid == other.uuid |
|---|
| 207 |
else: |
|---|
| 208 |
return False |
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 |
def __xor__(self, arg): |
|---|
| 212 |
""" the xor of two UUIDs """ |
|---|
| 213 |
temp = self.uuid.int ^ arg.uuid.int |
|---|
| 214 |
result = uuid.UUID(int = temp) |
|---|
| 215 |
return UUID(result.__str__()) |
|---|
| 216 |
|
|---|
| 217 |
|
|---|
| 218 |
""" |
|---|
| 219 |
Contributors can be viewed at: |
|---|
| 220 |
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt |
|---|
| 221 |
|
|---|
| 222 |
$LicenseInfo:firstyear=2008&license=apachev2$ |
|---|
| 223 |
|
|---|
| 224 |
Copyright 2009, Linden Research, Inc. |
|---|
| 225 |
|
|---|
| 226 |
Licensed under the Apache License, Version 2.0 (the "License"). |
|---|
| 227 |
You may obtain a copy of the License at: |
|---|
| 228 |
http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 229 |
or in |
|---|
| 230 |
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/LICENSE.txt |
|---|
| 231 |
|
|---|
| 232 |
$/LicenseInfo$ |
|---|
| 233 |
""" |
|---|
| 234 |
|
|---|