diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f581a15d1b..9749a61b82e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Changed to implementation of `Mesh.unify_cycles` to use the corresponding function of `compas.topology.orientation`. * Fixed bug in `compas.topology.orientation.unify_cycles`. * Fixed bug in `Mesh.thickened`. +* Fixed various bugs in `compas.geometry.Quaternion`. + ### Removed diff --git a/src/compas/geometry/quaternion.py b/src/compas/geometry/quaternion.py index 0dd0946099d..687bc54c6c7 100644 --- a/src/compas/geometry/quaternion.py +++ b/src/compas/geometry/quaternion.py @@ -159,7 +159,7 @@ def __getitem__(self, key): return self.y if key == 3: return self.z - raise KeyError + raise KeyError(key) def __setitem__(self, key, value): if key == 0: @@ -170,9 +170,11 @@ def __setitem__(self, key, value): return if key == 2: self.y = value + return if key == 3: self.z = value - raise KeyError + return + raise KeyError(key) def __iter__(self): return iter(self.wxyz) @@ -367,7 +369,7 @@ def unitize(self): True """ - qu = quaternion_unitize(self) + qu = quaternion_unitize(list(self)) self.w, self.x, self.y, self.z = qu def unitized(self): @@ -387,7 +389,7 @@ def unitized(self): True """ - qu = quaternion_unitize(self) + qu = quaternion_unitize(list(self)) return Quaternion(*qu) def canonize(self): @@ -408,7 +410,7 @@ def canonize(self): Quaternion(0.500, -0.500, -0.500, -0.500) """ - qc = quaternion_canonize(self) + qc = quaternion_canonize(list(self)) self.w, self.x, self.y, self.z = qc # type: ignore def canonized(self): @@ -430,7 +432,7 @@ def canonized(self): Quaternion(0.500, -0.500, -0.500, -0.500) """ - qc = quaternion_canonize(self) + qc = quaternion_canonize(list(self)) return Quaternion(*qc) # type: ignore def conjugate(self): @@ -448,7 +450,7 @@ def conjugate(self): Quaternion(1.000, -1.000, -1.000, -1.000) """ - qc = quaternion_conjugate(self) + qc = quaternion_conjugate(list(self)) self.w, self.x, self.y, self.z = qc def conjugated(self): @@ -469,5 +471,5 @@ def conjugated(self): Quaternion(1.000, -1.000, -1.000, -1.000) """ - qc = quaternion_conjugate(self) + qc = quaternion_conjugate(list(self)) return Quaternion(*qc) diff --git a/tests/compas/geometry/test_quaternion.py b/tests/compas/geometry/test_quaternion.py index ca76d7c40ec..3f3e5646474 100644 --- a/tests/compas/geometry/test_quaternion.py +++ b/tests/compas/geometry/test_quaternion.py @@ -5,6 +5,7 @@ from compas.geometry import Quaternion from compas.geometry import close +from compas.geometry import Frame @pytest.mark.parametrize( @@ -63,22 +64,89 @@ def test_quaternion_data(): assert Quaternion.validate_data(other.__data__) -# ============================================================================= -# Constructors -# ============================================================================= - # ============================================================================= # Properties and Geometry # ============================================================================= + +def test_quaternion_properties(): + w = 1.0 + x = 2.0 + y = 3.0 + z = 4.0 + + quaternion = Quaternion(w, x, y, z) + + assert quaternion.wxyz == [w, x, y, z] + assert quaternion.xyzw == [x, y, z, w] + assert close(quaternion.norm, 5.4772255) + assert quaternion.is_unit is False + + quaternion = Quaternion(0.0, 0.0, 0.0, 1.0) + assert quaternion.norm == 1.0 + + # ============================================================================= # Accessors # ============================================================================= + +def test_quaternion_accessors(): + w = 1.0 + x = 2.0 + y = 3.0 + z = 4.0 + + quaternion = Quaternion(w, x, y, z) + + assert quaternion[0] == w + assert quaternion[1] == x + assert quaternion[2] == y + assert quaternion[3] == z + + quaternion[0] = 5.0 + quaternion[1] = 6.0 + quaternion[2] = 7.0 + quaternion[3] = 8.0 + + assert quaternion.w == 5.0 + assert quaternion.x == 6.0 + assert quaternion.y == 7.0 + assert quaternion.z == 8.0 + + # ============================================================================= # Comparison # ============================================================================= + +def test_quaternion_comparison(): + quaternion1 = Quaternion(1.0, 2.0, 3.0, 4.0) + quaternion2 = Quaternion(1.0, 2.0, 3.0, 4.0) + quaternion3 = Quaternion(5.0, 6.0, 7.0, 8.0) + + assert quaternion1 == quaternion2 + assert quaternion1 != quaternion3 + + # ============================================================================= -# Other Methods +# Methods # ============================================================================= + + +def test_quaternion_other_methods(): + quaternion = Quaternion(1.0, 2.0, 3.0, 4.0) + + conjugate = quaternion.conjugated() + assert conjugate.w == 1.0 + assert conjugate.x == -2.0 + assert conjugate.y == -3.0 + assert conjugate.z == -4.0 + + unitized = quaternion.unitized() + assert unitized.is_unit + + quaternion = Quaternion.from_frame(Frame.worldZX()) + canonized = quaternion.canonized() + + assert str(canonized) == str("Quaternion(0.5, -0.5, -0.5, -0.5)")