@operato/scene-storage 10.0.0-beta.32 → 10.0.0-beta.34
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 +22 -0
- package/dist/crane-3d.d.ts +14 -0
- package/dist/crane-3d.js +238 -0
- package/dist/crane-3d.js.map +1 -0
- package/dist/crane.d.ts +157 -0
- package/dist/crane.js +440 -0
- package/dist/crane.js.map +1 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/mobile-storage-rack.d.ts +17 -0
- package/dist/mobile-storage-rack.js +55 -0
- package/dist/mobile-storage-rack.js.map +1 -0
- package/dist/rack-column.d.ts +35 -0
- package/dist/rack-column.js +258 -0
- package/dist/rack-column.js.map +1 -0
- package/dist/rack-grid-3d.d.ts +13 -0
- package/dist/rack-grid-3d.js +94 -0
- package/dist/rack-grid-3d.js.map +1 -0
- package/dist/rack-grid-cell.d.ts +341 -0
- package/dist/rack-grid-cell.js +321 -0
- package/dist/rack-grid-cell.js.map +1 -0
- package/dist/rack-grid-helpers.d.ts +28 -0
- package/dist/rack-grid-helpers.js +71 -0
- package/dist/rack-grid-helpers.js.map +1 -0
- package/dist/rack-grid-location.d.ts +37 -0
- package/dist/rack-grid-location.js +227 -0
- package/dist/rack-grid-location.js.map +1 -0
- package/dist/rack-grid.d.ts +80 -0
- package/dist/rack-grid.js +829 -0
- package/dist/rack-grid.js.map +1 -0
- package/dist/stock.d.ts +78 -0
- package/dist/stock.js +333 -0
- package/dist/stock.js.map +1 -0
- package/dist/{rack-cell-3d.d.ts → storage-cell-3d.d.ts} +1 -1
- package/dist/{rack-cell-3d.js → storage-cell-3d.js} +3 -3
- package/dist/storage-cell-3d.js.map +1 -0
- package/dist/{rack-cell.d.ts → storage-cell.d.ts} +12 -6
- package/dist/{rack-cell.js → storage-cell.js} +9 -9
- package/dist/storage-cell.js.map +1 -0
- package/dist/{asrs-rack-3d.d.ts → storage-rack-3d.d.ts} +1 -1
- package/dist/{asrs-rack-3d.js → storage-rack-3d.js} +4 -4
- package/dist/storage-rack-3d.js.map +1 -0
- package/dist/{asrs-rack.d.ts → storage-rack.d.ts} +22 -16
- package/dist/{asrs-rack.js → storage-rack.js} +32 -26
- package/dist/storage-rack.js.map +1 -0
- package/dist/templates/index.d.ts +60 -0
- package/dist/templates/index.js +59 -17
- package/dist/templates/index.js.map +1 -1
- package/package.json +3 -3
- package/src/crane-3d.ts +273 -0
- package/src/crane.ts +538 -0
- package/src/index.ts +13 -6
- package/src/mobile-storage-rack.ts +56 -0
- package/src/rack-column.ts +340 -0
- package/src/rack-grid-3d.ts +128 -0
- package/src/rack-grid-cell.ts +404 -0
- package/src/rack-grid-helpers.ts +77 -0
- package/src/rack-grid-location.ts +286 -0
- package/src/rack-grid.ts +994 -0
- package/src/stock.ts +426 -0
- package/src/{rack-cell-3d.ts → storage-cell-3d.ts} +2 -2
- package/src/{rack-cell.ts → storage-cell.ts} +19 -13
- package/src/{asrs-rack-3d.ts → storage-rack-3d.ts} +3 -3
- package/src/{asrs-rack.ts → storage-rack.ts} +31 -25
- package/src/templates/index.ts +59 -17
- package/test/test-rack-grid-crane.ts +212 -0
- package/test/test-rack-grid.ts +77 -0
- package/test/{test-asrs-crane.ts → test-storage-rack-crane.ts} +8 -8
- package/translations/en.json +55 -7
- package/translations/ja.json +52 -4
- package/translations/ko.json +52 -4
- package/translations/ms.json +55 -7
- package/translations/zh.json +52 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/asrs-crane-3d.d.ts +0 -17
- package/dist/asrs-crane-3d.js +0 -181
- package/dist/asrs-crane-3d.js.map +0 -1
- package/dist/asrs-crane.d.ts +0 -98
- package/dist/asrs-crane.js +0 -216
- package/dist/asrs-crane.js.map +0 -1
- package/dist/asrs-rack-3d.js.map +0 -1
- package/dist/asrs-rack.js.map +0 -1
- package/dist/rack-cell-3d.js.map +0 -1
- package/dist/rack-cell.js.map +0 -1
- package/src/asrs-crane-3d.ts +0 -211
- package/src/asrs-crane.ts +0 -275
- /package/icons/{asrs-crane.png → crane.png} +0 -0
- /package/icons/{asrs-rack.png → storage-rack.png} +0 -0
package/dist/templates/index.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* things-scene catalog templates for the storage domain
|
|
3
|
-
*
|
|
2
|
+
* things-scene catalog templates for the storage domain.
|
|
3
|
+
*
|
|
4
|
+
* Components:
|
|
5
|
+
* - pallet / box / parcel — carriers
|
|
6
|
+
* - rack — multi-level storage shelf (bays × levels)
|
|
7
|
+
* - rack-table — bulk layout (rows × columns × shelves) helper
|
|
8
|
+
* - crane — stacker picker (Mover + CarrierHolder + ContainerCapacity)
|
|
9
|
+
* - mobile-rack — Mover(Rack), an AGV-mounted / cart-mounted moving rack
|
|
10
|
+
* - spot — virtual placement marker
|
|
4
11
|
*/
|
|
5
12
|
import spot from './spot.js';
|
|
6
13
|
const pallet = new URL('../../icons/pallet.png', import.meta.url).href;
|
|
7
14
|
const box = new URL('../../icons/box.png', import.meta.url).href;
|
|
8
15
|
const parcel = new URL('../../icons/parcel.png', import.meta.url).href;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
16
|
+
const rack = new URL('../../icons/storage-rack.png', import.meta.url).href;
|
|
17
|
+
const crane = new URL('../../icons/crane.png', import.meta.url).href;
|
|
11
18
|
export default [
|
|
12
19
|
{
|
|
13
20
|
type: 'pallet',
|
|
@@ -79,12 +86,12 @@ export default [
|
|
|
79
86
|
}
|
|
80
87
|
},
|
|
81
88
|
{
|
|
82
|
-
type: '
|
|
83
|
-
description: '
|
|
89
|
+
type: 'storage-rack',
|
|
90
|
+
description: 'storage rack — multi-level shelves',
|
|
84
91
|
group: 'storage',
|
|
85
|
-
icon:
|
|
92
|
+
icon: rack,
|
|
86
93
|
model: {
|
|
87
|
-
type: '
|
|
94
|
+
type: 'storage-rack',
|
|
88
95
|
top: 300,
|
|
89
96
|
left: 100,
|
|
90
97
|
width: 800,
|
|
@@ -94,12 +101,32 @@ export default [
|
|
|
94
101
|
}
|
|
95
102
|
},
|
|
96
103
|
{
|
|
97
|
-
type: '
|
|
98
|
-
description: '
|
|
104
|
+
type: 'rack-grid',
|
|
105
|
+
description: 'rack table — N×M rack layout + auto location IDs',
|
|
99
106
|
group: 'storage',
|
|
100
|
-
icon:
|
|
107
|
+
icon: rack,
|
|
101
108
|
model: {
|
|
102
|
-
type: '
|
|
109
|
+
type: 'rack-grid',
|
|
110
|
+
top: 100,
|
|
111
|
+
left: 100,
|
|
112
|
+
width: 1200,
|
|
113
|
+
height: 600,
|
|
114
|
+
rows: 2,
|
|
115
|
+
columns: 4,
|
|
116
|
+
shelves: 4,
|
|
117
|
+
zone: 'A',
|
|
118
|
+
locPattern: '{z}{s}-{u}-{sh}',
|
|
119
|
+
sectionDigits: 2,
|
|
120
|
+
unitDigits: 2
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: 'crane',
|
|
125
|
+
description: 'stacker crane — picker actor',
|
|
126
|
+
group: 'storage',
|
|
127
|
+
icon: crane,
|
|
128
|
+
model: {
|
|
129
|
+
type: 'crane',
|
|
103
130
|
top: 550,
|
|
104
131
|
left: 400,
|
|
105
132
|
width: 100,
|
|
@@ -108,11 +135,26 @@ export default [
|
|
|
108
135
|
carriageHeight: 100
|
|
109
136
|
}
|
|
110
137
|
},
|
|
138
|
+
{
|
|
139
|
+
type: 'mobile-storage-rack',
|
|
140
|
+
description: 'mobile rack — Mover(Rack), AGV/cart-mounted',
|
|
141
|
+
group: 'storage',
|
|
142
|
+
icon: rack,
|
|
143
|
+
model: {
|
|
144
|
+
type: 'mobile-storage-rack',
|
|
145
|
+
top: 300,
|
|
146
|
+
left: 100,
|
|
147
|
+
width: 400,
|
|
148
|
+
height: 200,
|
|
149
|
+
levels: 3,
|
|
150
|
+
bays: 3
|
|
151
|
+
}
|
|
152
|
+
},
|
|
111
153
|
{
|
|
112
154
|
type: 'group',
|
|
113
|
-
description: '
|
|
155
|
+
description: 'storage aisle — rack pair + crane',
|
|
114
156
|
group: 'storage',
|
|
115
|
-
icon:
|
|
157
|
+
icon: rack,
|
|
116
158
|
model: {
|
|
117
159
|
type: 'group',
|
|
118
160
|
top: 100,
|
|
@@ -121,7 +163,7 @@ export default [
|
|
|
121
163
|
height: 220,
|
|
122
164
|
components: [
|
|
123
165
|
{
|
|
124
|
-
type: '
|
|
166
|
+
type: 'storage-rack',
|
|
125
167
|
top: 100,
|
|
126
168
|
left: 100,
|
|
127
169
|
width: 800,
|
|
@@ -130,7 +172,7 @@ export default [
|
|
|
130
172
|
bays: 8
|
|
131
173
|
},
|
|
132
174
|
{
|
|
133
|
-
type: '
|
|
175
|
+
type: 'crane',
|
|
134
176
|
top: 140,
|
|
135
177
|
left: 420,
|
|
136
178
|
width: 60,
|
|
@@ -139,7 +181,7 @@ export default [
|
|
|
139
181
|
carriageHeight: 0
|
|
140
182
|
},
|
|
141
183
|
{
|
|
142
|
-
type: '
|
|
184
|
+
type: 'storage-rack',
|
|
143
185
|
top: 320,
|
|
144
186
|
left: 100,
|
|
145
187
|
width: 800,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * things-scene catalog templates for the storage domain.\n *\n * Components:\n * - pallet / box / parcel — carriers\n * - rack — multi-level storage shelf (bays × levels)\n * - rack-table — bulk layout (rows × columns × shelves) helper\n * - crane — stacker picker (Mover + CarrierHolder + ContainerCapacity)\n * - mobile-rack — Mover(Rack), an AGV-mounted / cart-mounted moving rack\n * - spot — virtual placement marker\n */\nimport spot from './spot.js'\nconst pallet = new URL('../../icons/pallet.png', import.meta.url).href\nconst box = new URL('../../icons/box.png', import.meta.url).href\nconst parcel = new URL('../../icons/parcel.png', import.meta.url).href\nconst rack = new URL('../../icons/storage-rack.png', import.meta.url).href\nconst crane = new URL('../../icons/crane.png', import.meta.url).href\n\nexport default [\n {\n type: 'pallet',\n description: 'wood pallet (EUR / EPAL)',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 100,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'pallet',\n description: 'plastic pallet',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 250,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'box',\n description: 'wood crate',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 400,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'box',\n description: 'plastic tote',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 520,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'parcel',\n description: 'cardboard parcel',\n group: 'storage',\n icon: parcel,\n model: {\n type: 'parcel',\n top: 100,\n left: 640,\n width: 60,\n height: 80\n }\n },\n {\n type: 'storage-rack',\n description: 'storage rack — multi-level shelves',\n group: 'storage',\n icon: rack,\n model: {\n type: 'storage-rack',\n top: 300,\n left: 100,\n width: 800,\n height: 200,\n levels: 4,\n bays: 5\n }\n },\n {\n type: 'rack-grid',\n description: 'rack table — N×M rack layout + auto location IDs',\n group: 'storage',\n icon: rack,\n model: {\n type: 'rack-grid',\n top: 100,\n left: 100,\n width: 1200,\n height: 600,\n rows: 2,\n columns: 4,\n shelves: 4,\n zone: 'A',\n locPattern: '{z}{s}-{u}-{sh}',\n sectionDigits: 2,\n unitDigits: 2\n }\n },\n {\n type: 'crane',\n description: 'stacker crane — picker actor',\n group: 'storage',\n icon: crane,\n model: {\n type: 'crane',\n top: 550,\n left: 400,\n width: 100,\n height: 200,\n status: 'idle',\n carriageHeight: 100\n }\n },\n {\n type: 'mobile-storage-rack',\n description: 'mobile rack — Mover(Rack), AGV/cart-mounted',\n group: 'storage',\n icon: rack,\n model: {\n type: 'mobile-storage-rack',\n top: 300,\n left: 100,\n width: 400,\n height: 200,\n levels: 3,\n bays: 3\n }\n },\n {\n type: 'group',\n description: 'storage aisle — rack pair + crane',\n group: 'storage',\n icon: rack,\n model: {\n type: 'group',\n top: 100,\n left: 100,\n width: 840,\n height: 220,\n components: [\n {\n type: 'storage-rack',\n top: 100,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n },\n {\n type: 'crane',\n top: 140,\n left: 420,\n width: 60,\n height: 220,\n status: 'idle',\n carriageHeight: 0\n },\n {\n type: 'storage-rack',\n top: 320,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n }\n ]\n }\n },\n spot\n]\n"]}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/scene-storage",
|
|
3
3
|
"description": "Storage-domain components for things-scene (smart factory / logistics) — pallet, box, parcel; AS/RS and shelves planned.",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "10.0.0-beta.
|
|
5
|
+
"version": "10.0.0-beta.34",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@hatiolab/things-scene": "^10.0.0-beta.1",
|
|
29
|
-
"@operato/scene-base": "^10.0.0-beta.
|
|
29
|
+
"@operato/scene-base": "^10.0.0-beta.33",
|
|
30
30
|
"three": "^0.183.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"typescript": "^5.0.4"
|
|
46
46
|
},
|
|
47
47
|
"prettier": "@hatiolab/prettier-config",
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "07e3c36c043a6225ea2686dee96357a605f0812f"
|
|
49
49
|
}
|
package/src/crane-3d.ts
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Crane 3D — heavy-duty pallet AS/RS stacker crane (twin-mast).
|
|
5
|
+
*
|
|
6
|
+
* Axis convention (things-scene 3D):
|
|
7
|
+
* +X = aisle 진행 방향 (Crane 좌우 이동, *옆으로 길게* 축)
|
|
8
|
+
* +Y = 수직 (Crane 키, carriage 상하 이동)
|
|
9
|
+
* +Z = aisle 폭 방향 (Rack cell 쪽 / fork 신축 방향)
|
|
10
|
+
*
|
|
11
|
+
* **스케일 룰**:
|
|
12
|
+
* - 모든 가로(X,Z) dimension 과 Y 두께 → 2D footprint (state.width, state.height) 비례
|
|
13
|
+
* - Mast Y 길이만 → state.depth 사용 (수직 키)
|
|
14
|
+
* - Y 두께는 절대 depth (크레인 키) 에 비례 안 함 → 키워도 뭉치 안 두꺼워짐
|
|
15
|
+
* - mm/cm/scene-unit 무관 — 사용자의 footprint 스케일에 자동 맞춤
|
|
16
|
+
*
|
|
17
|
+
* 부품:
|
|
18
|
+
* [Ceiling rail]
|
|
19
|
+
* [Top guide trolley] — 천장 rail 위
|
|
20
|
+
* [Top frame] — 두 mast 상부 연결
|
|
21
|
+
* [Mast L][Mast R] — twin yellow column (X 축으로 떨어져 있음)
|
|
22
|
+
* [Carriage] — 두 mast 사이 가로 frame (carriageHeight 로 상하)
|
|
23
|
+
* └── [Two forks] — carriage 에서 ±Z 신축 (forkExtension)
|
|
24
|
+
* [Base trolley] — 바닥 motor housing (X 길게)
|
|
25
|
+
* └── [Cabinet] — base 한쪽 red 컨트롤박스
|
|
26
|
+
* └── [Status lamp]
|
|
27
|
+
* [Floor rail]
|
|
28
|
+
*
|
|
29
|
+
* Actuators (state):
|
|
30
|
+
* carriageHeight, forkExtension (±), forkLift
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import * as THREE from 'three'
|
|
34
|
+
import { RealObjectGroup } from '@hatiolab/things-scene'
|
|
35
|
+
|
|
36
|
+
const MAST_COLOR = 0xff7a00 // mast — orange
|
|
37
|
+
const TROLLEY_COLOR = 0x3a4048 // base / top — dark charcoal
|
|
38
|
+
const CARRIAGE_COLOR = 0xffcc00 // carriage (shuttle) — yellow
|
|
39
|
+
const CONTROLLER_COLOR = 0xc63333 // cabinet — red
|
|
40
|
+
const FORK_COLOR = 0xffcc00 // fork — yellow (same as carriage)
|
|
41
|
+
const RAIL_COLOR = 0x1a1f24 // rail — dark steel
|
|
42
|
+
const LAMP_OFF = 0x222222
|
|
43
|
+
|
|
44
|
+
export class Crane3D extends RealObjectGroup {
|
|
45
|
+
private _forkGroup?: THREE.Group
|
|
46
|
+
private _forkTopY: number = 0
|
|
47
|
+
private _bladeMidZ: number = 0
|
|
48
|
+
|
|
49
|
+
build() {
|
|
50
|
+
super.build()
|
|
51
|
+
|
|
52
|
+
this._forkGroup = undefined
|
|
53
|
+
this._forkTopY = 0
|
|
54
|
+
this._bladeMidZ = 0
|
|
55
|
+
|
|
56
|
+
const { width, height, depth } = this.component.state
|
|
57
|
+
const emissiveColor = (this.component.state.lampEmissive as string) || '#222222'
|
|
58
|
+
const status = this.component.state.status
|
|
59
|
+
const lampOn = status && status !== 'idle'
|
|
60
|
+
|
|
61
|
+
// Actuators
|
|
62
|
+
const D = numOr(depth, Math.max(width, height) * 4)
|
|
63
|
+
const carriageRaw = numOr((this.component.state as any).carriageHeight, D * 0.4)
|
|
64
|
+
const carriageHeight = Math.max(0, Math.min(carriageRaw, D * 0.85))
|
|
65
|
+
|
|
66
|
+
const forkLength = numOr((this.component.state as any).forkLength, height * 0.6)
|
|
67
|
+
const forkExtensionRaw = numOr((this.component.state as any).forkExtension, 0)
|
|
68
|
+
const forkExtension = Math.max(-forkLength, Math.min(forkLength, forkExtensionRaw))
|
|
69
|
+
const forkLift = numOr((this.component.state as any).forkLift, 0)
|
|
70
|
+
|
|
71
|
+
// ── Axis convention (FIXED): ─────────────────────────────────────
|
|
72
|
+
// Rail = X (state.left = 2D X = 3D X). Crane 좌우 이동.
|
|
73
|
+
// Fork = Z (2D Y = 3D Z). Fork 앞뒤 신축.
|
|
74
|
+
// 사용자: "포크는 앞뒤로, 크레인 본체는 좌우로."
|
|
75
|
+
// width = rail-direction 풋프린트 (좁음)
|
|
76
|
+
// height = cross-aisle (fork 방향) 풋프린트 (깊음, fork 가 cell 까지 닿는 거리)
|
|
77
|
+
const S = Math.min(width, height)
|
|
78
|
+
const railH = S * 0.04
|
|
79
|
+
const baseH = S * 0.18
|
|
80
|
+
const topFrameH = S * 0.1
|
|
81
|
+
const topGuideH = S * 0.1
|
|
82
|
+
const carriageH = S * 0.12
|
|
83
|
+
const mastW = width * 0.1 // mast X 단면 (along rail)
|
|
84
|
+
const mastD = height * 0.25 // mast Z 단면 (cross-rail)
|
|
85
|
+
const mastSpacing = width * 0.7 // 두 mast X 간격
|
|
86
|
+
const bladeW = S * 0.1
|
|
87
|
+
const bladeH = S * 0.05
|
|
88
|
+
const bladeL = forkLength
|
|
89
|
+
const bladeSpacing = mastSpacing * 0.45
|
|
90
|
+
const carriageW = mastSpacing - mastW * 0.2
|
|
91
|
+
const carriageZ = height * 0.55
|
|
92
|
+
const cabW = S * 0.4
|
|
93
|
+
const cabH = S * 0.4
|
|
94
|
+
const cabD = S * 0.3
|
|
95
|
+
|
|
96
|
+
const baseY = -D / 2
|
|
97
|
+
const mastH = Math.max(D - railH * 2 - baseH - topFrameH - topGuideH, S * 0.5)
|
|
98
|
+
|
|
99
|
+
// ── Materials ─────────────────────────────────────────────────────
|
|
100
|
+
const mastMat = new THREE.MeshStandardMaterial({ color: MAST_COLOR, metalness: 0.3, roughness: 0.5 })
|
|
101
|
+
const trolleyMat = new THREE.MeshStandardMaterial({ color: TROLLEY_COLOR, metalness: 0.6, roughness: 0.5 })
|
|
102
|
+
const carriageMat = new THREE.MeshStandardMaterial({ color: CARRIAGE_COLOR, metalness: 0.85, roughness: 0.35 })
|
|
103
|
+
const cabinetMat = new THREE.MeshStandardMaterial({ color: CONTROLLER_COLOR, metalness: 0.2, roughness: 0.6 })
|
|
104
|
+
const forkMat = new THREE.MeshStandardMaterial({ color: FORK_COLOR, metalness: 0.85, roughness: 0.3 })
|
|
105
|
+
const railMat = new THREE.MeshStandardMaterial({ color: RAIL_COLOR, metalness: 0.9, roughness: 0.3 })
|
|
106
|
+
|
|
107
|
+
// ── Floor rail ────────────────────────────────────────────────────
|
|
108
|
+
{
|
|
109
|
+
const geo = new THREE.BoxGeometry(width * 1.1, railH, height * 0.35)
|
|
110
|
+
const mesh = new THREE.Mesh(geo, railMat)
|
|
111
|
+
mesh.position.set(0, baseY + railH / 2, 0)
|
|
112
|
+
mesh.receiveShadow = true
|
|
113
|
+
this.object3d.add(mesh)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── Base trolley ──────────────────────────────────────────────────
|
|
117
|
+
const baseTrolleyY = baseY + railH + baseH / 2
|
|
118
|
+
{
|
|
119
|
+
const geo = new THREE.BoxGeometry(width * 0.95, baseH, height * 0.7)
|
|
120
|
+
const mesh = new THREE.Mesh(geo, trolleyMat)
|
|
121
|
+
mesh.position.set(0, baseTrolleyY, 0)
|
|
122
|
+
mesh.castShadow = true
|
|
123
|
+
mesh.receiveShadow = true
|
|
124
|
+
this.object3d.add(mesh)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── Control cabinet on one side of base ───────────────────────────
|
|
128
|
+
{
|
|
129
|
+
const geo = new THREE.BoxGeometry(cabW, cabH, cabD)
|
|
130
|
+
const cab = new THREE.Mesh(geo, cabinetMat)
|
|
131
|
+
cab.position.set(
|
|
132
|
+
-width * 0.4 + cabW / 2,
|
|
133
|
+
baseTrolleyY + baseH / 2 + cabH / 2,
|
|
134
|
+
-height * 0.25 + cabD / 2
|
|
135
|
+
)
|
|
136
|
+
cab.castShadow = true
|
|
137
|
+
this.object3d.add(cab)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── Status lamp ───────────────────────────────────────────────────
|
|
141
|
+
{
|
|
142
|
+
const lampR = S * 0.04
|
|
143
|
+
const lampH = S * 0.1
|
|
144
|
+
const lampMat = new THREE.MeshStandardMaterial({
|
|
145
|
+
color: lampOn ? emissiveColor : LAMP_OFF,
|
|
146
|
+
emissive: lampOn ? emissiveColor : LAMP_OFF,
|
|
147
|
+
emissiveIntensity: lampOn ? 1.5 : 0.2,
|
|
148
|
+
metalness: 0,
|
|
149
|
+
roughness: 0.3
|
|
150
|
+
})
|
|
151
|
+
const geo = new THREE.CylinderGeometry(lampR, lampR * 0.8, lampH, 12)
|
|
152
|
+
const lamp = new THREE.Mesh(geo, lampMat)
|
|
153
|
+
lamp.position.set(width * 0.4, baseTrolleyY + baseH / 2 + lampH / 2, 0)
|
|
154
|
+
this.object3d.add(lamp)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Twin masts ────────────────────────────────────────────────────
|
|
158
|
+
const mastY = baseTrolleyY + baseH / 2 + mastH / 2
|
|
159
|
+
for (const xOff of [-mastSpacing / 2, +mastSpacing / 2]) {
|
|
160
|
+
const geo = new THREE.BoxGeometry(mastW, mastH, mastD)
|
|
161
|
+
const mesh = new THREE.Mesh(geo, mastMat)
|
|
162
|
+
mesh.position.set(xOff, mastY, 0)
|
|
163
|
+
mesh.castShadow = true
|
|
164
|
+
mesh.receiveShadow = true
|
|
165
|
+
this.object3d.add(mesh)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ── Carriage (between masts) ──────────────────────────────────────
|
|
169
|
+
const carriageY = baseTrolleyY + baseH / 2 + carriageHeight + carriageH / 2
|
|
170
|
+
{
|
|
171
|
+
const geo = new THREE.BoxGeometry(carriageW, carriageH, carriageZ)
|
|
172
|
+
const mesh = new THREE.Mesh(geo, carriageMat)
|
|
173
|
+
mesh.position.set(0, carriageY, 0)
|
|
174
|
+
mesh.castShadow = true
|
|
175
|
+
mesh.receiveShadow = true
|
|
176
|
+
this.object3d.add(mesh)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ── Two-prong forks (telescopic ±Z) ───────────────────────────────
|
|
180
|
+
// forkExtension 부호: + = +Z, - = -Z. forkExtension=0 일 때 blade 중심이 carriage 안쪽
|
|
181
|
+
// (= retracted, blade tip 이 carriage 앞면 근처).
|
|
182
|
+
const forkSign = forkExtension >= 0 ? 1 : -1
|
|
183
|
+
const forkBaseZ = forkSign * (carriageZ / 2 - bladeL / 2 + Math.abs(forkExtension))
|
|
184
|
+
const forkY = carriageY + forkLift - bladeH / 2
|
|
185
|
+
{
|
|
186
|
+
const group = new THREE.Group()
|
|
187
|
+
group.position.set(0, forkY, forkBaseZ)
|
|
188
|
+
// forkSign 으로 blade tip 방향 설정
|
|
189
|
+
group.rotation.y = forkSign < 0 ? Math.PI : 0
|
|
190
|
+
|
|
191
|
+
for (const xOff of [-bladeSpacing / 2, +bladeSpacing / 2]) {
|
|
192
|
+
const geo = new THREE.BoxGeometry(bladeW, bladeH, bladeL)
|
|
193
|
+
const mesh = new THREE.Mesh(geo, forkMat)
|
|
194
|
+
mesh.position.set(xOff, 0, 0)
|
|
195
|
+
mesh.castShadow = true
|
|
196
|
+
mesh.receiveShadow = true
|
|
197
|
+
group.add(mesh)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this.object3d.add(group)
|
|
201
|
+
this._forkGroup = group
|
|
202
|
+
this._forkTopY = bladeH / 2
|
|
203
|
+
this._bladeMidZ = 0
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ── Top frame (connects mast tops) ────────────────────────────────
|
|
207
|
+
const topFrameY = mastY + mastH / 2 + topFrameH / 2
|
|
208
|
+
{
|
|
209
|
+
const geo = new THREE.BoxGeometry(mastSpacing + mastW, topFrameH, height * 0.35)
|
|
210
|
+
const mesh = new THREE.Mesh(geo, trolleyMat)
|
|
211
|
+
mesh.position.set(0, topFrameY, 0)
|
|
212
|
+
mesh.castShadow = true
|
|
213
|
+
this.object3d.add(mesh)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ── Top guide trolley ─────────────────────────────────────────────
|
|
217
|
+
const topGuideY = topFrameY + topFrameH / 2 + topGuideH / 2
|
|
218
|
+
{
|
|
219
|
+
const geo = new THREE.BoxGeometry(mastSpacing + mastW * 2, topGuideH, height * 0.3)
|
|
220
|
+
const mesh = new THREE.Mesh(geo, trolleyMat)
|
|
221
|
+
mesh.position.set(0, topGuideY, 0)
|
|
222
|
+
mesh.castShadow = true
|
|
223
|
+
this.object3d.add(mesh)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── Ceiling rail ──────────────────────────────────────────────────
|
|
227
|
+
{
|
|
228
|
+
const geo = new THREE.BoxGeometry(width * 1.1, railH, height * 0.3)
|
|
229
|
+
const mesh = new THREE.Mesh(geo, railMat)
|
|
230
|
+
mesh.position.set(0, topGuideY + topGuideH / 2 + railH / 2, 0)
|
|
231
|
+
this.object3d.add(mesh)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
getCarriageFrame(): THREE.Object3D | undefined {
|
|
236
|
+
return this._forkGroup ?? this.object3d
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
get platformTopY(): number {
|
|
240
|
+
return this._forkTopY
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
get bladeMidZ(): number {
|
|
244
|
+
return this._bladeMidZ
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
updateDimension() {}
|
|
248
|
+
|
|
249
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
250
|
+
if (
|
|
251
|
+
'width' in after ||
|
|
252
|
+
'height' in after ||
|
|
253
|
+
'depth' in after ||
|
|
254
|
+
'carriageHeight' in after ||
|
|
255
|
+
'forkLength' in after ||
|
|
256
|
+
'forkExtension' in after ||
|
|
257
|
+
'forkLift' in after ||
|
|
258
|
+
'status' in after ||
|
|
259
|
+
'bodyColor' in after ||
|
|
260
|
+
'lampEmissive' in after
|
|
261
|
+
) {
|
|
262
|
+
this.update()
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
super.onchange(after, before)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
updateAlpha() {}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function numOr(v: unknown, dflt: number): number {
|
|
272
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : dflt
|
|
273
|
+
}
|