wip
This commit is contained in:
commit
d8f2407ddf
44 changed files with 10377 additions and 0 deletions
78
src/lib/cut-list.ts
Normal file
78
src/lib/cut-list.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import type {
|
||||
FlooringPiece,
|
||||
FlooringPlan,
|
||||
FlooringSettings,
|
||||
SkirtingPiece,
|
||||
SkirtingPlan,
|
||||
} from './types';
|
||||
|
||||
const sameLength = (a: number, b: number) => Math.abs(a - b) < 0.01;
|
||||
|
||||
/** A ready offcut still needs a placement code; only fresh, uncut whole boards are omitted. */
|
||||
export const flooringCuts = (plan: FlooringPlan) =>
|
||||
plan.pieces.filter((piece) => piece.cut || piece.reused);
|
||||
|
||||
export function isSkirtingCut(piece: SkirtingPiece, plan: SkirtingPlan): boolean {
|
||||
const stock = plan.stocks.find((candidate) => candidate.id === piece.stockId);
|
||||
return (
|
||||
!stock ||
|
||||
!sameLength(piece.length, stock.length) ||
|
||||
Math.abs(piece.leftMitre) > 0.001 ||
|
||||
Math.abs(piece.rightMitre) > 0.001
|
||||
);
|
||||
}
|
||||
|
||||
export const skirtingCuts = (plan: SkirtingPlan) =>
|
||||
plan.pieces.filter((piece) => isSkirtingCut(piece, plan));
|
||||
|
||||
export function uncutFlooring(plan: FlooringPlan, settings: FlooringSettings) {
|
||||
const uncut = plan.pieces.filter((piece) => !piece.cut);
|
||||
const wholeBoards = uncut.filter(
|
||||
(piece) => sameLength(piece.length, settings.length) && sameLength(piece.width, settings.width),
|
||||
).length;
|
||||
return { wholeBoards, readyOffcuts: uncut.length - wholeBoards };
|
||||
}
|
||||
|
||||
export function uncutSkirting(plan: SkirtingPlan): { length: number; count: number }[] {
|
||||
const counts = new Map<number, number>();
|
||||
for (const piece of plan.pieces) {
|
||||
if (!isSkirtingCut(piece, plan)) counts.set(piece.length, (counts.get(piece.length) ?? 0) + 1);
|
||||
}
|
||||
return [...counts].sort(([a], [b]) => a - b).map(([length, count]) => ({ length, count }));
|
||||
}
|
||||
|
||||
/** Ready remnants need placement instructions, never another trimming instruction. */
|
||||
export function readyOffcutInstructions(piece: FlooringPiece): string {
|
||||
const ends =
|
||||
piece.factoryLeft && piece.factoryRight
|
||||
? 'both'
|
||||
: piece.factoryLeft
|
||||
? 'left'
|
||||
: piece.factoryRight
|
||||
? 'right'
|
||||
: 'neither';
|
||||
return `Use offcut; no new cut. Required factory short ends: ${ends}.`;
|
||||
}
|
||||
|
||||
/** Batch identical cuts without losing any placement codes or changing factory-edge orientation. */
|
||||
export function groupFlooringCuts(plan: FlooringPlan): FlooringPiece[][] {
|
||||
const groups = new Map<string, FlooringPiece[]>();
|
||||
const precise = (value: number) => Math.round(value * 1000);
|
||||
for (const piece of flooringCuts(plan)) {
|
||||
const key = JSON.stringify([
|
||||
piece.roomId,
|
||||
precise(piece.length),
|
||||
precise(piece.width),
|
||||
piece.shaped,
|
||||
piece.cut,
|
||||
piece.factoryLeft,
|
||||
piece.factoryRight,
|
||||
piece.ripEdge,
|
||||
piece.shaped ? piece.template.map((point) => [precise(point.x), precise(point.y)]) : null,
|
||||
]);
|
||||
const group = groups.get(key);
|
||||
if (group) group.push(piece);
|
||||
else groups.set(key, [piece]);
|
||||
}
|
||||
return [...groups.values()];
|
||||
}
|
||||
Loading…
Reference in a new issue