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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +39 -0
  3. data/.github/workflows/build.yml +48 -10
  4. data/.gitignore +3 -1
  5. data/.release-please-manifest.json +3 -0
  6. data/.rubocop.yml +5 -2
  7. data/.tool-versions +1 -0
  8. data/.yardopts +11 -0
  9. data/CHANGELOG.md +224 -0
  10. data/CODE_OF_CONDUCT.md +92 -0
  11. data/CONTRIBUTING.md +30 -0
  12. data/Gemfile +6 -2
  13. data/Gemfile.lock +85 -51
  14. data/README.md +330 -13
  15. data/Rakefile +21 -0
  16. data/benchmark/vector_comparison.rb +129 -0
  17. data/lib/vector2d/angles.rb +315 -0
  18. data/lib/vector2d/arithmetic.rb +97 -0
  19. data/lib/vector2d/comparison.rb +188 -0
  20. data/lib/vector2d/componentwise.rb +239 -0
  21. data/lib/vector2d/constructors.rb +137 -0
  22. data/lib/vector2d/conversions.rb +139 -0
  23. data/lib/vector2d/coordinates.rb +22 -0
  24. data/lib/vector2d/deprecation.rb +16 -0
  25. data/lib/vector2d/dimensions.rb +297 -0
  26. data/lib/vector2d/interpolation.rb +191 -0
  27. data/lib/vector2d/lengths.rb +284 -0
  28. data/lib/vector2d/matrix_interop.rb +93 -0
  29. data/lib/vector2d/parsing.rb +142 -0
  30. data/lib/vector2d/projection.rb +208 -0
  31. data/lib/vector2d/version.rb +2 -1
  32. data/lib/vector2d.rb +174 -62
  33. data/release-please-config.json +10 -0
  34. data/spec/lib/vector2d/angles_spec.rb +441 -0
  35. data/spec/lib/vector2d/{calculations_spec.rb → arithmetic_spec.rb} +48 -58
  36. data/spec/lib/vector2d/comparison_spec.rb +358 -0
  37. data/spec/lib/vector2d/componentwise_spec.rb +300 -0
  38. data/spec/lib/vector2d/constructors_spec.rb +299 -0
  39. data/spec/lib/vector2d/conversions_spec.rb +234 -0
  40. data/spec/lib/vector2d/dimensions_spec.rb +820 -0
  41. data/spec/lib/vector2d/interpolation_spec.rb +322 -0
  42. data/spec/lib/vector2d/lengths_spec.rb +457 -0
  43. data/spec/lib/vector2d/matrix_interop_spec.rb +92 -0
  44. data/spec/lib/vector2d/parsing_spec.rb +329 -0
  45. data/spec/lib/vector2d/projection_spec.rb +306 -0
  46. data/spec/lib/vector2d_documentation_spec.rb +38 -0
  47. data/spec/lib/vector2d_immutability_spec.rb +263 -0
  48. data/spec/lib/vector2d_spec.rb +90 -50
  49. data/spec/lib/vector2d_subclassing_spec.rb +210 -0
  50. data/spec/lib/vector2d_tags_spec.rb +43 -0
  51. data/spec/spec_helper.rb +2 -0
  52. data/spec/support/doc_examples/comments.rb +65 -0
  53. data/spec/support/doc_examples/markdown.rb +50 -0
  54. data/spec/support/doc_examples.rb +94 -0
  55. data/spec/support/doc_tags.rb +151 -0
  56. data/spec/support/shared_examples/class_preserving_method.rb +10 -0
  57. data/spec/support/shared_examples/deprecated_method.rb +25 -0
  58. data/spec/support/shared_examples/parsed_vector.rb +11 -0
  59. data/vector2d.gemspec +9 -3
  60. metadata +55 -19
  61. data/.travis.yml +0 -10
  62. data/lib/vector2d/calculations.rb +0 -141
  63. data/lib/vector2d/coercions.rb +0 -64
  64. data/lib/vector2d/fitting.rb +0 -60
  65. data/lib/vector2d/properties.rb +0 -46
  66. data/lib/vector2d/transformations.rb +0 -85
  67. data/spec/lib/vector2d/coercions_spec.rb +0 -59
  68. data/spec/lib/vector2d/fitting_spec.rb +0 -70
  69. data/spec/lib/vector2d/properties_spec.rb +0 -47
  70. 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
@@ -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
@@ -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
@@ -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