wip
This commit is contained in:
commit
d8f2407ddf
44 changed files with 10377 additions and 0 deletions
119
tests/cut-list.test.ts
Normal file
119
tests/cut-list.test.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { defaultProject } from '../src/lib/defaults';
|
||||
import { flooringCuts, groupFlooringCuts } from '../src/lib/cut-list';
|
||||
import { planFlooring } from '../src/lib/flooring';
|
||||
import type { FlooringPiece, FlooringPlan } from '../src/lib/types';
|
||||
|
||||
function piece(id: string, changes: Partial<FlooringPiece> = {}): FlooringPiece {
|
||||
return {
|
||||
id,
|
||||
roomId: 'room-1',
|
||||
row: 1,
|
||||
column: 1,
|
||||
polygon: [],
|
||||
length: 600,
|
||||
width: 190,
|
||||
stockId: 'B1',
|
||||
reused: false,
|
||||
cut: true,
|
||||
shaped: false,
|
||||
template: [],
|
||||
factoryLeft: true,
|
||||
factoryRight: false,
|
||||
ripEdge: null,
|
||||
...changes,
|
||||
};
|
||||
}
|
||||
function plan(pieces: FlooringPiece[]): FlooringPlan {
|
||||
return {
|
||||
pieces,
|
||||
rows: [],
|
||||
stocks: [],
|
||||
boardCount: 0,
|
||||
cuts: 0,
|
||||
wasteArea: 0,
|
||||
wastePercent: 0,
|
||||
reusedCount: 0,
|
||||
coveredArea: 0,
|
||||
issues: [],
|
||||
};
|
||||
}
|
||||
|
||||
describe('flooring cut batches', () => {
|
||||
it('combines matching cuts across rows and stocks, preserving every placement exactly once', () => {
|
||||
const pieces = [
|
||||
piece('F1'),
|
||||
piece('F2', { row: 4, stockId: 'B4', reused: true }),
|
||||
piece('F3', { cut: false, length: 1200 }),
|
||||
piece('F4', { cut: false, reused: true }),
|
||||
piece('F5', { roomId: 'room-2' }),
|
||||
];
|
||||
const source = plan(pieces),
|
||||
before = structuredClone(source);
|
||||
const groups = groupFlooringCuts(source);
|
||||
expect(groups.map((group) => group.map((p) => p.id))).toEqual([['F1', 'F2'], ['F4'], ['F5']]);
|
||||
expect(
|
||||
groups
|
||||
.flat()
|
||||
.map((p) => p.id)
|
||||
.sort(),
|
||||
).toEqual(
|
||||
flooringCuts(source)
|
||||
.map((p) => p.id)
|
||||
.sort(),
|
||||
);
|
||||
expect(source).toEqual(before);
|
||||
expect(groupFlooringCuts(source)).toEqual(groups);
|
||||
});
|
||||
|
||||
it('keeps different factory ends, rip edges and thousandth-millimetre dimensions separate', () => {
|
||||
const groups = groupFlooringCuts(
|
||||
plan([
|
||||
piece('F1'),
|
||||
piece('F2', { factoryLeft: false, factoryRight: true }),
|
||||
piece('F3', { ripEdge: 'top' }),
|
||||
piece('F4', { ripEdge: 'bottom' }),
|
||||
piece('F5', { length: 600.001 }),
|
||||
piece('F6', { width: 190.001 }),
|
||||
]),
|
||||
);
|
||||
expect(groups).toHaveLength(6);
|
||||
});
|
||||
|
||||
it('groups shapes only when their complete measured templates match', () => {
|
||||
const template = [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 600, y: 0 },
|
||||
{ x: 600, y: 190 },
|
||||
{ x: 0, y: 100 },
|
||||
];
|
||||
const groups = groupFlooringCuts(
|
||||
plan([
|
||||
piece('F1', { shaped: true, template }),
|
||||
piece('F2', { shaped: true, template: structuredClone(template) }),
|
||||
piece('F3', { shaped: true, template: [...template.slice(0, 3), { x: 0, y: 100.001 }] }),
|
||||
piece('F4'),
|
||||
]),
|
||||
);
|
||||
expect(groups.map((group) => group.map((p) => p.id))).toEqual([['F1', 'F2'], ['F3'], ['F4']]);
|
||||
});
|
||||
|
||||
it('reduces the default room to a few batches while keeping all cut and offcut codes', () => {
|
||||
const project = defaultProject();
|
||||
const floor = planFlooring(project.rooms, project.flooring, project.tolerance);
|
||||
const groups = groupFlooringCuts(floor);
|
||||
expect(groups.length).toBeLessThanOrEqual(7);
|
||||
expect(groups.length).toBeLessThan(flooringCuts(floor).length / 2);
|
||||
expect(
|
||||
groups
|
||||
.flat()
|
||||
.map((p) => p.id)
|
||||
.sort(),
|
||||
).toEqual(
|
||||
flooringCuts(floor)
|
||||
.map((p) => p.id)
|
||||
.sort(),
|
||||
);
|
||||
expect(new Set(groups.flat().map((p) => p.id)).size).toBe(flooringCuts(floor).length);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue