math2d 1.3.1 → 1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72d8b21dd200f75946bc59b4b96e5f357cd653cabc00473d75aaad84a1b62c16
4
- data.tar.gz: 5c070ccfa7c40f54dbd7ebd06390a36328d53bf375612939863f942a2db671bb
3
+ metadata.gz: 687573d7fe97c2627cea246b39ff246058cd1dce63c4163c6e4c9955db5bf00c
4
+ data.tar.gz: 9475dc4a1a0b96f5c6133a171159151469d39d0a8d495c759286530f5880596e
5
5
  SHA512:
6
- metadata.gz: eb0e711552f8d7b5dda6bb73cba772caa3d3b5a7d3dcc8aec924f318f8a9a7cbed654ce845bcdb84997c64d9eca459eceec4982da5f77b6a1acb727e21405617
7
- data.tar.gz: 2825fffd1279606fab25f882fc389055dd43e84a30cc25bf806b7ae943a1fa663c9d31a7741dfaceb205a5a494168372500fb8cdd3c7972e4d880866ffea4f1f
6
+ metadata.gz: e382704a1edebfb80e669128eaf2838468eb2429435513f2c8af7cf582e5483511c08cc62334f0d24e38eb937610837d4f741f9193145bc5e029869876b4bd6c
7
+ data.tar.gz: 625524b71e0d8c4b609cf846b89814bd3364f968b8f7276a3f31823720b6d41f2bc1116177d608cafa1696587736207cd020345236ce995e1e5992676efa71ad
@@ -13,11 +13,11 @@ module Math2D
13
13
  # Twice the mathematical constant PI, also called TAU.
14
14
  TWO_PI = TAU = Math::PI * 2
15
15
 
16
- # Multiplication constant to convert a value in degrees to radians
17
- # @note Can be used as a substitute to +Utils2D.to_deg+.
18
- DEG2RAD = Math::PI / 180
19
- # Multiplication constant to convert a value in degrees to radians
16
+ # Multiplication constant to convert a value in degrees to radians.
20
17
  # @note Can be used as a substitute to +Utils2D.to_rad+.
18
+ DEG2RAD = Math::PI / 180
19
+ # Multiplication constant to convert a value in radians to degrees.
20
+ # @note Can be used as a substitute to +Utils2D.to_deg+.
21
21
  RAD2DEG = 180 / Math::PI
22
22
 
23
23
  # Returns +angle+ radians in degrees.
@@ -142,8 +142,8 @@ module Math2D
142
142
  lerp(ix0, ix1, sy)
143
143
  end
144
144
 
145
- # If no argument is passed, randomly generates a greyscale RGB array.
146
- # Otherwise, returns a greyscale array with that argument normalized.
145
+ # If no argument is passed, randomly generates a grayscale RGB array.
146
+ # Otherwise, returns a grayscale array with that argument normalized.
147
147
  #
148
148
  # @param [Numeric] val
149
149
  # @return [Array<Float>]
@@ -156,6 +156,10 @@ module Math2D
156
156
  [c, c, c, 1.0]
157
157
  end
158
158
 
159
+ class << self
160
+ alias greyscale grayscale
161
+ end
162
+
159
163
  private
160
164
 
161
165
  # @private
@@ -5,8 +5,10 @@ module Math2D
5
5
  # - An implementation of various 2-dimensional vector methods.
6
6
  #
7
7
  # @author Ualace Henrique <ualacehenrique@hotmail.com>
8
- # @note MOST methods return a NEW Vector2D instead of changing
9
- # self and returning it, so be careful.
8
+ # @note ALL ! (bang) methods that return a vector (e.g. #normalize!, #add!) change the vector in place
9
+ # and return _self_.
10
+ # @note MOST (but not all) regular methods that return a vector create NEW _Vector2D_. Some however change the
11
+ # vector in place and return _self_, so be careful.
10
12
  # @attr [Numeric] x The x coordinate of the Vector
11
13
  # @attr [Numeric] y The y coordinate of the Vector
12
14
  class Vector2D
@@ -18,8 +20,27 @@ module Math2D
18
20
  # @param [Numeric] y
19
21
  # @return [Vector2D]
20
22
  def initialize(x = 0, y = 0)
