vector2d 2.2.4 → 3.0.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 +4 -4
- data/.github/dependabot.yml +39 -0
- data/.github/workflows/build.yml +48 -10
- data/.gitignore +3 -1
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +5 -2
- data/.tool-versions +1 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +224 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/CONTRIBUTING.md +30 -0
- data/Gemfile +6 -2
- data/Gemfile.lock +85 -51
- data/README.md +330 -13
- data/Rakefile +21 -0
- data/benchmark/vector_comparison.rb +129 -0
- data/lib/vector2d/angles.rb +315 -0
- data/lib/vector2d/arithmetic.rb +97 -0
- data/lib/vector2d/comparison.rb +188 -0
- data/lib/vector2d/componentwise.rb +239 -0
- data/lib/vector2d/constructors.rb +137 -0
- data/lib/vector2d/conversions.rb +139 -0
- data/lib/vector2d/coordinates.rb +22 -0
- data/lib/vector2d/deprecation.rb +16 -0
- data/lib/vector2d/dimensions.rb +297 -0
- data/lib/vector2d/interpolation.rb +191 -0
- data/lib/vector2d/lengths.rb +284 -0
- data/lib/vector2d/matrix_interop.rb +93 -0
- data/lib/vector2d/parsing.rb +142 -0
- data/lib/vector2d/projection.rb +208 -0
- data/lib/vector2d/version.rb +2 -1
- data/lib/vector2d.rb +174 -62
- data/release-please-config.json +10 -0
- data/spec/lib/vector2d/angles_spec.rb +441 -0
- data/spec/lib/vector2d/{calculations_spec.rb → arithmetic_spec.rb} +48 -58
- data/spec/lib/vector2d/comparison_spec.rb +358 -0
- data/spec/lib/vector2d/componentwise_spec.rb +300 -0
- data/spec/lib/vector2d/constructors_spec.rb +299 -0
- data/spec/lib/vector2d/conversions_spec.rb +234 -0
- data/spec/lib/vector2d/dimensions_spec.rb +820 -0
- data/spec/lib/vector2d/interpolation_spec.rb +322 -0
- data/spec/lib/vector2d/lengths_spec.rb +457 -0
- data/spec/lib/vector2d/matrix_interop_spec.rb +92 -0
- data/spec/lib/vector2d/parsing_spec.rb +329 -0
- data/spec/lib/vector2d/projection_spec.rb +306 -0
- data/spec/lib/vector2d_documentation_spec.rb +38 -0
- data/spec/lib/vector2d_immutability_spec.rb +263 -0
- data/spec/lib/vector2d_spec.rb +90 -50
- data/spec/lib/vector2d_subclassing_spec.rb +210 -0
- data/spec/lib/vector2d_tags_spec.rb +43 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/doc_examples/comments.rb +65 -0
- data/spec/support/doc_examples/markdown.rb +50 -0
- data/spec/support/doc_examples.rb +94 -0
- data/spec/support/doc_tags.rb +151 -0
- data/spec/support/shared_examples/class_preserving_method.rb +10 -0
- data/spec/support/shared_examples/deprecated_method.rb +25 -0
- data/spec/support/shared_examples/parsed_vector.rb +11 -0
- data/vector2d.gemspec +9 -3
- metadata +55 -19
- data/.travis.yml +0 -10
- data/lib/vector2d/calculations.rb +0 -141
- data/lib/vector2d/coercions.rb +0 -64
- data/lib/vector2d/fitting.rb +0 -60
- data/lib/vector2d/properties.rb +0 -46
- data/lib/vector2d/transformations.rb +0 -85
- data/spec/lib/vector2d/coercions_spec.rb +0 -59
- data/spec/lib/vector2d/fitting_spec.rb +0 -70
- data/spec/lib/vector2d/properties_spec.rb +0 -47
- data/spec/lib/vector2d/transformations_spec.rb +0 -122
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Vector2d
|
|
4
|
-
module Calculations
|
|
5
|
-
module ClassMethods
|
|
6
|
-
# Calculates cross product of two vectors.
|
|
7
|
-
#
|
|
8
|
-
# v1 = Vector2d(2, 1)
|
|
9
|
-
# v2 = Vector2d(2, 3)
|
|
10
|
-
# Vector2d.cross_product(v1, v2) # => 4
|
|
11
|
-
#
|
|
12
|
-
def cross_product(vector1, vector2)
|
|
13
|
-
(vector1.x * vector2.y) - (vector1.y * vector2.x)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Calculates dot product of two vectors.
|
|
17
|
-
#
|
|
18
|
-
# v1 = Vector2d(2, 1)
|
|
19
|
-
# v2 = Vector2d(2, 3)
|
|
20
|
-
# Vector2d.dot_product(v1, v2) # => 10
|
|
21
|
-
#
|
|
22
|
-
def dot_product(vector1, vector2)
|
|
23
|
-
(vector1.x * vector2.x) + (vector1.y * vector2.y)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Calculates angle between two vectors in radians.
|
|
27
|
-
#
|
|
28
|
-
# v1 = Vector2d(2, 3)
|
|
29
|
-
# v2 = Vector2d(4, 5)
|
|
30
|
-
# Vector2d.angle_between(v1, v2) # => 0.0867..
|
|
31
|
-
#
|
|
32
|
-
def angle_between(vector1, vector2)
|
|
33
|
-
one = vector1.normalized? ? vector1 : vector1.normalize
|
|
34
|
-
two = vector2.normalized? ? vector2 : vector2.normalize
|
|
35
|
-
Math.acos(dot_product(one, two))
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Multiplies vectors.
|
|
40
|
-
#
|
|
41
|
-
# Vector2d(1, 2) * Vector2d(2, 3) # => Vector2d(2, 6)
|
|
42
|
-
# Vector2d(1, 2) * 2 # => Vector2d(2, 4)
|
|
43
|
-
#
|
|
44
|
-
def *(other)
|
|
45
|
-
calculate_each(:*, other)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Divides vectors.
|
|
49
|
-
#
|
|
50
|
-
# Vector2d(4, 2) / Vector2d(2, 1) # => Vector2d(2, 2)
|
|
51
|
-
# Vector2d(4, 2) / 2 # => Vector2d(2, 1)
|
|
52
|
-
#
|
|
53
|
-
def /(other)
|
|
54
|
-
calculate_each(:/, other)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Adds vectors.
|
|
58
|
-
#
|
|
59
|
-
# Vector2d(1, 2) + Vector2d(2, 3) # => Vector2d(3, 5)
|
|
60
|
-
# Vector2d(1, 2) + 2 # => Vector2d(3, 4)
|
|
61
|
-
#
|
|
62
|
-
def +(other)
|
|
63
|
-
calculate_each(:+, other)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Subtracts vectors.
|
|
67
|
-
#
|
|
68
|
-
# Vector2d(2, 3) - Vector2d(2, 1) # => Vector2d(0, 2)
|
|
69
|
-
# Vector2d(4, 3) - 1 # => Vector2d(3, 2)
|
|
70
|
-
#
|
|
71
|
-
def -(other)
|
|
72
|
-
calculate_each(:-, other)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Calculates the distance between two vectors.
|
|
76
|
-
#
|
|
77
|
-
# v1 = Vector2d(2, 3)
|
|
78
|
-
# v2 = Vector2d(5, 6)
|
|
79
|
-
# v1.distance(v2) # => 1.4142..
|
|
80
|
-
#
|
|
81
|
-
def distance(other)
|
|
82
|
-
Math.sqrt(squared_distance(other))
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Calculate squared distance between vectors.
|
|
86
|
-
#
|
|
87
|
-
# v1 = Vector2d(2, 3)
|
|
88
|
-
# v2 = Vector2d(5, 6)
|
|
89
|
-
# v1.distance_squared(v2) # => 18
|
|
90
|
-
#
|
|
91
|
-
def squared_distance(other)
|
|
92
|
-
v, = coerce(other)
|
|
93
|
-
dx = v.x - x
|
|
94
|
-
dy = v.y - y
|
|
95
|
-
(dx * dx) + (dy * dy)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Dot product of this vector and another vector.
|
|
99
|
-
#
|
|
100
|
-
# v1 = Vector2d(2, 1)
|
|
101
|
-
# v2 = Vector2d(2, 3)
|
|
102
|
-
# v1.dot_product(v2) # => 10
|
|
103
|
-
#
|
|
104
|
-
def dot_product(other)
|
|
105
|
-
v, = coerce(other)
|
|
106
|
-
self.class.dot_product(self, v)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Cross product of this vector and another vector.
|
|
110
|
-
#
|
|
111
|
-
# v1 = Vector2d(2, 1)
|
|
112
|
-
# v2 = Vector2d(2, 3)
|
|
113
|
-
# v1.cross_product(v2) # => 4
|
|
114
|
-
#
|
|
115
|
-
def cross_product(other)
|
|
116
|
-
v, = coerce(other)
|
|
117
|
-
self.class.cross_product(self, v)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Angle in radians between this vector and another vector.
|
|
121
|
-
#
|
|
122
|
-
# v1 = Vector2d(2, 3)
|
|
123
|
-
# v2 = Vector2d(4, 5)
|
|
124
|
-
# v1.angle_between(v2) # => 0.0867..
|
|
125
|
-
#
|
|
126
|
-
def angle_between(other)
|
|
127
|
-
v, = coerce(other)
|
|
128
|
-
self.class.angle_between(self, v)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
private
|
|
132
|
-
|
|
133
|
-
def calculate_each(method, other)
|
|
134
|
-
v, = coerce(other)
|
|
135
|
-
self.class.new(
|
|
136
|
-
x.send(method, v.x),
|
|
137
|
-
y.send(method, v.y)
|
|
138
|
-
)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
data/lib/vector2d/coercions.rb
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Vector2d
|
|
4
|
-
module Coercions
|
|
5
|
-
def coerce(other)
|
|
6
|
-
case other
|
|
7
|
-
when Vector2d
|
|
8
|
-
[other, self]
|
|
9
|
-
when Array, Numeric, String, Hash
|
|
10
|
-
[Vector2d.parse(other), self]
|
|
11
|
-
else
|
|
12
|
-
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Renders vector as a pretty string.
|
|
17
|
-
#
|
|
18
|
-
# Vector2d(2, 3).inspect # => "Vector2d(2,3)"
|
|
19
|
-
#
|
|
20
|
-
def inspect
|
|
21
|
-
"Vector2d(#{x},#{y})"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Converts vector to array.
|
|
25
|
-
#
|
|
26
|
-
# Vector2d(2, 3).to_a # => [2,3]
|
|
27
|
-
#
|
|
28
|
-
def to_a
|
|
29
|
-
[x, y]
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Converts vector to hash.
|
|
33
|
-
#
|
|
34
|
-
# Vector2d(2, 3).to_hash # => {x: 2, y: 3}
|
|
35
|
-
#
|
|
36
|
-
def to_hash
|
|
37
|
-
{ x: x, y: y }
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Converts vector to fixnums.
|
|
41
|
-
#
|
|
42
|
-
# Vector2d(2.0, 3.0).to_i_vector # => Vector2d(2,3)
|
|
43
|
-
#
|
|
44
|
-
def to_i_vector
|
|
45
|
-
self.class.new(x.to_i, y.to_i)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Converts vector to floats.
|
|
49
|
-
#
|
|
50
|
-
# Vector2d(2, 3).to_f_vector # => Vector2d(2.0,3.0)
|
|
51
|
-
#
|
|
52
|
-
def to_f_vector
|
|
53
|
-
self.class.new(x.to_f, y.to_f)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Converts vector to string.
|
|
57
|
-
#
|
|
58
|
-
# Vector2d.new(150, 100).to_s # => "150x100"
|
|
59
|
-
#
|
|
60
|
-
def to_s
|
|
61
|
-
"#{x}x#{y}"
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
data/lib/vector2d/fitting.rb
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Vector2d
|
|
4
|
-
module Fitting
|
|
5
|
-
# Scales down the given vector unless it fits inside.
|
|
6
|
-
#
|
|
7
|
-
# vector = Vector2d(20, 20)
|
|
8
|
-
# vector.contain(Vector2d(10, 10)) # => Vector2d(10,10)
|
|
9
|
-
# vector.contain(Vector2d(40, 20)) # => Vector2d(20,10)
|
|
10
|
-
# vector.contain(Vector2d(20, 40)) # => Vector2d(10,20)
|
|
11
|
-
#
|
|
12
|
-
def contain(other)
|
|
13
|
-
v, = coerce(other)
|
|
14
|
-
v.x > x || v.y > y ? other.fit(self) : other
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Scales the vector to fit inside another vector, retaining the
|
|
18
|
-
# aspect ratio.
|
|
19
|
-
#
|
|
20
|
-
# vector = Vector2d(20, 10)
|
|
21
|
-
# vector.fit(Vector2d(10, 10)) # => Vector2d(10,5)
|
|
22
|
-
# vector.fit(Vector2d(20, 20)) # => Vector2d(20,10)
|
|
23
|
-
# vector.fit(Vector2d(40, 40)) # => Vector2d(40,20)
|
|
24
|
-
#
|
|
25
|
-
# Note: Either axis will be disregarded if zero or nil. This is a
|
|
26
|
-
# feature, not a bug.
|
|
27
|
-
#
|
|
28
|
-
def fit(other)
|
|
29
|
-
v, = coerce(other)
|
|
30
|
-
scale = v.to_f_vector / 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
|
-
)
|
|
38
|
-
end
|
|
39
|
-
alias constrain_both fit
|
|
40
|
-
|
|
41
|
-
# Constrain/expand so that one of the coordinates fit within (the
|
|
42
|
-
# square implied by) another vector.
|
|
43
|
-
#
|
|
44
|
-
# constraint = Vector2d(5, 5)
|
|
45
|
-
# Vector2d(20, 10).fit_either(constraint) # => Vector2d(10,5)
|
|
46
|
-
# Vector2d(10, 20).fit_either(constraint) # => Vector2d(5,10)
|
|
47
|
-
#
|
|
48
|
-
def fit_either(other)
|
|
49
|
-
v, = coerce(other)
|
|
50
|
-
scale = v.to_f_vector / self
|
|
51
|
-
if scale.x.positive? && scale.y.positive?
|
|
52
|
-
scale = [scale.x, scale.y].max
|
|
53
|
-
self * scale
|
|
54
|
-
else
|
|
55
|
-
fit(v)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
alias constrain_one fit_either
|
|
59
|
-
end
|
|
60
|
-
end
|
data/lib/vector2d/properties.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Vector2d
|
|
4
|
-
module Properties
|
|
5
|
-
# Angle of vector.
|
|
6
|
-
#
|
|
7
|
-
# Vector2d(2, 3).angle # => 0.9827..
|
|
8
|
-
#
|
|
9
|
-
def angle
|
|
10
|
-
Math.atan2(y, x)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Aspect ratio of vector.
|
|
14
|
-
#
|
|
15
|
-
# Vector2d(2, 3).aspect_ratio # => 0.6667..
|
|
16
|
-
#
|
|
17
|
-
def aspect_ratio
|
|
18
|
-
(x.to_f / y).abs
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Length of vector.
|
|
22
|
-
#
|
|
23
|
-
# Vector2d(2, 3).length # => 3.6055..
|
|
24
|
-
#
|
|
25
|
-
def length
|
|
26
|
-
Math.sqrt(squared_length)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Squared length of vector.
|
|
30
|
-
#
|
|
31
|
-
# Vector2d(2, 3).squared_length # => 13
|
|
32
|
-
#
|
|
33
|
-
def squared_length
|
|
34
|
-
(x * x) + (y * y)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Is this a normalized vector?
|
|
38
|
-
#
|
|
39
|
-
# Vector2d(0, 1).normalized? # => true
|
|
40
|
-
# Vector2d(2, 3).normalized? # => false
|
|
41
|
-
#
|
|
42
|
-
def normalized?
|
|
43
|
-
(length.to_f - 1.0).abs < Float::EPSILON
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Vector2d
|
|
4
|
-
module Transformations
|
|
5
|
-
# Rounds vector to up nearest integer.
|
|
6
|
-
#
|
|
7
|
-
# Vector2d(2.4, 3.6).ceil # => Vector2d(3,4)
|
|
8
|
-
#
|
|
9
|
-
def ceil
|
|
10
|
-
self.class.new(x.ceil, y.ceil)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Rounds vector to up nearest integer.
|
|
14
|
-
#
|
|
15
|
-
# Vector2d(2.4, 3.6).floor # => Vector2d(2,3)
|
|
16
|
-
#
|
|
17
|
-
def floor
|
|
18
|
-
self.class.new(x.floor, y.floor)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Normalizes the vector.
|
|
22
|
-
#
|
|
23
|
-
# vector = Vector2d(2, 3)
|
|
24
|
-
# vector.normalize # => Vector2d(0.5547.., 0.8320..)
|
|
25
|
-
# vector.normalize.length # => 1.0
|
|
26
|
-
#
|
|
27
|
-
def normalize
|
|
28
|
-
resize(1.0)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Returns a perpendicular vector.
|
|
32
|
-
#
|
|
33
|
-
# Vector2d(2, 3).perpendicular # => Vector2d(-3,2)
|
|
34
|
-
#
|
|
35
|
-
def perpendicular
|
|
36
|
-
Vector2d.new(-y, x)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Changes magnitude of vector.
|
|
40
|
-
#
|
|
41
|
-
# Vector2d(2, 3).resize(1.0) # => Vector2d(0.5547.., 0.8320..)
|
|
42
|
-
#
|
|
43
|
-
def resize(new_length)
|
|
44
|
-
self * (new_length / length)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Reverses the vector.
|
|
48
|
-
#
|
|
49
|
-
# Vector2d(2, 3).reverse # => Vector2d(-2,-3)
|
|
50
|
-
#
|
|
51
|
-
def reverse
|
|
52
|
-
self.class.new(-x, -y)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Rotates the vector
|
|
56
|
-
#
|
|
57
|
-
# Vector2d(1, 0).rotate(Math:PI/2) => Vector2d(1,0)
|
|
58
|
-
#
|
|
59
|
-
def rotate(angle)
|
|
60
|
-
Vector2d.new(
|
|
61
|
-
(x * Math.cos(angle)) - (y * Math.sin(angle)),
|
|
62
|
-
(x * Math.sin(angle)) + (y * Math.cos(angle))
|
|
63
|
-
)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Rounds vector to nearest integer.
|
|
67
|
-
#
|
|
68
|
-
# Vector2d(2.4, 3.6).round # => Vector2d(2,4)
|
|
69
|
-
# Vector2d(2.4444, 3.666).round(2) # => Vector2d(2.44, 3.67)
|
|
70
|
-
#
|
|
71
|
-
def round(digits = 0)
|
|
72
|
-
self.class.new(x.round(digits), y.round(digits))
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Truncates to max length if vector is longer than max.
|
|
76
|
-
#
|
|
77
|
-
# vector = Vector2d(2.0, 3.0)
|
|
78
|
-
# vector.truncate(5.0) # => Vector2d(2.0, 3.0)
|
|
79
|
-
# vector.truncate(1.0) # => Vector2d(0.5547.., 0.8320..)
|
|
80
|
-
#
|
|
81
|
-
def truncate(max)
|
|
82
|
-
resize([max, length].min)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
describe Vector2d::Coercions do
|
|
6
|
-
subject(:vector) { Vector2d.new(2, 3) }
|
|
7
|
-
|
|
8
|
-
describe "#inspect" do
|
|
9
|
-
it "renders a string representation" do
|
|
10
|
-
expect(vector.inspect).to eq("Vector2d(2,3)")
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe "#to_a" do
|
|
15
|
-
it "returns an array" do
|
|
16
|
-
expect(vector.to_a).to eq([2, 3])
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe "#to_f_vector" do
|
|
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
|
-
end
|
|
26
|
-
|
|
27
|
-
describe "#to_hash" do
|
|
28
|
-
it "returns a hash" do
|
|
29
|
-
expect(vector.to_hash).to eq(x: 2, y: 3)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe "#to_i_vector" do
|
|
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) }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
describe "#to_s" do
|
|
43
|
-
context "when fixnum" do
|
|
44
|
-
subject(:vector) { Vector2d.new(2, 3) }
|
|
45
|
-
|
|
46
|
-
it "renders a string" do
|
|
47
|
-
expect(vector.to_s).to eq("2x3")
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
context "when float" do
|
|
52
|
-
subject(:vector) { Vector2d.new(2.0, 3.0) }
|
|
53
|
-
|
|
54
|
-
it "renders a string" do
|
|
55
|
-
expect(vector.to_s).to eq("2.0x3.0")
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
describe Vector2d::Fitting do
|
|
6
|
-
let(:original) { Vector2d.new(300, 300) }
|
|
7
|
-
|
|
8
|
-
describe "#contain" do
|
|
9
|
-
subject(:vector) { original.contain(comp) }
|
|
10
|
-
|
|
11
|
-
context "when vector is smaller" do
|
|
12
|
-
let(:comp) { Vector2d.new(150, 100) }
|
|
13
|
-
|
|
14
|
-
its(:x) { is_expected.to eq(150) }
|
|
15
|
-
its(:y) { is_expected.to eq(100) }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
context "when vector is wider" do
|
|
19
|
-
let(:comp) { Vector2d.new(400, 300) }
|
|
20
|
-
|
|
21
|
-
its(:x) { is_expected.to eq(300) }
|
|
22
|
-
its(:y) { is_expected.to eq(225) }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
context "when vector is higher" do
|
|
26
|
-
let(:comp) { Vector2d.new(300, 400) }
|
|
27
|
-
|
|
28
|
-
its(:x) { is_expected.to eq(225) }
|
|
29
|
-
its(:y) { is_expected.to eq(300) }
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe "#fit" do
|
|
34
|
-
subject(:vector) { original.fit(comp) }
|
|
35
|
-
|
|
36
|
-
context "when scaling by height" do
|
|
37
|
-
let(:comp) { Vector2d.new(200, 150) }
|
|
38
|
-
|
|
39
|
-
its(:x) { is_expected.to eq(150) }
|
|
40
|
-
its(:y) { is_expected.to eq(150) }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context "when scaling by width" do
|
|
44
|
-
let(:comp) { Vector2d.new(150, 200) }
|
|
45
|
-
|
|
46
|
-
its(:x) { is_expected.to eq(150) }
|
|
47
|
-
its(:y) { is_expected.to eq(150) }
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
describe "#fit_either" do
|
|
52
|
-
subject(:vector) { original.fit_either(comp) }
|
|
53
|
-
|
|
54
|
-
let(:original) { Vector2d.new(300, 300) }
|
|
55
|
-
|
|
56
|
-
context "when width is largest" do
|
|
57
|
-
let(:comp) { Vector2d.new(200, 150) }
|
|
58
|
-
|
|
59
|
-
its(:x) { is_expected.to eq(200) }
|
|
60
|
-
its(:y) { is_expected.to eq(200) }
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
context "when height is largest" do
|
|
64
|
-
let(:comp) { Vector2d.new(150, 200) }
|
|
65
|
-
|
|
66
|
-
its(:x) { is_expected.to eq(200) }
|
|
67
|
-
its(:y) { is_expected.to eq(200) }
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
describe Vector2d::Properties do
|
|
6
|
-
subject(:vector) { Vector2d.new(2, 3) }
|
|
7
|
-
|
|
8
|
-
describe "#angle" do
|
|
9
|
-
it "returns the angle" do
|
|
10
|
-
expect(vector.angle).to be_within(0.0001).of(0.9827)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe "#aspect_ratio" do
|
|
15
|
-
it "returns the aspect_ratio" do
|
|
16
|
-
expect(vector.aspect_ratio).to be_within(0.0001).of(0.6667)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe "#length" do
|
|
21
|
-
it "calculates the length" do
|
|
22
|
-
expect(vector.length).to be_within(0.0001).of(3.6055)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
describe "#squared_length" do
|
|
27
|
-
it "calculates the squared length" do
|
|
28
|
-
expect(vector.squared_length).to eq(13)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
describe "#normalized?" do
|
|
33
|
-
subject { vector.normalized? }
|
|
34
|
-
|
|
35
|
-
context "when vector is normalized" do
|
|
36
|
-
let(:vector) { Vector2d.new(2, 3).normalize }
|
|
37
|
-
|
|
38
|
-
it { is_expected.to be(true) }
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
context "when vector isn't normalized" do
|
|
42
|
-
let(:vector) { Vector2d.new(2, 3) }
|
|
43
|
-
|
|
44
|
-
it { is_expected.to be(false) }
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
describe Vector2d::Transformations do
|
|
6
|
-
subject(:vector) { Vector2d.new(2, 3) }
|
|
7
|
-
|
|
8
|
-
describe "#ceil" do
|
|
9
|
-
subject(:vector) { Vector2d.new(2.3, 3.3) }
|
|
10
|
-
|
|
11
|
-
it "rounds the vector up" do
|
|
12
|
-
expect(vector.ceil).to eq(Vector2d.new(3, 4))
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
describe "#floor" do
|
|
17
|
-
subject(:vector) { Vector2d.new(2.7, 3.6) }
|
|
18
|
-
|
|
19
|
-
it "rounds the vector down" do
|
|
20
|
-
expect(vector.floor).to eq(Vector2d.new(2, 3))
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe "#normalize" do
|
|
25
|
-
subject { vector.normalize }
|
|
26
|
-
|
|
27
|
-
its(:x) { is_expected.to be_within(0.0001).of(0.5547) }
|
|
28
|
-
its(:y) { is_expected.to be_within(0.0001).of(0.8320) }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
describe "#perpendicular" do
|
|
32
|
-
it "returns a perpendicular vector" do
|
|
33
|
-
expect(vector.perpendicular).to eq(Vector2d.new(-3, 2))
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
describe "#resize" do
|
|
38
|
-
subject(:resized) { vector.resize(2.0) }
|
|
39
|
-
|
|
40
|
-
it "modifies the vector length" do
|
|
41
|
-
expect(resized.length).to be_within(0.0001).of(2.0)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it "modifies the x property" do
|
|
45
|
-
expect(resized.x).to be_within(0.0001).of(1.1094)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "modifies the y property" do
|
|
49
|
-
expect(resized.y).to be_within(0.0001).of(1.6641)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
describe "#reverse" do
|
|
54
|
-
it "reverses the vector" do
|
|
55
|
-
expect(vector.reverse).to eq(Vector2d.new(-2, -3))
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe "#rotate" do
|
|
60
|
-
subject { vector.rotate(rotation).round(3) }
|
|
61
|
-
|
|
62
|
-
let(:vector) { Vector2d.new(1, 0) }
|
|
63
|
-
|
|
64
|
-
context "when roating by PI" do
|
|
65
|
-
let(:rotation) { Math::PI }
|
|
66
|
-
|
|
67
|
-
it { is_expected.to eq(Vector2d.new(-1, 0)) }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
context "when roating by PI/2" do
|
|
71
|
-
let(:rotation) { Math::PI / 2 }
|
|
72
|
-
|
|
73
|
-
it { is_expected.to eq(Vector2d.new(0, 1)) }
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context "when roating by -PI/2" do
|
|
77
|
-
let(:rotation) { -Math::PI / 2 }
|
|
78
|
-
|
|
79
|
-
it { is_expected.to eq(Vector2d.new(0, -1)) }
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
context "when roating by PI/4" do
|
|
83
|
-
let(:rotation) { Math::PI / 4 }
|
|
84
|
-
|
|
85
|
-
it { is_expected.to eq(Vector2d.new(0.707, 0.707)) }
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
describe "#round" do
|
|
90
|
-
let(:vector) { Vector2d.new(2.3333, 3.666) }
|
|
91
|
-
|
|
92
|
-
context "without argument" do
|
|
93
|
-
subject { vector.round }
|
|
94
|
-
|
|
95
|
-
it { is_expected.to eq(Vector2d.new(2, 4)) }
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
context "with precision" do
|
|
99
|
-
subject { vector.round(2) }
|
|
100
|
-
|
|
101
|
-
it { is_expected.to eq(Vector2d.new(2.33, 3.67)) }
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe "#truncate" do
|
|
106
|
-
context "when argument is longer than length" do
|
|
107
|
-
let(:arg) { 5.0 }
|
|
108
|
-
|
|
109
|
-
it "does not change the length" do
|
|
110
|
-
expect(vector.truncate(arg).length).to be_within(0.0001).of(3.6055)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
context "when argument is shorter than length" do
|
|
115
|
-
let(:arg) { 2.5 }
|
|
116
|
-
|
|
117
|
-
it "changes the length" do
|
|
118
|
-
expect(vector.truncate(arg).length).to be_within(0.0001).of(arg)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|