@operato/scene-storage 10.0.0-beta.44 → 10.0.0-beta.47

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/crane-3d.d.ts +10 -0
  3. package/dist/crane-3d.js +34 -5
  4. package/dist/crane-3d.js.map +1 -1
  5. package/dist/crane.d.ts +136 -6
  6. package/dist/crane.js +578 -48
  7. package/dist/crane.js.map +1 -1
  8. package/dist/parcel-3d.d.ts +1 -0
  9. package/dist/parcel-3d.js +18 -1
  10. package/dist/parcel-3d.js.map +1 -1
  11. package/dist/rack-grid-3d.js +26 -8
  12. package/dist/rack-grid-3d.js.map +1 -1
  13. package/dist/rack-grid.d.ts +103 -10
  14. package/dist/rack-grid.js +484 -86
  15. package/dist/rack-grid.js.map +1 -1
  16. package/dist/storage-rack-3d.js +1 -1
  17. package/dist/storage-rack-3d.js.map +1 -1
  18. package/dist/storage-rack.d.ts +40 -6
  19. package/dist/storage-rack.js +111 -14
  20. package/dist/storage-rack.js.map +1 -1
  21. package/package.json +4 -4
  22. package/src/crane-3d.ts +34 -4
  23. package/src/crane.ts +625 -57
  24. package/src/parcel-3d.ts +19 -1
  25. package/src/rack-grid-3d.ts +31 -8
  26. package/src/rack-grid.ts +504 -82
  27. package/src/storage-rack-3d.ts +1 -1
  28. package/src/storage-rack.ts +111 -14
  29. package/test/test-coord-alignment.ts +2 -2
  30. package/test/test-crane-bay-match.ts +130 -0
  31. package/test/test-crane-binding-resolve.ts +168 -0
  32. package/test/test-crane-duration.ts +90 -0
  33. package/test/test-crane-rotation-reach.ts +218 -0
  34. package/test/test-rack-grid-3d-alignment.ts +235 -0
  35. package/test/test-rack-grid-3d-attach-real.ts +375 -0
  36. package/test/test-rack-grid-cell.ts +2 -2
  37. package/test/test-rack-grid-location.ts +2 -2
  38. package/test/test-rack-grid-occupied-slots.ts +165 -0
  39. package/test/test-rack-grid-picking-position.ts +154 -0
  40. package/test/test-rack-grid-slot-api.ts +483 -0
  41. package/test/test-slot-ids-enumeration.ts +137 -0
  42. package/test/things-scene-loader-impl.mjs +37 -0
  43. package/test/things-scene-loader.mjs +24 -0
  44. package/translations/en.json +2 -0
  45. package/translations/ja.json +2 -0
  46. package/translations/ko.json +2 -0
  47. package/translations/ms.json +2 -0
  48. package/translations/zh.json +2 -0
  49. package/tsconfig.tsbuildinfo +1 -1
@@ -52,13 +52,15 @@ export class RackGrid3D extends RealObjectGroup {
52
52
  this._beamGroup = new THREE.Group();
53
53
  this._frameGroup.add(this._beamGroup);
54
54
  this.object3d.add(this._frameGroup);
55
- const width = rs?.width ?? 400; // 3D X
56
- const height = rs?.depth ?? 2000; // 3D Y (floor ceiling)
57
- const depth = rs?.height ?? 200; // 3D Z (front → back)
55
+ // ?? 쓰면 NaN 통과 finite + positive 검증 후 default fallback.
56
+ const finite = (v, fb) => typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : fb;
57
+ const width = finite(rs?.width, 400); // 3D X
58
+ const height = finite(rs?.depth, 2000); // 3D Y (floor → ceiling)
59
+ const depth = finite(rs?.height, 200); // 3D Z (front → back)
58
60
  const cols = comp.columns;
59
61
  const rows = comp.rackRows;
60
62
  const shelves = comp.shelves;
61
- const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, height * 0.9));
63
+ const shelfBase = Math.max(0, Math.min(finite(rs?.shelfBaseHeight, 0), height * 0.9));
62
64
  const shelfZone = height - shelfBase;
63
65
  const bayW = width / cols;
64
66
  const bayD = depth / rows;
@@ -286,10 +288,13 @@ export class RackGrid3D extends RealObjectGroup {
286
288
  const cols = comp.columns;
287
289
  const rows = comp.rackRows;
288
290
  const shelves = comp.shelves;
289
- const width = rs?.width ?? 400;
290
- const height = rs?.depth ?? 2000;
291
- const depth = rs?.height ?? 200;
292
- const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, height * 0.9));
291
+ // state.width/depth/height NaN 인 경우 — ?? 는 nullish 만 fallback 이라 NaN 통과.
292
+ // 명시적 finite 검증 default 사용. NaN BoxGeometry 의 근본 원인.
293
+ const finite = (v, fb) => typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : fb;
294
+ const width = finite(rs?.width, 400);
295
+ const height = finite(rs?.depth, 2000);
296
+ const depth = finite(rs?.height, 200);
297
+ const shelfBase = Math.max(0, Math.min(finite(rs?.shelfBaseHeight, 0), height * 0.9));
293
298
  const shelfZone = height - shelfBase;
294
299
  const bayW = width / cols;
295
300
  const bayD = depth / rows;