21
- @x = x
22
- @y = y
23
+ @x = x.to_f
24
+ @y = y.to_f
25
+ end
26
+
27
+ # Creates a copy of the +other+ vector.
28
+ #
29
+ # @param [Vector2D] other Vector to copy
30
+ # @return [Vector2D]
31
+ def initialize_copy(other)
32
+ @x = other.x
33
+ @y = other.y
34
+ end
35
+
36
+ # Replace contents of this vector with contents of +other+ *in place*.
37
+ #
38
+ # @param [Vector2D] other
39
+ # @return [Vector2D] modified vector
40
+ def replace!(other)
41
+ @x = other.x
42
+ @y = other.y
43
+ self
23
44
  end
24
45
 
25
46
  # Sets the +x+ and +y+ components of the vector.
@@ -30,8 +51,8 @@ module Math2D
30
51
  # @param [Numeric] y
31
52
  # @return [Vector2D] self
32
53
  def set(x = self.x, y = self.y)
33
- @x = x
34
- @y = y
54
+ @x = x.to_f
55
+ @y = y.to_f
35
56
  self
36
57
  end
37
58
 
@@ -80,51 +101,56 @@ module Math2D
80
101
 
81
102
  # Negates both x and y values of +self+ and returns a new Vector2D.
82
103
  #
83
- # @return [Vector2D]
104
+ # @return [Vector2D] new vector
84
105
  def -@
85
106
  Vector2D.new(-@x, -@y)
86
107
  end
87
108
 
88
109
  alias negate -@
110
+ alias reverse -@
89
111
 
90
- # Adds +self+ to another vector or to a scalar.
91
112
  #
92
- # @param [Numeric, Vector2D] other
93
- # @return [Vector2D]
94
- def +(other)
95
- return Vector2D.new(@x + other.x, @y + other.y) if other.instance_of?(Vector2D)
113
+ # Negate this vector, modifying it in place
114
+ #
115
+ # @return [Vector2D] modified self
116
+ def reverse!
117
+ @x = -@x
118
+ @y = -@y
119
+ self
120
+ end
121
+
122
+ alias negate! reverse!
96
123
 
97
- Vector2D.new(@x + other, @y + other)
124
+ # Adds +self+ to another vector, scalar, or array of two scalars
125
+ #
126
+ # @param [Numeric, Vector2D, Array] other
127
+ # @return [Vector2D] new vector
128
+ def +(other)
129
+ clone.plus!(other)
98
130
  end
99
131
 
100
- # Subtracts +self+ to another vector or to a scalar.
132
+ # Subtracts +self+ from another vector, scalar, or array of two scalars
101
133
  #
102
- # @param [Numeric, Vector2D] other
103
- # @return [Vector2D]
134
+ # @param [Numeric, Vector2D, Array] other
135
+ # @return [Vector2D] new vector
104
136
  def -(other)
105
- return Vector2D.new(@x - other.x, @y - other.y) if other.instance_of?(Vector2D)
106
-
107
- Vector2D.new(@x - other, @y - other)
137
+ clone.minus!(other)
108
138
  end
109
139
 
110
- # Multiplies +self+ by another vector or by a scalar.
140
+ # Multiplies +self+ by another vector, scalar, or array of two scalars
111
141
  #
112
- # @param [Numeric, Vector2D] other
113
- # @return [Vector2D]
142
+ # @param [Numeric, Vector2D, Array] other
143
+ # @return [Vector2D] new vector
114
144
  def *(other)
115
- return Vector2D.new(@x * other.x, @y * other.y) if other.instance_of?(Vector2D)
116
-
117
- Vector2D.new(@x * other, @y * other)
145
+ clone.times!(other)
118
146
  end
119
147
 
120
- # Divides +self+ by another vector or by a scalar.
148
+ # Divides +self+ by another vector, scalar, or array of two scalars
121
149
  #
122
- # @param [Numeric, Vector2D] other
123
- # @return [Vector2D]
150
+ # @param [Numeric, Vector2D, Array] other
151
+ # @return [Vector2D] new vector
124
152
  def /(other)
125
- return Vector2D.new(@x / other.x, @y / other.y) if other.instance_of?(Vector2D)
126
-
127
- Vector2D.new(@x / other, @y / other)
153
+ clone.divide_by!(other)
128
154
  end
129
155
 
130
156
  # Compares +self+ and +other+ according to their components.
@@ -166,6 +192,8 @@ module Math2D
166
192
  (@x**2) + (@y**2)
167
193
  end
168
194
 
195
+ alias magnitude2 squared
196
+
169
197
  # Returns the magnitude of +self+.
170
198
  #
171
199
  # @return [Float]
@@ -175,6 +203,16 @@ module Math2D
175
203
 
176
204
  alias length magnitude
177
205
 
