@operato/scene-visualizer 10.0.0-beta.7 → 10.0.0-beta.9
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/dist/editors/index.d.ts +2 -0
- package/dist/editors/index.js +10 -0
- package/dist/editors/index.js.map +1 -1
- package/dist/editors/property-editor-gltf-fill-targets.d.ts +4 -1
- package/dist/editors/property-editor-gltf-fill-targets.js +178 -74
- package/dist/editors/property-editor-gltf-fill-targets.js.map +1 -1
- package/dist/editors/property-editor-gltf-info.d.ts +19 -4
- package/dist/editors/property-editor-gltf-info.js +279 -84
- package/dist/editors/property-editor-gltf-info.js.map +1 -1
- package/dist/editors/property-editor-gltf-play-targets.d.ts +25 -0
- package/dist/editors/property-editor-gltf-play-targets.js +388 -0
- package/dist/editors/property-editor-gltf-play-targets.js.map +1 -0
- package/dist/editors/property-editor-stocker-location.d.ts +13 -0
- package/dist/editors/property-editor-stocker-location.js +151 -0
- package/dist/editors/property-editor-stocker-location.js.map +1 -0
- package/dist/editors/property-editor-stocker-ports.d.ts +8 -0
- package/dist/editors/property-editor-stocker-ports.js +112 -0
- package/dist/editors/property-editor-stocker-ports.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/stocker-3d.d.ts +23 -0
- package/dist/stocker-3d.js +352 -0
- package/dist/stocker-3d.js.map +1 -0
- package/dist/stocker-port-3d.d.ts +14 -0
- package/dist/stocker-port-3d.js +80 -0
- package/dist/stocker-port-3d.js.map +1 -0
- package/dist/stocker-port.d.ts +254 -0
- package/dist/stocker-port.js +123 -0
- package/dist/stocker-port.js.map +1 -0
- package/dist/stocker.d.ts +340 -0
- package/dist/stocker.js +370 -0
- package/dist/stocker.js.map +1 -0
- package/dist/templates/index.d.ts +40 -0
- package/dist/templates/index.js +5 -1
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/stocker-port.d.ts +17 -0
- package/dist/templates/stocker-port.js +17 -0
- package/dist/templates/stocker-port.js.map +1 -0
- package/dist/templates/stocker.d.ts +27 -0
- package/dist/templates/stocker.js +38 -0
- package/dist/templates/stocker.js.map +1 -0
- package/package.json +2 -2
- package/translations/en.json +6 -0
- package/translations/ja.json +5 -0
- package/translations/ko.json +6 -1
- package/translations/ms.json +5 -0
- package/translations/zh.json +5 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Stocker Port Configuration Editor
|
|
5
|
+
*
|
|
6
|
+
* 주의: OxPropertyEditor base class가 모든 change 이벤트를 잡아서
|
|
7
|
+
* this.value를 덮어쓰므로, 내부 input/select의 change 이벤트 버블링을 차단해야 함.
|
|
8
|
+
*/
|
|
9
|
+
import { __decorate } from "tslib";
|
|
10
|
+
import { css, html } from 'lit';
|
|
11
|
+
import { customElement } from 'lit/decorators.js';
|
|
12
|
+
import { OxPropertyEditor } from '@operato/property-editor';
|
|
13
|
+
function parsePorts(value) {
|
|
14
|
+
if (!value)
|
|
15
|
+
return [];
|
|
16
|
+
if (Array.isArray(value))
|
|
17
|
+
return value;
|
|
18
|
+
if (typeof value === 'string') {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(value);
|
|
21
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
let StockerPortsEditor = class StockerPortsEditor extends OxPropertyEditor {
|
|
30
|
+
static styles = [
|
|
31
|
+
...OxPropertyEditor.styles,
|
|
32
|
+
css `
|
|
33
|
+
.port-table { width: 100%; font-size: 11px; border-collapse: collapse; }
|
|
34
|
+
.port-table th { text-align: left; padding: 3px 4px; font-weight: 600; color: #555; border-bottom: 1px solid rgba(0,0,0,0.12); font-size: 10px; }
|
|
35
|
+
.port-table td { padding: 2px 3px; vertical-align: middle; }
|
|
36
|
+
.port-table select, .port-table input {
|
|
37
|
+
width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;
|
|
38
|
+
border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;
|
|
39
|
+
}
|
|
40
|
+
.port-table input[type="number"] { width: 50px; }
|
|
41
|
+
.port-table input[type="text"] { width: 60px; }
|
|
42
|
+
.btn-row { display: flex; gap: 4px; margin-top: 4px; }
|
|
43
|
+
.btn {
|
|
44
|
+
padding: 3px 8px; font-size: 10px; cursor: pointer;
|
|
45
|
+
border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #f3edf7; color: #1c1b1f;
|
|
46
|
+
}
|
|
47
|
+
.btn:hover { background: #ece6f0; }
|
|
48
|
+
.btn-remove { color: #b3261e; cursor: pointer; font-size: 14px; padding: 0 4px; background: none; border: none; }
|
|
49
|
+
`
|
|
50
|
+
];
|
|
51
|
+
editorTemplate(value, _spec) {
|
|
52
|
+
const ports = Array.isArray(this.value) ? this.value : parsePorts(value);
|
|
53
|
+
return html `
|
|
54
|
+
<fieldset fullwidth>
|
|
55
|
+
${ports.length > 0 ? html `
|
|
56
|
+
<table class="port-table">
|
|
57
|
+
<thead><tr><th>Type</th><th>Side</th><th>Pos</th><th>Label</th><th></th></tr></thead>
|
|
58
|
+
<tbody>
|
|
59
|
+
${ports.map((port, i) => html `
|
|
60
|
+
<tr>
|
|
61
|
+
<td><select @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'type', e.target.value); }}>
|
|
62
|
+
<option value="in" ?selected=${port.type === 'in'}>IN</option>
|
|
63
|
+
<option value="out" ?selected=${port.type === 'out'}>OUT</option>
|
|
64
|
+
</select></td>
|
|
65
|
+
<td><select @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'side', e.target.value); }}>
|
|
66
|
+
<option value="front" ?selected=${port.side === 'front'}>Front</option>
|
|
67
|
+
<option value="back" ?selected=${port.side === 'back'}>Back</option>
|
|
68
|
+
</select></td>
|
|
69
|
+
<td><input type="number" .value=${String(port.position)} min="1" step="1"
|
|
70
|
+
@change=${(e) => { e.stopPropagation(); this._set(ports, i, 'position', Number(e.target.value)); }} /></td>
|
|
71
|
+
<td><input type="text" .value=${port.label || ''} placeholder="auto"
|
|
72
|
+
@change=${(e) => { e.stopPropagation(); this._set(ports, i, 'label', e.target.value || undefined); }} /></td>
|
|
73
|
+
<td><button class="btn-remove" @click=${() => this._applyPorts(ports.filter((_, j) => j !== i))}>×</button></td>
|
|
74
|
+
</tr>
|
|
75
|
+
`)}
|
|
76
|
+
</tbody>
|
|
77
|
+
</table>
|
|
78
|
+
` : html `<div style="font-size:11px;color:#888;padding:4px">No ports</div>`}
|
|
79
|
+
<div class="btn-row">
|
|
80
|
+
<button class="btn" @click=${() => {
|
|
81
|
+
const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0;
|
|
82
|
+
this._applyPorts([...ports, { type: 'in', side: 'front', position: maxPos + 1 }]);
|
|
83
|
+
}}>+ IN</button>
|
|
84
|
+
<button class="btn" @click=${() => {
|
|
85
|
+
const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0;
|
|
86
|
+
this._applyPorts([...ports, { type: 'out', side: 'front', position: maxPos + 1 }]);
|
|
87
|
+
}}>+ OUT</button>
|
|
88
|
+
</div>
|
|
89
|
+
</fieldset>
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
92
|
+
_set(ports, index, field, val) {
|
|
93
|
+
this._applyPorts(ports.map((p, i) => i === index ? { ...p, [field]: val } : p));
|
|
94
|
+
}
|
|
95
|
+
_applyPorts(ports) {
|
|
96
|
+
this.value = ports;
|
|
97
|
+
this.requestUpdate();
|
|
98
|
+
this.dispatchEvent(new CustomEvent('i-need-selected', {
|
|
99
|
+
bubbles: true, composed: true,
|
|
100
|
+
detail: {
|
|
101
|
+
callback: (selected) => {
|
|
102
|
+
selected[0]?.set('ports', JSON.stringify(ports));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
StockerPortsEditor = __decorate([
|
|
109
|
+
customElement('property-editor-stocker-ports')
|
|
110
|
+
], StockerPortsEditor);
|
|
111
|
+
export default StockerPortsEditor;
|
|
112
|
+
//# sourceMappingURL=property-editor-stocker-ports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-editor-stocker-ports.js","sourceRoot":"","sources":["../../src/editors/property-editor-stocker-ports.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Stocker Port Configuration Editor\n *\n * 주의: OxPropertyEditor base class가 모든 change 이벤트를 잡아서\n * this.value를 덮어쓰므로, 내부 input/select의 change 이벤트 버블링을 차단해야 함.\n */\n\nimport { css, html, TemplateResult } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { OxPropertyEditor, PropertySpec } from '@operato/property-editor'\n\ninterface PortEntry {\n type: 'in' | 'out'\n side: 'front' | 'back'\n position: number\n label?: string\n}\n\nfunction parsePorts(value: any): PortEntry[] {\n if (!value) return []\n if (Array.isArray(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value)\n return Array.isArray(parsed) ? parsed : []\n } catch { return [] }\n }\n return []\n}\n\n@customElement('property-editor-stocker-ports')\nexport default class StockerPortsEditor extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n .port-table { width: 100%; font-size: 11px; border-collapse: collapse; }\n .port-table th { text-align: left; padding: 3px 4px; font-weight: 600; color: #555; border-bottom: 1px solid rgba(0,0,0,0.12); font-size: 10px; }\n .port-table td { padding: 2px 3px; vertical-align: middle; }\n .port-table select, .port-table input {\n width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;\n border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;\n }\n .port-table input[type=\"number\"] { width: 50px; }\n .port-table input[type=\"text\"] { width: 60px; }\n .btn-row { display: flex; gap: 4px; margin-top: 4px; }\n .btn {\n padding: 3px 8px; font-size: 10px; cursor: pointer;\n border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #f3edf7; color: #1c1b1f;\n }\n .btn:hover { background: #ece6f0; }\n .btn-remove { color: #b3261e; cursor: pointer; font-size: 14px; padding: 0 4px; background: none; border: none; }\n `\n ]\n\n editorTemplate(value: any, _spec: PropertySpec): TemplateResult {\n const ports: PortEntry[] = Array.isArray(this.value) ? this.value : parsePorts(value)\n\n return html`\n <fieldset fullwidth>\n ${ports.length > 0 ? html`\n <table class=\"port-table\">\n <thead><tr><th>Type</th><th>Side</th><th>Pos</th><th>Label</th><th></th></tr></thead>\n <tbody>\n ${ports.map((port, i) => html`\n <tr>\n <td><select @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'type', (e.target as HTMLSelectElement).value) }}>\n <option value=\"in\" ?selected=${port.type === 'in'}>IN</option>\n <option value=\"out\" ?selected=${port.type === 'out'}>OUT</option>\n </select></td>\n <td><select @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'side', (e.target as HTMLSelectElement).value) }}>\n <option value=\"front\" ?selected=${port.side === 'front'}>Front</option>\n <option value=\"back\" ?selected=${port.side === 'back'}>Back</option>\n </select></td>\n <td><input type=\"number\" .value=${String(port.position)} min=\"1\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'position', Number((e.target as HTMLInputElement).value)) }} /></td>\n <td><input type=\"text\" .value=${port.label || ''} placeholder=\"auto\"\n @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'label', (e.target as HTMLInputElement).value || undefined) }} /></td>\n <td><button class=\"btn-remove\" @click=${() => this._applyPorts(ports.filter((_, j) => j !== i))}>×</button></td>\n </tr>\n `)}\n </tbody>\n </table>\n ` : html`<div style=\"font-size:11px;color:#888;padding:4px\">No ports</div>`}\n <div class=\"btn-row\">\n <button class=\"btn\" @click=${() => {\n const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0\n this._applyPorts([...ports, { type: 'in' as const, side: 'front' as const, position: maxPos + 1 }])\n }}>+ IN</button>\n <button class=\"btn\" @click=${() => {\n const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0\n this._applyPorts([...ports, { type: 'out' as const, side: 'front' as const, position: maxPos + 1 }])\n }}>+ OUT</button>\n </div>\n </fieldset>\n `\n }\n\n private _set(ports: PortEntry[], index: number, field: string, val: any) {\n this._applyPorts(ports.map((p, i) => i === index ? { ...p, [field]: val } : p))\n }\n\n private _applyPorts(ports: PortEntry[]) {\n this.value = ports\n this.requestUpdate()\n\n this.dispatchEvent(new CustomEvent('i-need-selected', {\n bubbles: true, composed: true,\n detail: {\n callback: (selected: any[]) => {\n selected[0]?.set('ports', JSON.stringify(ports))\n }\n }\n }))\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6CAA6C;AAC7C,2BAA2B;AAE3B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\n// threed 인프라 + 범용 3D 컴포넌트는 things-scene에서 제공\n// 여기서는 도메인 특화 컴포넌트만 export\n\nexport * from './desk.js'\nexport * from './rack.js'\nexport * from './rack-table.js'\nexport * from './rack-table-cell.js'\nexport * from './visualizer.js'\nexport * from './stock.js'\nexport * from './signal-tower.js'\nexport * from './stock-hub.js'\nexport * from './tank.js'\nexport * from './vehicle.js'\nexport * from './carrier.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6CAA6C;AAC7C,2BAA2B;AAE3B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\n// threed 인프라 + 범용 3D 컴포넌트는 things-scene에서 제공\n// 여기서는 도메인 특화 컴포넌트만 export\n\nexport * from './desk.js'\nexport * from './rack.js'\nexport * from './rack-table.js'\nexport * from './rack-table-cell.js'\nexport * from './visualizer.js'\nexport * from './stock.js'\nexport * from './signal-tower.js'\nexport * from './stock-hub.js'\nexport * from './tank.js'\nexport * from './vehicle.js'\nexport * from './carrier.js'\nexport * from './stocker.js'\nexport * from './stocker-port.js'\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
2
|
+
import type { Stocker } from './stocker.js';
|
|
3
|
+
export declare class Stocker3d extends RealObjectGroup {
|
|
4
|
+
private _cranes;
|
|
5
|
+
private _cellMeshes;
|
|
6
|
+
private _animRaf;
|
|
7
|
+
get stocker(): Stocker;
|
|
8
|
+
get position(): {
|
|
9
|
+
x: number;
|
|
10
|
+
y: any;
|
|
11
|
+
z: number;
|
|
12
|
+
};
|
|
13
|
+
build(): void;
|
|
14
|
+
private _buildRackSide;
|
|
15
|
+
private _buildEnclosure;
|
|
16
|
+
private _buildCranes;
|
|
17
|
+
updateCraneTargets(): void;
|
|
18
|
+
private _startCraneAnim;
|
|
19
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>): void;
|
|
20
|
+
dispose(): void;
|
|
21
|
+
updateDimension(): void;
|
|
22
|
+
updateAlpha(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Stocker 3D — aisle, rail, crane, ports, enclosure, rack frames, cell stocks.
|
|
5
|
+
*/
|
|
6
|
+
import * as THREE from 'three';
|
|
7
|
+
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
8
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
9
|
+
import { computeLayout } from './stocker.js';
|
|
10
|
+
const FRAME_COLOR = 0x8a8a8a;
|
|
11
|
+
const BOARD_COLOR = 0xcccccc;
|
|
12
|
+
const AISLE_COLOR = 0xd4d4c8;
|
|
13
|
+
const RAIL_COLOR = 0x666666;
|
|
14
|
+
const CRANE_COLOR = 0xff6600;
|
|
15
|
+
const CRANE_MAST_COLOR = 0xcc5500;
|
|
16
|
+
const FORK_COLOR = 0xddaa00;
|
|
17
|
+
const CELL_EMPTY_COLOR = 0xf0f0f0;
|
|
18
|
+
const CELL_FULL_COLOR = 0x4a9eff;
|
|
19
|
+
const CELL_RESERVED_COLOR = 0xffcc00;
|
|
20
|
+
const CELL_ERROR_COLOR = 0xe74c3c;
|
|
21
|
+
function cellColor3d(status) {
|
|
22
|
+
switch (status) {
|
|
23
|
+
case 'FULL': return CELL_FULL_COLOR;
|
|
24
|
+
case 'RESERVED': return CELL_RESERVED_COLOR;
|
|
25
|
+
case 'ERROR': return CELL_ERROR_COLOR;
|
|
26
|
+
default: return CELL_EMPTY_COLOR;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class Stocker3d extends RealObjectGroup {
|
|
30
|
+
_cranes = [];
|
|
31
|
+
_cellMeshes = [];
|
|
32
|
+
_animRaf = 0;
|
|
33
|
+
get stocker() {
|
|
34
|
+
return this.component;
|
|
35
|
+
}
|
|
36
|
+
get position() {
|
|
37
|
+
const { zPos = 0 } = this.component.state;
|
|
38
|
+
return { x: this.cx || 0, y: zPos, z: this.cy || 0 };
|
|
39
|
+
}
|
|
40
|
+
build() {
|
|
41
|
+
super.build();
|
|
42
|
+
const state = this.component.state;
|
|
43
|
+
const { width = 200, height = 100, depth: totalHeight = 80, rotation = 0, aisleRatio = 0.15 } = state;
|
|
44
|
+
const layout = computeLayout(state);
|
|
45
|
+
let orientY = -rotation;
|
|
46
|
+
if (layout.vertical)
|
|
47
|
+
orientY += Math.PI / 2;
|
|
48
|
+
if (layout.flipped)
|
|
49
|
+
orientY += Math.PI;
|
|
50
|
+
this.object3d.rotation.y = orientY;
|
|
51
|
+
const alongSize = layout.along;
|
|
52
|
+
const acrossSize = layout.across;
|
|
53
|
+
const aisleDepth = acrossSize * aisleRatio;
|
|
54
|
+
const rackAreaDepth = acrossSize - aisleDepth;
|
|
55
|
+
const leftRackDepth = layout.leftRack ? rackAreaDepth / (layout.rightRack ? 2 : 1) : 0;
|
|
56
|
+
const rightRackDepth = layout.rightRack ? rackAreaDepth / (layout.leftRack ? 2 : 1) : 0;
|
|
57
|
+
const frameGeoms = [];
|
|
58
|
+
const boardGeoms = [];
|
|
59
|
+
// ── Rack sides ──
|
|
60
|
+
if (layout.leftRack) {
|
|
61
|
+
const rackZ = -(aisleDepth / 2 + leftRackDepth / 2);
|
|
62
|
+
this._buildRackSide('L', layout.leftRack.config, alongSize, totalHeight, leftRackDepth, rackZ, frameGeoms, boardGeoms);
|
|
63
|
+
}
|
|
64
|
+
if (layout.rightRack) {
|
|
65
|
+
const rackZ = aisleDepth / 2 + rightRackDepth / 2;
|
|
66
|
+
this._buildRackSide('R', layout.rightRack.config, alongSize, totalHeight, rightRackDepth, rackZ, frameGeoms, boardGeoms);
|
|
67
|
+
}
|
|
68
|
+
// merge frames
|
|
69
|
+
if (!state.hideRackFrame && frameGeoms.length > 0) {
|
|
70
|
+
const mat = new THREE.MeshStandardMaterial({ color: FRAME_COLOR, metalness: 0.85, roughness: 0.35, transparent: true, opacity: 0.8 });
|
|
71
|
+
const mesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(frameGeoms), mat);
|
|
72
|
+
mesh.castShadow = true;
|
|
73
|
+
this.object3d.add(mesh);
|
|
74
|
+
}
|
|
75
|
+
if (!state.hideRackFrame && boardGeoms.length > 0) {
|
|
76
|
+
const mat = new THREE.MeshStandardMaterial({ color: BOARD_COLOR, side: THREE.DoubleSide, transparent: true, opacity: 0.5 });
|
|
77
|
+
this.object3d.add(new THREE.Mesh(BufferGeometryUtils.mergeGeometries(boardGeoms), mat));
|
|
78
|
+
}
|
|
79
|
+
// ── Enclosure ──
|
|
80
|
+
const { fillStyle } = state;
|
|
81
|
+
if (fillStyle && fillStyle !== 'transparent' && fillStyle !== 'rgba(0,0,0,0)') {
|
|
82
|
+
this._buildEnclosure(alongSize, acrossSize, totalHeight, fillStyle);
|
|
83
|
+
}
|
|
84
|
+
// ── Aisle ──
|
|
85
|
+
const aisleGeom = new THREE.PlaneGeometry(alongSize, aisleDepth);
|
|
86
|
+
aisleGeom.rotateX(-Math.PI / 2);
|
|
87
|
+
const aisleMesh = new THREE.Mesh(aisleGeom, new THREE.MeshStandardMaterial({ color: AISLE_COLOR, roughness: 0.9 }));
|
|
88
|
+
aisleMesh.position.y = 0.1;
|
|
89
|
+
aisleMesh.receiveShadow = true;
|
|
90
|
+
this.object3d.add(aisleMesh);
|
|
91
|
+
// rail
|
|
92
|
+
const railMesh = new THREE.Mesh(new THREE.BoxGeometry(alongSize, 1, 2), new THREE.MeshStandardMaterial({ color: RAIL_COLOR, metalness: 0.8, roughness: 0.3 }));
|
|
93
|
+
railMesh.position.set(0, 0.5, 0);
|
|
94
|
+
this.object3d.add(railMesh);
|
|
95
|
+
// ── Cranes ──
|
|
96
|
+
const maxBays = layout.maxBays;
|
|
97
|
+
const levels = Math.max(state.lLevels || 0, state.rLevels || 0, 1);
|
|
98
|
+
this._buildCranes(alongSize, totalHeight, maxBays, levels, aisleDepth, leftRackDepth, rightRackDepth);
|
|
99
|
+
}
|
|
100
|
+
_buildRackSide(side, config, totalWidth, totalHeight, rackDepth, rackZ, frameGeoms, boardGeoms) {
|
|
101
|
+
const { bays, levels, depthCount } = config;
|
|
102
|
+
const bayWidth = totalWidth / bays;
|
|
103
|
+
const levelHeight = totalHeight / levels;
|
|
104
|
+
const cellDepthSize = rackDepth / depthCount;
|
|
105
|
+
const postW = Math.min(bayWidth * 0.05, 2);
|
|
106
|
+
const inset = 3;
|
|
107
|
+
const hw = totalWidth / 2 - inset;
|
|
108
|
+
const hd = rackDepth / 2 - inset;
|
|
109
|
+
// vertical posts — 수평바 + 1/2 두께로 접합부 갭 채움
|
|
110
|
+
const topRailY = totalHeight - inset;
|
|
111
|
+
const bottomRailY = inset;
|
|
112
|
+
const postHeight = topRailY - bottomRailY + postW;
|
|
113
|
+
const postGeom = new THREE.BoxGeometry(postW, postHeight, postW);
|
|
114
|
+
for (const [px, pz] of [[-hw, rackZ - hd], [-hw, rackZ + hd], [hw, rackZ - hd], [hw, rackZ + hd]]) {
|
|
115
|
+
const g = postGeom.clone();
|
|
116
|
+
g.translate(px, bottomRailY - postW / 2 + postHeight / 2, pz);
|
|
117
|
+
frameGeoms.push(g);
|
|
118
|
+
}
|
|
119
|
+
// horizontal rails — 좌우 inset, 상하는 enclosure 안쪽에 위치
|
|
120
|
+
const railW = totalWidth - inset * 2;
|
|
121
|
+
const railAlongGeom = new THREE.BoxGeometry(railW, postW, postW);
|
|
122
|
+
const railDepthW = rackDepth - inset * 2;
|
|
123
|
+
const railDepthGeom = new THREE.BoxGeometry(postW, postW, railDepthW);
|
|
124
|
+
for (let l = 0; l <= levels; l++) {
|
|
125
|
+
let y = l * levelHeight;
|
|
126
|
+
// bottom은 enclosure 바닥에서 올라오고, top은 천장에서 내려옴
|
|
127
|
+
if (l === 0)
|
|
128
|
+
y = inset;
|
|
129
|
+
else if (l === levels)
|
|
130
|
+
y = totalHeight - inset;
|
|
131
|
+
// along 방향 (전면/후면)
|
|
132
|
+
for (const dz of [rackZ - hd, rackZ + hd]) {
|
|
133
|
+
const g = railAlongGeom.clone();
|
|
134
|
+
g.translate(0, y, dz);
|
|
135
|
+
frameGeoms.push(g);
|
|
136
|
+
}
|
|
137
|
+
// depth 방향 (좌측/우측 끝)
|
|
138
|
+
for (const px of [-hw, hw]) {
|
|
139
|
+
const g = railDepthGeom.clone();
|
|
140
|
+
g.translate(px, y, rackZ);
|
|
141
|
+
frameGeoms.push(g);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// shelf boards
|
|
145
|
+
const boardW = totalWidth - inset * 2;
|
|
146
|
+
const boardD = rackDepth - inset * 2;
|
|
147
|
+
for (let l = 0; l < levels; l++) {
|
|
148
|
+
const y = l * levelHeight + 0.5;
|
|
149
|
+
const g = new THREE.PlaneGeometry(boardW, boardD);
|
|
150
|
+
g.rotateX(-Math.PI / 2);
|
|
151
|
+
g.translate(0, y, rackZ);
|
|
152
|
+
boardGeoms.push(g);
|
|
153
|
+
}
|
|
154
|
+
// cell stock
|
|
155
|
+
for (let l = 1; l <= levels; l++) {
|
|
156
|
+
for (let b = 1; b <= bays; b++) {
|
|
157
|
+
for (let d = 1; d <= depthCount; d++) {
|
|
158
|
+
const status = this.stocker.getCellStatus(side, b, l, d);
|
|
159
|
+
const geom = new THREE.BoxGeometry(bayWidth * 0.7, levelHeight * 0.7, cellDepthSize * 0.7);
|
|
160
|
+
const mat = new THREE.MeshStandardMaterial({
|
|
161
|
+
color: cellColor3d(status), metalness: 0.1, roughness: 0.8,
|
|
162
|
+
transparent: !status || status === 'EMPTY',
|
|
163
|
+
opacity: (!status || status === 'EMPTY') ? 0.15 : 1
|
|
164
|
+
});
|
|
165
|
+
const mesh = new THREE.Mesh(geom, mat);
|
|
166
|
+
mesh.position.set(-totalWidth / 2 + (b - 0.5) * bayWidth, (l - 0.5) * levelHeight, rackZ + (d - 0.5 - depthCount / 2) * cellDepthSize);
|
|
167
|
+
mesh.name = this.stocker.getLocationId(side, b, l, d);
|
|
168
|
+
this._cellMeshes.push(mesh);
|
|
169
|
+
this.object3d.add(mesh);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
_buildEnclosure(alongSize, acrossSize, totalHeight, fillStyle) {
|
|
175
|
+
let color = 0xcccccc;
|
|
176
|
+
let opacity = 0.4;
|
|
177
|
+
// rgba에서 alpha 추출, 색상만 THREE.Color로
|
|
178
|
+
const rgbaMatch = fillStyle.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/);
|
|
179
|
+
if (rgbaMatch) {
|
|
180
|
+
const [, r, g, b, a] = rgbaMatch;
|
|
181
|
+
color = new THREE.Color(parseInt(r) / 255, parseInt(g) / 255, parseInt(b) / 255).getHex();
|
|
182
|
+
if (a !== undefined)
|
|
183
|
+
opacity = parseFloat(a);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
try {
|
|
187
|
+
color = new THREE.Color(fillStyle).getHex();
|
|
188
|
+
}
|
|
189
|
+
catch { }
|
|
190
|
+
}
|
|
191
|
+
const mat = new THREE.MeshStandardMaterial({ color, transparent: true, opacity, side: THREE.DoubleSide, depthWrite: false });
|
|
192
|
+
const halfW = alongSize / 2;
|
|
193
|
+
const halfD = acrossSize / 2;
|
|
194
|
+
for (const [w, h, x, y, z, ry] of [
|
|
195
|
+
[alongSize, totalHeight, 0, totalHeight / 2, -halfD, 0],
|
|
196
|
+
[alongSize, totalHeight, 0, totalHeight / 2, halfD, 0],
|
|
197
|
+
[acrossSize, totalHeight, -halfW, totalHeight / 2, 0, Math.PI / 2],
|
|
198
|
+
[acrossSize, totalHeight, halfW, totalHeight / 2, 0, Math.PI / 2]
|
|
199
|
+
]) {
|
|
200
|
+
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(w, h), mat);
|
|
201
|
+
mesh.position.set(x, y, z);
|
|
202
|
+
mesh.rotation.y = ry;
|
|
203
|
+
this.object3d.add(mesh);
|
|
204
|
+
}
|
|
205
|
+
const roofGeom = new THREE.PlaneGeometry(alongSize, acrossSize);
|
|
206
|
+
roofGeom.rotateX(-Math.PI / 2);
|
|
207
|
+
const roofMesh = new THREE.Mesh(roofGeom, mat);
|
|
208
|
+
roofMesh.position.y = totalHeight;
|
|
209
|
+
this.object3d.add(roofMesh);
|
|
210
|
+
}
|
|
211
|
+
_buildCranes(alongSize, totalHeight, maxBays, levels, aisleDepth, leftRackDepth, rightRackDepth) {
|
|
212
|
+
const cranesData = this.stocker.cranesData;
|
|
213
|
+
const craneCount = Math.max(cranesData.length, this.component.state.cranes || 1);
|
|
214
|
+
const bayWidth = alongSize / maxBays;
|
|
215
|
+
const levelHeight = totalHeight / levels;
|
|
216
|
+
const craneHeight = totalHeight * 0.95;
|
|
217
|
+
const mastMat = new THREE.MeshStandardMaterial({ color: CRANE_MAST_COLOR, metalness: 0.7, roughness: 0.4 });
|
|
218
|
+
const carriageMat = new THREE.MeshStandardMaterial({ color: CRANE_COLOR, metalness: 0.3, roughness: 0.6 });
|
|
219
|
+
const forkMat = new THREE.MeshStandardMaterial({ color: FORK_COLOR, metalness: 0.5, roughness: 0.5 });
|
|
220
|
+
for (let i = 0; i < craneCount; i++) {
|
|
221
|
+
const cd = cranesData[i];
|
|
222
|
+
const bay = cd?.bay ?? Math.round((i + 1) * maxBays / (craneCount + 1));
|
|
223
|
+
const level = cd?.level ?? 1;
|
|
224
|
+
const side = cd?.side;
|
|
225
|
+
const status = cd?.status || 'IDLE';
|
|
226
|
+
const craneX = -alongSize / 2 + (bay - 0.5) * bayWidth;
|
|
227
|
+
const craneY = (level - 0.5) * levelHeight;
|
|
228
|
+
let targetForkZ = 0;
|
|
229
|
+
if ((status === 'PICKING' || status === 'PLACING') && side) {
|
|
230
|
+
targetForkZ = side === 'L' ? -(aisleDepth / 2 + leftRackDepth / 2) : (aisleDepth / 2 + rightRackDepth / 2);
|
|
231
|
+
}
|
|
232
|
+
const mastGroup = new THREE.Group();
|
|
233
|
+
mastGroup.position.x = craneX;
|
|
234
|
+
this.object3d.add(mastGroup);
|
|
235
|
+
const mastMesh = new THREE.Mesh(new THREE.BoxGeometry(3, craneHeight, 3), mastMat);
|
|
236
|
+
mastMesh.position.y = craneHeight / 2;
|
|
237
|
+
mastMesh.castShadow = true;
|
|
238
|
+
mastGroup.add(mastMesh);
|
|
239
|
+
const topBeam = new THREE.Mesh(new THREE.BoxGeometry(bayWidth * 0.3, 2, aisleDepth * 0.8), mastMat);
|
|
240
|
+
topBeam.position.y = craneHeight - 1;
|
|
241
|
+
mastGroup.add(topBeam);
|
|
242
|
+
const carriageGroup = new THREE.Group();
|
|
243
|
+
carriageGroup.position.y = craneY;
|
|
244
|
+
mastGroup.add(carriageGroup);
|
|
245
|
+
const carrW = bayWidth * 0.7, carrH = 4, carrD = aisleDepth * 0.5;
|
|
246
|
+
const carriageMesh = new THREE.Mesh(new THREE.BoxGeometry(carrW, carrH, carrD), carriageMat);
|
|
247
|
+
carriageMesh.castShadow = true;
|
|
248
|
+
carriageGroup.add(carriageMesh);
|
|
249
|
+
const forkGroup = new THREE.Group();
|
|
250
|
+
carriageGroup.add(forkGroup);
|
|
251
|
+
const forkLength = Math.max(leftRackDepth, rightRackDepth) * 0.8;
|
|
252
|
+
const forkW = carrW * 0.15, forkH = 1.5;
|
|
253
|
+
const prongGeom = new THREE.BoxGeometry(forkW, forkH, forkLength);
|
|
254
|
+
const lp = new THREE.Mesh(prongGeom, forkMat);
|
|
255
|
+
lp.position.set(-carrW * 0.25, -carrH / 2 + forkH / 2, 0);
|
|
256
|
+
forkGroup.add(lp);
|
|
257
|
+
const rp = new THREE.Mesh(prongGeom.clone(), forkMat);
|
|
258
|
+
rp.position.set(carrW * 0.25, -carrH / 2 + forkH / 2, 0);
|
|
259
|
+
forkGroup.add(rp);
|
|
260
|
+
const baseMesh = new THREE.Mesh(new THREE.BoxGeometry(carrW * 0.7, forkH, forkW), forkMat);
|
|
261
|
+
baseMesh.position.set(0, -carrH / 2 + forkH / 2, -forkLength / 2 + forkW / 2);
|
|
262
|
+
forkGroup.add(baseMesh);
|
|
263
|
+
this._cranes.push({
|
|
264
|
+
mastGroup, carriageGroup, forkGroup,
|
|
265
|
+
state: { x: craneX, y: craneY, forkZ: 0, targetX: craneX, targetY: craneY, targetForkZ, bayWidth, levelHeight, maxBays, levels, leftRackDepth, rightRackDepth, aisleDepth }
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (this._cranes.some(c => c.state.targetForkZ !== 0))
|
|
269
|
+
this._startCraneAnim();
|
|
270
|
+
}
|
|
271
|
+
updateCraneTargets() {
|
|
272
|
+
const cranesData = this.stocker.cranesData;
|
|
273
|
+
const alongSize = this.stocker.layout.along;
|
|
274
|
+
for (let i = 0; i < this._cranes.length; i++) {
|
|
275
|
+
const crane = this._cranes[i];
|
|
276
|
+
const cd = cranesData[i];
|
|
277
|
+
const s = crane.state;
|
|
278
|
+
const bay = cd?.bay ?? Math.round((i + 1) * s.maxBays / (this._cranes.length + 1));
|
|
279
|
+
const level = cd?.level ?? 1;
|
|
280
|
+
const side = cd?.side;
|
|
281
|
+
const status = cd?.status || 'IDLE';
|
|
282
|
+
s.targetX = -alongSize / 2 + (bay - 0.5) * s.bayWidth;
|
|
283
|
+
s.targetY = (level - 0.5) * s.levelHeight;
|
|
284
|
+
if ((status === 'PICKING' || status === 'PLACING') && side) {
|
|
285
|
+
s.targetForkZ = side === 'L' ? -(s.aisleDepth / 2 + s.leftRackDepth / 2) : (s.aisleDepth / 2 + s.rightRackDepth / 2);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
s.targetForkZ = 0;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this._startCraneAnim();
|
|
292
|
+
}
|
|
293
|
+
_startCraneAnim() {
|
|
294
|
+
if (this._animRaf)
|
|
295
|
+
return;
|
|
296
|
+
const animate = () => {
|
|
297
|
+
let allDone = true;
|
|
298
|
+
for (const crane of this._cranes) {
|
|
299
|
+
const s = crane.state, speed = 0.08;
|
|
300
|
+
s.x += (s.targetX - s.x) * speed;
|
|
301
|
+
s.y += (s.targetY - s.y) * speed;
|
|
302
|
+
s.forkZ += (s.targetForkZ - s.forkZ) * speed;
|
|
303
|
+
crane.mastGroup.position.x = s.x;
|
|
304
|
+
crane.carriageGroup.position.y = s.y;
|
|
305
|
+
crane.forkGroup.position.z = s.forkZ;
|
|
306
|
+
if (Math.abs(s.targetX - s.x) > 0.1 || Math.abs(s.targetY - s.y) > 0.1 || Math.abs(s.targetForkZ - s.forkZ) > 0.1) {
|
|
307
|
+
allDone = false;
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
s.x = s.targetX;
|
|
311
|
+
s.y = s.targetY;
|
|
312
|
+
s.forkZ = s.targetForkZ;
|
|
313
|
+
crane.mastGroup.position.x = s.x;
|
|
314
|
+
crane.carriageGroup.position.y = s.y;
|
|
315
|
+
crane.forkGroup.position.z = s.forkZ;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (allDone) {
|
|
319
|
+
this._animRaf = 0;
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
this._animRaf = requestAnimationFrame(animate);
|
|
323
|
+
};
|
|
324
|
+
this._animRaf = requestAnimationFrame(animate);
|
|
325
|
+
}
|
|
326
|
+
onchange(after, before) {
|
|
327
|
+
if ('data' in after) {
|
|
328
|
+
this.updateCraneTargets();
|
|
329
|
+
this.update();
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if ('lBays' in after || 'lLevels' in after || 'lDepth' in after || 'rBays' in after || 'rLevels' in after || 'rDepth' in after ||
|
|
333
|
+
'cranes' in after || 'depth' in after || 'aisleRatio' in after ||
|
|
334
|
+
'width' in after || 'height' in after || 'locationRule' in after || 'hideRackFrame' in after || 'fillStyle' in after || 'frontSide' in after) {
|
|
335
|
+
this.update();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
super.onchange(after, before);
|
|
339
|
+
}
|
|
340
|
+
dispose() {
|
|
341
|
+
if (this._animRaf) {
|
|
342
|
+
cancelAnimationFrame(this._animRaf);
|
|
343
|
+
this._animRaf = 0;
|
|
344
|
+
}
|
|
345
|
+
this._cranes = [];
|
|
346
|
+
this._cellMeshes = [];
|
|
347
|
+
super.dispose();
|
|
348
|
+
}
|
|
349
|
+
updateDimension() { }
|
|
350
|
+
updateAlpha() { }
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=stocker-3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stocker-3d.js","sourceRoot":"","sources":["../src/stocker-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Stocker 3D — aisle, rail, crane, ports, enclosure, rack frames, cell stocks.\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\nimport type { Stocker, StockerData, CraneData } from './stocker.js'\nimport { computeLayout } from './stocker.js'\n\nconst FRAME_COLOR = 0x8a8a8a\nconst BOARD_COLOR = 0xcccccc\nconst AISLE_COLOR = 0xd4d4c8\nconst RAIL_COLOR = 0x666666\nconst CRANE_COLOR = 0xff6600\nconst CRANE_MAST_COLOR = 0xcc5500\nconst FORK_COLOR = 0xddaa00\nconst CELL_EMPTY_COLOR = 0xf0f0f0\nconst CELL_FULL_COLOR = 0x4a9eff\nconst CELL_RESERVED_COLOR = 0xffcc00\nconst CELL_ERROR_COLOR = 0xe74c3c\n\nfunction cellColor3d(status?: string): number {\n switch (status) {\n case 'FULL': return CELL_FULL_COLOR\n case 'RESERVED': return CELL_RESERVED_COLOR\n case 'ERROR': return CELL_ERROR_COLOR\n default: return CELL_EMPTY_COLOR\n }\n}\n\ninterface CraneState {\n x: number; y: number; forkZ: number\n targetX: number; targetY: number; targetForkZ: number\n bayWidth: number; levelHeight: number; maxBays: number; levels: number\n leftRackDepth: number; rightRackDepth: number; aisleDepth: number\n}\n\ninterface CraneInstance {\n mastGroup: THREE.Group\n carriageGroup: THREE.Group\n forkGroup: THREE.Group\n state: CraneState\n}\n\nexport class Stocker3d extends RealObjectGroup {\n private _cranes: CraneInstance[] = []\n private _cellMeshes: THREE.Mesh[] = []\n private _animRaf = 0\n\n get stocker(): Stocker {\n return this.component as unknown as Stocker\n }\n\n get position() {\n const { zPos = 0 } = this.component.state\n return { x: this.cx || 0, y: zPos, z: this.cy || 0 }\n }\n\n build() {\n super.build()\n\n const state = this.component.state\n const { width = 200, height = 100, depth: totalHeight = 80, rotation = 0, aisleRatio = 0.15 } = state\n\n const layout = computeLayout(state)\n let orientY = -rotation\n if (layout.vertical) orientY += Math.PI / 2\n if (layout.flipped) orientY += Math.PI\n this.object3d.rotation.y = orientY\n\n const alongSize = layout.along\n const acrossSize = layout.across\n const aisleDepth = acrossSize * aisleRatio\n const rackAreaDepth = acrossSize - aisleDepth\n const leftRackDepth = layout.leftRack ? rackAreaDepth / (layout.rightRack ? 2 : 1) : 0\n const rightRackDepth = layout.rightRack ? rackAreaDepth / (layout.leftRack ? 2 : 1) : 0\n\n const frameGeoms: THREE.BufferGeometry[] = []\n const boardGeoms: THREE.BufferGeometry[] = []\n\n // ── Rack sides ──\n if (layout.leftRack) {\n const rackZ = -(aisleDepth / 2 + leftRackDepth / 2)\n this._buildRackSide('L', layout.leftRack.config, alongSize, totalHeight, leftRackDepth, rackZ, frameGeoms, boardGeoms)\n }\n if (layout.rightRack) {\n const rackZ = aisleDepth / 2 + rightRackDepth / 2\n this._buildRackSide('R', layout.rightRack.config, alongSize, totalHeight, rightRackDepth, rackZ, frameGeoms, boardGeoms)\n }\n\n // merge frames\n if (!state.hideRackFrame && frameGeoms.length > 0) {\n const mat = new THREE.MeshStandardMaterial({ color: FRAME_COLOR, metalness: 0.85, roughness: 0.35, transparent: true, opacity: 0.8 })\n const mesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(frameGeoms), mat)\n mesh.castShadow = true\n this.object3d.add(mesh)\n }\n\n if (!state.hideRackFrame && boardGeoms.length > 0) {\n const mat = new THREE.MeshStandardMaterial({ color: BOARD_COLOR, side: THREE.DoubleSide, transparent: true, opacity: 0.5 })\n this.object3d.add(new THREE.Mesh(BufferGeometryUtils.mergeGeometries(boardGeoms), mat))\n }\n\n // ── Enclosure ──\n const { fillStyle } = state\n if (fillStyle && fillStyle !== 'transparent' && fillStyle !== 'rgba(0,0,0,0)') {\n this._buildEnclosure(alongSize, acrossSize, totalHeight, fillStyle)\n }\n\n // ── Aisle ──\n const aisleGeom = new THREE.PlaneGeometry(alongSize, aisleDepth)\n aisleGeom.rotateX(-Math.PI / 2)\n const aisleMesh = new THREE.Mesh(aisleGeom, new THREE.MeshStandardMaterial({ color: AISLE_COLOR, roughness: 0.9 }))\n aisleMesh.position.y = 0.1\n aisleMesh.receiveShadow = true\n this.object3d.add(aisleMesh)\n\n // rail\n const railMesh = new THREE.Mesh(\n new THREE.BoxGeometry(alongSize, 1, 2),\n new THREE.MeshStandardMaterial({ color: RAIL_COLOR, metalness: 0.8, roughness: 0.3 })\n )\n railMesh.position.set(0, 0.5, 0)\n this.object3d.add(railMesh)\n\n // ── Cranes ──\n const maxBays = layout.maxBays\n const levels = Math.max(state.lLevels || 0, state.rLevels || 0, 1)\n this._buildCranes(alongSize, totalHeight, maxBays, levels, aisleDepth, leftRackDepth, rightRackDepth)\n\n }\n\n private _buildRackSide(\n side: 'L' | 'R', config: { bays: number; levels: number; depthCount: number },\n totalWidth: number, totalHeight: number, rackDepth: number, rackZ: number,\n frameGeoms: THREE.BufferGeometry[], boardGeoms: THREE.BufferGeometry[]\n ) {\n const { bays, levels, depthCount } = config\n const bayWidth = totalWidth / bays\n const levelHeight = totalHeight / levels\n const cellDepthSize = rackDepth / depthCount\n const postW = Math.min(bayWidth * 0.05, 2)\n const inset = 3\n\n const hw = totalWidth / 2 - inset\n const hd = rackDepth / 2 - inset\n\n // vertical posts — 수평바 + 1/2 두께로 접합부 갭 채움\n const topRailY = totalHeight - inset\n const bottomRailY = inset\n const postHeight = topRailY - bottomRailY + postW\n const postGeom = new THREE.BoxGeometry(postW, postHeight, postW)\n for (const [px, pz] of [[-hw, rackZ - hd], [-hw, rackZ + hd], [hw, rackZ - hd], [hw, rackZ + hd]]) {\n const g = postGeom.clone()\n g.translate(px, bottomRailY - postW / 2 + postHeight / 2, pz)\n frameGeoms.push(g)\n }\n\n // horizontal rails — 좌우 inset, 상하는 enclosure 안쪽에 위치\n const railW = totalWidth - inset * 2\n const railAlongGeom = new THREE.BoxGeometry(railW, postW, postW)\n const railDepthW = rackDepth - inset * 2\n const railDepthGeom = new THREE.BoxGeometry(postW, postW, railDepthW)\n\n for (let l = 0; l <= levels; l++) {\n let y = l * levelHeight\n // bottom은 enclosure 바닥에서 올라오고, top은 천장에서 내려옴\n if (l === 0) y = inset\n else if (l === levels) y = totalHeight - inset\n\n // along 방향 (전면/후면)\n for (const dz of [rackZ - hd, rackZ + hd]) {\n const g = railAlongGeom.clone()\n g.translate(0, y, dz)\n frameGeoms.push(g)\n }\n // depth 방향 (좌측/우측 끝)\n for (const px of [-hw, hw]) {\n const g = railDepthGeom.clone()\n g.translate(px, y, rackZ)\n frameGeoms.push(g)\n }\n }\n\n // shelf boards\n const boardW = totalWidth - inset * 2\n const boardD = rackDepth - inset * 2\n for (let l = 0; l < levels; l++) {\n const y = l * levelHeight + 0.5\n const g = new THREE.PlaneGeometry(boardW, boardD)\n g.rotateX(-Math.PI / 2)\n g.translate(0, y, rackZ)\n boardGeoms.push(g)\n }\n\n // cell stock\n for (let l = 1; l <= levels; l++) {\n for (let b = 1; b <= bays; b++) {\n for (let d = 1; d <= depthCount; d++) {\n const status = this.stocker.getCellStatus(side, b, l, d)\n const geom = new THREE.BoxGeometry(bayWidth * 0.7, levelHeight * 0.7, cellDepthSize * 0.7)\n const mat = new THREE.MeshStandardMaterial({\n color: cellColor3d(status), metalness: 0.1, roughness: 0.8,\n transparent: !status || status === 'EMPTY',\n opacity: (!status || status === 'EMPTY') ? 0.15 : 1\n })\n const mesh = new THREE.Mesh(geom, mat)\n mesh.position.set(\n -totalWidth / 2 + (b - 0.5) * bayWidth,\n (l - 0.5) * levelHeight,\n rackZ + (d - 0.5 - depthCount / 2) * cellDepthSize\n )\n mesh.name = this.stocker.getLocationId(side, b, l, d)\n this._cellMeshes.push(mesh)\n this.object3d.add(mesh)\n }\n }\n }\n }\n\n private _buildEnclosure(alongSize: number, acrossSize: number, totalHeight: number, fillStyle: string) {\n let color = 0xcccccc\n let opacity = 0.4\n // rgba에서 alpha 추출, 색상만 THREE.Color로\n const rgbaMatch = fillStyle.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/)\n if (rgbaMatch) {\n const [, r, g, b, a] = rgbaMatch\n color = new THREE.Color(parseInt(r) / 255, parseInt(g) / 255, parseInt(b) / 255).getHex()\n if (a !== undefined) opacity = parseFloat(a)\n } else {\n try { color = new THREE.Color(fillStyle).getHex() } catch {}\n }\n const mat = new THREE.MeshStandardMaterial({ color, transparent: true, opacity, side: THREE.DoubleSide, depthWrite: false })\n const halfW = alongSize / 2\n const halfD = acrossSize / 2\n\n for (const [w, h, x, y, z, ry] of [\n [alongSize, totalHeight, 0, totalHeight / 2, -halfD, 0],\n [alongSize, totalHeight, 0, totalHeight / 2, halfD, 0],\n [acrossSize, totalHeight, -halfW, totalHeight / 2, 0, Math.PI / 2],\n [acrossSize, totalHeight, halfW, totalHeight / 2, 0, Math.PI / 2]\n ] as [number, number, number, number, number, number][]) {\n const mesh = new THREE.Mesh(new THREE.PlaneGeometry(w, h), mat)\n mesh.position.set(x, y, z)\n mesh.rotation.y = ry\n this.object3d.add(mesh)\n }\n const roofGeom = new THREE.PlaneGeometry(alongSize, acrossSize)\n roofGeom.rotateX(-Math.PI / 2)\n const roofMesh = new THREE.Mesh(roofGeom, mat)\n roofMesh.position.y = totalHeight\n this.object3d.add(roofMesh)\n }\n\n private _buildCranes(alongSize: number, totalHeight: number, maxBays: number, levels: number, aisleDepth: number, leftRackDepth: number, rightRackDepth: number) {\n const cranesData = this.stocker.cranesData\n const craneCount = Math.max(cranesData.length, this.component.state.cranes || 1)\n const bayWidth = alongSize / maxBays\n const levelHeight = totalHeight / levels\n const craneHeight = totalHeight * 0.95\n\n const mastMat = new THREE.MeshStandardMaterial({ color: CRANE_MAST_COLOR, metalness: 0.7, roughness: 0.4 })\n const carriageMat = new THREE.MeshStandardMaterial({ color: CRANE_COLOR, metalness: 0.3, roughness: 0.6 })\n const forkMat = new THREE.MeshStandardMaterial({ color: FORK_COLOR, metalness: 0.5, roughness: 0.5 })\n\n for (let i = 0; i < craneCount; i++) {\n const cd = cranesData[i]\n const bay = cd?.bay ?? Math.round((i + 1) * maxBays / (craneCount + 1))\n const level = cd?.level ?? 1\n const side = cd?.side\n const status = cd?.status || 'IDLE'\n\n const craneX = -alongSize / 2 + (bay - 0.5) * bayWidth\n const craneY = (level - 0.5) * levelHeight\n let targetForkZ = 0\n if ((status === 'PICKING' || status === 'PLACING') && side) {\n targetForkZ = side === 'L' ? -(aisleDepth / 2 + leftRackDepth / 2) : (aisleDepth / 2 + rightRackDepth / 2)\n }\n\n const mastGroup = new THREE.Group()\n mastGroup.position.x = craneX\n this.object3d.add(mastGroup)\n\n const mastMesh = new THREE.Mesh(new THREE.BoxGeometry(3, craneHeight, 3), mastMat)\n mastMesh.position.y = craneHeight / 2\n mastMesh.castShadow = true\n mastGroup.add(mastMesh)\n\n const topBeam = new THREE.Mesh(new THREE.BoxGeometry(bayWidth * 0.3, 2, aisleDepth * 0.8), mastMat)\n topBeam.position.y = craneHeight - 1\n mastGroup.add(topBeam)\n\n const carriageGroup = new THREE.Group()\n carriageGroup.position.y = craneY\n mastGroup.add(carriageGroup)\n\n const carrW = bayWidth * 0.7, carrH = 4, carrD = aisleDepth * 0.5\n const carriageMesh = new THREE.Mesh(new THREE.BoxGeometry(carrW, carrH, carrD), carriageMat)\n carriageMesh.castShadow = true\n carriageGroup.add(carriageMesh)\n\n const forkGroup = new THREE.Group()\n carriageGroup.add(forkGroup)\n\n const forkLength = Math.max(leftRackDepth, rightRackDepth) * 0.8\n const forkW = carrW * 0.15, forkH = 1.5\n const prongGeom = new THREE.BoxGeometry(forkW, forkH, forkLength)\n\n const lp = new THREE.Mesh(prongGeom, forkMat)\n lp.position.set(-carrW * 0.25, -carrH / 2 + forkH / 2, 0)\n forkGroup.add(lp)\n const rp = new THREE.Mesh(prongGeom.clone(), forkMat)\n rp.position.set(carrW * 0.25, -carrH / 2 + forkH / 2, 0)\n forkGroup.add(rp)\n const baseMesh = new THREE.Mesh(new THREE.BoxGeometry(carrW * 0.7, forkH, forkW), forkMat)\n baseMesh.position.set(0, -carrH / 2 + forkH / 2, -forkLength / 2 + forkW / 2)\n forkGroup.add(baseMesh)\n\n this._cranes.push({\n mastGroup, carriageGroup, forkGroup,\n state: { x: craneX, y: craneY, forkZ: 0, targetX: craneX, targetY: craneY, targetForkZ, bayWidth, levelHeight, maxBays, levels, leftRackDepth, rightRackDepth, aisleDepth }\n })\n }\n if (this._cranes.some(c => c.state.targetForkZ !== 0)) this._startCraneAnim()\n }\n\n updateCraneTargets() {\n const cranesData = this.stocker.cranesData\n const alongSize = this.stocker.layout.along\n for (let i = 0; i < this._cranes.length; i++) {\n const crane = this._cranes[i]\n const cd = cranesData[i]\n const s = crane.state\n const bay = cd?.bay ?? Math.round((i + 1) * s.maxBays / (this._cranes.length + 1))\n const level = cd?.level ?? 1\n const side = cd?.side\n const status = cd?.status || 'IDLE'\n s.targetX = -alongSize / 2 + (bay - 0.5) * s.bayWidth\n s.targetY = (level - 0.5) * s.levelHeight\n if ((status === 'PICKING' || status === 'PLACING') && side) {\n s.targetForkZ = side === 'L' ? -(s.aisleDepth / 2 + s.leftRackDepth / 2) : (s.aisleDepth / 2 + s.rightRackDepth / 2)\n } else { s.targetForkZ = 0 }\n }\n this._startCraneAnim()\n }\n\n private _startCraneAnim() {\n if (this._animRaf) return\n const animate = () => {\n let allDone = true\n for (const crane of this._cranes) {\n const s = crane.state, speed = 0.08\n s.x += (s.targetX - s.x) * speed; s.y += (s.targetY - s.y) * speed; s.forkZ += (s.targetForkZ - s.forkZ) * speed\n crane.mastGroup.position.x = s.x; crane.carriageGroup.position.y = s.y; crane.forkGroup.position.z = s.forkZ\n if (Math.abs(s.targetX - s.x) > 0.1 || Math.abs(s.targetY - s.y) > 0.1 || Math.abs(s.targetForkZ - s.forkZ) > 0.1) { allDone = false }\n else { s.x = s.targetX; s.y = s.targetY; s.forkZ = s.targetForkZ; crane.mastGroup.position.x = s.x; crane.carriageGroup.position.y = s.y; crane.forkGroup.position.z = s.forkZ }\n }\n if (allDone) { this._animRaf = 0; return }\n this._animRaf = requestAnimationFrame(animate)\n }\n this._animRaf = requestAnimationFrame(animate)\n }\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>) {\n if ('data' in after) { this.updateCraneTargets(); this.update(); return }\n if ('lBays' in after || 'lLevels' in after || 'lDepth' in after || 'rBays' in after || 'rLevels' in after || 'rDepth' in after ||\n 'cranes' in after || 'depth' in after || 'aisleRatio' in after ||\n 'width' in after || 'height' in after || 'locationRule' in after || 'hideRackFrame' in after || 'fillStyle' in after || 'frontSide' in after) {\n this.update(); return\n }\n super.onchange(after, before)\n }\n\n dispose() {\n if (this._animRaf) { cancelAnimationFrame(this._animRaf); this._animRaf = 0 }\n this._cranes = []; this._cellMeshes = []\n super.dispose()\n }\n\n updateDimension() {}\n updateAlpha() {}\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
2
|
+
import type { StockerPort } from './stocker-port.js';
|
|
3
|
+
export declare class StockerPort3d extends RealObjectGroup {
|
|
4
|
+
get port(): StockerPort;
|
|
5
|
+
get position(): {
|
|
6
|
+
x: number;
|
|
7
|
+
y: any;
|
|
8
|
+
z: number;
|
|
9
|
+
};
|
|
10
|
+
build(): void;
|
|
11
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>): void;
|
|
12
|
+
updateDimension(): void;
|
|
13
|
+
updateAlpha(): void;
|
|
14
|
+
}
|