@@ -299,6 +304,19 @@ export class RackGrid3D extends RealObjectGroup {
299
304
  const stockW = bayW * 0.85;
300
305
  const stockD = cellY * 0.7;
301
306
  const stockH = bayD * 0.85;
307
+ // 최종 차원이 finite 한지 검증 — accessor + finite() 거쳤어도 *모든 입력이 0* 이거나
308
+ // 예상 못한 경로로 NaN/0 가능성. invalid 시 stock mesh 생성 자체를 skip + 진단 로그.
309
+ if (!Number.isFinite(stockW) || stockW <= 0 ||
310
+ !Number.isFinite(stockD) || stockD <= 0 ||
311
+ !Number.isFinite(stockH) || stockH <= 0) {
312
+ console.error('[rack-grid-3d] rebuildStockMesh: invalid stock dims — mesh 생성 skip', {
313
+ stockW, stockD, stockH,
314
+ cols, rows, shelves,
315
+ width, height, depth, shelfBase, shelfZone, cellY, bayW, bayD,
316
+ stateW: rs?.width, stateDepth: rs?.depth, stateH: rs?.height, stateShelfBase: rs?.shelfBaseHeight
317
+ });
318
+ return;
319
+ }
302
320
  const records = comp.records;
303
321
  const recordsByCell = new Map();
304
322
  for (const r of records) {
@@ -1 +1 @@
1
- {"version":3,"file":"rack-grid-3d.js","sourceRoot":"","sources":["../src/rack-grid-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackGrid3D — *공유 corner posts + bay 별 beams + shelf planes*.\n *\n * Post (수직 기둥):\n * - (cols+1) × (rows+1) 의 grid corner 위치마다 *공유 post* 1 개.\n * - 인접 4 bay 중 *최소 1개 non-empty* 면 post 만듦. 모두 empty 면 skip.\n * - 옆 bay 와 *공유* → 두 post 겹침 X.\n *\n * Beam (수평 부재):\n * - non-empty bay 마다 front + back beam (각 shelf level).\n *\n * Shelf (반투명 판):\n * - non-empty bay 의 각 level 의 frame 안쪽.\n *\n * isEmpty source of truth: RackGrid.isBayEmpty(col, row) — cell.state.isEmpty 우선.\n */\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\nimport type RackGrid from './rack-grid.js'\nimport {\n POST_MATERIAL, BEAM_MATERIAL, SHELF_MATERIAL,\n STOCK_MATERIAL, EMPTY_STOCK_MATERIAL\n} from './rack-materials.js'\n\nexport class RackGrid3D extends RealObjectGroup {\n private _frameGroup?: THREE.Group // post + beam 묶음 (hideRackFrame 시 hidden)\n private _beamGroup?: THREE.Group // beam 만 (hideHorizontalFrame 시 hidden)\n\n build() {\n super.build()\n this._buildFrames()\n this._applyFrameVisibility()\n }\n\n /** hideRackFrame / hideHorizontalFrame 변경 시 visibility 즉시 반영. */\n applyFrameVisibility(): void {\n this._applyFrameVisibility()\n }\n\n private _applyFrameVisibility(): void {\n const rs: any = this.component.state\n const hideFrame = !!rs?.hideRackFrame\n const hideBeams = !!rs?.hideHorizontalFrame\n if (this._frameGroup) this._frameGroup.visible = !hideFrame\n // beam group 은 frame group 안에 nested — frame 이 hidden 일 때는 beam 도 자연히 hidden.\n // frame visible + beam toggle 따로\n if (this._beamGroup) this._beamGroup.visible = !hideBeams\n }\n\n private _buildFrames(): void {\n const comp = this.component as unknown as RackGrid\n const rs: any = comp.state\n // frame group — post + beamGroup 담음. hideRackFrame 시 frame group.visible=false.\n // beam group — 가로 frame 만 (hideHorizontalFrame 시 따로 토글).\n this._frameGroup = new THREE.Group()\n this._beamGroup = new THREE.Group()\n this._frameGroup.add(this._beamGroup)\n this.object3d.add(this._frameGroup)\n\n const width = (rs?.width as number) ?? 400 // 3D X\n const height = (rs?.depth as number) ?? 2000 // 3D Y (floor → ceiling)\n const depth = (rs?.height as number) ?? 200 // 3D Z (front → back)\n const cols = comp.columns\n const rows = comp.rackRows\n const shelves = comp.shelves\n const shelfBase = Math.max(0, Math.min((rs?.shelfBaseHeight as number) || 0, height * 0.9))\n const shelfZone = height - shelfBase\n\n const bayW = width / cols\n const bayD = depth / rows\n const baseY = -height / 2\n const shelfBaseY = baseY + shelfBase\n\n // Frame 굵기 — storage-rack 과 동일 비율 (공유 post / 공유 beam 적용 후엔\n // 겹침 없으므로 같은 비율 사용 가능).\n const postW = Math.min(bayW, bayD) * 0.06\n const beamH = postW * 1.2\n\n const isEmpty = (col: number, row: number): boolean => {\n if (col < 0 || col >= cols || row < 0 || row >= rows) return true\n return comp.isBayEmpty(col, row)\n }\n\n // ── 1. 공유 corner posts (hideRackFrame 면 skip) ───────\n //\n // (cols+1) × (rows+1) 의 모든 corner 위치. 4 인접 bay 중 *하나라도 non-empty*\n // 이면 post 생성. 인접 bay 가 모두 empty → post skip.\n\n const postGeos: THREE.BufferGeometry[] = []\n for (let c = 0; c <= cols; c++) {\n for (let r = 0; r <= rows; r++) {\n // 이 corner 에 인접한 4 bay (없는 위치는 isEmpty 처리)\n const anyActive =\n !isEmpty(c - 1, r - 1) ||\n !isEmpty(c, r - 1) ||\n !isEmpty(c - 1, r ) ||\n !isEmpty(c, r )\n if (!anyActive) continue\n\n const x = (c - cols / 2) * bayW\n const z = (r - rows / 2) * bayD\n const post = new THREE.BoxGeometry(postW, height, postW)\n post.translate(x, 0, z)\n postGeos.push(post)\n }\n }\n\n // ── 2. Horizontal beams (X 축 외곽 wall 만 — storage-rack 일관) ────\n //\n // storage-rack 처럼 *front + back 의 X 축 beam* 만. 내부 행 경계 beam +\n // Z 축 (좌우 side) beam 모두 제거 — *깔끔한 wall-frame 시각*.\n // 각 level 마다 front (zEdge=0) + back (zEdge=rows) 두 줄. 각 줄은 *연속\n // non-empty col 구간* 공유 통합.\n\n const beamGeos: THREE.BufferGeometry[] = []\n\n // 외곽 wall 의 가로 frame — *연속 non-empty bay 구간*만. isEmpty bay 영역엔\n // frame 없음. *내부 cross frame 은 항상 제외* — 깔끔함 유지.\n\n // X 축 beam (front + back, 각 level) — non-empty col segment 별 단일 beam\n for (const zEdge of [0, rows]) {\n const zPos = (zEdge - rows / 2) * bayD\n const adjacentRow = zEdge === 0 ? 0 : rows - 1\n for (let lv = 0; lv <= shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n let segStart = -1\n for (let col = 0; col <= cols; col++) {\n const active = col < cols && !isEmpty(col, adjacentRow)\n if (active && segStart === -1) segStart = col\n if (!active && segStart !== -1) {\n const startX = (segStart - cols / 2) * bayW\n const endX = (col - cols / 2) * bayW\n const beamLen = endX - startX\n const beamCenterX = (startX + endX) / 2\n const beam = new THREE.BoxGeometry(beamLen, beamH, beamH)\n beam.translate(beamCenterX, y, zPos)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // Z 축 beam (좌우 side) — *모든 level*, isEmpty row 제외 segment.\n for (const xEdge of [0, cols]) {\n const xPos = (xEdge - cols / 2) * bayW\n const adjacentCol = xEdge === 0 ? 0 : cols - 1\n for (let lv = 0; lv <= shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n let segStart = -1\n for (let row = 0; row <= rows; row++) {\n const active = row < rows && !isEmpty(adjacentCol, row)\n if (active && segStart === -1) segStart = row\n if (!active && segStart !== -1) {\n const startZ = (segStart - rows / 2) * bayD\n const endZ = (row - rows / 2) * bayD\n const beamLen = endZ - startZ\n const beamCenterZ = (startZ + endZ) / 2\n const beam = new THREE.BoxGeometry(beamH, beamH, beamLen)\n beam.translate(xPos, y, beamCenterZ)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // 천장 (lv=shelves) 내부 cross beam — *isEmpty 영역 제외 segment*.\n {\n const lv = shelves\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n\n // 내부 col 경계 의 Z 축 beam (col 사이, Z 방향) — 인접 2 col 중 *해당 row* 가 non-empty\n for (let xEdge = 1; xEdge < cols; xEdge++) {\n const xPos = (xEdge - cols / 2) * bayW\n let segStart = -1\n for (let row = 0; row <= rows; row++) {\n const active = row < rows && (!isEmpty(xEdge - 1, row) || !isEmpty(xEdge, row))\n if (active && segStart === -1) segStart = row\n if (!active && segStart !== -1) {\n const startZ = (segStart - rows / 2) * bayD\n const endZ = (row - rows / 2) * bayD\n const beamLen = endZ - startZ\n const beamCenterZ = (startZ + endZ) / 2\n const beam = new THREE.BoxGeometry(beamH, beamH, beamLen)\n beam.translate(xPos, y, beamCenterZ)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n\n // 내부 row 경계 의 X 축 beam (row 사이, X 방향) — 인접 2 row 중 *해당 col* 가 non-empty\n for (let zEdge = 1; zEdge < rows; zEdge++) {\n const zPos = (zEdge - rows / 2) * bayD\n let segStart = -1\n for (let col = 0; col <= cols; col++) {\n const active = col < cols && (!isEmpty(col, zEdge - 1) || !isEmpty(col, zEdge))\n if (active && segStart === -1) segStart = col\n if (!active && segStart !== -1) {\n const startX = (segStart - cols / 2) * bayW\n const endX = (col - cols / 2) * bayW\n const beamLen = endX - startX\n const beamCenterX = (startX + endX) / 2\n const beam = new THREE.BoxGeometry(beamLen, beamH, beamH)\n beam.translate(beamCenterX, y, zPos)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // ── 3. Shelf planes — *단일 InstancedMesh* (성능). 이전엔 cols × rows × shelves\n // 개별 Mesh (각 draw call) — 큰 grid 에서 수천 draw call. 이제 1 mesh / 1 draw call.\n\n const shelfW = Math.max(0, bayW - 2 * postW)\n const shelfDD = Math.max(0, bayD - 2 * beamH)\n if (shelfW > 0 && shelfDD > 0) {\n const positions: Array<{ x: number; y: number; z: number }> = []\n for (let col = 0; col < cols; col++) {\n for (let row = 0; row < rows; row++) {\n if (isEmpty(col, row)) continue\n const bayCenterX = (col - cols / 2 + 0.5) * bayW\n const bayCenterZ = (row - rows / 2 + 0.5) * bayD\n for (let lv = 0; lv < shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone + (lv === 0 ? beamH : 0)\n positions.push({ x: bayCenterX, y, z: bayCenterZ })\n }\n }\n }\n if (positions.length > 0) {\n const shelfGeo = new THREE.PlaneGeometry(shelfW, shelfDD)\n shelfGeo.rotateX(-Math.PI / 2)\n const shelfMesh = new THREE.InstancedMesh(shelfGeo, SHELF_MATERIAL, positions.length)\n shelfMesh.receiveShadow = true\n shelfMesh.frustumCulled = false\n const m = new THREE.Matrix4()\n const pos = new THREE.Vector3()\n const q = new THREE.Quaternion()\n const s = new THREE.Vector3(1, 1, 1)\n for (let i = 0; i < positions.length; i++) {\n pos.set(positions[i].x, positions[i].y, positions[i].z)\n m.compose(pos, q, s)\n shelfMesh.setMatrixAt(i, m)\n }\n shelfMesh.instanceMatrix.needsUpdate = true\n shelfMesh.computeBoundingSphere()\n this.object3d.add(shelfMesh)\n }\n }\n\n // ── Merge — post + beam ─────────────────────────────────\n\n if (postGeos.length > 0) {\n const merged = BufferGeometryUtils.mergeGeometries(postGeos)\n const mesh = new THREE.Mesh(merged, POST_MATERIAL)\n mesh.castShadow = true\n mesh.receiveShadow = true\n this._frameGroup!.add(mesh)\n }\n\n if (beamGeos.length > 0) {\n const merged = BufferGeometryUtils.mergeGeometries(beamGeos)\n const mesh = new THREE.Mesh(merged, BEAM_MATERIAL)\n mesh.castShadow = true\n mesh.receiveShadow = true\n this._beamGroup!.add(mesh)\n }\n\n // ── 4. Stock InstancedMesh — state.data 의 record + hideEmptyStock 분기 ────\n this.rebuildStockMesh()\n }\n\n // ── Stock visualization ─────────────────────────────────\n\n private _stockMesh?: THREE.InstancedMesh // record 있는 stock (불투명, 색)\n private _emptyStockMesh?: THREE.InstancedMesh // record 없는 stock (반투명 회색)\n\n /** Public — 후속 click 핸들러 사용. */\n get stockMesh(): THREE.InstancedMesh | undefined {\n return this._stockMesh\n }\n\n /**\n * Stock 시각화 (Plan A — InstancedMesh batched).\n * - hideEmptyStock=true : state.data 의 record 있는 cell 만 instance\n * - hideEmptyStock=false : *모든 (non-isEmpty bay) cell × shelf* 에 instance.\n * record 있으면 default 색, 없으면 *백색 반투명*.\n */\n rebuildStockMesh(): void {\n // 기존 두 mesh 모두 제거\n if (this._stockMesh) {\n this.object3d.remove(this._stockMesh)\n this._stockMesh.dispose?.()\n this._stockMesh = undefined\n }\n if (this._emptyStockMesh) {\n this.object3d.remove(this._emptyStockMesh)\n this._emptyStockMesh.dispose?.()\n this._emptyStockMesh = undefined\n }\n\n const comp = this.component as unknown as RackGrid\n const rs: any = comp.state\n const cols = comp.columns\n const rows = comp.rackRows\n const shelves = comp.shelves\n const width = (rs?.width as number) ?? 400\n const height = (rs?.depth as number) ?? 2000\n const depth = (rs?.height as number) ?? 200\n const shelfBase = Math.max(0, Math.min((rs?.shelfBaseHeight as number) || 0, height * 0.9))\n const shelfZone = height - shelfBase\n const bayW = width / cols\n const bayD = depth / rows\n const cellY = shelfZone / shelves\n const baseY = -height / 2\n const shelfBaseY = baseY + shelfBase\n\n const stockW = bayW * 0.85\n const stockD = cellY * 0.7\n const stockH = bayD * 0.85\n\n const records = comp.records\n const recordsByCell = new Map<string, any>()\n for (const r of records) {\n if (r?.cellId) recordsByCell.set(r.cellId, r)\n }\n\n const hideEmpty = !!rs?.hideEmptyStock\n\n // 두 그룹 분리: record 있는 stock (불투명, 색) vs empty stock (반투명 회색)\n const filled: Array<{ col: number; row: number; shelf: number; record: any }> = []\n const empties: Array<{ col: number; row: number; shelf: number }> = []\n\n for (let col = 0; col < cols; col++) {\n for (let row = 0; row < rows; row++) {\n if (comp.isBayEmpty(col, row)) continue\n for (let shelf = 0; shelf < shelves; shelf++) {\n const cellId = `${col}-${row}-${shelf}`\n const record = recordsByCell.get(cellId)\n if (record) {\n filled.push({ col, row, shelf, record })\n } else if (!hideEmpty) {\n empties.push({ col, row, shelf })\n }\n }\n }\n }\n\n const matrixFor = (col: number, row: number, shelf: number, target: THREE.Matrix4) => {\n const cx = (col - cols / 2 + 0.5) * bayW\n const cellBottomY = shelfBaseY + shelf * cellY\n const cy = cellBottomY + stockD / 2\n const cz = (row - rows / 2 + 0.5) * bayD\n target.compose(new THREE.Vector3(cx, cy, cz), new THREE.Quaternion(), new THREE.Vector3(1, 1, 1))\n }\n\n // ── 1. Filled stock — 불투명, legend/default 색 ──────\n if (filled.length > 0) {\n const STOCK_COLOR_DEFAULT = '#c8a878' // cardboard\n const geo = new THREE.BoxGeometry(stockW, stockD, stockH)\n const mesh = new THREE.InstancedMesh(geo, STOCK_MATERIAL, filled.length)\n mesh.frustumCulled = false\n mesh.userData.context = this\n mesh.userData._records = filled.map(i => i.record)\n\n const m = new THREE.Matrix4()\n const c = new THREE.Color()\n for (let i = 0; i < filled.length; i++) {\n const { col, row, shelf, record } = filled[i]\n matrixFor(col, row, shelf, m)\n mesh.setMatrixAt(i, m)\n const resolved = (comp as any).resolveLegendColor?.(record) ?? STOCK_COLOR_DEFAULT\n c.set(resolved)\n mesh.setColorAt(i, c)\n }\n mesh.instanceMatrix.needsUpdate = true\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true\n mesh.computeBoundingSphere()\n mesh.computeBoundingBox?.()\n this.object3d.add(mesh)\n this._stockMesh = mesh\n }\n\n // ── 2. Empty stock — 반투명 회색 (hideEmptyStock=off 시만) ────\n if (empties.length > 0) {\n const geo = new THREE.BoxGeometry(stockW, stockD, stockH)\n const mesh = new THREE.InstancedMesh(geo, EMPTY_STOCK_MATERIAL, empties.length)\n mesh.frustumCulled = false\n mesh.userData.context = this\n\n const m = new THREE.Matrix4()\n for (let i = 0; i < empties.length; i++) {\n const { col, row, shelf } = empties[i]\n matrixFor(col, row, shelf, m)\n mesh.setMatrixAt(i, m)\n }\n mesh.instanceMatrix.needsUpdate = true\n mesh.computeBoundingSphere()\n mesh.computeBoundingBox?.()\n this.object3d.add(mesh)\n this._emptyStockMesh = mesh\n }\n }\n\n dispose() {\n // Material 은 module-level singleton 이라 dispose 안 함 (전체 application\n // lifecycle 동안 살아있음). InstancedMesh / Group 의 geometry 만 정리.\n if (this._stockMesh) {\n this.object3d.remove(this._stockMesh)\n this._stockMesh.dispose?.()\n this._stockMesh = undefined\n }\n if (this._emptyStockMesh) {\n this.object3d.remove(this._emptyStockMesh)\n this._emptyStockMesh.dispose?.()\n this._emptyStockMesh = undefined\n }\n super.dispose()\n }\n\n updateAlpha() {}\n}\n"]}
1
+ {"version":3,"file":"rack-grid-3d.js","sourceRoot":"","sources":["../src/rack-grid-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackGrid3D — *공유 corner posts + bay 별 beams + shelf planes*.\n *\n * Post (수직 기둥):\n * - (cols+1) × (rows+1) 의 grid corner 위치마다 *공유 post* 1 개.\n * - 인접 4 bay 중 *최소 1개 non-empty* 면 post 만듦. 모두 empty 면 skip.\n * - 옆 bay 와 *공유* → 두 post 겹침 X.\n *\n * Beam (수평 부재):\n * - non-empty bay 마다 front + back beam (각 shelf level).\n *\n * Shelf (반투명 판):\n * - non-empty bay 의 각 level 의 frame 안쪽.\n *\n * isEmpty source of truth: RackGrid.isBayEmpty(col, row) — cell.state.isEmpty 우선.\n */\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\nimport type RackGrid from './rack-grid.js'\nimport {\n POST_MATERIAL, BEAM_MATERIAL, SHELF_MATERIAL,\n STOCK_MATERIAL, EMPTY_STOCK_MATERIAL\n} from './rack-materials.js'\n\nexport class RackGrid3D extends RealObjectGroup {\n private _frameGroup?: THREE.Group // post + beam 묶음 (hideRackFrame 시 hidden)\n private _beamGroup?: THREE.Group // beam 만 (hideHorizontalFrame 시 hidden)\n\n build() {\n super.build()\n this._buildFrames()\n this._applyFrameVisibility()\n }\n\n /** hideRackFrame / hideHorizontalFrame 변경 시 visibility 즉시 반영. */\n applyFrameVisibility(): void {\n this._applyFrameVisibility()\n }\n\n private _applyFrameVisibility(): void {\n const rs: any = this.component.state\n const hideFrame = !!rs?.hideRackFrame\n const hideBeams = !!rs?.hideHorizontalFrame\n if (this._frameGroup) this._frameGroup.visible = !hideFrame\n // beam group 은 frame group 안에 nested — frame 이 hidden 일 때는 beam 도 자연히 hidden.\n // frame visible + beam toggle 따로\n if (this._beamGroup) this._beamGroup.visible = !hideBeams\n }\n\n private _buildFrames(): void {\n const comp = this.component as unknown as RackGrid\n const rs: any = comp.state\n // frame group — post + beamGroup 담음. hideRackFrame 시 frame group.visible=false.\n // beam group — 가로 frame 만 (hideHorizontalFrame 시 따로 토글).\n this._frameGroup = new THREE.Group()\n this._beamGroup = new THREE.Group()\n this._frameGroup.add(this._beamGroup)\n this.object3d.add(this._frameGroup)\n\n // ?? 만 쓰면 NaN 통과 — finite + positive 검증 후 default fallback.\n const finite = (v: any, fb: number) =>\n typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : fb\n const width = finite(rs?.width, 400) // 3D X\n const height = finite(rs?.depth, 2000) // 3D Y (floor → ceiling)\n const depth = finite(rs?.height, 200) // 3D Z (front → back)\n const cols = comp.columns\n const rows = comp.rackRows\n const shelves = comp.shelves\n const shelfBase = Math.max(0, Math.min(finite(rs?.shelfBaseHeight, 0), height * 0.9))\n const shelfZone = height - shelfBase\n\n const bayW = width / cols\n const bayD = depth / rows\n const baseY = -height / 2\n const shelfBaseY = baseY + shelfBase\n\n // Frame 굵기 — storage-rack 과 동일 비율 (공유 post / 공유 beam 적용 후엔\n // 겹침 없으므로 같은 비율 사용 가능).\n const postW = Math.min(bayW, bayD) * 0.06\n const beamH = postW * 1.2\n\n const isEmpty = (col: number, row: number): boolean => {\n if (col < 0 || col >= cols || row < 0 || row >= rows) return true\n return comp.isBayEmpty(col, row)\n }\n\n // ── 1. 공유 corner posts (hideRackFrame 면 skip) ───────\n //\n // (cols+1) × (rows+1) 의 모든 corner 위치. 4 인접 bay 중 *하나라도 non-empty*\n // 이면 post 생성. 인접 bay 가 모두 empty → post skip.\n\n const postGeos: THREE.BufferGeometry[] = []\n for (let c = 0; c <= cols; c++) {\n for (let r = 0; r <= rows; r++) {\n // 이 corner 에 인접한 4 bay (없는 위치는 isEmpty 처리)\n const anyActive =\n !isEmpty(c - 1, r - 1) ||\n !isEmpty(c, r - 1) ||\n !isEmpty(c - 1, r ) ||\n !isEmpty(c, r )\n if (!anyActive) continue\n\n const x = (c - cols / 2) * bayW\n const z = (r - rows / 2) * bayD\n const post = new THREE.BoxGeometry(postW, height, postW)\n post.translate(x, 0, z)\n postGeos.push(post)\n }\n }\n\n // ── 2. Horizontal beams (X 축 외곽 wall 만 — storage-rack 일관) ────\n //\n // storage-rack 처럼 *front + back 의 X 축 beam* 만. 내부 행 경계 beam +\n // Z 축 (좌우 side) beam 모두 제거 — *깔끔한 wall-frame 시각*.\n // 각 level 마다 front (zEdge=0) + back (zEdge=rows) 두 줄. 각 줄은 *연속\n // non-empty col 구간* 공유 통합.\n\n const beamGeos: THREE.BufferGeometry[] = []\n\n // 외곽 wall 의 가로 frame — *연속 non-empty bay 구간*만. isEmpty bay 영역엔\n // frame 없음. *내부 cross frame 은 항상 제외* — 깔끔함 유지.\n\n // X 축 beam (front + back, 각 level) — non-empty col segment 별 단일 beam\n for (const zEdge of [0, rows]) {\n const zPos = (zEdge - rows / 2) * bayD\n const adjacentRow = zEdge === 0 ? 0 : rows - 1\n for (let lv = 0; lv <= shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n let segStart = -1\n for (let col = 0; col <= cols; col++) {\n const active = col < cols && !isEmpty(col, adjacentRow)\n if (active && segStart === -1) segStart = col\n if (!active && segStart !== -1) {\n const startX = (segStart - cols / 2) * bayW\n const endX = (col - cols / 2) * bayW\n const beamLen = endX - startX\n const beamCenterX = (startX + endX) / 2\n const beam = new THREE.BoxGeometry(beamLen, beamH, beamH)\n beam.translate(beamCenterX, y, zPos)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // Z 축 beam (좌우 side) — *모든 level*, isEmpty row 제외 segment.\n for (const xEdge of [0, cols]) {\n const xPos = (xEdge - cols / 2) * bayW\n const adjacentCol = xEdge === 0 ? 0 : cols - 1\n for (let lv = 0; lv <= shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n let segStart = -1\n for (let row = 0; row <= rows; row++) {\n const active = row < rows && !isEmpty(adjacentCol, row)\n if (active && segStart === -1) segStart = row\n if (!active && segStart !== -1) {\n const startZ = (segStart - rows / 2) * bayD\n const endZ = (row - rows / 2) * bayD\n const beamLen = endZ - startZ\n const beamCenterZ = (startZ + endZ) / 2\n const beam = new THREE.BoxGeometry(beamH, beamH, beamLen)\n beam.translate(xPos, y, beamCenterZ)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // 천장 (lv=shelves) 내부 cross beam — *isEmpty 영역 제외 segment*.\n {\n const lv = shelves\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone - beamH / 2 + (lv === 0 ? beamH : 0)\n\n // 내부 col 경계 의 Z 축 beam (col 사이, Z 방향) — 인접 2 col 중 *해당 row* 가 non-empty\n for (let xEdge = 1; xEdge < cols; xEdge++) {\n const xPos = (xEdge - cols / 2) * bayW\n let segStart = -1\n for (let row = 0; row <= rows; row++) {\n const active = row < rows && (!isEmpty(xEdge - 1, row) || !isEmpty(xEdge, row))\n if (active && segStart === -1) segStart = row\n if (!active && segStart !== -1) {\n const startZ = (segStart - rows / 2) * bayD\n const endZ = (row - rows / 2) * bayD\n const beamLen = endZ - startZ\n const beamCenterZ = (startZ + endZ) / 2\n const beam = new THREE.BoxGeometry(beamH, beamH, beamLen)\n beam.translate(xPos, y, beamCenterZ)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n\n // 내부 row 경계 의 X 축 beam (row 사이, X 방향) — 인접 2 row 중 *해당 col* 가 non-empty\n for (let zEdge = 1; zEdge < rows; zEdge++) {\n const zPos = (zEdge - rows / 2) * bayD\n let segStart = -1\n for (let col = 0; col <= cols; col++) {\n const active = col < cols && (!isEmpty(col, zEdge - 1) || !isEmpty(col, zEdge))\n if (active && segStart === -1) segStart = col\n if (!active && segStart !== -1) {\n const startX = (segStart - cols / 2) * bayW\n const endX = (col - cols / 2) * bayW\n const beamLen = endX - startX\n const beamCenterX = (startX + endX) / 2\n const beam = new THREE.BoxGeometry(beamLen, beamH, beamH)\n beam.translate(beamCenterX, y, zPos)\n beamGeos.push(beam)\n segStart = -1\n }\n }\n }\n }\n\n // ── 3. Shelf planes — *단일 InstancedMesh* (성능). 이전엔 cols × rows × shelves\n // 개별 Mesh (각 draw call) — 큰 grid 에서 수천 draw call. 이제 1 mesh / 1 draw call.\n\n const shelfW = Math.max(0, bayW - 2 * postW)\n const shelfDD = Math.max(0, bayD - 2 * beamH)\n if (shelfW > 0 && shelfDD > 0) {\n const positions: Array<{ x: number; y: number; z: number }> = []\n for (let col = 0; col < cols; col++) {\n for (let row = 0; row < rows; row++) {\n if (isEmpty(col, row)) continue\n const bayCenterX = (col - cols / 2 + 0.5) * bayW\n const bayCenterZ = (row - rows / 2 + 0.5) * bayD\n for (let lv = 0; lv < shelves; lv++) {\n const yFrac = lv / shelves\n const y = shelfBaseY + yFrac * shelfZone + (lv === 0 ? beamH : 0)\n positions.push({ x: bayCenterX, y, z: bayCenterZ })\n }\n }\n }\n if (positions.length > 0) {\n const shelfGeo = new THREE.PlaneGeometry(shelfW, shelfDD)\n shelfGeo.rotateX(-Math.PI / 2)\n const shelfMesh = new THREE.InstancedMesh(shelfGeo, SHELF_MATERIAL, positions.length)\n shelfMesh.receiveShadow = true\n shelfMesh.frustumCulled = false\n const m = new THREE.Matrix4()\n const pos = new THREE.Vector3()\n const q = new THREE.Quaternion()\n const s = new THREE.Vector3(1, 1, 1)\n for (let i = 0; i < positions.length; i++) {\n pos.set(positions[i].x, positions[i].y, positions[i].z)\n m.compose(pos, q, s)\n shelfMesh.setMatrixAt(i, m)\n }\n shelfMesh.instanceMatrix.needsUpdate = true\n shelfMesh.computeBoundingSphere()\n this.object3d.add(shelfMesh)\n }\n }\n\n // ── Merge — post + beam ─────────────────────────────────\n\n if (postGeos.length > 0) {\n const merged = BufferGeometryUtils.mergeGeometries(postGeos)\n const mesh = new THREE.Mesh(merged, POST_MATERIAL)\n mesh.castShadow = true\n mesh.receiveShadow = true\n this._frameGroup!.add(mesh)\n }\n\n if (beamGeos.length > 0) {\n const merged = BufferGeometryUtils.mergeGeometries(beamGeos)\n const mesh = new THREE.Mesh(merged, BEAM_MATERIAL)\n mesh.castShadow = true\n mesh.receiveShadow = true\n this._beamGroup!.add(mesh)\n }\n\n // ── 4. Stock InstancedMesh — state.data 의 record + hideEmptyStock 분기 ────\n this.rebuildStockMesh()\n }\n\n // ── Stock visualization ─────────────────────────────────\n\n private _stockMesh?: THREE.InstancedMesh // record 있는 stock (불투명, 색)\n private _emptyStockMesh?: THREE.InstancedMesh // record 없는 stock (반투명 회색)\n\n /** Public — 후속 click 핸들러 사용. */\n get stockMesh(): THREE.InstancedMesh | undefined {\n return this._stockMesh\n }\n\n /**\n * Stock 시각화 (Plan A — InstancedMesh batched).\n * - hideEmptyStock=true : state.data 의 record 있는 cell 만 instance\n * - hideEmptyStock=false : *모든 (non-isEmpty bay) cell × shelf* 에 instance.\n * record 있으면 default 색, 없으면 *백색 반투명*.\n */\n rebuildStockMesh(): void {\n // 기존 두 mesh 모두 제거\n if (this._stockMesh) {\n this.object3d.remove(this._stockMesh)\n this._stockMesh.dispose?.()\n this._stockMesh = undefined\n }\n if (this._emptyStockMesh) {\n this.object3d.remove(this._emptyStockMesh)\n this._emptyStockMesh.dispose?.()\n this._emptyStockMesh = undefined\n }\n\n const comp = this.component as unknown as RackGrid\n const rs: any = comp.state\n const cols = comp.columns\n const rows = comp.rackRows\n const shelves = comp.shelves\n // state.width/depth/height 가 NaN 인 경우 — ?? 는 nullish 만 fallback 이라 NaN 통과.\n // 명시적 finite 검증 후 default 사용. NaN BoxGeometry 의 근본 원인.\n const finite = (v: any, fb: number) =>\n typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : fb\n const width = finite(rs?.width, 400)\n const height = finite(rs?.depth, 2000)\n const depth = finite(rs?.height, 200)\n const shelfBase = Math.max(0, Math.min(finite(rs?.shelfBaseHeight, 0), height * 0.9))\n const shelfZone = height - shelfBase\n const bayW = width / cols\n const bayD = depth / rows\n const cellY = shelfZone / shelves\n const baseY = -height / 2\n const shelfBaseY = baseY + shelfBase\n\n const stockW = bayW * 0.85\n const stockD = cellY * 0.7\n const stockH = bayD * 0.85\n\n // 최종 차원이 finite 한지 검증 — accessor + finite() 거쳤어도 *모든 입력이 0* 이거나\n // 예상 못한 경로로 NaN/0 가능성. invalid 시 stock mesh 생성 자체를 skip + 진단 로그.\n if (\n !Number.isFinite(stockW) || stockW <= 0 ||\n !Number.isFinite(stockD) || stockD <= 0 ||\n !Number.isFinite(stockH) || stockH <= 0\n ) {\n console.error('[rack-grid-3d] rebuildStockMesh: invalid stock dims — mesh 생성 skip', {\n stockW, stockD, stockH,\n cols, rows, shelves,\n width, height, depth, shelfBase, shelfZone, cellY, bayW, bayD,\n stateW: rs?.width, stateDepth: rs?.depth, stateH: rs?.height, stateShelfBase: rs?.shelfBaseHeight\n })\n return\n }\n\n const records = comp.records\n const recordsByCell = new Map<string, any>()\n for (const r of records) {\n if (r?.cellId) recordsByCell.set(r.cellId, r)\n }\n\n const hideEmpty = !!rs?.hideEmptyStock\n\n // 두 그룹 분리: record 있는 stock (불투명, 색) vs empty stock (반투명 회색)\n const filled: Array<{ col: number; row: number; shelf: number; record: any }> = []\n const empties: Array<{ col: number; row: number; shelf: number }> = []\n\n for (let col = 0; col < cols; col++) {\n for (let row = 0; row < rows; row++) {\n if (comp.isBayEmpty(col, row)) continue\n for (let shelf = 0; shelf < shelves; shelf++) {\n const cellId = `${col}-${row}-${shelf}`\n const record = recordsByCell.get(cellId)\n if (record) {\n filled.push({ col, row, shelf, record })\n } else if (!hideEmpty) {\n empties.push({ col, row, shelf })\n }\n }\n }\n }\n\n const matrixFor = (col: number, row: number, shelf: number, target: THREE.Matrix4) => {\n const cx = (col - cols / 2 + 0.5) * bayW\n const cellBottomY = shelfBaseY + shelf * cellY\n const cy = cellBottomY + stockD / 2\n const cz = (row - rows / 2 + 0.5) * bayD\n target.compose(new THREE.Vector3(cx, cy, cz), new THREE.Quaternion(), new THREE.Vector3(1, 1, 1))\n }\n\n // ── 1. Filled stock — 불투명, legend/default 색 ──────\n if (filled.length > 0) {\n const STOCK_COLOR_DEFAULT = '#c8a878' // cardboard\n const geo = new THREE.BoxGeometry(stockW, stockD, stockH)\n const mesh = new THREE.InstancedMesh(geo, STOCK_MATERIAL, filled.length)\n mesh.frustumCulled = false\n mesh.userData.context = this\n mesh.userData._records = filled.map(i => i.record)\n\n const m = new THREE.Matrix4()\n const c = new THREE.Color()\n for (let i = 0; i < filled.length; i++) {\n const { col, row, shelf, record } = filled[i]\n matrixFor(col, row, shelf, m)\n mesh.setMatrixAt(i, m)\n const resolved = (comp as any).resolveLegendColor?.(record) ?? STOCK_COLOR_DEFAULT\n c.set(resolved)\n mesh.setColorAt(i, c)\n }\n mesh.instanceMatrix.needsUpdate = true\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true\n mesh.computeBoundingSphere()\n mesh.computeBoundingBox?.()\n this.object3d.add(mesh)\n this._stockMesh = mesh\n }\n\n // ── 2. Empty stock — 반투명 회색 (hideEmptyStock=off 시만) ────\n if (empties.length > 0) {\n const geo = new THREE.BoxGeometry(stockW, stockD, stockH)\n const mesh = new THREE.InstancedMesh(geo, EMPTY_STOCK_MATERIAL, empties.length)\n mesh.frustumCulled = false\n mesh.userData.context = this\n\n const m = new THREE.Matrix4()\n for (let i = 0; i < empties.length; i++) {\n const { col, row, shelf } = empties[i]\n matrixFor(col, row, shelf, m)\n mesh.setMatrixAt(i, m)\n }\n mesh.instanceMatrix.needsUpdate = true\n mesh.computeBoundingSphere()\n mesh.computeBoundingBox?.()\n this.object3d.add(mesh)\n this._emptyStockMesh = mesh\n }\n }\n\n dispose() {\n // Material 은 module-level singleton 이라 dispose 안 함 (전체 application\n // lifecycle 동안 살아있음). InstancedMesh / Group 의 geometry 만 정리.\n if (this._stockMesh) {\n this.object3d.remove(this._stockMesh)\n this._stockMesh.dispose?.()\n this._stockMesh = undefined\n }\n if (this._emptyStockMesh) {\n this.object3d.remove(this._emptyStockMesh)\n this._emptyStockMesh.dispose?.()\n this._emptyStockMesh = undefined\n }\n super.dispose()\n }\n\n updateAlpha() {}\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { Component, ComponentNature, Control, Properties, RealObject } from '@hatiolab/things-scene';
2
2
  import type { State } from '@hatiolab/things-scene';
3
3
  import * as THREE from 'three';
4
- import { SlotTarget, type Alignment, type Heights, type PlacementArchetype, type SlotRecord, type SlottedHolder } from '@operato/scene-base';
4
+ import { SlotTarget, type AttachFrame, type Alignment, type Heights, type PlacementArchetype, type SlotRecord, type SlottedHolder } from '@operato/scene-base';
5
5
  import RackGridCell from './rack-grid-cell.js';
6
6
  /** 한 (col, row) 위치의 메타데이터. 명시되지 않은 위치는 *룰의 기본값* 적용 (= location 없음). */
7
7
  export interface CellOverride {
@@ -73,6 +73,15 @@ export interface RackGridState extends State {
73
73
  declare const RackGrid_base: any;
74
74
  export default class RackGrid extends RackGrid_base implements SlottedHolder {
75
75
  state: RackGridState;
76
+ get isObstacle(): boolean;
77
+ obstacleBoundingBox(): {
78
+ left: number;
79
+ top: number;
80
+ width: number;
81
+ height: number;
82
+ y?: number;
83
+ zHeight?: number;
84
+ } | null;
76
85
  static placement: PlacementArchetype;
77
86
  static align: Alignment;
78
87
  static defaultDepth: (h: Heights) => number;
@@ -150,6 +159,35 @@ export default class RackGrid extends RackGrid_base implements SlottedHolder {
150
159
  * truth, 없으면 cellOverrides[posKey].isEmpty fallback.
151
160
  */
152
161
  isBayEmpty(col: number, row?: number): boolean;
162
+ /**
163
+ * 모든 slot id 의 목록. columns × rackRows × shelves 조합. *isEmpty bay 는 제외*
164
+ * (물리적으로 없는 위치). SlottedHolder.slotIds — capability 기반 enumeration
165
+ * entry point.
166
+ */
167
+ slotIds(): ReadonlyArray<string>;
168
+ /**
169
+ * 점유된 slot 의 id 목록 — state.data record + child *carrier* 둘 다.
170
+ *
171
+ * 중요: RackGridCell (시각 proxy) 의 *state.cellId 는 bayKey ("col-row")
172
+ * 형식* (`_syncChildCellIds` 가 set). slot 의 *full id ("col-row-shelf")* 와
173
+ * 다르다 — RackGridCell 은 *carrier 아닌 시각 proxy* 라 *occupied 카운트
174
+ * 대상 아님*. carriable child (= 실 carrier) 만 sweep.
175
+ *
176
+ * @param filter predicate — 통과하는 slotId 만. sweep 중 즉시 reject.
177
+ */
178
+ occupiedSlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string>;
179
+ /** 비어있는 slot 의 id 목록 — slotIds() - occupiedSlotIds(). isEmpty bay 자동 제외. */
180
+ emptySlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string>;
181
+ /**
182
+ * slot 의 *world position* — anchor object3d *생성 없이* 직접 계산. crane 의
183
+ * reach 검사 같은 *match 전 단계* 에서 *anchor 생성 0* 으로 사용 가능.
184
+ * match 후 *실제 attach* 가 필요할 때 `getSlotAttachObject3d` 가 lazy 생성.
185
+ */
186
+ slotWorldPosition(slotId: string): {
187
+ x: number;
188
+ y: number;
189
+ z: number;
190
+ } | undefined;
153
191
  buildRealObject(): RealObject | undefined;
154
192
  get layout(): any;
155
193
  get widths(): number[];
@@ -165,8 +203,8 @@ export default class RackGrid extends RackGrid_base implements SlottedHolder {
165
203
  /** posKey = `${col-1}-${row-1}` (0-based, 2 segments). 1-based input. */
166
204
  posKeyOf(col: number, row?: number): string;
167
205
  /** cellId = `${col-1}-${row-1}-${shelf-1}` (0-based, 3 segments). 1-based input. */
168
- cellIdOf(col: number, row?: number, shelf?: number): string;
169
- parseCellId(cellId: string): {
206
+ slotIdOf(col: number, row?: number, shelf?: number): string;
207
+ parseSlotId(cellId: string): {
170
208
  col: number;
171
209
  row: number;
172
210
  shelf: number;
@@ -220,18 +258,73 @@ export default class RackGrid extends RackGrid_base implements SlottedHolder {
220
258
  * 자식의 grid 위치 식별: 자식의 state.column / state.row (1-based) 명시. RackGrid 가
221
259
  * 자식 추가 시 자동 할당 또는 사용자가 명시.
222
260
  */
223
- private _childRackAt;
224
- hasCarrierAt(slotId: string): boolean;
261
+ /**
262
+ * cellId 매칭되는 RackGrid 의 직접 자식 carrier (operation archetype).
263
+ * RackGrid 의 자식 중 rack-grid-cell (시각 proxy) 외에 obtainCarrier 가 add 한
264
+ * transient carrier 들이 섞임 — 그 중 cellId / placement='operation' 매칭.
265
+ * storage-rack 의 동일 패턴.
266
+ */
267
+ private _carrierChildAt;
268
+ /**
269
+ * state.data 의 internal 갱신 — obtainCarrier / receiveAt 가 사용.
270
+ * setState 와 달리 'change' / onchangeData / mapping cascade 우회 — 사용자 script
271
+ * 의 자기-자신 호출 회귀 차단. 시각 갱신은 직접 RealObject.rebuildStockMesh 호출.
272
+ * storage-rack 의 동일 패턴.
273
+ */
274
+ private _setDataSilently;
275
+ /** state.data record 또는 이미 transient materialize 된 carrier child 가 있는가. */
276
+ hasCarrierAt(slotIdOrLocation: string): boolean;
277
+ /**
278
+ * carrier 를 obtain — 이미 child 면 그대로, 아니면 state.data record 로 transient
279
+ * materialize 후 RackGrid 의 직접 자식으로 add 하고 state.data 에서 그 record 제거.
280
+ * record 도 child 도 없으면 null.
281
+ */
225
282
  obtainCarrier(slotIdOrLocation: string): Component | null;
283
+ /**
284
+ * cell 이 carrier 를 받을 수 있는가.
285
+ * - isEmpty 위치 는 거부 (modeling 차원 location-less)
286
+ * - state.data 에 record 있으면 점유 → false
287
+ * - 자기 자신 carrier 가 child 면 idempotent true (자기 자리 복귀)
288
+ */
226
289
  canReceiveAt(slotIdOrLocation: string, carrier?: Component): boolean;
227
- receiveAt(slotIdOrLocation: string, carrier: Component, options?: any): Promise<void>;
228
- recordFromCarrier(carrier: Component, slotId: string): SlotRecord;
290
+ /**
291
+ * Carrier RackGrid 의 slot 으로 들어옴 — 즉시 dispose + state.data 에 record 로
292
+ * 환원. 결과: stock InstancedMesh 가 그 자리에 instance 표시, RackGrid 의 자식 트리는
293
+ * 깨끗 (rack-grid-cell 만 남음).
294
+ */
295
+ receiveAt(slotIdOrLocation: string, carrier: Component, _options?: any): Promise<void>;
296
+ /**
297
+ * Carrier 의 state 를 state.data record 로 추출. transform/position 관련은 record
298
+ * 와 무관해 skip. (storage-rack 의 동일 패턴.)
299
+ */
300
+ recordFromCarrier(carrier: Component, cellId: string): SlotRecord;
301
+ /**
302
+ * children gate — CarrierHolder.containable 의 *carriable-only* 제한을 완화.
303
+ * RackGrid 의 자식은 두 종류:
304
+ * - RackGridCell : modeling-time visual proxy (carriable 아님)
305
+ * - carrier : Plan A 의 obtainCarrier 가 materialize (carriable)
306
+ * 둘 다 허용해야 정상 동작.
307
+ */
308
+ containable(component: Component): boolean;
309
+ /**
310
+ * Attach frame for direct-child carrier — `applyHolderAttachPoint` 가 이 결과의
311
+ * `attach` 에 carrier obj3d 를 attach 하고 `localPosition` 을 set. cell anchor
312
+ * 반환 + carried placement 와 함께 동작 — carrier 가 cell 위치에 고정.
313
+ */
314
+ attachPointFor(carrier: Component): AttachFrame | null;
229
315
  /**
230
316
  * Slot 의 attach object3d — Stock InstancedMesh 의 instance 와 *같은 world 위치* 에
231
- * 위치한 invisible Object3D. popup tether / Carriable.applyHolderAttachPoint
232
- * object3d 의 matrixWorld 를 사용. lazy 생성 + cache.
317
+ * 위치한 invisible Object3D. popup tether 등이 object3d 의 matrixWorld 를
318
+ * 사용. lazy 생성 + cache.
319
+ */
320
+ private _attachAnchorBySlot;
321
+ /**
322
+ * Anchor position cache 의 signature — rack 의 차원 state 변경 시 무효화 trigger.
323
+ * 동일 signature 인 동안 *anchor.position.set 재계산 skip*. crane 의 첫
324
+ * findAdjacentSlots 가 *수많은 anchor 의 position.set 매 호출* — *동일 차원
325
+ * state 일 때* 의 *중복 계산 차단*.
233
326
  */
234
- private _attachAnchorByCell;
327
+ private _attachAnchorSig?;
235
328
  getSlotAttachObject3d(slotId: string): THREE.Object3D | undefined;
236
329
  getSlotSize(slotId: string): {
237
330
  width: number;