206
+ # Returns the squared Euclidean distance between +self+ and +other+. When comparing
207
+ # distances, comparing the squared distance yields the same result without the
208
+ # overhead of a square-root operation.
209
+ #
210
+ # @param [Vector2D] other
211
+ # @return [Float]
212
+ def distance2(other)
213
+ (other.x - @x)**2 + (other.y - @y)**2
214
+ end
215
+
178
216
  # Returns the Euclidean distance between +self+ and +other+.
179
217
  #
180
218
  # @param [Vector2D] other
@@ -193,32 +231,32 @@ module Math2D
193
231
  # Limit the magnitude of +self+ to +max+ and returns a new vector.
194
232
  #
195
233
  # @param [Numeric] max
196
- # @return [Vector2D]
234
+ # @return [Vector2D] new vector
197
235
  def limit(max)
198
236
  msq = squared
199
- vec = self
200
- if msq > (max**2)
201
- vec /= Math.sqrt(msq)
202
- vec *= max
203
- end
204
- vec
237
+ return self if msq <= (max**2)
238
+
239
+ self * (max / Math.sqrt(msq))
205
240
  end
206
241
 
207
- # Constrains the magnitude of +self+ between a minimum value +a+ and maximum value +b+.
242
+ # Constrains the magnitude of +self+ between a minimum value +min+ and maximum value +max+, returns a new
243
+ # vector or itself.
208
244
  #
209
245
  # @note I haven't experienced this with other methods (yet), so I'm only going to document this
210
246
  # here: you may end up with a broken magnitude (1.99999999 instead of 2, for example),
211
247
  # so always remember to check and round according to your need.
212
- # @param [Numeric] a
213
- # @param [Numeric] b
214
- # @return [Vector2D]
215
- def constrain(a, b)
216
- mag = magnitude
217
- v = Vector2D.one
218
- if mag > b
219
- v.set_magnitude(b)
220
- elsif mag < a
221
- v.set_magnitude(a)
248
+ # @param [Numeric] min
249
+ # @param [Numeric] max
250
+ # @return [Vector2D] new vector, or self
251
+ def constrain(min, max)
252
+ min, max = max, min if min > max # swap
253
+ mag2 = magnitude2
254
+ if mag2 > max.abs2
255
+ Vector2D.one.set_magnitude(max)
256
+ elsif mag2 < min.abs2
257
+ Vector2D.one.set_magnitude(min)
258
+ else
259
+ self
222
260
  end
223
261
  end
224
262
 
@@ -227,22 +265,26 @@ module Math2D
227
265
  # Sets the magnitude of +self+ to +new_mag+.
228
266
  #
229
267
  # @param [Numeric] new_mag
230
- # @return [Vector2D]
268
+ # @return [Vector2D] modified self
231
269
  def set_magnitude(new_mag)
232
270
  mag = magnitude
233
- mag = mag.zero? ? Float::INFINITY : mag
234
- Vector2D.new((@x * new_mag) / mag, (@y * new_mag) / mag)
271
+ mag = Float::INFINITY if mag.zero?
272
+ self * (new_mag / mag)
235
273
  end
236
274
 
275
+ alias magnitude! set_magnitude
276
+
237
277
  # Normalizes +self+ (set the magnitude to 1).
238
278
  # +unit+ is an alias for this method.
239
279
  #
240
- # @return [Vector2D]
280
+ # @return [Vector2D] modified self
241
281
  def normalize
242
282
  set_magnitude(1)
243
283
  end
244
284
 
245
- alias unit normalize
285
+ alias normalize! normalize
286
+ alias unit! normalize!
287
+ alias unit normalize!
246
288
 
247
289
  # Returns true if the magnitude of +self+ is equal to 1, false otherwise.
248
290
  # +unit?+ is an alias for this method.
@@ -292,39 +334,62 @@ module Math2D
292
334
  # @param [Vector2D] other
293
335
  # @return [Boolean]
294
336
  def opposite?(other)
295
- dot(other) < 0
337
+ dot(other).negative?
296
338
  end
297
339
 
298
340
  # Clockwise rotates +self+ +angle+ radians and returns it as a new Vector2D.
299
341
  #
300
342
  # @param [Numeric] angle
301
- # @return [Vector2D]
343
+ # @return [Vector2D] new vector
302
344
  def rotate(angle)
