@operato/scene-storage 10.0.0-beta.41 → 10.0.0-beta.42

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 (82) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/MIGRATION-plan-a-slot-api.md +266 -0
  3. package/PLAN-A-rack-as-slot-holder.md +164 -0
  4. package/dist/crane.js +1 -1
  5. package/dist/crane.js.map +1 -1
  6. package/dist/index.d.ts +3 -4
  7. package/dist/index.js +1 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/rack-grid-3d.d.ts +18 -7
  10. package/dist/rack-grid-3d.js +372 -69
  11. package/dist/rack-grid-3d.js.map +1 -1
  12. package/dist/rack-grid-cell.d.ts +21 -72
  13. package/dist/rack-grid-cell.js +147 -243
  14. package/dist/rack-grid-cell.js.map +1 -1
  15. package/dist/rack-grid.d.ts +277 -56
  16. package/dist/rack-grid.js +1230 -695
  17. package/dist/rack-grid.js.map +1 -1
  18. package/dist/rack-materials.d.ts +9 -0
  19. package/dist/rack-materials.js +55 -0
  20. package/dist/rack-materials.js.map +1 -0
  21. package/dist/storage-rack-3d.d.ts +15 -0
  22. package/dist/storage-rack-3d.js +131 -30
  23. package/dist/storage-rack-3d.js.map +1 -1
  24. package/dist/storage-rack.d.ts +242 -45
  25. package/dist/storage-rack.js +684 -106
  26. package/dist/storage-rack.js.map +1 -1
  27. package/package.json +3 -3
  28. package/src/crane.ts +1 -1
  29. package/src/index.ts +3 -4
  30. package/src/rack-grid-3d.ts +383 -80
  31. package/src/rack-grid-cell.ts +161 -305
  32. package/src/rack-grid.ts +1263 -762
  33. package/src/rack-materials.ts +61 -0
  34. package/src/storage-rack-3d.ts +144 -30
  35. package/src/storage-rack.ts +763 -111
  36. package/test/test-carrier-lifecycle.ts +361 -0
  37. package/test/test-coord-alignment.ts +201 -0
  38. package/test/test-external-to-rack.ts +461 -0
  39. package/test/test-mover-concurrent-bug.ts +304 -0
  40. package/test/test-mover-rollback.ts +290 -0
  41. package/test/test-r19-place-absorb.ts +174 -0
  42. package/test/test-rack-3d-attach-real.ts +301 -0
  43. package/test/test-rack-concurrent.ts +254 -0
  44. package/test/test-rack-edge-cases.ts +323 -0
  45. package/test/test-rack-grid-cell.ts +318 -0
  46. package/test/test-rack-grid-location.ts +657 -0
  47. package/test/test-real-3d-positioning.ts +158 -0
  48. package/test/test-slot-center-convention.ts +116 -0
  49. package/test/test-slot-target.ts +189 -0
  50. package/test/test-storage-rack-batched.ts +606 -0
  51. package/test/test-storage-rack-click.ts +329 -0
  52. package/test/test-storage-rack-slot-api.ts +357 -0
  53. package/test/test-toscene-convention.ts +162 -0
  54. package/test/test-user-scenario-sequential.ts +334 -0
  55. package/translations/en.json +2 -0
  56. package/translations/ja.json +2 -0
  57. package/translations/ko.json +2 -0
  58. package/translations/ms.json +2 -0
  59. package/translations/zh.json +2 -0
  60. package/tsconfig.tsbuildinfo +1 -1
  61. package/dist/rack-column.d.ts +0 -35
  62. package/dist/rack-column.js +0 -258
  63. package/dist/rack-column.js.map +0 -1
  64. package/dist/rack-grid-helpers.d.ts +0 -28
  65. package/dist/rack-grid-helpers.js +0 -71
  66. package/dist/rack-grid-helpers.js.map +0 -1
  67. package/dist/rack-grid-location.d.ts +0 -37
  68. package/dist/rack-grid-location.js +0 -227
  69. package/dist/rack-grid-location.js.map +0 -1
  70. package/dist/storage-cell-3d.d.ts +0 -25
  71. package/dist/storage-cell-3d.js +0 -88
  72. package/dist/storage-cell-3d.js.map +0 -1
  73. package/dist/storage-cell.d.ts +0 -73
  74. package/dist/storage-cell.js +0 -215
  75. package/dist/storage-cell.js.map +0 -1
  76. package/src/rack-column.ts +0 -340
  77. package/src/rack-grid-helpers.ts +0 -77
  78. package/src/rack-grid-location.ts +0 -286
  79. package/src/storage-cell-3d.ts +0 -101
  80. package/src/storage-cell.ts +0 -267
  81. package/test/test-cell-position.ts +0 -105
  82. package/test/test-rack-grid.ts +0 -77
