@operato/scene-storage 10.0.0-beta.41 → 10.0.0-beta.43

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 (85) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/MIGRATION-plan-a-slot-api.md +266 -0
  3. package/PLAN-A-rack-as-slot-holder.md +164 -0
  4. package/dist/crane.js +1 -1
  5. package/dist/crane.js.map +1 -1
  6. package/dist/index.d.ts +3 -4
  7. package/dist/index.js +1 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/parcel-3d.js +42 -9
  10. package/dist/parcel-3d.js.map +1 -1
  11. package/dist/rack-grid-3d.d.ts +18 -7
  12. package/dist/rack-grid-3d.js +372 -69
  13. package/dist/rack-grid-3d.js.map +1 -1
  14. package/dist/rack-grid-cell.d.ts +21 -72
  15. package/dist/rack-grid-cell.js +147 -243
  16. package/dist/rack-grid-cell.js.map +1 -1
  17. package/dist/rack-grid.d.ts +277 -56
  18. package/dist/rack-grid.js +1230 -695
  19. package/dist/rack-grid.js.map +1 -1
  20. package/dist/rack-materials.d.ts +9 -0
  21. package/dist/rack-materials.js +55 -0
  22. package/dist/rack-materials.js.map +1 -0
  23. package/dist/storage-rack-3d.d.ts +15 -0
  24. package/dist/storage-rack-3d.js +131 -30
  25. package/dist/storage-rack-3d.js.map +1 -1
  26. package/dist/storage-rack.d.ts +242 -45
  27. package/dist/storage-rack.js +684 -106
  28. package/dist/storage-rack.js.map +1 -1
  29. package/package.json +3 -3
  30. package/src/crane.ts +1 -1
  31. package/src/index.ts +3 -4
  32. package/src/parcel-3d.ts +41 -9
  33. package/src/rack-grid-3d.ts +383 -80
  34. package/src/rack-grid-cell.ts +161 -305
  35. package/src/rack-grid.ts +1263 -762
  36. package/src/rack-materials.ts +61 -0
  37. package/src/storage-rack-3d.ts +144 -30
  38. package/src/storage-rack.ts +763 -111
  39. package/test/test-carrier-lifecycle.ts +361 -0
  40. package/test/test-coord-alignment.ts +201 -0
  41. package/test/test-external-to-rack.ts +461 -0
  42. package/test/test-mover-concurrent-bug.ts +304 -0
  43. package/test/test-mover-rollback.ts +290 -0
  44. package/test/test-r19-place-absorb.ts +174 -0
  45. package/test/test-rack-3d-attach-real.ts +301 -0
  46. package/test/test-rack-concurrent.ts +254 -0
  47. package/test/test-rack-edge-cases.ts +323 -0
  48. package/test/test-rack-grid-cell.ts +318 -0
  49. package/test/test-rack-grid-location.ts +657 -0
  50. package/test/test-real-3d-positioning.ts +158 -0
  51. package/test/test-slot-center-convention.ts +116 -0
  52. package/test/test-slot-target.ts +189 -0
  53. package/test/test-storage-rack-batched.ts +606 -0
  54. package/test/test-storage-rack-click.ts +329 -0
  55. package/test/test-storage-rack-slot-api.ts +357 -0
  56. package/test/test-toscene-convention.ts +162 -0
  57. package/test/test-user-scenario-sequential.ts +334 -0
  58. package/translations/en.json +2 -0
  59. package/translations/ja.json +2 -0
  60. package/translations/ko.json +2 -0
  61. package/translations/ms.json +2 -0
  62. package/translations/zh.json +2 -0
  63. package/tsconfig.tsbuildinfo +1 -1
  64. package/dist/rack-column.d.ts +0 -35
  65. package/dist/rack-column.js +0 -258
  66. package/dist/rack-column.js.map +0 -1
  67. package/dist/rack-grid-helpers.d.ts +0 -28
  68. package/dist/rack-grid-helpers.js +0 -71
  69. package/dist/rack-grid-helpers.js.map +0 -1
  70. package/dist/rack-grid-location.d.ts +0 -37
  71. package/dist/rack-grid-location.js +0 -227
  72. package/dist/rack-grid-location.js.map +0 -1
  73. package/dist/storage-cell-3d.d.ts +0 -25
  74. package/dist/storage-cell-3d.js +0 -88
  75. package/dist/storage-cell-3d.js.map +0 -1
  76. package/dist/storage-cell.d.ts +0 -73
  77. package/dist/storage-cell.js +0 -215
  78. package/dist/storage-cell.js.map +0 -1
  79. package/src/rack-column.ts +0 -340
  80. package/src/rack-grid-helpers.ts +0 -77
  81. package/src/rack-grid-location.ts +0 -286
  82. package/src/storage-cell-3d.ts +0 -101
  83. package/src/storage-cell.ts +0 -267
  84. package/test/test-cell-position.ts +0 -105
  85. package/test/test-rack-grid.ts +0 -77
