@operato/scene-storage 10.0.0-beta.27 → 10.0.0-beta.30
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 +24 -0
- package/dist/asrs-crane-3d.d.ts +10 -0
- package/dist/asrs-crane-3d.js +17 -0
- package/dist/asrs-crane-3d.js.map +1 -1
- package/dist/asrs-crane.d.ts +49 -13
- package/dist/asrs-crane.js +120 -16
- package/dist/asrs-crane.js.map +1 -1
- package/dist/asrs-rack.d.ts +49 -19
- package/dist/asrs-rack.js +108 -20
- package/dist/asrs-rack.js.map +1 -1
- package/dist/box.d.ts +3 -3
- package/dist/box.js +1 -2
- package/dist/box.js.map +1 -1
- package/dist/generic-container.d.ts +2 -2
- package/dist/generic-container.js +1 -2
- package/dist/generic-container.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/pallet.d.ts +2 -2
- package/dist/pallet.js +1 -2
- package/dist/pallet.js.map +1 -1
- package/dist/parcel.d.ts +3 -3
- package/dist/parcel.js +1 -2
- package/dist/parcel.js.map +1 -1
- package/dist/rack-cell-3d.d.ts +25 -0
- package/dist/rack-cell-3d.js +88 -0
- package/dist/rack-cell-3d.js.map +1 -0
- package/dist/rack-cell.d.ts +56 -0
- package/dist/rack-cell.js +200 -0
- package/dist/rack-cell.js.map +1 -0
- package/dist/spot.d.ts +4 -11
- package/dist/spot.js +2 -3
- package/dist/spot.js.map +1 -1
- package/dist/templates/index.d.ts +42 -0
- package/dist/templates/index.js +49 -9
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/spot.js +1 -1
- package/dist/templates/spot.js.map +1 -1
- package/icons/asrs-crane.png +0 -0
- package/icons/asrs-rack.png +0 -0
- package/icons/box.png +0 -0
- package/icons/pallet.png +0 -0
- package/icons/parcel.png +0 -0
- package/icons/spot.png +0 -0
- package/package.json +9 -4
- package/src/asrs-crane-3d.ts +20 -0
- package/src/asrs-crane.ts +137 -16
- package/src/asrs-rack.ts +119 -20
- package/src/box.ts +2 -4
- package/src/generic-container.ts +1 -3
- package/src/index.ts +3 -0
- package/src/pallet.ts +1 -3
- package/src/parcel.ts +2 -4
- package/src/rack-cell-3d.ts +101 -0
- package/src/rack-cell.ts +228 -0
- package/src/spot.ts +4 -5
- package/src/templates/index.ts +49 -9
- package/src/templates/spot.ts +1 -1
- package/test/setup.js +279 -0
- package/test/test-asrs-crane.ts +319 -0
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/icons/box-plastic.png +0 -0
- package/icons/box-wood.png +0 -0
- package/icons/pallet-plastic.png +0 -0
- package/icons/pallet-wood.png +0 -0
package/dist/templates/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* things-scene catalog templates for the storage domain — pallet/box/parcel
|
|
3
|
-
* variants, ASRS rack/crane, and the virtual `spot` placement marker.
|
|
3
|
+
* variants, ASRS rack/crane, ASRS aisle composite, and the virtual `spot` placement marker.
|
|
4
4
|
*/
|
|
5
5
|
import spot from './spot.js';
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const boxWood = new URL('../../icons/box-wood.png', import.meta.url).href;
|
|
9
|
-
const boxPlastic = new URL('../../icons/box-plastic.png', import.meta.url).href;
|
|
6
|
+
const pallet = new URL('../../icons/pallet.png', import.meta.url).href;
|
|
7
|
+
const box = new URL('../../icons/box.png', import.meta.url).href;
|
|
10
8
|
const parcel = new URL('../../icons/parcel.png', import.meta.url).href;
|
|
11
9
|
const asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href;
|
|
12
10
|
const asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href;
|
|
@@ -15,7 +13,7 @@ export default [
|
|
|
15
13
|
type: 'pallet',
|
|
16
14
|
description: 'wood pallet (EUR / EPAL)',
|
|
17
15
|
group: 'storage',
|
|
18
|
-
icon:
|
|
16
|
+
icon: pallet,
|
|
19
17
|
model: {
|
|
20
18
|
type: 'pallet',
|
|
21
19
|
top: 100,
|
|
@@ -29,7 +27,7 @@ export default [
|
|
|
29
27
|
type: 'pallet',
|
|
30
28
|
description: 'plastic pallet',
|
|
31
29
|
group: 'storage',
|
|
32
|
-
icon:
|
|
30
|
+
icon: pallet,
|
|
33
31
|
model: {
|
|
34
32
|
type: 'pallet',
|
|
35
33
|
top: 100,
|
|
@@ -43,7 +41,7 @@ export default [
|
|
|
43
41
|
type: 'box',
|
|
44
42
|
description: 'wood crate',
|
|
45
43
|
group: 'storage',
|
|
46
|
-
icon:
|
|
44
|
+
icon: box,
|
|
47
45
|
model: {
|
|
48
46
|
type: 'box',
|
|
49
47
|
top: 100,
|
|
@@ -57,7 +55,7 @@ export default [
|
|
|
57
55
|
type: 'box',
|
|
58
56
|
description: 'plastic tote',
|
|
59
57
|
group: 'storage',
|
|
60
|
-
icon:
|
|
58
|
+
icon: box,
|
|
61
59
|
model: {
|
|
62
60
|
type: 'box',
|
|
63
61
|
top: 100,
|
|
@@ -110,6 +108,48 @@ export default [
|
|
|
110
108
|
carriageHeight: 100
|
|
111
109
|
}
|
|
112
110
|
},
|
|
111
|
+
{
|
|
112
|
+
type: 'group',
|
|
113
|
+
description: 'AS/RS aisle — 4-level rack pair + stacker crane',
|
|
114
|
+
group: 'storage',
|
|
115
|
+
icon: asrsRack,
|
|
116
|
+
model: {
|
|
117
|
+
type: 'group',
|
|
118
|
+
top: 100,
|
|
119
|
+
left: 100,
|
|
120
|
+
width: 840,
|
|
121
|
+
height: 220,
|
|
122
|
+
components: [
|
|
123
|
+
{
|
|
124
|
+
type: 'asrs-rack',
|
|
125
|
+
top: 100,
|
|
126
|
+
left: 100,
|
|
127
|
+
width: 800,
|
|
128
|
+
height: 80,
|
|
129
|
+
levels: 4,
|
|
130
|
+
bays: 8
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
type: 'asrs-crane',
|
|
134
|
+
top: 140,
|
|
135
|
+
left: 420,
|
|
136
|
+
width: 60,
|
|
137
|
+
height: 220,
|
|
138
|
+
status: 'idle',
|
|
139
|
+
carriageHeight: 0
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
type: 'asrs-rack',
|
|
143
|
+
top: 320,
|
|
144
|
+
left: 100,
|
|
145
|
+
width: 800,
|
|
146
|
+
height: 80,
|
|
147
|
+
levels: 4,
|
|
148
|
+
bays: 8
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
},
|
|
113
153
|
spot
|
|
114
154
|
];
|
|
115
155
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,MAAM,
|
|
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 — pallet/box/parcel\n * variants, ASRS rack/crane, ASRS aisle composite, and the virtual `spot` 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 asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href\nconst asrsCrane = new URL('../../icons/asrs-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: 'asrs-rack',\n description: 'AS/RS storage rack (multi-level)',\n group: 'storage',\n icon: asrsRack,\n model: {\n type: 'asrs-rack',\n top: 300,\n left: 100,\n width: 800,\n height: 200,\n levels: 4,\n bays: 5\n }\n },\n {\n type: 'asrs-crane',\n description: 'AS/RS stacker crane',\n group: 'storage',\n icon: asrsCrane,\n model: {\n type: 'asrs-crane',\n top: 550,\n left: 400,\n width: 100,\n height: 200,\n status: 'idle',\n carriageHeight: 100\n }\n },\n {\n type: 'group',\n description: 'AS/RS aisle — 4-level rack pair + stacker crane',\n group: 'storage',\n icon: asrsRack,\n model: {\n type: 'group',\n top: 100,\n left: 100,\n width: 840,\n height: 220,\n components: [\n {\n type: 'asrs-rack',\n top: 100,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n },\n {\n type: 'asrs-crane',\n top: 140,\n left: 420,\n width: 60,\n height: 220,\n status: 'idle',\n carriageHeight: 0\n },\n {\n type: 'asrs-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/dist/templates/spot.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Reuse parcel.png as a placeholder icon until a dedicated spot icon is drawn.
|
|
2
|
-
const icon = new URL('../../icons/
|
|
2
|
+
const icon = new URL('../../icons/spot.png', import.meta.url).href;
|
|
3
3
|
export default {
|
|
4
4
|
type: 'spot',
|
|
5
5
|
description: 'virtual pickup / drop zone — translucent floor pad that accepts carrier components as children',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../src/templates/spot.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../src/templates/spot.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAElE,eAAe;IACb,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,gGAAgG;IAC7G,KAAK,EAAE,SAAS,CAAC,sIAAsI;IACvJ,IAAI;IACJ,KAAK,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,SAAS;QACpB,WAAW,EAAE,SAAS;QACtB,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,SAAS;QACpB,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,YAAY;QACxB,IAAI,EAAE,IAAI;KACX;CACF,CAAA","sourcesContent":["// Reuse parcel.png as a placeholder icon until a dedicated spot icon is drawn.\nconst icon = new URL('../../icons/spot.png', import.meta.url).href\n\nexport default {\n type: 'spot',\n description: 'virtual pickup / drop zone — translucent floor pad that accepts carrier components as children',\n group: 'storage' /* line|shape|textAndMedia|chartAndGauge|table|container|dataSource|3D|facility|storage|conveyance|transport|manufacturing|form|etc */,\n icon,\n model: {\n type: 'spot',\n top: 200,\n left: 400,\n width: 80,\n height: 80,\n text: 'SPOT_A',\n fillStyle: '#3a8fbd',\n strokeStyle: '#3a8fbd',\n lineWidth: 1,\n lineDash: 'dash',\n alpha: 1,\n fontColor: '#3a8fbd',\n fontSize: 16,\n fontFamily: 'sans-serif',\n bold: true\n }\n}\n"]}
|
package/icons/asrs-crane.png
CHANGED
|
Binary file
|
package/icons/asrs-rack.png
CHANGED
|
Binary file
|
package/icons/box.png
ADDED
|
Binary file
|
package/icons/pallet.png
ADDED
|
Binary file
|
package/icons/parcel.png
CHANGED
|
Binary file
|
package/icons/spot.png
ADDED
|
Binary file
|
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.30",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -21,24 +21,29 @@
|
|
|
21
21
|
"build": "tsc",
|
|
22
22
|
"prepublishOnly": "tsc",
|
|
23
23
|
"lint": "eslint src/ && prettier \"src/**/*.ts\" --check",
|
|
24
|
-
"format": "eslint src/ --fix && prettier \"src/**/*.ts\" --write"
|
|
24
|
+
"format": "eslint src/ --fix && prettier \"src/**/*.ts\" --write",
|
|
25
|
+
"test": "mocha --require should --require ./test/setup.js --node-option import=tsx \"test/**/test-*.ts\""
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@hatiolab/things-scene": "^10.0.0-beta.1",
|
|
28
|
-
"@operato/scene-base": "^10.0.0-beta.
|
|
29
|
+
"@operato/scene-base": "^10.0.0-beta.30",
|
|
29
30
|
"three": "^0.183.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@hatiolab/prettier-config": "^1.0.0",
|
|
34
|
+
"@types/mocha": "^10.0.0",
|
|
33
35
|
"@types/three": "^0.183.0",
|
|
34
36
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
35
37
|
"@typescript-eslint/parser": "^8.0.0",
|
|
36
38
|
"eslint": "^9.18.0",
|
|
37
39
|
"eslint-config-prettier": "^10.0.1",
|
|
40
|
+
"mocha": "^11.0.0",
|
|
38
41
|
"prettier": "^3.2.5",
|
|
42
|
+
"should": "^13.2.3",
|
|
39
43
|
"tslib": "^2.3.1",
|
|
44
|
+
"tsx": "^4.21.0",
|
|
40
45
|
"typescript": "^5.0.4"
|
|
41
46
|
},
|
|
42
47
|
"prettier": "@hatiolab/prettier-config",
|
|
43
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "06b35b1726ec4f27ee76657ce341c6c6f3ba1b3a"
|
|
44
49
|
}
|
package/src/asrs-crane-3d.ts
CHANGED
|
@@ -167,6 +167,26 @@ export class AsrsCrane3D extends RealObjectGroup {
|
|
|
167
167
|
// Place lamp near the corner of the base, away from the mast
|
|
168
168
|
lampMesh.position.set(width * 0.3, baseY + railH + baseH + lampH / 2, height * 0.3)
|
|
169
169
|
this.object3d.add(lampMesh)
|
|
170
|
+
|
|
171
|
+
// ── Carriage frame (invisible anchor for carrier attach) ──────────
|
|
172
|
+
// Placed at the top of the shuttle, where cargo rests.
|
|
173
|
+
this._carriageFrame = new THREE.Object3D()
|
|
174
|
+
this._carriageFrame.name = 'crane-carriage-tcp'
|
|
175
|
+
this._carriageFrame.position.set(0, carriageY - carriageH / 2 - shuttleH, 0)
|
|
176
|
+
this.object3d.add(this._carriageFrame)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Sub-frame where carriers attach during transport (fork tool-centre-point). */
|
|
180
|
+
private _carriageFrame?: THREE.Object3D
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Return the carriage TCP anchor. Carriers attached to this frame will
|
|
184
|
+
* follow carriage movement as `carriageHeight` changes and the crane rebuilds.
|
|
185
|
+
*
|
|
186
|
+
* Callers should re-fetch this after any state change that triggers rebuild.
|
|
187
|
+
*/
|
|
188
|
+
getCarriageFrame(): THREE.Object3D | undefined {
|
|
189
|
+
return this._carriageFrame
|
|
170
190
|
}
|
|
171
191
|
|
|
172
192
|
updateDimension() {}
|
package/src/asrs-crane.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
|
-
import { Component, ComponentNature,
|
|
4
|
+
import { Component, ComponentNature, ContainerAbstract, ContainerCapacity, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
5
|
+
import type { SlotDef } from '@hatiolab/things-scene'
|
|
5
6
|
import {
|
|
7
|
+
CarrierHolder,
|
|
6
8
|
Legendable,
|
|
9
|
+
Mover,
|
|
7
10
|
Placeable,
|
|
11
|
+
type AttachFrame,
|
|
8
12
|
type Alignment,
|
|
9
13
|
type Heights,
|
|
10
14
|
type LegendBinding,
|
|
15
|
+
type MoveOptions,
|
|
11
16
|
type PlacementArchetype
|
|
12
17
|
} from '@operato/scene-base'
|
|
13
18
|
|
|
@@ -72,27 +77,37 @@ const NATURE: ComponentNature = {
|
|
|
72
77
|
help: 'scene/component/asrs-crane'
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
// Mixin chain: Mover → CarrierHolder → ContainerCapacity → Legendable → Placeable → ContainerAbstract
|
|
81
|
+
//
|
|
82
|
+
// Mover: pick / place / pickAndPlace / moveTo / engage primitives
|
|
83
|
+
// CarrierHolder: attachPointFor() — where the carrier sits on the crane (carriage fork)
|
|
84
|
+
// ContainerCapacity: receive() / dispatch() / canReceive() / slots — slot tracking +
|
|
85
|
+
// TRANSFER_SLOT_KEY bookkeeping during transit
|
|
86
|
+
// Legendable: status → bodyColor / lampEmissive colour mapping
|
|
87
|
+
// Placeable: floor-archetype 3D positioning
|
|
88
|
+
// ContainerAbstract: child management — carrier becomes a child while in transit
|
|
89
|
+
//
|
|
90
|
+
// Note: ContainerAbstract replaces Shape. The 2D outline is drawn manually in
|
|
91
|
+
// render() below (a simple top-down rectangle), matching the old Shape output
|
|
92
|
+
// without the Shape base-class overhead.
|
|
77
93
|
/**
|
|
78
94
|
* AsrsCrane — the stacker / retrieval crane that runs in the aisle of an
|
|
79
95
|
* AS/RS, moving cargo between the load port and the rack cells.
|
|
80
96
|
*
|
|
81
97
|
* Structure: a tall vertical mast that translates along a floor + ceiling
|
|
82
98
|
* rail (the aisle), with a carriage that slides up/down the mast carrying a
|
|
83
|
-
* shuttle / forks.
|
|
84
|
-
*
|
|
85
|
-
*
|
|
99
|
+
* shuttle / forks.
|
|
100
|
+
*
|
|
101
|
+
* **Monitoring mode**: crane status is driven by data binding
|
|
102
|
+
* (`state.status`, `state.carriageHeight`). The carrier is referenced
|
|
103
|
+
* via data binding — it is NOT a child of the crane in monitoring mode.
|
|
86
104
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* fmsim's CarrierManager pattern. Adding the carrier as a child would mix
|
|
91
|
-
* static placement with the dynamic data-driven flow we deliberately keep
|
|
92
|
-
* separate (see Phase A4 commit notes).
|
|
105
|
+
* **Simulation mode**: call `crane.pick(carrier)` / `crane.place(carrier, rackCell)`
|
|
106
|
+
* (or `crane.pickAndPlace(carrier, rackCell)`). Mover handles navigation +
|
|
107
|
+
* engage + reparent. During transit the carrier IS a child of the crane.
|
|
93
108
|
*/
|
|
94
109
|
@sceneComponent('asrs-crane')
|
|
95
|
-
export default class AsrsCrane extends
|
|
110
|
+
export default class AsrsCrane extends Mover(CarrierHolder(ContainerCapacity(Legendable(Placeable(ContainerAbstract))))) {
|
|
96
111
|
static legends: Record<string, LegendBinding> = {
|
|
97
112
|
bodyColor: { from: 'status', legend: BODY_LEGEND },
|
|
98
113
|
lampEmissive: { from: 'status', legend: LAMP_EMISSIVE_LEGEND }
|
|
@@ -102,6 +117,9 @@ export default class AsrsCrane extends Base {
|
|
|
102
117
|
static align: Alignment = 'bottom'
|
|
103
118
|
static defaultDepth = (h: Heights) => h.ceiling - h.floor
|
|
104
119
|
|
|
120
|
+
/** Yaw offset: crane model is drawn with the aisle axis along X (right = forward). */
|
|
121
|
+
static yawOffset = 0
|
|
122
|
+
|
|
105
123
|
get nature() {
|
|
106
124
|
return NATURE
|
|
107
125
|
}
|
|
@@ -110,21 +128,124 @@ export default class AsrsCrane extends Base {
|
|
|
110
128
|
return []
|
|
111
129
|
}
|
|
112
130
|
|
|
131
|
+
// ── ContainerCapacity ─────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
/** Stacker crane carries at most one load at a time on its forks. */
|
|
134
|
+
get slots(): SlotDef[] {
|
|
135
|
+
return [{ id: 'forks', maxCount: 1 }]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── CarrierHolder — attach frame (carriage fork position) ─────────────────
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return the 3D attach frame on the crane's carriage (fork tip).
|
|
142
|
+
* Carriers are attached here while the crane is in transit (pick phase).
|
|
143
|
+
*
|
|
144
|
+
* The AsrsCrane3D exposes `getCarriageFrame()` — a sub-Object3D that
|
|
145
|
+
* tracks the carriage height and sits at the fork TCP. If the 3D object
|
|
146
|
+
* isn't built yet (e.g. before scene initialization), fall back to the
|
|
147
|
+
* crane's own object3d centre.
|
|
148
|
+
*/
|
|
149
|
+
attachPointFor(carrier: Component): AttachFrame | null {
|
|
150
|
+
const ro = (this as any)._realObject as AsrsCrane3D | undefined
|
|
151
|
+
const frame = ro?.getCarriageFrame?.()
|
|
152
|
+
if (frame) {
|
|
153
|
+
const carrierDepth = resolveCarrierDepth(carrier)
|
|
154
|
+
return { attach: frame, localPosition: { x: 0, y: carrierDepth / 2, z: 0 } }
|
|
155
|
+
}
|
|
156
|
+
const root = (this as any)._realObject?.object3d
|
|
157
|
+
if (!root) return null
|
|
158
|
+
return { attach: root }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── Mover overrides ───────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Domain-specific actuation between arrival and reparent.
|
|
165
|
+
*
|
|
166
|
+
* Simulation sequence for PICK:
|
|
167
|
+
* 1. Mover.pick() navigates crane to carrier position (moveTo).
|
|
168
|
+
* 2. engage('pick') → snap carriage height + status 'loading'.
|
|
169
|
+
* 3. Carrier is reparented to crane (becomes child).
|
|
170
|
+
*
|
|
171
|
+
* For now: set status and snap carriage height. A full ASRS simulation
|
|
172
|
+
* would tween the carriageHeight here (animate AsrsCrane3D).
|
|
173
|
+
*
|
|
174
|
+
* Status lifecycle:
|
|
175
|
+
* idle → (moveTo running) → engage fires → loading/unloading → (reparent) → idle
|
|
176
|
+
* The 'moving' state is not set from Mover.moveTo() because TypeScript
|
|
177
|
+
* can't call super.moveTo() on an `: any`-typed mixin. WCS data binding
|
|
178
|
+
* sets 'moving' in monitoring mode; override pick()/place() to set it
|
|
179
|
+
* in full simulation environments.
|
|
180
|
+
*/
|
|
181
|
+
async engage(
|
|
182
|
+
target: Component,
|
|
183
|
+
kind: 'pick' | 'place',
|
|
184
|
+
_options: MoveOptions = {}
|
|
185
|
+
): Promise<void> {
|
|
186
|
+
if (kind === 'pick') {
|
|
187
|
+
this.setState({ status: 'loading' as AsrsCraneStatus })
|
|
188
|
+
const carrierY = resolveCarrierCenterY(target)
|
|
189
|
+
if (carrierY !== null) {
|
|
190
|
+
this.setState({ carriageHeight: carrierY })
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
this.setState({ status: 'unloading' as AsrsCraneStatus })
|
|
194
|
+
}
|
|
195
|
+
// In a full simulation: await carriage-motion tween here.
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ── Domain aliases ────────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
/** Fetch a carrier from a rack cell (semantically = pick). */
|
|
201
|
+
fetch(carrier: Component, options?: MoveOptions): Promise<void> {
|
|
202
|
+
return (this as any).pick(carrier, options)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Deposit a carrier into a rack cell (semantically = place). */
|
|
206
|
+
deposit(carrier: Component, cell: Component, options?: MoveOptions): Promise<void> {
|
|
207
|
+
return (this as any).place(carrier, cell, options)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ── 2D rendering ─────────────────────────────────────────────────────────
|
|
211
|
+
|
|
113
212
|
/**
|
|
114
213
|
* 2D — top-down rectangle showing the crane's footprint along the aisle.
|
|
115
214
|
* The crane is much taller than wide, so the 2D mark is small.
|
|
116
215
|
*/
|
|
117
216
|
render(ctx: CanvasRenderingContext2D) {
|
|
118
217
|
const { width, height, left, top } = this.state
|
|
218
|
+
const fillColor = (this.state.bodyColor as string) || '#888'
|
|
219
|
+
ctx.save()
|
|
220
|
+
ctx.fillStyle = fillColor
|
|
119
221
|
ctx.beginPath()
|
|
120
222
|
ctx.rect(left, top, width, height)
|
|
223
|
+
ctx.fill()
|
|
224
|
+
ctx.restore()
|
|
121
225
|
}
|
|
122
226
|
|
|
123
|
-
|
|
124
|
-
return (this.state.bodyColor as string) || '#888'
|
|
125
|
-
}
|
|
227
|
+
// ── 3D ───────────────────────────────────────────────────────────────────
|
|
126
228
|
|
|
127
229
|
buildRealObject(): RealObject | undefined {
|
|
128
230
|
return new AsrsCrane3D(this as any)
|
|
129
231
|
}
|
|
130
232
|
}
|
|
233
|
+
|
|
234
|
+
function resolveCarrierDepth(c: Component): number {
|
|
235
|
+
const eff = (c as any)._realObject?.effectiveDepth
|
|
236
|
+
if (typeof eff === 'number' && Number.isFinite(eff)) return eff
|
|
237
|
+
return numOr((c as any)?.state?.depth, 0)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function resolveCarrierCenterY(c: Component): number | null {
|
|
241
|
+
const pos = (c as any).state
|
|
242
|
+
if (!pos) return null
|
|
243
|
+
// zPos is the 3D Y center of a Placeable component in things-scene
|
|
244
|
+
const zPos = numOr(pos.zPos, NaN)
|
|
245
|
+
if (!Number.isNaN(zPos)) return zPos
|
|
246
|
+
return null
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function numOr(v: unknown, dflt: number): number {
|
|
250
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : dflt
|
|
251
|
+
}
|
package/src/asrs-rack.ts
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
5
5
|
import {
|
|
6
|
+
CellContainer,
|
|
7
|
+
CellMap,
|
|
8
|
+
CarrierHolder,
|
|
6
9
|
Placeable,
|
|
10
|
+
type AttachFrame,
|
|
7
11
|
type Alignment,
|
|
8
12
|
type Heights,
|
|
9
13
|
type PlacementArchetype
|
|
@@ -35,35 +39,31 @@ const NATURE: ComponentNature = {
|
|
|
35
39
|
// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),
|
|
36
40
|
// which forces `isHTMLElement(): true` and trips the 3D pipeline's
|
|
37
41
|
// addObject DOM-skip gate. ASRS rack lives only in the 3D scene graph.
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
//
|
|
43
|
+
// Mixin chain: CellContainer → CarrierHolder → Placeable → ContainerAbstract
|
|
44
|
+
// CellContainer: cell topology (cellMap, cell(), findAvailableCell(), occupiedCellIds())
|
|
45
|
+
// CarrierHolder: 3D attach-point protocol (attachPointFor, containable gates)
|
|
46
|
+
// Placeable: floor-archetype positioning
|
|
47
|
+
// ContainerAbstract: child component management
|
|
40
48
|
/**
|
|
41
49
|
* AsrsRack — a multi-level high-bay storage rack, the structural backbone of
|
|
42
50
|
* an AS/RS (Automated Storage / Retrieval System).
|
|
43
51
|
*
|
|
44
52
|
* `levels` × `bays` cells form a vertical grid. Each cell holds one logistics
|
|
45
53
|
* package (Pallet / Box / Parcel). A pair of AsrsRacks separated by an aisle
|
|
46
|
-
* (where an AsrsCrane runs) is the typical AS/RS configuration
|
|
47
|
-
* single-rack unit and lets users compose multi-rack systems by placing them
|
|
48
|
-
* side by side. A future `AsrsAisle` composite may bundle the pair + crane.
|
|
54
|
+
* (where an AsrsCrane runs) is the typical AS/RS configuration.
|
|
49
55
|
*
|
|
50
|
-
* **
|
|
51
|
-
*
|
|
52
|
-
* pallet load. Users can shorten via explicit `state.depth` for warehouses
|
|
53
|
-
* with smaller envelopes.
|
|
56
|
+
* **Monitoring mode** (default): pallets/boxes are direct children of the rack,
|
|
57
|
+
* placed by the WCS data binding. No RackCell children are created.
|
|
54
58
|
*
|
|
55
|
-
* **
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* z lands on the rack's overall bottom (parent.zPos + parent.depth = ceiling),
|
|
59
|
-
* which isn't quite cell-level resolution — true per-cell z positioning is
|
|
60
|
-
* a v3 concern (the cargo would need to know which cell-row it's in).
|
|
59
|
+
* **Simulation mode**: call `rack._buildCells()` after placing the rack on the
|
|
60
|
+
* scene. This creates RackCell children at the correct 3D positions. The
|
|
61
|
+
* AsrsCrane then navigates to individual RackCells for pick-and-place.
|
|
61
62
|
*
|
|
62
|
-
*
|
|
63
|
-
* occupancy state is implicit in the children, not a status flag.
|
|
63
|
+
* **Placement**: `floor` archetype, full ceiling depth by default.
|
|
64
64
|
*/
|
|
65
65
|
@sceneComponent('asrs-rack')
|
|
66
|
-
export default class AsrsRack extends
|
|
66
|
+
export default class AsrsRack extends CellContainer(CarrierHolder(Placeable(ContainerAbstract))) {
|
|
67
67
|
static placement: PlacementArchetype = 'floor'
|
|
68
68
|
static align: Alignment = 'bottom'
|
|
69
69
|
static defaultDepth = (h: Heights) => h.ceiling - h.floor
|
|
@@ -76,13 +76,110 @@ export default class AsrsRack extends Base {
|
|
|
76
76
|
return []
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// ── CellContainer ─────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Derive the cell topology from the rack's current dimensions and bay/level
|
|
83
|
+
* counts. The CellMap is rebuilt fresh each time (state changes trigger
|
|
84
|
+
* re-reads via things-scene's invalidation pipeline).
|
|
85
|
+
*
|
|
86
|
+
* Coordinate convention (matches things-scene 3D):
|
|
87
|
+
* X = bay axis (left → right)
|
|
88
|
+
* Y = level axis (floor → ceiling, the rack's `depth` state property)
|
|
89
|
+
* Z = row axis (front → back, the rack's `height` state property)
|
|
90
|
+
*/
|
|
91
|
+
get cellMap(): CellMap {
|
|
92
|
+
const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))
|
|
93
|
+
const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))
|
|
94
|
+
const width = (this.state.width as number) || 1000
|
|
95
|
+
const rackDepth = (this.state.depth as number) || 3000 // Y: floor→ceiling
|
|
96
|
+
const rackHeight = (this.state.height as number) || 600 // Z: front→back
|
|
97
|
+
|
|
98
|
+
return CellMap.grid({
|
|
99
|
+
bays,
|
|
100
|
+
rows: 1,
|
|
101
|
+
levels,
|
|
102
|
+
bayWidth: width / bays,
|
|
103
|
+
rowDepth: rackHeight,
|
|
104
|
+
levelHeight: rackDepth / levels
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create RackCell child components for each cell in the CellMap.
|
|
110
|
+
*
|
|
111
|
+
* Called explicitly to enter simulation mode — monitoring-mode racks
|
|
112
|
+
* never call this (pallets are direct children, no explicit cells).
|
|
113
|
+
*
|
|
114
|
+
* Idempotent: removes existing rack-cell children first.
|
|
115
|
+
*/
|
|
116
|
+
_buildCells(): void {
|
|
117
|
+
// Remove existing rack-cell children
|
|
118
|
+
const existing = ((this as any).components as Component[] | undefined) ?? []
|
|
119
|
+
for (const child of [...existing]) {
|
|
120
|
+
if ((child as any).state?.type === 'rack-cell') {
|
|
121
|
+
;(this as any).removeComponent?.(child)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Create a RackCell for each cell in the map
|
|
126
|
+
const RackCellClass = (Component as any).register('rack-cell') as (new (...args: any[]) => Component) | undefined
|
|
127
|
+
if (!RackCellClass) {
|
|
128
|
+
console.warn('AsrsRack._buildCells: rack-cell type not registered. Import rack-cell.ts first.')
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const context = (this as any)._app
|
|
133
|
+
for (const cell of this.cellMap.cells) {
|
|
134
|
+
const model = {
|
|
135
|
+
type: 'rack-cell',
|
|
136
|
+
cellId: cell.id,
|
|
137
|
+
width: cell.size.width,
|
|
138
|
+
height: cell.size.depth, // 2D height = 3D Z depth
|
|
139
|
+
depth: cell.size.height // 3D Y = level height
|
|
140
|
+
}
|
|
141
|
+
const rackCell = new RackCellClass(model, context)
|
|
142
|
+
;(this as any).addComponent?.(rackCell)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Container gates ───────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Allow:
|
|
150
|
+
* - Carriable components (pallets, boxes, parcels) — direct children in monitoring mode.
|
|
151
|
+
* - RackCell — created by _buildCells() in simulation mode.
|
|
152
|
+
*
|
|
153
|
+
* Block:
|
|
154
|
+
* - Everything else (sensors, labels, etc. can be siblings of the rack, not children).
|
|
155
|
+
*/
|
|
156
|
+
containable(component: Component): boolean {
|
|
157
|
+
if ((component as any).state?.type === 'rack-cell') return true
|
|
81
158
|
const archetype = (component.constructor as any).placement
|
|
82
159
|
if (archetype === 'operation') return true
|
|
83
160
|
return component.isDescendible(this as any)
|
|
84
161
|
}
|
|
85
162
|
|
|
163
|
+
// ── CarrierHolder — attach frame for direct carrier children ─────────────
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Attach frame for carriers that are DIRECT children of the rack
|
|
167
|
+
* (monitoring mode, where pallets go directly into the rack without
|
|
168
|
+
* explicit RackCell components).
|
|
169
|
+
*
|
|
170
|
+
* In simulation mode, carriers become children of their RackCell,
|
|
171
|
+
* and each RackCell provides its own attachPointFor(). So this method
|
|
172
|
+
* is only invoked on direct-child carriers in monitoring mode — it
|
|
173
|
+
* returns the rack's own object3d as the attach frame (default behavior).
|
|
174
|
+
*/
|
|
175
|
+
attachPointFor(_carrier: Component): AttachFrame | null {
|
|
176
|
+
const root = (this as any)._realObject?.object3d
|
|
177
|
+
if (!root) return null
|
|
178
|
+
return { attach: root }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ── 2D rendering ─────────────────────────────────────────────────────────
|
|
182
|
+
|
|
86
183
|
/**
|
|
87
184
|
* 2D — top-down rectangle showing the rack footprint, with subdivisions
|
|
88
185
|
* suggesting the bay layout (lines parallel to the aisle).
|
|
@@ -106,6 +203,8 @@ export default class AsrsRack extends Base {
|
|
|
106
203
|
return '#a0a0a8'
|
|
107
204
|
}
|
|
108
205
|
|
|
206
|
+
// ── 3D ───────────────────────────────────────────────────────────────────
|
|
207
|
+
|
|
109
208
|
buildRealObject(): RealObject | undefined {
|
|
110
209
|
return new AsrsRack3D(this as any)
|
|
111
210
|
}
|
package/src/box.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { ComponentNature, RealObject, RectPath, Shape, sceneComponent } from '@hatiolab/things-scene'
|
|
5
5
|
import {
|
|
6
6
|
Carriable,
|
|
7
7
|
Legendable,
|
|
@@ -54,8 +54,6 @@ const NATURE: ComponentNature = {
|
|
|
54
54
|
|
|
55
55
|
// Carriable: a box can be a child of any CarrierHolder (Pallet for stacking,
|
|
56
56
|
// AGV deck, robot-arm gripper, Spot for staging).
|
|
57
|
-
const Base = Carriable(Legendable(Placeable(RectPath(Shape)))) as unknown as typeof Component
|
|
58
|
-
|
|
59
57
|
/**
|
|
60
58
|
* Box — a generic stackable container for goods. Wood crate or plastic tote
|
|
61
59
|
* variants distinguished by `material` prop.
|
|
@@ -65,7 +63,7 @@ const Base = Carriable(Legendable(Placeable(RectPath(Shape)))) as unknown as typ
|
|
|
65
63
|
* scene-tree). If a future use case needs nested boxes, extend Container.
|
|
66
64
|
*/
|
|
67
65
|
@sceneComponent('box')
|
|
68
|
-
export default class Box extends
|
|
66
|
+
export default class Box extends Carriable(Legendable(Placeable(RectPath(Shape)))) {
|
|
69
67
|
static legends: Record<string, LegendBinding> = {
|
|
70
68
|
bodyColor: { from: 'material', legend: BODY_LEGEND }
|
|
71
69
|
}
|