Class: Math2D::Vector2D

Inherits:
Object
  • Object
show all
Defined in:
lib/math2d/vector2d.rb

Overview

Note:

ALL ! (bang) methods that return a vector (e.g. #normalize!, #add!) change the vector in place and return self.

Note:

MOST (but not all) regular methods that return a vector create NEW Vector2D. Some however change the vector in place and return self, so be careful.

Vector2D

  • An implementation of various 2-dimensional vector methods.

Author:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x = 0, y = 0) ⇒ Vector2D

Creates a new vector (x, y).

Parameters:

  • x (Numeric) (defaults to: 0)
  • y (Numeric) (defaults to: 0)


22
23
24
25
# File 'lib/math2d/vector2d.rb', line 22

def initialize(x = 0, y = 0)
  @x = x.to_f
  @y = y.to_f
end

Instance Attribute Details

#xNumeric

The x coordinate of the Vector

Returns:

  • (Numeric)

    the current value of x



14
15
16
# File 'lib/math2d/vector2d.rb', line 14

def x
  @x
end

#yNumeric

The y coordinate of the Vector

Returns:

  • (Numeric)

    the current value of y



14
15
16
# File 'lib/math2d/vector2d.rb', line 14

def y
  @y
end

Class Method Details

.downVector2D

Shorthand for writing Vector2D.new(0, 1).

Returns:



84
85
86
# File 'lib/math2d/vector2d.rb', line 84

def self.down
  Vector2D.new(0, 1)
end

.from_angle(theta, len = 1) ⇒ Vector2D

Returns a new Vector2D from a given angle theta with length len.

Parameters:

  • theta (Numeric)
  • len (Numeric) (defaults to: 1)

Returns:



328
329
330
# File 'lib/math2d/vector2d.rb', line 328

def self.from_angle(theta, len = 1)
  Vector2D.new(len * Math.cos(theta), len * Math.sin(theta))
end

.leftVector2D

Shorthand for writing Vector2D.new(-1, 0).

Returns:



91
92
93
# File 'lib/math2d/vector2d.rb', line 91

def self.left
  Vector2D.new(-1, 0)
end

.oneVector2D

Shorthand for writing Vector2D.new(1, 1).

Returns:



69
70
71
# File 'lib/math2d/vector2d.rb', line 69

def self.one
  Vector2D.new(1, 1)
end

.randomVector2D

Returns a new Vector2D with random components but magnitude equal to 1.

Returns:



449
450
451
452
# File 'lib/math2d/vector2d.rb', line 449

def self.random
  theta = rand(-Utils2D::TWO_PI..Utils2D::TWO_PI)
  Vector2D.new(Math.cos(theta), Math.sin(theta))
end

.rightVector2D

Shorthand for writing Vector2D.new(1, 0).

Returns:



98
99
100
# File 'lib/math2d/vector2d.rb', line 98

def self.right
  Vector2D.new(1, 0)
end

.to_vector(arr) ⇒ Vector2D

Returns a new Vector2D from an array arr. If the array is bigger than 2 elements, only the first 2 will be considered.

Parameters:

  • arr (Array<Numeric>)

Returns:

Raises:

  • (ArgumentError)


493
494
495
496
497
# File 'lib/math2d/vector2d.rb', line 493

def self.to_vector(arr)
  raise ArgumentError, '`arr` must be an Array' if arr.class != Array

  Vector2D.new(arr[0], arr[1])
end

.upVector2D

Shorthand for writing Vector2D.new(0, -1). NOTE: the y-axis is inverted as per Ruby2D’s y-axis orientation

Returns:



77
78
79
# File 'lib/math2d/vector2d.rb', line 77

def self.up
  Vector2D.new(0, -1)
end

.zeroVector2D

Shorthand for writing Vector2D.new(0, 0).

Returns:



62
63
64
# File 'lib/math2d/vector2d.rb', line 62

