@gridspace/raster-path 1.0.2 → 1.0.4
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/README.md +3 -5
- package/build/app.js +363 -39
- package/build/index.html +39 -1
- package/build/raster-path.js +13 -13
- package/build/style.css +65 -0
- package/build/webgpu-worker.js +475 -686
- package/package.json +7 -4
- package/scripts/build-shaders.js +1 -1
- package/src/etc/serve.json +12 -0
- package/src/index.js +13 -13
- package/src/shaders/{radial-raster-v2.wgsl → radial-raster.wgsl} +8 -2
- package/src/test/batch-divisor-benchmark.cjs +286 -0
- package/src/test/lathe-cylinder-2-debug.cjs +334 -0
- package/src/test/lathe-cylinder-2-test.cjs +157 -0
- package/src/test/lathe-cylinder-test.cjs +198 -0
- package/src/test/planar-test.cjs +253 -0
- package/src/test/planar-tiling-test.cjs +230 -0
- package/src/test/radial-test.cjs +269 -0
- package/src/test/work-estimation-profile.cjs +406 -0
- package/src/test/workload-calculator-demo.cjs +113 -0
- package/src/test/workload-calibration.cjs +310 -0
- package/src/web/app.js +363 -39
- package/src/web/index.html +130 -0
- package/src/web/style.css +223 -0
- package/src/web/webgpu-worker.js +470 -687
- package/src/workload-calculator.js +318 -0
package/build/index.html
CHANGED
|
@@ -8,7 +8,45 @@
|
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<div id="container">
|
|
11
|
-
<!--
|
|
11
|
+
<!-- Left Panel - Model Manipulation -->
|
|
12
|
+
<div class="model-controls">
|
|
13
|
+
<div class="section">
|
|
14
|
+
<h3>Model Rotation</h3>
|
|
15
|
+
<div class="rotation-controls">
|
|
16
|
+
<div class="rotation-row">
|
|
17
|
+
<span class="rotation-label">X:</span>
|
|
18
|
+
<button class="rotate-btn" data-axis="x" data-dir="-1">-90°</button>
|
|
19
|
+
<button class="rotate-btn" data-axis="x" data-dir="1">+90°</button>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="rotation-row">
|
|
22
|
+
<span class="rotation-label">Y:</span>
|
|
23
|
+
<button class="rotate-btn" data-axis="y" data-dir="-1">-90°</button>
|
|
24
|
+
<button class="rotate-btn" data-axis="y" data-dir="1">+90°</button>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="rotation-row">
|
|
27
|
+
<span class="rotation-label">Z:</span>
|
|
28
|
+
<button class="rotate-btn" data-axis="z" data-dir="-1">-90°</button>
|
|
29
|
+
<button class="rotate-btn" data-axis="z" data-dir="1">+90°</button>
|
|
30
|
+
</div>
|
|
31
|
+
<button id="reset-rotation" class="btn btn-small">Reset</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="section">
|
|
36
|
+
<h3>Tool Size</h3>
|
|
37
|
+
<select id="tool-size">
|
|
38
|
+
<option value="1.0">1.0mm</option>
|
|
39
|
+
<option value="2.0">2.0mm</option>
|
|
40
|
+
<option value="2.5" selected>2.5mm</option>
|
|
41
|
+
<option value="3.0">3.0mm</option>
|
|
42
|
+
<option value="4.0">4.0mm</option>
|
|
43
|
+
<option value="5.0">5.0mm</option>
|
|
44
|
+
</select>
|
|
45
|
+
<div id="tool-size-status" class="status">No tool loaded</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- Right Panel - Controls -->
|
|
12
50
|
<div class="controls">
|
|
13
51
|
<div class="section">
|
|
14
52
|
<h3>Mode</h3>
|
package/build/raster-path.js
CHANGED
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
* @property {number} resolution - Grid step size in mm (required)
|
|
56
56
|
* @property {number} rotationStep - Radial mode only: degrees between rays (e.g., 1.0 = 360 rays)
|
|
57
57
|
* @property {number} trianglesPerTile - Target triangles per tile for radial rasterization (default: calculated)
|
|
58
|
+
* @property {number} batchDivisor - Testing parameter to artificially divide batch size (default: 1)
|
|
58
59
|
* @property {boolean} debug - Enable debug logging (default: false)
|
|
59
60
|
* @property {boolean} quiet - Suppress log output (default: false)
|
|
60
61
|
*/
|
|
@@ -103,18 +104,13 @@ export class RasterPath {
|
|
|
103
104
|
this.deviceCapabilities = null;
|
|
104
105
|
|
|
105
106
|
// Configure debug output
|
|
106
|
-
let urlOpt = [];
|
|
107
107
|
if (config.quiet) {
|
|
108
108
|
debug.log = function() {};
|
|
109
|
-
urlOpt.push('quiet');
|
|
110
|
-
}
|
|
111
|
-
if (config.debug) {
|
|
112
|
-
urlOpt.push('debug');
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
// Configuration with defaults
|
|
116
112
|
this.config = {
|
|
117
|
-
workerName:
|
|
113
|
+
workerName: config.workerName ?? "webgpu-worker.js",
|
|
118
114
|
maxGPUMemoryMB: config.maxGPUMemoryMB ?? 256,
|
|
119
115
|
gpuMemorySafetyMargin: config.gpuMemorySafetyMargin ?? 0.8,
|
|
120
116
|
autoTiling: config.autoTiling ?? true,
|
|
@@ -122,7 +118,12 @@ export class RasterPath {
|
|
|
122
118
|
maxConcurrentTiles: config.maxConcurrentTiles ?? 10,
|
|
123
119
|
trianglesPerTile: config.trianglesPerTile, // undefined = auto-calculate
|
|
124
120
|
radialRotationOffset: config.radialRotationOffset ?? 0, // degrees
|
|
121
|
+
batchDivisor: config.batchDivisor ?? 1, // For testing batching overhead
|
|
122
|
+
debug: config.debug,
|
|
123
|
+
quiet: config.quiet
|
|
125
124
|
};
|
|
125
|
+
|
|
126
|
+
debug.log('config', this.config);
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
@@ -238,8 +239,8 @@ export class RasterPath {
|
|
|
238
239
|
const originalBounds = boundsOverride || this.#calculateBounds(triangles);
|
|
239
240
|
|
|
240
241
|
// Center model in YZ plane (required for radial rasterization)
|
|
241
|
-
// Radial mode casts rays from
|
|
242
|
-
//
|
|
242
|
+
// Radial mode casts rays from max_radius distance inward toward the X-axis,
|
|
243
|
+
// and centering ensures the geometry is symmetric around the rotation axis
|
|
243
244
|
const centerY = (originalBounds.min.y + originalBounds.max.y) / 2;
|
|
244
245
|
const centerZ = (originalBounds.min.z + originalBounds.max.z) / 2;
|
|
245
246
|
|
|
@@ -273,12 +274,10 @@ export class RasterPath {
|
|
|
273
274
|
* @param {number} params.xStep - Sample every Nth point in X direction
|
|
274
275
|
* @param {number} params.yStep - Sample every Nth point in Y direction
|
|
275
276
|
* @param {number} params.zFloor - Z floor value for out-of-bounds areas
|
|
276
|
-
* @param {number} params.radiusOffset - (Radial mode only) Distance from terrain surface to tool tip in mm.
|
|
277
|
-
* Used to calculate radial collision offset. Default: 20mm
|
|
278
277
|
* @param {function} params.onProgress - Optional progress callback (progress: number, info?: string) => void
|
|
279
278
|
* @returns {Promise<object>} Planar: {pathData, width, height} | Radial: {strips[], numStrips, totalPoints}
|
|
280
279
|
*/
|
|
281
|
-
async generateToolpaths({ xStep, yStep, zFloor,
|
|
280
|
+
async generateToolpaths({ xStep, yStep, zFloor, onProgress }) {
|
|
282
281
|
if (!this.isInitialized) {
|
|
283
282
|
throw new Error('RasterPath not initialized. Call init() first.');
|
|
284
283
|
}
|
|
@@ -287,6 +286,8 @@ export class RasterPath {
|
|
|
287
286
|
throw new Error('Tool not loaded. Call loadTool() first.');
|
|
288
287
|
}
|
|
289
288
|
|
|
289
|
+
debug.log('gen.paths', { xStep, yStep, zFloor });
|
|
290
|
+
|
|
290
291
|
if (this.mode === 'planar') {
|
|
291
292
|
if (!this.terrainData) {
|
|
292
293
|
throw new Error('Terrain not loaded. Call loadTerrain() first.');
|
|
@@ -444,8 +445,7 @@ export class RasterPath {
|
|
|
444
445
|
zFloor: zFloor,
|
|
445
446
|
bounds,
|
|
446
447
|
xStep,
|
|
447
|
-
yStep
|
|
448
|
-
gridStep: this.resolution
|
|
448
|
+
yStep
|
|
449
449
|
},
|
|
450
450
|
'radial-toolpaths-complete',
|
|
451
451
|
completionHandler
|
package/build/style.css
CHANGED
|
@@ -23,10 +23,26 @@ body {
|
|
|
23
23
|
height: 100%;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
.model-controls {
|
|
27
|
+
position: absolute;
|
|
28
|
+
top: 20px;
|
|
29
|
+
left: 20px;
|
|
30
|
+
background: rgba(0, 0, 0, 0.85);
|
|
31
|
+
backdrop-filter: blur(10px);
|
|
32
|
+
border: 1px solid #333;
|
|
33
|
+
border-radius: 8px;
|
|
34
|
+
padding: 20px;
|
|
35
|
+
min-width: 200px;
|
|
36
|
+
max-width: 240px;
|
|
37
|
+
z-index: 100;
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
.controls {
|
|
27
41
|
position: absolute;
|
|
28
42
|
top: 20px;
|
|
29
43
|
right: 20px;
|
|
44
|
+
bottom: 20px;
|
|
45
|
+
overflow-y: auto;
|
|
30
46
|
background: rgba(0, 0, 0, 0.85);
|
|
31
47
|
backdrop-filter: blur(10px);
|
|
32
48
|
border: 1px solid #333;
|
|
@@ -156,3 +172,52 @@ input[type="checkbox"] {
|
|
|
156
172
|
.hide {
|
|
157
173
|
display: none;
|
|
158
174
|
}
|
|
175
|
+
|
|
176
|
+
/* Rotation controls */
|
|
177
|
+
.rotation-controls {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 8px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.rotation-row {
|
|
184
|
+
display: flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
gap: 6px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.rotation-label {
|
|
190
|
+
font-size: 13px;
|
|
191
|
+
font-weight: 600;
|
|
192
|
+
min-width: 18px;
|
|
193
|
+
color: #00ffff;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.rotate-btn {
|
|
197
|
+
flex: 1;
|
|
198
|
+
padding: 6px 10px;
|
|
199
|
+
font-size: 11px;
|
|
200
|
+
font-weight: 600;
|
|
201
|
+
background: rgba(0, 255, 255, 0.08);
|
|
202
|
+
border: 1px solid #00ffff;
|
|
203
|
+
border-radius: 4px;
|
|
204
|
+
color: #00ffff;
|
|
205
|
+
cursor: pointer;
|
|
206
|
+
transition: all 0.2s ease;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.rotate-btn:hover {
|
|
210
|
+
background: rgba(0, 255, 255, 0.15);
|
|
211
|
+
box-shadow: 0 0 6px rgba(0, 255, 255, 0.2);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.rotate-btn:active {
|
|
215
|
+
background: rgba(0, 255, 255, 0.25);
|
|
216
|
+
transform: scale(0.98);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.btn-small {
|
|
220
|
+
padding: 6px 10px;
|
|
221
|
+
font-size: 11px;
|
|
222
|
+
margin-top: 4px;
|
|
223
|
+
}
|