@operato/scene-storage 10.0.0-beta.40 → 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 +29 -0
- package/MIGRATION-plan-a-slot-api.md +266 -0
- package/PLAN-A-rack-as-slot-holder.md +164 -0
- package/dist/box.js +18 -0
- package/dist/box.js.map +1 -1
- package/dist/crane-3d.d.ts +47 -2
- package/dist/crane-3d.js +246 -89
- package/dist/crane-3d.js.map +1 -1
- package/dist/crane.d.ts +96 -12
- package/dist/crane.js +395 -100
- 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/pallet.d.ts +15 -0
- package/dist/pallet.js +38 -2
- package/dist/pallet.js.map +1 -1
- package/dist/parcel-3d.js +22 -18
- package/dist/parcel-3d.js.map +1 -1
- package/dist/parcel.d.ts +4 -3
- package/dist/parcel.js +24 -5
- package/dist/parcel.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 +165 -29
- package/dist/storage-rack-3d.js.map +1 -1
- package/dist/storage-rack.d.ts +253 -32
- package/dist/storage-rack.js +726 -66
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/box.ts +18 -0
- package/src/crane-3d.ts +258 -93
- package/src/crane.ts +445 -110
- package/src/index.ts +3 -4
- package/src/pallet.ts +50 -1
- package/src/parcel-3d.ts +23 -18
- package/src/parcel.ts +24 -5
- 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 +182 -29
- package/src/storage-rack.ts +819 -67
- package/test/test-carrier-lifecycle.ts +361 -0
- package/test/test-coord-alignment.ts +201 -0
- package/test/test-crane-geometry.ts +167 -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-phase-h-carrier-pickable.ts +4 -3
- 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 +7 -1
- package/translations/ja.json +7 -1
- package/translations/ko.json +7 -1
- package/translations/ms.json +7 -1
- package/translations/zh.json +7 -1
- 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 -70
- package/dist/storage-cell.js +0 -197
- 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 -247
- package/test/test-rack-grid.ts +0 -77
package/src/index.ts
CHANGED
|
@@ -13,12 +13,11 @@ export { default as StorageRack } from './storage-rack.js'
|
|
|
13
13
|
export type { StorageRackState } from './storage-rack.js'
|
|
14
14
|
export { StorageRack3D } from './storage-rack-3d.js'
|
|
15
15
|
export { default as RackGrid } from './rack-grid.js'
|
|
16
|
-
export type { RackGridState } from './rack-grid.js'
|
|
16
|
+
export type { RackGridState, CellOverride } from './rack-grid.js'
|
|
17
17
|
export { RackGrid3D } from './rack-grid-3d.js'
|
|
18
|
+
export { default as RackGridCell } from './rack-grid-cell.js'
|
|
19
|
+
export type { RackGridCellState } from './rack-grid-cell.js'
|
|
18
20
|
export { default as MobileStorageRack } from './mobile-storage-rack.js'
|
|
19
|
-
export { default as StorageCell } from './storage-cell.js'
|
|
20
|
-
export type { StorageCellType } from './storage-cell.js'
|
|
21
|
-
export { StorageCell3D } from './storage-cell-3d.js'
|
|
22
21
|
export { default as Crane } from './crane.js'
|
|
23
22
|
export type { CraneState, CraneStatus } from './crane.js'
|
|
24
23
|
export { Crane3D } from './crane-3d.js'
|
package/src/pallet.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
RealObject,
|
|
9
9
|
Pose6DOF,
|
|
10
10
|
rectangularFootprintFrames,
|
|
11
|
+
topApproachFrame,
|
|
11
12
|
getWorldPose,
|
|
12
13
|
sceneComponent
|
|
13
14
|
} from '@hatiolab/things-scene'
|
|
@@ -41,6 +42,15 @@ export interface PalletState extends State {
|
|
|
41
42
|
// ── 외관 ──
|
|
42
43
|
material?: PalletMaterial
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Fork pocket 의 깊이 (mm) — pallet 외부 bottom (skid bottom) 부터 deck bottom
|
|
47
|
+
* 까지의 수직 거리. fork blade 가 이 *pocket 안* 으로 수평 진입. 표준 EUR
|
|
48
|
+
* pallet (144mm depth) 의 pocket ≈ 50~60mm.
|
|
49
|
+
*
|
|
50
|
+
* 미명시 시 default = depth 의 40% (= ~60mm for 150mm pallet).
|
|
51
|
+
*/
|
|
52
|
+
pocketDepth?: number
|
|
53
|
+
|
|
44
54
|
// ── 3D 재질 ──
|
|
45
55
|
material3d?: Material3D
|
|
46
56
|
}
|
|
@@ -66,6 +76,12 @@ const NATURE: ComponentNature = {
|
|
|
66
76
|
{ display: 'Plastic', value: 'plastic' }
|
|
67
77
|
]
|
|
68
78
|
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'number',
|
|
82
|
+
label: 'pocket-depth',
|
|
83
|
+
name: 'pocketDepth',
|
|
84
|
+
placeholder: 'mm — fork 진입 pocket 깊이 (skid bottom → deck bottom). default depth × 40%.'
|
|
69
85
|
}
|
|
70
86
|
],
|
|
71
87
|
help: 'scene/component/pallet'
|
|
@@ -121,6 +137,24 @@ export default class Pallet extends Carriable(Legendable(Placeable(ContainerAbst
|
|
|
121
137
|
return NATURE
|
|
122
138
|
}
|
|
123
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Fork pocket 의 깊이 — fork blade 가 진입하는 *pallet 외부 bottom 부터 deck
|
|
142
|
+
* bottom* 까지의 수직 거리. crane.attachPointFor 가 이 값을 차감해서
|
|
143
|
+
* carrier 외부 bottom (skid) 이 fork blade bottom *아래로 pocketDepth 만큼*
|
|
144
|
+
* 깊이 정렬 (= fork 가 pallet 의 *deck 와 skid 사이* 안 으로 들어간 자세).
|
|
145
|
+
*/
|
|
146
|
+
get pocketDepth(): number {
|
|
147
|
+
const explicit = (this.state as any).pocketDepth
|
|
148
|
+
if (typeof explicit === 'number' && Number.isFinite(explicit) && explicit >= 0) {
|
|
149
|
+
return explicit
|
|
150
|
+
}
|
|
151
|
+
const d = this.state.depth
|
|
152
|
+
const depth = typeof d === 'number' && Number.isFinite(d) && d > 0
|
|
153
|
+
? d
|
|
154
|
+
: ((this.constructor as any).defaultDepth ?? 150)
|
|
155
|
+
return depth * 0.4
|
|
156
|
+
}
|
|
157
|
+
|
|
124
158
|
get anchors() {
|
|
125
159
|
return []
|
|
126
160
|
}
|
|
@@ -240,7 +274,7 @@ export default class Pallet extends Carriable(Legendable(Placeable(ContainerAbst
|
|
|
240
274
|
|
|
241
275
|
const longerAxis = Math.max(width, height)
|
|
242
276
|
|
|
243
|
-
|
|
277
|
+
const forkFrames = rectangularFootprintFrames({
|
|
244
278
|
carrierWorld: me,
|
|
245
279
|
width,
|
|
246
280
|
depth: height,
|
|
@@ -251,5 +285,20 @@ export default class Pallet extends Carriable(Legendable(Placeable(ContainerAbst
|
|
|
251
285
|
tolerance: { positionMm: 50, angleDeg: 5 },
|
|
252
286
|
priority: 0
|
|
253
287
|
})
|
|
288
|
+
|
|
289
|
+
// 큰 AGV (deck size 충분) 가 pallet 을 위에 적재하는 패턴. priority 낮음
|
|
290
|
+
// — forklift fork 가 더 자연스러운 default. AGV deck size 가 pallet 보다
|
|
291
|
+
// 작으면 application 측이 carrier 의 dimensions check 필요.
|
|
292
|
+
const deckFrame = topApproachFrame({
|
|
293
|
+
carrierWorld: me,
|
|
294
|
+
topY: palletDepth,
|
|
295
|
+
approachDistance: longerAxis * 0.5 + 100,
|
|
296
|
+
toolType: 'agv-deck',
|
|
297
|
+
tolerance: { positionMm: 30, angleDeg: 4 },
|
|
298
|
+
priority: 1,
|
|
299
|
+
id: 'top-deck'
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
return [...forkFrames, deckFrame]
|
|
254
303
|
}
|
|
255
304
|
}
|
package/src/parcel-3d.ts
CHANGED
|
@@ -21,6 +21,26 @@ const CARDBOARD_COLOR = 0xc8a878
|
|
|
21
21
|
const TAPE_COLOR = 0xddc899
|
|
22
22
|
const LABEL_COLOR = 0xeeeeee
|
|
23
23
|
|
|
24
|
+
// ── Module-level shared materials ───────────────────────────────────────────
|
|
25
|
+
// Parcel 인스턴스가 수백~수천 가능. instance 별 new MeshStandardMaterial 시
|
|
26
|
+
// material 개수 폭증 → GPU memory + draw call 비효율. static color 라 단일
|
|
27
|
+
// instance 공유. 색 변경 시 모든 Parcel 에 자동 반영 (의도).
|
|
28
|
+
const PARCEL_BODY_MATERIAL = new THREE.MeshStandardMaterial({
|
|
29
|
+
color: CARDBOARD_COLOR,
|
|
30
|
+
metalness: 0,
|
|
31
|
+
roughness: 0.9
|
|
32
|
+
})
|
|
33
|
+
const PARCEL_TAPE_MATERIAL = new THREE.MeshStandardMaterial({
|
|
34
|
+
color: TAPE_COLOR,
|
|
35
|
+
metalness: 0.05,
|
|
36
|
+
roughness: 0.5
|
|
37
|
+
})
|
|
38
|
+
const PARCEL_LABEL_MATERIAL = new THREE.MeshStandardMaterial({
|
|
39
|
+
color: LABEL_COLOR,
|
|
40
|
+
metalness: 0,
|
|
41
|
+
roughness: 0.4
|
|
42
|
+
})
|
|
43
|
+
|
|
24
44
|
export class Parcel3D extends RealObjectGroup {
|
|
25
45
|
build() {
|
|
26
46
|
super.build()
|
|
@@ -30,12 +50,7 @@ export class Parcel3D extends RealObjectGroup {
|
|
|
30
50
|
|
|
31
51
|
// ── Main body ────────────────────────────────────────────────────
|
|
32
52
|
const bodyGeo = new THREE.BoxGeometry(width, depth, height)
|
|
33
|
-
const
|
|
34
|
-
color: CARDBOARD_COLOR,
|
|
35
|
-
metalness: 0,
|
|
36
|
-
roughness: 0.9
|
|
37
|
-
})
|
|
38
|
-
const bodyMesh = new THREE.Mesh(bodyGeo, bodyMaterial)
|
|
53
|
+
const bodyMesh = new THREE.Mesh(bodyGeo, PARCEL_BODY_MATERIAL)
|
|
39
54
|
bodyMesh.position.set(0, 0, 0)
|
|
40
55
|
bodyMesh.castShadow = true
|
|
41
56
|
bodyMesh.receiveShadow = true
|
|
@@ -48,12 +63,7 @@ export class Parcel3D extends RealObjectGroup {
|
|
|
48
63
|
const tapeGeo = tapeAlongLong
|
|
49
64
|
? new THREE.BoxGeometry(width * 1.005, tapeT, tapeW)
|
|
50
65
|
: new THREE.BoxGeometry(tapeW, tapeT, height * 1.005)
|
|
51
|
-
const
|
|
52
|
-
color: TAPE_COLOR,
|
|
53
|
-
metalness: 0.05,
|
|
54
|
-
roughness: 0.5
|
|
55
|
-
})
|
|
56
|
-
const tapeMesh = new THREE.Mesh(tapeGeo, tapeMaterial)
|
|
66
|
+
const tapeMesh = new THREE.Mesh(tapeGeo, PARCEL_TAPE_MATERIAL)
|
|
57
67
|
tapeMesh.position.set(0, baseY + depth + tapeT / 2 - 0.01, 0)
|
|
58
68
|
this.object3d.add(tapeMesh)
|
|
59
69
|
|
|
@@ -61,12 +71,7 @@ export class Parcel3D extends RealObjectGroup {
|
|
|
61
71
|
const labelW = Math.min(width, height) * 0.35
|
|
62
72
|
const labelH = labelW * 0.6
|
|
63
73
|
const labelGeo = new THREE.BoxGeometry(labelW, depth * 0.005, labelH)
|
|
64
|
-
const
|
|
65
|
-
color: LABEL_COLOR,
|
|
66
|
-
metalness: 0,
|
|
67
|
-
roughness: 0.4
|
|
68
|
-
})
|
|
69
|
-
const labelMesh = new THREE.Mesh(labelGeo, labelMaterial)
|
|
74
|
+
const labelMesh = new THREE.Mesh(labelGeo, PARCEL_LABEL_MATERIAL)
|
|
70
75
|
// Position on top, off-center by ~25% of long axis
|
|
71
76
|
if (tapeAlongLong) {
|
|
72
77
|
labelMesh.position.set(width * 0.2, baseY + depth + depth * 0.0025, -height * 0.15)
|
package/src/parcel.ts
CHANGED
|
@@ -93,9 +93,10 @@ export default class Parcel extends Carriable(Placeable(RectPath(Shape))) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
|
-
* Phase H — pickup contract. Parcel
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* Phase H — pickup contract. Parcel 의 pickup 방식:
|
|
97
|
+
* - gripper (vacuum / suction): 위에서 흡착 — RobotArm
|
|
98
|
+
* - agv-deck: AGV/Forklift 의 deck 위에 위에서 얹기 — 같은 top approach 지만
|
|
99
|
+
* deck 자체가 운반체라 tolerance 더 완화
|
|
99
100
|
*/
|
|
100
101
|
pickupFrames(): PickupFrame[] {
|
|
101
102
|
const wp = getWorldPose(this)
|
|
@@ -109,11 +110,29 @@ export default class Parcel extends Carriable(Placeable(RectPath(Shape))) {
|
|
|
109
110
|
topApproachFrame({
|
|
110
111
|
carrierWorld: me,
|
|
111
112
|
topY: parcelDepth,
|
|
112
|
-
approachDistance: 80,
|
|
113
|
+
approachDistance: 80,
|
|
113
114
|
toolType: 'gripper',
|
|
114
|
-
tolerance: { positionMm: 10, angleDeg: 2 },
|
|
115
|
+
tolerance: { positionMm: 10, angleDeg: 2 },
|
|
115
116
|
priority: 0,
|
|
116
117
|
id: 'top-suction'
|
|
118
|
+
}),
|
|
119
|
+
topApproachFrame({
|
|
120
|
+
carrierWorld: me,
|
|
121
|
+
topY: parcelDepth,
|
|
122
|
+
approachDistance: 60,
|
|
123
|
+
toolType: 'agv-deck',
|
|
124
|
+
tolerance: { positionMm: 20, angleDeg: 5 },
|
|
125
|
+
priority: 1,
|
|
126
|
+
id: 'top-deck'
|
|
127
|
+
}),
|
|
128
|
+
topApproachFrame({
|
|
129
|
+
carrierWorld: me,
|
|
130
|
+
topY: parcelDepth,
|
|
131
|
+
approachDistance: 100, // crane fork 가 cell 진입 hover
|
|
132
|
+
toolType: 'forklift-fork',
|
|
133
|
+
tolerance: { positionMm: 30, angleDeg: 5 }, // fork 적재 tolerance
|
|
134
|
+
priority: 2, // gripper/deck 다음
|
|
135
|
+
id: 'top-fork'
|
|
117
136
|
})
|
|
118
137
|
]
|
|
119
138
|
}
|