From 5b10b4502773481693fe6ad7cec5e97e9a2475fe Mon Sep 17 00:00:00 2001 From: obucklin Date: Thu, 15 May 2025 10:27:02 +0200 Subject: [PATCH 1/3] added catch for vector parallel to normal --- src/compas/geometry/_core/angles.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compas/geometry/_core/angles.py b/src/compas/geometry/_core/angles.py index c10835d08c9f..f77a8dde18a3 100644 --- a/src/compas/geometry/_core/angles.py +++ b/src/compas/geometry/_core/angles.py @@ -155,6 +155,9 @@ def angle_vectors_projected(u, v, normal, deg=False, tol=None): u_cross = cross_vectors(u, normal) v_cross = cross_vectors(v, normal) + if TOL.is_allclose(u_cross, [0.0, 0.0, 0.0]) or TOL.is_allclose(v_cross, [0.0, 0.0, 0.0]): + return None + return angle_vectors_signed(u_cross, v_cross, normal, deg, tol) From 1af2b03503a3231d924ad4071564cee9fd71bb6d Mon Sep 17 00:00:00 2001 From: obucklin Date: Thu, 15 May 2025 10:36:53 +0200 Subject: [PATCH 2/3] Changelog --- CHANGELOG.md | 1 + src/compas/files/gltf/gltf_node.py | 4 ++-- src/compas/rpc/dispatcher.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3495d78de47b..5d7b50a01614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed a bug when printing an empty `Tree`. * Fixed a bug in `Group` for IronPython where the decoding declaration was missing. * Fixed a bug where a `Group` without name could not be added to the scene. +* Fixed a bug where `angle_vectors_projected` returned a 0 when an input vector was parallel to projection normal. Now returns `None`. ### Removed diff --git a/src/compas/files/gltf/gltf_node.py b/src/compas/files/gltf/gltf_node.py index 78446abfbf7f..23d6bee91d2c 100644 --- a/src/compas/files/gltf/gltf_node.py +++ b/src/compas/files/gltf/gltf_node.py @@ -162,7 +162,7 @@ def rotation(self, value): if self._matrix: raise Exception("Cannot set rotation when matrix is set.") if not isinstance(value, list) or len(value) != 4 or fabs(sum([q**2 for q in value]) - 1) > 1e-03: - raise Exception("Invalid rotation. Rotations are expected to be given as " "unit quaternions of the form [q1, q2, q3, q4]") + raise Exception("Invalid rotation. Rotations are expected to be given as unit quaternions of the form [q1, q2, q3, q4]") self._rotation = value @property @@ -199,7 +199,7 @@ def matrix(self, value): raise Exception("Invalid matrix. A 4x4 matrix is expected.") if value[3] != [0, 0, 0, 1]: raise Exception( - "Invalid matrix. A matrix without shear or skew is expected. It must be of " "the form TRS, where T is a translation, R is a rotation and S is a scaling." + "Invalid matrix. A matrix without shear or skew is expected. It must be of the form TRS, where T is a translation, R is a rotation and S is a scaling." ) self._matrix = value diff --git a/src/compas/rpc/dispatcher.py b/src/compas/rpc/dispatcher.py index 82ec6bc8040e..ef0853833632 100644 --- a/src/compas/rpc/dispatcher.py +++ b/src/compas/rpc/dispatcher.py @@ -122,7 +122,7 @@ def _dispatch(self, name, args): try: idict = json.loads(args[0], cls=DataDecoder) except (IndexError, TypeError): - odict["error"] = "API methods require a single JSON encoded dictionary as input.\n" "For example: input = json.dumps({'param_1': 1, 'param_2': [2, 3]})" + odict["error"] = "API methods require a single JSON encoded dictionary as input.\nFor example: input = json.dumps({'param_1': 1, 'param_2': [2, 3]})" else: self._call(function, idict, odict) From b75d2d75d12a24636b6a19bb47a773fe08b0f08f Mon Sep 17 00:00:00 2001 From: obucklin Date: Wed, 11 Jun 2025 13:15:57 +0200 Subject: [PATCH 3/3] changed to raise ValueEror --- src/compas/geometry/_core/angles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compas/geometry/_core/angles.py b/src/compas/geometry/_core/angles.py index f77a8dde18a3..b95c1f9c25a5 100644 --- a/src/compas/geometry/_core/angles.py +++ b/src/compas/geometry/_core/angles.py @@ -156,7 +156,7 @@ def angle_vectors_projected(u, v, normal, deg=False, tol=None): v_cross = cross_vectors(v, normal) if TOL.is_allclose(u_cross, [0.0, 0.0, 0.0]) or TOL.is_allclose(v_cross, [0.0, 0.0, 0.0]): - return None + raise ValueError("Cannot compute angle between vectors projected onto a plane defined by the normal vector. One of the vectors is parallel to the normal vector.") return angle_vectors_signed(u_cross, v_cross, normal, deg, tol)