woodml-parser 1.0.0
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 +181 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +554 -0
- package/dist/cli.js.map +1 -0
- package/dist/cost.d.ts +94 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +340 -0
- package/dist/cost.js.map +1 -0
- package/dist/cost.test.d.ts +2 -0
- package/dist/cost.test.d.ts.map +1 -0
- package/dist/cost.test.js +241 -0
- package/dist/cost.test.js.map +1 -0
- package/dist/example.d.ts +6 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +136 -0
- package/dist/example.js.map +1 -0
- package/dist/formulas.d.ts +23 -0
- package/dist/formulas.d.ts.map +1 -0
- package/dist/formulas.js +442 -0
- package/dist/formulas.js.map +1 -0
- package/dist/formulas.test.d.ts +5 -0
- package/dist/formulas.test.d.ts.map +1 -0
- package/dist/formulas.test.js +360 -0
- package/dist/formulas.test.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +6 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +271 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/optimizer.d.ts +119 -0
- package/dist/optimizer.d.ts.map +1 -0
- package/dist/optimizer.js +423 -0
- package/dist/optimizer.js.map +1 -0
- package/dist/optimizer.test.d.ts +2 -0
- package/dist/optimizer.test.d.ts.map +1 -0
- package/dist/optimizer.test.js +225 -0
- package/dist/optimizer.test.js.map +1 -0
- package/dist/parser.d.ts +59 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +305 -0
- package/dist/parser.js.map +1 -0
- package/dist/parser.test.d.ts +5 -0
- package/dist/parser.test.d.ts.map +1 -0
- package/dist/parser.test.js +486 -0
- package/dist/parser.test.js.map +1 -0
- package/dist/pdf.d.ts +36 -0
- package/dist/pdf.d.ts.map +1 -0
- package/dist/pdf.js +316 -0
- package/dist/pdf.js.map +1 -0
- package/dist/svg.d.ts +73 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/svg.js +613 -0
- package/dist/svg.js.map +1 -0
- package/dist/svg.test.d.ts +5 -0
- package/dist/svg.test.d.ts.map +1 -0
- package/dist/svg.test.js +333 -0
- package/dist/svg.test.js.map +1 -0
- package/dist/templates.d.ts +126 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +448 -0
- package/dist/templates.js.map +1 -0
- package/dist/templates.test.d.ts +5 -0
- package/dist/templates.test.d.ts.map +1 -0
- package/dist/templates.test.js +630 -0
- package/dist/templates.test.js.map +1 -0
- package/dist/types.d.ts +250 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/units.d.ts +53 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +359 -0
- package/dist/units.js.map +1 -0
- package/dist/units.test.d.ts +5 -0
- package/dist/units.test.d.ts.map +1 -0
- package/dist/units.test.js +364 -0
- package/dist/units.test.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cut list optimization for WoodML projects
|
|
4
|
+
* Uses First Fit Decreasing bin packing algorithm for sheet goods
|
|
5
|
+
* and 1D bin packing for dimensional lumber
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.STANDARD_BOARD_LENGTHS = exports.STANDARD_SHEET_SIZES = void 0;
|
|
9
|
+
exports.optimizeCutList = optimizeCutList;
|
|
10
|
+
exports.formatOptimizationResult = formatOptimizationResult;
|
|
11
|
+
const units_1 = require("./units");
|
|
12
|
+
/**
|
|
13
|
+
* Standard sheet sizes (in inches)
|
|
14
|
+
*/
|
|
15
|
+
exports.STANDARD_SHEET_SIZES = {
|
|
16
|
+
'4x8': { width: 48, length: 96 },
|
|
17
|
+
'4x4': { width: 48, length: 48 },
|
|
18
|
+
'5x5': { width: 60, length: 60 },
|
|
19
|
+
'4x10': { width: 48, length: 120 },
|
|
20
|
+
'4x12': { width: 48, length: 144 },
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Standard board lengths (in inches)
|
|
24
|
+
*/
|
|
25
|
+
exports.STANDARD_BOARD_LENGTHS = [72, 96, 120, 144, 192]; // 6', 8', 10', 12', 16'
|
|
26
|
+
/**
|
|
27
|
+
* Check if a material is a sheet good
|
|
28
|
+
*/
|
|
29
|
+
function isSheetGood(material) {
|
|
30
|
+
const sheetMaterials = [
|
|
31
|
+
'plywood',
|
|
32
|
+
'mdf',
|
|
33
|
+
'particleboard',
|
|
34
|
+
'hardboard',
|
|
35
|
+
'melamine',
|
|
36
|
+
'baltic birch',
|
|
37
|
+
'osb',
|
|
38
|
+
];
|
|
39
|
+
const lower = material.toLowerCase();
|
|
40
|
+
return sheetMaterials.some((m) => lower.includes(m));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert parts to optimization format
|
|
44
|
+
*/
|
|
45
|
+
function prepareParts(doc, kerf) {
|
|
46
|
+
const parts = [];
|
|
47
|
+
for (const part of doc.resolvedParts) {
|
|
48
|
+
const length = (0, units_1.toInches)(part.dimensions.length) + kerf;
|
|
49
|
+
const width = (0, units_1.toInches)(part.dimensions.width) + kerf;
|
|
50
|
+
const thickness = (0, units_1.toInches)(part.dimensions.thickness);
|
|
51
|
+
const material = part.material || 'unknown';
|
|
52
|
+
const quantity = part.quantity || 1;
|
|
53
|
+
for (let i = 0; i < quantity; i++) {
|
|
54
|
+
parts.push({
|
|
55
|
+
id: quantity > 1 ? `${part.id}_${i + 1}` : part.id,
|
|
56
|
+
name: part.name || part.id,
|
|
57
|
+
length,
|
|
58
|
+
width,
|
|
59
|
+
thickness,
|
|
60
|
+
material,
|
|
61
|
+
quantity: 1,
|
|
62
|
+
isSheetGood: isSheetGood(material),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return parts;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Guillotine algorithm for 2D bin packing (sheet goods)
|
|
70
|
+
*/
|
|
71
|
+
class GuillotinePacker {
|
|
72
|
+
sheetWidth;
|
|
73
|
+
sheetLength;
|
|
74
|
+
freeRects;
|
|
75
|
+
kerf;
|
|
76
|
+
constructor(width, length, kerf) {
|
|
77
|
+
this.sheetWidth = width;
|
|
78
|
+
this.sheetLength = length;
|
|
79
|
+
this.kerf = kerf;
|
|
80
|
+
this.freeRects = [
|
|
81
|
+
{ x: 0, y: 0, width: width, height: length, valid: true },
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Try to place a part, returns placement or null
|
|
86
|
+
*/
|
|
87
|
+
place(width, height, allowRotation) {
|
|
88
|
+
let bestRect = null;
|
|
89
|
+
let bestFit = Infinity;
|
|
90
|
+
let rotated = false;
|
|
91
|
+
for (const rect of this.freeRects) {
|
|
92
|
+
if (!rect.valid)
|
|
93
|
+
continue;
|
|
94
|
+
// Try normal orientation
|
|
95
|
+
if (width <= rect.width && height <= rect.height) {
|
|
96
|
+
const fit = rect.width * rect.height - width * height;
|
|
97
|
+
if (fit < bestFit) {
|
|
98
|
+
bestFit = fit;
|
|
99
|
+
bestRect = rect;
|
|
100
|
+
rotated = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Try rotated orientation
|
|
104
|
+
if (allowRotation && height <= rect.width && width <= rect.height) {
|
|
105
|
+
const fit = rect.width * rect.height - height * width;
|
|
106
|
+
if (fit < bestFit) {
|
|
107
|
+
bestFit = fit;
|
|
108
|
+
bestRect = rect;
|
|
109
|
+
rotated = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!bestRect)
|
|
114
|
+
return null;
|
|
115
|
+
const placedWidth = rotated ? height : width;
|
|
116
|
+
const placedHeight = rotated ? width : height;
|
|
117
|
+
// Split the rectangle
|
|
118
|
+
this.splitRect(bestRect, placedWidth, placedHeight);
|
|
119
|
+
return { x: bestRect.x, y: bestRect.y, rotated };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Split a rectangle after placing a part
|
|
123
|
+
*/
|
|
124
|
+
splitRect(rect, width, height) {
|
|
125
|
+
rect.valid = false;
|
|
126
|
+
// Create right remainder
|
|
127
|
+
if (rect.width - width > this.kerf) {
|
|
128
|
+
this.freeRects.push({
|
|
129
|
+
x: rect.x + width,
|
|
130
|
+
y: rect.y,
|
|
131
|
+
width: rect.width - width,
|
|
132
|
+
height: height,
|
|
133
|
+
valid: true,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Create bottom remainder
|
|
137
|
+
if (rect.height - height > this.kerf) {
|
|
138
|
+
this.freeRects.push({
|
|
139
|
+
x: rect.x,
|
|
140
|
+
y: rect.y + height,
|
|
141
|
+
width: rect.width,
|
|
142
|
+
height: rect.height - height,
|
|
143
|
+
valid: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Merge adjacent free rectangles
|
|
147
|
+
this.mergeFreeRects();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Merge adjacent free rectangles where possible
|
|
151
|
+
*/
|
|
152
|
+
mergeFreeRects() {
|
|
153
|
+
// Simple cleanup - remove invalid rectangles
|
|
154
|
+
this.freeRects = this.freeRects.filter((r) => r.valid);
|
|
155
|
+
}
|
|
156
|
+
getWasteArea() {
|
|
157
|
+
return this.freeRects
|
|
158
|
+
.filter((r) => r.valid)
|
|
159
|
+
.reduce((sum, r) => sum + r.width * r.height, 0);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* First Fit Decreasing for 1D bin packing (boards)
|
|
164
|
+
*/
|
|
165
|
+
function packBoards(parts, boardLengths, kerf, minCutoff) {
|
|
166
|
+
// Sort parts by length descending
|
|
167
|
+
const sortedParts = [...parts].sort((a, b) => b.length - a.length);
|
|
168
|
+
// Find the most common width/thickness combination
|
|
169
|
+
const sizeGroups = new Map();
|
|
170
|
+
for (const part of sortedParts) {
|
|
171
|
+
const key = `${part.width.toFixed(2)}x${part.thickness.toFixed(2)}`;
|
|
172
|
+
if (!sizeGroups.has(key)) {
|
|
173
|
+
sizeGroups.set(key, []);
|
|
174
|
+
}
|
|
175
|
+
sizeGroups.get(key).push(part);
|
|
176
|
+
}
|
|
177
|
+
const boards = [];
|
|
178
|
+
let boardNumber = 1;
|
|
179
|
+
for (const [sizeKey, groupParts] of sizeGroups) {
|
|
180
|
+
const [widthStr, thicknessStr] = sizeKey.split('x');
|
|
181
|
+
const boardWidth = parseFloat(widthStr);
|
|
182
|
+
const boardThickness = parseFloat(thicknessStr);
|
|
183
|
+
// Find optimal board length for this group
|
|
184
|
+
const totalLength = groupParts.reduce((sum, p) => sum + p.length + kerf, 0);
|
|
185
|
+
const avgPartLength = groupParts.reduce((sum, p) => sum + p.length, 0) / groupParts.length;
|
|
186
|
+
// Select board length that minimizes waste
|
|
187
|
+
let optimalBoardLength = boardLengths[0];
|
|
188
|
+
for (const len of boardLengths) {
|
|
189
|
+
if (len >= avgPartLength * 1.5) {
|
|
190
|
+
optimalBoardLength = len;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Pack parts into boards
|
|
195
|
+
const remainingParts = [...groupParts];
|
|
196
|
+
while (remainingParts.length > 0) {
|
|
197
|
+
const board = {
|
|
198
|
+
boardNumber: boardNumber++,
|
|
199
|
+
boardLength: optimalBoardLength,
|
|
200
|
+
boardWidth,
|
|
201
|
+
boardThickness,
|
|
202
|
+
parts: [],
|
|
203
|
+
usedLength: 0,
|
|
204
|
+
wasteLength: 0,
|
|
205
|
+
efficiency: 0,
|
|
206
|
+
};
|
|
207
|
+
let position = 0;
|
|
208
|
+
const placedIndices = [];
|
|
209
|
+
// First fit decreasing
|
|
210
|
+
for (let i = 0; i < remainingParts.length; i++) {
|
|
211
|
+
const part = remainingParts[i];
|
|
212
|
+
const requiredLength = part.length + (board.parts.length > 0 ? kerf : 0);
|
|
213
|
+
if (position + requiredLength <= optimalBoardLength) {
|
|
214
|
+
board.parts.push({
|
|
215
|
+
partId: part.id,
|
|
216
|
+
partName: part.name,
|
|
217
|
+
position: position,
|
|
218
|
+
length: part.length,
|
|
219
|
+
});
|
|
220
|
+
position += requiredLength;
|
|
221
|
+
placedIndices.push(i);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Remove placed parts
|
|
225
|
+
for (let i = placedIndices.length - 1; i >= 0; i--) {
|
|
226
|
+
remainingParts.splice(placedIndices[i], 1);
|
|
227
|
+
}
|
|
228
|
+
board.usedLength = position;
|
|
229
|
+
board.wasteLength = optimalBoardLength - position;
|
|
230
|
+
board.efficiency =
|
|
231
|
+
(board.usedLength / optimalBoardLength) * 100;
|
|
232
|
+
boards.push(board);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return boards;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Pack sheet goods using Guillotine algorithm
|
|
239
|
+
*/
|
|
240
|
+
function packSheets(parts, sheetWidth, sheetLength, kerf, allowRotation) {
|
|
241
|
+
// Sort parts by area descending (First Fit Decreasing)
|
|
242
|
+
const sortedParts = [...parts].sort((a, b) => b.length * b.width - a.length * a.width);
|
|
243
|
+
const sheets = [];
|
|
244
|
+
const unplaced = [];
|
|
245
|
+
let sheetNumber = 1;
|
|
246
|
+
const remainingParts = [...sortedParts];
|
|
247
|
+
while (remainingParts.length > 0) {
|
|
248
|
+
const packer = new GuillotinePacker(sheetWidth, sheetLength, kerf);
|
|
249
|
+
const sheetParts = [];
|
|
250
|
+
let usedArea = 0;
|
|
251
|
+
const placedIndices = [];
|
|
252
|
+
for (let i = 0; i < remainingParts.length; i++) {
|
|
253
|
+
const part = remainingParts[i];
|
|
254
|
+
const placement = packer.place(part.width, part.length, allowRotation);
|
|
255
|
+
if (placement) {
|
|
256
|
+
sheetParts.push({
|
|
257
|
+
partId: part.id,
|
|
258
|
+
partName: part.name,
|
|
259
|
+
x: placement.x,
|
|
260
|
+
y: placement.y,
|
|
261
|
+
width: placement.rotated ? part.length : part.width,
|
|
262
|
+
length: placement.rotated ? part.width : part.length,
|
|
263
|
+
rotated: placement.rotated,
|
|
264
|
+
});
|
|
265
|
+
usedArea += part.width * part.length;
|
|
266
|
+
placedIndices.push(i);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// If we couldn't place any parts, they're too large
|
|
270
|
+
if (placedIndices.length === 0) {
|
|
271
|
+
for (const part of remainingParts) {
|
|
272
|
+
unplaced.push(part.id);
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
// Remove placed parts
|
|
277
|
+
for (let i = placedIndices.length - 1; i >= 0; i--) {
|
|
278
|
+
remainingParts.splice(placedIndices[i], 1);
|
|
279
|
+
}
|
|
280
|
+
const totalArea = sheetWidth * sheetLength;
|
|
281
|
+
sheets.push({
|
|
282
|
+
sheetNumber: sheetNumber++,
|
|
283
|
+
sheetWidth,
|
|
284
|
+
sheetLength,
|
|
285
|
+
parts: sheetParts,
|
|
286
|
+
usedArea,
|
|
287
|
+
wasteArea: totalArea - usedArea,
|
|
288
|
+
efficiency: (usedArea / totalArea) * 100,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
return { sheets, unplaced };
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Optimize cut list for a project
|
|
295
|
+
*/
|
|
296
|
+
function optimizeCutList(doc, options = {}) {
|
|
297
|
+
const kerf = options.kerf ?? 0.125; // 1/8" default
|
|
298
|
+
const allowRotation = options.allowRotation ?? true;
|
|
299
|
+
const minCutoff = options.minCutoff ?? 6;
|
|
300
|
+
const sheetSize = exports.STANDARD_SHEET_SIZES[options.sheetSize ?? '4x8'];
|
|
301
|
+
const boardLengths = options.boardLengths ?? exports.STANDARD_BOARD_LENGTHS;
|
|
302
|
+
// Prepare parts
|
|
303
|
+
const allParts = prepareParts(doc, kerf);
|
|
304
|
+
const sheetParts = allParts.filter((p) => p.isSheetGood);
|
|
305
|
+
const boardParts = allParts.filter((p) => !p.isSheetGood);
|
|
306
|
+
// Optimize sheet goods
|
|
307
|
+
const { sheets, unplaced: unplacedSheets } = packSheets(sheetParts, sheetSize.width, sheetSize.length, kerf, allowRotation);
|
|
308
|
+
// Optimize dimensional lumber
|
|
309
|
+
const boards = packBoards(boardParts, boardLengths, kerf, minCutoff);
|
|
310
|
+
// Calculate totals
|
|
311
|
+
const totalSheets = sheets.length;
|
|
312
|
+
const boardCounts = new Map();
|
|
313
|
+
for (const board of boards) {
|
|
314
|
+
const count = boardCounts.get(board.boardLength) || 0;
|
|
315
|
+
boardCounts.set(board.boardLength, count + 1);
|
|
316
|
+
}
|
|
317
|
+
const totalBoards = Array.from(boardCounts.entries())
|
|
318
|
+
.map(([length, count]) => ({ length, count }))
|
|
319
|
+
.sort((a, b) => a.length - b.length);
|
|
320
|
+
// Calculate overall efficiency
|
|
321
|
+
const totalSheetArea = totalSheets * sheetSize.width * sheetSize.length;
|
|
322
|
+
const usedSheetArea = sheets.reduce((sum, s) => sum + s.usedArea, 0);
|
|
323
|
+
const totalBoardLength = boards.reduce((sum, b) => sum + b.boardLength, 0);
|
|
324
|
+
const usedBoardLength = boards.reduce((sum, b) => sum + b.usedLength, 0);
|
|
325
|
+
let overallEfficiency = 0;
|
|
326
|
+
if (totalSheetArea + totalBoardLength > 0) {
|
|
327
|
+
overallEfficiency =
|
|
328
|
+
((usedSheetArea + usedBoardLength) /
|
|
329
|
+
(totalSheetArea + totalBoardLength)) *
|
|
330
|
+
100;
|
|
331
|
+
}
|
|
332
|
+
const wastePercentage = 100 - overallEfficiency;
|
|
333
|
+
// Generate notes
|
|
334
|
+
const notes = [];
|
|
335
|
+
if (kerf > 0) {
|
|
336
|
+
notes.push(`Kerf allowance: ${kerf}" per cut`);
|
|
337
|
+
}
|
|
338
|
+
if (unplacedSheets.length > 0) {
|
|
339
|
+
notes.push(`${unplacedSheets.length} part(s) could not be placed - may be larger than sheet size`);
|
|
340
|
+
}
|
|
341
|
+
if (overallEfficiency < 70) {
|
|
342
|
+
notes.push('Low material efficiency - consider consolidating parts or adjusting dimensions');
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
sheets,
|
|
346
|
+
boards,
|
|
347
|
+
totalSheets,
|
|
348
|
+
totalBoards,
|
|
349
|
+
overallEfficiency: Math.round(overallEfficiency * 10) / 10,
|
|
350
|
+
wastePercentage: Math.round(wastePercentage * 10) / 10,
|
|
351
|
+
unplacedParts: unplacedSheets,
|
|
352
|
+
notes,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Format optimization result as text
|
|
357
|
+
*/
|
|
358
|
+
function formatOptimizationResult(result) {
|
|
359
|
+
const lines = [];
|
|
360
|
+
lines.push('='.repeat(60));
|
|
361
|
+
lines.push('CUT LIST OPTIMIZATION RESULTS');
|
|
362
|
+
lines.push('='.repeat(60));
|
|
363
|
+
lines.push('');
|
|
364
|
+
// Sheet goods
|
|
365
|
+
if (result.sheets.length > 0) {
|
|
366
|
+
lines.push('SHEET GOODS');
|
|
367
|
+
lines.push('-'.repeat(60));
|
|
368
|
+
lines.push(`Total sheets needed: ${result.totalSheets}`);
|
|
369
|
+
lines.push('');
|
|
370
|
+
for (const sheet of result.sheets) {
|
|
371
|
+
lines.push(`Sheet #${sheet.sheetNumber} (${sheet.sheetWidth}" x ${sheet.sheetLength}")`);
|
|
372
|
+
lines.push(` Efficiency: ${sheet.efficiency.toFixed(1)}%`);
|
|
373
|
+
lines.push(' Parts:');
|
|
374
|
+
for (const part of sheet.parts) {
|
|
375
|
+
const rotated = part.rotated ? ' (rotated)' : '';
|
|
376
|
+
lines.push(` - ${part.partName}: ${part.length}" x ${part.width}" at (${part.x}", ${part.y}")${rotated}`);
|
|
377
|
+
}
|
|
378
|
+
lines.push('');
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
// Dimensional lumber
|
|
382
|
+
if (result.boards.length > 0) {
|
|
383
|
+
lines.push('DIMENSIONAL LUMBER');
|
|
384
|
+
lines.push('-'.repeat(60));
|
|
385
|
+
for (const { length, count } of result.totalBoards) {
|
|
386
|
+
const feet = length / 12;
|
|
387
|
+
lines.push(`${count} board(s) at ${feet}' length`);
|
|
388
|
+
}
|
|
389
|
+
lines.push('');
|
|
390
|
+
for (const board of result.boards) {
|
|
391
|
+
const feet = board.boardLength / 12;
|
|
392
|
+
lines.push(`Board #${board.boardNumber} (${feet}' x ${board.boardWidth}" x ${board.boardThickness}")`);
|
|
393
|
+
lines.push(` Efficiency: ${board.efficiency.toFixed(1)}%`);
|
|
394
|
+
lines.push(' Cuts:');
|
|
395
|
+
for (const part of board.parts) {
|
|
396
|
+
lines.push(` - ${part.partName}: ${part.length}" at position ${part.position}"`);
|
|
397
|
+
}
|
|
398
|
+
lines.push('');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// Summary
|
|
402
|
+
lines.push('='.repeat(60));
|
|
403
|
+
lines.push('SUMMARY');
|
|
404
|
+
lines.push('-'.repeat(60));
|
|
405
|
+
lines.push(`Overall efficiency: ${result.overallEfficiency}%`);
|
|
406
|
+
lines.push(`Waste: ${result.wastePercentage}%`);
|
|
407
|
+
if (result.unplacedParts.length > 0) {
|
|
408
|
+
lines.push('');
|
|
409
|
+
lines.push('UNPLACED PARTS:');
|
|
410
|
+
for (const id of result.unplacedParts) {
|
|
411
|
+
lines.push(` - ${id}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (result.notes.length > 0) {
|
|
415
|
+
lines.push('');
|
|
416
|
+
lines.push('NOTES:');
|
|
417
|
+
for (const note of result.notes) {
|
|
418
|
+
lines.push(` * ${note}`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return lines.join('\n');
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimizer.js","sourceRoot":"","sources":["../src/optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimizer.test.d.ts","sourceRoot":"","sources":["../src/optimizer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const node_test_1 = require("node:test");
|
|
37
|
+
const assert = __importStar(require("node:assert"));
|
|
38
|
+
const index_1 = require("./index");
|
|
39
|
+
const optimizer_1 = require("./optimizer");
|
|
40
|
+
(0, node_test_1.describe)('cut list optimization', () => {
|
|
41
|
+
const SHEET_PROJECT = `
|
|
42
|
+
woodml: "1.0"
|
|
43
|
+
project:
|
|
44
|
+
name: "Sheet Good Project"
|
|
45
|
+
units: imperial
|
|
46
|
+
|
|
47
|
+
parts:
|
|
48
|
+
- id: panel_a
|
|
49
|
+
name: "Panel A"
|
|
50
|
+
material: plywood
|
|
51
|
+
dimensions:
|
|
52
|
+
length: 24"
|
|
53
|
+
width: 18"
|
|
54
|
+
thickness: 3/4"
|
|
55
|
+
quantity: 2
|
|
56
|
+
|
|
57
|
+
- id: panel_b
|
|
58
|
+
name: "Panel B"
|
|
59
|
+
material: plywood
|
|
60
|
+
dimensions:
|
|
61
|
+
length: 36"
|
|
62
|
+
width: 24"
|
|
63
|
+
thickness: 3/4"
|
|
64
|
+
quantity: 1
|
|
65
|
+
`;
|
|
66
|
+
const BOARD_PROJECT = `
|
|
67
|
+
woodml: "1.0"
|
|
68
|
+
project:
|
|
69
|
+
name: "Board Project"
|
|
70
|
+
units: imperial
|
|
71
|
+
|
|
72
|
+
parts:
|
|
73
|
+
- id: rail
|
|
74
|
+
name: "Rail"
|
|
75
|
+
material: oak
|
|
76
|
+
dimensions:
|
|
77
|
+
length: 36"
|
|
78
|
+
width: 3"
|
|
79
|
+
thickness: 3/4"
|
|
80
|
+
quantity: 2
|
|
81
|
+
|
|
82
|
+
- id: stile
|
|
83
|
+
name: "Stile"
|
|
84
|
+
material: oak
|
|
85
|
+
dimensions:
|
|
86
|
+
length: 24"
|
|
87
|
+
width: 3"
|
|
88
|
+
thickness: 3/4"
|
|
89
|
+
quantity: 4
|
|
90
|
+
`;
|
|
91
|
+
const MIXED_PROJECT = `
|
|
92
|
+
woodml: "1.0"
|
|
93
|
+
project:
|
|
94
|
+
name: "Mixed Project"
|
|
95
|
+
units: imperial
|
|
96
|
+
|
|
97
|
+
parts:
|
|
98
|
+
- id: back
|
|
99
|
+
name: "Back Panel"
|
|
100
|
+
material: plywood
|
|
101
|
+
dimensions:
|
|
102
|
+
length: 48"
|
|
103
|
+
width: 36"
|
|
104
|
+
thickness: 1/4"
|
|
105
|
+
quantity: 1
|
|
106
|
+
|
|
107
|
+
- id: leg
|
|
108
|
+
name: "Leg"
|
|
109
|
+
material: walnut
|
|
110
|
+
dimensions:
|
|
111
|
+
length: 30"
|
|
112
|
+
width: 2"
|
|
113
|
+
thickness: 2"
|
|
114
|
+
quantity: 4
|
|
115
|
+
`;
|
|
116
|
+
(0, node_test_1.describe)('optimizeCutList', () => {
|
|
117
|
+
(0, node_test_1.it)('should optimize sheet goods', () => {
|
|
118
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
119
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
120
|
+
assert.ok(result.sheets.length > 0);
|
|
121
|
+
assert.strictEqual(result.boards.length, 0);
|
|
122
|
+
assert.ok(result.overallEfficiency > 0);
|
|
123
|
+
});
|
|
124
|
+
(0, node_test_1.it)('should optimize dimensional lumber', () => {
|
|
125
|
+
const doc = (0, index_1.parseAndResolve)(BOARD_PROJECT);
|
|
126
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
127
|
+
assert.strictEqual(result.sheets.length, 0);
|
|
128
|
+
assert.ok(result.boards.length > 0);
|
|
129
|
+
assert.ok(result.overallEfficiency > 0);
|
|
130
|
+
});
|
|
131
|
+
(0, node_test_1.it)('should handle mixed materials', () => {
|
|
132
|
+
const doc = (0, index_1.parseAndResolve)(MIXED_PROJECT);
|
|
133
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
134
|
+
assert.ok(result.sheets.length > 0);
|
|
135
|
+
assert.ok(result.boards.length > 0);
|
|
136
|
+
});
|
|
137
|
+
(0, node_test_1.it)('should apply kerf allowance', () => {
|
|
138
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
139
|
+
const resultNoKerf = (0, optimizer_1.optimizeCutList)(doc, { kerf: 0 });
|
|
140
|
+
const resultWithKerf = (0, optimizer_1.optimizeCutList)(doc, { kerf: 0.125 });
|
|
141
|
+
// Both should produce valid results
|
|
142
|
+
assert.ok(resultNoKerf.overallEfficiency > 0);
|
|
143
|
+
assert.ok(resultWithKerf.overallEfficiency > 0);
|
|
144
|
+
// With kerf, used area will be slightly higher due to kerf added to dimensions
|
|
145
|
+
// Both should place all parts
|
|
146
|
+
assert.strictEqual(resultNoKerf.unplacedParts.length, 0);
|
|
147
|
+
assert.strictEqual(resultWithKerf.unplacedParts.length, 0);
|
|
148
|
+
});
|
|
149
|
+
(0, node_test_1.it)('should place parts on sheets', () => {
|
|
150
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
151
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
152
|
+
// All 3 parts should be placed
|
|
153
|
+
const totalPlacedParts = result.sheets.reduce((sum, s) => sum + s.parts.length, 0);
|
|
154
|
+
assert.strictEqual(totalPlacedParts, 3);
|
|
155
|
+
});
|
|
156
|
+
(0, node_test_1.it)('should calculate waste percentage', () => {
|
|
157
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
158
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
159
|
+
assert.ok(result.wastePercentage >= 0);
|
|
160
|
+
assert.ok(result.wastePercentage <= 100);
|
|
161
|
+
assert.strictEqual(result.overallEfficiency + result.wastePercentage, 100);
|
|
162
|
+
});
|
|
163
|
+
(0, node_test_1.it)('should use standard sheet size', () => {
|
|
164
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
165
|
+
const result = (0, optimizer_1.optimizeCutList)(doc, { sheetSize: '4x8' });
|
|
166
|
+
for (const sheet of result.sheets) {
|
|
167
|
+
assert.strictEqual(sheet.sheetWidth, optimizer_1.STANDARD_SHEET_SIZES['4x8'].width);
|
|
168
|
+
assert.strictEqual(sheet.sheetLength, optimizer_1.STANDARD_SHEET_SIZES['4x8'].length);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
(0, node_test_1.it)('should report total sheets needed', () => {
|
|
172
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
173
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
174
|
+
assert.strictEqual(result.totalSheets, result.sheets.length);
|
|
175
|
+
});
|
|
176
|
+
(0, node_test_1.it)('should report total boards by length', () => {
|
|
177
|
+
const doc = (0, index_1.parseAndResolve)(BOARD_PROJECT);
|
|
178
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
179
|
+
const totalFromSummary = result.totalBoards.reduce((sum, b) => sum + b.count, 0);
|
|
180
|
+
assert.strictEqual(totalFromSummary, result.boards.length);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
(0, node_test_1.describe)('formatOptimizationResult', () => {
|
|
184
|
+
(0, node_test_1.it)('should format sheet optimization', () => {
|
|
185
|
+
const doc = (0, index_1.parseAndResolve)(SHEET_PROJECT);
|
|
186
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
187
|
+
const formatted = (0, optimizer_1.formatOptimizationResult)(result);
|
|
188
|
+
assert.ok(formatted.includes('CUT LIST OPTIMIZATION'));
|
|
189
|
+
assert.ok(formatted.includes('SHEET GOODS'));
|
|
190
|
+
assert.ok(formatted.includes('Total sheets needed'));
|
|
191
|
+
assert.ok(formatted.includes('Efficiency'));
|
|
192
|
+
});
|
|
193
|
+
(0, node_test_1.it)('should format board optimization', () => {
|
|
194
|
+
const doc = (0, index_1.parseAndResolve)(BOARD_PROJECT);
|
|
195
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
196
|
+
const formatted = (0, optimizer_1.formatOptimizationResult)(result);
|
|
197
|
+
assert.ok(formatted.includes('DIMENSIONAL LUMBER'));
|
|
198
|
+
assert.ok(formatted.includes('Board #'));
|
|
199
|
+
});
|
|
200
|
+
(0, node_test_1.it)('should include summary', () => {
|
|
201
|
+
const doc = (0, index_1.parseAndResolve)(MIXED_PROJECT);
|
|
202
|
+
const result = (0, optimizer_1.optimizeCutList)(doc);
|
|
203
|
+
const formatted = (0, optimizer_1.formatOptimizationResult)(result);
|
|
204
|
+
assert.ok(formatted.includes('SUMMARY'));
|
|
205
|
+
assert.ok(formatted.includes('Overall efficiency'));
|
|
206
|
+
assert.ok(formatted.includes('Waste'));
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
(0, node_test_1.describe)('STANDARD_SHEET_SIZES', () => {
|
|
210
|
+
(0, node_test_1.it)('should have common sizes', () => {
|
|
211
|
+
assert.ok(optimizer_1.STANDARD_SHEET_SIZES['4x8']);
|
|
212
|
+
assert.ok(optimizer_1.STANDARD_SHEET_SIZES['4x4']);
|
|
213
|
+
assert.strictEqual(optimizer_1.STANDARD_SHEET_SIZES['4x8'].width, 48);
|
|
214
|
+
assert.strictEqual(optimizer_1.STANDARD_SHEET_SIZES['4x8'].length, 96);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
(0, node_test_1.describe)('STANDARD_BOARD_LENGTHS', () => {
|
|
218
|
+
(0, node_test_1.it)('should have common lengths', () => {
|
|
219
|
+
assert.ok(optimizer_1.STANDARD_BOARD_LENGTHS.includes(96)); // 8'
|
|
220
|
+
assert.ok(optimizer_1.STANDARD_BOARD_LENGTHS.includes(120)); // 10'
|
|
221
|
+
assert.ok(optimizer_1.STANDARD_BOARD_LENGTHS.includes(144)); // 12'
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
//# sourceMappingURL=optimizer.test.js.map
|