Files
web-cad/frontend/src/plugins/builtin/core-measure/index.ts
T

126 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* core-measure Built-in V2-Plugin (Task A4.5).
*
* measure: 2 Klicks → Distanz+Winkel-Anzeige im Status. KEIN Element-Commit
* (Legacy-Verhalten getreu — Messung ist Information, keine Zeichnung).
* Distanzformatierung via bestehendem formatDistance(unit, scaleFactor).
*/
import type { PluginV2, ToolExtensionV2, FullToolContext } from '../../types';
import { formatDistance, formatArea } from '../../../utils/format';
import { polygonArea } from '../../../tools/modification/geometry';
type MeasurePhase = 0 | 1; // 0=wartet auf Start, 1=wartet auf Ende
let measureStart: import('../../../tools/modification/geometry').Pt | null = null;
export const measureTool: ToolExtensionV2 = {
manifest: {
id: 'measure',
label: 'Messen',
icon: '\u2194',
ribbonTab: 'view',
tags: ['basic'],
description: 'Distanz und Winkel zwischen zwei Punkten messen',
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!measureStart) {
measureStart = e.world;
ctx.setStatus('Messung: Endpunkt klicken');
return;
}
// Zweiter Klick → anzeigen (Legacy-Ausgabeformat)
const rawDist = Math.hypot(e.world.x - measureStart.x, e.world.y - measureStart.y);
const angle = (Math.atan2(e.world.y - measureStart.y, e.world.x - measureStart.x) * 180) / Math.PI;
const unit = (c.options.unit as string | undefined) ?? 'mm';
const scale = (c.options.scaleFactor as number | undefined) ?? 1;
const distStr = formatDistance(rawDist, unit as never, scale);
ctx.setStatus(`distance: ${distStr} angle: ${angle.toFixed(1)}\u00b0`);
measureStart = null;
},
cancel(ctx) {
measureStart = null;
ctx.setStatus('Messung abgebrochen');
},
},
};
/** V2-Plugin: Messwerkzeuge. */
// ─────────────────────────────────────────────────────────────
// Task H5: measure-area — Polygon-Fläche messen (Status-only).
// Klick: Punkt hinzufügen; ENTER: committet Fläche ab 3 Punkten;
// ESC/Rechtsklick: Abbruch. Kein Element-Commit (wie measure).
// ─────────────────────────────────────────────────────────────
let areaPts: Array<{ x: number; y: number }> = [];
export const measureAreaTool: ToolExtensionV2 = {
manifest: {
id: 'measure-area',
label: 'Fläche messen',
icon: '\u25a9',
ribbonTab: 'canvas',
tags: ['basic'],
description: 'Polygon-Fläche messen: Punkte klicken, ENTER schließt ab',
},
optionsSchema: [
{ key: 'unit', label: 'Einheit', type: 'select', options: [
{ value: 'mm', label: 'mm' }, { value: 'cm', label: 'cm' }, { value: 'm', label: 'm' },
] },
{ key: 'scaleFactor', label: 'Maßstab (Welt→mm)', type: 'number' },
],
handlers: {
down(e, ctx) {
areaPts.push({ x: e.world.x, y: e.world.y });
if (areaPts.length === 1) {
ctx.setStatus(`Flächenmessung gestartet (1 Punkt) — weitere Punkte klicken, ENTER schließt ab`);
} else if (areaPts.length >= 3) {
const unit = (ctx.options.unit as string | undefined) ?? 'mm';
const scale = (ctx.options.scaleFactor as number | undefined) ?? 1;
ctx.setStatus(`Fläche: ${formatArea(polygonArea(areaPts), unit as never, scale)} — weiter klicken oder ENTER`);
} else {
ctx.setStatus(`${areaPts.length} Punkte — mindestens 3 benötigt, weitere Punkte klicken`);
}
},
move(e, ctx) {
if (areaPts.length < 2) return;
const probe = [...areaPts, { x: e.world.x, y: e.world.y }];
if (probe.length < 3) return;
const unit = (ctx.options.unit as string | undefined) ?? 'mm';
const scale = (ctx.options.scaleFactor as number | undefined) ?? 1;
ctx.setStatus(`Fläche: ${formatArea(polygonArea(probe), unit as never, scale)}`);
},
key(k, ctx) {
if (k.key === 'Enter' || k.key === 'ENTER') {
if (areaPts.length >= 3) {
const unit = (ctx.options.unit as string | undefined) ?? 'mm';
const scale = (ctx.options.scaleFactor as number | undefined) ?? 1;
ctx.setStatus(`Flächenmessung: ${formatArea(polygonArea(areaPts), unit as never, scale)} (${areaPts.length} Punkte)`);
areaPts = [];
} else {
ctx.setStatus(`Flächenmessung benötigt mindestens 3 Punkte (aktuell ${areaPts.length})`);
}
return true; // ENTER konsumiert
}
return false;
},
cancel(ctx) {
areaPts = [];
ctx.setStatus('Flächenmessung abgebrochen');
},
},
};
export const coreMeasurePlugin: PluginV2 = {
manifest: {
id: 'core-measure',
name: 'Messen (Kern)',
version: '1.0.0',
author: 'web-cad team',
description: 'Abstandswinkel-Messung ohne Element-Erzeugung.',
category: 'tools',
enabledByDefault: true,
},
tools: [measureTool, measureAreaTool],
};