Module: Vector2d::Projection

Included in:
Vector2d
Defined in:
lib/vector2d/projection.rb

Overview

Products of two vectors, and the projection, reflection and refraction built on them.

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#cross_product(other) ⇒ Integer, ...

Cross product of this vector and another vector. In two dimensions this is a scalar, the z component of the equivalent three dimensional cross product. Vector#cross_product returns a perpendicular vector instead, which is #perpendicular here.

v1 = Vector2d(2, 1)
v2 = Vector2d(2, 3)
v1.cross_product(v2) # => 4

Parameters:

  • other (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)

    a scalar



66
67
68
69
# File 'lib/vector2d/projection.rb', line 66

def cross_product(other)
  v = coerce_vector(other)
  self.class.cross_product(self, v)
end

#dot_product(other) ⇒ Integer, ... Also known as: inner_product, dot

Dot product of this vector and another vector.

v1 = Vector2d(2, 1)
v2 = Vector2d(2, 3)
v1.dot_product(v2) # => 7

Parameters:

  • other (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)

    a scalar



48
49
50
51
# File 'lib/vector2d/projection.rb', line 48

def dot_product(other)
  v = coerce_vector(other)
  self.class.dot_product(self, v)
end

#project(other) ⇒ self

Vector projection of this vector onto another vector. The argument is coerced, so scalars work too.

v1 = Vector2d(2, 3)
v2 = Vector2d(4, 0)
v1.project(v2) # => Vector2d(2.0,0.0)

The zero vector has no direction, and there is nothing to project onto. The zero vector is returned.

v1.project(Vector2d(0, 0)) # => Vector2d(0.0,0.0)

Parameters:

  • other (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (self)


85
86
87
88
89
90
91
# File 'lib/vector2d/projection.rb', line 85

def project(other)
  v = coerce_vector(other)
  return build(0.0, 0.0) if v.zero?

  scale = dot_product(v).to_f / v.length_squared
  build(v.x * scale, v.y * scale)
end

#reflect(normal) ⇒ self

Reflects this vector about the line perpendicular to the normal, the way a ray bounces off a surface. The normal is normalized internally, so it can be of any length.

vector = Vector2d(2, 3)
vector.reflect(Vector2d(0, 1)) # => Vector2d(2.0,-3.0)
vector.reflect(Vector2d(0, 5)) # => Vector2d(2.0,-3.0)

The zero vector has no direction, and defines no surface to reflect off. Nothing is reflected, and the vector is returned.

vector.reflect(Vector2d(0, 0)) # => Vector2d(2.0,3.0)

Parameters:

  • normal (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (self)


148
149
150
151
152
153
154
# File 'lib/vector2d/projection.rb', line 148

def reflect(normal)
  v = coerce_vector(normal)
  return to_f_vector if v.zero?

  n = v.normalize
  self - (n * (2 * dot_product(n)))
end

#refract(normal, refractive_index) ⇒ self

Refracts this vector through a surface with the given normal and ratio of refractive indices, the way a ray bends entering a different medium. The normal is normalized internally, so it can be of any length.

ray = Vector2d(1, -1).normalize
ray.refract(Vector2d(0, 1), 0.5) # => Vector2d(0.3535..,-0.9354..)
ray.refract(Vector2d(0, 5), 0.5) # => Vector2d(0.3535..,-0.9354..)

A ratio of one leaves the ray on its course.

ray.refract(Vector2d(0, 1), 1.0) # => Vector2d(0.7071..,-0.7071..)

Past the critical angle the ray does not cross the surface at all. This is total internal reflection, and the zero vector is returned.

ray.refract(Vector2d(0, 1), 2.0) # => Vector2d(0.0,0.0)

The zero vector has no direction, and defines no surface to refract through. Nothing is refracted, and the vector is returned.

ray.refract(Vector2d(0, 0), 0.5) # => Vector2d(0.7071..,-0.7071..)

Raises ArgumentError unless the ratio is a real number.

ray.refract(Vector2d(0, 1), Complex(1, 2)) # => ArgumentError

Parameters:

  • normal (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

  • refractive_index (Integer, Float, Rational, BigDecimal)

    the ratio of refractive indices

Returns:

  • (self)


188
189
190
191
192
193
194
# File 'lib/vector2d/projection.rb', line 188

def refract(normal, refractive_index)
  v = coerce_vector(normal)
  eta = coordinate(refractive_index)
  return to_f_vector if v.zero?

  refract_through(v.normalize, eta)
end

#reject(other) ⇒ self

Vector rejection of this vector from another vector, the component left over when the projection is subtracted.

v1 = Vector2d(2, 3)
v2 = Vector2d(4, 0)
v1.reject(v2) # => Vector2d(0.0,3.0)

The zero vector has no direction, and nothing is projected away.

v1.reject(Vector2d(0, 0)) # => Vector2d(2.0,3.0)

Parameters:

  • other (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (self)


106
107
108
# File 'lib/vector2d/projection.rb', line 106

def reject(other)
  self - project(other)
end

#scalar_projection(other) ⇒ Float

Scalar projection of this vector onto another vector, the signed length of the projection. It is negative when the vectors point in opposite directions.

v1 = Vector2d(2, 3)
v2 = Vector2d(4, 0)
v1.scalar_projection(v2)              # => 2.0
v1.scalar_projection(Vector2d(-4, 0)) # => -2.0

The zero vector has no direction, and there is nothing to project onto. The scalar projection is zero.

v1.scalar_projection(Vector2d(0, 0)) # => 0.0

Parameters:

  • other (Vector2d, Array, String, Hash, Integer, Float, Rational, BigDecimal, ::Vector, ::Matrix)

    anything Vector2d.parse accepts

Returns:

  • (Float)

    a scalar, the signed length of the projection



126
127
128
129
130
131
# File 'lib/vector2d/projection.rb', line 126

def scalar_projection(other)
  v = coerce_vector(other)
  return 0.0 if v.zero?

  dot_product(v) / v.length
end