Module: Vector2d::Lengths

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

Overview

The length of a vector, the distance between two, and the operations that change the length while keeping the direction.

Instance Method Summary collapse

Instance Method Details

#approx_zero?(tolerance = nil) ⇒ Boolean

Is this the zero vector, give or take floating point drift? See #approx_equal? for what the tolerance is.

Vector2d(0, 0).approx_zero?     # => true
Vector2d(1e-17, 0).approx_zero? # => true
Vector2d(1e-15, 0).approx_zero? # => false

An explicit tolerance is an absolute length.

Vector2d(0.2, 0).approx_zero?(0.5) # => true

Parameters:

  • tolerance (Integer, Float, Rational, BigDecimal, nil) (defaults to: nil)

    an absolute length, or nil for the default scaled tolerance

Returns:

  • (Boolean)


60
61
62
63
64
# File 'lib/vector2d/lengths.rb', line 60

def approx_zero?(tolerance = nil)
  return length <= coordinate(tolerance) unless tolerance.nil?

  near_zero?(length)
end

#chebyshev_distance(other) ⇒ Integer, ...

Calculates the Chebyshev distance between two vectors, the largest absolute difference along any axis.

v1 = Vector2d(2, 3)
v2 = Vector2d(5, 7)
v1.chebyshev_distance(v2) # => 4

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)


233
234
235
# File 'lib/vector2d/lengths.rb', line 233

def chebyshev_distance(other)
  (self - other).abs.to_a.max
end

#clamp_length(min, max) ⇒ self #clamp_length(range) ⇒ self

Clamps the length of the vector between a minimum and a maximum, scaling it up if it is shorter than min and down if it is longer than max. The direction is kept.

vector = Vector2d(2.0, 3.0)
vector.clamp_length(5.0, 10.0) # => Vector2d(2.7735.., 4.1602..)
vector.clamp_length(1.0, 10.0) # => Vector2d(2.0, 3.0)

The bounds can also be given as a single range, which may be beginless or endless to clamp only one side, as in #clamp.

vector.clamp_length(5.0..10.0) # => Vector2d(2.7735.., 4.1602..)
vector.clamp_length(..1.0)     # => Vector2d(0.5547.., 0.8320..)
vector.clamp_length(5.0..)     # => Vector2d(2.7735.., 4.1602..)

A maximum on its own is #limit_length.

The range must not exclude its end, as with Comparable#clamp.

vector.clamp_length(5.0...10.0) # => ArgumentError

The zero vector has no direction, and is returned unchanged. It can't be scaled up to a minimum length.

Vector2d(0, 0).clamp_length(1.0, 2.0) # => Vector2d(0,0)

Lengths can't be negative, and min can't exceed max.

Vector2d(2, 3).clamp_length(-1.0, 1.0) # => ArgumentError
Vector2d(2, 3).clamp_length(4.0, 2.0)  # => ArgumentError

Overloads:

  • #clamp_length(min, max) ⇒ self

    Parameters:

    • min (Integer, Float, Rational, BigDecimal)

      the minimum length

    • max (Integer, Float, Rational, BigDecimal)

      the maximum length

  • #clamp_length(range) ⇒ self

    Parameters:

    • range (Range)

      both bounds, and may be beginless or endless

Returns:

  • (self)


172
173
174
175
# File 'lib/vector2d/lengths.rb', line 172

def clamp_length(min, max = nil)
  min_length, max_length = clamp_length_bounds(min, max)
  resize(length.clamp(Range.new(min_length, max_length)))
end

#direction_to(other) ⇒ self

Unit vector pointing from this vector to another vector, the direction a step from here to there would take. The other vector is coerced, so scalars work too.

v1 = Vector2d(2, 3)
v1.direction_to(Vector2d(2, 6)) # => Vector2d(0.0,1.0)
v1.direction_to(Vector2d(5, 7)) # => Vector2d(0.6000..,0.8)

This is (other - self).normalize. #distance measures the same step, and #move_toward takes it.

There is no direction to where you already are. The zero vector has no direction, and is returned.

v1.direction_to(v1) # => Vector2d(0,0)

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (self)


255
256
257
258
# File 'lib/vector2d/lengths.rb', line 255

def direction_to(other)
  v = coerce_vector(other)
  build(v.x - x, v.y - y).normalize
end

#distance(other) ⇒ Float

Calculates the distance between two vectors.

v1 = Vector2d(2, 3)
v2 = Vector2d(3, 4)
v1.distance(v2) # => 1.4142..

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (Float)


185
186
187
# File 'lib/vector2d/lengths.rb', line 185

def distance(other)
  (self - other).length
end

#distance_squared(other) ⇒ Integer, ...

Calculate squared distance between vectors. Avoids the square root when distances are only being compared to each other.

