Skip to content
This repository has been archived by the owner on Sep 25, 2022. It is now read-only.

Commit

Permalink
Merge pull request #8 from nickdelgrosso/anycoord
Browse files Browse the repository at this point in the history
Anycoord
  • Loading branch information
nickdelgrosso committed Jun 6, 2018
2 parents 9428c0e + 9bef8f3 commit ae739e4
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 133 deletions.
143 changes: 29 additions & 114 deletions ratcave/coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,44 @@
import _transformations as trans
from abc import ABCMeta, abstractmethod
from ratcave.utils.observers import IterObservable

import itertools
from operator import setitem

class Coordinates(IterObservable):

coords = {'x': 0, 'y': 1, 'z': 2}

def __init__(self, *args, **kwargs):
super(Coordinates, self).__init__(**kwargs)
self._array = np.array(args, dtype=np.float32)
self._init_coord_properties()

def __repr__(self):
arg_str = ', '.join(['{}={}'.format(*el) for el in zip('xyz', self._array)])
return "{cls}({coords})".format(cls=self.__class__.__name__, coords=arg_str)

def _init_coord_properties(self):
"""
Generates combinations of named coordinate values, mapping them to the internal array.
For Example: x, xy, xyz, y, yy, zyx, etc
"""
def gen_getter_setter_funs(*args):
indices = [self.coords[coord] for coord in args]

def getter(self):
return tuple(self._array[indices]) if len(args) > 1 else self._array[indices[0]]

def setter(self, value):
setitem(self._array, indices, value)
self.notify_observers()

return getter, setter

for n_repeats in range(1, len(self.coords)+1):
for args in itertools.product(self.coords.keys(), repeat=n_repeats):
getter, setter = gen_getter_setter_funs(*args)
setattr(self.__class__, ''.join(args), property(fget=getter, fset=setter))

def __getitem__(self, item):
if type(item) == slice:
return tuple(self._array[item])
Expand All @@ -25,64 +51,6 @@ def __setitem__(self, idx, value):
super(Coordinates, self).__setitem__(idx, value)


# Note: Index counts backwards from end of array to increase compatibility with Quaternions.
@property
def x(self):
return self[-3]

@x.setter
def x(self, value):
self[-3] = value

@property
def y(self):
return self[-2]

@y.setter
def y(self, value):
self[-2] = value

@property
def z(self):
return self[-1]

@z.setter
def z(self, value):
self[-1] = value

@property
def xy(self):
return self[-3:-1]

@xy.setter
def xy(self, value):
self[-3:-1] = value

@property
def yz(self):
return self[-2:]

@yz.setter
def yz(self, value):
self[-2:] = value

@property
def xz(self):
return self[-3], self[-1]

@xz.setter
def xz(self, value):
self[-3], self[-1] = value[0], value[1]

@property
def xyz(self):
return self[-3:]

@xyz.setter
def xyz(self, value):
self[-3:] = value


class RotationBase(object):
__metaclass__ = ABCMeta

Expand Down Expand Up @@ -172,6 +140,8 @@ def from_matrix(cls, matrix, axes='rxyz'):

class RotationQuaternion(RotationBase, Coordinates):

coords = {'w': 0, 'x': 1, 'y': 2, 'z': 3}

def __init__(self, w, x, y, z, **kwargs):
super(RotationQuaternion, self).__init__(w, x, y, z)

Expand Down Expand Up @@ -203,30 +173,6 @@ def from_matrix(cls, matrix):
coords = trans.quaternion_from_matrix(matrix)
return cls(*coords)

@property
def w(self):
return self[-4]

@w.setter
def w(self, value):
self[-4] = value

@property
def wxyz(self):
return self[-4:]

@wxyz.setter
def wxyz(self, value):
self[-4:] = value

@property
def xyzw(self):
return self[[1, 2, 3, 0]]

@xyzw.setter
def xyzw(self, value):
self[[1, 2, 3, 0]] = value


class Translation(Coordinates):

Expand Down Expand Up @@ -260,37 +206,6 @@ def __init__(self, *args, **kwargs):
def to_matrix(self):
return np.diag((self._array[0], self._array[1], self._array[2], 1.))

@property
def x(self):
return self[0]

@x.setter
def x(self, value):
self[0] = value

@property
def y(self):
return self[1]

@y.setter
def y(self, value):
self[1] = value

@property
def z(self):
return self[2]

@z.setter
def z(self, value):
self[2] = value

@property
def xyz(self):
return self[:]

@xyz.setter
def xyz(self, value):
self[:] = value


def cross_product_matrix(vec):
Expand Down
8 changes: 4 additions & 4 deletions tests/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@

def test_camera_physical_attributes():
cam = Camera()
assert cam.position.xyz == (0, 0, 0)
assert cam.rotation.xyz == (0, 0, 0)
assert np.isclose(cam.position.xyz, (0, 0, 0)).all()
assert np.isclose(cam.rotation.xyz, (0, 0, 0)).all()

