geom_craft 0.0.1
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +20 -0
- data/Rakefile +4 -0
- data/geom_craft.gemspec +23 -0
- data/lib/geom_craft/core_ext/math.rb +13 -0
- data/lib/geom_craft/core_ext/numeric.rb +44 -0
- data/lib/geom_craft/core_ext.rb +7 -0
- data/lib/geom_craft/rand_norm.rb +55 -0
- data/lib/geom_craft/range2.rb +462 -0
- data/lib/geom_craft/rect.rb +723 -0
- data/lib/geom_craft/top_level_bind.rb +17 -0
- data/lib/geom_craft/vec2.rb +610 -0
- data/lib/geom_craft/version.rb +3 -0
- data/lib/geom_craft.rb +8 -0
- data/spec/geom_craft_spec.rb +4 -0
- data/spec/spec_helper.rb +6 -0
- data/workbench/core_ext.rb +21 -0
- data/workbench/range2.rb +217 -0
- data/workbench/rect.rb +271 -0
- data/workbench/setup.rb +8 -0
- data/workbench/vec2.rb +538 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2c55f5ca6a18a1d30f105f666b6aa1d51f97ef06f376af7b4aea7a9c4b2448ab
|
4
|
+
data.tar.gz: e07e3b8f910da37f28b60f69f4dac4b19259fc5738b1c04941c07a97aca5d789
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be621512a1a79272ea25a9ad4ca1208e51ffbea198f0fdbc285669aa2abc56b3422682fb9e3052cd163309620626189f36cca19990853837e1cf2cc9fe1e840b
|
7
|
+
data.tar.gz: 9597e85fc040319961b90217a8ed18024190efba7f99020e26ff7bbf55b9e64990556f6cf207a7bdd83282db8c5de5e59c83918a97ccc749fb99ec0f0f9e58a2
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2025 akicho8
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# GeomCraft
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
This is a Ruby library inspired by the Rect and 2D vector libraries used in the Rust Nannou framework.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install as a standalone gem
|
10
|
+
|
11
|
+
```shell
|
12
|
+
$ gem install geom_craft
|
13
|
+
```
|
14
|
+
|
15
|
+
Or install within application using Gemfile
|
16
|
+
|
17
|
+
```shell
|
18
|
+
$ bundle add geom_craft
|
19
|
+
$ bundle install
|
20
|
+
```
|
data/Rakefile
ADDED
data/geom_craft.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "geom_craft/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "geom_craft"
|
7
|
+
spec.version = GeomCraft::VERSION
|
8
|
+
spec.authors = ["akicho8"]
|
9
|
+
spec.email = ["akicho8@gmail.com"]
|
10
|
+
spec.description = %q{This is a Ruby library inspired by the Rect and 2D vector libraries used in the Rust Nannou framework}
|
11
|
+
spec.summary = %q{This is a Ruby library inspired by the Rect and 2D vector libraries used in the Rust Nannou framework}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
spec.add_development_dependency "rspec"
|
22
|
+
spec.add_development_dependency "test-unit"
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module GeomCraft
|
2
|
+
module MathExt
|
3
|
+
# https://github.com/godotengine/godot/blob/44e399ed5fa895f760b2995e59788bdb49782666/core/math/math_funcs.cpp#L120
|
4
|
+
def snapped(value, step)
|
5
|
+
if step.nonzero?
|
6
|
+
value = (value / step + 0.5).floor * step
|
7
|
+
end
|
8
|
+
value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Math.extend(GeomCraft::MathExt)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module GeomCraft
|
2
|
+
module AngleConvert
|
3
|
+
TAU = 2 * Math::PI
|
4
|
+
ONE_TURN_DEGREES = 360.0
|
5
|
+
|
6
|
+
def rad_to_deg
|
7
|
+
self * ONE_TURN_DEGREES / TAU
|
8
|
+
end
|
9
|
+
|
10
|
+
def rad_to_turn
|
11
|
+
self / TAU
|
12
|
+
end
|
13
|
+
|
14
|
+
def rad_to_rad
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def deg_to_rad
|
19
|
+
self * TAU / ONE_TURN_DEGREES
|
20
|
+
end
|
21
|
+
|
22
|
+
def deg_to_turn
|
23
|
+
self / ONE_TURN_DEGREES
|
24
|
+
end
|
25
|
+
|
26
|
+
def deg_to_deg
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def turn_to_deg
|
31
|
+
self * ONE_TURN_DEGREES
|
32
|
+
end
|
33
|
+
|
34
|
+
def turn_to_rad
|
35
|
+
self * TAU
|
36
|
+
end
|
37
|
+
|
38
|
+
def turn_to_turn
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Numeric.include(GeomCraft::AngleConvert)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module GeomCraft
|
2
|
+
# 普通は rand の実行回数が少ないこっちを使う
|
3
|
+
# 平均(mean) で 標準偏差が 1.0 (7割が±1.0の範囲にあるという意味)
|
4
|
+
class RandNorm
|
5
|
+
class << self
|
6
|
+
def call(...)
|
7
|
+
@instance ||= new(...)
|
8
|
+
@instance.call(...)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(mu: 0.0, sigma: 1.0, random: Random.new)
|
13
|
+
@mu = mu
|
14
|
+
@sigma = sigma
|
15
|
+
@random = random
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(mu: @mu, sigma: @sigma, random: @random)
|
19
|
+
if @next_value
|
20
|
+
v = @next_value
|
21
|
+
@next_value = nil
|
22
|
+
else
|
23
|
+
r1 = random.rand
|
24
|
+
r2 = random.rand
|
25
|
+
a = Math.sqrt(-2 * Math.log(r1))
|
26
|
+
b = 2 * Math::PI * r2
|
27
|
+
x = a * Math.cos(b) # ここで1つ取れる
|
28
|
+
y = a * Math.sin(b) # まとめて2つ目も取れる
|
29
|
+
@next_value = y # 次に返すように取っておく
|
30
|
+
v = x
|
31
|
+
end
|
32
|
+
mu + sigma * v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if $0 == __FILE__
|
38
|
+
@rand_norm = GeomCraft::RandNorm.new
|
39
|
+
def rnorm(...)
|
40
|
+
@rand_norm.call(...)
|
41
|
+
end
|
42
|
+
|
43
|
+
n = 1000000
|
44
|
+
list = n.times.collect { rnorm(mu: 70, sigma: 10) }
|
45
|
+
|
46
|
+
# 配列から標準偏差の取得
|
47
|
+
avg = list.sum.fdiv(n)
|
48
|
+
sd = Math.sqrt(list.collect { |v| (v - avg)**2 }.sum.fdiv(n))
|
49
|
+
sd # => 9.996427943190731
|
50
|
+
|
51
|
+
# 1,2,3倍はそれぞれ 68.26% 95.44% 99.74% になるか?
|
52
|
+
list.count { |v| (-(sd*1)..(sd*1)).include?(v - avg) }.fdiv(n) # => 0.682338
|
53
|
+
list.count { |v| (-(sd*2)..(sd*2)).include?(v - avg) }.fdiv(n) # => 0.954698
|
54
|
+
list.count { |v| (-(sd*3)..(sd*3)).include?(v - avg) }.fdiv(n) # => 0.997286
|
55
|
+
end
|
@@ -0,0 +1,462 @@
|
|
1
|
+
# https://zenn.dev/megeton/articles/0ace7ce5d23f48
|
2
|
+
# https://docs.rs/nannou/0.18.1/nannou/geom/range/struct.Range.html
|
3
|
+
|
4
|
+
module GeomCraft
|
5
|
+
class Range2
|
6
|
+
class << self
|
7
|
+
def [](...)
|
8
|
+
new(...)
|
9
|
+
end
|
10
|
+
|
11
|
+
def one; 1.0; end
|
12
|
+
def zero; 0.0; end
|
13
|
+
|
14
|
+
def from_pos_and_len(pos, len)
|
15
|
+
half_len = len / 2.0
|
16
|
+
start = pos - half_len
|
17
|
+
_end = pos + half_len
|
18
|
+
new(start, _end)
|
19
|
+
end
|
20
|
+
|
21
|
+
def map_range(val, in_min, in_max, out_min, out_max)
|
22
|
+
(val.to_f - in_min) / (in_max - in_min) * (out_max - out_min) + out_min
|
23
|
+
end
|
24
|
+
|
25
|
+
def clamp(value, start, _end)
|
26
|
+
if start <= _end
|
27
|
+
if value < start
|
28
|
+
start
|
29
|
+
elsif value > _end
|
30
|
+
_end
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
else
|
35
|
+
if value < _end
|
36
|
+
_end
|
37
|
+
elsif value > start
|
38
|
+
start
|
39
|
+
else
|
40
|
+
value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_accessor :start
|
47
|
+
attr_accessor :end
|
48
|
+
|
49
|
+
def initialize(start, _end)
|
50
|
+
@start = start
|
51
|
+
@end = _end
|
52
|
+
end
|
53
|
+
|
54
|
+
def magnitude
|
55
|
+
@end - @start
|
56
|
+
end
|
57
|
+
|
58
|
+
def length
|
59
|
+
mag = magnitude
|
60
|
+
if mag < self.class.zero
|
61
|
+
-mag
|
62
|
+
else
|
63
|
+
mag
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def middle
|
68
|
+
(@end + @start).fdiv(2)
|
69
|
+
end
|
70
|
+
|
71
|
+
def invert
|
72
|
+
self.class.new(@end, @start)
|
73
|
+
end
|
74
|
+
|
75
|
+
def map_value(value, other)
|
76
|
+
self.class.map_range(value, @start, @end, other.start, other.end)
|
77
|
+
end
|
78
|
+
|
79
|
+
def lerp(amount)
|
80
|
+
@start + (@end - @start) * amount
|
81
|
+
end
|
82
|
+
|
83
|
+
def shift(amount)
|
84
|
+
self.class.new(@start + amount, @end + amount)
|
85
|
+
end
|
86
|
+
|
87
|
+
def direction
|
88
|
+
if @start < @end
|
89
|
+
self.class.one
|
90
|
+
elsif @start > @end
|
91
|
+
-self.class.one
|
92
|
+
else
|
93
|
+
self.class.zero
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def absolute
|
98
|
+
if @start > @end
|
99
|
+
invert
|
100
|
+
else
|
101
|
+
self
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def max(other)
|
106
|
+
start = [@start, @end, other.start, other.end].min
|
107
|
+
_end = [@start, @end, other.start, other.end].max
|
108
|
+
self.class.new(start, _end)
|
109
|
+
end
|
110
|
+
|
111
|
+
def overlap(other)
|
112
|
+
a = absolute
|
113
|
+
other = other.absolute
|
114
|
+
start = [a.start, other.start].max
|
115
|
+
_end = [a.end, other.end].min
|
116
|
+
magnitude = _end - start
|
117
|
+
if magnitude >= self.class.zero
|
118
|
+
self.class.new(start, _end)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def max_directed(other)
|
123
|
+
if @start <= @end
|
124
|
+
max(other)
|
125
|
+
else
|
126
|
+
max(other).invert
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def contains?(pos)
|
131
|
+
a = absolute
|
132
|
+
a.start <= pos && pos <= a.end
|
133
|
+
end
|
134
|
+
|
135
|
+
def round(...); self.class.new(@start.round(...), @end.round(...)); end
|
136
|
+
def floor(...); self.class.new(@start.floor(...), @end.floor(...)); end
|
137
|
+
def ceil(...); self.class.new(@start.ceil(...), @end.ceil(...)); end
|
138
|
+
def truncate(...); self.class.new(@start.truncate(...), @end.truncate(...)); end
|
139
|
+
|
140
|
+
def pad_start(pad); self.class.new(@start + (@start <= @end ? pad : -pad), @end); end
|
141
|
+
def pad_end(pad); self.class.new(@start, @end + (@start <= @end ? -pad : pad)); end
|
142
|
+
def pad(pad); pad_start(pad).pad_end(pad); end
|
143
|
+
def pad_ends(start, _end); pad_start(start).pad_end(_end); end
|
144
|
+
|
145
|
+
def clamp_value(value)
|
146
|
+
self.class.clamp(value, @start, @end)
|
147
|
+
end
|
148
|
+
|
149
|
+
def stretch_to_value(value)
|
150
|
+
if @start <= @end
|
151
|
+
if value < @start
|
152
|
+
self.class.new(value, @end)
|
153
|
+
elsif value > @end
|
154
|
+
self.class.new(@start, value)
|
155
|
+
else
|
156
|
+
self
|
157
|
+
end
|
158
|
+
else
|
159
|
+
if value < @end
|
160
|
+
self.class.new(@start, value)
|
161
|
+
elsif value > @start
|
162
|
+
self.class.new(value, @end)
|
163
|
+
else
|
164
|
+
self
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def same_direction?(other)
|
170
|
+
self_direction = @start <= @end
|
171
|
+
other_direction = other.start <= other.end
|
172
|
+
self_direction == other_direction
|
173
|
+
end
|
174
|
+
|
175
|
+
def align_start_of(other)
|
176
|
+
if same_direction?(other)
|
177
|
+
diff = other.start - @start
|
178
|
+
else
|
179
|
+
diff = other.start - @end
|
180
|
+
end
|
181
|
+
shift(diff)
|
182
|
+
end
|
183
|
+
|
184
|
+
def align_end_of(other)
|
185
|
+
if same_direction?(other)
|
186
|
+
diff = other.end - @end
|
187
|
+
else
|
188
|
+
diff = other.end - @start
|
189
|
+
end
|
190
|
+
shift(diff)
|
191
|
+
end
|
192
|
+
|
193
|
+
def align_middle_of(other)
|
194
|
+
diff = other.middle - middle
|
195
|
+
shift(diff)
|
196
|
+
end
|
197
|
+
|
198
|
+
def align_after(other)
|
199
|
+
if same_direction?(other)
|
200
|
+
diff = other.end - @start
|
201
|
+
else
|
202
|
+
diff = other.end - @end
|
203
|
+
end
|
204
|
+
shift(diff)
|
205
|
+
end
|
206
|
+
|
207
|
+
def align_before(other)
|
208
|
+
if self.same_direction?(other)
|
209
|
+
diff = other.start - @end
|
210
|
+
else
|
211
|
+
diff = other.start - @start
|
212
|
+
end
|
213
|
+
shift(diff)
|
214
|
+
end
|
215
|
+
|
216
|
+
def align_to(align, other)
|
217
|
+
public_send("align_#{align}_of", other)
|
218
|
+
end
|
219
|
+
|
220
|
+
def closest_edge(scalar)
|
221
|
+
if scalar < @start
|
222
|
+
start_diff = @start - scalar
|
223
|
+
else
|
224
|
+
start_diff = scalar - @start
|
225
|
+
end
|
226
|
+
if scalar < @end
|
227
|
+
end_diff = @end - scalar
|
228
|
+
else
|
229
|
+
end_diff = scalar - @end
|
230
|
+
end
|
231
|
+
if start_diff <= end_diff
|
232
|
+
:start
|
233
|
+
else
|
234
|
+
:end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
################################################################################
|
239
|
+
|
240
|
+
def to_a
|
241
|
+
[@start, @end]
|
242
|
+
end
|
243
|
+
|
244
|
+
def ==(other)
|
245
|
+
self.class == other.class && @start == other.start && @end == other.end
|
246
|
+
end
|
247
|
+
|
248
|
+
def eql?(other)
|
249
|
+
self.class == other.class && @start == other.start && @end == other.end
|
250
|
+
end
|
251
|
+
|
252
|
+
def hash
|
253
|
+
self.class.hash ^ @start.hash ^ @end.hash
|
254
|
+
end
|
255
|
+
|
256
|
+
def <=>(other)
|
257
|
+
[self.class, @start, @end] <=> [other.class, other.start, other.end]
|
258
|
+
end
|
259
|
+
|
260
|
+
def inspect
|
261
|
+
"(#{@start} -> #{@end})"
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_s
|
265
|
+
"(#{@start} -> #{@end})"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
if $0 == __FILE__
|
271
|
+
Range2 = GeomCraft::Range2
|
272
|
+
|
273
|
+
require "rspec/autorun"
|
274
|
+
|
275
|
+
RSpec.configure do |config|
|
276
|
+
config.expect_with :test_unit
|
277
|
+
end
|
278
|
+
|
279
|
+
describe Range2 do
|
280
|
+
it "new" do
|
281
|
+
assert { Range2.new(1, 2) == Range2.new(1, 2) }
|
282
|
+
end
|
283
|
+
|
284
|
+
it "pos を中心に半径 len / 2 の幅とする (重要)" do
|
285
|
+
assert { Range2::from_pos_and_len(100.0, 10.0) == Range2.new(95.0, 105.0) }
|
286
|
+
end
|
287
|
+
|
288
|
+
it "それぞれの値" do
|
289
|
+
assert { Range2.new(100.0, 200.0).start == 100.0 }
|
290
|
+
assert { Range2.new(100.0, 200.0).middle == 150.0 }
|
291
|
+
assert { Range2.new(100.0, 200.0).end == 200.0 }
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "ベクトルの強さと長さ" do
|
295
|
+
it "強さ (end - start)" do
|
296
|
+
assert { Range2.new(100, -200).magnitude == -300 }
|
297
|
+
end
|
298
|
+
|
299
|
+
it "長さ (強さの絶対値)" do
|
300
|
+
assert { Range2.new(100, -200).length == 300 }
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
it "小数の補正" do
|
305
|
+
assert { Range2.new(0.4, 0.5).round == Range2.new(0, 1) }
|
306
|
+
assert { Range2.new(0.4, 0.5).floor == Range2.new(0, 0) }
|
307
|
+
assert { Range2.new(0.4, 0.5).ceil == Range2.new(1, 1) }
|
308
|
+
assert { Range2.new(0.4, 0.5).truncate == Range2.new(0, 0) }
|
309
|
+
end
|
310
|
+
|
311
|
+
describe "範囲" do
|
312
|
+
it "OR (向きを破壊する)" do
|
313
|
+
a = Range2.new(5.0, 3.0)
|
314
|
+
b = Range2.new(4.0, 6.0)
|
315
|
+
assert { a.max(b) == Range2.new(3.0, 6.0) }
|
316
|
+
end
|
317
|
+
|
318
|
+
it "OR (向きを維持する)" do
|
319
|
+
a = Range2.new(5.0, 3.0)
|
320
|
+
b = Range2.new(4.0, 6.0)
|
321
|
+
assert { a.max_directed(b) == Range2.new(6.0, 3.0) }
|
322
|
+
end
|
323
|
+
|
324
|
+
it "AND (向きを破壊する)" do
|
325
|
+
a = Range2.new(5.0, 3.0)
|
326
|
+
b = Range2.new(4.0, 6.0)
|
327
|
+
assert { a.overlap(b) == Range2.new(4.0, 5.0) }
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe "向き" do
|
332
|
+
it "現在の向きを返す" do
|
333
|
+
assert { Range2.new(0, 10).direction == 1.0 }
|
334
|
+
assert { Range2.new(10, 0).direction == -1.0 }
|
335
|
+
assert { Range2.new(10, 10).direction == -0.0 }
|
336
|
+
end
|
337
|
+
|
338
|
+
it "向きが同じか?" do
|
339
|
+
a = Range2.new(1, 2)
|
340
|
+
b = Range2.new(3, 4)
|
341
|
+
assert { a.same_direction?(b) == true }
|
342
|
+
end
|
343
|
+
|
344
|
+
it "向きを反転する" do
|
345
|
+
assert { Range2.new(0, 100).invert == Range2.new(100, 0) }
|
346
|
+
end
|
347
|
+
|
348
|
+
it "正の向きにする" do
|
349
|
+
assert { Range2.new(10, 0).absolute == Range2.new(0, 10) }
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe "スケーリング" do
|
354
|
+
it "map_value" do
|
355
|
+
a = Range2.new(0.0, 1.0)
|
356
|
+
b = Range2.new(0.0, 100.0)
|
357
|
+
assert { a.map_value(0.9, b) == 90.0 }
|
358
|
+
end
|
359
|
+
|
360
|
+
it "元の範囲が 0..1 の場合 lerp 使うと簡潔に書ける" do
|
361
|
+
b = Range2.new(0.0, 100.0)
|
362
|
+
assert { b.lerp(0.9) == 90.0 }
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe "指定の軸で整列する" do
|
367
|
+
it "相手の左端に揃える" do
|
368
|
+
a = Range2.new(0, 100)
|
369
|
+
b = Range2.new(50, 100)
|
370
|
+
assert { a.align_start_of(b) == Range2.new(50, 150) }
|
371
|
+
end
|
372
|
+
|
373
|
+
it "相手の右端に揃える" do
|
374
|
+
a = Range2.new(0, 50)
|
375
|
+
b = Range2.new(0, 100)
|
376
|
+
assert { a.align_end_of(b) == Range2.new(50, 100) }
|
377
|
+
end
|
378
|
+
|
379
|
+
it "相手の中央に揃える" do
|
380
|
+
a = Range2.new(0.0, 50.0)
|
381
|
+
b = Range2.new(0.0, 100.0)
|
382
|
+
assert { a.align_middle_of(b) == Range2.new(25.0, 75.0) }
|
383
|
+
end
|
384
|
+
|
385
|
+
it "相手のどこかに揃える" do
|
386
|
+
a = Range2.new(0.0, 5.0)
|
387
|
+
b = Range2.new(10.0, 20.0)
|
388
|
+
assert { a.align_to(:start, b) == Range2.new(10.0, 15.0) }
|
389
|
+
assert { a.align_to(:end, b) == Range2.new(15.0, 20.0) }
|
390
|
+
assert { a.align_to(:middle, b) == Range2.new(12.5, 17.5) }
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe "横に並べる" do
|
395
|
+
it "相手の左隣り並べる" do
|
396
|
+
a = Range2.new(0.0, 5.0)
|
397
|
+
b = Range2.new(0.0, 10.0)
|
398
|
+
assert { a.align_after(b) == Range2.new(10.0, 15.0) }
|
399
|
+
end
|
400
|
+
|
401
|
+
it "相手の右隣り並べる" do
|
402
|
+
a = Range2.new(0.0, 5.0)
|
403
|
+
b = Range2.new(0.0, 0.0)
|
404
|
+
assert { a.align_before(b) == Range2.new(-5.0, 0.0) }
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe "Edge を寄せる (サイズが変わる)" do
|
409
|
+
it "左端を内側に寄せる" do
|
410
|
+
assert { Range2.new(10, 0).pad_start(3) == Range2.new(7, 0) }
|
411
|
+
end
|
412
|
+
|
413
|
+
it "右端を内側に寄せる" do
|
414
|
+
assert { Range2.new(10, 0).pad_end(3) == Range2.new(10, 3) }
|
415
|
+
end
|
416
|
+
|
417
|
+
it "両端を内側に寄せる" do
|
418
|
+
assert { Range2.new(10, 0).pad(3) == Range2.new(7, 3) }
|
419
|
+
end
|
420
|
+
|
421
|
+
it "両端を内側に寄せる (個別指定)" do
|
422
|
+
assert { Range2.new(10, 0).pad_ends(3, 4) == Range2.new(7, 4) }
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
it "この範囲に含むか?" do
|
427
|
+
assert { Range2.new(1, 2).contains?(2) == true }
|
428
|
+
end
|
429
|
+
|
430
|
+
it "対象を補正する" do
|
431
|
+
assert { Range2.new(10, 0).clamp_value(-1) == 0 }
|
432
|
+
assert { Range2.new(10, 0).clamp_value(11) == 10 }
|
433
|
+
end
|
434
|
+
|
435
|
+
it "ずらす (サイズ不変)" do
|
436
|
+
assert { Range2.new(2, 3).shift(10) == Range2.new(12, 13) }
|
437
|
+
end
|
438
|
+
|
439
|
+
it "近い方の端を引き伸ばす" do
|
440
|
+
assert { Range2.new(10, 20).stretch_to_value(5) == Range2.new(5, 20) }
|
441
|
+
assert { Range2.new(10, 20).stretch_to_value(25) == Range2.new(10, 25) }
|
442
|
+
end
|
443
|
+
|
444
|
+
it "範囲内を指定した場合は何も変化しない" do
|
445
|
+
assert { Range2.new(10, 20).stretch_to_value(15) == Range2.new(10, 20) }
|
446
|
+
end
|
447
|
+
|
448
|
+
it "値に近い方の Edge を返す" do
|
449
|
+
assert { Range2.new(0.0, 10.0).closest_edge(4.0) == :start }
|
450
|
+
assert { Range2.new(0.0, 10.0).closest_edge(6.0) == :end }
|
451
|
+
end
|
452
|
+
|
453
|
+
it "==" do
|
454
|
+
assert { Range2.new(1, 2) == Range2.new(1, 2) }
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
# >> ................................
|
459
|
+
# >>
|
460
|
+
# >> Finished in 0.02209 seconds (files took 0.08981 seconds to load)
|
461
|
+
# >> 32 examples, 0 failures
|
462
|
+
# >>
|