task(A4.10): migrate trim/extend/fillet to v2 + real CAD extend fallback

This commit is contained in:
Agent Zero
2026-08-27 01:21:44 +02:00
parent ebafcf0c65
commit 19f838fbf8
3 changed files with 271 additions and 7 deletions
@@ -21,6 +21,9 @@ import {
angleBetween,
distance,
offsetElement,
trimElement,
extendElement,
filletElements,
} from '../../../tools/modification/geometry';
import type { Pt } from '../../../tools/modification/geometry';
@@ -275,7 +278,105 @@ export const scaleTool: ToolExtensionV2 = makeTransformTool('scale');
export const mirrorTool: ToolExtensionV2 = makeTransformTool('mirror');
// ─────────────────────────────────────────────────────────────
// Delete (Task A4.8) — Portierung aus Legacy handleDeleteDown:
// Trim / Extend / Fillet (Task A4.10) — baut auf BUG-2-reparierter
// findIntersection-Geometrie (B2). Legacy-Ablauf:
// - trim/extend: Klick1=Boundary, Klick2=Ziel → Ziel wird angepasst
// - fillet: Klick1+Klick2 = zwei Elemente → Paar wird angepasst
// Jede Operation committed in EINER Transaktion.
// ─────────────────────────────────────────────────────────────
let twoPickBoundary: CADElement | null = null;
let twoPickFirst: CADElement | null = null;
function make2PickGeometryTool(
mode: 'trim' | 'extend' | 'fillet',
filletRadius: number,
): ToolExtensionV2 {
const labels = { trim: 'Trimmen', extend: 'Verlängern', fillet: 'Fillet' } as const;
return {
manifest: {
id: mode,
label: labels[mode],
icon: mode === 'fillet' ? '\u23dc' : '\u2717',
ribbonTab: 'canvas',
tags: ['pro'],
description: `${labels[mode]}: ${mode === 'fillet' ? 'zwei' : 'Kante, dann'} Element(e) anklicken`,
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc || !c.selection) return;
const hit = c.selection.hitTest(e.world.x, e.world.y, 5);
if (!hit) return;
if (mode === 'fillet') {
if (!twoPickFirst) {
twoPickFirst = hit;
ctx.setStatus(`Fillet: zweites Element wählen`);
return;
}
// Zweiter Pick → Paar-Commit
const second = hit;
const pair = filletElements(twoPickFirst, second, filletRadius);
if (!pair) {
ctx.setStatus('Fillet: kein Schnittpunkt gefunden');
twoPickFirst = null;
return;
}
const idA = twoPickFirst.id;
const idB = second.id;
c.doc.transact(() => {
c.doc!.updateElement(idA, {
x: pair[0].x, y: pair[0].y,
width: pair[0].width, height: pair[0].height,
properties: pair[0].properties,
});
c.doc!.updateElement(idB, {
x: pair[1].x, y: pair[1].y,
width: pair[1].width, height: pair[1].height,
properties: pair[1].properties,
});
});
ctx.setStatus(`Fillet angewendet (${idA}, ${idB})`);
twoPickFirst = null;
return;
}
// trim/extend: Boundary dann Ziel
if (!twoPickBoundary) {
twoPickBoundary = hit;
ctx.setStatus(`${labels[mode]}: jetzt das zu bearbeitende Element wählen`);
return;
}
const target = hit;
const fn = mode === 'trim' ? trimElement : extendElement;
const result = fn(target, twoPickBoundary);
if (!result) {
ctx.setStatus(`${labels[mode]}: keine Schnittmenge mit der Kante`);
twoPickBoundary = null;
return;
}
c.doc.transact(() => {
c.doc!.updateElement(target.id, {
x: result.x, y: result.y,
width: result.width, height: result.height,
properties: result.properties,
});
});
ctx.setStatus(`${labels[mode]} auf ${target.id} angewendet`);
twoPickBoundary = null;
},
cancel(ctx) {
twoPickBoundary = null;
twoPickFirst = null;
ctx.setStatus(`${labels[mode]} abgebrochen`);
},
},
};
}
export const trimTool: ToolExtensionV2 = make2PickGeometryTool('trim', 0);
export const extendTool: ToolExtensionV2 = make2PickGeometryTool('extend', 0);
export const filletTool: ToolExtensionV2 = make2PickGeometryTool('fillet', 5);
// Einzelnklick auf Element löscht es sofort (kein up/Bestätigung).
// Jetzt via doc.deleteElements → undo-fähig.
// ─────────────────────────────────────────────────────────────
@@ -369,11 +470,11 @@ export const coreModifyPlugin: PluginV2 = {
manifest: {
id: 'core-modify',
name: 'Bearbeiten (Kern)',
version: '1.4.0',
version: '1.5.0',
author: 'web-cad team',
description: 'Auswahl, Schraffur, Verschieben, Kopieren, Rotieren, Skalieren, Spiegeln, Löschen, Versatz (V2).',
description: 'Auswahl, Schraffur, Move/Copy/Rotate/Scale/Mirror/Delete/Offset/Trim/Extend/Fillet (V2).',
category: 'tools',
enabledByDefault: true,
},
tools: [selectTool, hatchTool, moveTool, copyTool, rotateTool, scaleTool, mirrorTool, deleteTool, offsetTool],
tools: [selectTool, hatchTool, moveTool, copyTool, rotateTool, scaleTool, mirrorTool, deleteTool, offsetTool, trimTool, extendTool, filletTool],
};