303
- Vector2D.new(
304
- @x * Math.cos(angle) - @y * Math.sin(angle),
305
- @x * Math.sin(angle) + @y * Math.cos(angle)
306
- )
345
+ clone.rotate!(angle)
346
+ end
347
+
348
+ # Clockwise rotates +self+ by +angle+ radians *in place*
349
+ #
350
+ # @param [Numeric] angle
351
+ # @return [Vector2D] modified self
352
+ def rotate!(angle)
353
+ sin_ang = Math.sin(angle)
354
+ cos_ang = Math.cos(angle)
355
+ @x = @x * cos_ang - @y * sin_ang
356
+ @y = @x * sin_ang + @y * cos_ang
307
357
  end
308
358
 
309
359
  # Clockwise rotates +self+ +angle+ radians around a +pivot+ point and returns it as a new Vector2D.
310
360
  #
311
361
  # @param [Vector2D] pivot
312
362
  # @param [Numeric] angle
313
- # @return [Vector2D]
363
+ # @return [Vector2D] new vector
314
364
  def rotate_around(pivot, angle)
315
- x_rotated = pivot.x + ((@x - pivot.x) * Math.cos(angle)) - ((@y - pivot.y) * Math.sin(angle))
316
- y_rotated = pivot.y + ((@x - pivot.x) * Math.sin(angle)) + ((@y - pivot.y) * Math.cos(angle))
365
+ clone.rotate_around!(pivot, angle)
366
+ end
317
367
 
318
- Vector2D.new(x_rotated, y_rotated)
368
+ # Clockwise rotates +self+ by +angle+ radians around a +pivot+ point *in place*
369
+ #
370
+ # @param [Vector2D] pivot
371
+ # @param [Numeric] angle
372
+ # @return [Vector2D] modified self
373
+ def rotate_around!(pivot, angle)
374
+ pivot_x = pivot.x
375
+ pivot_y = pivot.y
376
+ dx = (@x - pivot_x)
377
+ dy = (@y - pivot_y)
378
+ sin_ang = Math.sin(angle)
379
+ cos_ang = Math.cos(angle)
380
+ @x = pivot_x + (dx * cos_ang) - (dy * sin_ang)
381
+ @y = pivot_y + (dx * sin_ang) + (dy * cos_ang)
319
382
  end
320
383
 
321
384
  # Linear interpolate +self+ and +other+ with an amount +amt+.
322
385
  #
323
386
  # @param [Numeric, Vector2D] other
324
387
  # @param [Numeric] amt
325
- # @return [Vector2D]
388
+ # @return [Vector2D] new vector
326
389
  def lerp(other, amt)
327
- self + (other - self) * amt
390
+ Vector2D.new @x + (other.x - @x) * amt,
391
+ @y + (other.y - @y) * amt
392
+ # self + (other - self) * amt
328
393
  end
329
394
 
330
395
  # Calculates the parameter t of the +#lerp+ method between +self+ and +other+ given an interpolant +value+.
@@ -344,26 +409,27 @@ module Math2D
344
409
  def reflect(other)
345
410
  other = other.normalize
346
411
  dot_prod = other.dot(self)
347
- x = @x - dot_prod * other.x * 2
348
- y = @y - dot_prod * other.y * 2
349
- Vector2D.new(x, y)
412
+ Vector2D.new @x - dot_prod * other.x * 2,
413
+ @y - dot_prod * other.y * 2
350
414
  end
351
415
 
352
416
  # Refracts +self+ and returns it as a new Vector2D.
353
417
  # +other+ is the normal of the plane where +self+ is refracted.
354
418
  #
355
419
  # @see https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf GLS Language Specification (page 66)
420
+ # @see https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/refract.xhtml
356
421
  #
357
422
  # @param [Vector2D] other
358
423
  # @param [Numeric] refractive_index
359
424
  # @return [Vector2D]
360
425
  def refract(other, refractive_index)
361
426
  dot_prod = other.dot(self)
362
- k = 1.0 - refractive_index * refractive_index * (1.0 - dot_prod * dot_prod)
427
+ k = 1.0 - refractive_index.abs2 * (1.0 - dot_prod.abs2)
363
428
  return Vector2D.zero if k.negative?
364
429
 
365
- x = refractive_index * @x - (refractive_index * dot_prod * Math.sqrt(k)) * other.x
366
- y = refractive_index * @y - (refractive_index * dot_prod * Math.sqrt(k)) * other.y
430
+ other_refraction = (refractive_index * dot_prod * Math.sqrt(k))
431
+ x = refractive_index * @x - other_refraction * other.x
432
+ y = refractive_index * @y - other_refraction * other.y
367
433
  Vector2D.new(x, y)
