@gridspace/raster-path 1.0.3 → 1.0.5
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 +40 -2
- package/build/raster-path.js +16 -24
- package/build/raster-worker.js +2450 -0
- package/build/style.css +65 -0
- package/package.json +12 -4
- package/scripts/build-shaders.js +32 -8
- package/src/core/path-planar.js +788 -0
- package/src/core/path-radial.js +651 -0
- package/src/core/raster-config.js +185 -0
- package/src/{index.js → core/raster-path.js} +16 -24
- package/src/core/raster-planar.js +754 -0
- package/src/core/raster-tool.js +104 -0
- package/src/core/raster-worker.js +152 -0
- package/src/core/workload-calibrate.js +416 -0
- package/src/shaders/{radial-raster-v2.wgsl → radial-raster.wgsl} +8 -2
- package/src/shaders/workload-calibrate.wgsl +106 -0
- package/src/test/batch-divisor-benchmark.cjs +286 -0
- package/src/test/calibrate-test.cjs +136 -0
- package/src/test/extreme-work-test.cjs +167 -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/radial-thread-limit-test.cjs +152 -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 +40 -2
- package/src/web/style.css +65 -0
- package/src/workload-calculator.js +318 -0
- package/build/webgpu-worker.js +0 -3011
- package/src/web/webgpu-worker.js +0 -2520
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
// work-estimation-profile.cjs
|
|
2
|
+
// Profile different models to determine work estimation heuristics for optimal batch sizing
|
|
3
|
+
// Tests multiple models at different batch divisors to find inflection points
|
|
4
|
+
|
|
5
|
+
const { app, BrowserWindow } = require('electron');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
const OUTPUT_DIR = path.join(__dirname, '../../test-output');
|
|
10
|
+
const RESULTS_FILE = path.join(OUTPUT_DIR, 'tool-diameter-scaling.json');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(OUTPUT_DIR)) {
|
|
13
|
+
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Tool scale factors to test (baseline is 5mm radius = 10mm diameter)
|
|
17
|
+
// Scale factors: 0.2 → 2mm diameter, 0.4 → 4mm diameter, 0.6 → 6mm diameter, 0.8 → 8mm diameter, 1.0 → 10mm diameter
|
|
18
|
+
// Only test tool scaling with divisor=1 to measure tool diameter impact on toolpath generation
|
|
19
|
+
const TOOL_SCALES = [0.2, 0.4, 0.6, 0.8, 1.0];
|
|
20
|
+
|
|
21
|
+
// Test configurations - use divisor=1 only for tool scaling tests
|
|
22
|
+
const TEST_CONFIGS = [
|
|
23
|
+
{
|
|
24
|
+
name: 'terrain',
|
|
25
|
+
file: '../benchmark/fixtures/terrain.stl',
|
|
26
|
+
resolution: 0.05,
|
|
27
|
+
rotationStep: 1.0,
|
|
28
|
+
divisors: [1], // Only baseline for tool diameter testing
|
|
29
|
+
expectedTriangles: 75586
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'lathe-cylinder',
|
|
33
|
+
file: '../benchmark/fixtures/lathe-cylinder.stl',
|
|
34
|
+
resolution: 0.05,
|
|
35
|
+
rotationStep: 1.0,
|
|
36
|
+
divisors: [1],
|
|
37
|
+
expectedTriangles: 90620
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'lathe-cylinder-2',
|
|
41
|
+
file: '../benchmark/fixtures/lathe-cylinder-2.stl',
|
|
42
|
+
resolution: 0.05,
|
|
43
|
+
rotationStep: 1.0,
|
|
44
|
+
divisors: [1],
|
|
45
|
+
expectedTriangles: 144890
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'lathe-torture',
|
|
49
|
+
file: '../benchmark/fixtures/lathe-torture.stl',
|
|
50
|
+
resolution: 0.05,
|
|
51
|
+
rotationStep: 1.0,
|
|
52
|
+
divisors: [1],
|
|
53
|
+
expectedTriangles: 1491718
|
|
54
|
+
}
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
console.log('=== Work Estimation Profiling with Tool Diameter Scaling ===');
|
|
58
|
+
console.log(`Testing ${TEST_CONFIGS.length} models × ${TOOL_SCALES.length} tool scales`);
|
|
59
|
+
console.log(`Tool diameters: ${TOOL_SCALES.map(s => `${(s * 10).toFixed(1)}mm`).join(', ')}`);
|
|
60
|
+
console.log('');
|
|
61
|
+
|
|
62
|
+
let mainWindow;
|
|
63
|
+
let currentConfigIndex = 0;
|
|
64
|
+
let currentDivisorIndex = 0;
|
|
65
|
+
let currentToolScaleIndex = 0;
|
|
66
|
+
const results = [];
|
|
67
|
+
|
|
68
|
+
function createWindow() {
|
|
69
|
+
mainWindow = new BrowserWindow({
|
|
70
|
+
width: 1200,
|
|
71
|
+
height: 800,
|
|
72
|
+
show: false,
|
|
73
|
+
webPreferences: {
|
|
74
|
+
nodeIntegration: false,
|
|
75
|
+
contextIsolation: true,
|
|
76
|
+
enableBlinkFeatures: 'WebGPU',
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const htmlPath = path.join(__dirname, '../../build/index.html');
|
|
81
|
+
mainWindow.loadFile(htmlPath);
|
|
82
|
+
|
|
83
|
+
mainWindow.webContents.on('did-finish-load', async () => {
|
|
84
|
+
console.log('✓ Page loaded\n');
|
|
85
|
+
await runNextTest();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Capture detailed timing logs
|
|
89
|
+
mainWindow.webContents.on('console-message', (event, level, message) => {
|
|
90
|
+
if (message.includes('Batch') && message.includes('timing:')) {
|
|
91
|
+
console.log('[TIMING]', message);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function runNextTest() {
|
|
97
|
+
if (currentConfigIndex >= TEST_CONFIGS.length) {
|
|
98
|
+
// All tests complete
|
|
99
|
+
await analyzeResults();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const config = TEST_CONFIGS[currentConfigIndex];
|
|
104
|
+
const divisors = config.divisors;
|
|
105
|
+
|
|
106
|
+
if (currentToolScaleIndex >= TOOL_SCALES.length) {
|
|
107
|
+
// Move to next divisor
|
|
108
|
+
currentDivisorIndex++;
|
|
109
|
+
currentToolScaleIndex = 0;
|
|
110
|
+
await runNextTest();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (currentDivisorIndex >= divisors.length) {
|
|
115
|
+
// Move to next model
|
|
116
|
+
currentConfigIndex++;
|
|
117
|
+
currentDivisorIndex = 0;
|
|
118
|
+
currentToolScaleIndex = 0;
|
|
119
|
+
await runNextTest();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const divisor = divisors[currentDivisorIndex];
|
|
124
|
+
const toolScale = TOOL_SCALES[currentToolScaleIndex];
|
|
125
|
+
const toolDiameter = (toolScale * 10).toFixed(1);
|
|
126
|
+
|
|
127
|
+
console.log(`${'='.repeat(70)}`);
|
|
128
|
+
console.log(`Model: ${config.name} | Divisor: ${divisor} | Tool: ${toolDiameter}mm`);
|
|
129
|
+
console.log('='.repeat(70));
|
|
130
|
+
|
|
131
|
+
const testScript = `
|
|
132
|
+
(async function() {
|
|
133
|
+
const config = ${JSON.stringify(config)};
|
|
134
|
+
const divisor = ${divisor};
|
|
135
|
+
const toolScale = ${toolScale};
|
|
136
|
+
const toolDiameter = ${toolDiameter};
|
|
137
|
+
|
|
138
|
+
if (!navigator.gpu) {
|
|
139
|
+
return { error: 'WebGPU not available' };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const { RasterPath } = await import('./raster-path.js');
|
|
143
|
+
|
|
144
|
+
// Load STL files
|
|
145
|
+
const terrainResponse = await fetch('${config.file}');
|
|
146
|
+
const terrainBuffer = await terrainResponse.arrayBuffer();
|
|
147
|
+
|
|
148
|
+
const toolResponse = await fetch('../benchmark/fixtures/tool.stl');
|
|
149
|
+
const toolBuffer = await toolResponse.arrayBuffer();
|
|
150
|
+
|
|
151
|
+
// Parse STL
|
|
152
|
+
function parseBinarySTL(buffer) {
|
|
153
|
+
const dataView = new DataView(buffer);
|
|
154
|
+
const numTriangles = dataView.getUint32(80, true);
|
|
155
|
+
const positions = new Float32Array(numTriangles * 9);
|
|
156
|
+
let offset = 84;
|
|
157
|
+
|
|
158
|
+
for (let i = 0; i < numTriangles; i++) {
|
|
159
|
+
offset += 12;
|
|
160
|
+
for (let j = 0; j < 9; j++) {
|
|
161
|
+
positions[i * 9 + j] = dataView.getFloat32(offset, true);
|
|
162
|
+
offset += 4;
|
|
163
|
+
}
|
|
164
|
+
offset += 2;
|
|
165
|
+
}
|
|
166
|
+
return positions;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const terrainTriangles = parseBinarySTL(terrainBuffer);
|
|
170
|
+
let toolTriangles = parseBinarySTL(toolBuffer);
|
|
171
|
+
|
|
172
|
+
// Scale the tool triangles
|
|
173
|
+
if (toolScale !== 1.0) {
|
|
174
|
+
toolTriangles = toolTriangles.map(v => v * toolScale);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const actualTriangleCount = terrainTriangles.length / 9;
|
|
178
|
+
const toolTriangleCount = toolTriangles.length / 9;
|
|
179
|
+
|
|
180
|
+
console.log('Terrain triangles:', actualTriangleCount);
|
|
181
|
+
console.log('Tool triangles:', toolTriangleCount);
|
|
182
|
+
console.log('Tool diameter:', toolDiameter, 'mm (scale:', toolScale, ')');
|
|
183
|
+
|
|
184
|
+
// Create RasterPath instance
|
|
185
|
+
const raster = new RasterPath({
|
|
186
|
+
mode: 'radial',
|
|
187
|
+
resolution: config.resolution,
|
|
188
|
+
rotationStep: config.rotationStep,
|
|
189
|
+
batchDivisor: divisor
|
|
190
|
+
});
|
|
191
|
+
await raster.init();
|
|
192
|
+
|
|
193
|
+
// Load tool
|
|
194
|
+
const t0 = performance.now();
|
|
195
|
+
await raster.loadTool({ triangles: toolTriangles });
|
|
196
|
+
const toolTime = performance.now() - t0;
|
|
197
|
+
|
|
198
|
+
// Load terrain
|
|
199
|
+
const t1 = performance.now();
|
|
200
|
+
await raster.loadTerrain({
|
|
201
|
+
triangles: terrainTriangles,
|
|
202
|
+
zFloor: 0
|
|
203
|
+
});
|
|
204
|
+
const terrainTime = performance.now() - t1;
|
|
205
|
+
|
|
206
|
+
// Generate toolpaths (batching happens here)
|
|
207
|
+
const t2 = performance.now();
|
|
208
|
+
const toolpathData = await raster.generateToolpaths({
|
|
209
|
+
xStep: 1,
|
|
210
|
+
yStep: 1,
|
|
211
|
+
zFloor: 0,
|
|
212
|
+
radiusOffset: 20
|
|
213
|
+
});
|
|
214
|
+
const toolpathTime = performance.now() - t2;
|
|
215
|
+
|
|
216
|
+
raster.terminate();
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
success: true,
|
|
220
|
+
model: config.name,
|
|
221
|
+
divisor: divisor,
|
|
222
|
+
toolScale: toolScale,
|
|
223
|
+
toolDiameter: toolDiameter,
|
|
224
|
+
triangleCount: actualTriangleCount,
|
|
225
|
+
toolTriangleCount: toolTriangleCount,
|
|
226
|
+
timing: {
|
|
227
|
+
tool: toolTime,
|
|
228
|
+
terrain: terrainTime,
|
|
229
|
+
toolpath: toolpathTime,
|
|
230
|
+
total: toolTime + terrainTime + toolpathTime
|
|
231
|
+
},
|
|
232
|
+
result: {
|
|
233
|
+
numStrips: toolpathData.numStrips,
|
|
234
|
+
totalPoints: toolpathData.totalPoints
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
})();
|
|
238
|
+
`;
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const result = await mainWindow.webContents.executeJavaScript(testScript);
|
|
242
|
+
|
|
243
|
+
if (result.error) {
|
|
244
|
+
console.error('❌ Test failed:', result.error);
|
|
245
|
+
app.exit(1);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
results.push(result);
|
|
250
|
+
|
|
251
|
+
console.log(`\nResults:`);
|
|
252
|
+
console.log(` Terrain triangles: ${result.triangleCount.toLocaleString()}`);
|
|
253
|
+
console.log(` Tool triangles: ${result.toolTriangleCount}`);
|
|
254
|
+
console.log(` Tool diameter: ${result.toolDiameter}mm`);
|
|
255
|
+
console.log(` Toolpath time: ${result.timing.toolpath.toFixed(1)}ms`);
|
|
256
|
+
console.log(` Total time: ${result.timing.total.toFixed(1)}ms`);
|
|
257
|
+
console.log(` Strips generated: ${result.result.numStrips}`);
|
|
258
|
+
|
|
259
|
+
// Move to next test
|
|
260
|
+
currentToolScaleIndex++;
|
|
261
|
+
setTimeout(() => runNextTest(), 500);
|
|
262
|
+
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error('Error running test:', error);
|
|
265
|
+
app.exit(1);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function analyzeResults() {
|
|
270
|
+
console.log('\n' + '='.repeat(70));
|
|
271
|
+
console.log('WORK ESTIMATION ANALYSIS');
|
|
272
|
+
console.log('='.repeat(70));
|
|
273
|
+
|
|
274
|
+
// Save raw results
|
|
275
|
+
const resultsData = {
|
|
276
|
+
timestamp: new Date().toISOString(),
|
|
277
|
+
configs: TEST_CONFIGS,
|
|
278
|
+
results: results
|
|
279
|
+
};
|
|
280
|
+
fs.writeFileSync(RESULTS_FILE, JSON.stringify(resultsData, null, 2));
|
|
281
|
+
console.log(`\n✓ Raw results saved to: ${RESULTS_FILE}\n`);
|
|
282
|
+
|
|
283
|
+
// Group by model
|
|
284
|
+
const modelGroups = {};
|
|
285
|
+
for (const result of results) {
|
|
286
|
+
if (!modelGroups[result.model]) {
|
|
287
|
+
modelGroups[result.model] = [];
|
|
288
|
+
}
|
|
289
|
+
modelGroups[result.model].push(result);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Analyze each model - focus on tool diameter impact
|
|
293
|
+
console.log('--- Tool Diameter Impact Analysis ---\n');
|
|
294
|
+
|
|
295
|
+
const toolDiameterData = [];
|
|
296
|
+
|
|
297
|
+
for (const [modelName, modelResults] of Object.entries(modelGroups)) {
|
|
298
|
+
console.log(`\n${modelName.toUpperCase()}`);
|
|
299
|
+
console.log('─'.repeat(70));
|
|
300
|
+
|
|
301
|
+
const triangleCount = modelResults[0].triangleCount;
|
|
302
|
+
const totalAngles = modelResults[0].result.numStrips; // 360 for 1° step
|
|
303
|
+
|
|
304
|
+
console.log(`Triangle count: ${triangleCount.toLocaleString()}`);
|
|
305
|
+
console.log(`Total angles: ${totalAngles}`);
|
|
306
|
+
console.log(`Resolution: 0.05mm\n`);
|
|
307
|
+
|
|
308
|
+
console.log('Tool Ø | Tool Tris | Toolpath (ms) | Total (ms) | Toolpath/Strip');
|
|
309
|
+
console.log('-------|-----------|---------------|------------|---------------');
|
|
310
|
+
|
|
311
|
+
const baseline = modelResults[0]; // Smallest tool
|
|
312
|
+
|
|
313
|
+
for (const result of modelResults) {
|
|
314
|
+
const toolpathPerStrip = result.timing.toolpath / totalAngles;
|
|
315
|
+
const speedup = baseline.timing.toolpath / result.timing.toolpath;
|
|
316
|
+
|
|
317
|
+
console.log(
|
|
318
|
+
`${String(result.toolDiameter + 'mm').padEnd(6)} | ` +
|
|
319
|
+
`${String(result.toolTriangleCount).padStart(9)} | ` +
|
|
320
|
+
`${result.timing.toolpath.toFixed(1).padStart(13)} | ` +
|
|
321
|
+
`${result.timing.total.toFixed(1).padStart(10)} | ` +
|
|
322
|
+
`${toolpathPerStrip.toFixed(2).padStart(14)}ms`
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// Store data for correlation analysis
|
|
326
|
+
toolDiameterData.push({
|
|
327
|
+
model: modelName,
|
|
328
|
+
triangleCount: triangleCount,
|
|
329
|
+
toolDiameter: result.toolDiameter,
|
|
330
|
+
toolTriangleCount: result.toolTriangleCount,
|
|
331
|
+
toolpathTime: result.timing.toolpath,
|
|
332
|
+
toolpathPerStrip: toolpathPerStrip
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
console.log('');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Correlation analysis - tool diameter vs toolpath time
|
|
340
|
+
console.log('\n' + '='.repeat(70));
|
|
341
|
+
console.log('TOOL DIAMETER CORRELATION ANALYSIS');
|
|
342
|
+
console.log('='.repeat(70));
|
|
343
|
+
|
|
344
|
+
// Group by model to analyze scaling
|
|
345
|
+
const modelToolData = {};
|
|
346
|
+
for (const data of toolDiameterData) {
|
|
347
|
+
if (!modelToolData[data.model]) {
|
|
348
|
+
modelToolData[data.model] = [];
|
|
349
|
+
}
|
|
350
|
+
modelToolData[data.model].push(data);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log('\n--- Scaling Relationship Analysis ---\n');
|
|
354
|
+
|
|
355
|
+
for (const [modelName, dataPoints] of Object.entries(modelToolData)) {
|
|
356
|
+
console.log(`${modelName.toUpperCase()}:`);
|
|
357
|
+
|
|
358
|
+
// Sort by tool diameter
|
|
359
|
+
dataPoints.sort((a, b) => a.toolDiameter - b.toolDiameter);
|
|
360
|
+
|
|
361
|
+
const baseline = dataPoints[0];
|
|
362
|
+
|
|
363
|
+
console.log(` Tool Ø vs Time (normalized to ${baseline.toolDiameter}mm baseline):`);
|
|
364
|
+
|
|
365
|
+
for (const point of dataPoints) {
|
|
366
|
+
const diameterRatio = point.toolDiameter / baseline.toolDiameter;
|
|
367
|
+
const timeRatio = point.toolpathTime / baseline.toolpathTime;
|
|
368
|
+
const expectedLinear = diameterRatio;
|
|
369
|
+
const expectedSquare = diameterRatio ** 2;
|
|
370
|
+
|
|
371
|
+
console.log(` ${point.toolDiameter.toFixed(1)}mm: ${timeRatio.toFixed(2)}x slower`);
|
|
372
|
+
console.log(` Diameter ratio: ${diameterRatio.toFixed(2)}x`);
|
|
373
|
+
console.log(` If linear (Ø): ${expectedLinear.toFixed(2)}x (error: ${Math.abs(timeRatio - expectedLinear).toFixed(2)})`);
|
|
374
|
+
console.log(` If square (ز): ${expectedSquare.toFixed(2)}x (error: ${Math.abs(timeRatio - expectedSquare).toFixed(2)})`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Calculate correlation coefficient for linear and square relationships
|
|
378
|
+
const diameterRatios = dataPoints.map(p => p.toolDiameter / baseline.toolDiameter);
|
|
379
|
+
const timeRatios = dataPoints.map(p => p.toolpathTime / baseline.toolpathTime);
|
|
380
|
+
|
|
381
|
+
// Linear correlation: timeRatio ~ diameterRatio
|
|
382
|
+
const linearErrors = diameterRatios.map((dr, i) => Math.abs(timeRatios[i] - dr));
|
|
383
|
+
const avgLinearError = linearErrors.reduce((sum, e) => sum + e, 0) / linearErrors.length;
|
|
384
|
+
|
|
385
|
+
// Square correlation: timeRatio ~ diameterRatio²
|
|
386
|
+
const squareErrors = diameterRatios.map((dr, i) => Math.abs(timeRatios[i] - dr ** 2));
|
|
387
|
+
const avgSquareError = squareErrors.reduce((sum, e) => sum + e, 0) / squareErrors.length;
|
|
388
|
+
|
|
389
|
+
console.log(` Average error: Linear ${avgLinearError.toFixed(3)}, Square ${avgSquareError.toFixed(3)}`);
|
|
390
|
+
console.log(` ${avgSquareError < avgLinearError ? '✓ Square relationship fits better' : '✓ Linear relationship fits better'}\n`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Summary
|
|
394
|
+
console.log('\n--- Summary ---\n');
|
|
395
|
+
console.log('This test measures the relationship between tool diameter and toolpath');
|
|
396
|
+
console.log('generation time. The hypothesis is that work scales with tool diameter²');
|
|
397
|
+
console.log('because the sparse tool representation has more points to check.');
|
|
398
|
+
console.log('\nThe analysis compares linear (Ø) vs square (ز) scaling to validate');
|
|
399
|
+
console.log('or refute this hypothesis.');
|
|
400
|
+
|
|
401
|
+
console.log('\n✅ Profiling complete!');
|
|
402
|
+
app.exit(0);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
app.whenReady().then(createWindow);
|
|
406
|
+
app.on('window-all-closed', () => app.quit());
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// workload-calculator-demo.cjs
|
|
2
|
+
// Demonstration of the workload calculator
|
|
3
|
+
|
|
4
|
+
const { WorkloadCalculator } = require('../workload-calculator.js');
|
|
5
|
+
|
|
6
|
+
const calculator = new WorkloadCalculator();
|
|
7
|
+
|
|
8
|
+
console.log('=== Workload Calculator Demo ===\n');
|
|
9
|
+
|
|
10
|
+
// Example 1: Typical lathe part
|
|
11
|
+
console.log('Example 1: Lathe cylinder (typical parameters)');
|
|
12
|
+
calculator.printAnalysis({
|
|
13
|
+
triangleCount: 90620,
|
|
14
|
+
bounds: {
|
|
15
|
+
minX: 0, maxX: 100,
|
|
16
|
+
minY: -25, maxY: 25,
|
|
17
|
+
minZ: -25, maxZ: 25
|
|
18
|
+
},
|
|
19
|
+
resolution: 0.05,
|
|
20
|
+
rotationStep: 1.0,
|
|
21
|
+
toolDiameter: 2.5
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
25
|
+
|
|
26
|
+
// Example 2: High resolution
|
|
27
|
+
console.log('Example 2: Same part, high resolution (0.01mm)');
|
|
28
|
+
calculator.printAnalysis({
|
|
29
|
+
triangleCount: 90620,
|
|
30
|
+
bounds: {
|
|
31
|
+
minX: 0, maxX: 100,
|
|
32
|
+
minY: -25, maxY: 25,
|
|
33
|
+
minZ: -25, maxZ: 25
|
|
34
|
+
},
|
|
35
|
+
resolution: 0.01,
|
|
36
|
+
rotationStep: 1.0,
|
|
37
|
+
toolDiameter: 2.5
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
41
|
+
|
|
42
|
+
// Example 3: Large tool
|
|
43
|
+
console.log('Example 3: Same part, larger tool (5mm)');
|
|
44
|
+
calculator.printAnalysis({
|
|
45
|
+
triangleCount: 90620,
|
|
46
|
+
bounds: {
|
|
47
|
+
minX: 0, maxX: 100,
|
|
48
|
+
minY: -25, maxY: 25,
|
|
49
|
+
minZ: -25, maxZ: 25
|
|
50
|
+
},
|
|
51
|
+
resolution: 0.05,
|
|
52
|
+
rotationStep: 1.0,
|
|
53
|
+
toolDiameter: 5.0
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
57
|
+
|
|
58
|
+
// Example 4: Fine angular step
|
|
59
|
+
console.log('Example 4: Same part, fine angular step (0.5°)');
|
|
60
|
+
calculator.printAnalysis({
|
|
61
|
+
triangleCount: 90620,
|
|
62
|
+
bounds: {
|
|
63
|
+
minX: 0, maxX: 100,
|
|
64
|
+
minY: -25, maxY: 25,
|
|
65
|
+
minZ: -25, maxZ: 25
|
|
66
|
+
},
|
|
67
|
+
resolution: 0.05,
|
|
68
|
+
rotationStep: 0.5,
|
|
69
|
+
toolDiameter: 2.5
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
73
|
+
|
|
74
|
+
// Example 5: Complex torture test
|
|
75
|
+
console.log('Example 5: Lathe torture (1.5M triangles)');
|
|
76
|
+
calculator.printAnalysis({
|
|
77
|
+
triangleCount: 1491718,
|
|
78
|
+
bounds: {
|
|
79
|
+
minX: 0, maxX: 100,
|
|
80
|
+
minY: -30, maxY: 30,
|
|
81
|
+
minZ: -30, maxZ: 30
|
|
82
|
+
},
|
|
83
|
+
resolution: 0.05,
|
|
84
|
+
rotationStep: 1.0,
|
|
85
|
+
toolDiameter: 2.5
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
89
|
+
|
|
90
|
+
// Example 6: Memory constraint check
|
|
91
|
+
console.log('Example 6: Memory limit suggestions');
|
|
92
|
+
const params = {
|
|
93
|
+
triangleCount: 90620,
|
|
94
|
+
bounds: {
|
|
95
|
+
minX: 0, maxX: 100,
|
|
96
|
+
minY: -25, maxY: 25,
|
|
97
|
+
minZ: -25, maxZ: 25
|
|
98
|
+
},
|
|
99
|
+
resolution: 0.01, // Very fine - may exceed memory
|
|
100
|
+
rotationStep: 0.5,
|
|
101
|
+
toolDiameter: 2.5
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const suggestion = calculator.suggestOptimalParameters(params, 256);
|
|
105
|
+
console.log(suggestion.message);
|
|
106
|
+
if (suggestion.needsAdjustment) {
|
|
107
|
+
console.log(`Current memory: ${suggestion.currentMemory.toFixed(1)} MB`);
|
|
108
|
+
console.log('Suggestions:');
|
|
109
|
+
console.log(` Resolution: ${suggestion.suggestions.resolution}mm`);
|
|
110
|
+
console.log(` Angular step: ${suggestion.suggestions.angularStep}°`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log('\n=== Demo Complete ===');
|