@@ -1,105 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * 정밀 진단 — Rack 의 _buildCells 가 cell 의 board-absolute state.left/top
5
- * 정확히 설정하는지 + Crane.moveTo 의 railLocalX 계산 정확한지.
6
- */
7
-
8
- import 'should'
9
- import { readFileSync } from 'fs'
10
- import { resolve, dirname } from 'path'
11
- import { fileURLToPath } from 'url'
12
-
13
- const __filename = fileURLToPath(import.meta.url)
14
- const __dirname = dirname(__filename)
15
-
16
- function readSrc(rel: string): string {
17
- return readFileSync(resolve(__dirname, rel), 'utf-8')
18
- }
19
-
20
- // ── Test 1: storage-rack._buildCells 의 cell 좌표 계산 검증 ─────────────────
21
-
22
- describe('storage-rack._buildCells: cell 의 rack-local state.left/top', () => {
23
- it('coordinate formula — rack-local (toScene 이 parent transform 자동)', () => {
24
- // rack-local: cell.state.left = bayIdx * bayWidth + (bayWidth - cellW)/2
25
- // things-scene 의 toScene() 이 parent (rack) 의 transform 자동 적용 →
26
- // board-absolute 변환. rackLeft 더하면 *이중 변환* 결함.
27
- const src = readSrc('../src/storage-rack.ts')
28
- src.should.match(/cellLeft = bayIdx \* bayWidth/)
29
- src.should.not.match(/cellLeft = rackLeft/) // rackLeft 더하면 안 됨
30
- src.should.match(/left: cellLeft/)
31
- src.should.match(/top: cellTop/)
32
- })
33
-
34
- it('cell.size.width 는 cellMap.grid 의 bayWidth (= rack.width / bays)', () => {
35
- // 즉 (bayWidth - cellW) / 2 = 0 → bay 별 cellLeft = rackLeft + bayIdx * bayWidth
36
- const src = readSrc('../src/storage-rack.ts')
37
- src.should.match(/bayWidth = rackWidth \/ bays/)
38
- })
39
-
40
- it('storage-rack 은 rows=1 hardcoded', () => {
41
- const src = readSrc('../src/storage-rack.ts')
42
- src.should.match(/rows: 1/)
43
- })
44
- })
45
-
46
- // ── Test 2: Crane.moveTo 의 railLocalX 계산 ─────────────────────────────
47
-
48
- describe('Crane.moveTo: target.center 의 carrier 위치 → carriagePosition', () => {
49
- it('rotation=0 + crane.center.x = 200, target.center.x = 360 → railLocalX = 160', () => {
50
- // crane.left=0, width=400 → crane.center.x = 200
51
- // target (cell) 의 center.x = 360
52
- // dx = 360 - 200 = 160, dy = 0
53
- // rotation = 0 → cos=1, sin=0
54
- // railLocalX = 160 * 1 + 0 * 0 = 160
55
- // carriagePosition = clamp(160 + 400/2, [cw/2, width-cw/2]) = clamp(360, ...) → 360
56
- const rotation = 0
57
- const cos = Math.cos(rotation)
58
- const sin = Math.sin(rotation)
59
- const dx = 360 - 200
60
- const dy = 0
61
- const railLocalX = dx * cos + dy * sin
62
- const W = 400
63
- const cw = 40
64
- const minPos = cw / 2
65
- const maxPos = W - cw / 2
66
- const carriagePos = Math.max(minPos, Math.min(maxPos, railLocalX + W / 2))
67
- carriagePos.should.equal(360)
68
- })
69
-
70
- it('clamp 적용 — target 이 rail 범위 밖 (target.center.x = 1000, crane.center.x = 200)', () => {
71
- const dx = 1000 - 200 // 800 — 매우 큼
72
- const dy = 0
73
- const railLocalX = dx * 1 + dy * 0 // 800
74
- const W = 400
75
- const cw = 40
76
- const minPos = cw / 2 // 20
77
- const maxPos = W - cw / 2 // 380
78
- const carriagePos = Math.max(minPos, Math.min(maxPos, railLocalX + W / 2))
79
- carriagePos.should.equal(380) // clamp to maxPos
80
- })
81
-
82
- it('clamp 적용 — target 이 rail 왼쪽 밖 (target.center.x = -500, crane.center.x = 200)', () => {
83
- const dx = -500 - 200 // -700
84
- const dy = 0
85
- const railLocalX = dx * 1 + dy * 0 // -700
86
- const W = 400
87
- const cw = 40
88
- const carriagePos = Math.max(cw / 2, Math.min(W - cw / 2, railLocalX + W / 2))
89
- carriagePos.should.equal(20) // clamp to minPos
90
- })
91
-
92
- it('rotation=π/2 (90도) — Y projection 사용', () => {
93
- // rack 이 사선 90도 — crane 의 rail 도 90도. target 의 Y 좌표만 사용.
94
- const rotation = Math.PI / 2
95
- const cos = Math.cos(rotation) // ≈ 0
96
- const sin = Math.sin(rotation) // = 1
97
- const dx = 0
98
- const dy = 160
99
- const railLocalX = dx * cos + dy * sin // ≈ 160
100
- const W = 400
101
- const cw = 40
102
- const carriagePos = Math.max(cw / 2, Math.min(W - cw / 2, railLocalX + W / 2))
103
- carriagePos.should.be.approximately(360, 0.001)
104
- })
105
- })
@@ -1,77 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * RackTable unit tests — pure helpers (parseShelfLabels, formatLocationId)
5
- * + state-derived topology accessors (columnWidths, rowHeights).
6
- *
7
- * The full _buildRacks() + assignLocations() integration is exercised in
8
- * test-rack-table-crane.ts where minimal fake Rack/RackCell mocks are
9
- * wired through a Crane.
10
- */
11
-
12
- import 'should'
13
-
14
- import { parseShelfLabels, formatLocationId, distribute } from '../src/rack-grid-helpers.js'
15
-
16
- describe('RackTable: parseShelfLabels', () => {
17
- it('빈 문자열 → 1-based index fallback', () => {
18
- parseShelfLabels('', 4).should.deepEqual(['1', '2', '3', '4'])
19
- })
20
- it('undefined → 1-based index fallback', () => {
21
- parseShelfLabels(undefined, 3).should.deepEqual(['1', '2', '3'])
22
- })
23
- it('완전 명시 라벨 그대로', () => {
24
- parseShelfLabels('A,B,C', 3).should.deepEqual(['A', 'B', 'C'])
25
- })
26
- it('부분 empty entries 는 default 로 fallback', () => {
27
- parseShelfLabels(',,,04', 4).should.deepEqual(['1', '2', '3', '04'])
28
- })
29
- it('input 보다 levels 가 많으면 나머지는 default', () => {
30
- parseShelfLabels('A,B', 4).should.deepEqual(['A', 'B', '3', '4'])
31
- })
32
- it('input 이 levels 보다 많으면 잘림', () => {
33
- parseShelfLabels('A,B,C,D,E', 3).should.deepEqual(['A', 'B', 'C'])
34
- })
35
- it('공백 trim', () => {
36
- parseShelfLabels(' A , B , C ', 3).should.deepEqual(['A', 'B', 'C'])
37
- })
38
- })
39
-
40
- describe('RackTable: formatLocationId', () => {
41
- it('default 패턴 {z}{s}-{u}-{sh}', () => {
42
- formatLocationId('A', '01', '02', '3', '{z}{s}-{u}-{sh}').should.equal('A01-02-3')
43
- })
44
- it('zone 빈 값', () => {
45
- formatLocationId('', '01', '02', '1', '{z}{s}-{u}-{sh}').should.equal('01-02-1')
46
- })
47
- it('section/unit zero-padded 4자리', () => {
48
- formatLocationId('Z', '0042', '0007', '3', '{z}S{s}U{u}-{sh}').should.equal('ZS0042U0007-3')
49
- })
50
- it('placeholder 없는 패턴 그대로', () => {
51
- formatLocationId('A', '01', '02', '3', 'fixed').should.equal('fixed')
52
- })
53
- it('동일 placeholder 여러 번', () => {
54
- formatLocationId('A', '01', '02', '3', '{z}{z}{s}{s}').should.equal('AA0101')
55
- })
56
- it('shelf 라벨 문자', () => {
57
- formatLocationId('A', '01', '02', 'TOP', '{z}{s}-{u}-{sh}').should.equal('A01-02-TOP')
58
- })
59
- })
60
-
61
- describe('RackTable: distribute (per-column / per-row sizing)', () => {
62
- it('declared 없음 → 모두 균등', () => {
63
- distribute(1000, 4).should.deepEqual([250, 250, 250, 250])
64
- })
65
- it('전부 declared → 그대로', () => {
66
- distribute(1000, 3, [100, 200, 300]).should.deepEqual([100, 200, 300])
67
- })
68
- it('일부 declared → 나머지가 remaining 균등 분배', () => {
69
- distribute(1000, 4, [200, undefined, 300, undefined]).should.deepEqual([200, 250, 300, 250])
70
- })
71
- it('declared 합이 total 초과 → 나머지는 0', () => {
72
- distribute(500, 3, [400, 200, undefined]).should.deepEqual([400, 200, 0])
73
- })
74
- it('n=1 + declared 비어있음', () => {
75
- distribute(800, 1).should.deepEqual([800])
76
- })
77
- })