From f371ab0026186d243899e04f30638afe41e05482 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 5 Apr 2024 10:49:55 -0500 Subject: [PATCH] feat: Add support for extra space on top and right sides of panels --- npm/src/geometry.ts | 16 ++++++++++------ npm/src/index.ts | 13 +++++++------ npm/src/types.ts | 4 ++++ npm/src/units.ts | 7 ++++++- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/npm/src/geometry.ts b/npm/src/geometry.ts index 56cd4a5..0cad24b 100644 --- a/npm/src/geometry.ts +++ b/npm/src/geometry.ts @@ -135,11 +135,15 @@ export interface Point { export class BoardLayouter { readonly placements: Rectangle[] = []; + private readonly paddedStock: Rectangle; constructor( readonly stock: Rectangle, readonly config: Config, - ) {} + ) { + const padding = -new Distance(config.extraSpace).m; + this.paddedStock = stock.pad({ right: padding, top: padding }); + } tryAddPart(part: PartToCut): boolean { if (part.material !== this.stock.data.material) return false; @@ -161,7 +165,7 @@ export class BoardLayouter { const possiblePositions: Point[] = this.placements.length === 0 ? // Always position bottom left when empty - [{ x: this.stock.x, y: this.stock.y }] + [{ x: this.paddedStock.x, y: this.paddedStock.y }] : // Get possible locations from callback getPossiblePositions(); @@ -172,7 +176,7 @@ export class BoardLayouter { ) .find( (placement) => - placement.isInside(this.stock) && + placement.isInside(this.paddedStock) && this.placements.every((p) => !placement.isIntersecting(p)), ); @@ -191,9 +195,9 @@ export class BoardLayouter { const bladeWidth = new Distance(this.config.bladeWidth).m; return [ // Left of stock and top of existing - { x: this.stock.x, y: existing.top + bladeWidth }, + { x: this.paddedStock.x, y: existing.top + bladeWidth }, // left of existing, bottom of stock - { x: existing.right + bladeWidth, y: this.stock.y }, + { x: existing.right + bladeWidth, y: this.paddedStock.y }, // Left of existing, top of other existing ...this.placements.map((existing2) => ({ @@ -262,7 +266,7 @@ export class BoardLayouter { reduceStock(allStock: Rectangle[]): BoardLayouter { const validStock = allStock.filter( - (stock) => stock.data.material === this.stock.data.material, + (stock) => stock.data.material === this.paddedStock.data.material, ); const validLayouts = validStock .map((stock) => { diff --git a/npm/src/index.ts b/npm/src/index.ts index 7b411aa..2281148 100644 --- a/npm/src/index.ts +++ b/npm/src/index.ts @@ -1,10 +1,10 @@ -import type { - PartToCut, - Stock, - StockMatrix, +import { + type PartToCut, + type Stock, + type StockMatrix, Config, - BoardLayout, - BoardLayoutLeftover, + type BoardLayout, + type BoardLayoutLeftover, } from './types'; import consola from 'consola'; import { BoardLayouter, Rectangle } from './geometry'; @@ -26,6 +26,7 @@ export function generateBoardLayouts( layouts: BoardLayout[]; leftovers: BoardLayoutLeftover[]; } { + config = Config.parse(config); consola.info('Generating board layouts...'); // Create geometry for stock and parts diff --git a/npm/src/types.ts b/npm/src/types.ts index ab060d5..dc85da9 100644 --- a/npm/src/types.ts +++ b/npm/src/types.ts @@ -80,6 +80,10 @@ export const Config = z.object({ * column, making it easier to cut out. */ optimize: z.union([z.literal('space'), z.literal('cuts')]).default('cuts'), + /** + * Extra padding to add to the top and right sides of the boards/stock. + */ + extraSpace: Distance.default('0'), }); export type Config = z.infer; diff --git a/npm/src/units.ts b/npm/src/units.ts index 8891a65..bc1306c 100644 --- a/npm/src/units.ts +++ b/npm/src/units.ts @@ -68,8 +68,13 @@ export class Distance { this.m = Number(v.replace('ft', '')) * 0.3048; } else if (v.endsWith('in') || v.endsWith('"')) { this.m = Number(v.replace(/(in|")/, '')) * 0.0254; + } else if (v.endsWith('mm')) { + this.m = Number(v.replace('mm', '')) / 1000; } else { - throw Error('Could not parse distance: ' + JSON.stringify(v)); + this.m = Number(v.replace('m', '')); + } + if (isNaN(this.m)) { + throw Error('Could not convert to meters: ' + v); } }