Skip to content

Commit 929784f

Browse files
committed
Make vector projections independent of direction scale
1 parent 2de7801 commit 929784f

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

‎spatialmath/base/vectors.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,14 @@ def project(v1: ArrayLike3, v2: ArrayLike3) -> ArrayLike3:
832832
:return: vector projection of v1 onto v2 (parrallel to v2)
833833
:rtype: ndarray(n)
834834
"""
835-
return np.dot(v1, v2) * v2
835+
v1 = getvector(v1)
836+
v2 = getvector(v2)
837+
scale = np.max(np.abs(v2))
838+
if scale == 0:
839+
return np.zeros_like(v2)
840+
# Normalize the scale before dot products to avoid over/underflow.
841+
v2 = v2 / scale
842+
return (np.dot(v1, v2) / np.dot(v2, v2)) * v2
836843

837844

838845
def orthogonalize(v1: ArrayLike3, v2: ArrayLike3, normalize: bool = True) -> ArrayLike3:

‎tests/base/test_vectors.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ class TestVector(unittest.TestCase):
3333
def tearDownClass(cls):
3434
plt.close("all")
3535

36+
def test_project_nonunit_direction(self):
37+
for scale in (1, 2, -3, 1e-200, 1e200):
38+
direction = np.array([scale, scale, 0])
39+
nt.assert_allclose(project([3, 1, 4], direction), [2, 2, 0])
40+
nt.assert_allclose(project((3, 1, 4), (2, 2, 0)), [2, 2, 0])
41+
42+
def test_orthogonalize_nonunit_direction(self):
43+
result = orthogonalize([3, 1, 4], [2, 2, 0], normalize=False)
44+
nt.assert_allclose(result, [1, -1, 4])
45+
self.assertAlmostEqual(np.dot(result, [2, 2, 0]), 0)
46+
normalized = orthogonalize([3, 1, 4], [2, 2, 0])
47+
self.assertAlmostEqual(np.linalg.norm(normalized), 1)
48+
self.assertAlmostEqual(np.dot(normalized, [2, 2, 0]), 0)
49+
50+
def test_project_zero_direction(self):
51+
nt.assert_array_equal(project([1, 2, 3], [0, 0, 0]), [0, 0, 0])
52+
3653
def test_unit(self):
3754
nt.assert_array_almost_equal(unitvec([1, 0, 0]), np.r_[1, 0, 0])
3855
nt.assert_array_almost_equal(unitvec([0, 1, 0]), np.r_[0, 1, 0])

0 commit comments

Comments
 (0)