def self.zero
  Vector2D.new(0, 0)
end

Instance Method Details

#*(other) ⇒ Vector2D

Multiplies self by another vector, scalar, or array of two scalars

Parameters:

Returns:



144
145
146
# File 'lib/math2d/vector2d.rb', line 144

def *(other)
  clone.times!(other)
end

#+(other) ⇒ Vector2D

Adds self to another vector, scalar, or array of two scalars

Parameters:

Returns:



128
129
130
# File 'lib/math2d/vector2d.rb', line 128

def +(other)
  clone.plus!(other)
end

#-(other) ⇒ Vector2D

Subtracts self from another vector, scalar, or array of two scalars

Parameters:

Returns:



136
137
138
# File 'lib/math2d/vector2d.rb', line 136

def -(other)
  clone.minus!(other)
end

#-@Vector2D Also known as: negate, reverse

Negates both x and y values of self and returns a new Vector2D.

Returns:



105
106
107
# File 'lib/math2d/vector2d.rb', line 105

def -@
  Vector2D.new(-@x, -@y)
end

#/(other) ⇒ Vector2D

Divides self by another vector, scalar, or array of two scalars

Parameters:

Returns:



152
153
154
# File 'lib/math2d/vector2d.rb', line 152

def /(other)
  clone.divide_by!(other)
end

#==(other) ⇒ Boolean

Compares self and other according to their components.

Parameters:

Returns:

  • (Boolean)


160
161
162
# File 'lib/math2d/vector2d.rb', line 160

def ==(other)
  (@x == other.x) && (@y == other.y)
end

#add!(dx, dy) ⇒ Vector2d

Add dx and dy to the current vector’s components, respectively

Parameters:

  • dx (Numeric)
  • dy (Numeric)

Returns:

  • (Vector2d)

    modified self



580
581
582
583
584
# File 'lib/math2d/vector2d.rb', line 580

def add!(dx, dy)
  @x += dx
  @y += dy
  self
end

#angle_between(other) ⇒ Float

Returns the angle between self and other in radians.

Parameters:

Returns:

  • (Float)


336
337
338
# File 'lib/math2d/vector2d.rb', line 336

def angle_between(other)
  Math.acos((@x * other.x + @y * other.y) / (magnitude * other.magnitude))
end

#constrain(min, max) ⇒ Vector2D Also known as: clamp

Note:

I haven’t experienced this with other methods (yet), so I’m only going to document this here: you may end up with a broken magnitude (1.99999999 instead of 2, for example), so always remember to check and round according to your need.

Constrains the magnitude of self between a minimum value min and maximum value max, returns a new vector or itself.

Parameters:

  • min (Numeric)
  • max (Numeric)

Returns:



251
252
253
254
255
256
257
258
259
260
261
# File 'lib/math2d/vector2d.rb', line 251

def constrain(min, max)
  min, max = max, min if min > max # swap

  mag2 = magnitude2
  if mag2 > max.abs2
    Vector2D.one.set_magnitude(max)
  elsif mag2 < min.abs2
    Vector2D.one.set_magnitude(min)
  else
    self
  end
end

#cross(other) ⇒ Numeric Also known as: wedge

Note:

Strictly speaking, the cross product is not defined in a 2-dimensional space,

Calculates the “cross product” (see note) between self and other, where: A^B (A wedge B) = (Ax * By) - (Bx * Ay)

