vector2d 2.2.3 → 2.3.0
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 +5 -5
- data/.github/dependabot.yml +39 -0
- data/.github/workflows/build.yml +79 -0
- data/.gitignore +1 -0
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +29 -0
- data/.tool-versions +1 -0
- data/.travis.yml +6 -7
- data/CHANGELOG.md +8 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/CONTRIBUTING.md +30 -0
- data/Gemfile +12 -4
- data/Gemfile.lock +67 -29
- data/README.md +14 -5
- data/Rakefile +9 -2
- data/lib/vector2d/calculations.rb +10 -26
- data/lib/vector2d/coercions.rb +1 -10
- data/lib/vector2d/fitting.rb +22 -18
- data/lib/vector2d/properties.rb +4 -11
- data/lib/vector2d/transformations.rb +19 -17
- data/lib/vector2d/version.rb +2 -2
- data/lib/vector2d.rb +27 -53
- data/release-please-config.json +10 -0
- data/spec/lib/vector2d/calculations_spec.rb +29 -5
- data/spec/lib/vector2d/coercions_spec.rb +19 -15
- data/spec/lib/vector2d/fitting_spec.rb +26 -32
- data/spec/lib/vector2d/properties_spec.rb +8 -4
- data/spec/lib/vector2d/transformations_spec.rb +73 -18
- data/spec/lib/vector2d_spec.rb +39 -22
- data/spec/spec_helper.rb +5 -4
- data/vector2d.gemspec +17 -17
- metadata +22 -62
data/lib/vector2d/coercions.rb
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Vector2d
|
|
4
4
|
module Coercions
|
|
5
|
-
include Contracts
|
|
6
|
-
|
|
7
|
-
Contract VectorLike => [Vector2d, Vector2d]
|
|
8
5
|
def coerce(other)
|
|
9
6
|
case other
|
|
10
7
|
when Vector2d
|
|
@@ -20,7 +17,6 @@ class Vector2d
|
|
|
20
17
|
#
|
|
21
18
|
# Vector2d(2, 3).inspect # => "Vector2d(2,3)"
|
|
22
19
|
#
|
|
23
|
-
Contract None => String
|
|
24
20
|
def inspect
|
|
25
21
|
"Vector2d(#{x},#{y})"
|
|
26
22
|
end
|
|
@@ -29,7 +25,6 @@ class Vector2d
|
|
|
29
25
|
#
|
|
30
26
|
# Vector2d(2, 3).to_a # => [2,3]
|
|
31
27
|
#
|
|
32
|
-
Contract None => [Num, Num]
|
|
33
28
|
def to_a
|
|
34
29
|
[x, y]
|
|
35
30
|
end
|
|
@@ -38,7 +33,6 @@ class Vector2d
|
|
|
38
33
|
#
|
|
39
34
|
# Vector2d(2, 3).to_hash # => {x: 2, y: 3}
|
|
40
35
|
#
|
|
41
|
-
Contract None => Hash
|
|
42
36
|
def to_hash
|
|
43
37
|
{ x: x, y: y }
|
|
44
38
|
end
|
|
@@ -47,7 +41,6 @@ class Vector2d
|
|
|
47
41
|
#
|
|
48
42
|
# Vector2d(2.0, 3.0).to_i_vector # => Vector2d(2,3)
|
|
49
43
|
#
|
|
50
|
-
Contract None => Vector2d
|
|
51
44
|
def to_i_vector
|
|
52
45
|
self.class.new(x.to_i, y.to_i)
|
|
53
46
|
end
|
|
@@ -56,7 +49,6 @@ class Vector2d
|
|
|
56
49
|
#
|
|
57
50
|
# Vector2d(2, 3).to_f_vector # => Vector2d(2.0,3.0)
|
|
58
51
|
#
|
|
59
|
-
Contract None => Vector2d
|
|
60
52
|
def to_f_vector
|
|
61
53
|
self.class.new(x.to_f, y.to_f)
|
|
62
54
|
end
|
|
@@ -65,7 +57,6 @@ class Vector2d
|
|
|
65
57
|
#
|
|
66
58
|
# Vector2d.new(150, 100).to_s # => "150x100"
|
|
67
59
|
#
|
|
68
|
-
Contract None => String
|
|
69
60
|
def to_s
|
|
70
61
|
"#{x}x#{y}"
|
|
71
62
|
end
|
data/lib/vector2d/fitting.rb
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Vector2d
|
|
4
4
|
module Fitting
|
|
5
|
-
include Contracts
|
|
6
|
-
|
|
7
5
|
# Scales down the given vector unless it fits inside.
|
|
8
6
|
#
|
|
9
7
|
# vector = Vector2d(20, 20)
|
|
@@ -11,46 +9,52 @@ class Vector2d
|
|
|
11
9
|
# vector.contain(Vector2d(40, 20)) # => Vector2d(20,10)
|
|
12
10
|
# vector.contain(Vector2d(20, 40)) # => Vector2d(10,20)
|
|
13
11
|
#
|
|
14
|
-
Contract VectorLike => Vector2d
|
|
15
12
|
def contain(other)
|
|
16
|
-
v,
|
|
17
|
-
|
|
13
|
+
v, = coerce(other)
|
|
14
|
+
v.x > x || v.y > y ? other.fit(self) : other
|
|
18
15
|
end
|
|
19
16
|
|
|
20
|
-
# Scales the vector to fit inside another vector, retaining the
|
|
17
|
+
# Scales the vector to fit inside another vector, retaining the
|
|
18
|
+
# aspect ratio.
|
|
21
19
|
#
|
|
22
20
|
# vector = Vector2d(20, 10)
|
|
23
21
|
# vector.fit(Vector2d(10, 10)) # => Vector2d(10,5)
|
|
24
22
|
# vector.fit(Vector2d(20, 20)) # => Vector2d(20,10)
|
|
25
23
|
# vector.fit(Vector2d(40, 40)) # => Vector2d(40,20)
|
|
26
24
|
#
|
|
27
|
-
# Note: Either axis will be disregarded if zero or nil. This is a
|
|
25
|
+
# Note: Either axis will be disregarded if zero or nil. This is a
|
|
26
|
+
# feature, not a bug.
|
|
28
27
|
#
|
|
29
|
-
Contract VectorLike => Vector2d
|
|
30
28
|
def fit(other)
|
|
31
|
-
v,
|
|
29
|
+
v, = coerce(other)
|
|
32
30
|
scale = v.to_f_vector / self
|
|
33
|
-
self * (
|
|
31
|
+
self * (
|
|
32
|
+
if scale.y.zero? || (scale.x.positive? && scale.x < scale.y)
|
|
33
|
+
scale.x
|
|
34
|
+
else
|
|
35
|
+
scale.y
|
|
36
|
+
end
|
|
37
|
+
)
|
|
34
38
|
end
|
|
35
|
-
|
|
39
|
+
alias constrain_both fit
|
|
36
40
|
|
|
37
|
-
# Constrain/expand so that one of the coordinates fit within (the
|
|
41
|
+
# Constrain/expand so that one of the coordinates fit within (the
|
|
42
|
+
# square implied by) another vector.
|
|
38
43
|
#
|
|
39
44
|
# constraint = Vector2d(5, 5)
|
|
40
45
|
# Vector2d(20, 10).fit_either(constraint) # => Vector2d(10,5)
|
|
41
46
|
# Vector2d(10, 20).fit_either(constraint) # => Vector2d(5,10)
|
|
42
47
|
#
|
|
43
|
-
Contract VectorLike => Vector2d
|
|
44
48
|
def fit_either(other)
|
|
45
|
-
v,
|
|
49
|
+
v, = coerce(other)
|
|
46
50
|
scale = v.to_f_vector / self
|
|
47
|
-
if
|
|
48
|
-
scale =
|
|
51
|
+
if scale.x.positive? && scale.y.positive?
|
|
52
|
+
scale = [scale.x, scale.y].max
|
|
49
53
|
self * scale
|
|
50
54
|
else
|
|
51
55
|
fit(v)
|
|
52
56
|
end
|
|
53
57
|
end
|
|
54
|
-
|
|
58
|
+
alias constrain_one fit_either
|
|
55
59
|
end
|
|
56
60
|
end
|
data/lib/vector2d/properties.rb
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Vector2d
|
|
4
4
|
module Properties
|
|
5
|
-
include Contracts
|
|
6
|
-
|
|
7
5
|
# Angle of vector.
|
|
8
6
|
#
|
|
9
7
|
# Vector2d(2, 3).angle # => 0.9827..
|
|
10
8
|
#
|
|
11
|
-
Contract None => Num
|
|
12
9
|
def angle
|
|
13
10
|
Math.atan2(y, x)
|
|
14
11
|
end
|
|
@@ -17,16 +14,14 @@ class Vector2d
|
|
|
17
14
|
#
|
|
18
15
|
# Vector2d(2, 3).aspect_ratio # => 0.6667..
|
|
19
16
|
#
|
|
20
|
-
Contract None => Num
|
|
21
17
|
def aspect_ratio
|
|
22
|
-
(x.to_f / y
|
|
18
|
+
(x.to_f / y).abs
|
|
23
19
|
end
|
|
24
20
|
|
|
25
21
|
# Length of vector.
|
|
26
22
|
#
|
|
27
23
|
# Vector2d(2, 3).length # => 3.6055..
|
|
28
24
|
#
|
|
29
|
-
Contract None => Num
|
|
30
25
|
def length
|
|
31
26
|
Math.sqrt(squared_length)
|
|
32
27
|
end
|
|
@@ -35,9 +30,8 @@ class Vector2d
|
|
|
35
30
|
#
|
|
36
31
|
# Vector2d(2, 3).squared_length # => 13
|
|
37
32
|
#
|
|
38
|
-
Contract None => Num
|
|
39
33
|
def squared_length
|
|
40
|
-
x * x + y * y
|
|
34
|
+
(x * x) + (y * y)
|
|
41
35
|
end
|
|
42
36
|
|
|
43
37
|
# Is this a normalized vector?
|
|
@@ -45,9 +39,8 @@ class Vector2d
|
|
|
45
39
|
# Vector2d(0, 1).normalized? # => true
|
|
46
40
|
# Vector2d(2, 3).normalized? # => false
|
|
47
41
|
#
|
|
48
|
-
Contract None => Bool
|
|
49
42
|
def normalized?
|
|
50
|
-
|
|
43
|
+
(length.to_f - 1.0).abs < Float::EPSILON
|
|
51
44
|
end
|
|
52
45
|
end
|
|
53
46
|
end
|
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Vector2d
|
|
4
4
|
module Transformations
|
|
5
|
-
include Contracts
|
|
6
|
-
|
|
7
5
|
# Rounds vector to up nearest integer.
|
|
8
6
|
#
|
|
9
7
|
# Vector2d(2.4, 3.6).ceil # => Vector2d(3,4)
|
|
10
8
|
#
|
|
11
|
-
Contract None => Vector2d
|
|
12
9
|
def ceil
|
|
13
10
|
self.class.new(x.ceil, y.ceil)
|
|
14
11
|
end
|
|
15
12
|
|
|
13
|
+
# Clamps the vector between two others, one axis at a time.
|
|
14
|
+
# The bounds are coerced, so scalars work too.
|
|
15
|
+
#
|
|
16
|
+
# vector = Vector2d(2, 8)
|
|
17
|
+
# vector.clamp(Vector2d(3, 3), Vector2d(6, 6)) # => Vector2d(3,6)
|
|
18
|
+
# vector.clamp(3, 6) # => Vector2d(3,6)
|
|
19
|
+
#
|
|
20
|
+
def clamp(min, max)
|
|
21
|
+
min_v, = coerce(min)
|
|
22
|
+
max_v, = coerce(max)
|
|
23
|
+
self.class.new(x.clamp(min_v.x, max_v.x), y.clamp(min_v.y, max_v.y))
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
# Rounds vector to up nearest integer.
|
|
17
27
|
#
|
|
18
28
|
# Vector2d(2.4, 3.6).floor # => Vector2d(2,3)
|
|
19
29
|
#
|
|
20
|
-
Contract None => Vector2d
|
|
21
30
|
def floor
|
|
22
31
|
self.class.new(x.floor, y.floor)
|
|
23
32
|
end
|
|
@@ -28,7 +37,6 @@ class Vector2d
|
|
|
28
37
|
# vector.normalize # => Vector2d(0.5547.., 0.8320..)
|
|
29
38
|
# vector.normalize.length # => 1.0
|
|
30
39
|
#
|
|
31
|
-
Contract None => Vector2d
|
|
32
40
|
def normalize
|
|
33
41
|
resize(1.0)
|
|
34
42
|
end
|
|
@@ -37,7 +45,6 @@ class Vector2d
|
|
|
37
45
|
#
|
|
38
46
|
# Vector2d(2, 3).perpendicular # => Vector2d(-3,2)
|
|
39
47
|
#
|
|
40
|
-
Contract None => Vector2d
|
|
41
48
|
def perpendicular
|
|
42
49
|
Vector2d.new(-y, x)
|
|
43
50
|
end
|
|
@@ -46,16 +53,14 @@ class Vector2d
|
|
|
46
53
|
#
|
|
47
54
|
# Vector2d(2, 3).resize(1.0) # => Vector2d(0.5547.., 0.8320..)
|
|
48
55
|
#
|
|
49
|
-
Contract Num => Vector2d
|
|
50
56
|
def resize(new_length)
|
|
51
|
-
self * (new_length /
|
|
57
|
+
self * (new_length / length)
|
|
52
58
|
end
|
|
53
59
|
|
|
54
60
|
# Reverses the vector.
|
|
55
61
|
#
|
|
56
62
|
# Vector2d(2, 3).reverse # => Vector2d(-2,-3)
|
|
57
63
|
#
|
|
58
|
-
Contract None => Vector2d
|
|
59
64
|
def reverse
|
|
60
65
|
self.class.new(-x, -y)
|
|
61
66
|
end
|
|
@@ -64,11 +69,10 @@ class Vector2d
|
|
|
64
69
|
#
|
|
65
70
|
# Vector2d(1, 0).rotate(Math:PI/2) => Vector2d(1,0)
|
|
66
71
|
#
|
|
67
|
-
Contract Num => Vector2d
|
|
68
72
|
def rotate(angle)
|
|
69
73
|
Vector2d.new(
|
|
70
|
-
x * Math.cos(angle) - y * Math.sin(angle),
|
|
71
|
-
x * Math.sin(angle) + y * Math.cos(angle)
|
|
74
|
+
(x * Math.cos(angle)) - (y * Math.sin(angle)),
|
|
75
|
+
(x * Math.sin(angle)) + (y * Math.cos(angle))
|
|
72
76
|
)
|
|
73
77
|
end
|
|
74
78
|
|
|
@@ -77,8 +81,7 @@ class Vector2d
|
|
|
77
81
|
# Vector2d(2.4, 3.6).round # => Vector2d(2,4)
|
|
78
82
|
# Vector2d(2.4444, 3.666).round(2) # => Vector2d(2.44, 3.67)
|
|
79
83
|
#
|
|
80
|
-
|
|
81
|
-
def round(digits=0)
|
|
84
|
+
def round(digits = 0)
|
|
82
85
|
self.class.new(x.round(digits), y.round(digits))
|
|
83
86
|
end
|
|
84
87
|
|
|
@@ -88,9 +91,8 @@ class Vector2d
|
|
|
88
91
|
# vector.truncate(5.0) # => Vector2d(2.0, 3.0)
|
|
89
92
|
# vector.truncate(1.0) # => Vector2d(0.5547.., 0.8320..)
|
|
90
93
|
#
|
|
91
|
-
Contract Num => Vector2d
|
|
92
94
|
def truncate(max)
|
|
93
|
-
resize([max,
|
|
95
|
+
resize([max, length].min)
|
|
94
96
|
end
|
|
95
97
|
end
|
|
96
98
|
end
|
data/lib/vector2d/version.rb
CHANGED
data/lib/vector2d.rb
CHANGED
|
@@ -1,25 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{ x: Num, y: Num },
|
|
10
|
-
{ 'x' => Num, 'y' => Num },
|
|
11
|
-
Num,
|
|
12
|
-
String,
|
|
13
|
-
Vector2d
|
|
14
|
-
]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
require 'vector2d/calculations'
|
|
18
|
-
require 'vector2d/coercions'
|
|
19
|
-
require 'vector2d/fitting'
|
|
20
|
-
require 'vector2d/properties'
|
|
21
|
-
require 'vector2d/transformations'
|
|
22
|
-
require 'vector2d/version'
|
|
3
|
+
require "vector2d/calculations"
|
|
4
|
+
require "vector2d/coercions"
|
|
5
|
+
require "vector2d/fitting"
|
|
6
|
+
require "vector2d/properties"
|
|
7
|
+
require "vector2d/transformations"
|
|
8
|
+
require "vector2d/version"
|
|
23
9
|
|
|
24
10
|
class Vector2d
|
|
25
11
|
extend Vector2d::Calculations::ClassMethods
|
|
@@ -41,55 +27,44 @@ class Vector2d
|
|
|
41
27
|
# Vector2d.parse({x: 150, y: 100})
|
|
42
28
|
# Vector2d.parse({"x" => 150.0, "y" => 100.0})
|
|
43
29
|
# Vector2d.parse(Vector2d(150, 100))
|
|
44
|
-
Contract VectorLike, Maybe[Num] => Vector2d
|
|
45
30
|
def parse(arg, second_arg = nil)
|
|
46
31
|
if second_arg.nil?
|
|
47
32
|
parse_single_arg(arg)
|
|
48
33
|
else
|
|
49
|
-
|
|
34
|
+
new(arg, second_arg)
|
|
50
35
|
end
|
|
51
36
|
end
|
|
52
37
|
|
|
53
38
|
private
|
|
54
39
|
|
|
55
|
-
Contract VectorLike => Vector2d
|
|
56
40
|
def parse_single_arg(arg)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
parse_str(arg)
|
|
64
|
-
when Hash
|
|
65
|
-
parse_hash(arg.dup)
|
|
66
|
-
else
|
|
67
|
-
self.new(arg, arg)
|
|
68
|
-
end
|
|
41
|
+
return arg if arg.is_a?(Vector2d)
|
|
42
|
+
return parse(*arg) if arg.is_a?(Array)
|
|
43
|
+
return parse_str(arg) if arg.is_a?(String)
|
|
44
|
+
return parse_hash(arg.dup) if arg.is_a?(Hash)
|
|
45
|
+
|
|
46
|
+
new(arg, arg)
|
|
69
47
|
end
|
|
70
48
|
|
|
71
|
-
Contract Hash => Vector2d
|
|
72
49
|
def parse_hash(hash)
|
|
73
|
-
hash[:x] ||= hash[
|
|
74
|
-
hash[:y] ||= hash[
|
|
75
|
-
|
|
50
|
+
hash[:x] ||= hash["x"] if hash.key?("x")
|
|
51
|
+
hash[:y] ||= hash["y"] if hash.key?("y")
|
|
52
|
+
new(hash[:x], hash[:y])
|
|
76
53
|
end
|
|
77
54
|
|
|
78
|
-
Contract String => Vector2d
|
|
79
55
|
def parse_str(str)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
fail ArgumentError, "not a valid string input"
|
|
85
|
-
end
|
|
56
|
+
raise ArgumentError, "not a valid string input" unless /^\s*[\d.]*\s*x\s*[\d.]*\s*$/.match?(str)
|
|
57
|
+
|
|
58
|
+
x, y = str.split("x")
|
|
59
|
+
new(x.to_f, y.to_f)
|
|
86
60
|
end
|
|
87
61
|
end
|
|
88
62
|
|
|
89
63
|
attr_reader :x, :y
|
|
90
64
|
|
|
91
65
|
def initialize(x, y)
|
|
92
|
-
@x
|
|
66
|
+
@x = x
|
|
67
|
+
@y = y
|
|
93
68
|
end
|
|
94
69
|
|
|
95
70
|
# Compares two vectors
|
|
@@ -97,9 +72,8 @@ class Vector2d
|
|
|
97
72
|
# Vector2d(2, 3) == Vector2d(2, 3) # => true
|
|
98
73
|
# Vector2d(2, 3) == Vector2d(1, 0) # => false
|
|
99
74
|
#
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
comp.x === x && comp.y === y
|
|
75
|
+
def ==(other)
|
|
76
|
+
other.x == x && other.y == y
|
|
103
77
|
end
|
|
104
78
|
end
|
|
105
79
|
|
|
@@ -107,6 +81,6 @@ end
|
|
|
107
81
|
#
|
|
108
82
|
# Vector2d(2, 3) # => Vector2d(2,3)
|
|
109
83
|
#
|
|
110
|
-
def Vector2d(*
|
|
111
|
-
Vector2d.parse(*
|
|
84
|
+
def Vector2d(*)
|
|
85
|
+
Vector2d.parse(*)
|
|
112
86
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "spec_helper"
|
|
4
4
|
|
|
5
5
|
describe Vector2d::Calculations do
|
|
6
6
|
subject(:vector) { Vector2d.new(2, 3) }
|
|
@@ -8,6 +8,7 @@ describe Vector2d::Calculations do
|
|
|
8
8
|
describe ".cross_product" do
|
|
9
9
|
let(:v1) { Vector2d.new(2, 3) }
|
|
10
10
|
let(:v2) { Vector2d.new(4, 5) }
|
|
11
|
+
|
|
11
12
|
it "calculates the cross product between two vectors" do
|
|
12
13
|
expect(Vector2d.cross_product(v1, v2)).to eq(-2.0)
|
|
13
14
|
end
|
|
@@ -16,6 +17,7 @@ describe Vector2d::Calculations do
|
|
|
16
17
|
describe ".dot_product" do
|
|
17
18
|
let(:v1) { Vector2d.new(2, 3) }
|
|
18
19
|
let(:v2) { Vector2d.new(4, 5) }
|
|
20
|
+
|
|
19
21
|
it "calculates the dot product between two vectors" do
|
|
20
22
|
expect(Vector2d.dot_product(v1, v2)).to eq(23)
|
|
21
23
|
end
|
|
@@ -24,6 +26,7 @@ describe Vector2d::Calculations do
|
|
|
24
26
|
describe ".angle_between" do
|
|
25
27
|
let(:v1) { Vector2d.new(2, 3) }
|
|
26
28
|
let(:v2) { Vector2d.new(4, 5) }
|
|
29
|
+
|
|
27
30
|
it "calculates the angle between two vectors" do
|
|
28
31
|
expect(Vector2d.angle_between(v1, v2)).to be_within(0.0001).of(0.0867)
|
|
29
32
|
end
|
|
@@ -32,12 +35,15 @@ describe Vector2d::Calculations do
|
|
|
32
35
|
describe "*" do
|
|
33
36
|
context "with vector" do
|
|
34
37
|
subject(:vector) { Vector2d.new(2, 3) * Vector2d.new(3, 4) }
|
|
38
|
+
|
|
35
39
|
it "multiplies the vectors" do
|
|
36
40
|
expect(vector).to eq(Vector2d.new(6, 12))
|
|
37
41
|
end
|
|
38
42
|
end
|
|
43
|
+
|
|
39
44
|
context "with number" do
|
|
40
45
|
subject(:vector) { Vector2d.new(2, 3) * 3 }
|
|
46
|
+
|
|
41
47
|
it "multiplies both members" do
|
|
42
48
|
expect(vector).to eq(Vector2d.new(6, 9))
|
|
43
49
|
end
|
|
@@ -47,12 +53,15 @@ describe Vector2d::Calculations do
|
|
|
47
53
|
describe "/" do
|
|
48
54
|
context "with vector" do
|
|
49
55
|
subject(:vector) { Vector2d.new(6, 12) / Vector2d.new(2, 3) }
|
|
56
|
+
|
|
50
57
|
it "divides the vectors" do
|
|
51
58
|
expect(vector).to eq(Vector2d.new(3, 4))
|
|
52
59
|
end
|
|
53
60
|
end
|
|
61
|
+
|
|
54
62
|
context "with number" do
|
|
55
63
|
subject(:vector) { Vector2d.new(6, 12) / 3 }
|
|
64
|
+
|
|
56
65
|
it "divides both members" do
|
|
57
66
|
expect(vector).to eq(Vector2d.new(2, 4))
|
|
58
67
|
end
|
|
@@ -62,12 +71,15 @@ describe Vector2d::Calculations do
|
|
|
62
71
|
describe "+" do
|
|
63
72
|
context "with vector" do
|
|
64
73
|
subject(:vector) { Vector2d.new(2, 3) + Vector2d.new(3, 4) }
|
|
74
|
+
|
|
65
75
|
it "adds the vectors" do
|
|
66
76
|
expect(vector).to eq(Vector2d.new(5, 7))
|
|
67
77
|
end
|
|
68
78
|
end
|
|
79
|
+
|
|
69
80
|
context "with number" do
|
|
70
81
|
subject(:vector) { Vector2d.new(2, 3) + 2 }
|
|
82
|
+
|
|
71
83
|
it "adds to both members" do
|
|
72
84
|
expect(vector).to eq(Vector2d.new(4, 5))
|
|
73
85
|
end
|
|
@@ -77,12 +89,15 @@ describe Vector2d::Calculations do
|
|
|
77
89
|
describe "-" do
|
|
78
90
|
context "with vector" do
|
|
79
91
|
subject(:vector) { Vector2d.new(3, 5) - Vector2d.new(1, 2) }
|
|
92
|
+
|
|
80
93
|
it "subtracts the vectors" do
|
|
81
94
|
expect(vector).to eq(Vector2d.new(2, 3))
|
|
82
95
|
end
|
|
83
96
|
end
|
|
97
|
+
|
|
84
98
|
context "with number" do
|
|
85
99
|
subject(:vector) { Vector2d.new(2, 3) - 2 }
|
|
100
|
+
|
|
86
101
|
it "subtracts from both members" do
|
|
87
102
|
expect(vector).to eq(Vector2d.new(0, 1))
|
|
88
103
|
end
|
|
@@ -91,13 +106,17 @@ describe Vector2d::Calculations do
|
|
|
91
106
|
|
|
92
107
|
describe "#cross_product" do
|
|
93
108
|
let(:comp) { Vector2d.new(3, 4) }
|
|
109
|
+
|
|
94
110
|
it "calulates the cross product" do
|
|
95
|
-
expect(
|
|
111
|
+
expect(
|
|
112
|
+
vector.cross_product(comp)
|
|
113
|
+
).to eq(Vector2d.cross_product(vector, comp))
|
|
96
114
|
end
|
|
97
115
|
end
|
|
98
116
|
|
|
99
117
|
describe "#distance" do
|
|
100
118
|
let(:comp) { Vector2d.new(3, 4) }
|
|
119
|
+
|
|
101
120
|
it "returns the distance between two vectors" do
|
|
102
121
|
expect(vector.distance(comp)).to be_within(0.0001).of(1.4142)
|
|
103
122
|
end
|
|
@@ -105,6 +124,7 @@ describe Vector2d::Calculations do
|
|
|
105
124
|
|
|
106
125
|
describe "#squared_distance" do
|
|
107
126
|
let(:comp) { Vector2d.new(5, 6) }
|
|
127
|
+
|
|
108
128
|
it "returns the squared distance between two vectors" do
|
|
109
129
|
expect(vector.squared_distance(comp)).to eq(18)
|
|
110
130
|
end
|
|
@@ -112,6 +132,7 @@ describe Vector2d::Calculations do
|
|
|
112
132
|
|
|
113
133
|
describe "#dot_product" do
|
|
114
134
|
let(:comp) { Vector2d.new(3, 4) }
|
|
135
|
+
|
|
115
136
|
it "calulates the dot product" do
|
|
116
137
|
expect(vector.dot_product(comp)).to eq(Vector2d.dot_product(vector, comp))
|
|
117
138
|
end
|
|
@@ -119,8 +140,11 @@ describe Vector2d::Calculations do
|
|
|
119
140
|
|
|
120
141
|
describe "#angle_between" do
|
|
121
142
|
let(:comp) { Vector2d.new(3, 4) }
|
|
143
|
+
|
|
122
144
|
it "calculates the angle between vectors" do
|
|
123
|
-
expect(
|
|
145
|
+
expect(
|
|
146
|
+
vector.angle_between(comp)
|
|
147
|
+
).to eq(Vector2d.angle_between(vector, comp))
|
|
124
148
|
end
|
|
125
149
|
end
|
|
126
|
-
end
|
|
150
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "spec_helper"
|
|
4
4
|
|
|
5
5
|
describe Vector2d::Coercions do
|
|
6
6
|
subject(:vector) { Vector2d.new(2, 3) }
|
|
@@ -18,38 +18,42 @@ describe Vector2d::Coercions do
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
describe "#to_f_vector" do
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
subject { vector.to_f_vector }
|
|
22
|
+
|
|
23
|
+
its(:x) { is_expected.to be_a(Float) }
|
|
24
|
+
its(:y) { is_expected.to be_a(Float) }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
describe "#to_hash" do
|
|
28
28
|
it "returns a hash" do
|
|
29
|
-
expect(vector.to_hash).to eq(
|
|
29
|
+
expect(vector.to_hash).to eq(x: 2, y: 3)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
describe "#to_i_vector" do
|
|
34
|
-
subject
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
subject { vector.to_i_vector }
|
|
35
|
+
|
|
36
|
+
let(:vector) { Vector2d.new(2.0, 3.0) }
|
|
37
|
+
|
|
38
|
+
its(:x) { is_expected.to be_a(Integer) }
|
|
39
|
+
its(:y) { is_expected.to be_a(Integer) }
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
describe "#to_s" do
|
|
42
43
|
context "when fixnum" do
|
|
43
44
|
subject(:vector) { Vector2d.new(2, 3) }
|
|
45
|
+
|
|
44
46
|
it "renders a string" do
|
|
45
|
-
expect(vector.to_s).to eq(
|
|
47
|
+
expect(vector.to_s).to eq("2x3")
|
|
46
48
|
end
|
|
47
49
|
end
|
|
50
|
+
|
|
48
51
|
context "when float" do
|
|
49
52
|
subject(:vector) { Vector2d.new(2.0, 3.0) }
|
|
53
|
+
|
|
50
54
|
it "renders a string" do
|
|
51
|
-
expect(vector.to_s).to eq(
|
|
55
|
+
expect(vector.to_s).to eq("2.0x3.0")
|
|
52
56
|
end
|
|
53
57
|
end
|
|
54
58
|
end
|
|
55
|
-
end
|
|
59
|
+
end
|