DXF-Import: CIRCLE/ARC als echte glatte Kreis-/Bogen-Formen (statt tesselliertem Vieleck)

This commit is contained in:
2026-07-05 15:06:25 +02:00
parent 45e19b7293
commit 4ac99d37cb
7 changed files with 200 additions and 15 deletions
+46
View File
@@ -471,6 +471,52 @@ describe("textsToDrawings", () => {
});
});
describe("parseDxf — Kurven behalten echte Geometrie (curve)", () => {
it("CIRCLE trägt curve {kind:circle}", () => {
const c = onlyContour(dxf(circle(10, 20, 5, 4)));
expect(c.curve?.kind).toBe("circle");
expect(c.curve?.cx).toBeCloseTo(10, 9);
expect(c.curve?.cy).toBeCloseTo(20, 9);
expect(c.curve?.r).toBeCloseTo(4, 9);
});
it("ARC trägt curve {kind:arc} mit Winkeln (Radiant)", () => {
const c = onlyContour(dxf(arc(0, 0, 10, 0, 90)));
expect(c.curve?.kind).toBe("arc");
expect(c.curve?.r).toBeCloseTo(10, 9);
expect(c.curve?.a0).toBeCloseTo(0, 9);
expect(c.curve?.a1).toBeCloseTo(Math.PI / 2, 9);
});
});
describe("contoursToDrawings — Kurven → glatte Formen", () => {
it("curve circle → {shape:\"circle\"}", () => {
const set: ContourSet = {
id: "s", type: "contourSet", name: "c",
contours: [{ z: 0, closed: true, pts: [{ x: 0, y: 0 }], curve: { kind: "circle", cx: 1, cy: 2, r: 3, a0: 0, a1: Math.PI * 2 } }],
};
const [d] = contoursToDrawings([set], "lvl", "active", "C", (s) => s);
expect(d.geom.shape).toBe("circle");
if (d.geom.shape === "circle") {
expect(d.geom.r).toBeCloseTo(3, 9);
expect(d.geom.center.x).toBeCloseTo(1, 9);
}
});
it("curve arc → {shape:\"arc\"}", () => {
const set: ContourSet = {
id: "s", type: "contourSet", name: "c",
contours: [{ z: 0, closed: false, pts: [{ x: 0, y: 0 }], curve: { kind: "arc", cx: 0, cy: 0, r: 5, a0: 0, a1: 1 } }],
};
const [d] = contoursToDrawings([set], "lvl", "active", "C", (s) => s);
expect(d.geom.shape).toBe("arc");
if (d.geom.shape === "arc") {
expect(d.geom.r).toBeCloseTo(5, 9);
expect(d.geom.a1).toBeCloseTo(1, 9);
}
});
});
describe("contoursToDrawings — HATCH-Füllung", () => {
it("gefüllte Kontur → Drawing2D mit fillColor und polyline-Form", () => {
const set: ContourSet = {
+14 -2
View File
@@ -444,7 +444,13 @@ function arcContour(e: DxfEntity): Contour | null {
const t = start + (sweep * i) / segs;
pts.push({ x: cx + r * Math.cos(t), y: cy + r * Math.sin(t) });
}
return { z, pts, closed: false, layer: e.layer };
return {
z,
pts,
closed: false,
layer: e.layer,
curve: { kind: "arc", cx, cy, r, a0: start, a1: start + sweep },
};
}
/** CIRCLE → geschlossener Kreis-Linienzug (voller Umlauf, letzter Punkt weggelassen). */
@@ -471,7 +477,13 @@ function circleContour(e: DxfEntity): Contour | null {
const t = (Math.PI * 2 * i) / segs;
pts.push({ x: cx + r * Math.cos(t), y: cy + r * Math.sin(t) });
}
return { z, pts, closed: true, layer: e.layer };
return {
z,
pts,
closed: true,
layer: e.layer,
curve: { kind: "circle", cx, cy, r, a0: 0, a1: Math.PI * 2 },
};
}
/**
+8
View File
@@ -102,6 +102,14 @@ export function textsToDrawings(
/** Eine Kontur → 2D-Geometrie (line bei 2 offenen Punkten, sonst polyline). */
function contourGeom(contour: Contour): Drawing2DGeom | null {
// Echte Kurve (CIRCLE/ARC) → GLATTE Kreis-/Bogen-Form statt tesselliertem Vieleck.
const c = contour.curve;
if (c) {
if (c.kind === "circle") {
return { shape: "circle", center: { x: c.cx, y: c.cy }, r: c.r };
}
return { shape: "arc", center: { x: c.cx, y: c.cy }, r: c.r, a0: c.a0, a1: c.a1 };
}
const pts = contour.pts;
if (pts.length < 2) return null;
if (pts.length === 2 && !contour.closed) {