@@ -1,227 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * RackGrid location management utilities.
5
- * Extracted from rack-table.ts for separation of concerns.
6
- */
7
- /**
8
- * Classify cells by their row index.
9
- */
10
- export function classifyByRow(cells) {
11
- const classified = [];
12
- cells.forEach(c => {
13
- const { row, column } = c.index;
14
- if (!classified[row]) {
15
- classified[row] = [];
16
- }
17
- classified[row][column] = c;
18
- });
19
- return classified;
20
- }
21
- /**
22
- * Find aisle rows (rows where all cells are empty).
23
- */
24
- export function findAisle(rows) {
25
- if (!rows) {
26
- return [];
27
- }
28
- return rows.filter(r => {
29
- return r[0] && r[0].isAisle;
30
- });
31
- }
32
- /**
33
- * Get indices of aisle rows.
34
- */
35
- export function getAisleRowIndices(rows) {
36
- const aisles = findAisle(rows);
37
- const aisleRowIndices = [];
38
- aisles.forEach(aisle => {
39
- aisleRowIndices.push(rows.indexOf(aisle));
40
- });
41
- return aisleRowIndices;
42
- }
43
- /**
44
- * Classify rows into sections separated by aisle rows.
45
- */
46
- export function classifyCellsBySection(rows, aisleRowIndices) {
47
- const sections = [];
48
- let wasAisle = false;
49
- let section;
50
- rows.forEach((row, i) => {
51
- const isAisle = aisleRowIndices.indexOf(i) > -1;
52
- if (!(wasAisle || isAisle)) {
53
- section = [];
54
- sections.push(section);
55
- }
56
- wasAisle = isAisle;
57
- section.push(row);
58
- });
59
- return sections;
60
- }
61
- /**
62
- * Rearrange cells by aisle direction pattern.
63
- */
64
- export function rearrangeByAisle(type, sections) {
65
- const rearranged = [];
66
- switch (type.toLowerCase()) {
67
- case 'cw': {
68
- let reverse = false;
69
- sections.forEach(rows => {
70
- const section = [];
71
- rearranged.push(section);
72
- rows.forEach((r, i) => {
73
- if (reverse)
74
- r.reverse();
75
- if (i % 2 === 0) {
76
- section.push(r);
77
- reverse = !reverse;
78
- }
79
- });
80
- });
81
- break;
82
- }
83
- case 'ccw': {
84
- let reverse = true;
85
- sections.forEach(rows => {
86
- const section = [];
87
- rearranged.push(section);
88
- rows.forEach((r, i) => {
89
- if (reverse)
90
- r.reverse();
91
- if (i % 2 === 0) {
92
- section.push(r);
93
- reverse = !reverse;
94
- }
95
- });
96
- });
97
- break;
98
- }
99
- case 'zigzag':
100
- sections.forEach(rows => {
101
- const section = [];
102
- rows.forEach((r, i) => {
103
- if (i % 2 === 0) {
104
- section.push(r);
105
- }
106
- });
107
- const sectionLength = section.length;
108
- const tempRow = [];
109
- const tempSection = [];
110
- section.forEach((row, rowIdx) => {
111
- row.forEach((cell, idx) => {
112
- tempRow[rowIdx + idx * section.length] = cell;
113
- });
114
- });
115
- const chunkSize = tempRow.length / sectionLength;
116
- for (let idx = 0; idx < sectionLength; idx++) {
117
- tempSection.push(tempRow.slice(idx * chunkSize, (idx + 1) * chunkSize));
118
- }
119
- rearranged.push(tempSection);
120
- });
121
- break;
122
- case 'zigzag-reverse':
123
- sections.forEach(rows => {
124
- const section = [];
125
- rows.forEach((r, i) => {
126
- if (i % 2 === 0) {
127
- r.reverse();
128
- section.push(r);
129
- }
130
- });
131
- const sectionLength = section.length;
132
- const tempRow = [];
133
- const tempSection = [];
134
- section.forEach((row, rowIdx) => {
135
- row.forEach((cell, idx) => {
136
- tempRow[rowIdx + idx * section.length] = cell;
137
- });
138
- });
139
- const chunkSize = tempRow.length / sectionLength;
140
- for (let idx = 0; idx < sectionLength; idx++) {
141
- tempSection.push(tempRow.slice(idx * chunkSize, (idx + 1) * chunkSize));
142
- }
143
- rearranged.push(tempSection);
144
- });
145
- break;
146
- }
147
- return rearranged;
148
- }
149
- /**
150
- * Remove empty cells from sections.
151
- */
152
- export function removeEmptyCells(sections) {
153
- const newSections = [];
154
- sections.forEach(rows => {
155
- const newRows = [];
156
- newSections.push(newRows);
157
- rows.forEach(row => {
158
- const newRow = [];
159
- newRows.push(newRow);
160
- row.forEach(c => {
161
- if (!c.isEmpty)
162
- newRow.push(c);
163
- });
164
- });
165
- });
166
- return newSections;
167
- }
168
- /**
169
- * Merge section rows into flat arrays.
170
- */
171
- export function mergeRows(sections) {
172
- const merged = [];
173
- sections.forEach(section => {
174
- let newSection = [];
175
- section.forEach(rows => {
176
- let mergedRow = [];
177
- rows.forEach(row => {
178
- mergedRow = mergedRow.concat(row);
179
- });
180
- newSection = newSection.concat(mergedRow);
181
- });
182
- merged.push(newSection);
183
- });
184
- return merged;
185
- }
186
- /**
187
- * Set section/unit location on cells.
188
- */
189
- export function setLocations(sections, startSection, startUnit, sectionDigits, unitDigits) {
190
- let sectionNumber = Number(startSection) || 1;
191
- sections.forEach(section => {
192
- let unitNumber = Number(startUnit) || 1;
193
- section.forEach(c => {
194
- if (!c.isEmpty) {
195
- c.set('section', String(sectionNumber).padStart(sectionDigits, '0'));
196
- c.set('unit', String(unitNumber).padStart(unitDigits, '0'));
197
- }
198
- else {
199
- c.set('section', null);
200
- c.set('unit', null);
201
- }
202
- unitNumber++;
203
- });
204
- sectionNumber++;
205
- });
206
- }
207
- /**
208
- * Run the full location increase flow.
209
- */
210
- export function increaseLocation(selectedCells, type, skipNumbering, startSection, startUnit, sectionDigits, unitDigits) {
211
- // step 1: classify cells by row
212
- const classified = classifyByRow(selectedCells);
213
- // step 2: find aisle row indices
214
- const aisleRowIndices = getAisleRowIndices(classified);
215
- // step 3: classify cells by section
216
- const sections = classifyCellsBySection(classified, aisleRowIndices);
217
- // step 4: rearrange by aisle
218
- let rearranged = rearrangeByAisle(type, sections);
219
- // step 5: if skip numbering, remove empty cells
220
- if (skipNumbering)
221
- rearranged = removeEmptyCells(rearranged);
222
- // step 6: merge rows
223
- const merged = mergeRows(rearranged);
224
- // step 7: set location
225
- setLocations(merged, startSection, startUnit, sectionDigits, unitDigits);
226
- }
227
- //# sourceMappingURL=rack-grid-location.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rack-grid-location.js","sourceRoot":"","sources":["../src/rack-grid-location.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackGrid location management utilities.\n * Extracted from rack-table.ts for separation of concerns.\n */\n\nimport type { RackGridCell } from './rack-grid-cell.js'\n\n/**\n * Classify cells by their row index.\n */\nexport function classifyByRow(cells: RackGridCell[]): RackGridCell[][] {\n const classified: RackGridCell[][] = []\n\n cells.forEach(c => {\n const { row, column } = c.index\n\n if (!classified[row]) {\n classified[row] = []\n }\n\n classified[row][column] = c\n })\n\n return classified\n}\n\n/**\n * Find aisle rows (rows where all cells are empty).\n */\nexport function findAisle(rows?: RackGridCell[][]): RackGridCell[][] {\n if (!rows) {\n return []\n }\n\n return rows.filter(r => {\n return r[0] && r[0].isAisle\n })\n}\n\n/**\n * Get indices of aisle rows.\n */\nexport function getAisleRowIndices(rows: RackGridCell[][]): number[] {\n const aisles = findAisle(rows)\n const aisleRowIndices: number[] = []\n\n aisles.forEach(aisle => {\n aisleRowIndices.push(rows.indexOf(aisle))\n })\n\n return aisleRowIndices\n}\n\n/**\n * Classify rows into sections separated by aisle rows.\n */\nexport function classifyCellsBySection(\n rows: RackGridCell[][],\n aisleRowIndices: number[]\n): RackGridCell[][][] {\n const sections: RackGridCell[][][] = []\n let wasAisle = false\n let section!: RackGridCell[][]\n\n rows.forEach((row, i) => {\n const isAisle = aisleRowIndices.indexOf(i) > -1\n\n if (!(wasAisle || isAisle)) {\n section = []\n sections.push(section)\n }\n\n wasAisle = isAisle\n\n section.push(row)\n })\n\n return sections\n}\n\n/**\n * Rearrange cells by aisle direction pattern.\n */\nexport function rearrangeByAisle(type: string, sections: RackGridCell[][][]): RackGridCell[][][] {\n const rearranged: RackGridCell[][][] = []\n\n switch (type.toLowerCase()) {\n case 'cw': {\n let reverse = false\n sections.forEach(rows => {\n const section: RackGridCell[][] = []\n rearranged.push(section)\n rows.forEach((r, i) => {\n if (reverse) r.reverse()\n\n if (i % 2 === 0) {\n section.push(r)\n reverse = !reverse\n }\n })\n })\n break\n }\n case 'ccw': {\n let reverse = true\n sections.forEach(rows => {\n const section: RackGridCell[][] = []\n rearranged.push(section)\n rows.forEach((r, i) => {\n if (reverse) r.reverse()\n\n if (i % 2 === 0) {\n section.push(r)\n reverse = !reverse\n }\n })\n })\n break\n }\n case 'zigzag':\n sections.forEach(rows => {\n const section: RackGridCell[][] = []\n\n rows.forEach((r, i) => {\n if (i % 2 === 0) {\n section.push(r)\n }\n })\n\n const sectionLength = section.length\n const tempRow: RackGridCell[] = []\n const tempSection: RackGridCell[][] = []\n\n section.forEach((row, rowIdx) => {\n row.forEach((cell, idx) => {\n tempRow[rowIdx + idx * section.length] = cell\n })\n })\n\n const chunkSize = tempRow.length / sectionLength\n for (let idx = 0; idx < sectionLength; idx++) {\n tempSection.push(tempRow.slice(idx * chunkSize, (idx + 1) * chunkSize))\n }\n\n rearranged.push(tempSection)\n })\n break\n case 'zigzag-reverse':\n sections.forEach(rows => {\n const section: RackGridCell[][] = []\n\n rows.forEach((r, i) => {\n if (i % 2 === 0) {\n r.reverse()\n section.push(r)\n }\n })\n\n const sectionLength = section.length\n const tempRow: RackGridCell[] = []\n const tempSection: RackGridCell[][] = []\n\n section.forEach((row, rowIdx) => {\n row.forEach((cell, idx) => {\n tempRow[rowIdx + idx * section.length] = cell\n })\n })\n\n const chunkSize = tempRow.length / sectionLength\n for (let idx = 0; idx < sectionLength; idx++) {\n tempSection.push(tempRow.slice(idx * chunkSize, (idx + 1) * chunkSize))\n }\n\n rearranged.push(tempSection)\n })\n break\n }\n\n return rearranged\n}\n\n/**\n * Remove empty cells from sections.\n */\nexport function removeEmptyCells(sections: RackGridCell[][][]): RackGridCell[][][] {\n const newSections: RackGridCell[][][] = []\n sections.forEach(rows => {\n const newRows: RackGridCell[][] = []\n newSections.push(newRows)\n rows.forEach(row => {\n const newRow: RackGridCell[] = []\n newRows.push(newRow)\n row.forEach(c => {\n if (!c.isEmpty) newRow.push(c)\n })\n })\n })\n\n return newSections\n}\n\n/**\n * Merge section rows into flat arrays.\n */\nexport function mergeRows(sections: RackGridCell[][][]): RackGridCell[][] {\n const merged: RackGridCell[][] = []\n\n sections.forEach(section => {\n let newSection: RackGridCell[] = []\n\n section.forEach(rows => {\n let mergedRow: RackGridCell[] = []\n rows.forEach(row => {\n mergedRow = mergedRow.concat(row)\n })\n newSection = newSection.concat(mergedRow)\n })\n merged.push(newSection)\n })\n\n return merged\n}\n\n/**\n * Set section/unit location on cells.\n */\nexport function setLocations(\n sections: RackGridCell[][],\n startSection: number,\n startUnit: number,\n sectionDigits: number,\n unitDigits: number\n) {\n let sectionNumber = Number(startSection) || 1\n\n sections.forEach(section => {\n let unitNumber = Number(startUnit) || 1\n section.forEach(c => {\n if (!c.isEmpty) {\n c.set('section', String(sectionNumber).padStart(sectionDigits, '0'))\n c.set('unit', String(unitNumber).padStart(unitDigits, '0'))\n } else {\n c.set('section', null)\n c.set('unit', null)\n }\n unitNumber++\n })\n sectionNumber++\n })\n}\n\n/**\n * Run the full location increase flow.\n */\nexport function increaseLocation(\n selectedCells: RackGridCell[],\n type: string,\n skipNumbering: boolean,\n startSection: number,\n startUnit: number,\n sectionDigits: number,\n unitDigits: number\n) {\n // step 1: classify cells by row\n const classified = classifyByRow(selectedCells)\n\n // step 2: find aisle row indices\n const aisleRowIndices = getAisleRowIndices(classified)\n\n // step 3: classify cells by section\n const sections = classifyCellsBySection(classified, aisleRowIndices)\n\n // step 4: rearrange by aisle\n let rearranged = rearrangeByAisle(type, sections)\n\n // step 5: if skip numbering, remove empty cells\n if (skipNumbering) rearranged = removeEmptyCells(rearranged)\n\n // step 6: merge rows\n const merged = mergeRows(rearranged)\n\n // step 7: set location\n setLocations(merged, startSection, startUnit, sectionDigits, unitDigits)\n}\n"]}
@@ -1,25 +0,0 @@
1
- import { RealObjectGroup } from '@hatiolab/things-scene';
2
- export declare class StorageCell3D extends RealObjectGroup {
3
- build(): void;
4
- updateDimension(): void;
5
- updateTransform(): void;
6
- updateAlpha(): void;
7
- /**
8
- * Position this group at the cell's localPosition within the rack's 3D space.
9
- *
10
- * CellMap.grid() places cell origins at:
11
- * x = b * bayWidth, y = l * levelHeight, z = r * rowDepth
12
- * (starting from 0,0,0 at the rack's bottom-left-front corner).
13
- *
14
- * The rack's object3d is centered: X spans [-width/2, +width/2],
15
- * Y spans [-depth/2, +depth/2], Z spans [-height/2, +height/2].
16
- *
17
- * So the cell centre in rack-local 3D space:
18
- * x3d = cellPos.x + bayWidth/2 - width/2
19
- * y3d = cellPos.y + levelHeight/2 - rackDepth/2
20
- * z3d = cellPos.z + rowDepth/2 - rackHeight/2
21
- */
22
- _repositionFromCellMap(): void;
23
- private _debugBox?;
24
- private _addDebugBox;
25
- }
@@ -1,88 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * RackCell 3D — invisible anchor group positioned at the cell's location
5
- * within the parent rack's 3D coordinate space.
6
- *
7
- * RackCell has no geometry of its own. Its sole 3D purpose is to provide
8
- * an Object3D that carriers can be attached to (via Three.js `.attach()`),
9
- * placed at the exact cell position within the rack. The position is derived
10
- * from the parent Rack's CellMap (by cellId), not from 2D state fields —
11
- * rack cells occupy 3D levels that have no 2D analogue.
12
- *
13
- * updateTransform() override: things-scene's standard updateTransform
14
- * reads `component.center` (2D) and flattens it to 3D. For rack cells this
15
- * is wrong — we need the 3D cell position (bay x, level y, row z) from the
16
- * parent rack. So we override and read it directly from the CellMap.
17
- */
18
- import * as THREE from 'three';
19
- import { RealObjectGroup } from '@hatiolab/things-scene';
20
- export class StorageCell3D extends RealObjectGroup {
21
- build() {
22
- super.build();
23
- this._repositionFromCellMap();
24
- }
25
- updateDimension() {
26
- // intentional no-op — size comes from the cell definition, not state
27
- }
28
- updateTransform() {
29
- this._repositionFromCellMap();
30
- }
31
- updateAlpha() {
32
- // invisible — no materials to update
33
- }
34
- /**
35
- * Position this group at the cell's localPosition within the rack's 3D space.
36
- *
37
- * CellMap.grid() places cell origins at:
38
- * x = b * bayWidth, y = l * levelHeight, z = r * rowDepth
39
- * (starting from 0,0,0 at the rack's bottom-left-front corner).
40
- *
41
- * The rack's object3d is centered: X spans [-width/2, +width/2],
42
- * Y spans [-depth/2, +depth/2], Z spans [-height/2, +height/2].
43
- *
44
- * So the cell centre in rack-local 3D space:
45
- * x3d = cellPos.x + bayWidth/2 - width/2
46
- * y3d = cellPos.y + levelHeight/2 - rackDepth/2
47
- * z3d = cellPos.z + rowDepth/2 - rackHeight/2
48
- */
49
- _repositionFromCellMap() {
50
- const rack = this.component.parent;
51
- if (!rack?.cellMap)
52
- return;
53
- const cellId = this.component.state.cellId;
54
- if (!cellId)
55
- return;
56
- const cell = rack.cellMap.findById(cellId);
57
- if (!cell)
58
- return;
59
- const rs = rack.state;
60
- const rackWidth = rs?.width || 1000;
61
- const rackDepth = rs?.depth || 3000; // Y dimension (floor→ceiling)
62
- const rackHeight = rs?.height || 600; // Z dimension (front→back, 2D height)
63
- const bays = Math.max(1, Math.floor(rs?.bays || 5));
64
- const levels = Math.max(1, Math.floor(rs?.levels || 4));
65
- const rows = 1;
66
- const bayWidth = rackWidth / bays;
67
- const levelHeight = rackDepth / levels;
68
- const rowDepth = rackHeight / rows;
69
- const x3d = cell.localPosition.x + bayWidth / 2 - rackWidth / 2;
70
- const y3d = cell.localPosition.y + levelHeight / 2 - rackDepth / 2;
71
- const z3d = cell.localPosition.z + rowDepth / 2 - rackHeight / 2;
72
- this.object3d.position.set(x3d, y3d, z3d);
73
- // Optionally visualise cells in debug mode (outline box, very faint)
74
- if (process.env.NODE_ENV !== 'production' && rack.state?.debugCells) {
75
- this._addDebugBox(bayWidth, levelHeight, rowDepth);
76
- }
77
- }
78
- _debugBox;
79
- _addDebugBox(w, h, d) {
80
- if (this._debugBox)
81
- return;
82
- const geo = new THREE.BoxGeometry(w * 0.98, h * 0.98, d * 0.98);
83
- const edges = new THREE.EdgesGeometry(geo);
84
- this._debugBox = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x00ff88, transparent: true, opacity: 0.2 }));
85
- this.object3d.add(this._debugBox);
86
- }
87
- }
88
- //# sourceMappingURL=storage-cell-3d.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-cell-3d.js","sourceRoot":"","sources":["../src/storage-cell-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackCell 3D — invisible anchor group positioned at the cell's location\n * within the parent rack's 3D coordinate space.\n *\n * RackCell has no geometry of its own. Its sole 3D purpose is to provide\n * an Object3D that carriers can be attached to (via Three.js `.attach()`),\n * placed at the exact cell position within the rack. The position is derived\n * from the parent Rack's CellMap (by cellId), not from 2D state fields —\n * rack cells occupy 3D levels that have no 2D analogue.\n *\n * updateTransform() override: things-scene's standard updateTransform\n * reads `component.center` (2D) and flattens it to 3D. For rack cells this\n * is wrong — we need the 3D cell position (bay x, level y, row z) from the\n * parent rack. So we override and read it directly from the CellMap.\n */\n\nimport * as THREE from 'three'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nexport class StorageCell3D extends RealObjectGroup {\n build() {\n super.build()\n this._repositionFromCellMap()\n }\n\n updateDimension() {\n // intentional no-op — size comes from the cell definition, not state\n }\n\n updateTransform() {\n this._repositionFromCellMap()\n }\n\n updateAlpha() {\n // invisible — no materials to update\n }\n\n /**\n * Position this group at the cell's localPosition within the rack's 3D space.\n *\n * CellMap.grid() places cell origins at:\n * x = b * bayWidth, y = l * levelHeight, z = r * rowDepth\n * (starting from 0,0,0 at the rack's bottom-left-front corner).\n *\n * The rack's object3d is centered: X spans [-width/2, +width/2],\n * Y spans [-depth/2, +depth/2], Z spans [-height/2, +height/2].\n *\n * So the cell centre in rack-local 3D space:\n * x3d = cellPos.x + bayWidth/2 - width/2\n * y3d = cellPos.y + levelHeight/2 - rackDepth/2\n * z3d = cellPos.z + rowDepth/2 - rackHeight/2\n */\n _repositionFromCellMap() {\n const rack = (this.component as any).parent\n if (!rack?.cellMap) return\n\n const cellId = this.component.state.cellId as string | undefined\n if (!cellId) return\n\n const cell = rack.cellMap.findById(cellId)\n if (!cell) return\n\n const rs = rack.state as any\n const rackWidth = (rs?.width as number) || 1000\n const rackDepth = (rs?.depth as number) || 3000 // Y dimension (floor→ceiling)\n const rackHeight = (rs?.height as number) || 600 // Z dimension (front→back, 2D height)\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const rows = 1\n\n const bayWidth = rackWidth / bays\n const levelHeight = rackDepth / levels\n const rowDepth = rackHeight / rows\n\n const x3d = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y3d = cell.localPosition.y + levelHeight / 2 - rackDepth / 2\n const z3d = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n\n this.object3d.position.set(x3d, y3d, z3d)\n\n // Optionally visualise cells in debug mode (outline box, very faint)\n if (process.env.NODE_ENV !== 'production' && (rack.state as any)?.debugCells) {\n this._addDebugBox(bayWidth, levelHeight, rowDepth)\n }\n }\n\n private _debugBox?: THREE.LineSegments\n\n private _addDebugBox(w: number, h: number, d: number) {\n if (this._debugBox) return\n const geo = new THREE.BoxGeometry(w * 0.98, h * 0.98, d * 0.98)\n const edges = new THREE.EdgesGeometry(geo)\n this._debugBox = new THREE.LineSegments(\n edges,\n new THREE.LineBasicMaterial({ color: 0x00ff88, transparent: true, opacity: 0.2 })\n )\n this.object3d.add(this._debugBox)\n }\n}\n"]}
@@ -1,73 +0,0 @@
1
- import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
2
- import type { State, Material3D } from '@hatiolab/things-scene';
3
- import { type AttachFrame } from '@operato/scene-base';
4
- /**
5
- * How many carriers a cell can hold simultaneously.
6
- * - single: exactly 1 (typical pallet bay)
7
- * - multi: small stack (up to 4, e.g. a multi-deep tray)
8
- * - bulk: unlimited (e.g. a floor area measured in slots)
9
- */
10
- export type StorageCellType = 'single' | 'multi' | 'bulk';
11
- /** RackCell 컴포넌트 state */
12
- export interface StorageCellState extends State {
13
- cellId?: string;
14
- cellType?: StorageCellType;
15
- /**
16
- * 자동 할당된 location ID — RackTable.assignLocations() 가 set. 외부 시스템
17
- * (WMS, picker 명령 등) 이 cell 을 지칭하는 사람-친화 ID. RackTable 없이
18
- * 단독으로 Rack 을 사용할 땐 unset.
19
- */
20
- locationId?: string;
21
- material3d?: Material3D;
22
- }
23
- declare const RackCell_base: any;
24
- /**
25
- * RackCell — single-slot storage cell inside an Rack.
26
- *
27
- * Mixin chain: CarrierHolder(ContainerAbstract)
28
- * - CarrierHolder: publishes attachPointFor(), gates containable() to Carriables
29
- * - ContainerAbstract: manages child carrier components
30
- *
31
- * No Placeable mixin — RackCell3D self-positions from the parent rack's
32
- * CellMap (via updateTransform override), bypassing things-scene's standard
33
- * 2D→3D coordinate mapping which cannot express 3D levels.
34
- */
35
- export default class RackCell extends RackCell_base {
36
- state: StorageCellState;
37
- get cellId(): string;
38
- get cellType(): StorageCellType;
39
- /** Maximum carrier count for this cell based on cellType. */
40
- get capacity(): number;
41
- get nature(): ComponentNature;
42
- get anchors(): [];
43
- /** True when fewer carriers are currently held than capacity. */
44
- canReceive(_component?: any): boolean;
45
- /**
46
- * Accept a carrier into this cell.
47
- * Sets TRANSFER_SLOT_KEY = cellId on the carrier, then reparents.
48
- * Fires 'transfer-received' so monitors can react.
49
- */
50
- receive(carrier: any, options?: any): Promise<void>;
51
- /**
52
- * Release a carrier from this cell to `target`.
53
- * Delegates to `target.receive()` if available, otherwise `target.reparent()`.
54
- */
55
- dispatch(carrier: any, target: any, options?: any): Promise<void>;
56
- /** Alias for receive() — semantic sugar for the storage domain. */
57
- store(carrier: any, options?: any): Promise<void>;
58
- /** Alias for dispatch() — semantic sugar for the storage domain. */
59
- retrieve(carrier: any, target: any, options?: any): Promise<void>;
60
- /**
61
- * Return the 3D attach frame for carriers placed in this cell.
62
- *
63
- * Center-origin convention: cell 의 *local origin* 은 cell 의 center
64
- * (= levelHeight/2 above the shelf beam). carrier 의 *bottom face* 가 cell
65
- * 의 *bottom* (= local Y -cellDepth/2) 에 닿도록 carrier center =
66
- * -cellDepth/2 + carrierDepth/2.
67
- */
68
- attachPointFor(carrier: Component): AttachFrame | null;
69
- /** RackCell has no 2D visual — the rack draws its own structure. */
70
- render(_ctx: CanvasRenderingContext2D): void;
71
- buildRealObject(): RealObject | undefined;
72
- }
73
- export {};
@@ -1,215 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * RackCell — a single storage slot within an Rack.
5
- *
6
- * A RackCell is a virtual component: it occupies a specific (bay, row, level)
7
- * coordinate within the parent rack and acts as a CarrierHolder for one carrier
8
- * (or several, depending on `cellType`).
9
- *
10
- * The crane (or any picker) navigates toward a RackCell as its `place()` destination —
11
- * because the rack cell is a discrete component, Mover.moveTo() can target it
12
- * directly and arrive at exactly the right bay × level position.
13
- *
14
- * Visual: invisible in 2D (no visible 2D footprint — rack cells don't make
15
- * sense as 2D top-down boxes). In 3D, each cell is an invisible Group
16
- * positioned within the rack's coordinate space (RackCell3D handles
17
- * this via updateTransform override).
18
- *
19
- * Lifecycle: Rack._buildCells() instantiates RackCell children.
20
- * Do not create RackCell components manually — they are managed by the rack.
21
- *
22
- * Domain aliases:
23
- * cell.store(carrier) ← cell.receive(carrier)
24
- * cell.retrieve(carrier, target) ← cell.dispatch(carrier, target)
25
- */
26
- import { __decorate } from "tslib";
27
- import { ContainerAbstract, TRANSFER_SLOT_KEY, sceneComponent } from '@hatiolab/things-scene';
28
- import { CarrierHolder } from '@operato/scene-base';
29
- import { StorageCell3D } from './storage-cell-3d.js';
30
- const NATURE = {
31
- mutable: false,
32
- resizable: false,
33
- rotatable: false,
34
- properties: [
35
- {
36
- type: 'string',
37
- label: 'cell-id',
38
- name: 'cellId',
39
- placeholder: 'e.g. 0-0-0'
40
- },
41
- {
42
- type: 'select',
43
- label: 'cell-type',
44
- name: 'cellType',
45
- property: {
46
- options: [
47
- { display: 'Single', value: 'single' },
48
- { display: 'Multi', value: 'multi' },
49
- { display: 'Bulk', value: 'bulk' }
50
- ]
51
- }
52
- }
53
- ],
54
- help: 'scene/component/storage-cell'
55
- };
56
- /**
57
- * RackCell — single-slot storage cell inside an Rack.
58
- *
59
- * Mixin chain: CarrierHolder(ContainerAbstract)
60
- * - CarrierHolder: publishes attachPointFor(), gates containable() to Carriables
61
- * - ContainerAbstract: manages child carrier components
62
- *
63
- * No Placeable mixin — RackCell3D self-positions from the parent rack's
64
- * CellMap (via updateTransform override), bypassing things-scene's standard
65
- * 2D→3D coordinate mapping which cannot express 3D levels.
66
- */
67
- let RackCell = class RackCell extends CarrierHolder(ContainerAbstract) {
68
- // ── Identification ────────────────────────────────────────────────────────
69
- get cellId() {
70
- return this.state.cellId ?? '';
71
- }
72
- get cellType() {
73
- return this.state.cellType ?? 'single';
74
- }
75
- /** Maximum carrier count for this cell based on cellType. */
76
- get capacity() {
77
- switch (this.cellType) {
78
- case 'single': return 1;
79
- case 'multi': return 4;
80
- case 'bulk': return Infinity;
81
- }
82
- }
83
- // ── Interface ─────────────────────────────────────────────────────────────
84
- get nature() {
85
- return NATURE;
86
- }
87
- get anchors() {
88
- return [];
89
- }
90
- // ── Transfer protocol ─────────────────────────────────────────────────────
91
- /** True when fewer carriers are currently held than capacity. */
92
- canReceive(_component) {
93
- const occupied = this.components?.length ?? 0;
94
- return occupied < this.capacity;
95
- }
96
- /**
97
- * Accept a carrier into this cell.
98
- * Sets TRANSFER_SLOT_KEY = cellId on the carrier, then reparents.
99
- * Fires 'transfer-received' so monitors can react.
100
- */
101
- async receive(carrier, options = {}) {
102
- if (!this.canReceive(carrier)) {
103
- this.trigger('transfer-rejected', {
104
- type: 'transfer-rejected',
105
- component: carrier,
106
- container: this,
107
- reason: 'no-slot'
108
- });
109
- return;
110
- }
111
- carrier[TRANSFER_SLOT_KEY] = this.cellId;
112
- this.reparent(carrier, options);
113
- // carrier.state.left/top/zPos 을 *cell-local center* 로 명시. 이전 holder
114
- // 의 state (예: crane-local center) 가 그대로 남으면 *다음 pick 시
115
- // moveTo(carrier) 의 target.center 계산이 *잘못된 좌표* 로 → 엉뚱한 위치
116
- // 이동 결함. transient placement 'carried' 라 3D obj3d.position 영향 X,
117
- // 2D render 와 moveTo 의 center 계산에만 영향.
118
- const cw = numOr(this.state?.width, 0);
119
- const ch = numOr(this.state?.height, 0);
120
- const carrierW = numOr(carrier?.state?.width, 0);
121
- const carrierH = numOr(carrier?.state?.height, 0);
122
- carrier.setState?.({
123
- left: (cw - carrierW) / 2,
124
- top: (ch - carrierH) / 2,
125
- zPos: 0
126
- });
127
- this.trigger('transfer-received', {
128
- type: 'transfer-received',
129
- component: carrier,
130
- container: this,
131
- slotId: this.cellId
132
- });
133
- }
134
- /**
135
- * Release a carrier from this cell to `target`.
136
- * Delegates to `target.receive()` if available, otherwise `target.reparent()`.
137
- */
138
- async dispatch(carrier, target, options = {}) {
139
- if (target?.canReceive && !target.canReceive(carrier)) {
140
- this.trigger('transfer-rejected', {
141
- type: 'transfer-rejected',
142
- component: carrier,
143
- container: this,
144
- reason: 'target-full'
145
- });
146
- return;
147
- }
148
- delete carrier[TRANSFER_SLOT_KEY];
149
- if (typeof target?.receive === 'function') {
150
- await target.receive(carrier, options);
151
- }
152
- else {
153
- ;
154
- target.reparent?.(carrier, options);
155
- }
156
- this.trigger('transfer-dispatched', {
157
- type: 'transfer-dispatched',
158
- component: carrier,
159
- container: this,
160
- target
161
- });
162
- }
163
- // ── Domain aliases ────────────────────────────────────────────────────────
164
- /** Alias for receive() — semantic sugar for the storage domain. */
165
- store(carrier, options) {
166
- return this.receive(carrier, options);
167
- }
168
- /** Alias for dispatch() — semantic sugar for the storage domain. */
169
- retrieve(carrier, target, options) {
170
- return this.dispatch(carrier, target, options);
171
- }
172
- // ── 3D attach frame ───────────────────────────────────────────────────────
173
- /**
174
- * Return the 3D attach frame for carriers placed in this cell.
175
- *
176
- * Center-origin convention: cell 의 *local origin* 은 cell 의 center
177
- * (= levelHeight/2 above the shelf beam). carrier 의 *bottom face* 가 cell
178
- * 의 *bottom* (= local Y -cellDepth/2) 에 닿도록 carrier center =
179
- * -cellDepth/2 + carrierDepth/2.
180
- */
181
- attachPointFor(carrier) {
182
- const root = this._realObject?.object3d;
183
- if (!root)
184
- return null;
185
- const carrierDepth = resolveCarrierDepth(carrier);
186
- const cellDepth = numOr(this.state?.depth, 0);
187
- return {
188
- attach: root,
189
- localPosition: { x: 0, y: -cellDepth / 2 + carrierDepth / 2, z: 0 }
190
- };
191
- }
192
- // ── 2D rendering ──────────────────────────────────────────────────────────
193
- /** RackCell has no 2D visual — the rack draws its own structure. */
194
- render(_ctx) {
195
- // intentional no-op
196
- }
197
- // ── 3D ───────────────────────────────────────────────────────────────────
198
- buildRealObject() {
199
- return new StorageCell3D(this);
200
- }
201
- };
202
- RackCell = __decorate([
203
- sceneComponent('storage-cell')
204
- ], RackCell);
205
- export default RackCell;
206
- function resolveCarrierDepth(c) {
207
- const eff = c._realObject?.effectiveDepth;
208
- if (typeof eff === 'number' && Number.isFinite(eff))
209
- return eff;
210
- return numOr(c?.state?.depth, 0);
211
- }
212
- function numOr(v, dflt) {
213
- return typeof v === 'number' && Number.isFinite(v) ? v : dflt;
214
- }
215
- //# sourceMappingURL=storage-cell.js.map