@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
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* StockpileGrid3D — cell × cell 의 평치 영역 3D 시각화. cell 마다 pad + records 기반
|
|
5
|
+
* 자동 적치 carrier mesh. Stockpile3D 와 같은 idiom 의 cell 별 적용.
|
|
6
|
+
*
|
|
7
|
+
* cell pad mesh 에 userData.slotId 를 심어 click raycast 가 cell 을 식별, popup
|
|
8
|
+
* tether anchor 로 동작 (storage-rack 패턴).
|
|
9
|
+
*/
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
import { RealObjectGroup } from '@hatiolab/things-scene';
|
|
12
|
+
const PAD_DEPTH = 2;
|
|
13
|
+
const PRESET_COLOR = {
|
|
14
|
+
box: 0xb87333,
|
|
15
|
+
pallet: 0x8b6f47,
|
|
16
|
+
drum: 0x556679,
|
|
17
|
+
sack: 0xd4c89a,
|
|
18
|
+
crate: 0x9a7548,
|
|
19
|
+
bale: 0xa89968
|
|
20
|
+
};
|
|
21
|
+
const PRESET_DEFAULT_SIZE = {
|
|
22
|
+
box: { w: 26, h: 26, d: 20 },
|
|
23
|
+
pallet: { w: 40, h: 30, d: 15 },
|
|
24
|
+
drum: { w: 24, h: 24, d: 30 },
|
|
25
|
+
sack: { w: 30, h: 28, d: 18 },
|
|
26
|
+
crate: { w: 30, h: 30, d: 22 },
|
|
27
|
+
bale: { w: 32, h: 30, d: 18 }
|
|
28
|
+
};
|
|
29
|
+
export class StockpileGrid3D extends RealObjectGroup {
|
|
30
|
+
/** cellSlotId → pad mesh (popup tether anchor 용). */
|
|
31
|
+
_padByCellId = new Map();
|
|
32
|
+
/** cellSlotId → carriers group. */
|
|
33
|
+
_carriersByCellId = new Map();
|
|
34
|
+
/** material 캐시 (color → material) — 같은 색 carrier 공유. */
|
|
35
|
+
_materialByColor = new Map();
|
|
36
|
+
/** grid 전체를 감싸는 outer group (보드 보정 등). */
|
|
37
|
+
_gridGroup;
|
|
38
|
+
build() {
|
|
39
|
+
super.build();
|
|
40
|
+
this._buildGrid();
|
|
41
|
+
}
|
|
42
|
+
update() {
|
|
43
|
+
super.update();
|
|
44
|
+
this._rebuildAll();
|
|
45
|
+
}
|
|
46
|
+
/** carrier attach anchor — slotId 가 cellId 면 그 cell pad 반환, 아니면 grid group. */
|
|
47
|
+
getAttachFrame(slotId) {
|
|
48
|
+
if (slotId) {
|
|
49
|
+
const pad = this._padByCellId.get(slotId);
|
|
50
|
+
if (pad)
|
|
51
|
+
return pad;
|
|
52
|
+
}
|
|
53
|
+
return this._gridGroup;
|
|
54
|
+
}
|
|
55
|
+
/** slotTargetAt(cellId).attachObject3d = cell pad — Stockpile.getSlotAttachObject3d 가 호출. */
|
|
56
|
+
getCellPadMesh(slotId) {
|
|
57
|
+
return this._padByCellId.get(slotId);
|
|
58
|
+
}
|
|
59
|
+
_disposeAll() {
|
|
60
|
+
if (this._gridGroup) {
|
|
61
|
+
this._disposeGroupChildren(this._gridGroup);
|
|
62
|
+
this.object3d.remove(this._gridGroup);
|
|
63
|
+
this._gridGroup = undefined;
|
|
64
|
+
}
|
|
65
|
+
this._padByCellId.clear();
|
|
66
|
+
this._carriersByCellId.clear();
|
|
67
|
+
for (const m of this._materialByColor.values())
|
|
68
|
+
m.dispose();
|
|
69
|
+
this._materialByColor.clear();
|
|
70
|
+
}
|
|
71
|
+
_disposeGroupChildren(group) {
|
|
72
|
+
while (group.children.length > 0) {
|
|
73
|
+
const child = group.children[0];
|
|
74
|
+
this._disposeGroupChildren(child);
|
|
75
|
+
group.remove(child);
|
|
76
|
+
if (child.geometry?.dispose)
|
|
77
|
+
child.geometry.dispose();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
_rebuildAll() {
|
|
81
|
+
this._disposeAll();
|
|
82
|
+
this._buildGrid();
|
|
83
|
+
}
|
|
84
|
+
_buildGrid() {
|
|
85
|
+
const grid = this.component;
|
|
86
|
+
const cols = grid.cols;
|
|
87
|
+
const rows = grid.rows;
|
|
88
|
+
const cellW = grid.cellW;
|
|
89
|
+
const cellH = grid.cellH;
|
|
90
|
+
const state = grid.state;
|
|
91
|
+
const outline = new THREE.Color(state.strokeStyle || '#7a5a2e');
|
|
92
|
+
const fillColor = new THREE.Color(state.fillStyle || '#c89c5c');
|
|
93
|
+
this._gridGroup = new THREE.Group();
|
|
94
|
+
// grid pad 원점은 컴포넌트 중심 (left+totalW/2). state.left/top 기준 origin 0
|
|
95
|
+
// 인 사각형 좌상단 — grid local 좌표에서 cell 의 인덱스 (col, row) → cell center
|
|
96
|
+
// = (col+0.5)*cellW - totalW/2, (row+0.5)*cellH - totalH/2 (3D world 의 컴포넌트
|
|
97
|
+
// 중심 기준 local).
|
|
98
|
+
const totalW = cellW * cols;
|
|
99
|
+
const totalH = cellH * rows;
|
|
100
|
+
this.object3d.add(this._gridGroup);
|
|
101
|
+
for (let r = 0; r < rows; r++) {
|
|
102
|
+
for (let c = 0; c < cols; c++) {
|
|
103
|
+
const cellId = grid.cellIdOf(c, r);
|
|
104
|
+
const cellFill = fillColor; // cell 별 색 override 없음 — 모두 grid 공통
|
|
105
|
+
// ── cell pad ─────────────────────────────────────────
|
|
106
|
+
const padGeom = new THREE.BoxGeometry(cellW * 0.96, PAD_DEPTH, cellH * 0.96);
|
|
107
|
+
const padMat = new THREE.MeshStandardMaterial({
|
|
108
|
+
color: cellFill, roughness: 0.85, transparent: true, opacity: 0.55
|
|
109
|
+
});
|
|
110
|
+
const pad = new THREE.Mesh(padGeom, padMat);
|
|
111
|
+
const cx = (c + 0.5) * cellW - totalW / 2;
|
|
112
|
+
const cz = (r + 0.5) * cellH - totalH / 2;
|
|
113
|
+
pad.position.set(cx, PAD_DEPTH / 2, cz);
|
|
114
|
+
pad.receiveShadow = true;
|
|
115
|
+
pad.userData.slotId = cellId;
|
|
116
|
+
this._gridGroup.add(pad);
|
|
117
|
+
this._padByCellId.set(cellId, pad);
|
|
118
|
+
// cell outline — 페인트 라인
|
|
119
|
+
const padEdges = new THREE.EdgesGeometry(padGeom);
|
|
120
|
+
const padLine = new THREE.LineSegments(padEdges, new THREE.LineBasicMaterial({ color: outline }));
|
|
121
|
+
padLine.position.copy(pad.position);
|
|
122
|
+
this._gridGroup.add(padLine);
|
|
123
|
+
// ── cell carriers ────────────────────────────────────
|
|
124
|
+
const cg = new THREE.Group();
|
|
125
|
+
cg.position.set(cx, PAD_DEPTH, cz);
|
|
126
|
+
this._gridGroup.add(cg);
|
|
127
|
+
this._carriersByCellId.set(cellId, cg);
|
|
128
|
+
this._populateCellCarriers(c, r, cg);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** cell 의 records 를 stackPattern / carrierPreset 으로 배치. */
|
|
133
|
+
_populateCellCarriers(col, row, group) {
|
|
134
|
+
const grid = this.component;
|
|
135
|
+
const records = grid.recordsOf(col, row);
|
|
136
|
+
if (records.length === 0)
|
|
137
|
+
return;
|
|
138
|
+
const state = grid.state;
|
|
139
|
+
const preset = (state.carrierPreset ?? 'box');
|
|
140
|
+
const pattern = (state.stackPattern ?? 'row');
|
|
141
|
+
const def = PRESET_DEFAULT_SIZE[preset] ?? PRESET_DEFAULT_SIZE.box;
|
|
142
|
+
const cw = state.carrierWidth ?? def.w;
|
|
143
|
+
const ch = state.carrierHeight ?? def.h;
|
|
144
|
+
const cd = state.carrierDepth ?? def.d;
|
|
145
|
+
const gap = state.carrierGap ?? 10;
|
|
146
|
+
const heightLimit = state.stackHeightLimit;
|
|
147
|
+
const cellW = grid.cellW;
|
|
148
|
+
const cellH = grid.cellH;
|
|
149
|
+
const geom = this._carrierGeometry(preset, cw, ch, cd);
|
|
150
|
+
const positions = this._computeStackPositions(pattern, records.length, cellW, cellH, cw, ch, cd, gap, heightLimit);
|
|
151
|
+
const presetDefault = PRESET_COLOR[preset] ?? PRESET_COLOR.box;
|
|
152
|
+
for (let i = 0; i < positions.length; i++) {
|
|
153
|
+
const p = positions[i];
|
|
154
|
+
const record = records[i];
|
|
155
|
+
const legendColor = grid.resolveLegendColor?.(record);
|
|
156
|
+
let colorHex = presetDefault;
|
|
157
|
+
if (typeof legendColor === 'string' && legendColor.length > 0) {
|
|
158
|
+
try {
|
|
159
|
+
colorHex = new THREE.Color(legendColor).getHex();
|
|
160
|
+
}
|
|
161
|
+
catch { /* ignore */ }
|
|
162
|
+
}
|
|
163
|
+
const mat = this._getMaterial(colorHex);
|
|
164
|
+
const mesh = new THREE.Mesh(geom, mat);
|
|
165
|
+
mesh.position.set(p.x, p.y, p.z);
|
|
166
|
+
mesh.castShadow = true;
|
|
167
|
+
mesh.receiveShadow = true;
|
|
168
|
+
mesh.userData.recordId = record.id;
|
|
169
|
+
mesh.userData.cellId = grid.cellIdOf(col, row);
|
|
170
|
+
group.add(mesh);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
_computeStackPositions(pattern, count, areaW, areaH, cw, ch, cd, gap, heightLimit) {
|
|
174
|
+
const out = [];
|
|
175
|
+
if (pattern === 'column') {
|
|
176
|
+
const layers = heightLimit ?? count;
|
|
177
|
+
for (let i = 0; i < count; i++) {
|
|
178
|
+
const layer = Math.min(i, layers - 1);
|
|
179
|
+
out.push({ x: 0, y: layer * cd + cd / 2, z: 0 });
|
|
180
|
+
}
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
const stridX = cw + gap;
|
|
184
|
+
const stridZ = ch + gap;
|
|
185
|
+
const cols = Math.max(1, Math.floor((areaW + gap) / stridX));
|
|
186
|
+
const rows = Math.max(1, Math.floor((areaH + gap) / stridZ));
|
|
187
|
+
const cellsPerLayer = cols * rows;
|
|
188
|
+
if (pattern === 'pyramid') {
|
|
189
|
+
let remaining = count;
|
|
190
|
+
let layer = 0;
|
|
191
|
+
while (remaining > 0) {
|
|
192
|
+
const lcols = Math.max(1, cols - layer);
|
|
193
|
+
const lrows = Math.max(1, rows - layer);
|
|
194
|
+
const cellsThisLayer = lcols * lrows;
|
|
195
|
+
const take = Math.min(remaining, cellsThisLayer);
|
|
196
|
+
for (let i = 0; i < take; i++) {
|
|
197
|
+
const c = i % lcols;
|
|
198
|
+
const r = Math.floor(i / lcols);
|
|
199
|
+
const offC = (cols - lcols) / 2;
|
|
200
|
+
const offR = (rows - lrows) / 2;
|
|
201
|
+
const x = -areaW / 2 + (c + offC + 0.5) * stridX;
|
|
202
|
+
const z = -areaH / 2 + (r + offR + 0.5) * stridZ;
|
|
203
|
+
out.push({ x, y: layer * cd + cd / 2, z });
|
|
204
|
+
}
|
|
205
|
+
remaining -= take;
|
|
206
|
+
layer++;
|
|
207
|
+
if (lcols === 1 && lrows === 1) {
|
|
208
|
+
for (let i = 0; i < remaining; i++) {
|
|
209
|
+
out.push({ x: 0, y: (layer + i) * cd + cd / 2, z: 0 });
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if (heightLimit && layer >= heightLimit)
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
if (pattern === 'pile') {
|
|
219
|
+
const rng = (i) => ((Math.sin(i * 12.9898) * 43758.5453) % 1 + 1) % 1;
|
|
220
|
+
for (let i = 0; i < count; i++) {
|
|
221
|
+
const layer = Math.floor(i / cellsPerLayer);
|
|
222
|
+
const idx = i % cellsPerLayer;
|
|
223
|
+
const c = idx % cols;
|
|
224
|
+
const r = Math.floor(idx / cols);
|
|
225
|
+
const jX = (rng(i * 2) - 0.5) * cw * 0.2;
|
|
226
|
+
const jZ = (rng(i * 2 + 1) - 0.5) * ch * 0.2;
|
|
227
|
+
const x = -areaW / 2 + (c + 0.5) * stridX + jX;
|
|
228
|
+
const z = -areaH / 2 + (r + 0.5) * stridZ + jZ;
|
|
229
|
+
out.push({ x, y: layer * cd + cd / 2, z });
|
|
230
|
+
if (heightLimit && layer >= heightLimit - 1 && idx === cellsPerLayer - 1)
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
// row / staggered
|
|
236
|
+
for (let i = 0; i < count; i++) {
|
|
237
|
+
const layer = Math.floor(i / cellsPerLayer);
|
|
238
|
+
if (heightLimit && layer >= heightLimit)
|
|
239
|
+
break;
|
|
240
|
+
const idx = i % cellsPerLayer;
|
|
241
|
+
const c = idx % cols;
|
|
242
|
+
const r = Math.floor(idx / cols);
|
|
243
|
+
let x = -areaW / 2 + (c + 0.5) * stridX;
|
|
244
|
+
const z = -areaH / 2 + (r + 0.5) * stridZ;
|
|
245
|
+
if (pattern === 'staggered' && layer % 2 === 1)
|
|
246
|
+
x += stridX / 2;
|
|
247
|
+
out.push({ x, y: layer * cd + cd / 2, z });
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
_carrierGeometry(preset, w, h, d) {
|
|
252
|
+
if (preset === 'drum') {
|
|
253
|
+
const radius = Math.min(w, h) / 2;
|
|
254
|
+
return new THREE.CylinderGeometry(radius, radius, d, 16);
|
|
255
|
+
}
|
|
256
|
+
if (preset === 'sack' || preset === 'bale') {
|
|
257
|
+
return new THREE.BoxGeometry(w * 0.92, d * 0.92, h * 0.92);
|
|
258
|
+
}
|
|
259
|
+
return new THREE.BoxGeometry(w, d, h);
|
|
260
|
+
}
|
|
261
|
+
_getMaterial(colorHex) {
|
|
262
|
+
let m = this._materialByColor.get(colorHex);
|
|
263
|
+
if (!m) {
|
|
264
|
+
m = new THREE.MeshStandardMaterial({ color: colorHex, roughness: 0.7 });
|
|
265
|
+
this._materialByColor.set(colorHex, m);
|
|
266
|
+
}
|
|
267
|
+
return m;
|
|
268
|
+
}
|
|
269
|
+
onchange(after, before) {
|
|
270
|
+
// 거의 모든 속성 변경이 grid 재구성 — 단순화.
|
|
271
|
+
const keys = [
|
|
272
|
+
'cols', 'rows', 'cellWidth', 'cellHeight',
|
|
273
|
+
'cells', 'data',
|
|
274
|
+
'stackPattern', 'carrierPreset',
|
|
275
|
+
'carrierWidth', 'carrierHeight', 'carrierDepth', 'carrierGap',
|
|
276
|
+
'capacity', 'stackHeightLimit', 'pickPolicy',
|
|
277
|
+
'fillStyle', 'strokeStyle',
|
|
278
|
+
'width', 'height'
|
|
279
|
+
];
|
|
280
|
+
if (keys.some(k => k in after)) {
|
|
281
|
+
this._rebuildAll();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
super.onchange?.(after, before);
|
|
285
|
+
}
|
|
286
|
+
updateDimension() {
|
|
287
|
+
this._rebuildAll();
|
|
288
|
+
}
|
|
289
|
+
updateAlpha() {
|
|
290
|
+
const alpha = typeof this.component.state.alpha === 'number'
|
|
291
|
+
? this.component.state.alpha : 1;
|
|
292
|
+
// pad 들의 opacity 만 (carriers 는 alpha 그대로)
|
|
293
|
+
for (const pad of this._padByCellId.values()) {
|
|
294
|
+
const m = pad.material;
|
|
295
|
+
m.opacity = 0.55 * alpha;
|
|
296
|
+
m.transparent = m.opacity < 1;
|
|
297
|
+
m.needsUpdate = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=stockpile-grid-3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stockpile-grid-3d.js","sourceRoot":"","sources":["../src/stockpile-grid-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * StockpileGrid3D — cell × cell 의 평치 영역 3D 시각화. cell 마다 pad + records 기반\n * 자동 적치 carrier mesh. Stockpile3D 와 같은 idiom 의 cell 별 적용.\n *\n * cell pad mesh 에 userData.slotId 를 심어 click raycast 가 cell 을 식별, popup\n * tether anchor 로 동작 (storage-rack 패턴).\n */\n\nimport * as THREE from 'three'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nimport type StockpileGrid from './stockpile-grid.js'\nimport type { StackPattern, CarrierPreset } from './stockpile.js'\n\nconst PAD_DEPTH = 2\n\nconst PRESET_COLOR: Record<CarrierPreset, number> = {\n box: 0xb87333,\n pallet: 0x8b6f47,\n drum: 0x556679,\n sack: 0xd4c89a,\n crate: 0x9a7548,\n bale: 0xa89968\n}\n\nconst PRESET_DEFAULT_SIZE: Record<CarrierPreset, { w: number; h: number; d: number }> = {\n box: { w: 26, h: 26, d: 20 },\n pallet: { w: 40, h: 30, d: 15 },\n drum: { w: 24, h: 24, d: 30 },\n sack: { w: 30, h: 28, d: 18 },\n crate: { w: 30, h: 30, d: 22 },\n bale: { w: 32, h: 30, d: 18 }\n}\n\nexport class StockpileGrid3D extends RealObjectGroup {\n /** cellSlotId → pad mesh (popup tether anchor 용). */\n private _padByCellId: Map<string, THREE.Mesh> = new Map()\n /** cellSlotId → carriers group. */\n private _carriersByCellId: Map<string, THREE.Group> = new Map()\n /** material 캐시 (color → material) — 같은 색 carrier 공유. */\n private _materialByColor: Map<number, THREE.MeshStandardMaterial> = new Map()\n /** grid 전체를 감싸는 outer group (보드 보정 등). */\n private _gridGroup?: THREE.Group\n\n build() {\n super.build()\n this._buildGrid()\n }\n\n update() {\n super.update()\n this._rebuildAll()\n }\n\n /** carrier attach anchor — slotId 가 cellId 면 그 cell pad 반환, 아니면 grid group. */\n getAttachFrame(slotId?: string): THREE.Object3D | undefined {\n if (slotId) {\n const pad = this._padByCellId.get(slotId)\n if (pad) return pad\n }\n return this._gridGroup\n }\n /** slotTargetAt(cellId).attachObject3d = cell pad — Stockpile.getSlotAttachObject3d 가 호출. */\n getCellPadMesh(slotId: string): THREE.Mesh | undefined {\n return this._padByCellId.get(slotId)\n }\n\n private _disposeAll(): void {\n if (this._gridGroup) {\n this._disposeGroupChildren(this._gridGroup)\n this.object3d.remove(this._gridGroup)\n this._gridGroup = undefined\n }\n this._padByCellId.clear()\n this._carriersByCellId.clear()\n for (const m of this._materialByColor.values()) m.dispose()\n this._materialByColor.clear()\n }\n\n private _disposeGroupChildren(group: THREE.Object3D): void {\n while (group.children.length > 0) {\n const child = group.children[0]\n this._disposeGroupChildren(child)\n group.remove(child)\n if ((child as any).geometry?.dispose) (child as any).geometry.dispose()\n }\n }\n\n private _rebuildAll(): void {\n this._disposeAll()\n this._buildGrid()\n }\n\n private _buildGrid(): void {\n const grid = this.component as unknown as StockpileGrid\n const cols = grid.cols\n const rows = grid.rows\n const cellW = grid.cellW\n const cellH = grid.cellH\n const state = grid.state as any\n\n const outline = new THREE.Color((state.strokeStyle as string) || '#7a5a2e')\n const fillColor = new THREE.Color((state.fillStyle as string) || '#c89c5c')\n\n this._gridGroup = new THREE.Group()\n // grid pad 원점은 컴포넌트 중심 (left+totalW/2). state.left/top 기준 origin 0\n // 인 사각형 좌상단 — grid local 좌표에서 cell 의 인덱스 (col, row) → cell center\n // = (col+0.5)*cellW - totalW/2, (row+0.5)*cellH - totalH/2 (3D world 의 컴포넌트\n // 중심 기준 local).\n const totalW = cellW * cols\n const totalH = cellH * rows\n this.object3d.add(this._gridGroup)\n\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const cellId = grid.cellIdOf(c, r)\n const cellFill = fillColor // cell 별 색 override 없음 — 모두 grid 공통\n\n // ── cell pad ─────────────────────────────────────────\n const padGeom = new THREE.BoxGeometry(cellW * 0.96, PAD_DEPTH, cellH * 0.96)\n const padMat = new THREE.MeshStandardMaterial({\n color: cellFill, roughness: 0.85, transparent: true, opacity: 0.55\n })\n const pad = new THREE.Mesh(padGeom, padMat)\n const cx = (c + 0.5) * cellW - totalW / 2\n const cz = (r + 0.5) * cellH - totalH / 2\n pad.position.set(cx, PAD_DEPTH / 2, cz)\n pad.receiveShadow = true\n pad.userData.slotId = cellId\n this._gridGroup.add(pad)\n this._padByCellId.set(cellId, pad)\n\n // cell outline — 페인트 라인\n const padEdges = new THREE.EdgesGeometry(padGeom)\n const padLine = new THREE.LineSegments(padEdges, new THREE.LineBasicMaterial({ color: outline }))\n padLine.position.copy(pad.position)\n this._gridGroup.add(padLine)\n\n // ── cell carriers ────────────────────────────────────\n const cg = new THREE.Group()\n cg.position.set(cx, PAD_DEPTH, cz)\n this._gridGroup.add(cg)\n this._carriersByCellId.set(cellId, cg)\n this._populateCellCarriers(c, r, cg)\n }\n }\n }\n\n /** cell 의 records 를 stackPattern / carrierPreset 으로 배치. */\n private _populateCellCarriers(col: number, row: number, group: THREE.Group): void {\n const grid = this.component as unknown as StockpileGrid\n const records = grid.recordsOf(col, row)\n if (records.length === 0) return\n\n const state = grid.state as any\n const preset = (state.carrierPreset ?? 'box') as CarrierPreset\n const pattern = (state.stackPattern ?? 'row') as StackPattern\n const def = PRESET_DEFAULT_SIZE[preset] ?? PRESET_DEFAULT_SIZE.box\n const cw = state.carrierWidth ?? def.w\n const ch = state.carrierHeight ?? def.h\n const cd = state.carrierDepth ?? def.d\n const gap = state.carrierGap ?? 10\n const heightLimit = state.stackHeightLimit as number | undefined\n\n const cellW = grid.cellW\n const cellH = grid.cellH\n const geom = this._carrierGeometry(preset, cw, ch, cd)\n\n const positions = this._computeStackPositions(pattern, records.length, cellW, cellH, cw, ch, cd, gap, heightLimit)\n const presetDefault = PRESET_COLOR[preset] ?? PRESET_COLOR.box\n for (let i = 0; i < positions.length; i++) {\n const p = positions[i]\n const record = records[i]\n const legendColor = (grid as any).resolveLegendColor?.(record)\n let colorHex = presetDefault\n if (typeof legendColor === 'string' && legendColor.length > 0) {\n try { colorHex = new THREE.Color(legendColor).getHex() } catch { /* ignore */ }\n }\n const mat = this._getMaterial(colorHex)\n const mesh = new THREE.Mesh(geom, mat)\n mesh.position.set(p.x, p.y, p.z)\n mesh.castShadow = true\n mesh.receiveShadow = true\n mesh.userData.recordId = record.id\n mesh.userData.cellId = grid.cellIdOf(col, row)\n group.add(mesh)\n }\n }\n\n private _computeStackPositions(\n pattern: StackPattern,\n count: number,\n areaW: number, areaH: number,\n cw: number, ch: number, cd: number,\n gap: number,\n heightLimit?: number\n ): Array<{ x: number; y: number; z: number }> {\n const out: Array<{ x: number; y: number; z: number }> = []\n if (pattern === 'column') {\n const layers = heightLimit ?? count\n for (let i = 0; i < count; i++) {\n const layer = Math.min(i, layers - 1)\n out.push({ x: 0, y: layer * cd + cd / 2, z: 0 })\n }\n return out\n }\n const stridX = cw + gap\n const stridZ = ch + gap\n const cols = Math.max(1, Math.floor((areaW + gap) / stridX))\n const rows = Math.max(1, Math.floor((areaH + gap) / stridZ))\n const cellsPerLayer = cols * rows\n if (pattern === 'pyramid') {\n let remaining = count\n let layer = 0\n while (remaining > 0) {\n const lcols = Math.max(1, cols - layer)\n const lrows = Math.max(1, rows - layer)\n const cellsThisLayer = lcols * lrows\n const take = Math.min(remaining, cellsThisLayer)\n for (let i = 0; i < take; i++) {\n const c = i % lcols\n const r = Math.floor(i / lcols)\n const offC = (cols - lcols) / 2\n const offR = (rows - lrows) / 2\n const x = -areaW / 2 + (c + offC + 0.5) * stridX\n const z = -areaH / 2 + (r + offR + 0.5) * stridZ\n out.push({ x, y: layer * cd + cd / 2, z })\n }\n remaining -= take\n layer++\n if (lcols === 1 && lrows === 1) {\n for (let i = 0; i < remaining; i++) {\n out.push({ x: 0, y: (layer + i) * cd + cd / 2, z: 0 })\n }\n break\n }\n if (heightLimit && layer >= heightLimit) break\n }\n return out\n }\n if (pattern === 'pile') {\n const rng = (i: number) => ((Math.sin(i * 12.9898) * 43758.5453) % 1 + 1) % 1\n for (let i = 0; i < count; i++) {\n const layer = Math.floor(i / cellsPerLayer)\n const idx = i % cellsPerLayer\n const c = idx % cols\n const r = Math.floor(idx / cols)\n const jX = (rng(i * 2) - 0.5) * cw * 0.2\n const jZ = (rng(i * 2 + 1) - 0.5) * ch * 0.2\n const x = -areaW / 2 + (c + 0.5) * stridX + jX\n const z = -areaH / 2 + (r + 0.5) * stridZ + jZ\n out.push({ x, y: layer * cd + cd / 2, z })\n if (heightLimit && layer >= heightLimit - 1 && idx === cellsPerLayer - 1) break\n }\n return out\n }\n // row / staggered\n for (let i = 0; i < count; i++) {\n const layer = Math.floor(i / cellsPerLayer)\n if (heightLimit && layer >= heightLimit) break\n const idx = i % cellsPerLayer\n const c = idx % cols\n const r = Math.floor(idx / cols)\n let x = -areaW / 2 + (c + 0.5) * stridX\n const z = -areaH / 2 + (r + 0.5) * stridZ\n if (pattern === 'staggered' && layer % 2 === 1) x += stridX / 2\n out.push({ x, y: layer * cd + cd / 2, z })\n }\n return out\n }\n\n private _carrierGeometry(preset: CarrierPreset, w: number, h: number, d: number): THREE.BufferGeometry {\n if (preset === 'drum') {\n const radius = Math.min(w, h) / 2\n return new THREE.CylinderGeometry(radius, radius, d, 16)\n }\n if (preset === 'sack' || preset === 'bale') {\n return new THREE.BoxGeometry(w * 0.92, d * 0.92, h * 0.92)\n }\n return new THREE.BoxGeometry(w, d, h)\n }\n\n private _getMaterial(colorHex: number): THREE.MeshStandardMaterial {\n let m = this._materialByColor.get(colorHex)\n if (!m) {\n m = new THREE.MeshStandardMaterial({ color: colorHex, roughness: 0.7 })\n this._materialByColor.set(colorHex, m)\n }\n return m\n }\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>): void {\n // 거의 모든 속성 변경이 grid 재구성 — 단순화.\n const keys = [\n 'cols', 'rows', 'cellWidth', 'cellHeight',\n 'cells', 'data',\n 'stackPattern', 'carrierPreset',\n 'carrierWidth', 'carrierHeight', 'carrierDepth', 'carrierGap',\n 'capacity', 'stackHeightLimit', 'pickPolicy',\n 'fillStyle', 'strokeStyle',\n 'width', 'height'\n ]\n if (keys.some(k => k in after)) {\n this._rebuildAll()\n return\n }\n super.onchange?.(after, before)\n }\n\n updateDimension(): void {\n this._rebuildAll()\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 // pad 들의 opacity 만 (carriers 는 alpha 그대로)\n for (const pad of this._padByCellId.values()) {\n const m = pad.material as THREE.MeshStandardMaterial\n m.opacity = 0.55 * alpha\n m.transparent = m.opacity < 1\n m.needsUpdate = true\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
|
|
2
|
+
import type { State, Material3D } from '@hatiolab/things-scene';
|
|
3
|
+
import { SlotTarget, type AttachFrame, type Alignment, type Heights, type PlacementArchetype } from '@operato/scene-base';
|
|
4
|
+
import { StockpileGrid3D } from './stockpile-grid-3d.js';
|
|
5
|
+
import type { StackPattern, CarrierPreset, StockpileRecord, PickPolicy } from './stockpile.js';
|
|
6
|
+
/** grid 의 한 cell — 위치 + 그 cell 의 records. */
|
|
7
|
+
export interface StockpileGridCell {
|
|
8
|
+
col: number;
|
|
9
|
+
row: number;
|
|
10
|
+
data?: StockpileRecord[];
|
|
11
|
+
}
|
|
12
|
+
export interface StockpileGridState extends State {
|
|
13
|
+
cols?: number;
|
|
14
|
+
rows?: number;
|
|
15
|
+
/** 한 cell 의 평면 크기 (전체 width/height = cellWidth*cols, cellHeight*rows). */
|
|
16
|
+
cellWidth?: number;
|
|
17
|
+
cellHeight?: number;
|
|
18
|
+
/** grid 의 cell 들 — 각 cell 은 { col, row, data: Record[] }. */
|
|
19
|
+
data?: StockpileGridCell[];
|
|
20
|
+
stackPattern?: StackPattern;
|
|
21
|
+
carrierPreset?: CarrierPreset;
|
|
22
|
+
carrierWidth?: number;
|
|
23
|
+
carrierHeight?: number;
|
|
24
|
+
carrierDepth?: number;
|
|
25
|
+
carrierGap?: number;
|
|
26
|
+
capacity?: number;
|
|
27
|
+
stackHeightLimit?: number;
|
|
28
|
+
pickPolicy?: PickPolicy;
|
|
29
|
+
popupRef?: string;
|
|
30
|
+
legendTarget?: string;
|
|
31
|
+
material3d?: Material3D;
|
|
32
|
+
}
|
|
33
|
+
declare const StockpileGrid_base: any;
|
|
34
|
+
export default class StockpileGrid extends StockpileGrid_base {
|
|
35
|
+
state: StockpileGridState;
|
|
36
|
+
_realObject?: StockpileGrid3D;
|
|
37
|
+
static placement: PlacementArchetype;
|
|
38
|
+
static align: Alignment;
|
|
39
|
+
static defaultDepth: (_h: Heights) => number;
|
|
40
|
+
get nature(): ComponentNature;
|
|
41
|
+
get anchors(): never[];
|
|
42
|
+
_rebuildVisual(): void;
|
|
43
|
+
get cols(): number;
|
|
44
|
+
get rows(): number;
|
|
45
|
+
get cellW(): number;
|
|
46
|
+
get cellH(): number;
|
|
47
|
+
cellIdOf(col: number, row: number): string;
|
|
48
|
+
parseCellId(slotId: string): {
|
|
49
|
+
col: number;
|
|
50
|
+
row: number;
|
|
51
|
+
} | null;
|
|
52
|
+
/** state.data 에서 (col,row) cell 찾기. */
|
|
53
|
+
private _findCell;
|
|
54
|
+
/** cell 의 records (없으면 빈 배열). */
|
|
55
|
+
recordsOf(col: number, row: number): ReadonlyArray<StockpileRecord>;
|
|
56
|
+
/** capacity 는 모든 cell 공통. */
|
|
57
|
+
capacityOf(_col: number, _row: number): number | undefined;
|
|
58
|
+
slotIds(): ReadonlyArray<string>;
|
|
59
|
+
hasCarrierAt(slotId: string): boolean;
|
|
60
|
+
canReceiveAt(slotId: string, _carrier?: Component): boolean;
|
|
61
|
+
occupiedSlotIds(): ReadonlyArray<string>;
|
|
62
|
+
emptySlotIds(): ReadonlyArray<string>;
|
|
63
|
+
obtainCarrier(slotId: string): Component | null;
|
|
64
|
+
receiveAt(slotId: string, carrier: Component, _options?: any): Promise<void>;
|
|
65
|
+
accept(carrier: Component, options?: any): Promise<void>;
|
|
66
|
+
receive(carrier: Component, options?: any): Promise<void>;
|
|
67
|
+
slotTargetAt(slotId: string): SlotTarget;
|
|
68
|
+
getSlotAttachObject3d(slotId: string): any;
|
|
69
|
+
attachPointFor(carrier: Component): AttachFrame | null;
|
|
70
|
+
private _setCellRecords;
|
|
71
|
+
private _materializeCarrier;
|
|
72
|
+
get eventMap(): {
|
|
73
|
+
'(self)': {
|
|
74
|
+
'(self)': {
|
|
75
|
+
click: (mouseEvent: MouseEvent) => void;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
private _onGridClick;
|
|
80
|
+
private _dispatchCellPopup;
|
|
81
|
+
private _raycastHit;
|
|
82
|
+
render(ctx: CanvasRenderingContext2D): void;
|
|
83
|
+
buildRealObject(): RealObject | undefined;
|
|
84
|
+
}
|
|
85
|
+
export {};
|