task(D3): construction tools - point placer, xline (bidirectional), ray (unidirectional) on auto-created defpoints layer with construction tags

This commit is contained in:
Agent Zero
2026-08-29 03:17:38 +02:00
parent 1664404948
commit bfd500bbc2
3 changed files with 383 additions and 2 deletions
@@ -112,6 +112,11 @@ export class CADDocument {
}
/** Fügt einen Layer hinzu (überschreibt gleiche ID, kein Undo-Schritt). */
addLayer(layer: CADLayer): void {
this.ydoc.data.layers.set(layer.id, layer);
}
/**
* Ersetzt das komplette Layer-Set (Task H2: Projekt-Templates).
* Bestehende Layer werden entfernt, Template-Layer übernommen.
@@ -662,15 +662,244 @@ export const splineTool: ToolExtensionV2 = {
},
};
// ─────────────────────────────────────────────────────────────
// Task D3: Point/XLine/Ray — Konstruktions-Elemente auf defpoints.
// ─────────────────────────────────────────────────────────────
/** Auto-Anlegen des defpoints-Layers (Task D3) falls fehlt. */
function ensureDefpointsLayer(ctx: FullToolContext): void {
const doc = ctx.doc as unknown as {
getLayer(id: string): unknown;
addLayer(l: unknown): void;
} | undefined;
if (!doc || doc.getLayer('defpoints')) return;
doc.addLayer({
id: 'defpoints',
name: 'defpoints',
visible: true,
locked: false,
color: '#8a8f98',
lineType: 'dotted',
transparency: 0.5,
sortOrder: 999,
parentId: null,
});
}
/** Konstruktions-Element-Basis-Props (construction-Tags, Task D3). */
function constructionProps(): Record<string, unknown> {
return { stroke: '#8a8f98', strokeWidth: 1, construction: true };
}
export const pointTool: ToolExtensionV2 = {
manifest: {
id: 'point',
label: 'Punkt',
icon: '\u2022',
ribbonTab: 'canvas',
tags: ['basic'],
description: 'Konstruktionspunkt platzieren (defpoints-Layer)',
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc) return;
ensureDefpointsLayer(c);
const r = 1.5;
const el: CADElement = {
id: uid('point'),
type: 'circle',
layerId: 'defpoints',
x: e.world.x,
y: e.world.y,
width: r * 2,
height: r * 2,
properties: { ...constructionProps(), radius: r, point: true },
} as unknown as CADElement;
c.doc.transact(() => c.doc!.addElement(el));
ctx.setStatus(`Punkt platziert (${el.id})`);
},
},
};
/** XLine: sehr lange Linie in BEIDE Richtungen um den Basispunkt. */
let xlineBase: Pt | null = null;
export const xlineTool: ToolExtensionV2 = {
manifest: {
id: 'xline',
label: 'Konstruktionslinie',
icon: '\u2194',
ribbonTab: 'canvas',
tags: ['basic'],
description: 'Unendliche Konstruktionslinie: Basispunkt + Richtung klicken',
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc) return;
if (!xlineBase) {
xlineBase = e.world;
ctx.setStatus('Konstruktionslinie: Basis gesetzt Richtung klicken');
return;
}
ensureDefpointsLayer(c);
const dx = e.world.x - xlineBase.x;
const dy = e.world.y - xlineBase.y;
const len = Math.hypot(dx, dy);
if (len < 0.001) { xlineBase = null; return; }
const ux = dx / len, uy = dy / len;
const L = 100000;
const el: CADElement = {
id: uid('xline'),
type: 'line',
layerId: 'defpoints',
x: xlineBase.x,
y: xlineBase.y,
width: 0,
height: 0,
properties: {
...constructionProps(),
x1: xlineBase.x - ux * L,
y1: xlineBase.y - uy * L,
x2: xlineBase.x + ux * L,
y2: xlineBase.y + uy * L,
},
} as unknown as CADElement;
c.doc.transact(() => c.doc!.addElement(el));
xlineBase = null;
ctx.setPreview?.(null);
ctx.setStatus(`Konstruktionslinie erstellt (${el.id})`);
},
move(e, ctx) {
const c = ctx as FullToolContext;
if (!xlineBase) return;
const dx = e.world.x - xlineBase.x;
const dy = e.world.y - xlineBase.y;
const len = Math.hypot(dx, dy);
if (len < 0.001) return;
const ux = dx / len, uy = dy / len;
const L = 100000;
ctx.setPreview?.({
id: '__preview_xline__',
type: 'line',
layerId: 'defpoints',
x: xlineBase.x,
y: xlineBase.y,
width: 0,
height: 0,
properties: {
...constructionProps(),
x1: xlineBase.x - ux * L,
y1: xlineBase.y - uy * L,
x2: xlineBase.x + ux * L,
y2: xlineBase.y + uy * L,
},
} as unknown as CADElement);
},
cancel(ctx) {
xlineBase = null;
ctx.setPreview?.(null);
ctx.setStatus('Konstruktionslinie abgebrochen');
},
},
};
/** Ray: Linie ab Basispunkt NUR in Klickrichtung. */
let rayBase: Pt | null = null;
export const rayTool: ToolExtensionV2 = {
manifest: {
id: 'ray',
label: 'Strahl',
icon: '\u2192',
ribbonTab: 'canvas',
tags: ['basic'],
description: 'Strahl ab Basispunkt in Klickrichtung',
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc) return;
if (!rayBase) {
rayBase = e.world;
ctx.setStatus('Strahl: Basis gesetzt Richtung klicken');
return;
}
ensureDefpointsLayer(c);
const dx = e.world.x - rayBase.x;
const dy = e.world.y - rayBase.y;
const len = Math.hypot(dx, dy);
if (len < 0.001) { rayBase = null; return; }
const ux = dx / len, uy = dy / len;
const L = 100000;
const el: CADElement = {
id: uid('ray'),
type: 'line',
layerId: 'defpoints',
x: rayBase.x,
y: rayBase.y,
width: 0,
height: 0,
properties: {
...constructionProps(),
x1: rayBase.x,
y1: rayBase.y,
x2: rayBase.x + ux * L,
y2: rayBase.y + uy * L,
},
} as unknown as CADElement;
c.doc.transact(() => c.doc!.addElement(el));
rayBase = null;
ctx.setPreview?.(null);
ctx.setStatus(`Strahl erstellt (${el.id})`);
},
move(e, ctx) {
const c = ctx as FullToolContext;
if (!rayBase) return;
const dx = e.world.x - rayBase.x;
const dy = e.world.y - rayBase.y;
const len = Math.hypot(dx, dy);
if (len < 0.001) return;
const ux = dx / len, uy = dy / len;
const L = 100000;
ctx.setPreview?.({
id: '__preview_ray__',
type: 'line',
layerId: 'defpoints',
x: rayBase.x,
y: rayBase.y,
width: 0,
height: 0,
properties: {
...constructionProps(),
x1: rayBase.x,
y1: rayBase.y,
x2: rayBase.x + ux * L,
y2: rayBase.y + uy * L,
},
} as unknown as CADElement);
},
cancel(ctx) {
rayBase = null;
ctx.setPreview?.(null);
ctx.setStatus('Strahl abgebrochen');
},
},
};
export const coreDrawingPlugin: PluginV2 = {
manifest: {
id: 'core-drawing',
name: 'Zeichnen (Kern)',
version: '1.4.0',
version: '1.5.0',
author: 'web-cad team',
description: 'Zeichenwerkzeuge V2: Linie, Rechteck, Kreis, Bogen, Polylinie, Polygon, RevCloud.',
category: 'tools',
enabledByDefault: true,
},
tools: [lineTool, rectTool, circleTool, arcTool, polylineTool, polygonTool, revcloudTool, ellipseTool, splineTool],
tools: [lineTool, rectTool, circleTool, arcTool, polylineTool, polygonTool, revcloudTool, ellipseTool, splineTool, pointTool, xlineTool, rayTool],
};