cam.position.x = 1
assert cam.position.xyz == (1, 0, 0)
assert np.isclose(cam.position.xyz, (1, 0, 0)).all()
assert np.all(cam.view_matrix[:3, -1] == tuple(-el for el in cam.position.xyz))
assert np.all(cam.model_matrix[:3, -1] == cam.position.xyz)


cam.rotation.y = 30
assert cam.rotation.xyz == (0, 30, 0)
assert np.isclose(cam.rotation.xyz, (0, 30, 0)).all()
assert cam.rotation.y == 30


Expand Down
15 changes: 7 additions & 8 deletions tests/test_meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ def tearDown(self):

def test_position_update_to_modelmatrix(self):


for pos in [(4,5, 6), (5, 4, 1)]:
mesh = self.reader.get_mesh("Cube", position=pos)
self.assertEqual(mesh.position.xyz, pos)
# self.assertTrue(np.isclose(mesh.uniforms['model_matrix'][:3, 3], pos).all())
self.assertTrue(np.isclose(mesh.position.xyz, pos).all())
self.assertTrue(np.isclose(mesh.uniforms['model_matrix'][:3, 3], pos).all())

for pos in [(4,5, 6), (5, 4, 1)]:
mesh = self.mesh
mesh.position.xyz = pos
self.assertEqual(mesh.position.xyz, pos)
self.assertTrue(np.isclose(mesh.position.xyz, pos).all())
self.assertTrue(np.isclose(mesh.uniforms['model_matrix'][:3, 3], pos).all())


Expand All @@ -37,25 +36,25 @@ def test_position_update(self):
mesh = self.mesh
for pos in [(4,5, 6), (5, 4, 1)]:
mesh.position.x, mesh.position.y, mesh.position.z = pos
self.assertEqual(mesh.position.xyz, pos)
self.assertTrue(np.isclose(mesh.position.xyz, pos).all())

def test_rotation_update(self):

mesh = self.mesh
for rot in [(4, 5, 6), (5, 4, 1)]:
mesh.rotation.x, mesh.rotation.y, mesh.rotation.z = rot
self.assertEqual(mesh.rotation.xyz, rot)
self.assertTrue(np.isclose(mesh.rotation.xyz, rot).all())

def test_scale_update(self):

mesh = self.mesh
for rot in [(4, 5, 6), (5, 4, 1)]:
mesh.scale.x, mesh.scale.y, mesh.scale.z = rot
self.assertEqual(mesh.scale.xyz, rot)
self.assertTrue(np.isclose(mesh.scale.xyz, rot).all())

for rot in [4, 5]:
mesh.scale.xyz = rot
self.assertEqual(mesh.scale.xyz, (rot, rot, rot))
self.assertTrue(np.isclose(mesh.scale.xyz, (rot, rot, rot)).all())


@pytest.fixture()
Expand Down
21 changes: 14 additions & 7 deletions tests/test_physical.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,39 @@ def test_position_update_to_modelmatrix(self):

for pos in [(4,5, 6), (5, 4, 1)]:
phys = Physical(position=pos)
self.assertEqual(phys.position.xyz, pos)
self.assertTrue(np.isclose(phys.position.xyz, pos).all())
self.assertTrue(np.isclose(phys.position.zyx, pos[::-1]).all())
self.assertTrue(np.isclose(phys.model_matrix[:3, 3], pos).all())

for pos in [(4,5, 6), (5, 4, 1)]:
phys = Physical()
phys.position.xyz = pos
self.assertEqual(phys.position.xyz, pos)
self.assertTrue(np.isclose(phys.position.xyz, pos).all())
self.assertTrue(np.isclose(phys.position.zyx, pos[::-1]).all())
self.assertTrue(np.isclose(phys.model_matrix[:3, 3], pos).all())

for pos in [4, 5]:
phys = Physical()
phys.position.xxx = pos
self.assertTrue(np.isclose(phys.model_matrix[:3, 3], (pos, 0, 0)).all())

def test_rotation_update(self):

for rot in [(4, 5, 6), (5, 4, 1)]:
phys = Physical(rotation=rot)
self.assertEqual(phys.rotation.xyz, rot)
self.assertTrue(np.isclose(phys.rotation.xyz, rot).all())

for rot in [(4, 5, 6), (5, 4, 1)]:
phys.rotation.xyz = rot
self.assertEqual(phys.rotation.xyz, rot)
self.assertTrue(np.isclose(phys.rotation.xyz, rot).all())

def test_scale_update_to_modelmatrix(self):

for scale in (5, 6, 7):
phys = Physical(scale=scale)
self.assertTrue(np.isclose(phys.model_matrix[0, 0], scale))
self.assertTrue(np.isclose(phys.model_matrix[1, 1], scale))
self.assertTrue(np.isclose(phys.model_matrix[2, 2], scale))
self.assertTrue(np.isclose(phys.model_matrix[0, 0], scale).all())
self.assertTrue(np.isclose(phys.model_matrix[1, 1], scale).all())
self.assertTrue(np.isclose(phys.model_matrix[2, 2], scale).all())


class TestModelViewNormalMatrices(unittest.TestCase):
Expand Down

0 comments on commit ae739e4

Please sign in to comment.