@operato/scene-storage 10.0.0-beta.48 → 10.0.0-beta.53
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 +36 -0
- package/dist/box.js +2 -2
- package/dist/box.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/pallet.js +2 -2
- package/dist/pallet.js.map +1 -1
- package/dist/parcel.js +2 -2
- package/dist/parcel.js.map +1 -1
- package/dist/picking-station-3d.d.ts +20 -0
- package/dist/picking-station-3d.js +162 -0
- package/dist/picking-station-3d.js.map +1 -0
- package/dist/picking-station.d.ts +50 -0
- package/dist/picking-station.js +186 -0
- package/dist/picking-station.js.map +1 -0
- package/dist/rack-capability.d.ts +11 -0
- package/dist/rack-capability.js +25 -0
- package/dist/rack-capability.js.map +1 -0
- package/dist/rack-grid.d.ts +4 -22
- package/dist/rack-grid.js +23 -115
- package/dist/rack-grid.js.map +1 -1
- package/dist/spot.d.ts +1 -0
- package/dist/spot.js +6 -2
- package/dist/spot.js.map +1 -1
- package/dist/stockpile-3d.d.ts +55 -0
- package/dist/stockpile-3d.js +387 -0
- package/dist/stockpile-3d.js.map +1 -0
- package/dist/stockpile-grid-3d.d.ts +30 -0
- package/dist/stockpile-grid-3d.js +301 -0
- package/dist/stockpile-grid-3d.js.map +1 -0
- package/dist/stockpile-grid.d.ts +85 -0
- package/dist/stockpile-grid.js +361 -0
- package/dist/stockpile-grid.js.map +1 -0
- package/dist/stockpile.d.ts +116 -0
- package/dist/stockpile.js +345 -0
- package/dist/stockpile.js.map +1 -0
- package/dist/storage-rack.d.ts +39 -44
- package/dist/storage-rack.js +71 -146
- package/dist/storage-rack.js.map +1 -1
- package/dist/templates/index.d.ts +80 -0
- package/dist/templates/index.js +7 -1
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/picking-station.d.ts +20 -0
- package/dist/templates/picking-station.js +22 -0
- package/dist/templates/picking-station.js.map +1 -0
- package/dist/templates/stockpile-grid.d.ts +37 -0
- package/dist/templates/stockpile-grid.js +38 -0
- package/dist/templates/stockpile-grid.js.map +1 -0
- package/dist/templates/stockpile.d.ts +29 -0
- package/dist/templates/stockpile.js +31 -0
- package/dist/templates/stockpile.js.map +1 -0
- package/package.json +3 -3
- package/src/box.ts +2 -1
- package/src/index.ts +14 -0
- package/src/pallet.ts +2 -1
- package/src/parcel.ts +2 -1
- package/src/picking-station-3d.ts +164 -0
- package/src/picking-station.ts +220 -0
- package/src/rack-capability.ts +26 -0
- package/src/rack-grid.ts +24 -108
- package/src/spot.ts +15 -1
- package/src/stockpile-3d.ts +412 -0
- package/src/stockpile-grid-3d.ts +327 -0
- package/src/stockpile-grid.ts +408 -0
- package/src/stockpile.ts +427 -0
- package/src/storage-rack.ts +82 -137
- package/src/templates/index.ts +7 -1
- package/src/templates/picking-station.ts +23 -0
- package/src/templates/stockpile-grid.ts +39 -0
- package/src/templates/stockpile.ts +32 -0
- package/test/test-rack-capability.ts +51 -0
- package/translations/en.json +23 -6
- package/translations/ja.json +23 -6
- package/translations/ko.json +22 -5
- package/translations/ms.json +23 -6
- package/translations/zh.json +22 -5
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.0-beta.53](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.52...v10.0.0-beta.53) (2026-06-03)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
* **scene-base,storage:** Phase ZT-V PR-3a — RecordStorage mixin + Stockpile 마이그 ([e83e054](https://github.com/things-scene/operato-scene/commit/e83e054170d0526c3a8d7290c9ccedd75861149c))
|
|
12
|
+
* **scene-base,storage:** Phase ZT-V PR-9 — SingleSlotHolder mixin + Spot/PickingStation 마이그 ([cb11c4e](https://github.com/things-scene/operato-scene/commit/cb11c4e7dc97a671b63fabd4aef518d0aa215a61))
|
|
13
|
+
* **scene-base:** Phase ZT-V PR-1 — Identity + CapabilityRegistry ([3353b99](https://github.com/things-scene/operato-scene/commit/3353b99e28f80e6a32eb072af3adbd9dad36a2cf))
|
|
14
|
+
* **scene:** dock-door pure gate + trailer-container + forklift home/smooth ([e7302ca](https://github.com/things-scene/operato-scene/commit/e7302ca425209b7870b7d6d2d94c89ad67a25a28))
|
|
15
|
+
* **storage,scene-base:** Step 1+2 — StorageRack cell-precise approach + fromPos 전달 ([e79b266](https://github.com/things-scene/operato-scene/commit/e79b26633a69545de4b75e3519d20fcb2ed5d6ed))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### :house: Code Refactoring
|
|
19
|
+
|
|
20
|
+
* **storage:** Phase ZT-V PR-3b — StockpileGrid 의 RecordStorage 마이그 ([7257b83](https://github.com/things-scene/operato-scene/commit/7257b83f517173418c86762de33f6585119bd866))
|
|
21
|
+
* **storage:** Phase ZT-V PR-3c — StorageRack 의 RecordStorage 마이그 ([27b930e](https://github.com/things-scene/operato-scene/commit/27b930e0cd50806cf6db55435d300febdaf93158))
|
|
22
|
+
* **storage:** Phase ZT-V PR-3d — RackGrid 의 RecordStorage 마이그 ([5055129](https://github.com/things-scene/operato-scene/commit/505512970ee2a9eec2d836b2b2c2539961e64056))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## [10.0.0-beta.50](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.49...v10.0.0-beta.50) (2026-05-28)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### :rocket: New Features
|
|
30
|
+
|
|
31
|
+
* **scene-base,transport:** AMR 자동 운반 — planTransfer 다중 hop + zone 좌표 정합 + slot reservation ([3474236](https://github.com/things-scene/operato-scene/commit/347423683c9814627334f134259b203117a32a69))
|
|
32
|
+
* **storage,transport:** PickingStation + PickingCart — picking workflow 컴포넌트 ([8017e39](https://github.com/things-scene/operato-scene/commit/8017e39c5caeed81200b1c922bf1176cf85784b8))
|
|
33
|
+
* **storage:** Stockpile + StockpileGrid — 평치 보관 컴포넌트 ([d144cb0](https://github.com/things-scene/operato-scene/commit/d144cb0e7731800569594c29e0cf49c7e2fd71d9))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### :house: Code Refactoring
|
|
37
|
+
|
|
38
|
+
* **storage:** StockpileGrid 데이터 구조 단순화 — cells → data 통일, cell override 제거 ([475e72d](https://github.com/things-scene/operato-scene/commit/475e72d4c03b562b240da00f56177af51f27b2c6))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
6
42
|
## [10.0.0-beta.48](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.47...v10.0.0-beta.48) (2026-05-26)
|
|
7
43
|
|
|
8
44
|
**Note:** Version bump only for package @operato/scene-storage
|
package/dist/box.js
CHANGED
|
@@ -3,7 +3,7 @@ import { __decorate } from "tslib";
|
|
|
3
3
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
4
4
|
*/
|
|
5
5
|
import { RectPath, Shape, topApproachFrame, getWorldPose, sceneComponent } from '@hatiolab/things-scene';
|
|
6
|
-
import { Carriable, Legendable, Placeable } from '@operato/scene-base';
|
|
6
|
+
import { Carriable, Identifiable, Legendable, Placeable } from '@operato/scene-base';
|
|
7
7
|
import { Box3D } from './box-3d.js';
|
|
8
8
|
const BODY_LEGEND = {
|
|
9
9
|
wood: '#a87644',
|
|
@@ -39,7 +39,7 @@ const NATURE = {
|
|
|
39
39
|
* logistics visualization (a *case* of items inside a box is data, not
|
|
40
40
|
* scene-tree). If a future use case needs nested boxes, extend Container.
|
|
41
41
|
*/
|
|
42
|
-
let Box = class Box extends Carriable(Legendable(Placeable(RectPath(Shape)))) {
|
|
42
|
+
let Box = class Box extends Identifiable(Carriable(Legendable(Placeable(RectPath(Shape))))) {
|
|
43
43
|
static legends = {
|
|
44
44
|
bodyColor: { from: 'material', legend: BODY_LEGEND }
|
|
45
45
|
};
|
package/dist/box.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"box.js","sourceRoot":"","sources":["../src/box.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,EAGL,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACf,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACL,SAAS,EACT,UAAU,EACV,SAAS,EAIV,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAwBnC,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAA;AAED,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,UAAU;YACjB,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,OAAO,EAAE;oBACP,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;oBAClC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;iBACzC;aACF;SACF;KACF;IACD,IAAI,EAAE,qBAAqB;CAC5B,CAAA;AAED,6EAA6E;AAC7E,kDAAkD;AAClD;;;;;;;GAOG;AAEY,IAAM,GAAG,GAAT,MAAM,GAAI,SAAQ,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"box.js","sourceRoot":"","sources":["../src/box.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,EAGL,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACf,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EAIV,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAwBnC,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAA;AAED,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,UAAU;YACjB,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,OAAO,EAAE;oBACP,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;oBAClC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;iBACzC;aACF;SACF;KACF;IACD,IAAI,EAAE,qBAAqB;CAC5B,CAAA;AAED,6EAA6E;AAC7E,kDAAkD;AAClD;;;;;;;GAOG;AAEY,IAAM,GAAG,GAAT,MAAM,GAAI,SAAQ,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAG9F,MAAM,CAAC,OAAO,GAAkC;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE;KACrD,CAAA;IAED,MAAM,CAAC,SAAS,GAAuB,WAAW,CAAA;IAClD,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,GAAG,CAAA;IAEzB,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED,+BAA+B;IAC/B,MAAM,CAAC,GAA6B;QAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAC/C,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;IACpC,CAAC;IAED,IAAI,SAAS;QACX,OAAQ,IAAI,CAAC,KAAK,CAAC,SAAoB,IAAI,SAAS,CAAA;IACtD,CAAC;IAED,eAAe;QACb,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,CAAA;IACxB,CAAC;IAED;;;;;;;OAOG;IACH,YAAY;QACV,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,EAAE,GAAmB;YACzB,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;YAClE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;SACrF,CAAA;QACD,MAAM,QAAQ,GAAI,IAAI,CAAC,WAAmB,CAAC,YAAY,IAAI,GAAG,CAAA;QAE9D,OAAO;YACL,gBAAgB,CAAC;gBACf,YAAY,EAAE,EAAE;gBAChB,IAAI,EAAE,QAAQ,EAAmB,iEAAiE;gBAClG,gBAAgB,EAAE,EAAE,EAAa,wBAAwB;gBACzD,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;gBACzC,QAAQ,EAAE,CAAC;gBACX,EAAE,EAAE,aAAa;aAClB,CAAC;YACF,gBAAgB,CAAC;gBACf,YAAY,EAAE,EAAE;gBAChB,IAAI,EAAE,QAAQ;gBACd,gBAAgB,EAAE,EAAE;gBACpB,QAAQ,EAAE,UAAU;gBACpB,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;gBAC1C,QAAQ,EAAE,CAAC;gBACX,EAAE,EAAE,UAAU;aACf,CAAC;YACF,gBAAgB,CAAC;gBACf,YAAY,EAAE,EAAE;gBAChB,IAAI,EAAE,QAAQ;gBACd,gBAAgB,EAAE,EAAE,EAAa,mBAAmB;gBACpD,QAAQ,EAAE,eAAe;gBACzB,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;gBAC1C,QAAQ,EAAE,CAAC;gBACX,EAAE,EAAE,UAAU;aACf,CAAC;SACH,CAAA;IACH,CAAC;;AA/EkB,GAAG;IADvB,cAAc,CAAC,KAAK,CAAC;GACD,GAAG,CAgFvB;eAhFoB,GAAG","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport {\n ComponentNature,\n RealObject,\n RectPath,\n Shape,\n topApproachFrame,\n getWorldPose,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State, Material3D, PickupFrame, PoseSerialized } from '@hatiolab/things-scene'\nimport {\n Carriable,\n Identifiable,\n Legendable,\n Placeable,\n type Alignment,\n type LegendBinding,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Box3D } from './box-3d.js'\n\n/**\n * Box material — drives 3D structure and color.\n *\n * - `wood` — wood crate: visible vertical slats, gaps between, open or\n * semi-open top. Used for heavy / industrial parts.\n * - `plastic` — plastic tote / bin: solid molded walls with stackable lip\n * at top. Used for fulfillment, parts kitting.\n *\n * Cardboard parcels are a separate component (see `parcel.ts`) — they have\n * different proportions, taping, and labels that warrant a distinct class.\n */\nexport type BoxMaterial = 'wood' | 'plastic'\n\n/** Box 컴포넌트 state */\nexport interface BoxState extends State {\n // ── 외관 ──\n material?: BoxMaterial\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst BODY_LEGEND = {\n wood: '#a87644',\n plastic: '#3a5078',\n default: '#a87644'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'material',\n name: 'material',\n property: {\n options: [\n { display: 'Wood', value: 'wood' },\n { display: 'Plastic', value: 'plastic' }\n ]\n }\n }\n ],\n help: 'scene/component/box'\n}\n\n// Carriable: a box can be a child of any CarrierHolder (Pallet for stacking,\n// AGV deck, robot-arm gripper, Spot for staging).\n/**\n * Box — a generic stackable container for goods. Wood crate or plastic tote\n * variants distinguished by `material` prop.\n *\n * Shape-based (not Container) — boxes nesting other components is rare in\n * logistics visualization (a *case* of items inside a box is data, not\n * scene-tree). If a future use case needs nested boxes, extend Container.\n */\n@sceneComponent('box')\nexport default class Box extends Identifiable(Carriable(Legendable(Placeable(RectPath(Shape))))) {\n declare state: BoxState\n\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'material', legend: BODY_LEGEND }\n }\n\n static placement: PlacementArchetype = 'operation'\n static align: Alignment = 'bottom'\n static defaultDepth = 300\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /** 2D — top-down rectangle. */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n ctx.beginPath()\n ctx.rect(left, top, width, height)\n }\n\n get fillStyle() {\n return (this.state.bodyColor as string) || '#a87644'\n }\n\n buildRealObject(): RealObject | undefined {\n return new Box3D(this)\n }\n\n /**\n * Phase H — pickup contract. Box 는 위에서 gripper / vacuum cup 으로 집기 —\n * 단일 entry (top center). Box 의 dimensions 가 작아서 forklift fork 보다는\n * gripper 가 일반적. forklift 로 들어올릴 box 는 통상 pallet 위에 stacking\n * 후 pallet 째로 운반.\n *\n * tolerance 가 pallet 보다 빡빡 (gripper 정밀도 vs forklift pocket 폭).\n */\n pickupFrames(): PickupFrame[] {\n const wp = getWorldPose(this)\n const me: PoseSerialized = {\n position: { x: wp.position.x, y: wp.position.y, z: wp.position.z },\n rotation: { x: wp.rotation.x, y: wp.rotation.y, z: wp.rotation.z, w: wp.rotation.w }\n }\n const boxDepth = (this.constructor as any).defaultDepth ?? 300\n\n return [\n topApproachFrame({\n carrierWorld: me,\n topY: boxDepth, // Box top in carrier-local Y (depth = full height; top at depth)\n approachDistance: 50, // gripper 가 hover 하는 거리\n toolType: 'gripper',\n tolerance: { positionMm: 5, angleDeg: 1 },\n priority: 0,\n id: 'top-gripper'\n }),\n topApproachFrame({\n carrierWorld: me,\n topY: boxDepth,\n approachDistance: 40,\n toolType: 'agv-deck',\n tolerance: { positionMm: 15, angleDeg: 3 },\n priority: 1,\n id: 'top-deck'\n }),\n topApproachFrame({\n carrierWorld: me,\n topY: boxDepth,\n approachDistance: 80, // crane fork hover\n toolType: 'forklift-fork',\n tolerance: { positionMm: 25, angleDeg: 4 },\n priority: 2,\n id: 'top-fork'\n })\n ]\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,15 @@ export type { CraneState, CraneStatus } from './crane.js';
|
|
|
17
17
|
export { Crane3D } from './crane-3d.js';
|
|
18
18
|
export { default as Spot } from './spot.js';
|
|
19
19
|
export { Spot3D } from './spot-3d.js';
|
|
20
|
+
export { default as Stockpile } from './stockpile.js';
|
|
21
|
+
export type { StockpileState, StockpileRecord, StackPattern, CarrierPreset, PickPolicy } from './stockpile.js';
|
|
22
|
+
export { Stockpile3D } from './stockpile-3d.js';
|
|
23
|
+
export { default as StockpileGrid } from './stockpile-grid.js';
|
|
24
|
+
export type { StockpileGridState, StockpileGridCell } from './stockpile-grid.js';
|
|
25
|
+
export { StockpileGrid3D } from './stockpile-grid-3d.js';
|
|
26
|
+
export { default as PickingStation } from './picking-station.js';
|
|
27
|
+
export type { PickingStationState, PickingStationStatus } from './picking-station.js';
|
|
28
|
+
export { PickingStation3D } from './picking-station-3d.js';
|
|
20
29
|
export { default as GenericContainer } from './generic-container.js';
|
|
21
30
|
export type { ContainerStatus } from './generic-container.js';
|
|
22
31
|
export { GenericContainer3D } from './generic-container-3d.js';
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,12 @@ export { default as Crane } from './crane.js';
|
|
|
14
14
|
export { Crane3D } from './crane-3d.js';
|
|
15
15
|
export { default as Spot } from './spot.js';
|
|
16
16
|
export { Spot3D } from './spot-3d.js';
|
|
17
|
+
export { default as Stockpile } from './stockpile.js';
|
|
18
|
+
export { Stockpile3D } from './stockpile-3d.js';
|
|
19
|
+
export { default as StockpileGrid } from './stockpile-grid.js';
|
|
20
|
+
export { StockpileGrid3D } from './stockpile-grid-3d.js';
|
|
21
|
+
export { default as PickingStation } from './picking-station.js';
|
|
22
|
+
export { PickingStation3D } from './picking-station-3d.js';
|
|
17
23
|
export { default as GenericContainer } from './generic-container.js';
|
|
18
24
|
export { GenericContainer3D } from './generic-container-3d.js';
|
|
19
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,YAAY,CAAA;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nexport { default as Pallet } from './pallet.js'\nexport type { PalletMaterial } from './pallet.js'\n\nexport { default as Box } from './box.js'\nexport type { BoxMaterial } from './box.js'\n\nexport { default as Parcel } from './parcel.js'\n\nexport { default as StorageRack } from './storage-rack.js'\nexport type { StorageRackState } from './storage-rack.js'\nexport { StorageRack3D } from './storage-rack-3d.js'\nexport { default as RackGrid } from './rack-grid.js'\nexport type { RackGridState, CellOverride } from './rack-grid.js'\nexport { RackGrid3D } from './rack-grid-3d.js'\nexport { default as RackGridCell } from './rack-grid-cell.js'\nexport type { RackGridCellState } from './rack-grid-cell.js'\nexport { default as MobileStorageRack } from './mobile-storage-rack.js'\nexport { default as Crane } from './crane.js'\nexport type { CraneState, CraneStatus } from './crane.js'\nexport { Crane3D } from './crane-3d.js'\n\nexport { default as Spot } from './spot.js'\nexport { Spot3D } from './spot-3d.js'\n\nexport { default as GenericContainer } from './generic-container.js'\nexport type { ContainerStatus } from './generic-container.js'\nexport { GenericContainer3D } from './generic-container-3d.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,YAAY,CAAA;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAIrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE1D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nexport { default as Pallet } from './pallet.js'\nexport type { PalletMaterial } from './pallet.js'\n\nexport { default as Box } from './box.js'\nexport type { BoxMaterial } from './box.js'\n\nexport { default as Parcel } from './parcel.js'\n\nexport { default as StorageRack } from './storage-rack.js'\nexport type { StorageRackState } from './storage-rack.js'\nexport { StorageRack3D } from './storage-rack-3d.js'\nexport { default as RackGrid } from './rack-grid.js'\nexport type { RackGridState, CellOverride } from './rack-grid.js'\nexport { RackGrid3D } from './rack-grid-3d.js'\nexport { default as RackGridCell } from './rack-grid-cell.js'\nexport type { RackGridCellState } from './rack-grid-cell.js'\nexport { default as MobileStorageRack } from './mobile-storage-rack.js'\nexport { default as Crane } from './crane.js'\nexport type { CraneState, CraneStatus } from './crane.js'\nexport { Crane3D } from './crane-3d.js'\n\nexport { default as Spot } from './spot.js'\nexport { Spot3D } from './spot-3d.js'\n\nexport { default as Stockpile } from './stockpile.js'\nexport type {\n StockpileState, StockpileRecord, StackPattern, CarrierPreset, PickPolicy\n} from './stockpile.js'\nexport { Stockpile3D } from './stockpile-3d.js'\n\nexport { default as StockpileGrid } from './stockpile-grid.js'\nexport type { StockpileGridState, StockpileGridCell } from './stockpile-grid.js'\nexport { StockpileGrid3D } from './stockpile-grid-3d.js'\n\nexport { default as PickingStation } from './picking-station.js'\nexport type { PickingStationState, PickingStationStatus } from './picking-station.js'\nexport { PickingStation3D } from './picking-station-3d.js'\n\nexport { default as GenericContainer } from './generic-container.js'\nexport type { ContainerStatus } from './generic-container.js'\nexport { GenericContainer3D } from './generic-container-3d.js'\n"]}
|
package/dist/pallet.js
CHANGED
|
@@ -3,7 +3,7 @@ import { __decorate } from "tslib";
|
|
|
3
3
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
4
4
|
*/
|
|
5
5
|
import { ContainerAbstract, rectangularFootprintFrames, topApproachFrame, getWorldPose, sceneComponent } from '@hatiolab/things-scene';
|
|
6
|
-
import { Carriable, Legendable, Placeable } from '@operato/scene-base';
|
|
6
|
+
import { Carriable, Identifiable, Legendable, Placeable } from '@operato/scene-base';
|
|
7
7
|
import { Pallet3D } from './pallet-3d.js';
|
|
8
8
|
const BODY_LEGEND = {
|
|
9
9
|
wood: '#a87644',
|
|
@@ -69,7 +69,7 @@ const NATURE = {
|
|
|
69
69
|
* (machine-3d.ts:113-122). v1 accepts the visual overlap; v2 will add the
|
|
70
70
|
* detection.
|
|
71
71
|
*/
|
|
72
|
-
let Pallet = class Pallet extends Carriable(Legendable(Placeable(ContainerAbstract))) {
|
|
72
|
+
let Pallet = class Pallet extends Identifiable(Carriable(Legendable(Placeable(ContainerAbstract)))) {
|
|
73
73
|
static legends = {
|
|
74
74
|
bodyColor: { from: 'material', legend: BODY_LEGEND }
|
|
75
75
|
};
|
package/dist/pallet.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pallet.js","sourceRoot":"","sources":["../src/pallet.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport {\n Component,\n ComponentNature,\n ContainerAbstract,\n RealObject,\n Pose6DOF,\n rectangularFootprintFrames,\n topApproachFrame,\n getWorldPose,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State, Material3D, PickupFrame, PoseSerialized } from '@hatiolab/things-scene'\nimport {\n Carriable,\n Legendable,\n Placeable,\n type Alignment,\n type LegendBinding,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Pallet3D } from './pallet-3d.js'\n\n/**\n * Pallet material — drives both 2D fill color and 3D structure.\n *\n * - `wood` — traditional EUR / EPAL pallet: parallel slats on top and\n * bottom, three perpendicular stringers between them.\n * - `plastic` — molded one-piece pallet: solid top deck with cutouts,\n * hollow underside with feet. Distinct ribbed underside.\n *\n * Adding a third material (e.g. metal, composite) is a one-line change to the\n * legend + a 3D variant in pallet-3d.ts.\n */\nexport type PalletMaterial = 'wood' | 'plastic'\n\n/** Pallet 컴포넌트 state */\nexport interface PalletState extends State {\n // ── 외관 ──\n material?: PalletMaterial\n\n /**\n * Fork pocket 의 깊이 (mm) — pallet 외부 bottom (skid bottom) 부터 deck bottom\n * 까지의 수직 거리. fork blade 가 이 *pocket 안* 으로 수평 진입. 표준 EUR\n * pallet (144mm depth) 의 pocket ≈ 50~60mm.\n *\n * 미명시 시 default = depth 의 40% (= ~60mm for 150mm pallet).\n */\n pocketDepth?: number\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst BODY_LEGEND = {\n wood: '#a87644',\n plastic: '#5a6a78',\n default: '#a87644'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'material',\n name: 'material',\n property: {\n options: [\n { display: 'Wood', value: 'wood' },\n { display: 'Plastic', value: 'plastic' }\n ]\n }\n },\n {\n type: 'number',\n label: 'pocket-depth',\n name: 'pocketDepth',\n placeholder: 'mm — fork 진입 pocket 깊이 (skid bottom → deck bottom). default depth × 40%.'\n }\n ],\n help: 'scene/component/pallet'\n}\n\n// Carriable: a pallet can sit on AGV / Forklift / robot-arm gripper / Spot\n// and also accept boxes / parcels as children (ContainerAbstract base\n// provides the child-container behavior; Carriable only adds the\n// holder-mount hook).\n//\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Pallet renders only as a 3D mesh.\n/**\n * Pallet — a flat transport structure that goods are stacked and stored on.\n *\n * Standard EUR pallet is 1200 × 800mm × 144mm; we don't enforce these\n * dimensions but they're a good starting point for the catalog templates.\n *\n * **Container-based.** Boxes / parcels stacked on the pallet are added as\n * children — same `containable()` archetype-filter pattern as Forklift / Agv.\n * Visual stacking (children rendering on top of the pallet rather than at\n * absolute operation level) is a v2 concern; see ARCHITECTURE NOTES below.\n *\n * **Placement = `operation`.** A pallet's *normal* state is loaded and in\n * transit on a conveyor / AGV / forklift fork — at operation level. Empty\n * pallets in a floor-storage area are an exceptional state where the user\n * sets `state.zPos = 0` explicitly. Default to the common case.\n *\n * ## ARCHITECTURE NOTES — visual stacking\n *\n * When a Box (also `placement: 'operation'`) is added as a child of a\n * Pallet, both default to z = operation_height. They overlap visually\n * rather than the box sitting on top of the pallet. Solving this cleanly\n * (parent-relative z derivation when the parent is a structural carrier)\n * is a follow-up — fmsim's pattern is to detect parent type at render time\n * (machine-3d.ts:113-122). v1 accepts the visual overlap; v2 will add the\n * detection.\n */\n@sceneComponent('pallet')\nexport default class Pallet extends Carriable(Legendable(Placeable(ContainerAbstract))) {\n declare state: PalletState\n\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'material', legend: BODY_LEGEND }\n }\n\n static placement: PlacementArchetype = 'operation'\n static align: Alignment = 'bottom'\n static defaultDepth = 150 // EUR pallet is 144mm; 150 is the round number convention\n\n get nature() {\n return NATURE\n }\n\n /**\n * Fork pocket 의 깊이 — fork blade 가 진입하는 *pallet 외부 bottom 부터 deck\n * bottom* 까지의 수직 거리. crane.attachPointFor 가 이 값을 차감해서\n * carrier 외부 bottom (skid) 이 fork blade bottom *아래로 pocketDepth 만큼*\n * 깊이 정렬 (= fork 가 pallet 의 *deck 와 skid 사이* 안 으로 들어간 자세).\n */\n get pocketDepth(): number {\n const explicit = (this.state as any).pocketDepth\n if (typeof explicit === 'number' && Number.isFinite(explicit) && explicit >= 0) {\n return explicit\n }\n const d = this.state.depth\n const depth = typeof d === 'number' && Number.isFinite(d) && d > 0\n ? d\n : ((this.constructor as any).defaultDepth ?? 150)\n return depth * 0.4\n }\n\n get anchors() {\n return []\n }\n\n /** Accept other operation-archetype cargo (boxes, parcels, smaller pallets) as stacked children. */\n containable(component: Component) {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this)\n }\n\n /**\n * 2D — top-down silhouette. Body is a flat rectangle (wood/plastic deck);\n * `postrender()` adds the deck pattern + edge stroke so the pallet reads\n * as a pallet instead of a featureless rectangle.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n ctx.beginPath()\n ctx.rect(left, top, width, height)\n }\n\n /**\n * Deck pattern + edge stroke. Wood: parallel slats with darker grooves\n * between (typical EUR pallet deck). Plastic: cross-cutout pattern\n * suggesting the molded reinforcement ribs.\n *\n * Slats run along the *short* axis of the rectangle (= along the longer\n * stringer direction in real life), so a 1200×800 pallet shows multiple\n * narrow slats across the 1200mm dimension — matching the EUR layout.\n */\n postrender(ctx: CanvasRenderingContext2D) {\n super.postrender?.(ctx)\n\n const { width, height, left, top } = this.state\n const isPlastic = this.state.material === 'plastic'\n\n ctx.save()\n\n if (!isPlastic) {\n // Wood — slats. Run them along the longer axis so the grooves are\n // perpendicular to the longer side (typical pallet appearance).\n const longAxisHorizontal = width >= height\n const slatCount = 5\n const grooveColor = '#7a4f25'\n ctx.fillStyle = grooveColor\n if (longAxisHorizontal) {\n // grooves vertical (X direction across the width)\n const grooveW = Math.max(1, width * 0.012)\n const slatW = (width - grooveW * (slatCount - 1)) / slatCount\n for (let i = 1; i < slatCount; i++) {\n const x = left + i * slatW + (i - 1) * grooveW\n ctx.fillRect(x, top + height * 0.05, grooveW, height * 0.9)\n }\n } else {\n const grooveH = Math.max(1, height * 0.012)\n const slatH = (height - grooveH * (slatCount - 1)) / slatCount\n for (let i = 1; i < slatCount; i++) {\n const y = top + i * slatH + (i - 1) * grooveH\n ctx.fillRect(left + width * 0.05, y, width * 0.9, grooveH)\n }\n }\n } else {\n // Plastic — cross + corner cutouts hint\n ctx.strokeStyle = '#3a4956'\n ctx.lineWidth = Math.max(1, Math.min(width, height) * 0.012)\n ctx.beginPath()\n ctx.moveTo(left + width * 0.5, top + height * 0.1)\n ctx.lineTo(left + width * 0.5, top + height * 0.9)\n ctx.moveTo(left + width * 0.1, top + height * 0.5)\n ctx.lineTo(left + width * 0.9, top + height * 0.5)\n ctx.stroke()\n }\n\n // Edge stroke\n ctx.strokeStyle = isPlastic ? '#2a3946' : '#5e3818'\n ctx.lineWidth = 1\n ctx.strokeRect(left, top, width, height)\n\n ctx.restore()\n }\n\n get fillStyle() {\n return (this.state.bodyColor as string) || '#a87644'\n }\n\n buildRealObject(): RealObject | undefined {\n return new Pallet3D(this)\n }\n\n /**\n * Phase H — pickup contract. EUR/EPAL pallet 의 fork 진입은 양 단면 (긴 변\n * 두 군데). 'east' / 'west' = pallet 의 짧은 축 방향에서 fork 가 들어감.\n *\n * fork 진입 높이 (entryHeight) 는 pallet 의 fork pocket 위치 — pallet 의\n * 바닥에서 약 50mm (top deck 와 bottom deck 사이의 stringer 영역). 표준\n * EUR pallet 의 fork pocket 은 144mm 두께의 약 50% 지점.\n *\n * approachDistance 는 forklift 가 fork 끝을 pallet 에 닿기 직전 hover 자세 —\n * pallet 길이만큼 떨어져서 fork 길이 (보통 1100mm) 가 다 들어가도록 한다.\n * 여기선 conservative 하게 pallet 너비 + 200mm.\n */\n pickupFrames(): PickupFrame[] {\n const { width = 1200, height = 800 } = this.state\n const palletDepth = (this.constructor as any).defaultDepth ?? 150\n\n // 4-way pallet: 모든 면에서 fork 진입 가능. 2-way 는 sides 를 ['east','west']\n // 로 한정 — pallet 의 stringer 방향에 따라 다르나 default 는 4-way 가정.\n // (state.palletType 같은 속성 추가 시 분기 가능 — 현재는 4-way 가정.)\n const me: PoseSerialized = (() => {\n const wp = getWorldPose(this)\n return {\n position: { x: wp.position.x, y: wp.position.y, z: wp.position.z },\n rotation: { x: wp.rotation.x, y: wp.rotation.y, z: wp.rotation.z, w: wp.rotation.w }\n }\n })()\n\n const longerAxis = Math.max(width, height)\n\n const forkFrames = rectangularFootprintFrames({\n carrierWorld: me,\n width,\n depth: height,\n entryHeight: palletDepth * 0.4, // fork pocket 중심\n approachDistance: longerAxis + 200,\n sides: ['east', 'west', 'north', 'south'],\n toolType: 'forklift-fork',\n tolerance: { positionMm: 50, angleDeg: 5 },\n priority: 0\n })\n\n // 큰 AGV (deck size 충분) 가 pallet 을 위에 적재하는 패턴. priority 낮음\n // — forklift fork 가 더 자연스러운 default. AGV deck size 가 pallet 보다\n // 작으면 application 측이 carrier 의 dimensions check 필요.\n const deckFrame = topApproachFrame({\n carrierWorld: me,\n topY: palletDepth,\n approachDistance: longerAxis * 0.5 + 100,\n toolType: 'agv-deck',\n tolerance: { positionMm: 30, angleDeg: 4 },\n priority: 1,\n id: 'top-deck'\n })\n\n return [...forkFrames, deckFrame]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pallet.js","sourceRoot":"","sources":["../src/pallet.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport {\n Component,\n ComponentNature,\n ContainerAbstract,\n RealObject,\n Pose6DOF,\n rectangularFootprintFrames,\n topApproachFrame,\n getWorldPose,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State, Material3D, PickupFrame, PoseSerialized } from '@hatiolab/things-scene'\nimport {\n Carriable,\n Identifiable,\n Legendable,\n Placeable,\n type Alignment,\n type LegendBinding,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Pallet3D } from './pallet-3d.js'\n\n/**\n * Pallet material — drives both 2D fill color and 3D structure.\n *\n * - `wood` — traditional EUR / EPAL pallet: parallel slats on top and\n * bottom, three perpendicular stringers between them.\n * - `plastic` — molded one-piece pallet: solid top deck with cutouts,\n * hollow underside with feet. Distinct ribbed underside.\n *\n * Adding a third material (e.g. metal, composite) is a one-line change to the\n * legend + a 3D variant in pallet-3d.ts.\n */\nexport type PalletMaterial = 'wood' | 'plastic'\n\n/** Pallet 컴포넌트 state */\nexport interface PalletState extends State {\n // ── 외관 ──\n material?: PalletMaterial\n\n /**\n * Fork pocket 의 깊이 (mm) — pallet 외부 bottom (skid bottom) 부터 deck bottom\n * 까지의 수직 거리. fork blade 가 이 *pocket 안* 으로 수평 진입. 표준 EUR\n * pallet (144mm depth) 의 pocket ≈ 50~60mm.\n *\n * 미명시 시 default = depth 의 40% (= ~60mm for 150mm pallet).\n */\n pocketDepth?: number\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst BODY_LEGEND = {\n wood: '#a87644',\n plastic: '#5a6a78',\n default: '#a87644'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'material',\n name: 'material',\n property: {\n options: [\n { display: 'Wood', value: 'wood' },\n { display: 'Plastic', value: 'plastic' }\n ]\n }\n },\n {\n type: 'number',\n label: 'pocket-depth',\n name: 'pocketDepth',\n placeholder: 'mm — fork 진입 pocket 깊이 (skid bottom → deck bottom). default depth × 40%.'\n }\n ],\n help: 'scene/component/pallet'\n}\n\n// Carriable: a pallet can sit on AGV / Forklift / robot-arm gripper / Spot\n// and also accept boxes / parcels as children (ContainerAbstract base\n// provides the child-container behavior; Carriable only adds the\n// holder-mount hook).\n//\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Pallet renders only as a 3D mesh.\n/**\n * Pallet — a flat transport structure that goods are stacked and stored on.\n *\n * Standard EUR pallet is 1200 × 800mm × 144mm; we don't enforce these\n * dimensions but they're a good starting point for the catalog templates.\n *\n * **Container-based.** Boxes / parcels stacked on the pallet are added as\n * children — same `containable()` archetype-filter pattern as Forklift / Agv.\n * Visual stacking (children rendering on top of the pallet rather than at\n * absolute operation level) is a v2 concern; see ARCHITECTURE NOTES below.\n *\n * **Placement = `operation`.** A pallet's *normal* state is loaded and in\n * transit on a conveyor / AGV / forklift fork — at operation level. Empty\n * pallets in a floor-storage area are an exceptional state where the user\n * sets `state.zPos = 0` explicitly. Default to the common case.\n *\n * ## ARCHITECTURE NOTES — visual stacking\n *\n * When a Box (also `placement: 'operation'`) is added as a child of a\n * Pallet, both default to z = operation_height. They overlap visually\n * rather than the box sitting on top of the pallet. Solving this cleanly\n * (parent-relative z derivation when the parent is a structural carrier)\n * is a follow-up — fmsim's pattern is to detect parent type at render time\n * (machine-3d.ts:113-122). v1 accepts the visual overlap; v2 will add the\n * detection.\n */\n@sceneComponent('pallet')\nexport default class Pallet extends Identifiable(Carriable(Legendable(Placeable(ContainerAbstract)))) {\n declare state: PalletState\n\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'material', legend: BODY_LEGEND }\n }\n\n static placement: PlacementArchetype = 'operation'\n static align: Alignment = 'bottom'\n static defaultDepth = 150 // EUR pallet is 144mm; 150 is the round number convention\n\n get nature() {\n return NATURE\n }\n\n /**\n * Fork pocket 의 깊이 — fork blade 가 진입하는 *pallet 외부 bottom 부터 deck\n * bottom* 까지의 수직 거리. crane.attachPointFor 가 이 값을 차감해서\n * carrier 외부 bottom (skid) 이 fork blade bottom *아래로 pocketDepth 만큼*\n * 깊이 정렬 (= fork 가 pallet 의 *deck 와 skid 사이* 안 으로 들어간 자세).\n */\n get pocketDepth(): number {\n const explicit = (this.state as any).pocketDepth\n if (typeof explicit === 'number' && Number.isFinite(explicit) && explicit >= 0) {\n return explicit\n }\n const d = this.state.depth\n const depth = typeof d === 'number' && Number.isFinite(d) && d > 0\n ? d\n : ((this.constructor as any).defaultDepth ?? 150)\n return depth * 0.4\n }\n\n get anchors() {\n return []\n }\n\n /** Accept other operation-archetype cargo (boxes, parcels, smaller pallets) as stacked children. */\n containable(component: Component) {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this)\n }\n\n /**\n * 2D — top-down silhouette. Body is a flat rectangle (wood/plastic deck);\n * `postrender()` adds the deck pattern + edge stroke so the pallet reads\n * as a pallet instead of a featureless rectangle.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n ctx.beginPath()\n ctx.rect(left, top, width, height)\n }\n\n /**\n * Deck pattern + edge stroke. Wood: parallel slats with darker grooves\n * between (typical EUR pallet deck). Plastic: cross-cutout pattern\n * suggesting the molded reinforcement ribs.\n *\n * Slats run along the *short* axis of the rectangle (= along the longer\n * stringer direction in real life), so a 1200×800 pallet shows multiple\n * narrow slats across the 1200mm dimension — matching the EUR layout.\n */\n postrender(ctx: CanvasRenderingContext2D) {\n super.postrender?.(ctx)\n\n const { width, height, left, top } = this.state\n const isPlastic = this.state.material === 'plastic'\n\n ctx.save()\n\n if (!isPlastic) {\n // Wood — slats. Run them along the longer axis so the grooves are\n // perpendicular to the longer side (typical pallet appearance).\n const longAxisHorizontal = width >= height\n const slatCount = 5\n const grooveColor = '#7a4f25'\n ctx.fillStyle = grooveColor\n if (longAxisHorizontal) {\n // grooves vertical (X direction across the width)\n const grooveW = Math.max(1, width * 0.012)\n const slatW = (width - grooveW * (slatCount - 1)) / slatCount\n for (let i = 1; i < slatCount; i++) {\n const x = left + i * slatW + (i - 1) * grooveW\n ctx.fillRect(x, top + height * 0.05, grooveW, height * 0.9)\n }\n } else {\n const grooveH = Math.max(1, height * 0.012)\n const slatH = (height - grooveH * (slatCount - 1)) / slatCount\n for (let i = 1; i < slatCount; i++) {\n const y = top + i * slatH + (i - 1) * grooveH\n ctx.fillRect(left + width * 0.05, y, width * 0.9, grooveH)\n }\n }\n } else {\n // Plastic — cross + corner cutouts hint\n ctx.strokeStyle = '#3a4956'\n ctx.lineWidth = Math.max(1, Math.min(width, height) * 0.012)\n ctx.beginPath()\n ctx.moveTo(left + width * 0.5, top + height * 0.1)\n ctx.lineTo(left + width * 0.5, top + height * 0.9)\n ctx.moveTo(left + width * 0.1, top + height * 0.5)\n ctx.lineTo(left + width * 0.9, top + height * 0.5)\n ctx.stroke()\n }\n\n // Edge stroke\n ctx.strokeStyle = isPlastic ? '#2a3946' : '#5e3818'\n ctx.lineWidth = 1\n ctx.strokeRect(left, top, width, height)\n\n ctx.restore()\n }\n\n get fillStyle() {\n return (this.state.bodyColor as string) || '#a87644'\n }\n\n buildRealObject(): RealObject | undefined {\n return new Pallet3D(this)\n }\n\n /**\n * Phase H — pickup contract. EUR/EPAL pallet 의 fork 진입은 양 단면 (긴 변\n * 두 군데). 'east' / 'west' = pallet 의 짧은 축 방향에서 fork 가 들어감.\n *\n * fork 진입 높이 (entryHeight) 는 pallet 의 fork pocket 위치 — pallet 의\n * 바닥에서 약 50mm (top deck 와 bottom deck 사이의 stringer 영역). 표준\n * EUR pallet 의 fork pocket 은 144mm 두께의 약 50% 지점.\n *\n * approachDistance 는 forklift 가 fork 끝을 pallet 에 닿기 직전 hover 자세 —\n * pallet 길이만큼 떨어져서 fork 길이 (보통 1100mm) 가 다 들어가도록 한다.\n * 여기선 conservative 하게 pallet 너비 + 200mm.\n */\n pickupFrames(): PickupFrame[] {\n const { width = 1200, height = 800 } = this.state\n const palletDepth = (this.constructor as any).defaultDepth ?? 150\n\n // 4-way pallet: 모든 면에서 fork 진입 가능. 2-way 는 sides 를 ['east','west']\n // 로 한정 — pallet 의 stringer 방향에 따라 다르나 default 는 4-way 가정.\n // (state.palletType 같은 속성 추가 시 분기 가능 — 현재는 4-way 가정.)\n const me: PoseSerialized = (() => {\n const wp = getWorldPose(this)\n return {\n position: { x: wp.position.x, y: wp.position.y, z: wp.position.z },\n rotation: { x: wp.rotation.x, y: wp.rotation.y, z: wp.rotation.z, w: wp.rotation.w }\n }\n })()\n\n const longerAxis = Math.max(width, height)\n\n const forkFrames = rectangularFootprintFrames({\n carrierWorld: me,\n width,\n depth: height,\n entryHeight: palletDepth * 0.4, // fork pocket 중심\n approachDistance: longerAxis + 200,\n sides: ['east', 'west', 'north', 'south'],\n toolType: 'forklift-fork',\n tolerance: { positionMm: 50, angleDeg: 5 },\n priority: 0\n })\n\n // 큰 AGV (deck size 충분) 가 pallet 을 위에 적재하는 패턴. priority 낮음\n // — forklift fork 가 더 자연스러운 default. AGV deck size 가 pallet 보다\n // 작으면 application 측이 carrier 의 dimensions check 필요.\n const deckFrame = topApproachFrame({\n carrierWorld: me,\n topY: palletDepth,\n approachDistance: longerAxis * 0.5 + 100,\n toolType: 'agv-deck',\n tolerance: { positionMm: 30, angleDeg: 4 },\n priority: 1,\n id: 'top-deck'\n })\n\n return [...forkFrames, deckFrame]\n }\n}\n"]}
|
package/dist/parcel.js
CHANGED
|
@@ -3,7 +3,7 @@ import { __decorate } from "tslib";
|
|
|
3
3
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
4
4
|
*/
|
|
5
5
|
import { RectPath, Shape, topApproachFrame, getWorldPose, sceneComponent } from '@hatiolab/things-scene';
|
|
6
|
-
import { Carriable, Placeable } from '@operato/scene-base';
|
|
6
|
+
import { Carriable, Identifiable, Placeable } from '@operato/scene-base';
|
|
7
7
|
import { Parcel3D } from './parcel-3d.js';
|
|
8
8
|
const NATURE = {
|
|
9
9
|
mutable: false,
|
|
@@ -36,7 +36,7 @@ const NATURE = {
|
|
|
36
36
|
* No Legendable for v1 — parcel color is fixed cardboard. Future damaged /
|
|
37
37
|
* inspected indicators would add a status legend then.
|
|
38
38
|
*/
|
|
39
|
-
let Parcel = class Parcel extends Carriable(Placeable(RectPath(Shape))) {
|
|
39
|
+
let Parcel = class Parcel extends Identifiable(Carriable(Placeable(RectPath(Shape)))) {
|
|
40
40
|
static placement = 'operation';
|
|
41
41
|
static align = 'bottom';
|
|
42
42
|
static defaultDepth = 150;
|
package/dist/parcel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parcel.js","sourceRoot":"","sources":["../src/parcel.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,EAGL,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACf,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACL,SAAS,EACT,SAAS,EAGV,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAWzC,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,aAAa;YACpB,IAAI,EAAE,YAAY;SACnB;KACF;IACD,IAAI,EAAE,wBAAwB;CAC/B,CAAA;AAED,yEAAyE;AACzE,uEAAuE;AACvE,oDAAoD;AACpD;;;;;;;;;;;;;;GAcG;AAEY,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"parcel.js","sourceRoot":"","sources":["../src/parcel.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport {\n ComponentNature,\n RealObject,\n RectPath,\n Shape,\n topApproachFrame,\n getWorldPose,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State, Material3D, PickupFrame, PoseSerialized } from '@hatiolab/things-scene'\nimport {\n Carriable,\n Identifiable,\n Placeable,\n type Alignment,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Parcel3D } from './parcel-3d.js'\n\n/** Parcel 컴포넌트 state */\nexport interface ParcelState extends State {\n // ── 정체 ──\n trackingId?: string\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'string',\n label: 'tracking-id',\n name: 'trackingId'\n }\n ],\n help: 'scene/component/parcel'\n}\n\n// Carriable: parcel can be a child of any CarrierHolder (Spot, robot-arm\n// gripper, AGV deck, …). Mixin wraps add() so the parcel's 3D object3d\n// is reattached to the holder's chosen mount frame.\n/**\n * Parcel — a cardboard package, the typical e-commerce / parcel-sortation unit.\n *\n * Distinct from `Box` because parcels have:\n * - cardboard appearance (tan/brown corrugate, not wood / plastic)\n * - tape line down the center (the visual signature that says \"package\")\n * - typically a label on top (where shipping info goes)\n * - flatter / more elongated proportions in real-world parcel networks\n *\n * No `material` prop — parcels are always cardboard. If a future shipping\n * domain needs metal cases or polybags, those become separate components.\n *\n * No Legendable for v1 — parcel color is fixed cardboard. Future damaged /\n * inspected indicators would add a status legend then.\n */\n@sceneComponent('parcel')\nexport default class Parcel extends Identifiable(Carriable(Placeable(RectPath(Shape)))) {\n declare state: ParcelState\n\n static placement: PlacementArchetype = 'operation'\n static align: Alignment = 'bottom'\n static defaultDepth = 150\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /** 2D — top-down rectangle in cardboard tan. */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n ctx.beginPath()\n ctx.rect(left, top, width, height)\n }\n\n get fillStyle() {\n return '#c8a878'\n }\n\n buildRealObject(): RealObject | undefined {\n return new Parcel3D(this)\n }\n\n /**\n * Phase H — pickup contract. Parcel 의 pickup 방식:\n * - gripper (vacuum / suction): 위에서 흡착 — RobotArm\n * - agv-deck: AGV/Forklift 의 deck 위에 위에서 얹기 — 같은 top approach 지만\n * deck 자체가 운반체라 tolerance 더 완화\n */\n pickupFrames(): PickupFrame[] {\n const wp = getWorldPose(this)\n const me: PoseSerialized = {\n position: { x: wp.position.x, y: wp.position.y, z: wp.position.z },\n rotation: { x: wp.rotation.x, y: wp.rotation.y, z: wp.rotation.z, w: wp.rotation.w }\n }\n const parcelDepth = (this.constructor as any).defaultDepth ?? 150\n\n return [\n topApproachFrame({\n carrierWorld: me,\n topY: parcelDepth,\n approachDistance: 80,\n toolType: 'gripper',\n tolerance: { positionMm: 10, angleDeg: 2 },\n priority: 0,\n id: 'top-suction'\n }),\n topApproachFrame({\n carrierWorld: me,\n topY: parcelDepth,\n approachDistance: 60,\n toolType: 'agv-deck',\n tolerance: { positionMm: 20, angleDeg: 5 },\n priority: 1,\n id: 'top-deck'\n }),\n topApproachFrame({\n carrierWorld: me,\n topY: parcelDepth,\n approachDistance: 100, // crane fork 가 cell 진입 hover\n toolType: 'forklift-fork',\n tolerance: { positionMm: 30, angleDeg: 5 }, // fork 적재 tolerance\n priority: 2, // gripper/deck 다음\n id: 'top-fork'\n })\n ]\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
3
|
+
export declare class PickingStation3D extends RealObjectGroup {
|
|
4
|
+
private _padMesh?;
|
|
5
|
+
private _padOutline?;
|
|
6
|
+
private _tableMesh?;
|
|
7
|
+
build(): void;
|
|
8
|
+
/** carrier 안착 anchor — 작업대 top face. */
|
|
9
|
+
getAttachFrame(): THREE.Object3D | undefined;
|
|
10
|
+
private _padColor;
|
|
11
|
+
private _strokeColor;
|
|
12
|
+
/** status 에 따른 작업대 색 — idle/processing/busy. */
|
|
13
|
+
private _statusColor;
|
|
14
|
+
private _applyPadColor;
|
|
15
|
+
private _applyStrokeColor;
|
|
16
|
+
private _applyStatusColor;
|
|
17
|
+
updateAlpha(): void;
|
|
18
|
+
updateDimension(): void;
|
|
19
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* PickingStation3D — 사람 작업 위치의 3D 시각화. pad(영역) + 작업대(가운데 box, top
|
|
5
|
+
* face 가 carrier 안착면). status 별 색 변화 (idle/processing/busy) 로 작업 진행
|
|
6
|
+
* 인지성.
|
|
7
|
+
*/
|
|
8
|
+
import * as THREE from 'three';
|
|
9
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
10
|
+
const PAD_DEPTH = 2;
|
|
11
|
+
const STATUS_TINT = {
|
|
12
|
+
idle: 0x4a7a9b, // 차분한 blue-grey
|
|
13
|
+
processing: 0xd9943a, // 작업 중 — 주황
|
|
14
|
+
busy: 0xc04040 // busy/blocked — 빨강
|
|
15
|
+
};
|
|
16
|
+
export class PickingStation3D extends RealObjectGroup {
|
|
17
|
+
_padMesh;
|
|
18
|
+
_padOutline;
|
|
19
|
+
_tableMesh;
|
|
20
|
+
build() {
|
|
21
|
+
super.build();
|
|
22
|
+
const state = this.component.state;
|
|
23
|
+
const w = state.width ?? 100;
|
|
24
|
+
const h = state.height ?? 100;
|
|
25
|
+
const depth = state.depth ?? 5;
|
|
26
|
+
// ── pad (영역) ─────────────────────────────────────────────
|
|
27
|
+
const padGeom = new THREE.BoxGeometry(w, PAD_DEPTH, h);
|
|
28
|
+
const padMat = new THREE.MeshStandardMaterial({
|
|
29
|
+
color: this._padColor(), roughness: 0.85, transparent: true, opacity: 0.5
|
|
30
|
+
});
|
|
31
|
+
this._padMesh = new THREE.Mesh(padGeom, padMat);
|
|
32
|
+
this._padMesh.position.y = PAD_DEPTH / 2;
|
|
33
|
+
this._padMesh.receiveShadow = true;
|
|
34
|
+
this.object3d.add(this._padMesh);
|
|
35
|
+
// pad outline
|
|
36
|
+
const outline = new THREE.LineBasicMaterial({ color: this._strokeColor() });
|
|
37
|
+
this._padOutline = new THREE.LineSegments(new THREE.EdgesGeometry(padGeom), outline);
|
|
38
|
+
this._padOutline.position.y = PAD_DEPTH / 2;
|
|
39
|
+
this.object3d.add(this._padOutline);
|
|
40
|
+
// ── 작업대 (table) — pad 위 가운데 box. top face = carrier 안착면. ──
|
|
41
|
+
const tableW = w * 0.55;
|
|
42
|
+
const tableH = h * 0.45;
|
|
43
|
+
const tableD = Math.max(8, depth); // 작업면 높이 — operation height 근사
|
|
44
|
+
const tableGeom = new THREE.BoxGeometry(tableW, tableD, tableH);
|
|
45
|
+
const tableMat = new THREE.MeshStandardMaterial({
|
|
46
|
+
color: this._statusColor(), roughness: 0.6, metalness: 0.1
|
|
47
|
+
});
|
|
48
|
+
this._tableMesh = new THREE.Mesh(tableGeom, tableMat);
|
|
49
|
+
this._tableMesh.position.y = PAD_DEPTH + tableD / 2;
|
|
50
|
+
this._tableMesh.castShadow = true;
|
|
51
|
+
this._tableMesh.receiveShadow = true;
|
|
52
|
+
this.object3d.add(this._tableMesh);
|
|
53
|
+
}
|
|
54
|
+
/** carrier 안착 anchor — 작업대 top face. */
|
|
55
|
+
getAttachFrame() {
|
|
56
|
+
return this._tableMesh ?? this._padMesh;
|
|
57
|
+
}
|
|
58
|
+
_padColor() {
|
|
59
|
+
const raw = this.component.state?.fillStyle;
|
|
60
|
+
if (typeof raw === 'string' && raw.length > 0) {
|
|
61
|
+
try {
|
|
62
|
+
return new THREE.Color(raw);
|
|
63
|
+
}
|
|
64
|
+
catch { /* fallthrough */ }
|
|
65
|
+
}
|
|
66
|
+
return new THREE.Color(0x5a8ab8);
|
|
67
|
+
}
|
|
68
|
+
_strokeColor() {
|
|
69
|
+
const raw = this.component.state?.strokeStyle;
|
|
70
|
+
if (typeof raw === 'string' && raw.length > 0) {
|
|
71
|
+
try {
|
|
72
|
+
return new THREE.Color(raw);
|
|
73
|
+
}
|
|
74
|
+
catch { /* fallthrough */ }
|
|
75
|
+
}
|
|
76
|
+
return this._padColor().clone().multiplyScalar(0.6);
|
|
77
|
+
}
|
|
78
|
+
/** status 에 따른 작업대 색 — idle/processing/busy. */
|
|
79
|
+
_statusColor() {
|
|
80
|
+
const s = this.component.state?.status;
|
|
81
|
+
return new THREE.Color(STATUS_TINT[s ?? 'idle'] ?? STATUS_TINT.idle);
|
|
82
|
+
}
|
|
83
|
+
_applyPadColor() {
|
|
84
|
+
if (this._padMesh) {
|
|
85
|
+
const m = this._padMesh.material;
|
|
86
|
+
m.color.copy(this._padColor());
|
|
87
|
+
m.needsUpdate = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
_applyStrokeColor() {
|
|
91
|
+
if (this._padOutline) {
|
|
92
|
+
const m = this._padOutline.material;
|
|
93
|
+
m.color.copy(this._strokeColor());
|
|
94
|
+
m.needsUpdate = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
_applyStatusColor() {
|
|
98
|
+
if (this._tableMesh) {
|
|
99
|
+
const m = this._tableMesh.material;
|
|
100
|
+
m.color.copy(this._statusColor());
|
|
101
|
+
m.needsUpdate = true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
updateAlpha() {
|
|
105
|
+
const alpha = typeof this.component.state.alpha === 'number'
|
|
106
|
+
? this.component.state.alpha : 1;
|
|
107
|
+
if (this._padMesh) {
|
|
108
|
+
const m = this._padMesh.material;
|
|
109
|
+
m.opacity = 0.5 * alpha;
|
|
110
|
+
m.transparent = m.opacity < 1;
|
|
111
|
+
m.needsUpdate = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
updateDimension() {
|
|
115
|
+
if (this._padMesh) {
|
|
116
|
+
const state = this.component.state;
|
|
117
|
+
const w = state.width ?? 100;
|
|
118
|
+
const h = state.height ?? 100;
|
|
119
|
+
const depth = state.depth ?? 5;
|
|
120
|
+
this._padMesh.geometry.dispose();
|
|
121
|
+
this._padMesh.geometry = new THREE.BoxGeometry(w, PAD_DEPTH, h);
|
|
122
|
+
if (this._padOutline) {
|
|
123
|
+
this._padOutline.geometry.dispose();
|
|
124
|
+
this._padOutline.geometry = new THREE.EdgesGeometry(this._padMesh.geometry);
|
|
125
|
+
}
|
|
126
|
+
if (this._tableMesh) {
|
|
127
|
+
const tableW = w * 0.55;
|
|
128
|
+
const tableH = h * 0.45;
|
|
129
|
+
const tableD = Math.max(8, depth);
|
|
130
|
+
this._tableMesh.geometry.dispose();
|
|
131
|
+
this._tableMesh.geometry = new THREE.BoxGeometry(tableW, tableD, tableH);
|
|
132
|
+
this._tableMesh.position.y = PAD_DEPTH + tableD / 2;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
onchange(after, before) {
|
|
137
|
+
if ('width' in after || 'height' in after || 'depth' in after) {
|
|
138
|
+
this.updateDimension();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if ('alpha' in after) {
|
|
142
|
+
this.updateAlpha();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if ('fillStyle' in after) {
|
|
146
|
+
this._applyPadColor();
|
|
147
|
+
if (this.component.state.strokeStyle == null)
|
|
148
|
+
this._applyStrokeColor();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if ('strokeStyle' in after) {
|
|
152
|
+
this._applyStrokeColor();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if ('status' in after) {
|
|
156
|
+
this._applyStatusColor();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
super.onchange?.(after, before);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=picking-station-3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picking-station-3d.js","sourceRoot":"","sources":["../src/picking-station-3d.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAKxD,MAAM,SAAS,GAAG,CAAC,CAAA;AAEnB,MAAM,WAAW,GAAyC;IACxD,IAAI,EAAE,QAAQ,EAAS,gBAAgB;IACvC,UAAU,EAAE,QAAQ,EAAG,YAAY;IACnC,IAAI,EAAE,QAAQ,CAAU,oBAAoB;CAC7C,CAAA;AAED,MAAM,OAAO,gBAAiB,SAAQ,eAAe;IAC3C,QAAQ,CAAa;IACrB,WAAW,CAAqB;IAChC,UAAU,CAAa;IAE/B,KAAK;QACH,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,KAAY,CAAA;QACzC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,CAAA;QAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;QAE9B,4DAA4D;QAC5D,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YAC5C,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG;SAC1E,CAAC,CAAA;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC/C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;QACxC,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAA;QAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAEhC,cAAc;QACd,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA;QAC3E,IAAI,CAAC,WAAW,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAA;QACpF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAEnC,6DAA6D;QAC7D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAA;QACvB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAA;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA,CAAG,+BAA+B;QACnE,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/D,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;SAC3D,CAAC,CAAA;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QACrD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,CAAC,CAAA;QACnD,IAAI,CAAC,UAAU,CAAC,UAAU,GAAG,IAAI,CAAA;QACjC,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,IAAI,CAAA;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC;IAED,wCAAwC;IACxC,cAAc;QACZ,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAA;IACzC,CAAC;IAEO,SAAS;QACf,MAAM,GAAG,GAAI,IAAI,CAAC,SAAS,CAAC,KAAa,EAAE,SAAS,CAAA;QACpD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC;gBAAC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IAClC,CAAC;IAEO,YAAY;QAClB,MAAM,GAAG,GAAI,IAAI,CAAC,SAAS,CAAC,KAAa,EAAE,WAAW,CAAA;QACtD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC;gBAAC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAA;IACrD,CAAC;IAED,gDAAgD;IACxC,YAAY;QAClB,MAAM,CAAC,GAAI,IAAI,CAAC,SAAS,CAAC,KAAa,EAAE,MAA0C,CAAA;QACnF,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAA;IACtE,CAAC;IAEO,cAAc;QACpB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAsC,CAAA;YAC9D,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;YAC9B,CAAC,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,CAAC;IACH,CAAC;IACO,iBAAiB;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,QAAmC,CAAA;YAC9D,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAA;YACjC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,CAAC;IACH,CAAC;IACO,iBAAiB;QACvB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,QAAsC,CAAA;YAChE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAA;YACjC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,CAAC;IACH,CAAC;IAED,WAAW;QACT,MAAM,KAAK,GAAG,OAAQ,IAAI,CAAC,SAAS,CAAC,KAAa,CAAC,KAAK,KAAK,QAAQ;YACnE,CAAC,CAAE,IAAI,CAAC,SAAS,CAAC,KAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC3C,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAsC,CAAA;YAC9D,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,KAAK,CAAA;YACvB,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAA;YAC7B,CAAC,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,CAAC;IACH,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,KAAY,CAAA;YACzC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,CAAA;YAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;YAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;YAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;YAChC,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;YAC/D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;gBACnC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC7E,CAAC;YACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAA;gBACvB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAA;gBACvB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;gBACjC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;gBAClC,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;gBACxE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,CAAC,CAAA;YACrD,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,KAA8B,EAAE,MAA+B;QACtE,IAAI,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;YAC9D,IAAI,CAAC,eAAe,EAAE,CAAA;YACtB,OAAM;QACR,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;YAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAAC,OAAM;QAAC,CAAC;QACpD,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,cAAc,EAAE,CAAA;YACrB,IAAK,IAAI,CAAC,SAAS,CAAC,KAAa,CAAC,WAAW,IAAI,IAAI;gBAAE,IAAI,CAAC,iBAAiB,EAAE,CAAA;YAC/E,OAAM;QACR,CAAC;QACD,IAAI,aAAa,IAAI,KAAK,EAAE,CAAC;YAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAAC,OAAM;QAAC,CAAC;QAChE,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAAC,OAAM;QAAC,CAAC;QAC3D,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IACjC,CAAC;CACF","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * PickingStation3D — 사람 작업 위치의 3D 시각화. pad(영역) + 작업대(가운데 box, top\n * face 가 carrier 안착면). status 별 색 변화 (idle/processing/busy) 로 작업 진행\n * 인지성.\n */\n\nimport * as THREE from 'three'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nimport type PickingStation from './picking-station.js'\nimport type { PickingStationStatus } from './picking-station.js'\n\nconst PAD_DEPTH = 2\n\nconst STATUS_TINT: Record<PickingStationStatus, number> = {\n idle: 0x4a7a9b, // 차분한 blue-grey\n processing: 0xd9943a, // 작업 중 — 주황\n busy: 0xc04040 // busy/blocked — 빨강\n}\n\nexport class PickingStation3D extends RealObjectGroup {\n private _padMesh?: THREE.Mesh\n private _padOutline?: THREE.LineSegments\n private _tableMesh?: THREE.Mesh\n\n build() {\n super.build()\n const state = this.component.state as any\n const w = state.width ?? 100\n const h = state.height ?? 100\n const depth = state.depth ?? 5\n\n // ── pad (영역) ─────────────────────────────────────────────\n const padGeom = new THREE.BoxGeometry(w, PAD_DEPTH, h)\n const padMat = new THREE.MeshStandardMaterial({\n color: this._padColor(), roughness: 0.85, transparent: true, opacity: 0.5\n })\n this._padMesh = new THREE.Mesh(padGeom, padMat)\n this._padMesh.position.y = PAD_DEPTH / 2\n this._padMesh.receiveShadow = true\n this.object3d.add(this._padMesh)\n\n // pad outline\n const outline = new THREE.LineBasicMaterial({ color: this._strokeColor() })\n this._padOutline = new THREE.LineSegments(new THREE.EdgesGeometry(padGeom), outline)\n this._padOutline.position.y = PAD_DEPTH / 2\n this.object3d.add(this._padOutline)\n\n // ── 작업대 (table) — pad 위 가운데 box. top face = carrier 안착면. ──\n const tableW = w * 0.55\n const tableH = h * 0.45\n const tableD = Math.max(8, depth) // 작업면 높이 — operation height 근사\n const tableGeom = new THREE.BoxGeometry(tableW, tableD, tableH)\n const tableMat = new THREE.MeshStandardMaterial({\n color: this._statusColor(), roughness: 0.6, metalness: 0.1\n })\n this._tableMesh = new THREE.Mesh(tableGeom, tableMat)\n this._tableMesh.position.y = PAD_DEPTH + tableD / 2\n this._tableMesh.castShadow = true\n this._tableMesh.receiveShadow = true\n this.object3d.add(this._tableMesh)\n }\n\n /** carrier 안착 anchor — 작업대 top face. */\n getAttachFrame(): THREE.Object3D | undefined {\n return this._tableMesh ?? this._padMesh\n }\n\n private _padColor(): THREE.Color {\n const raw = (this.component.state as any)?.fillStyle\n if (typeof raw === 'string' && raw.length > 0) {\n try { return new THREE.Color(raw) } catch { /* fallthrough */ }\n }\n return new THREE.Color(0x5a8ab8)\n }\n\n private _strokeColor(): THREE.Color {\n const raw = (this.component.state as any)?.strokeStyle\n if (typeof raw === 'string' && raw.length > 0) {\n try { return new THREE.Color(raw) } catch { /* fallthrough */ }\n }\n return this._padColor().clone().multiplyScalar(0.6)\n }\n\n /** status 에 따른 작업대 색 — idle/processing/busy. */\n private _statusColor(): THREE.Color {\n const s = (this.component.state as any)?.status as PickingStationStatus | undefined\n return new THREE.Color(STATUS_TINT[s ?? 'idle'] ?? STATUS_TINT.idle)\n }\n\n private _applyPadColor(): void {\n if (this._padMesh) {\n const m = this._padMesh.material as THREE.MeshStandardMaterial\n m.color.copy(this._padColor())\n m.needsUpdate = true\n }\n }\n private _applyStrokeColor(): void {\n if (this._padOutline) {\n const m = this._padOutline.material as THREE.LineBasicMaterial\n m.color.copy(this._strokeColor())\n m.needsUpdate = true\n }\n }\n private _applyStatusColor(): void {\n if (this._tableMesh) {\n const m = this._tableMesh.material as THREE.MeshStandardMaterial\n m.color.copy(this._statusColor())\n m.needsUpdate = true\n }\n }\n\n updateAlpha(): void {\n const alpha = typeof (this.component.state as any).alpha === 'number'\n ? (this.component.state as any).alpha : 1\n if (this._padMesh) {\n const m = this._padMesh.material as THREE.MeshStandardMaterial\n m.opacity = 0.5 * alpha\n m.transparent = m.opacity < 1\n m.needsUpdate = true\n }\n }\n\n updateDimension(): void {\n if (this._padMesh) {\n const state = this.component.state as any\n const w = state.width ?? 100\n const h = state.height ?? 100\n const depth = state.depth ?? 5\n this._padMesh.geometry.dispose()\n this._padMesh.geometry = new THREE.BoxGeometry(w, PAD_DEPTH, h)\n if (this._padOutline) {\n this._padOutline.geometry.dispose()\n this._padOutline.geometry = new THREE.EdgesGeometry(this._padMesh.geometry)\n }\n if (this._tableMesh) {\n const tableW = w * 0.55\n const tableH = h * 0.45\n const tableD = Math.max(8, depth)\n this._tableMesh.geometry.dispose()\n this._tableMesh.geometry = new THREE.BoxGeometry(tableW, tableD, tableH)\n this._tableMesh.position.y = PAD_DEPTH + tableD / 2\n }\n }\n }\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>): void {\n if ('width' in after || 'height' in after || 'depth' in after) {\n this.updateDimension()\n return\n }\n if ('alpha' in after) { this.updateAlpha(); return }\n if ('fillStyle' in after) {\n this._applyPadColor()\n if ((this.component.state as any).strokeStyle == null) this._applyStrokeColor()\n return\n }\n if ('strokeStyle' in after) { this._applyStrokeColor(); return }\n if ('status' in after) { this._applyStatusColor(); return }\n super.onchange?.(after, before)\n }\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
|
|
2
|
+
import type { State, Material3D } from '@hatiolab/things-scene';
|
|
3
|
+
import { type AttachFrame, type Alignment, type Heights, type PlacementArchetype, type ProcessStep } from '@operato/scene-base';
|
|
4
|
+
import { PickingStation3D } from './picking-station-3d.js';
|
|
5
|
+
export type PickingStationStatus = 'idle' | 'processing' | 'busy';
|
|
6
|
+
export interface PickingStationState extends State {
|
|
7
|
+
/** carrier 가 머무는 처리 시간 (ms). 0/미설정이면 즉시 idle 유지. */
|
|
8
|
+
processingTimeMs?: number;
|
|
9
|
+
/** 현재 상태 (자동). */
|
|
10
|
+
status?: PickingStationStatus;
|
|
11
|
+
/** click 시 invoke 할 Popup 컴포넌트 id. */
|
|
12
|
+
popupRef?: string;
|
|
13
|
+
material3d?: Material3D;
|
|
14
|
+
}
|
|
15
|
+
declare const PickingStation_base: any;
|
|
16
|
+
export default class PickingStation extends PickingStation_base implements ProcessStep {
|
|
17
|
+
state: PickingStationState;
|
|
18
|
+
_realObject?: PickingStation3D;
|
|
19
|
+
static placement: PlacementArchetype;
|
|
20
|
+
static align: Alignment;
|
|
21
|
+
static defaultDepth: (h: Heights) => number;
|
|
22
|
+
get nature(): ComponentNature;
|
|
23
|
+
get anchors(): never[];
|
|
24
|
+
_singleSlotId(): string;
|
|
25
|
+
/**
|
|
26
|
+
* SlottedHolder duck (slotIds / hasCarrierAt / canReceiveAt / occupiedSlotIds
|
|
27
|
+
* / emptySlotIds / obtainCarrier / receiveAt / accept / receive / slotTargetAt
|
|
28
|
+
* / getSlotAttachObject3d) — SingleSlotHolder mixin 제공.
|
|
29
|
+
*
|
|
30
|
+
* receiveAt 후 부가 dwell 동작은 `_onCarrierReceived` hook 으로 위임.
|
|
31
|
+
*/
|
|
32
|
+
_onCarrierReceived(_carrier: Component, _options?: any): void;
|
|
33
|
+
readonly isProcessStep: true;
|
|
34
|
+
get processingTimeMs(): number;
|
|
35
|
+
/** carrier 를 작업대(table) 상단에 안착. */
|
|
36
|
+
attachPointFor(carrier: Component): AttachFrame | null;
|
|
37
|
+
render(ctx: CanvasRenderingContext2D): void;
|
|
38
|
+
get eventMap(): {
|
|
39
|
+
'(self)': {
|
|
40
|
+
'(self)': {
|
|
41
|
+
click: (mouseEvent: MouseEvent) => void;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
private _onStationClick;
|
|
46
|
+
private _invokePopup;
|
|
47
|
+
private _raycastStationHit;
|
|
48
|
+
buildRealObject(): RealObject | undefined;
|
|
49
|
+
}
|
|
50
|
+
export {};
|