368
434
  end
369
435
 
@@ -389,6 +455,26 @@ module Math2D
389
455
  to_a.to_s
390
456
  end
391
457
 
458
+ # Returns a *new vector* of the clockwise perpendicular to this vector.
459
+ #
460
+ # @return [Vector2D]
461
+ #
462
+ def vector_cross_product
463
+ Vector2D.new @y, -@x
464
+ end
465
+
466
+ alias perp vector_cross_product
467
+
468
+ # Replace this vector with it's clockwise perpendicular
469
+ #
470
+ # @return [Vector2D] modified self
471
+ def vector_cross_product!
472
+ @x, @y = @y, -@x
473
+ self
474
+ end
475
+
476
+ alias perp! vector_cross_product!
477
+
392
478
  # Returns a new Vector2D from an array +arr+.
393
479
  # If the array is bigger than 2 elements, only the first 2 will be considered.
394
480
  #
@@ -399,5 +485,103 @@ module Math2D
399
485
 
400
486
  Vector2D.new(arr[0], arr[1])
401
487
  end
488
+
489
+ # Multiplies +self+ by +delta+ in place.
490
+ #
491
+ # @param [Numeric, Vector2D, Array] delta
492
+ # @return [Vector2D] modified self
493
+ def times!(delta)
494
+ case delta
495
+ when Vector2D
496
+ @x *= delta.x
497
+ @y *= delta.y
498
+ when Array
499
+ @x *= delta[0]
500
+ @y *= delta[1]
501
+ else
502
+ @x *= delta
503
+ @y *= delta
504
+ end
505
+ self
506
+ end
507
+
508
+ # Subtracts +delta+ from +self+ in place.
509
+ #
510
+ # @param [Numeric, Vector2D, Array] delta
511
+ # @return [Vector2D] modified self
512
+ def minus!(delta)
513
+ case delta
514
+ when Vector2D
515
+ @x -= delta.x
516
+ @y -= delta.y
517
+ when Array
518
+ @x -= delta[0]
519
+ @y -= delta[1]
520
+ else
521
+ @x -= delta
522
+ @y -= delta
523
+ end
524
+ self
525
+ end
526
+
527
+ # Adds +delta+ to +self+ in place.
528
+ #
529
+ # @param [Numeric, Vector2D, Array] delta
530
+ # @return [Vector2D] modified self
531
+ def plus!(delta)
532
+ case delta
533
+ when Vector2D
534
+ @x += delta.x
535
+ @y += delta.y
536
+ when Array
537
+ @x += delta[0]
538
+ @y += delta[1]
539
+ else
540
+ @x += delta
541
+ @y += delta
542
+ end
543
+ self
544
+ end
545
+
546
+ # Divides +self+ by +delta+ in place.
547
+ #
548
+ # @param [Numeric, Vector2D, Array] delta
549
+ # @return [Vector2D] modified self
550
+ def divide_by!(delta)
551
+ case delta
552
+ when Vector2D
553
+ @x /= delta.x
554
+ @y /= delta.y
555
+ when Array
556
+ @x /= delta[0]
557
+ @y /= delta[1]
558
+ else
559
+ @x /= delta
560
+ @y /= delta
561
+ end
562
+ self
563
+ end
564
+
565
+ # Add +dx+ and +dy+ to the current vector's components, respectively
566
+ #
567
+ # @param [Numeric] dx
568
+ # @param [Numeric] dy
569
+ # @return [Vector2d] modified self
570
+ def add!(dx, dy)
571
+ @x += dx
572
+ @y += dy
573
+ self
574
+ end
575
+
576
+ # Subtract +dx+ and +dy+ _from_ the current vector's components, respectively
577
+ #
578
+ # @param [Numeric] dx
579
+ # @param [Numeric] dy
580
+ # @return [Vector2d] modified self
581
+ def subtract!(dx, dy)
582
+ @x -= dx
583
+ @y -= dy
584
+ self
585
+ end
402
586
  end
403
587
  end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: math2d
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: '1.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ualace Henrique
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-04-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
13
55
  description: A collection of useful Mathematical and Vector tools in 2D space
14
56
  email:
15
57
  executables: []
@@ -38,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
80
  - !ruby/object:Gem::Version
39
81
  version: '0'
40
82
  requirements: []
41
- rubygems_version: 3.3.3
83
+ rubygems_version: 3.3.9
42
84
  signing_key:
43
85
  specification_version: 4
44
86
  summary: Math2D