task(A4.10): migrate trim/extend/fillet to v2 + real CAD extend fallback
This commit is contained in:
@@ -482,7 +482,103 @@ describe('A4.6 pilot: move/copy tools', () => {
|
||||
expect(selIds2).toEqual(['auto']);
|
||||
move.handlers.down!(pe(30, 30), ctx); // Zielklick (Δ=+20)
|
||||
|
||||
expect(doc.getElement('auto')!.x).toBe(30); // 10+Δ20
|
||||
expect(doc.undo()).toBe(true);
|
||||
expect(doc.getAllElements().length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('A4.10 pilot: geometry tools', () => {
|
||||
function makeLineEl(id: string): CADElement {
|
||||
return {
|
||||
id,
|
||||
type: 'line',
|
||||
layerId: 'l',
|
||||
x: 100,
|
||||
y: 0,
|
||||
width: 200,
|
||||
height: 0,
|
||||
properties: { x1: 0, y1: 0, x2: 200, y2: 0 },
|
||||
} as unknown as CADElement;
|
||||
}
|
||||
|
||||
function makeCircleEl(id: string): CADElement {
|
||||
return {
|
||||
id,
|
||||
type: 'circle',
|
||||
layerId: 'l',
|
||||
x: 100,
|
||||
y: 0,
|
||||
width: 80,
|
||||
height: 80,
|
||||
properties: { radius: 40 },
|
||||
} as unknown as CADElement;
|
||||
}
|
||||
|
||||
it('trim: Kante+Ziel kürzt die Linie am Schnittpunkt; undo stellt her', () => {
|
||||
const { ydoc } = createInMemoryDoc();
|
||||
const doc = new CADDocument(ydoc);
|
||||
const boundary = makeCircleEl('bnd');
|
||||
const target = makeLineEl('tgt');
|
||||
doc.addElement(boundary);
|
||||
doc.addElement(target);
|
||||
|
||||
// Sequenzieller Brücken-HitTest: 1. Klick → boundary, 2. Klick → target
|
||||
const pickQueue = [boundary, target];
|
||||
let pickIdx = 0;
|
||||
const bridge = {
|
||||
getIds: () => [] as string[],
|
||||
setIds: () => {},
|
||||
hitTest: () => pickQueue[Math.min(pickIdx++, pickQueue.length - 1)],
|
||||
};
|
||||
const ctx = makeCtx({ doc, selection: bridge });
|
||||
const trim = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'trim')!;
|
||||
|
||||
trim.handlers.down!(pe(140, 0), ctx); // Kante
|
||||
trim.handlers.down!(pe(180, 0), ctx); // Ziel-Linie rechts vom Kreis
|
||||
|
||||
const trimmed = doc.getElement('tgt')!;
|
||||
expect(trimmed.properties.x2).toBeLessThan(200); // gekürzt
|
||||
// Legacy-Semantik: das NÄHERE Ende wird auf den ERSTEN Schnittpunkt
|
||||
// gesetzt (findIntersection wählt den nächsten zu p1 → x=60):
|
||||
expect(Math.abs(trimmed.properties.x2 as number)).toBeCloseTo(60); // Schnitt bei x=140
|
||||
|
||||
expect(doc.undo()).toBe(true);
|
||||
expect(doc.getElement('tgt')!.properties.x2).toBe(200);
|
||||
});
|
||||
|
||||
it('extend: Linie wird zur Kante hin verlängert', () => {
|
||||
const { ydoc } = createInMemoryDoc();
|
||||
const doc = new CADDocument(ydoc);
|
||||
// kurze Linie (10→50); Kreis (100,0,r=40) hat Schnitte bei x=60/140
|
||||
// → Extend muss das nahe Ende x2 auf 60 strecken
|
||||
const boundary = makeCircleEl('bnd');
|
||||
const shortLine = {
|
||||
id: 'sl', type: 'line', layerId: 'l', x: 30, y: 0,
|
||||
width: 40, height: 0,
|
||||
properties: { x1: 10, y1: 0, x2: 50, y2: 0 },
|
||||
} as unknown as CADElement;
|
||||
doc.addElement(boundary);
|
||||
doc.addElement(shortLine);
|
||||
|
||||
const pickQueue = [boundary, shortLine];
|
||||
let pickIdx = 0;
|
||||
const bridge = {
|
||||
getIds: () => [] as string[],
|
||||
setIds: () => {},
|
||||
hitTest: () => pickQueue[Math.min(pickIdx++, pickQueue.length - 1)],
|
||||
};
|
||||
const ctx = makeCtx({ doc, selection: bridge });
|
||||
const extend = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'extend')!;
|
||||
|
||||
extend.handlers.down!(pe(100, 40), ctx);
|
||||
extend.handlers.down!(pe(45, 0), ctx);
|
||||
|
||||
const ext = doc.getElement('sl')!;
|
||||
// Extend richtet das nahe Ende exakt auf den Schnittpunkt aus:
|
||||
expect(ext.properties.x2).toBeCloseTo(60);
|
||||
|
||||
expect(doc.undo()).toBe(true);
|
||||
expect(doc.getElement('sl')!.properties.x2).toBe(50); // Original-Länge
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user