task(CAD-1): associative dimensioning - DimStyles (ISO-25/50/Arch/Engineering), 5 dimension types (linear H/V, aligned, angular, radius, diameter), computed values, full primitives with arrows + extension lines
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
* - arc-Winkel in Grad, 0° = 3 Uhr, gegen den Uhrzeigersinn
|
||||
*/
|
||||
import type { CADElement } from '../../types/cad.types';
|
||||
import { getDimStyle } from '../../services/dimStyleService';
|
||||
import type { Pt } from '../../tools/modification/geometry';
|
||||
|
||||
/** Zeichenprimitiv — kleinste darstellbare Einheit. */
|
||||
@@ -42,6 +43,29 @@ function fillOrNull(raw: unknown): string | null {
|
||||
* Gibt ein leeres Array zurück für unbekannte Typen bzw. Elemente,
|
||||
* die nichts Sichtbares beitragen (z.B. leerer Text).
|
||||
*/
|
||||
/**
|
||||
* Pfeilspitze als geschlossenes Polygon (Task CAD-1).
|
||||
* Spitze bei (x,y), Richtung ang (rad), Laenge size.
|
||||
*/
|
||||
function arrowPrimitives(x: number, y: number, ang: number, size: number, color: string): ShapePrimitive[] {
|
||||
const halfW = size * 0.35;
|
||||
const bx = x - size * Math.cos(ang);
|
||||
const by = y - size * Math.sin(ang);
|
||||
const px = -Math.sin(ang) * halfW;
|
||||
const py = Math.cos(ang) * halfW;
|
||||
return [{
|
||||
kind: 'polyline',
|
||||
points: [
|
||||
{ x, y },
|
||||
{ x: bx + px, y: by + py },
|
||||
{ x: bx - px, y: by - py },
|
||||
],
|
||||
close: true,
|
||||
stroke: color,
|
||||
strokeWidth: 1,
|
||||
}];
|
||||
}
|
||||
|
||||
export function elementToPrimitives(el: CADElement, attrDefs?: Array<{ tag: string; prompt: string; defaultValue?: string }>): ShapePrimitive[] {
|
||||
const props = (el.properties ?? {}) as Record<string, unknown>;
|
||||
const stroke = (props.stroke as string | undefined) ?? FALLBACK_STROKE;
|
||||
@@ -133,25 +157,75 @@ export function elementToPrimitives(el: CADElement, attrDefs?: Array<{ tag: stri
|
||||
// ── Task C3: bisher im Pixi-Pfad fehlende Typen ──
|
||||
|
||||
case 'dimension': {
|
||||
// Legacy-Konvention: x1..y2 in properties, BBox-Zentrum als x/y,
|
||||
// Extension lines + Hauptlinie; Pfeilspitzen sind Detail (C3+)
|
||||
// Task CAD-1: komplette Bemassung mit Extension lines, Masslinie,
|
||||
// Pfeilspitzen (geschlossene Polygone) und Wert-Text nach DimStyle.
|
||||
const dimType = (props.dimType as string | undefined) ?? 'linear';
|
||||
const style = getDimStyle(props.dimStyle as string | undefined);
|
||||
const dimColor = (props.dimColor as string | undefined) ?? (props.color as string | undefined) ?? '#aaaaaa';
|
||||
const label = String(props.value ?? props.text ?? '');
|
||||
|
||||
if (dimType === 'radius' || dimType === 'diameter') {
|
||||
const cx = (props.centerX as number | undefined) ?? el.x;
|
||||
const cy = (props.centerY as number | undefined) ?? el.y;
|
||||
const ax = (props.arrowX as number | undefined) ?? cx + el.width / 2;
|
||||
const ay = (props.arrowY as number | undefined) ?? cy;
|
||||
const out: ShapePrimitive[] = [
|
||||
{ kind: 'line', from: { x: cx, y: cy }, to: { x: ax, y: ay }, stroke: dimColor, strokeWidth: 1 },
|
||||
];
|
||||
out.push(...arrowPrimitives(ax, ay, Math.atan2(ay - cy, ax - cx), style.arrowSize, dimColor));
|
||||
if (label) {
|
||||
out.push({ kind: 'text', at: { x: (cx + ax) / 2, y: (cy + ay) / 2 - style.textHeight * 0.6 }, text: label, fontSize: style.textHeight * 4, color: dimColor });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
if (dimType === 'angular') {
|
||||
const vx = (props.vertexX as number | undefined) ?? el.x;
|
||||
const vy = (props.vertexY as number | undefined) ?? el.y;
|
||||
const l1x = (props.leg1X as number | undefined) ?? vx + 100;
|
||||
const l1y = (props.leg1Y as number | undefined) ?? vy;
|
||||
const l2x = (props.leg2X as number | undefined) ?? vx;
|
||||
const l2y = (props.leg2Y as number | undefined) ?? vy + 100;
|
||||
const out: ShapePrimitive[] = [
|
||||
{ kind: 'line', from: { x: vx, y: vy }, to: { x: l1x, y: l1y }, stroke: dimColor, strokeWidth: 1 },
|
||||
{ kind: 'line', from: { x: vx, y: vy }, to: { x: l2x, y: l2y }, stroke: dimColor, strokeWidth: 1 },
|
||||
];
|
||||
if (label) {
|
||||
out.push({ kind: 'text', at: { x: vx + 30, y: vy - 10 }, text: label, fontSize: style.textHeight * 4, color: dimColor });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// linear / aligned
|
||||
const x1 = (props.x1 as number | undefined) ?? el.x - el.width / 2;
|
||||
const y1 = (props.y1 as number | undefined) ?? el.y;
|
||||
const x2 = (props.x2 as number | undefined) ?? el.x + el.width / 2;
|
||||
const y2 = (props.y2 as number | undefined) ?? el.y;
|
||||
const color = (props.color as string | undefined) ?? '#aaaaaa';
|
||||
const dimColor = (props.dimColor as string | undefined) ?? color;
|
||||
const label = String(props.value ?? props.text ?? '');
|
||||
const subtype = (props.dimSubtype as string | undefined) ?? 'horizontal';
|
||||
|
||||
// Masslinie: bei horizontal bei y = min(y1,y2) - offset; vertical bei x analog
|
||||
const off = 15;
|
||||
let mx1 = x1, my1 = y1, mx2 = x2, my2 = y2;
|
||||
if (subtype === 'horizontal') { my1 = Math.min(y1, y2) - off; my2 = my1; }
|
||||
else if (subtype === 'vertical') { mx1 = Math.min(x1, x2) - off; mx2 = mx1; }
|
||||
else { /* aligned: Masslinie = Punkte-Verbindung */ }
|
||||
|
||||
const out: ShapePrimitive[] = [
|
||||
{ kind: 'line', from: { x: x1, y: y1 }, to: { x: x2, y: y2 }, stroke: dimColor, strokeWidth: 1 },
|
||||
// Extension lines
|
||||
{ kind: 'line', from: { x: x1, y: y1 }, to: { x: x1, y: my1 }, stroke: '#888888', strokeWidth: 0.5 },
|
||||
{ kind: 'line', from: { x: x2, y: y2 }, to: { x: x2, y: my2 }, stroke: '#888888', strokeWidth: 0.5 },
|
||||
// Masslinie
|
||||
{ kind: 'line', from: { x: mx1, y: my1 }, to: { x: mx2, y: my2 }, stroke: dimColor, strokeWidth: 1 },
|
||||
];
|
||||
// Pfeilspitzen an beiden Enden der Masslinie
|
||||
const ang1 = Math.atan2(my2 - my1, mx2 - mx1);
|
||||
out.push(...arrowPrimitives(mx1, my1, ang1, style.arrowSize, dimColor));
|
||||
out.push(...arrowPrimitives(mx2, my2, ang1 + Math.PI, style.arrowSize, dimColor));
|
||||
if (label) {
|
||||
out.push({
|
||||
kind: 'text',
|
||||
at: { x: (x1 + x2) / 2, y: (y1 + y2) / 2 - 12 },
|
||||
text: label,
|
||||
fontSize: 10,
|
||||
color: dimColor,
|
||||
at: { x: (mx1 + mx2) / 2, y: (my1 + my2) / 2 - style.textHeight * 0.6 },
|
||||
text: label, fontSize: style.textHeight * 4, color: dimColor,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
|
||||
Reference in New Issue
Block a user