diff --git a/lib/matrix.rb b/lib/matrix.rb index b39973b..ab4a899 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1999,6 +1999,19 @@ class Vector self / n end + # + # Returns an angle with another vector. Result is within the [0...Math::PI]. + # Vector[1,0].angle_with(Vector[0,1]) + # # => 1.5707963267948966 + # + def angle_with(v) + raise TypeError, "Expected a Vector, got a #{v.class}" unless v.is_a?(Vector) + Vector.Raise ErrDimensionMismatch if size != v.size + raise ZeroVectorError, "Can't get angle of zero vector" if magnitude == 0 || v.magnitude == 0 + + Math.acos( inner_product(v) / (magnitude * v.magnitude) ) + end + #-- # CONVERTING #++ diff --git a/test/matrix/test_vector.rb b/test/matrix/test_vector.rb index fa29496..ee278e0 100644 --- a/test/matrix/test_vector.rb +++ b/test/matrix/test_vector.rb @@ -169,4 +169,15 @@ class TestVector < Test::Unit::TestCase v = Vector[1, 0, 0].cross_product Vector[0, 1, 0] assert_equal(Vector[0, 0, 1], v) end + + def test_angle_with + assert_in_epsilon(Math::PI, Vector[1, 0].angle_with(Vector[-1, 0])) + assert_in_epsilon(Math::PI/2, Vector[1, 0].angle_with(Vector[0, -1])) + assert_in_epsilon(Math::PI/4, Vector[2, 2].angle_with(Vector[0, 1])) + assert_in_delta(0.0, Vector[1, 1].angle_with(Vector[1, 1]), 0.00001) + + assert_raise(Vector::ZeroVectorError) { Vector[1, 1].angle_with(Vector[0, 0]) } + assert_raise(Vector::ZeroVectorError) { Vector[0, 0].angle_with(Vector[1, 1]) } + assert_raise(Matrix::ErrDimensionMismatch) { Vector[1, 2, 3].angle_with(Vector[0, 1]) } + end end