instead what is being calculated here is called a ‘wedge product`, which is defined in any space of dimension greater than 1.

Parameters:

Returns:

  • (Numeric)


182
183
184
# File 'lib/math2d/vector2d.rb', line 182

def cross(other)
  (@x * other.y) - (other.x * @y)
end

#distance(other) ⇒ Float

Returns the Euclidean distance between self and other.

Parameters:

Returns:

  • (Float)


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

def distance(other)
  Math.sqrt((other.x - @x)**2 + (other.y - @y)**2)
end

#distance2(other) ⇒ Float

Returns the squared Euclidean distance between self and other. When comparing distances, comparing the squared distance yields the same result without the overhead of a square-root operation.

Parameters:

Returns:

  • (Float)


212
213
214
# File 'lib/math2d/vector2d.rb', line 212

def distance2(other)
  (other.x - @x)**2 + (other.y - @y)**2
end

#divide_by!(delta) ⇒ Vector2D

Divides self by delta in place.

Parameters:

Returns:



560
561
562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/math2d/vector2d.rb', line 560

def divide_by!(delta)
  case delta
  when Vector2D
    @x /= delta.x
    @y /= delta.y
  when Array
    @x /= delta[0]
    @y /= delta[1]
  else
    @x /= delta
    @y /= delta
  end
  self
end

#dot(other) ⇒ Numeric

Calculates the dot product between self and other, where: A.B (A dot B) = (Ax * Bx) + (Ay * By)

Parameters:

Returns:

  • (Numeric)


169
170
171
# File 'lib/math2d/vector2d.rb', line 169

def dot(other)
  (@x * other.x) + (@y * other.y)
end

#headingFloat

Returns the x-heading angle of self in radians. The x-heading angle is the angle formed between self and the x-axis.

Returns:

  • (Float)


311
312
313
# File 'lib/math2d/vector2d.rb', line 311

def heading
  Math.atan2(@y.to_f, @x)
end

#initialize_copy(other) ⇒ Vector2D

Creates a copy of the other vector.

Parameters:

Returns:



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

def initialize_copy(other)
  @x = other.x
  @y = other.y
end

#inverse_lerp(other, value) ⇒ Vector2D

Calculates the parameter t of the #lerp method between self and other given an interpolant value.

Parameters:

Returns:



410
411
412
# File 'lib/math2d/vector2d.rb', line 410

def inverse_lerp(other, value)
  (value - self) / (other - self)
end

#lerp(other, amt) ⇒ Vector2D

Linear interpolate self and other with an amount amt.

Parameters:

  • other (Numeric, Vector2D)
  • amt (Numeric)

Returns:



399
400
401
402
403
# File 'lib/math2d/vector2d.rb', line 399

def lerp(other, amt)
  Vector2D.new @x + (other.x - @x) * amt,
               @y + (other.y - @y) * amt
  # self + (other - self) * amt

end

#limit(max) ⇒ Vector2D

Limit the magnitude of self to max and returns a new vector.

Parameters:

  • max (Numeric)

Returns:



235
236
237
238
239
240
# File 'lib/math2d/vector2d.rb', line 235

def limit(max)
  msq = squared
  return self if msq <= (max**2)

  self * (max / Math.sqrt(msq))
end

#magnitudeFloat Also known as: length

Returns the magnitude of self.

Returns:

  • (Float)


200
201
202
# File 'lib/math2d/vector2d.rb', line 200

def magnitude
  Math.sqrt(@x**2 + @y**2)
end

#minus!(delta) ⇒ Vector2D

Subtracts delta from self in place.

Parameters:

Returns:



522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/math2d/vector2d.rb', line 522

def minus!(delta)
  case delta
  when Vector2D
    @x -= delta.x
    @y -= delta.y
  when Array
    @x -= delta[0]
    @y -= delta[1]
  else
    @x -= delta
    @y -= delta
  end
  self
end

#normalizeVector2D Also known as: unit

Normalizes self (set the magnitude to 1) and returns a new vector. unit is an alias for this method.

Returns:



281
282
283
# File 'lib/math2d/vector2d.rb', line 281

def normalize
  clone.set_magnitude(1)
end

#normalize!Vector2D Also known as: unit!

Normalizes self (set the magnitude to 1) *in place*. unit! is an alias for this method.

Returns:



291
292
293
# File 'lib/math2d/vector2d.rb', line 291

def normalize!
  set_magnitude(1)
end

#normalized?Boolean Also known as: unit?

Returns true if the magnitude of self is equal to 1, false otherwise. unit? is an alias for this method.

Returns:

  • (Boolean)


301
302
303
# File 'lib/math2d/vector2d.rb', line 301

def normalized?
  magnitude == 1
end

#opposite?(other) ⇒ Boolean

Checks if self is facing the opposite direction of other.

Parameters:

Returns:

  • (Boolean)


344
345
346
# File 'lib/math2d/vector2d.rb', line 344

def opposite?(other)
  dot(other).negative?
end

#plus!(delta) ⇒ Vector2D

Adds delta to self in place.

Parameters:

Returns:



541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/math2d/vector2d.rb', line 541

def plus!(delta)
  case delta
  when Vector2D
    @x += delta.x
    @y += delta.y
  when Array
    @x += delta[0]
    @y += delta[1]
  else
    @x += delta
    @y += delta
  end
  self
end

#ratioFloat

Returns the ratio (x / y) of self.

Returns:

  • (Float)


227
228
229
# File 'lib/math2d/vector2d.rb', line 227

def ratio
  x.to_f / y
end

#reflect(other) ⇒ Vector2D

Reflects self and returns it as a new Vector2D. other is the normal of the plane where self is reflected.

Parameters:

Returns:



419
420
421
422
423
424
# File 'lib/math2d/vector2d.rb', line 419

def reflect(other)
  other = other.normalize
  dot_prod = other.dot(self)
  Vector2D.new @x - dot_prod * other.x * 2,
               @y - dot_prod * other.y * 2
end

#refract(other, refractive_index) ⇒ Vector2D

Refracts self and returns it as a new Vector2D. other is the normal of the plane where self is refracted.



435
436
437
438
439
440
441
442
443
444
# File 'lib/math2d/vector2d.rb', line 435

def refract(other, refractive_index)
  dot_prod = other.dot(self)
  k = 1.0 - refractive_index.abs2 * (1.0 - dot_prod.abs2)
  return Vector2D.zero if k.negative?

  other_refraction = (refractive_index * dot_prod * Math.sqrt(k))
  x = refractive_index * @x - other_refraction * other.x
  y = refractive_index * @y - other_refraction * other.y
  Vector2D.new(x, y)
end

#replace!(other) ⇒ Vector2D

Replace contents of this vector with contents of other *in place*.

Parameters:

Returns:



40
41
42
43
44
# File 'lib/math2d/vector2d.rb', line 40

def replace!(other)
  @x = other.x
  @y = other.y
  self
end

#reverse!Vector2D Also known as: negate!

Negate this vector, modifying it in place

Returns:



116
117
118
119
120
# File 'lib/math2d/vector2d.rb', line 116

def reverse!
  @x = -@x
  @y = -@y
  self
end

#rotate(angle) ⇒ Vector2D

Clockwise rotates self angle radians and returns it as a new Vector2D.

Parameters:

  • angle (Numeric)

Returns:



352
353
354
# File 'lib/math2d/vector2d.rb', line 352

def rotate(angle)
  clone.rotate!(angle)
end

#rotate!(angle) ⇒ Vector2D

Clockwise rotates self by angle radians *in place*

Parameters:

  • angle (Numeric)

Returns:



360
361
362
363
364
365
366
# File 'lib/math2d/vector2d.rb', line 360

def rotate!(angle)
  sin_ang = Math.sin(angle)
  cos_ang = Math.cos(angle)
  @x = @x * cos_ang - @y * sin_ang
  @y = @x * sin_ang + @y * cos_ang
  self
end

#rotate_around(pivot, angle) ⇒ Vector2D

Clockwise rotates self angle radians around a pivot point and returns it as a new Vector2D.

Parameters:

Returns:



373
374
375
# File 'lib/math2d/vector2d.rb', line 373

def rotate_around(pivot, angle)
  clone.rotate_around!(pivot, angle)
end

#rotate_around!(pivot, angle) ⇒ Vector2D

Clockwise rotates self by angle radians around a pivot point *in place*

Parameters:

Returns:



382
383
384
385
386
387
388
389
390
391
392
# File 'lib/math2d/vector2d.rb', line 382

def rotate_around!(pivot, angle)
  pivot_x = pivot.x
  pivot_y = pivot.y
  dx = (@x - pivot_x)
  dy = (@y - pivot_y)
  sin_ang = Math.sin(angle)
  cos_ang = Math.cos(angle)
  @x = pivot_x + (dx * cos_ang) - (dy * sin_ang)
  @y = pivot_y + (dx * sin_ang) + (dy * cos_ang)
  self
end

#set(x = self.x, y = self.y) ⇒ Vector2D

Sets the x and y components of the vector. Each argument is optional, so you can change a single component and keep the other one’s current value.

Parameters:

  • x (Numeric) (defaults to: self.x)
  • y (Numeric) (defaults to: self.y)

Returns:



53
54
55
56
57
# File 'lib/math2d/vector2d.rb', line 53

def set(x = self.x, y = self.y)
  @x = x.to_f
  @y = y.to_f
  self
end

#set_magnitude(new_mag) ⇒ Vector2D Also known as: magnitude!

Sets the magnitude of self to new_mag.

Parameters:

  • new_mag (Numeric)

Returns:



269
270
271
272
273
# File 'lib/math2d/vector2d.rb', line 269

def set_magnitude(new_mag)
  mag = magnitude
  mag = Float::INFINITY if mag.zero?
  times!(new_mag / mag)
end

#squaredNumeric Also known as: magnitude2

Returns the magnitude squared of self.

Returns:

  • (Numeric)


191
192
193
# File 'lib/math2d/vector2d.rb', line 191

def squared
  (@x**2) + (@y**2)
end

#subtract!(dx, dy) ⇒ Vector2d

Subtract dx and dy from the current vector’s components, respectively

Parameters:

  • dx (Numeric)
  • dy (Numeric)

Returns:

  • (Vector2d)

    modified self



591
592
593
594
595
# File 'lib/math2d/vector2d.rb', line 591

def subtract!(dx, dy)
  @x -= dx
  @y -= dy
  self
end

#times!(delta) ⇒ Vector2D

Multiplies self by delta in place.

Parameters:

Returns:



503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/math2d/vector2d.rb', line 503

def times!(delta)
  case delta
  when Vector2D
    @x *= delta.x
    @y *= delta.y
  when Array
    @x *= delta[0]
    @y *= delta[1]
  else
    @x *= delta
    @y *= delta
  end
  self
end

#to_aArray<Numeric>

Converts self to an array.

Returns:

  • (Array<Numeric>)


457
458
459
# File 'lib/math2d/vector2d.rb', line 457

def to_a
  [@x, @y]
end

#to_sString

Converts self to a string.

Returns:

  • (String)


464
465
466
# File 'lib/math2d/vector2d.rb', line 464

def to_s
  to_a.to_s
end

#vector_cross_productVector2D Also known as: perp

Returns a *new vector* of the clockwise perpendicular to this vector.

Returns:



472
473
474
# File 'lib/math2d/vector2d.rb', line 472

def vector_cross_product
  Vector2D.new @y, -@x
end

#vector_cross_product!Vector2D Also known as: perp!

Replace this vector with it’s clockwise perpendicular

Returns:



481
482
483
484
# File 'lib/math2d/vector2d.rb', line 481

def vector_cross_product!
  @x, @y = @y, -@x
  self
end

#y_headingFloat

Returns the y-heading angle of self in radians. The y-heading angle is the angle formed between self and the y-axis.

Returns:

  • (Float)


319
320
321
# File 'lib/math2d/vector2d.rb', line 319

def y_heading
  Utils2D::HALF_PI - heading
end