@faicad/faijs-sketch 0.18.0 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"contour.d.ts","sourceRoot":"","sources":["../src/contour.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,gHAAgH;AAChH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChE;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEN,0GAA0G;AAC1G,MAAM,WAAW,OAAO;IACtB,0CAA0C;IAC1C,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;CACjB;AAwCD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,EAAE,CA8EnE"}
1
+ {"version":3,"file":"contour.d.ts","sourceRoot":"","sources":["../src/contour.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,gHAAgH;AAChH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChE;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEN,0GAA0G;AAC1G,MAAM,WAAW,OAAO;IACtB,0CAA0C;IAC1C,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;CACjB;AAwCD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,EAAE,CA0FnE"}
package/dist/contour.js CHANGED
@@ -44,6 +44,18 @@ function segEnds(g) {
44
44
  export function extractContours(geoms) {
45
45
  const pool = [];
46
46
  for (const g of geoms) {
47
+ // GOTCHA (2026-09-26): this function's doc comment always promised
48
+ // "non-construction segments only" but nothing filtered them. FreeCAD
49
+ // leaves construction geometry unconstrained, so its coordinates are
50
+ // frequently leftover garbage — a reference line at `StartY = -16508`
51
+ // sitting next to real geometry at y ≈ 1165 (Double glazed window
52
+ // … .FCStd, Sketch095). Left in the pool it contributed two dangling
53
+ // endpoints, and because the DFS marks pool entries `used` as it walks,
54
+ // a construction branch could consume real segments before the actual
55
+ // profile was ever tried — the sketch then had zero loops even though it
56
+ // was solved.
57
+ if (g.construction)
58
+ continue;
47
59
  const s = segEnds(g);
48
60
  if (!s)
49
61
  continue;
@@ -109,9 +121,10 @@ export function extractContours(geoms) {
109
121
  contours.push({ segments: expanded, closed: true });
110
122
  }
111
123
  }
112
- // circles are self-closed contours
124
+ // circles are self-closed contours (construction circles excluded: they are
125
+ // reference geometry, not profile holes/outer rings)
113
126
  for (const g of geoms) {
114
- if (g.kind === 'circle' && g.radius > 0) {
127
+ if (g.kind === 'circle' && g.radius > 0 && !g.construction) {
115
128
  contours.push({
116
129
  segments: [{
117
130
  kind: 'arc', cx: g.cx, cy: g.cy, radius: g.radius,
@@ -1 +1 @@
1
- {"version":3,"file":"contour.js","sourceRoot":"","sources":["../src/contour.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M3.6 — contour extraction: solved sketch geometry → closed loops → 2D\n * contour (R6: pure data, no OCCT dependency; the cad-face wiring that turns\n * contours into Blueprint/extrude inputs happens in M4.6/M5).\n *\n * Extraction: collect endpoints of every non-construction geometry, chain\n * segments sharing endpoints (tolerance-based), keep closed loops.\n */\nimport type { FcstdSketchGeom } from './fcstd-types.js';\nimport { bsplineToSegments } from './bspline.js';\n\n/** One segment of a 2D contour: either a straight line or a circular arc (planar, sketch-local coordinates). */\nexport type ContourSeg =\n | { kind: 'line'; x1: number; y1: number; x2: number; y2: number }\n | {\n kind: 'arc';\n cx: number;\n cy: number;\n radius: number;\n startAngle: number;\n endAngle: number;\n ccw: boolean;\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n };\n\n/** A chained run of segments; `closed` when the chain's ends meet (R6: pure data, no OCCT dependency). */\nexport interface Contour {\n /** chained segments in traversal order */\n segments: ContourSeg[];\n /** true when the chain's endpoints meet within JOIN_TOL */\n closed: boolean;\n}\n\nconst JOIN_TOL = 1e-7;\n\nfunction segEnds(g: FcstdSketchGeom): [ContourSeg, { x: number; y: number }, { x: number; y: number }] | undefined {\n switch (g.kind) {\n case 'line':\n return [\n { kind: 'line', x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 },\n { x: g.x1, y: g.y1 },\n { x: g.x2, y: g.y2 },\n ];\n case 'arc':\n return [\n {\n kind: 'arc', cx: g.cx, cy: g.cy, radius: g.radius,\n startAngle: g.startAngle, endAngle: g.endAngle, ccw: true,\n x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2,\n },\n { x: g.x1, y: g.y1 },\n { x: g.x2, y: g.y2 },\n ];\n case 'bspline': {\n // P4: flatten the spline into a sampled polyline. Only the FIRST\n // sub-segment is returned here so the pool gets exactly one entry per\n // geometry (no index duplication); extractContours splices the full\n // polyline run in its place (see expandBSpline below).\n const segs = bsplineToSegments({\n poles: g.poles, knots: g.knots, degree: g.degree, periodic: g.periodic,\n });\n const first = segs[0];\n const last = segs[segs.length - 1];\n if (!first || !last) return undefined;\n return [{ kind: 'line', x1: first.x1, y1: first.y1, x2: last.x2, y2: last.y2 }, { x: first.x1, y: first.y1 }, { x: last.x2, y: last.y2 }];\n }\n default:\n return undefined; // circles are closed on their own; points don't join\n }\n}\n\n/**\n * Extract closed contours (chains of segments whose endpoints meet).\n * @param geoms solved sketch geometry to chain (non-construction segments only)\n * @returns closed loops plus self-closed circles (open chains are dropped)\n */\nexport function extractContours(geoms: FcstdSketchGeom[]): Contour[] {\n const pool: { seg: ContourSeg; a: { x: number; y: number }; b: { x: number; y: number }; used: boolean; spline?: { x1: number; y1: number; x2: number; y2: number }[] }[] = [];\n for (const g of geoms) {\n const s = segEnds(g);\n if (!s) continue;\n // P4: keep the full sampled polyline for splines — after chaining, the\n // winning seg is expanded back into all sub-segments (no interior loss).\n const spline = g.kind === 'bspline'\n ? bsplineToSegments({ poles: g.poles, knots: g.knots, degree: g.degree, periodic: g.periodic })\n : undefined;\n pool.push({ seg: s[0], a: s[1], b: s[2], used: false, spline });\n }\n\n const near = (p: { x: number; y: number }, q: { x: number; y: number }): boolean =>\n Math.hypot(p.x - q.x, p.y - q.y) <= JOIN_TOL;\n\n const contours: Contour[] = [];\n for (const start of pool) {\n if (start.used) continue;\n start.used = true;\n const head = start.a;\n // GOTCHA (slittingsaw corpus, 2026-09-20): junction points with free\n // branches (three+ segments sharing an endpoint) defeat first-come\n // chaining — a branch to a dead end consumed the segments and the real\n // loop never closed. DFS with backtracking: try each candidate\n // continuation; the FIRST chain that closes at the head wins; a dead\n // branch returns its segments to the pool. Closure-stop (tap GOTCHA) and\n // pool-restart are both subsumed by the DFS ordering.\n const dfs = (tail: { x: number; y: number }, walk: ContourSeg[]): ContourSeg[] | undefined => {\n if (walk.length > 0 && near(tail, head)) return walk;\n for (const cand of pool) {\n if (cand.used) continue;\n cand.used = true;\n if (near(tail, cand.a)) {\n const r = dfs(cand.b, [...walk, cand.seg]);\n if (r) return r;\n } else if (near(tail, cand.b)) {\n const r = dfs(cand.a, [...walk, reverseSeg(cand.seg)]);\n if (r) return r;\n }\n cand.used = false; // dead branch — return the segment to the pool\n }\n return undefined;\n };\n const solved = dfs(start.b, [start.seg]);\n if (solved && solved.length > 1) {\n // P4: replace spline proxy segs with their full sampled polyline runs.\n // The proxy seg for geometry index i sits in pool order; recover the\n // spline runs by matching the seg reference against pool entries.\n const expanded: ContourSeg[] = [];\n for (const seg of solved) {\n const entry = pool.find((e) => e.seg === seg && e.spline);\n if (entry?.spline) {\n for (const sub of entry.spline) {\n expanded.push({ kind: 'line', x1: sub.x1, y1: sub.y1, x2: sub.x2, y2: sub.y2 });\n }\n } else {\n expanded.push(seg);\n }\n }\n contours.push({ segments: expanded, closed: true });\n }\n }\n\n // circles are self-closed contours\n for (const g of geoms) {\n if (g.kind === 'circle' && g.radius > 0) {\n contours.push({\n segments: [{\n kind: 'arc', cx: g.cx, cy: g.cy, radius: g.radius,\n startAngle: 0, endAngle: Math.PI * 2, ccw: true,\n x1: g.cx + g.radius, y1: g.cy, x2: g.cx + g.radius, y2: g.cy,\n }],\n closed: true,\n });\n }\n }\n return contours;\n}\n\nfunction reverseSeg(s: ContourSeg): ContourSeg {\n if (s.kind === 'line') return { kind: 'line', x1: s.x2, y1: s.y2, x2: s.x1, y2: s.y1 };\n return { ...s, startAngle: s.endAngle, endAngle: s.startAngle, ccw: !s.ccw, x1: s.x2, y1: s.y2, x2: s.x1, y2: s.y1 };\n}\n"]}
1
+ {"version":3,"file":"contour.js","sourceRoot":"","sources":["../src/contour.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M3.6 — contour extraction: solved sketch geometry → closed loops → 2D\n * contour (R6: pure data, no OCCT dependency; the cad-face wiring that turns\n * contours into Blueprint/extrude inputs happens in M4.6/M5).\n *\n * Extraction: collect endpoints of every non-construction geometry, chain\n * segments sharing endpoints (tolerance-based), keep closed loops.\n */\nimport type { FcstdSketchGeom } from './fcstd-types.js';\nimport { bsplineToSegments } from './bspline.js';\n\n/** One segment of a 2D contour: either a straight line or a circular arc (planar, sketch-local coordinates). */\nexport type ContourSeg =\n | { kind: 'line'; x1: number; y1: number; x2: number; y2: number }\n | {\n kind: 'arc';\n cx: number;\n cy: number;\n radius: number;\n startAngle: number;\n endAngle: number;\n ccw: boolean;\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n };\n\n/** A chained run of segments; `closed` when the chain's ends meet (R6: pure data, no OCCT dependency). */\nexport interface Contour {\n /** chained segments in traversal order */\n segments: ContourSeg[];\n /** true when the chain's endpoints meet within JOIN_TOL */\n closed: boolean;\n}\n\nconst JOIN_TOL = 1e-7;\n\nfunction segEnds(g: FcstdSketchGeom): [ContourSeg, { x: number; y: number }, { x: number; y: number }] | undefined {\n switch (g.kind) {\n case 'line':\n return [\n { kind: 'line', x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 },\n { x: g.x1, y: g.y1 },\n { x: g.x2, y: g.y2 },\n ];\n case 'arc':\n return [\n {\n kind: 'arc', cx: g.cx, cy: g.cy, radius: g.radius,\n startAngle: g.startAngle, endAngle: g.endAngle, ccw: true,\n x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2,\n },\n { x: g.x1, y: g.y1 },\n { x: g.x2, y: g.y2 },\n ];\n case 'bspline': {\n // P4: flatten the spline into a sampled polyline. Only the FIRST\n // sub-segment is returned here so the pool gets exactly one entry per\n // geometry (no index duplication); extractContours splices the full\n // polyline run in its place (see expandBSpline below).\n const segs = bsplineToSegments({\n poles: g.poles, knots: g.knots, degree: g.degree, periodic: g.periodic,\n });\n const first = segs[0];\n const last = segs[segs.length - 1];\n if (!first || !last) return undefined;\n return [{ kind: 'line', x1: first.x1, y1: first.y1, x2: last.x2, y2: last.y2 }, { x: first.x1, y: first.y1 }, { x: last.x2, y: last.y2 }];\n }\n default:\n return undefined; // circles are closed on their own; points don't join\n }\n}\n\n/**\n * Extract closed contours (chains of segments whose endpoints meet).\n * @param geoms solved sketch geometry to chain (non-construction segments only)\n * @returns closed loops plus self-closed circles (open chains are dropped)\n */\nexport function extractContours(geoms: FcstdSketchGeom[]): Contour[] {\n const pool: { seg: ContourSeg; a: { x: number; y: number }; b: { x: number; y: number }; used: boolean; spline?: { x1: number; y1: number; x2: number; y2: number }[] }[] = [];\n for (const g of geoms) {\n // GOTCHA (2026-09-26): this function's doc comment always promised\n // \"non-construction segments only\" but nothing filtered them. FreeCAD\n // leaves construction geometry unconstrained, so its coordinates are\n // frequently leftover garbage — a reference line at `StartY = -16508`\n // sitting next to real geometry at y ≈ 1165 (Double glazed window\n // … .FCStd, Sketch095). Left in the pool it contributed two dangling\n // endpoints, and because the DFS marks pool entries `used` as it walks,\n // a construction branch could consume real segments before the actual\n // profile was ever tried — the sketch then had zero loops even though it\n // was solved.\n if (g.construction) continue;\n const s = segEnds(g);\n if (!s) continue;\n // P4: keep the full sampled polyline for splines — after chaining, the\n // winning seg is expanded back into all sub-segments (no interior loss).\n const spline = g.kind === 'bspline'\n ? bsplineToSegments({ poles: g.poles, knots: g.knots, degree: g.degree, periodic: g.periodic })\n : undefined;\n pool.push({ seg: s[0], a: s[1], b: s[2], used: false, spline });\n }\n\n const near = (p: { x: number; y: number }, q: { x: number; y: number }): boolean =>\n Math.hypot(p.x - q.x, p.y - q.y) <= JOIN_TOL;\n\n const contours: Contour[] = [];\n for (const start of pool) {\n if (start.used) continue;\n start.used = true;\n const head = start.a;\n // GOTCHA (slittingsaw corpus, 2026-09-20): junction points with free\n // branches (three+ segments sharing an endpoint) defeat first-come\n // chaining — a branch to a dead end consumed the segments and the real\n // loop never closed. DFS with backtracking: try each candidate\n // continuation; the FIRST chain that closes at the head wins; a dead\n // branch returns its segments to the pool. Closure-stop (tap GOTCHA) and\n // pool-restart are both subsumed by the DFS ordering.\n const dfs = (tail: { x: number; y: number }, walk: ContourSeg[]): ContourSeg[] | undefined => {\n if (walk.length > 0 && near(tail, head)) return walk;\n for (const cand of pool) {\n if (cand.used) continue;\n cand.used = true;\n if (near(tail, cand.a)) {\n const r = dfs(cand.b, [...walk, cand.seg]);\n if (r) return r;\n } else if (near(tail, cand.b)) {\n const r = dfs(cand.a, [...walk, reverseSeg(cand.seg)]);\n if (r) return r;\n }\n cand.used = false; // dead branch — return the segment to the pool\n }\n return undefined;\n };\n const solved = dfs(start.b, [start.seg]);\n if (solved && solved.length > 1) {\n // P4: replace spline proxy segs with their full sampled polyline runs.\n // The proxy seg for geometry index i sits in pool order; recover the\n // spline runs by matching the seg reference against pool entries.\n const expanded: ContourSeg[] = [];\n for (const seg of solved) {\n const entry = pool.find((e) => e.seg === seg && e.spline);\n if (entry?.spline) {\n for (const sub of entry.spline) {\n expanded.push({ kind: 'line', x1: sub.x1, y1: sub.y1, x2: sub.x2, y2: sub.y2 });\n }\n } else {\n expanded.push(seg);\n }\n }\n contours.push({ segments: expanded, closed: true });\n }\n }\n\n // circles are self-closed contours (construction circles excluded: they are\n // reference geometry, not profile holes/outer rings)\n for (const g of geoms) {\n if (g.kind === 'circle' && g.radius > 0 && !g.construction) {\n contours.push({\n segments: [{\n kind: 'arc', cx: g.cx, cy: g.cy, radius: g.radius,\n startAngle: 0, endAngle: Math.PI * 2, ccw: true,\n x1: g.cx + g.radius, y1: g.cy, x2: g.cx + g.radius, y2: g.cy,\n }],\n closed: true,\n });\n }\n }\n return contours;\n}\n\nfunction reverseSeg(s: ContourSeg): ContourSeg {\n if (s.kind === 'line') return { kind: 'line', x1: s.x2, y1: s.y2, x2: s.x1, y2: s.y1 };\n return { ...s, startAngle: s.endAngle, endAngle: s.startAngle, ccw: !s.ccw, x1: s.x2, y1: s.y2, x2: s.x1, y2: s.y1 };\n}\n"]}
@@ -61,6 +61,14 @@ export declare const PointPos: {
61
61
  /**
62
62
  * One parsed sketch geometry element (point, line, circle, arc, ellipse or
63
63
  * bspline), in 3D sketch-local coordinates.
64
+ *
65
+ * `construction` (2026-09-26): FreeCAD marks reference geometry (axes, symmetry
66
+ * lines, helper circles) with `<Construction value="1"/>`. It participates in
67
+ * the constraint solve but is NOT part of the profile: FreeCAD never constrains
68
+ * it to the real outline, so its stored coordinates are frequently leftover
69
+ * garbage (measured on `Double glazed window … .FCStd` Sketch095: a
70
+ * construction line with `StartY = -16508.67` next to real geometry at y≈1165).
71
+ * Contour extraction must therefore filter on it — see `contour.ts`.
64
72
  */
65
73
  export type FcstdSketchGeom = {
66
74
  kind: 'point';
@@ -68,6 +76,7 @@ export type FcstdSketchGeom = {
68
76
  x: number;
69
77
  y: number;
70
78
  z: number;
79
+ construction?: boolean;
71
80
  } | {
72
81
  kind: 'line';
73
82
  index: number;
@@ -77,6 +86,7 @@ export type FcstdSketchGeom = {
77
86
  x2: number;
78
87
  y2: number;
79
88
  z2: number;
89
+ construction?: boolean;
80
90
  } | {
81
91
  kind: 'circle';
82
92
  index: number;
@@ -84,6 +94,7 @@ export type FcstdSketchGeom = {
84
94
  cy: number;
85
95
  cz: number;
86
96
  radius: number;
97
+ construction?: boolean;
87
98
  } | {
88
99
  kind: 'arc';
89
100
  index: number;
@@ -100,6 +111,7 @@ export type FcstdSketchGeom = {
100
111
  x2: number;
101
112
  y2: number;
102
113
  z2: number;
114
+ construction?: boolean;
103
115
  } | {
104
116
  kind: 'ellipse';
105
117
  index: number;
@@ -115,6 +127,7 @@ export type FcstdSketchGeom = {
115
127
  fy1: number;
116
128
  fx2: number;
117
129
  fy2: number;
130
+ construction?: boolean;
118
131
  } | {
119
132
  /** Part::GeomBSplineCurve (Poles/Knots/Degree/IsPeriodic) */
120
133
  kind: 'bspline';
@@ -133,6 +146,7 @@ export type FcstdSketchGeom = {
133
146
  x2: number;
134
147
  y2: number;
135
148
  z2: number;
149
+ construction?: boolean;
136
150
  };
137
151
  /**
138
152
  * One (geometry, point) reference inside a constraint: a geoId plus a
@@ -1 +1 @@
1
- {"version":3,"file":"fcstd-types.d.ts","sourceRoot":"","sources":["../src/fcstd-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;CAsBjB,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMnD,CAAA;AAED,qDAAqD;AACrD,eAAO,MAAM,KAAK;;;;;CAKR,CAAA;AAEV,iCAAiC;AACjC,eAAO,MAAM,QAAQ;;;;;CAKX,CAAA;AAEV;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACvG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrF;IACE,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX,GACD;IACE,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ,GACD;IACE,6DAA6D;IAC7D,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACjC,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAEL;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,IAAI,EAAE,WAAW,EAAE,CAAA;IACnB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAA;IAClB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,gBAAgB,EAAE,OAAO,CAAA;IACzB,6CAA6C;IAC7C,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB"}
1
+ {"version":3,"file":"fcstd-types.d.ts","sourceRoot":"","sources":["../src/fcstd-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fcstd-types.js","sourceRoot":"","sources":["../src/fcstd-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,CAAC;IACR,aAAa,EAAE,EAAE;IACjB,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE;IACb,iBAAiB,EAAE,EAAE;IACrB,SAAS,EAAE,EAAE;IACb,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;CACA,CAAA;AAEV;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS;IAC5E,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe;IAC9E,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW;IAC/D,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU;IACrE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM;CACtC,CAAA;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;CACF,CAAA;AAEV,iCAAiC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,CAAC,EAAE,cAAc;IACvB,KAAK,EAAE,CAAC;IACR,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC,EAAE,2BAA2B;CAC3B,CAAA","sourcesContent":["/**\n * fcstd-types — FCStd sketch geometry / constraint model (migrated from\n * `@faicad/faijs-fcstd`'s `sketch-parse.ts`, type half only).\n *\n * These are the FreeCAD-shaped records the solver pipeline consumes: geometry\n * carries an `index` (geoId) and 3D sketch-local coordinates; constraints carry\n * the `ConstraintType` integer and `(geoId, pos)` refs. The canonical,\n * projection-friendly model lives in `./canonical.ts` — this module is the\n * internal/FCStd-projection representation.\n *\n * Field format per the fcstd port plan §5.2/§5.3:\n * - geometry coordinates are 3D (X/Y/Z); sketch-local Z is usually 0\n * - `<Constrain>` carries Type as the ConstraintType enum integer\n * - ElementIds/ElementPositions take precedence over First/Second/Third\n * - IsDriving defaults to true when missing\n * - geoId: >= 0 own geometry; -1 HAxis/RtPnt; -2 VAxis; <= -3 external\n */\n\n/** ConstraintType enum values (src/Mod/Sketcher/App/Constraint.h:52-77) */\nexport const ConstraintType = {\n Coincident: 1,\n Horizontal: 2,\n Vertical: 3,\n Parallel: 4,\n Tangent: 5,\n Distance: 6,\n DistanceX: 7,\n DistanceY: 8,\n Angle: 9,\n Perpendicular: 10,\n Radius: 11,\n Equal: 12,\n PointOnObject: 13,\n Symmetric: 14,\n InternalAlignment: 15,\n SnellsLaw: 16,\n Block: 17,\n Diameter: 18,\n Weight: 19,\n Group: 20,\n Text: 21,\n} as const\n\n/**\n * Human-readable names for the ConstraintType enum integers (debugging/\n * diagnostics only).\n */\nexport const CONSTRAINT_NAMES: Record<number, string> = {\n 1: 'Coincident', 2: 'Horizontal', 3: 'Vertical', 4: 'Parallel', 5: 'Tangent',\n 6: 'Distance', 7: 'DistanceX', 8: 'DistanceY', 9: 'Angle', 10: 'Perpendicular',\n 11: 'Radius', 12: 'Equal', 13: 'PointOnObject', 14: 'Symmetric',\n 15: 'InternalAlignment', 16: 'SnellsLaw', 17: 'Block', 18: 'Diameter',\n 19: 'Weight', 20: 'Group', 21: 'Text',\n}\n\n/** GeoEnum (src/Mod/Sketcher/App/GeoEnum.h:71-78) */\nexport const GeoId = {\n RtPnt: -1,\n HAxis: -1,\n VAxis: -2,\n RefExt: -3,\n} as const\n\n/** PointPos (GeoEnum.h:88-94) */\nexport const PointPos = {\n none: 0, // edge itself\n start: 1,\n end: 2,\n mid: 3, // center of circle/ellipse\n} as const\n\n/**\n * One parsed sketch geometry element (point, line, circle, arc, ellipse or\n * bspline), in 3D sketch-local coordinates.\n */\nexport type FcstdSketchGeom =\n | { kind: 'point'; index: number; x: number; y: number; z: number }\n | { kind: 'line'; index: number; x1: number; y1: number; z1: number; x2: number; y2: number; z2: number }\n | { kind: 'circle'; index: number; cx: number; cy: number; cz: number; radius: number }\n | {\n kind: 'arc'\n index: number\n cx: number\n cy: number\n cz: number\n radius: number\n startAngle: number // radians\n endAngle: number\n /** arc endpoints derived from angles (kept for solver wiring) */\n x1: number\n y1: number\n z1: number\n x2: number\n y2: number\n z2: number\n }\n | {\n kind: 'ellipse'\n index: number\n cx: number\n cy: number\n cz: number\n majorRadius: number\n minorRadius: number\n /** rotation of major axis, radians */\n angleXU: number\n /** first focus (computed) */\n fx1: number\n fy1: number\n fx2: number\n fy2: number\n }\n | {\n /** Part::GeomBSplineCurve (Poles/Knots/Degree/IsPeriodic) */\n kind: 'bspline'\n index: number\n poles: { x: number; y: number }[]\n knots: number[]\n degree: number\n periodic: boolean\n /** curve start/end (exact for clamped splines; solver wiring + chaining) */\n x1: number\n y1: number\n z1: number\n x2: number\n y2: number\n z2: number\n }\n\n/**\n * One (geometry, point) reference inside a constraint: a geoId plus a\n * PointPos selector.\n */\nexport interface FcstdGeoRef {\n /** geometry id: >= 0 own geometry; -1 HAxis/RtPnt; -2 VAxis; <= -3 external */\n geoId: number\n /** PointPos selector (0 = edge itself, 1/2 = start/end, 3 = center) */\n pos: number // PointPos\n}\n\n/**\n * One parsed sketch constraint.\n */\nexport interface FcstdSketchCon {\n /** index in the constraint list */\n index: number\n /** ConstraintType integer */\n type: number\n /** resolved element refs */\n refs: FcstdGeoRef[]\n /** driving dimension value (Distance/Angle/Radius/...) */\n value: number\n /** IsDriving; missing means true */\n isDriving: boolean\n /** raw name attribute */\n name: string\n /** InternalAlignmentType when type === 15 */\n internalAlignmentType?: number\n}\n\n/**\n * The fully parsed sketch: geometry, constraints, constrainedness and the set\n * of referenced external geoIds.\n */\nexport interface FcstdParsedSketch {\n geoms: FcstdSketchGeom[]\n constraints: FcstdSketchCon[]\n fullyConstrained: boolean\n /** geoIds <= -3 referenced by constraints */\n externalGeoIds: number[]\n}"]}
1
+ {"version":3,"file":"fcstd-types.js","sourceRoot":"","sources":["../src/fcstd-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,CAAC;IACR,aAAa,EAAE,EAAE;IACjB,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE;IACb,iBAAiB,EAAE,EAAE;IACrB,SAAS,EAAE,EAAE;IACb,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;CACA,CAAA;AAEV;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS;IAC5E,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe;IAC9E,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW;IAC/D,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU;IACrE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM;CACtC,CAAA;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;CACF,CAAA;AAEV,iCAAiC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,CAAC,EAAE,cAAc;IACvB,KAAK,EAAE,CAAC;IACR,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC,EAAE,2BAA2B;CAC3B,CAAA","sourcesContent":["/**\n * fcstd-types — FCStd sketch geometry / constraint model (migrated from\n * `@faicad/faijs-fcstd`'s `sketch-parse.ts`, type half only).\n *\n * These are the FreeCAD-shaped records the solver pipeline consumes: geometry\n * carries an `index` (geoId) and 3D sketch-local coordinates; constraints carry\n * the `ConstraintType` integer and `(geoId, pos)` refs. The canonical,\n * projection-friendly model lives in `./canonical.ts` — this module is the\n * internal/FCStd-projection representation.\n *\n * Field format per the fcstd port plan §5.2/§5.3:\n * - geometry coordinates are 3D (X/Y/Z); sketch-local Z is usually 0\n * - `<Constrain>` carries Type as the ConstraintType enum integer\n * - ElementIds/ElementPositions take precedence over First/Second/Third\n * - IsDriving defaults to true when missing\n * - geoId: >= 0 own geometry; -1 HAxis/RtPnt; -2 VAxis; <= -3 external\n */\n\n/** ConstraintType enum values (src/Mod/Sketcher/App/Constraint.h:52-77) */\nexport const ConstraintType = {\n Coincident: 1,\n Horizontal: 2,\n Vertical: 3,\n Parallel: 4,\n Tangent: 5,\n Distance: 6,\n DistanceX: 7,\n DistanceY: 8,\n Angle: 9,\n Perpendicular: 10,\n Radius: 11,\n Equal: 12,\n PointOnObject: 13,\n Symmetric: 14,\n InternalAlignment: 15,\n SnellsLaw: 16,\n Block: 17,\n Diameter: 18,\n Weight: 19,\n Group: 20,\n Text: 21,\n} as const\n\n/**\n * Human-readable names for the ConstraintType enum integers (debugging/\n * diagnostics only).\n */\nexport const CONSTRAINT_NAMES: Record<number, string> = {\n 1: 'Coincident', 2: 'Horizontal', 3: 'Vertical', 4: 'Parallel', 5: 'Tangent',\n 6: 'Distance', 7: 'DistanceX', 8: 'DistanceY', 9: 'Angle', 10: 'Perpendicular',\n 11: 'Radius', 12: 'Equal', 13: 'PointOnObject', 14: 'Symmetric',\n 15: 'InternalAlignment', 16: 'SnellsLaw', 17: 'Block', 18: 'Diameter',\n 19: 'Weight', 20: 'Group', 21: 'Text',\n}\n\n/** GeoEnum (src/Mod/Sketcher/App/GeoEnum.h:71-78) */\nexport const GeoId = {\n RtPnt: -1,\n HAxis: -1,\n VAxis: -2,\n RefExt: -3,\n} as const\n\n/** PointPos (GeoEnum.h:88-94) */\nexport const PointPos = {\n none: 0, // edge itself\n start: 1,\n end: 2,\n mid: 3, // center of circle/ellipse\n} as const\n\n/**\n * One parsed sketch geometry element (point, line, circle, arc, ellipse or\n * bspline), in 3D sketch-local coordinates.\n *\n * `construction` (2026-09-26): FreeCAD marks reference geometry (axes, symmetry\n * lines, helper circles) with `<Construction value=\"1\"/>`. It participates in\n * the constraint solve but is NOT part of the profile: FreeCAD never constrains\n * it to the real outline, so its stored coordinates are frequently leftover\n * garbage (measured on `Double glazed window … .FCStd` Sketch095: a\n * construction line with `StartY = -16508.67` next to real geometry at y≈1165).\n * Contour extraction must therefore filter on it — see `contour.ts`.\n */\nexport type FcstdSketchGeom =\n | { kind: 'point'; index: number; x: number; y: number; z: number; construction?: boolean }\n | { kind: 'line'; index: number; x1: number; y1: number; z1: number; x2: number; y2: number; z2: number; construction?: boolean }\n | { kind: 'circle'; index: number; cx: number; cy: number; cz: number; radius: number; construction?: boolean }\n | {\n kind: 'arc'\n index: number\n cx: number\n cy: number\n cz: number\n radius: number\n startAngle: number // radians\n endAngle: number\n /** arc endpoints derived from angles (kept for solver wiring) */\n x1: number\n y1: number\n z1: number\n x2: number\n y2: number\n z2: number\n construction?: boolean\n }\n | {\n kind: 'ellipse'\n index: number\n cx: number\n cy: number\n cz: number\n majorRadius: number\n minorRadius: number\n /** rotation of major axis, radians */\n angleXU: number\n /** first focus (computed) */\n fx1: number\n fy1: number\n fx2: number\n fy2: number\n construction?: boolean\n }\n | {\n /** Part::GeomBSplineCurve (Poles/Knots/Degree/IsPeriodic) */\n kind: 'bspline'\n index: number\n poles: { x: number; y: number }[]\n knots: number[]\n degree: number\n periodic: boolean\n /** curve start/end (exact for clamped splines; solver wiring + chaining) */\n x1: number\n y1: number\n z1: number\n x2: number\n y2: number\n z2: number\n construction?: boolean\n }\n\n/**\n * One (geometry, point) reference inside a constraint: a geoId plus a\n * PointPos selector.\n */\nexport interface FcstdGeoRef {\n /** geometry id: >= 0 own geometry; -1 HAxis/RtPnt; -2 VAxis; <= -3 external */\n geoId: number\n /** PointPos selector (0 = edge itself, 1/2 = start/end, 3 = center) */\n pos: number // PointPos\n}\n\n/**\n * One parsed sketch constraint.\n */\nexport interface FcstdSketchCon {\n /** index in the constraint list */\n index: number\n /** ConstraintType integer */\n type: number\n /** resolved element refs */\n refs: FcstdGeoRef[]\n /** driving dimension value (Distance/Angle/Radius/...) */\n value: number\n /** IsDriving; missing means true */\n isDriving: boolean\n /** raw name attribute */\n name: string\n /** InternalAlignmentType when type === 15 */\n internalAlignmentType?: number\n}\n\n/**\n * The fully parsed sketch: geometry, constraints, constrainedness and the set\n * of referenced external geoIds.\n */\nexport interface FcstdParsedSketch {\n geoms: FcstdSketchGeom[]\n constraints: FcstdSketchCon[]\n fullyConstrained: boolean\n /** geoIds <= -3 referenced by constraints */\n externalGeoIds: number[]\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faicad/faijs-sketch",
3
- "version": "0.18.0",
3
+ "version": "0.18.3",
4
4
  "description": "faijs sketch & constraint capability library — canonical model, planegcs solving, contour extraction and face construction",
5
5
  "keywords": [
6
6
  "faijs",
@@ -62,4 +62,4 @@
62
62
  "test:install": "vitest run -c vitest.install.config.ts",
63
63
  "lint": "eslint src"
64
64
  }
65
- }
65
+ }