v1 = Vector2d(2, 3)
v2 = Vector2d(5, 6)
v1.distance_squared(v2) # => 18

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)


198
199
200
# File 'lib/vector2d/lengths.rb', line 198

def distance_squared(other)
  (self - other).length_squared
end

#lengthFloat Also known as: magnitude, norm

Length of vector.

Vector2d(2, 3).length # => 3.6055..

Returns:

  • (Float)


12
13
14
# File 'lib/vector2d/lengths.rb', line 12

def length
  Math.sqrt(length_squared)
end

#length_squaredInteger, ...

Squared length of vector. Avoids the square root when lengths are only being compared to each other.

Vector2d(2, 3).length_squared # => 13

Returns:

  • (Integer, Float, Rational, BigDecimal)


24
25
26
# File 'lib/vector2d/lengths.rb', line 24

def length_squared
  (x * x) + (y * y)
end

#limit_length(max) ⇒ self

Limits the length of the vector, scaling it down if it is longer than max. The direction is kept.

vector = Vector2d(2.0, 3.0)
vector.limit_length(5.0) # => Vector2d(2.0, 3.0)
vector.limit_length(1.0) # => Vector2d(0.5547.., 0.8320..)

#clamp_length bounds the length at both ends.

The zero vector has no direction, and is returned unchanged.

Vector2d(0, 0).limit_length(1.0) # => Vector2d(0,0)

Lengths can't be negative.

Vector2d(2, 3).limit_length(-1.0) # => ArgumentError

Parameters:

  • max (Integer, Float, Rational, BigDecimal)

    the maximum length

Returns:

  • (self)


131
132
133
# File 'lib/vector2d/lengths.rb', line 131

def limit_length(max)
  resize(length.clamp(..length_bound(max, "max")))
end

#manhattan_distance(other) ⇒ Integer, ...

Calculates the Manhattan distance between two vectors, the sum of the absolute differences along each axis.

v1 = Vector2d(2, 3)
v2 = Vector2d(5, 7)
v1.manhattan_distance(v2) # => 7

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)


220
221
222
# File 'lib/vector2d/lengths.rb', line 220

def manhattan_distance(other)
  (self - other).abs.to_a.sum
end

#normalizeself

Normalizes the vector.

vector = Vector2d(2, 3)
vector.normalize        # => Vector2d(0.5547.., 0.8320..)
vector.normalize.length # => 1.0

The zero vector has no direction, and is returned unchanged.

Vector2d(0, 0).normalize # => Vector2d(0,0)

Returns:

  • (self)


87
88
89
# File 'lib/vector2d/lengths.rb', line 87

def normalize
  resize(1.0)
end

#normalized?Boolean

Is this a normalized vector?

Vector2d(0, 1).normalized? # => true
Vector2d(2, 3).normalized? # => false

Returns:

  • (Boolean)


72
73
74
# File 'lib/vector2d/lengths.rb', line 72

def normalized?
  near_zero?(length - 1.0)
end

#resize(new_length) ⇒ self

Changes magnitude of vector.

Vector2d(2, 3).resize(1.0) # => Vector2d(0.5547.., 0.8320..)

The zero vector has no direction, and is returned unchanged.

Vector2d(0, 0).resize(1.0) # => Vector2d(0,0)

A negative length reverses the vector.

Vector2d(2, 3).resize(-1.0) # => Vector2d(-0.5547..,-0.8320..)

Parameters:

  • new_length (Integer, Float, Rational, BigDecimal)

    the new length

Returns:

  • (self)


105
106
107
108
109
110
# File 'lib/vector2d/lengths.rb', line 105

def resize(new_length)
  new_length = coordinate(new_length)
  return self if zero?

  self * (new_length / length)
end

#squared_distance(other) ⇒ Integer, ...

Deprecated.

Use #distance_squared instead.

Parameters:

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

    anything Vector2d.parse accepts

Returns:

  • (Integer, Float, Rational, BigDecimal)


206
207
208
209
# File 'lib/vector2d/lengths.rb', line 206

def squared_distance(other)
  warn_deprecated("Vector2d#squared_distance is deprecated. Use #distance_squared instead.")
  distance_squared(other)
end

#squared_lengthInteger, ...

Deprecated.

Use #length_squared instead.

Returns:

  • (Integer, Float, Rational, BigDecimal)


31
32
33
34
# File 'lib/vector2d/lengths.rb', line 31

def squared_length
  warn_deprecated("Vector2d#squared_length is deprecated. Use #length_squared instead.")
  length_squared
end

#zero?Boolean

Is this the zero vector?

Vector2d(0, 0).zero? # => true
Vector2d(2, 3).zero? # => false

Returns:

  • (Boolean)


42
43
44
# File 'lib/vector2d/lengths.rb', line 42

def zero?
  length_squared.zero?
end