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
@@ -0,0 +1,723 @@
|
|
1
|
+
# https://zenn.dev/megeton/articles/fc94eb1fece2c5
|
2
|
+
# https://docs.rs/nannou/0.18.1/nannou/geom/rect/struct.Rect.html
|
3
|
+
|
4
|
+
if $0 == __FILE__
|
5
|
+
$LOAD_PATH.unshift("..")
|
6
|
+
end
|
7
|
+
|
8
|
+
require "geom_craft/vec2"
|
9
|
+
require "geom_craft/range2"
|
10
|
+
|
11
|
+
module GeomCraft
|
12
|
+
class Rect
|
13
|
+
class << self
|
14
|
+
# 指定された x y 座標と w h 次元から Rect を構築する
|
15
|
+
def from_x_y_w_h(x, y, w, h)
|
16
|
+
new(Range2.from_pos_and_len(x, w), Range2.from_pos_and_len(y, h))
|
17
|
+
end
|
18
|
+
|
19
|
+
# 指定された Point と Dimensions から Rect を構築する
|
20
|
+
def from_xy_wh(p, s)
|
21
|
+
from_x_y_w_h(p.x, p.y, s.x, s.y)
|
22
|
+
end
|
23
|
+
|
24
|
+
# 指定された寸法で原点に Rect を構築する
|
25
|
+
def from_wh(s)
|
26
|
+
from_w_h(s.x, s.y)
|
27
|
+
end
|
28
|
+
|
29
|
+
# 指定された幅と高さで原点に Rect を構築する
|
30
|
+
def from_w_h(w, h)
|
31
|
+
from_x_y_w_h(0.0, 0.0, w, h)
|
32
|
+
end
|
33
|
+
|
34
|
+
# 2点の座標から Rect を構築する
|
35
|
+
def from_corners(a, b)
|
36
|
+
if a.x < b.x
|
37
|
+
left, right = a.x, b.x
|
38
|
+
else
|
39
|
+
left, right = b.x, a.x
|
40
|
+
end
|
41
|
+
if a.y < b.y
|
42
|
+
bottom, top = a.y, b.y
|
43
|
+
else
|
44
|
+
bottom, top = b.y, a.y
|
45
|
+
end
|
46
|
+
new(Range2.new(left, right), Range2.new(bottom, top))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :x
|
51
|
+
attr_accessor :y
|
52
|
+
|
53
|
+
def initialize(x, y)
|
54
|
+
@x = x
|
55
|
+
@y = y
|
56
|
+
end
|
57
|
+
|
58
|
+
# x の中央
|
59
|
+
def x_middle
|
60
|
+
@x.middle
|
61
|
+
end
|
62
|
+
|
63
|
+
# y の中央
|
64
|
+
def y_middle
|
65
|
+
@y.middle
|
66
|
+
end
|
67
|
+
|
68
|
+
# 中心
|
69
|
+
def x_y
|
70
|
+
[x_middle, y_middle]
|
71
|
+
end
|
72
|
+
|
73
|
+
# 幅
|
74
|
+
def w
|
75
|
+
@x.length
|
76
|
+
end
|
77
|
+
|
78
|
+
# 高さ
|
79
|
+
def h
|
80
|
+
@y.length
|
81
|
+
end
|
82
|
+
|
83
|
+
# 寸法
|
84
|
+
def w_h
|
85
|
+
[w, h]
|
86
|
+
end
|
87
|
+
|
88
|
+
# 中心と寸法
|
89
|
+
def x_y_w_h
|
90
|
+
[x_middle, y_middle, w, h]
|
91
|
+
end
|
92
|
+
|
93
|
+
# 左上と寸法
|
94
|
+
def l_t_w_h
|
95
|
+
[left, top, w, h]
|
96
|
+
end
|
97
|
+
|
98
|
+
# 左下と寸法
|
99
|
+
def l_b_w_h
|
100
|
+
[left, bottom, w, h]
|
101
|
+
end
|
102
|
+
|
103
|
+
# 長方形の最長辺の長さ
|
104
|
+
def length
|
105
|
+
[w, h].max
|
106
|
+
end
|
107
|
+
|
108
|
+
# Rect の最小の y 値
|
109
|
+
def bottom
|
110
|
+
@y.absolute.start
|
111
|
+
end
|
112
|
+
|
113
|
+
# Rect の最大の y 値
|
114
|
+
def top
|
115
|
+
@y.absolute.end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Rect の最小の x 値
|
119
|
+
def left
|
120
|
+
@x.absolute.start
|
121
|
+
end
|
122
|
+
|
123
|
+
# Rect の最大の x 値
|
124
|
+
def right
|
125
|
+
@x.absolute.end
|
126
|
+
end
|
127
|
+
|
128
|
+
# 辺 (左右下上)
|
129
|
+
def l_r_b_t
|
130
|
+
[left, right, bottom, top]
|
131
|
+
end
|
132
|
+
|
133
|
+
# 境界の中央の xy 位置
|
134
|
+
def xy
|
135
|
+
V[x_middle, y_middle]
|
136
|
+
end
|
137
|
+
|
138
|
+
# Rect の合計寸法
|
139
|
+
def wh
|
140
|
+
V[w, h]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Rect を Point と Dimensions に変換する
|
144
|
+
def xy_wh
|
145
|
+
[xy, wh]
|
146
|
+
end
|
147
|
+
|
148
|
+
# 左上隅位置
|
149
|
+
def top_left
|
150
|
+
V[left, top]
|
151
|
+
end
|
152
|
+
|
153
|
+
# 左下隅位置
|
154
|
+
def bottom_left
|
155
|
+
V[left, bottom]
|
156
|
+
end
|
157
|
+
|
158
|
+
# 右上隅位置
|
159
|
+
def top_right
|
160
|
+
V[right, top]
|
161
|
+
end
|
162
|
+
|
163
|
+
# 右下隅位置
|
164
|
+
def bottom_right
|
165
|
+
V[right, bottom]
|
166
|
+
end
|
167
|
+
|
168
|
+
# 左端の真ん中
|
169
|
+
def mid_left
|
170
|
+
V[left, y_middle]
|
171
|
+
end
|
172
|
+
|
173
|
+
# 上端の真ん中
|
174
|
+
def mid_top
|
175
|
+
V[x_middle, top]
|
176
|
+
end
|
177
|
+
|
178
|
+
# 右端の真ん中
|
179
|
+
def mid_right
|
180
|
+
V[right, y_middle]
|
181
|
+
end
|
182
|
+
|
183
|
+
# 下端の真ん中
|
184
|
+
def mid_bottom
|
185
|
+
V[x_middle, bottom]
|
186
|
+
end
|
187
|
+
|
188
|
+
################################################################################
|
189
|
+
|
190
|
+
# 指定された Align バリアントに従って、x 軸に沿って self を other に位置を合わせる
|
191
|
+
def align_x_of(align, other)
|
192
|
+
self.class.new(@x.align_to(align, other.x), @y)
|
193
|
+
end
|
194
|
+
|
195
|
+
# 指定された Align バリアントに従って、y 軸に沿って self を other に位置を合わせる
|
196
|
+
def align_y_of(align, other)
|
197
|
+
self.class.new(@x, @y.align_to(align, other.y))
|
198
|
+
end
|
199
|
+
|
200
|
+
# x 軸に沿って、自分の中心を相手の Rect の中心に揃える
|
201
|
+
def align_middle_x_of(other)
|
202
|
+
self.class.new(@x.align_middle_of(other.x), @y)
|
203
|
+
end
|
204
|
+
|
205
|
+
# y 軸に沿って、self の中央を other Rect の中央に揃える
|
206
|
+
def align_middle_y_of(other)
|
207
|
+
self.class.new(@x, @y.align_middle_of(other.y))
|
208
|
+
end
|
209
|
+
|
210
|
+
# 自分を相手の Rect の上端の中央に配置する
|
211
|
+
def mid_top_of(other)
|
212
|
+
align_middle_x_of(other).align_top_of(other)
|
213
|
+
end
|
214
|
+
|
215
|
+
# 自分を相手の Rect の下端の中央に配置する
|
216
|
+
def mid_bottom_of(other)
|
217
|
+
align_middle_x_of(other).align_bottom_of(other)
|
218
|
+
end
|
219
|
+
|
220
|
+
# 自分を相手の Rect の左端の中央に配置する
|
221
|
+
def mid_left_of(other)
|
222
|
+
align_left_of(other).align_middle_y_of(other)
|
223
|
+
end
|
224
|
+
|
225
|
+
# 自分を相手の Rect の右端の中央に配置する
|
226
|
+
def mid_right_of(other)
|
227
|
+
align_right_of(other).align_middle_y_of(other)
|
228
|
+
end
|
229
|
+
|
230
|
+
# 自分を相手の Rect の中央に直接配置する
|
231
|
+
def middle_of(other)
|
232
|
+
align_middle_x_of(other).align_middle_y_of(other)
|
233
|
+
end
|
234
|
+
|
235
|
+
def subdivision_ranges
|
236
|
+
x_a = Range2.new(@x.start, x_middle)
|
237
|
+
x_b = Range2.new(x_middle, @x.end)
|
238
|
+
y_a = Range2.new(@y.start, y_middle)
|
239
|
+
y_b = Range2.new(y_middle, @y.end)
|
240
|
+
SubdivisionRanges.new(x_a, x_b, y_a, y_b)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Rect を x 軸と y 軸に沿って半分に分割し、4 つの細分割を返す
|
244
|
+
#
|
245
|
+
# サブディビジョンは次の順序で生成されます
|
246
|
+
#
|
247
|
+
# 1. Bottom left
|
248
|
+
# 2. Bottom right
|
249
|
+
# 3. Top left
|
250
|
+
# 4. Top right
|
251
|
+
def subdivisions
|
252
|
+
subdivision_ranges.rects
|
253
|
+
end
|
254
|
+
|
255
|
+
# 各範囲の大きさが常に正になるように、self を絶対的な Rect に変換する
|
256
|
+
def absolute
|
257
|
+
self.class.new(@x.absolute, @y.absolute)
|
258
|
+
end
|
259
|
+
|
260
|
+
################################################################################
|
261
|
+
|
262
|
+
# 2 つの Rect が重なる領域を表す Rect
|
263
|
+
def overlap(other)
|
264
|
+
if x = @x.overlap(other.x) && y = @y.overlap(other.y)
|
265
|
+
self.class.new(x, y)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# 指定された 2 つの Rect セットを包含する Rect
|
270
|
+
def max(other)
|
271
|
+
self.class.new(@x.max(other.x), @y.max(other.y))
|
272
|
+
end
|
273
|
+
|
274
|
+
################################################################################
|
275
|
+
|
276
|
+
# Rect を x 軸に沿って移動します
|
277
|
+
def shift_x(x)
|
278
|
+
self.class.new(@x.shift(x), @y)
|
279
|
+
end
|
280
|
+
|
281
|
+
# Rect を y 軸に沿って移動します
|
282
|
+
def shift_y(y)
|
283
|
+
self.class.new(@x, @y.shift(y))
|
284
|
+
end
|
285
|
+
|
286
|
+
# 自分の右端を相手の Rect の左端に揃える
|
287
|
+
def left_of(other)
|
288
|
+
self.class.new(@x.align_before(other.x), @y)
|
289
|
+
end
|
290
|
+
|
291
|
+
# 自分の左端を相手の Rect の右端に揃える
|
292
|
+
def right_of(other)
|
293
|
+
self.class.new(@x.align_after(other.x), @y)
|
294
|
+
end
|
295
|
+
|
296
|
+
# 自分の上端を相手の Rectの下端に揃える
|
297
|
+
def below(other)
|
298
|
+
self.class.new(@x, @y.align_before(other.y))
|
299
|
+
end
|
300
|
+
|
301
|
+
# Align self's bottom edge with the top edge of the other Rect.
|
302
|
+
def above(other)
|
303
|
+
self.class.new(@x, @y.align_after(other.y))
|
304
|
+
end
|
305
|
+
|
306
|
+
# 自分の左端を相手の Rect の左端に揃える
|
307
|
+
def align_left_of(other)
|
308
|
+
self.class.new(@x.align_start_of(other.x), @y)
|
309
|
+
end
|
310
|
+
|
311
|
+
# 自分の右端を相手のRectの右端に揃える
|
312
|
+
def align_right_of(other)
|
313
|
+
self.class.new(@x.align_end_of(other.x), @y)
|
314
|
+
end
|
315
|
+
|
316
|
+
# self の下端を other Rect の下端に揃える
|
317
|
+
def align_bottom_of(other)
|
318
|
+
self.class.new(@x, @y.align_start_of(other.y))
|
319
|
+
end
|
320
|
+
|
321
|
+
# 自分の上端を相手の Rect の上端に揃える
|
322
|
+
def align_top_of(other)
|
323
|
+
self.class.new(@x, @y.align_end_of(other.y))
|
324
|
+
end
|
325
|
+
|
326
|
+
# 自分を相手の Rect の左上端に沿って配置する
|
327
|
+
def top_left_of(other)
|
328
|
+
align_left_of(other).align_top_of(other)
|
329
|
+
end
|
330
|
+
|
331
|
+
# 相手の Rect の右上端に沿って自分を配置する
|
332
|
+
def top_right_of(other)
|
333
|
+
align_right_of(other).align_top_of(other)
|
334
|
+
end
|
335
|
+
|
336
|
+
# 自分を相手の Rect の左下の端に沿って配置する
|
337
|
+
def bottom_left_of(other)
|
338
|
+
align_left_of(other).align_bottom_of(other)
|
339
|
+
end
|
340
|
+
|
341
|
+
# 相手の Rect の右下の端に沿って自分を配置する
|
342
|
+
def bottom_right_of(other)
|
343
|
+
align_right_of(other).align_bottom_of(other)
|
344
|
+
end
|
345
|
+
|
346
|
+
# 指定された位置に最も近い角を返す
|
347
|
+
CLOSEST_CORNER_TABLE = {
|
348
|
+
[:start, :start] => :bottom_left,
|
349
|
+
[:start, :end] => :top_left,
|
350
|
+
[:end, :start] => :bottom_right,
|
351
|
+
[:end, :end] => :top_right,
|
352
|
+
}
|
353
|
+
def closest_corner(v)
|
354
|
+
CLOSEST_CORNER_TABLE.fetch([@x.closest_edge(v.x), @y.closest_edge(v.y)])
|
355
|
+
end
|
356
|
+
|
357
|
+
# Rect の四隅
|
358
|
+
def corners
|
359
|
+
[
|
360
|
+
V[@x.start, @y.end],
|
361
|
+
V[@x.end, @y.end],
|
362
|
+
V[@x.end, @y.start],
|
363
|
+
V[@x.start, @y.start],
|
364
|
+
]
|
365
|
+
end
|
366
|
+
|
367
|
+
# Rect を表す2つの三角形の頂点を返す
|
368
|
+
def triangles
|
369
|
+
a, b, c, d = corners
|
370
|
+
[[a, b, c], [a, c, d]]
|
371
|
+
end
|
372
|
+
|
373
|
+
# Rect を指定されたベクトルだけシフトします
|
374
|
+
def shift(v)
|
375
|
+
shift_x(v.x).shift_y(v.y)
|
376
|
+
end
|
377
|
+
|
378
|
+
# 指定された位置が Rectangle に触れているかどうか
|
379
|
+
def contains?(v)
|
380
|
+
@x.contains?(v.x) && @y.contains?(v.y)
|
381
|
+
end
|
382
|
+
|
383
|
+
# 指定された位置が Rect 領域の外側にある場合、その位置に最も近い辺を引き伸ばす
|
384
|
+
def stretch_to(v)
|
385
|
+
self.class.new(@x.stretch_to_value(v.x), @y.stretch_to_value(v.y))
|
386
|
+
end
|
387
|
+
|
388
|
+
# 指定された位置が Rect 領域の外側にある場合、その位置に最も近い辺を引き伸ばす
|
389
|
+
def stretch_to_point(v)
|
390
|
+
stretch_to(v)
|
391
|
+
end
|
392
|
+
|
393
|
+
# 左端にパディングが適用された Rect
|
394
|
+
def pad_left(pad)
|
395
|
+
self.class.new(@x.pad_start(pad), @y)
|
396
|
+
end
|
397
|
+
|
398
|
+
# 右端にパディングが適用された Rect
|
399
|
+
def pad_right(pad)
|
400
|
+
self.class.new(@x.pad_end(pad), @y)
|
401
|
+
end
|
402
|
+
|
403
|
+
# 下端にパディングが適用された四角形
|
404
|
+
def pad_bottom(pad)
|
405
|
+
self.class.new(@x, @y.pad_start(pad))
|
406
|
+
end
|
407
|
+
|
408
|
+
# 上端にパディングが適用された Rect
|
409
|
+
def pad_top(pad)
|
410
|
+
self.class.new(@x, @y.pad_end(pad))
|
411
|
+
end
|
412
|
+
|
413
|
+
# 各辺にある程度のパディング量が適用された Rect
|
414
|
+
def pad(pad)
|
415
|
+
self.class.new(@x.pad(pad), @y.pad(pad))
|
416
|
+
end
|
417
|
+
|
418
|
+
# パディングが適用された Rect
|
419
|
+
def padding(padding)
|
420
|
+
self.class.new(@x.pad_ends(padding.x.start, padding.x.end), @y.pad_ends(padding.y.start, padding.y.end))
|
421
|
+
end
|
422
|
+
|
423
|
+
# x 軸上の指定された位置を基準とした相対位置を持つ Rect を返す
|
424
|
+
def relative_to_x(x)
|
425
|
+
self.class.new(@x.shift(-x), @y)
|
426
|
+
end
|
427
|
+
|
428
|
+
# y 軸上の指定された位置を基準とした相対位置を持つ Rect を返す
|
429
|
+
def relative_to_y(y)
|
430
|
+
self.class.new(@x, @y.shift(-y))
|
431
|
+
end
|
432
|
+
|
433
|
+
# 指定された位置を基準とした相対位置を持つ Rect を返す
|
434
|
+
def relative_to(v)
|
435
|
+
relative_to_x(v.x).relative_to_y(v.y)
|
436
|
+
end
|
437
|
+
|
438
|
+
# X 軸を反転する (別名: Y 軸を中心に反転する)
|
439
|
+
def invert_x
|
440
|
+
self.class.new(@x.invert, @y)
|
441
|
+
end
|
442
|
+
|
443
|
+
# Y 軸を反転する (別名: X 軸を中心に反転する)
|
444
|
+
def invert_y
|
445
|
+
self.class.new(@x, @y.invert)
|
446
|
+
end
|
447
|
+
|
448
|
+
################################################################################
|
449
|
+
|
450
|
+
def ==(other)
|
451
|
+
self.class == other.class && @x == other.x && @y == other.y
|
452
|
+
end
|
453
|
+
|
454
|
+
def eql?(other)
|
455
|
+
self.class == other.class && @x == other.x && @y == other.y
|
456
|
+
end
|
457
|
+
|
458
|
+
def hash
|
459
|
+
self.class.hash ^ @x.hash ^ @y.hash
|
460
|
+
end
|
461
|
+
|
462
|
+
def <=>(other)
|
463
|
+
[self.class, @x, @y] <=> [other.class, other.x, other.y]
|
464
|
+
end
|
465
|
+
|
466
|
+
def inspect
|
467
|
+
"(#{@x}, #{@y})"
|
468
|
+
end
|
469
|
+
|
470
|
+
def to_s
|
471
|
+
"(#{@x}, #{@y})"
|
472
|
+
end
|
473
|
+
|
474
|
+
SubdivisionRanges = Data.define(:x_a, :x_b, :y_a, :y_b) do
|
475
|
+
def rects
|
476
|
+
[
|
477
|
+
Rect.new(x_a, y_a),
|
478
|
+
Rect.new(x_b, y_a),
|
479
|
+
Rect.new(x_a, y_b),
|
480
|
+
Rect.new(x_b, y_b),
|
481
|
+
]
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
if $0 == __FILE__
|
488
|
+
V = GeomCraft::Vec2
|
489
|
+
Range2 = GeomCraft::Range2
|
490
|
+
Rect = GeomCraft::Rect
|
491
|
+
|
492
|
+
require "rspec/autorun"
|
493
|
+
|
494
|
+
RSpec.configure do |config|
|
495
|
+
config.expect_with :test_unit
|
496
|
+
end
|
497
|
+
|
498
|
+
describe Rect do
|
499
|
+
it "x, y, w, h から作る" do
|
500
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 100.0, 100.0)
|
501
|
+
assert { a.x == Range2.new(-50.0, 50.0) }
|
502
|
+
assert { a.y == Range2.new(-50.0, 50.0) }
|
503
|
+
end
|
504
|
+
|
505
|
+
it "w, h から作る" do
|
506
|
+
a = Rect.from_w_h(100.0, 100.0)
|
507
|
+
assert { a.x == Range2.new(-50.0, 50.0) }
|
508
|
+
assert { a.y == Range2.new(-50.0, 50.0) }
|
509
|
+
end
|
510
|
+
|
511
|
+
it "対角から作る" do
|
512
|
+
assert { Rect.from_corners(V[-10, 10], V[-10, 10]) == Rect.new(Range2.new(-10, -10), Range2.new(10, 10)) }
|
513
|
+
end
|
514
|
+
|
515
|
+
it "基本的な値の取得" do
|
516
|
+
a = Rect.from_x_y_w_h(10.0, 20.0, 100.0, 100.0)
|
517
|
+
assert { a.x_middle == 10.0 }
|
518
|
+
assert { a.y_middle == 20.0 }
|
519
|
+
assert { a.w == 100.0 }
|
520
|
+
assert { a.h == 100.0 }
|
521
|
+
assert { a.x_y == [10.0, 20.0] }
|
522
|
+
assert { a.w_h == [100.0, 100.0] }
|
523
|
+
end
|
524
|
+
|
525
|
+
it "a を b の座標の align に揃える" do
|
526
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0)
|
527
|
+
b = Rect.from_x_y_w_h(0.0, 0.0, 100.0, 100.0)
|
528
|
+
assert { a.align_x_of(:start, b) == Rect.new(Range2.new(-50.0, -40.0), Range2.new(-5.0, 5.0)) }
|
529
|
+
assert { a.align_x_of(:middle, b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
530
|
+
assert { a.align_x_of(:end, b) == Rect.new(Range2.new(40.0, 50.0), Range2.new(-5.0, 5.0)) }
|
531
|
+
|
532
|
+
assert { a.align_y_of(:start, b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-50.0, -40.0)) }
|
533
|
+
assert { a.align_y_of(:middle, b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
534
|
+
assert { a.align_y_of(:end, b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(40.0, 50.0)) }
|
535
|
+
|
536
|
+
# a.align_x_of(:middle, b) と a.align_y_of(:middle, b) のショートカット:
|
537
|
+
assert { a.align_middle_x_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
538
|
+
assert { a.align_middle_y_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
539
|
+
|
540
|
+
# a を b の内側の上下左右の辺にくっつける
|
541
|
+
assert { a.mid_top_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(40.0, 50.0)) }
|
542
|
+
assert { a.mid_bottom_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-50.0, -40.0)) }
|
543
|
+
assert { a.mid_left_of(b) == Rect.new(Range2.new(-50.0, -40.0), Range2.new(-5.0, 5.0)) }
|
544
|
+
assert { a.mid_right_of(b) == Rect.new(Range2.new(40.0, 50.0), Range2.new(-5.0, 5.0)) }
|
545
|
+
|
546
|
+
# a を b の中心に配置する
|
547
|
+
assert { a.middle_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
548
|
+
end
|
549
|
+
|
550
|
+
it "中央で区切って上下左右の範囲を返す" do
|
551
|
+
a = Rect.from_x_y_w_h(200.0, 300.0, 10.0, 10.0)
|
552
|
+
b = a.subdivision_ranges
|
553
|
+
assert { b.y_a == Range2.new(295.0, 300.0) }
|
554
|
+
assert { b.y_b == Range2.new(300.0, 305.0) }
|
555
|
+
assert { b.x_a == Range2.new(195.0, 200.0) }
|
556
|
+
assert { b.x_b == Range2.new(200.0, 205.0) }
|
557
|
+
end
|
558
|
+
|
559
|
+
it "内部の方向を正にする" do
|
560
|
+
a = Rect.new(Range2.new(1.0, -1.0), Range2.new(1.0, -1.0))
|
561
|
+
assert { a == Rect.new(Range2.new(1.0, -1.0), Range2.new(1.0, -1.0)) }
|
562
|
+
assert { a.absolute == Rect.new(Range2.new(-1.0, 1.0), Range2.new(-1.0, 1.0)) }
|
563
|
+
end
|
564
|
+
|
565
|
+
it "AND 領域" do
|
566
|
+
a = Rect.from_x_y_w_h(100.0, 100.0, 100.0, 100.0)
|
567
|
+
b = Rect.from_x_y_w_h(150.0, 150.0, 100.0, 100.0)
|
568
|
+
assert { a.overlap(b) == Rect.new(Range2.new(100.0, 150.0), Range2.new(100.0, 150.0)) }
|
569
|
+
end
|
570
|
+
|
571
|
+
it "OR 領域" do
|
572
|
+
a = Rect.from_x_y_w_h(100.0, 100.0, 100.0, 100.0)
|
573
|
+
b = Rect.from_x_y_w_h(150.0, 150.0, 100.0, 100.0)
|
574
|
+
assert { a.max(b) == Rect.new(Range2.new(50.0, 200.0), Range2.new(50.0, 200.0)) }
|
575
|
+
end
|
576
|
+
|
577
|
+
it "辺の座標" do
|
578
|
+
a = Rect.from_x_y_w_h(100.0, 100.0, 100.0, 100.0)
|
579
|
+
assert { a.left == 50.0 }
|
580
|
+
assert { a.right == 150.0 }
|
581
|
+
assert { a.bottom == 50.0 }
|
582
|
+
assert { a.top == 150.0 }
|
583
|
+
|
584
|
+
# まとめて
|
585
|
+
assert { a.l_r_b_t == [50.0, 150.0, 50.0, 150.0] }
|
586
|
+
end
|
587
|
+
|
588
|
+
it "x y をそれぞれ移動" do
|
589
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 100.0, 100.0)
|
590
|
+
assert { a == Rect.new(Range2.new(-50.0, 50.0), Range2.new(-50.0, 50.0)) }
|
591
|
+
assert { a.shift_x(25.0) == Rect.new(Range2.new(-25.0, 75.0), Range2.new(-50.0, 50.0)) }
|
592
|
+
assert { a.shift_y(25.0) == Rect.new(Range2.new(-50.0, 50.0), Range2.new(-25.0, 75.0)) }
|
593
|
+
end
|
594
|
+
|
595
|
+
describe "相手のどこかに移動する" do
|
596
|
+
let(:a) { Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0) }
|
597
|
+
let(:b) { Rect.from_x_y_w_h(0.0, 0.0, 100.0, 100.0) }
|
598
|
+
|
599
|
+
it "相手の辺の外側に移動する" do
|
600
|
+
assert { a.left_of(b) == Rect.new(Range2.new(-60.0, -50.0), Range2.new(-5.0, 5.0)) }
|
601
|
+
assert { a.right_of(b) == Rect.new(Range2.new(50.0, 60.0), Range2.new(-5.0, 5.0)) }
|
602
|
+
assert { a.below(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-60.0, -50.0)) }
|
603
|
+
assert { a.above(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(50.0, 60.0)) }
|
604
|
+
end
|
605
|
+
|
606
|
+
it "相手の辺の内側に移動する" do
|
607
|
+
assert { a.align_left_of(b) == Rect.new(Range2.new(-50.0, -40.0), Range2.new(-5.0, 5.0)) }
|
608
|
+
assert { a.align_right_of(b) == Rect.new(Range2.new(40.0, 50.0), Range2.new(-5.0, 5.0)) }
|
609
|
+
assert { a.align_bottom_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-50.0, -40.0)) }
|
610
|
+
assert { a.align_top_of(b) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(40.0, 50.0)) }
|
611
|
+
end
|
612
|
+
|
613
|
+
it "相手の角の内側に移動する" do
|
614
|
+
assert { a.top_left_of(b) == Rect.new(Range2.new(-50.0, -40.0), Range2.new(40.0, 50.0)) }
|
615
|
+
assert { a.top_right_of(b) == Rect.new(Range2.new(40.0, 50.0), Range2.new(40.0, 50.0)) }
|
616
|
+
assert { a.bottom_left_of(b) == Rect.new(Range2.new(-50.0, -40.0), Range2.new(-50.0, -40.0)) }
|
617
|
+
assert { a.bottom_right_of(b) == Rect.new(Range2.new(40.0, 50.0), Range2.new(-50.0, -40.0)) }
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
it "指定の座標を含むように近い方の辺を広げる(比率が壊れる)" do
|
622
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0)
|
623
|
+
assert { a.stretch_to_point(V[6.0, 6.0]) == Rect.new(Range2.new(-5.0, 6.0), Range2.new(-5.0, 6.0)) }
|
624
|
+
end
|
625
|
+
|
626
|
+
it "指定の座標にいちばん近い角の名前を返す" do
|
627
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0)
|
628
|
+
assert { a.closest_corner(V[1.0, 1.0]) == :top_right }
|
629
|
+
assert { a.closest_corner(V[-1.0, -1.0]) == :bottom_left }
|
630
|
+
assert { a.closest_corner(V[-1.0, 1.0]) == :top_left }
|
631
|
+
assert { a.closest_corner(V[1.0, -1.0]) == :bottom_right }
|
632
|
+
end
|
633
|
+
|
634
|
+
it "角の座標を返す" do
|
635
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0)
|
636
|
+
assert { a.corners == [[-5.0, 5.0], [5.0, 5.0], [5.0, -5.0], [-5.0, -5.0]] }
|
637
|
+
end
|
638
|
+
|
639
|
+
it "四角形を斜めに切ってできる三角形を得る" do
|
640
|
+
a = Rect.from_x_y_w_h(0.0, 0.0, 10.0, 10.0)
|
641
|
+
assert { a.triangles == [[[-5.0, 5.0], [5.0, 5.0], [5.0, -5.0]], [[-5.0, 5.0], [5.0, -5.0], [-5.0, -5.0]]] }
|
642
|
+
end
|
643
|
+
|
644
|
+
it "ベクトルや Point2 から作る" do
|
645
|
+
assert { Rect.from_xy_wh(V[0.0, 0.0], V[10.0, 10.0]) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
646
|
+
assert { Rect.from_wh(V[10.0, 10.0]) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
647
|
+
end
|
648
|
+
|
649
|
+
it "基本的な情報の参照" do
|
650
|
+
a = Rect.from_wh(V[100.0, 100.0])
|
651
|
+
assert { a.xy == V[0.0, 0.0] }
|
652
|
+
assert { a.wh == V[100.0, 100.0] }
|
653
|
+
assert { a.xy_wh == [V[0.0, 0.0], V[100.0, 100.0]] }
|
654
|
+
|
655
|
+
assert { a.top_left == V[-50.0, 50.0] }
|
656
|
+
assert { a.top_right == V[50.0, 50.0] }
|
657
|
+
assert { a.bottom_left == V[-50.0, -50.0] }
|
658
|
+
assert { a.bottom_right == V[50.0, -50.0] }
|
659
|
+
|
660
|
+
assert { a.mid_left == V[-50.0, 0.0] }
|
661
|
+
assert { a.mid_top == V[0.0, 50.0] }
|
662
|
+
assert { a.mid_right == V[50.0, 0.0] }
|
663
|
+
assert { a.mid_bottom == V[0.0, -50.0] }
|
664
|
+
end
|
665
|
+
|
666
|
+
it "x, y をまとめて移動" do
|
667
|
+
a = Rect.from_wh(V[100.0, 100.0])
|
668
|
+
assert { a.shift(V[10.0, 10.0]) == Rect.new(Range2.new(-40.0, 60.0), Range2.new(-40.0, 60.0)) }
|
669
|
+
end
|
670
|
+
|
671
|
+
it "指定の座標が含まれるか?" do
|
672
|
+
a = Rect.from_wh(V[100.0, 100.0])
|
673
|
+
assert { a.contains?(V[0.0, 0.0]) == true }
|
674
|
+
assert { a.contains?(V[0.0, 51.0]) == false }
|
675
|
+
end
|
676
|
+
|
677
|
+
it "指定の座標が含まれるまで近い方を伸ばす" do
|
678
|
+
a = Rect.from_wh(V[2.0, 2.0])
|
679
|
+
assert { a.stretch_to(V[5.0, 5.0]) == Rect.new(Range2.new(-1.0, 5.0), Range2.new(-1.0, 5.0)) }
|
680
|
+
end
|
681
|
+
|
682
|
+
it "左上wh や 左下wh をまとめて得る" do
|
683
|
+
a = Rect.from_wh(V[100.0, 100.0])
|
684
|
+
assert { a.l_t_w_h == [-50.0, 50.0, 100.0, 100.0] }
|
685
|
+
assert { a.l_b_w_h == [-50.0, -50.0, 100.0, 100.0] }
|
686
|
+
end
|
687
|
+
|
688
|
+
it "領域を内側に縮小する" do
|
689
|
+
a = Rect.from_wh(V[100.0, 100.0])
|
690
|
+
assert { a.pad_left(10.0) == Rect.new(Range2.new(-40.0, 50.0), Range2.new(-50.0, 50.0)) }
|
691
|
+
assert { a.pad_right(10.0) == Rect.new(Range2.new(-50.0, 40.0), Range2.new(-50.0, 50.0)) }
|
692
|
+
assert { a.pad_bottom(10.0) == Rect.new(Range2.new(-50.0, 50.0), Range2.new(-40.0, 50.0)) }
|
693
|
+
assert { a.pad_top(10.0) == Rect.new(Range2.new(-50.0, 50.0), Range2.new(-50.0, 40.0)) }
|
694
|
+
assert { a.pad(10.0) == Rect.new(Range2.new(-40.0, 40.0), Range2.new(-40.0, 40.0)) }
|
695
|
+
p = Rect.new(Range2.new(10.0, 10.0), Range2.new(10.0, 10.0))
|
696
|
+
assert { a.padding(p) == Rect.new(Range2.new(-40.0, 40.0), Range2.new(-40.0, 40.0)) }
|
697
|
+
end
|
698
|
+
|
699
|
+
it "相対的な範囲を返す" do
|
700
|
+
a = Rect.from_wh(V[10.0, 10.0])
|
701
|
+
assert { a == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-5.0, 5.0)) }
|
702
|
+
assert { a.relative_to_x(10.0) == Rect.new(Range2.new(-15.0, -5.0), Range2.new(-5.0, 5.0)) }
|
703
|
+
assert { a.relative_to_y(10.0) == Rect.new(Range2.new(-5.0, 5.0), Range2.new(-15.0, -5.0)) }
|
704
|
+
assert { a.relative_to(V[10.0, 10.0]) == Rect.new(Range2.new(-15.0, -5.0), Range2.new(-15.0, -5.0)) }
|
705
|
+
end
|
706
|
+
|
707
|
+
it "反転" do
|
708
|
+
a = Rect.from_wh(V[2.0, 2.0])
|
709
|
+
assert { a == Rect.new(Range2.new(-1.0, 1.0), Range2.new(-1.0, 1.0)) }
|
710
|
+
assert { a.invert_x == Rect.new(Range2.new(1.0, -1.0), Range2.new(-1.0, 1.0)) }
|
711
|
+
assert { a.invert_y == Rect.new(Range2.new(-1.0, 1.0), Range2.new(1.0, -1.0)) }
|
712
|
+
end
|
713
|
+
|
714
|
+
it "==" do
|
715
|
+
assert { Rect.from_wh(V[2.0, 2.0]) == Rect.from_wh(V[2.0, 2.0]) }
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
# >> ............................
|
720
|
+
# >>
|
721
|
+
# >> Finished in 0.04071 seconds (files took 0.06077 seconds to load)
|
722
|
+
# >> 28 examples, 0 failures
|
723
|
+
# >>
|