@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.
- package/CHANGELOG.md +12 -0
- package/MIGRATION-plan-a-slot-api.md +266 -0
- package/PLAN-A-rack-as-slot-holder.md +164 -0
- package/dist/crane.js +1 -1
- package/dist/crane.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/rack-grid-3d.d.ts +18 -7
- package/dist/rack-grid-3d.js +372 -69
- package/dist/rack-grid-3d.js.map +1 -1
- package/dist/rack-grid-cell.d.ts +21 -72
- package/dist/rack-grid-cell.js +147 -243
- package/dist/rack-grid-cell.js.map +1 -1
- package/dist/rack-grid.d.ts +277 -56
- package/dist/rack-grid.js +1230 -695
- package/dist/rack-grid.js.map +1 -1
- package/dist/rack-materials.d.ts +9 -0
- package/dist/rack-materials.js +55 -0
- package/dist/rack-materials.js.map +1 -0
- package/dist/storage-rack-3d.d.ts +15 -0
- package/dist/storage-rack-3d.js +131 -30
- package/dist/storage-rack-3d.js.map +1 -1
- package/dist/storage-rack.d.ts +242 -45
- package/dist/storage-rack.js +684 -106
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/crane.ts +1 -1
- package/src/index.ts +3 -4
- package/src/rack-grid-3d.ts +383 -80
- package/src/rack-grid-cell.ts +161 -305
- package/src/rack-grid.ts +1263 -762
- package/src/rack-materials.ts +61 -0
- package/src/storage-rack-3d.ts +144 -30
- package/src/storage-rack.ts +763 -111
- package/test/test-carrier-lifecycle.ts +361 -0
- package/test/test-coord-alignment.ts +201 -0
- package/test/test-external-to-rack.ts +461 -0
- package/test/test-mover-concurrent-bug.ts +304 -0
- package/test/test-mover-rollback.ts +290 -0
- package/test/test-r19-place-absorb.ts +174 -0
- package/test/test-rack-3d-attach-real.ts +301 -0
- package/test/test-rack-concurrent.ts +254 -0
- package/test/test-rack-edge-cases.ts +323 -0
- package/test/test-rack-grid-cell.ts +318 -0
- package/test/test-rack-grid-location.ts +657 -0
- package/test/test-real-3d-positioning.ts +158 -0
- package/test/test-slot-center-convention.ts +116 -0
- package/test/test-slot-target.ts +189 -0
- package/test/test-storage-rack-batched.ts +606 -0
- package/test/test-storage-rack-click.ts +329 -0
- package/test/test-storage-rack-slot-api.ts +357 -0
- package/test/test-toscene-convention.ts +162 -0
- package/test/test-user-scenario-sequential.ts +334 -0
- package/translations/en.json +2 -0
- package/translations/ja.json +2 -0
- package/translations/ko.json +2 -0
- package/translations/ms.json +2 -0
- package/translations/zh.json +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/rack-column.d.ts +0 -35
- package/dist/rack-column.js +0 -258
- package/dist/rack-column.js.map +0 -1
- package/dist/rack-grid-helpers.d.ts +0 -28
- package/dist/rack-grid-helpers.js +0 -71
- package/dist/rack-grid-helpers.js.map +0 -1
- package/dist/rack-grid-location.d.ts +0 -37
- package/dist/rack-grid-location.js +0 -227
- package/dist/rack-grid-location.js.map +0 -1
- package/dist/storage-cell-3d.d.ts +0 -25
- package/dist/storage-cell-3d.js +0 -88
- package/dist/storage-cell-3d.js.map +0 -1
- package/dist/storage-cell.d.ts +0 -73
- package/dist/storage-cell.js +0 -215
- package/dist/storage-cell.js.map +0 -1
- package/src/rack-column.ts +0 -340
- package/src/rack-grid-helpers.ts +0 -77
- package/src/rack-grid-location.ts +0 -286
- package/src/storage-cell-3d.ts +0 -101
- package/src/storage-cell.ts +0 -267
- package/test/test-cell-position.ts +0 -105
- 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
|
-
})
|
package/test/test-rack-grid.ts
DELETED
|
@@ -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
|
-
})
|