@faicad/faijs 0.13.0 → 0.13.2
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.
- package/dist/api/edge-ref.d.ts +3 -2
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +3 -2
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/internal/compat-op.d.ts +2 -0
- package/dist/api/internal/compat-op.d.ts.map +1 -1
- package/dist/api/internal/compat-op.js +8 -1
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/occt-kernel-bridge.d.ts.map +1 -1
- package/dist/api/occt-kernel-bridge.js +7 -1
- package/dist/api/occt-kernel-bridge.js.map +1 -1
- package/dist/browser.d.ts +0 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.d.ts +1 -1
- package/dist/cad-runtime/browser-lib-loader.js +1 -1
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/fcstd/attachment.d.ts +65 -0
- package/dist/fcstd/attachment.d.ts.map +1 -0
- package/dist/fcstd/attachment.js +87 -0
- package/dist/fcstd/attachment.js.map +1 -0
- package/dist/fcstd/build-fai-zip.d.ts +11 -0
- package/dist/fcstd/build-fai-zip.d.ts.map +1 -1
- package/dist/fcstd/build-fai-zip.js +9 -1
- package/dist/fcstd/build-fai-zip.js.map +1 -1
- package/dist/fcstd/cli.d.ts +3 -0
- package/dist/fcstd/cli.d.ts.map +1 -0
- package/dist/fcstd/cli.js +37 -0
- package/dist/fcstd/cli.js.map +1 -0
- package/dist/fcstd/codegen.d.ts +14 -1
- package/dist/fcstd/codegen.d.ts.map +1 -1
- package/dist/fcstd/codegen.js +11 -2
- package/dist/fcstd/codegen.js.map +1 -1
- package/dist/fcstd/container.d.ts +16 -1
- package/dist/fcstd/container.d.ts.map +1 -1
- package/dist/fcstd/container.js +12 -1
- package/dist/fcstd/container.js.map +1 -1
- package/dist/fcstd/contour.d.ts +9 -1
- package/dist/fcstd/contour.d.ts.map +1 -1
- package/dist/fcstd/contour.js +12 -1
- package/dist/fcstd/contour.js.map +1 -1
- package/dist/fcstd/convert.d.ts +47 -2
- package/dist/fcstd/convert.d.ts.map +1 -1
- package/dist/fcstd/convert.js +82 -13
- package/dist/fcstd/convert.js.map +1 -1
- package/dist/fcstd/document.d.ts +8 -1
- package/dist/fcstd/document.d.ts.map +1 -1
- package/dist/fcstd/document.js +4 -1
- package/dist/fcstd/document.js.map +1 -1
- package/dist/fcstd/expressions.d.ts +14 -1
- package/dist/fcstd/expressions.d.ts.map +1 -1
- package/dist/fcstd/expressions.js +11 -1
- package/dist/fcstd/expressions.js.map +1 -1
- package/dist/fcstd/external-geo.d.ts +15 -1
- package/dist/fcstd/external-geo.d.ts.map +1 -1
- package/dist/fcstd/external-geo.js +8 -1
- package/dist/fcstd/external-geo.js.map +1 -1
- package/dist/fcstd/feature-translate.d.ts +65 -3
- package/dist/fcstd/feature-translate.d.ts.map +1 -1
- package/dist/fcstd/feature-translate.js +82 -4
- package/dist/fcstd/feature-translate.js.map +1 -1
- package/dist/fcstd/index.d.ts +23 -0
- package/dist/fcstd/index.d.ts.map +1 -0
- package/dist/fcstd/index.js +19 -0
- package/dist/fcstd/index.js.map +1 -0
- package/dist/fcstd/placement.d.ts +49 -6
- package/dist/fcstd/placement.d.ts.map +1 -1
- package/dist/fcstd/placement.js +46 -6
- package/dist/fcstd/placement.js.map +1 -1
- package/dist/fcstd/planegcs-backend.d.ts +16 -1
- package/dist/fcstd/planegcs-backend.d.ts.map +1 -1
- package/dist/fcstd/planegcs-backend.js +16 -1
- package/dist/fcstd/planegcs-backend.js.map +1 -1
- package/dist/fcstd/sketch-parse.d.ts +43 -0
- package/dist/fcstd/sketch-parse.d.ts.map +1 -1
- package/dist/fcstd/sketch-parse.js +26 -0
- package/dist/fcstd/sketch-parse.js.map +1 -1
- package/dist/fcstd/sketch-solver.d.ts +20 -2
- package/dist/fcstd/sketch-solver.d.ts.map +1 -1
- package/dist/fcstd/sketch-solver.js +6 -1
- package/dist/fcstd/sketch-solver.js.map +1 -1
- package/dist/fcstd/sketch-verify.d.ts +19 -1
- package/dist/fcstd/sketch-verify.d.ts.map +1 -1
- package/dist/fcstd/sketch-verify.js +14 -1
- package/dist/fcstd/sketch-verify.js.map +1 -1
- package/dist/fcstd/unpack.d.ts +21 -2
- package/dist/fcstd/unpack.d.ts.map +1 -1
- package/dist/fcstd/unpack.js +11 -2
- package/dist/fcstd/unpack.js.map +1 -1
- package/dist/fcstd-convert.d.ts +30 -0
- package/dist/fcstd-convert.d.ts.map +1 -0
- package/dist/fcstd-convert.js +27 -0
- package/dist/fcstd-convert.js.map +1 -0
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +20 -19
- package/dist/node-host/cli.js.map +1 -1
- package/dist/vendored/brepjs/kernel/index.d.ts +7 -0
- package/dist/vendored/brepjs/kernel/index.d.ts.map +1 -1
- package/dist/vendored/brepjs/kernel/index.js +57 -0
- package/dist/vendored/brepjs/kernel/index.js.map +1 -1
- package/dist/weapp.d.ts +22 -0
- package/dist/weapp.d.ts.map +1 -0
- package/dist/weapp.js +23 -0
- package/dist/weapp.js.map +1 -0
- package/package.json +18 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/fcstd/document.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M1.2 — Document.xml → object graph.\n *\n * Contract per plan §5.5 / 前文 A §3.3: `<ObjectData>` is authoritative\n * (objects + properties); `<Objects>` is only a type index. Transient\n * `_Property` elements are skipped.\n */\nimport { DOMParser, XMLSerializer } from '@xmldom/xmldom';\nimport { err, ok, type Result } from '../vendored/brepjs/core/result.js';\n\nexport interface FcstdProperty {\n /** property name attribute ('' for non-property elements like <Geometry>) */\n name: string;\n /** e.g. \"App::PropertyString\", \"Part::PropertyPartShape\" */\n type: string;\n /** serialized element tag, e.g. \"Geometry\", \"Constrain\", \"LineSegment\" */\n tagName: string;\n /** raw nested XML content (first element child), serialized */\n valueXml?: string;\n /** for simple value properties, the text content */\n valueText?: string;\n /** named sub-elements (e.g. <Python .../>, <ExpressionEngine> children) */\n children: FcstdProperty[];\n attributes: Record<string, string>;\n}\n\nexport interface FcstdObject {\n /** object name, e.g. \"Sketch\" or \"Pad\" */\n name: string;\n /** e.g. \"Sketcher::SketchObject\", \"PartDesign::Pad\" */\n type: string;\n properties: Map<string, FcstdProperty>;\n}\n\nexport interface FcstdDocument {\n objects: FcstdObject[];\n /** from <Objects>: name → type (index only, not authoritative) */\n typeIndex: Map<string, string>;\n /** document-level properties (Creator, LastModifiedDate, ...) */\n meta: Map<string, FcstdProperty>;\n}\n\nexport type ParseError = { kind: 'xml'; message: string };\n\nfunction attrs(el: Element): Record<string, string> {\n const out: Record<string, string> = {};\n for (let i = 0; i < el.attributes.length; i++) {\n const a = el.attributes.item(i);\n if (a) out[a.name] = a.value;\n }\n return out;\n}\n\nfunction firstElementChild(el: Element): Element | undefined {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType === 1) return c as Element;\n }\n return undefined;\n}\n\nfunction serialize(el: Element): string {\n // @xmldom/xmldom ships its own Node/Element types that conflict with lib: DOM;\n // the parser/serializer boundary is the only place the two universes meet.\n type SerNode = Parameters<XMLSerializer['serializeToString']>[0];\n return new XMLSerializer().serializeToString(el as unknown as SerNode);\n}\n\nfunction parseProperty(propEl: Element): FcstdProperty {\n const children: FcstdProperty[] = [];\n for (let c = propEl.firstChild; c; c = c.nextSibling) {\n if (c.nodeType === 1) {\n const child = c as Element;\n children.push(parseProperty(child));\n }\n }\n const valueEl = firstElementChild(propEl);\n return {\n name: propEl.getAttribute('name') ?? '',\n type: propEl.getAttribute('type') ?? '',\n tagName: propEl.tagName,\n attributes: attrs(propEl),\n valueXml: valueEl ? serialize(valueEl) : undefined,\n valueText: valueEl?.textContent ?? propEl.textContent ?? '',\n children,\n };\n}\n\n/**\n * Parse Document.xml into the object graph. Only `<ObjectData>` entries are\n * returned as objects; `<Objects>` feeds `typeIndex`; document meta from\n * `<Document ...>` attributes' sibling properties.\n */\nexport function parseDocumentXml(xml: string): Result<FcstdDocument, ParseError> {\n let doc: Document;\n try {\n // xmldom's Document type conflicts with lib: DOM; cast across the boundary.\n doc = new DOMParser().parseFromString(xml, 'application/xml') as unknown as Document;\n } catch (e) {\n return err({ kind: 'xml', message: `Document.xml parse failed: ${e instanceof Error ? e.message : String(e)}` });\n }\n const root = doc.documentElement;\n if (!root || root.tagName !== 'Document') {\n return err({ kind: 'xml', message: `root element is <${root?.tagName ?? 'none'}>, expected <Document>` });\n }\n\n const objects: FcstdObject[] = [];\n const typeIndex = new Map<string, string>();\n const meta = new Map<string, FcstdProperty>();\n\n for (let n = root.firstChild; n; n = n.nextSibling) {\n if (n.nodeType !== 1) continue;\n const el = n as Element;\n switch (el.tagName) {\n case 'Objects': {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType !== 1) continue;\n const oe = c as Element;\n if (oe.tagName !== 'Object') continue;\n const name = oe.getAttribute('name');\n const type = oe.getAttribute('type');\n if (name && type) typeIndex.set(name, type);\n }\n break;\n }\n case 'ObjectData': {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType !== 1) continue;\n const oe = c as Element;\n if (oe.tagName !== 'Object') continue;\n const name = oe.getAttribute('name') ?? '';\n // ObjectData <Object> carries only `name`; the type lives in the\n // <Objects> index (plan §3.3: Objects is the type index).\n const type = oe.getAttribute('type') ?? typeIndex.get(name) ?? '';\n const properties = new Map<string, FcstdProperty>();\n // properties live under a <Properties Count=\"N\"> wrapper element\n for (let p = oe.firstChild; p; p = p.nextSibling) {\n if (p.nodeType !== 1) continue;\n const pe = p as Element;\n if (pe.tagName === 'Properties') {\n for (let q = pe.firstChild; q; q = q.nextSibling) {\n if (q.nodeType !== 1) continue;\n const qe = q as Element;\n if (qe.tagName === '_Property') continue; // transient\n const prop = parseProperty(qe);\n if (prop.name) properties.set(prop.name, prop);\n }\n } else if (pe.tagName !== '_Property') {\n const prop = parseProperty(pe);\n if (prop.name) properties.set(prop.name, prop);\n }\n }\n objects.push({ name, type, properties });\n }\n break;\n }\n default: {\n // document meta properties (Creator, Uuid, LastModifiedDate, ...)\n const prop = parseProperty(el);\n if (prop.name) meta.set(prop.name, prop);\n }\n }\n }\n return ok({ objects, typeIndex, meta });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/fcstd/document.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M1.2 — Document.xml → object graph.\n *\n * Contract per plan §5.5 / 前文 A §3.3: `<ObjectData>` is authoritative\n * (objects + properties); `<Objects>` is only a type index. Transient\n * `_Property` elements are skipped.\n */\nimport { DOMParser, XMLSerializer } from '@xmldom/xmldom';\nimport { err, ok, type Result } from '../api/result.js';\n\n/** One parsed XML node from Document.xml: a property element (or nested value element) with its children. */\nexport interface FcstdProperty {\n /** property name attribute ('' for non-property elements like <Geometry>) */\n name: string;\n /** e.g. \"App::PropertyString\", \"Part::PropertyPartShape\" */\n type: string;\n /** serialized element tag, e.g. \"Geometry\", \"Constrain\", \"LineSegment\" */\n tagName: string;\n /** raw nested XML content (first element child), serialized */\n valueXml?: string;\n /** for simple value properties, the text content */\n valueText?: string;\n /** named sub-elements (e.g. <Python .../>, <ExpressionEngine> children) */\n children: FcstdProperty[];\n attributes: Record<string, string>;\n}\n\n/** One object from <ObjectData>: name, resolved type and its property map. */\nexport interface FcstdObject {\n /** object name, e.g. \"Sketch\" or \"Pad\" */\n name: string;\n /** e.g. \"Sketcher::SketchObject\", \"PartDesign::Pad\" */\n type: string;\n properties: Map<string, FcstdProperty>;\n}\n\n/** Parsed Document.xml: objects, the <Objects> type index and document-level meta. */\nexport interface FcstdDocument {\n objects: FcstdObject[];\n /** from <Objects>: name → type (index only, not authoritative) */\n typeIndex: Map<string, string>;\n /** document-level properties (Creator, LastModifiedDate, ...) */\n meta: Map<string, FcstdProperty>;\n}\n\n/** Parse failure detail; currently only XML-level errors (`kind: 'xml'`). */\nexport type ParseError = { kind: 'xml'; message: string };\n\nfunction attrs(el: Element): Record<string, string> {\n const out: Record<string, string> = {};\n for (let i = 0; i < el.attributes.length; i++) {\n const a = el.attributes.item(i);\n if (a) out[a.name] = a.value;\n }\n return out;\n}\n\nfunction firstElementChild(el: Element): Element | undefined {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType === 1) return c as Element;\n }\n return undefined;\n}\n\nfunction serialize(el: Element): string {\n // @xmldom/xmldom ships its own Node/Element types that conflict with lib: DOM;\n // the parser/serializer boundary is the only place the two universes meet.\n type SerNode = Parameters<XMLSerializer['serializeToString']>[0];\n return new XMLSerializer().serializeToString(el as unknown as SerNode);\n}\n\nfunction parseProperty(propEl: Element): FcstdProperty {\n const children: FcstdProperty[] = [];\n for (let c = propEl.firstChild; c; c = c.nextSibling) {\n if (c.nodeType === 1) {\n const child = c as Element;\n children.push(parseProperty(child));\n }\n }\n const valueEl = firstElementChild(propEl);\n return {\n name: propEl.getAttribute('name') ?? '',\n type: propEl.getAttribute('type') ?? '',\n tagName: propEl.tagName,\n attributes: attrs(propEl),\n valueXml: valueEl ? serialize(valueEl) : undefined,\n valueText: valueEl?.textContent ?? propEl.textContent ?? '',\n children,\n };\n}\n\n/**\n * Parse Document.xml into the object graph. Only `<ObjectData>` entries are\n * returned as objects; `<Objects>` feeds `typeIndex`; document meta from\n * `<Document ...>` attributes' sibling properties.\n *\n * @param xml raw Document.xml content\n * @returns the parsed object graph, or an xml ParseError\n */\nexport function parseDocumentXml(xml: string): Result<FcstdDocument, ParseError> {\n let doc: Document;\n try {\n // xmldom's Document type conflicts with lib: DOM; cast across the boundary.\n doc = new DOMParser().parseFromString(xml, 'application/xml') as unknown as Document;\n } catch (e) {\n return err({ kind: 'xml', message: `Document.xml parse failed: ${e instanceof Error ? e.message : String(e)}` });\n }\n const root = doc.documentElement;\n if (!root || root.tagName !== 'Document') {\n return err({ kind: 'xml', message: `root element is <${root?.tagName ?? 'none'}>, expected <Document>` });\n }\n\n const objects: FcstdObject[] = [];\n const typeIndex = new Map<string, string>();\n const meta = new Map<string, FcstdProperty>();\n\n for (let n = root.firstChild; n; n = n.nextSibling) {\n if (n.nodeType !== 1) continue;\n const el = n as Element;\n switch (el.tagName) {\n case 'Objects': {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType !== 1) continue;\n const oe = c as Element;\n if (oe.tagName !== 'Object') continue;\n const name = oe.getAttribute('name');\n const type = oe.getAttribute('type');\n if (name && type) typeIndex.set(name, type);\n }\n break;\n }\n case 'ObjectData': {\n for (let c = el.firstChild; c; c = c.nextSibling) {\n if (c.nodeType !== 1) continue;\n const oe = c as Element;\n if (oe.tagName !== 'Object') continue;\n const name = oe.getAttribute('name') ?? '';\n // ObjectData <Object> carries only `name`; the type lives in the\n // <Objects> index (plan §3.3: Objects is the type index).\n const type = oe.getAttribute('type') ?? typeIndex.get(name) ?? '';\n const properties = new Map<string, FcstdProperty>();\n // properties live under a <Properties Count=\"N\"> wrapper element\n for (let p = oe.firstChild; p; p = p.nextSibling) {\n if (p.nodeType !== 1) continue;\n const pe = p as Element;\n if (pe.tagName === 'Properties') {\n for (let q = pe.firstChild; q; q = q.nextSibling) {\n if (q.nodeType !== 1) continue;\n const qe = q as Element;\n if (qe.tagName === '_Property') continue; // transient\n const prop = parseProperty(qe);\n if (prop.name) properties.set(prop.name, prop);\n }\n } else if (pe.tagName !== '_Property') {\n const prop = parseProperty(pe);\n if (prop.name) properties.set(prop.name, prop);\n }\n }\n objects.push({ name, type, properties });\n }\n break;\n }\n default: {\n // document meta properties (Creator, Uuid, LastModifiedDate, ...)\n const prop = parseProperty(el);\n if (prop.name) meta.set(prop.name, prop);\n }\n }\n }\n return ok({ objects, typeIndex, meta });\n}\n"]}
|
|
@@ -12,14 +12,20 @@
|
|
|
12
12
|
* treat the property as unknown and degrade (no heuristic fallback, plan §12).
|
|
13
13
|
*/
|
|
14
14
|
import type { FcstdProperty } from './document.js';
|
|
15
|
+
/** Evaluated expression result in mm (angles keep their own unit): a number, or undefined when unsupported. */
|
|
15
16
|
export type ExprValue = number | undefined;
|
|
16
17
|
/**
|
|
17
18
|
* Evaluate a constant expression. Returns undefined when the expression is
|
|
18
19
|
* not a bare constant (reference/arithmetic/function) — explicit unsupported,
|
|
19
20
|
* no guessing.
|
|
21
|
+
*
|
|
22
|
+
* @param expr raw expression string (e.g. "10 mm")
|
|
23
|
+
* @returns the value in mm, or undefined when not a constant expression
|
|
20
24
|
*/
|
|
21
25
|
export declare function evalConstantExpression(expr: string): ExprValue;
|
|
26
|
+
/** One <Expression path=... expression=...> binding with its optional constant value. */
|
|
22
27
|
export interface ExpressionBinding {
|
|
28
|
+
/** property path the expression drives (e.g. "Length") */
|
|
23
29
|
path: string;
|
|
24
30
|
/** raw expression string */
|
|
25
31
|
expression: string;
|
|
@@ -30,8 +36,15 @@ export interface ExpressionBinding {
|
|
|
30
36
|
* Extract expression bindings from a parsed ExpressionEngine property.
|
|
31
37
|
* `bindable` = every expression evaluated to a constant (then the property
|
|
32
38
|
* values can be overridden); otherwise the engine is only partially readable.
|
|
39
|
+
*
|
|
40
|
+
* @param prop the parsed <ExpressionEngine> property (undefined → no bindings)
|
|
41
|
+
* @returns one binding per <Expression> child, values evaluated
|
|
33
42
|
*/
|
|
34
43
|
export declare function parseExpressionEngine(prop: FcstdProperty | undefined): ExpressionBinding[];
|
|
35
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* True when all bindings are constants → safe to override property values.
|
|
46
|
+
* @param bindings bindings extracted by parseExpressionEngine
|
|
47
|
+
* @returns true when there is at least one binding and every value is defined
|
|
48
|
+
*/
|
|
36
49
|
export declare function allConstant(bindings: ExpressionBinding[]): boolean;
|
|
37
50
|
//# sourceMappingURL=expressions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/fcstd/expressions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAa3C
|
|
1
|
+
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/fcstd/expressions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,+GAA+G;AAC/G,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAa3C;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAY9D;AAGD,yFAAyF;AACzF,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,aAAa,GAAG,SAAS,GAC9B,iBAAiB,EAAE,CAWrB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAElE"}
|
|
@@ -12,6 +12,9 @@ const UNIT_TO_MM = {
|
|
|
12
12
|
* Evaluate a constant expression. Returns undefined when the expression is
|
|
13
13
|
* not a bare constant (reference/arithmetic/function) — explicit unsupported,
|
|
14
14
|
* no guessing.
|
|
15
|
+
*
|
|
16
|
+
* @param expr raw expression string (e.g. "10 mm")
|
|
17
|
+
* @returns the value in mm, or undefined when not a constant expression
|
|
15
18
|
*/
|
|
16
19
|
export function evalConstantExpression(expr) {
|
|
17
20
|
const s = expr.trim();
|
|
@@ -34,6 +37,9 @@ export function evalConstantExpression(expr) {
|
|
|
34
37
|
* Extract expression bindings from a parsed ExpressionEngine property.
|
|
35
38
|
* `bindable` = every expression evaluated to a constant (then the property
|
|
36
39
|
* values can be overridden); otherwise the engine is only partially readable.
|
|
40
|
+
*
|
|
41
|
+
* @param prop the parsed <ExpressionEngine> property (undefined → no bindings)
|
|
42
|
+
* @returns one binding per <Expression> child, values evaluated
|
|
37
43
|
*/
|
|
38
44
|
export function parseExpressionEngine(prop) {
|
|
39
45
|
const engineEl = prop?.children[0];
|
|
@@ -49,7 +55,11 @@ export function parseExpressionEngine(prop) {
|
|
|
49
55
|
}
|
|
50
56
|
return out;
|
|
51
57
|
}
|
|
52
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* True when all bindings are constants → safe to override property values.
|
|
60
|
+
* @param bindings bindings extracted by parseExpressionEngine
|
|
61
|
+
* @returns true when there is at least one binding and every value is defined
|
|
62
|
+
*/
|
|
53
63
|
export function allConstant(bindings) {
|
|
54
64
|
return bindings.length > 0 && bindings.every((b) => b.value !== undefined);
|
|
55
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.js","sourceRoot":"","sources":["../../src/fcstd/expressions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"expressions.js","sourceRoot":"","sources":["../../src/fcstd/expressions.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,GAA2B;IACzC,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;IACpB,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE;IACtB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IACpB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IAC/B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK;IACtB,qEAAqE;IACrE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;IACzB,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,gBAAgB;IAChB,MAAM,CAAC,GAAG,+DAA+D,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACnB,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC,CAAC,6BAA6B;IACzE,OAAO,KAAK,GAAG,MAAM,CAAC;AACxB,CAAC;AAaD;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAA+B;IAE/B,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC,OAAO,KAAK,YAAY;YAAE,SAAS;QAC1C,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAA6B;IACvD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/**\r\n * M6.2 — expression downgrade: <ExpressionEngine> → concrete values.\r\n *\r\n * Format (verified on TwoLengthsPadWithExpression.FCStd):\r\n * <ExpressionEngine count=\"N\">\r\n * <Expression path=\"Length\" expression=\"10 mm\" />\r\n * </ExpressionEngine>\r\n *\r\n * Scope: constant expressions only — number literals with optional unit\r\n * (mm/m/cm/in/deg/rad). Anything else (object references like Sketch.Constraints[3],\r\n * arithmetic with identifiers, functions) is NOT evaluated: the consumer must\r\n * treat the property as unknown and degrade (no heuristic fallback, plan §12).\r\n */\r\nimport type { FcstdProperty } from './document.js';\r\n\r\n/** Evaluated expression result in mm (angles keep their own unit): a number, or undefined when unsupported. */\nexport type ExprValue = number | undefined;\r\n\r\nconst UNIT_TO_MM: Record<string, number> = {\r\n mm: 1, millimeter: 1,\r\n cm: 10, centimeter: 10,\r\n m: 1000, meter: 1000,\r\n in: 25.4, inch: 25.4, '\"': 25.4,\r\n ft: 304.8, foot: 304.8,\r\n // angles: value kept in the expression's own unit; callers interpret\r\n deg: 1, degree: 1, '°': 1,\r\n rad: 1, radian: 1,\r\n};\r\n\r\n/**\r\n * Evaluate a constant expression. Returns undefined when the expression is\r\n * not a bare constant (reference/arithmetic/function) — explicit unsupported,\r\n * no guessing.\r\n *\r\n * @param expr raw expression string (e.g. \"10 mm\")\r\n * @returns the value in mm, or undefined when not a constant expression\r\n */\r\nexport function evalConstantExpression(expr: string): ExprValue {\r\n const s = expr.trim();\r\n // number [unit]\r\n const m = /^([-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?)\\s*([A-Za-z°\"]*)$/.exec(s);\r\n if (!m) return undefined;\r\n const value = Number(m[1]);\r\n if (!Number.isFinite(value)) return undefined;\r\n const unit = m[2]!;\r\n if (unit === '') return value;\r\n const factor = UNIT_TO_MM[unit.toLowerCase()];\r\n if (factor === undefined) return undefined; // unknown unit → unsupported\r\n return value * factor;\r\n}\r\n\r\n\r\n/** One <Expression path=... expression=...> binding with its optional constant value. */\r\nexport interface ExpressionBinding {\r\n /** property path the expression drives (e.g. \"Length\") */\r\n path: string;\r\n /** raw expression string */\r\n expression: string;\r\n /** evaluated constant; undefined when not a constant expression */\r\n value?: number;\r\n}\r\n\r\n/**\r\n * Extract expression bindings from a parsed ExpressionEngine property.\r\n * `bindable` = every expression evaluated to a constant (then the property\r\n * values can be overridden); otherwise the engine is only partially readable.\r\n *\r\n * @param prop the parsed <ExpressionEngine> property (undefined → no bindings)\r\n * @returns one binding per <Expression> child, values evaluated\r\n */\r\nexport function parseExpressionEngine(\r\n prop: FcstdProperty | undefined,\r\n): ExpressionBinding[] {\r\n const engineEl = prop?.children[0];\r\n if (!engineEl) return [];\r\n const out: ExpressionBinding[] = [];\r\n for (const el of engineEl.children) {\r\n if (el.tagName !== 'Expression') continue;\r\n const path = el.attributes['path'] ?? '';\r\n const expression = el.attributes['expression'] ?? '';\r\n out.push({ path, expression, value: evalConstantExpression(expression) });\r\n }\r\n return out;\r\n}\r\n\r\n/**\n * True when all bindings are constants → safe to override property values.\r\n * @param bindings bindings extracted by parseExpressionEngine\r\n * @returns true when there is at least one binding and every value is defined\r\n */\r\nexport function allConstant(bindings: ExpressionBinding[]): boolean {\r\n return bindings.length > 0 && bindings.every((b) => b.value !== undefined);\r\n}\r\n"]}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type FcstdArchive } from './unpack.js';
|
|
2
2
|
import type { FcstdDocument, FcstdProperty } from './document.js';
|
|
3
|
+
/**
|
|
4
|
+
* One resolved external-geometry link of a sketch.
|
|
5
|
+
*/
|
|
3
6
|
export interface ExternalLink {
|
|
4
7
|
/** source object name, e.g. "Chamfer002" */
|
|
5
8
|
obj: string;
|
|
@@ -8,6 +11,10 @@ export interface ExternalLink {
|
|
|
8
11
|
/** resolved sketch-local 2D polyline */
|
|
9
12
|
polyline: [number, number][];
|
|
10
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Result of external-geometry resolution: successfully projected links plus
|
|
16
|
+
* per-link failures (with a human-readable reason) for the caller to report.
|
|
17
|
+
*/
|
|
11
18
|
export interface ExternalGeoResult {
|
|
12
19
|
links: ExternalLink[];
|
|
13
20
|
failures: {
|
|
@@ -18,7 +25,14 @@ export interface ExternalGeoResult {
|
|
|
18
25
|
}
|
|
19
26
|
/**
|
|
20
27
|
* Resolve every external link of a sketch to sketch-local 2D polylines.
|
|
21
|
-
*
|
|
28
|
+
*
|
|
29
|
+
* @param externalGeoProp - the sketch's ExternalGeometry property.
|
|
30
|
+
* @param doc - the parsed FCStd document, used to locate source objects and their shapes.
|
|
31
|
+
* @param archive - the FCStd container, used to read the source `.brp` shape files.
|
|
32
|
+
* @param sketchPlacement - the sketch's Placement property, whose inverse maps
|
|
33
|
+
* source geometry into sketch-local coordinates.
|
|
34
|
+
* @returns the resolved sketch-local polylines per link, plus a failure entry
|
|
35
|
+
* (with reason) for every link that could not be resolved.
|
|
22
36
|
*/
|
|
23
37
|
export declare function resolveExternalGeometry(externalGeoProp: FcstdProperty | undefined, doc: FcstdDocument, archive: FcstdArchive, sketchPlacement: FcstdProperty | undefined): Promise<ExternalGeoResult>;
|
|
24
38
|
//# sourceMappingURL=external-geo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-geo.d.ts","sourceRoot":"","sources":["../../src/fcstd/external-geo.ts"],"names":[],"mappings":"AAWA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAe,aAAa,EAAE,MAAM,eAAe,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D;AAiCD
|
|
1
|
+
{"version":3,"file":"external-geo.d.ts","sourceRoot":"","sources":["../../src/fcstd/external-geo.ts"],"names":[],"mappings":"AAWA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAe,aAAa,EAAE,MAAM,eAAe,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D;AAiCD;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,eAAe,EAAE,aAAa,GAAG,SAAS,EAC1C,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,YAAY,EACrB,eAAe,EAAE,aAAa,GAAG,SAAS,GACzC,OAAO,CAAC,iBAAiB,CAAC,CA4E5B"}
|
|
@@ -41,7 +41,14 @@ function placementOf(obj) {
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Resolve every external link of a sketch to sketch-local 2D polylines.
|
|
44
|
-
*
|
|
44
|
+
*
|
|
45
|
+
* @param externalGeoProp - the sketch's ExternalGeometry property.
|
|
46
|
+
* @param doc - the parsed FCStd document, used to locate source objects and their shapes.
|
|
47
|
+
* @param archive - the FCStd container, used to read the source `.brp` shape files.
|
|
48
|
+
* @param sketchPlacement - the sketch's Placement property, whose inverse maps
|
|
49
|
+
* source geometry into sketch-local coordinates.
|
|
50
|
+
* @returns the resolved sketch-local polylines per link, plus a failure entry
|
|
51
|
+
* (with reason) for every link that could not be resolved.
|
|
45
52
|
*/
|
|
46
53
|
export async function resolveExternalGeometry(externalGeoProp, doc, archive, sketchPlacement) {
|
|
47
54
|
const links = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-geo.js","sourceRoot":"","sources":["../../src/fcstd/external-geo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M6.3 — external geometry resolution: decode ExternalGeometry links\n * (App::PropertyLinkSubList), load the source object's .brp via OCCT,\n * extract the named edge polyline (TopExp::MapShapes + IndexedMap order —\n * Edge13 = wireframe edgeGroups[12], verified against hole_puzzle.fcstd),\n * and project it into sketch-local 2D via the sketch Placement inverse.\n *\n * Result: fixed 2D segments/points that the solver treats as immutable\n * constraints targets (geoId -3, -4, ... in link order).\n */\nimport { initOcctWasm } from '../occt-kernel/occtKernel.js';\nimport { memberText, type FcstdArchive } from './unpack.js';\nimport type { FcstdDocument, FcstdObject, FcstdProperty } from './document.js';\n\nexport interface ExternalLink {\n /** source object name, e.g. \"Chamfer002\" */\n obj: string;\n /** sub-element name, e.g. \"Edge13\" */\n sub: string;\n /** resolved sketch-local 2D polyline */\n polyline: [number, number][];\n}\n\nexport interface ExternalGeoResult {\n links: ExternalLink[];\n failures: { obj: string; sub: string; reason: string }[];\n}\n\n/** Quaternion (x,y,z,w) inverse-rotate + translate into sketch-local frame. */\nfunction makeInverseTransformer(q: [number, number, number, number], p: [number, number, number]) {\n const n = Math.hypot(q[0], q[1], q[2], q[3]);\n const [qx, qy, qz, qw] = [-q[0] / n, -q[1] / n, -q[2] / n, q[3] / n]; // conjugate\n return (w: [number, number, number]): [number, number, number] => {\n // local = R⁻¹ · (world − P): subtract the translation FIRST, then rotate\n // by the conjugate quaternion. GOTCHA (probe-hole-ext.ts): rotating first\n // and subtracting after (R⁻¹·v − P) is only correct for identity rotation\n // — with Sketch005's 90° placement it shifted projected points by the\n // rotated translation (−140,30 instead of (−40,40)) and the solver chased\n // the wrong frame (delta 1.0e2).\n const [vx, vy, vz] = [w[0] - p[0], w[1] - p[1], w[2] - p[2]];\n const tx = 2 * (qy * vz - qz * vy);\n const ty = 2 * (qz * vx - qx * vz);\n const tz = 2 * (qx * vy - qy * vx);\n const rx = vx + qw * tx + (qy * tz - qz * ty);\n const ry = vy + qw * ty + (qz * tx - qx * tz);\n const rz = vz + qw * tz + (qx * ty - qy * tx);\n return [rx, ry, rz];\n };\n}\n\nfunction placementOf(obj: FcstdObject): { q: [number, number, number, number]; p: [number, number, number] } {\n const el = obj.properties.get('Placement')?.children[0];\n const a = el?.attributes ?? {};\n return {\n p: [Number(a['Px'] ?? 0), Number(a['Py'] ?? 0), Number(a['Pz'] ?? 0)],\n q: [Number(a['Q0'] ?? 0), Number(a['Q1'] ?? 0), Number(a['Q2'] ?? 0), Number(a['Q3'] ?? 1)],\n };\n}\n\n/**\n * Resolve every external link of a sketch to sketch-local 2D polylines.\n * `externalGeoProp` is the sketch's ExternalGeometry property.\n */\nexport async function resolveExternalGeometry(\n externalGeoProp: FcstdProperty | undefined,\n doc: FcstdDocument,\n archive: FcstdArchive,\n sketchPlacement: FcstdProperty | undefined,\n): Promise<ExternalGeoResult> {\n const links: ExternalLink[] = [];\n const failures: ExternalGeoResult['failures'] = [];\n const listEl = externalGeoProp?.children[0];\n if (!listEl) return { links, failures };\n\n const skPl = placementOf({ name: '', type: '', properties: new Map([['Placement', sketchPlacement ?? { name: 'Placement', type: '', tagName: 'Property', children: [], valueXml: '', valueText: '', attributes: {} } as FcstdProperty]]) as never });\n const toLocal = makeInverseTransformer(skPl.q, skPl.p);\n\n const kernel: {\n fromBREP: (s: string) => unknown;\n wireframe: (s: unknown, deflection: number) => { points: Float32Array; edgeGroups: number[] };\n } = (await initOcctWasm()) as never;\n\n const brpCache = new Map<string, { points: Float32Array; edgeGroups: number[] } | undefined>();\n const wireframeOf = (objName: string) => {\n if (brpCache.has(objName)) return brpCache.get(objName);\n const src = doc.objects.find((o) => o.name === objName);\n const brpFile = src?.properties.get('Shape')?.children[0]?.attributes['file'];\n if (!brpFile) {\n brpCache.set(objName, undefined);\n return undefined;\n }\n const brp = memberText(archive, brpFile);\n if (!brp) {\n brpCache.set(objName, undefined);\n return undefined;\n }\n try {\n const shape = kernel.fromBREP(brp);\n const wf = kernel.wireframe(shape, 0.01);\n brpCache.set(objName, wf);\n return wf;\n } catch {\n brpCache.set(objName, undefined);\n return undefined;\n }\n };\n\n for (const link of listEl.children) {\n const obj = link.attributes['obj'] ?? '';\n const sub = link.attributes['sub'] ?? '';\n const ord = Number(sub.replace('Edge', ''));\n if (!obj || !sub.startsWith('Edge') || !Number.isInteger(ord) || ord < 1) {\n failures.push({ obj, sub, reason: `unsupported sub-element: ${sub}` });\n continue;\n }\n const wf = wireframeOf(obj);\n if (!wf) {\n failures.push({ obj, sub, reason: 'source shape not loadable' });\n continue;\n }\n const idx = ord - 1; // Edge13 → edgeGroups[12]\n const g0 = wf.edgeGroups[idx * 3];\n const g1 = wf.edgeGroups[idx * 3 + 1];\n if (g0 === undefined || g1 === undefined) {\n failures.push({ obj, sub, reason: `edge ordinal out of range (${wf.edgeGroups.length / 3} edges)` });\n continue;\n }\n const n = Math.floor(g1 / 3);\n const polyline: [number, number][] = [];\n for (let p = 0; p < n; p++) {\n const w: [number, number, number] = [\n wf.points[g0 + p * 3]!, wf.points[g0 + p * 3 + 1]!, wf.points[g0 + p * 3 + 2]!,\n ];\n const l = toLocal(w);\n polyline.push([l[0], l[1]]);\n }\n // drop consecutive duplicates\n const deduped = polyline.filter(\n (pt, i) => i === 0 || Math.hypot(pt[0] - polyline[i - 1]![0], pt[1] - polyline[i - 1]![1]) > 1e-9,\n );\n if (deduped.length >= 2) links.push({ obj, sub, polyline: deduped });\n else failures.push({ obj, sub, reason: 'degenerate polyline' });\n }\n return { links, failures };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"external-geo.js","sourceRoot":"","sources":["../../src/fcstd/external-geo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M6.3 — external geometry resolution: decode ExternalGeometry links\n * (App::PropertyLinkSubList), load the source object's .brp via OCCT,\n * extract the named edge polyline (TopExp::MapShapes + IndexedMap order —\n * Edge13 = wireframe edgeGroups[12], verified against hole_puzzle.fcstd),\n * and project it into sketch-local 2D via the sketch Placement inverse.\n *\n * Result: fixed 2D segments/points that the solver treats as immutable\n * constraints targets (geoId -3, -4, ... in link order).\n */\nimport { initOcctWasm } from '../occt-kernel/occtKernel.js';\nimport { memberText, type FcstdArchive } from './unpack.js';\nimport type { FcstdDocument, FcstdObject, FcstdProperty } from './document.js';\n\n/**\n * One resolved external-geometry link of a sketch.\n */\nexport interface ExternalLink {\n /** source object name, e.g. \"Chamfer002\" */\n obj: string;\n /** sub-element name, e.g. \"Edge13\" */\n sub: string;\n /** resolved sketch-local 2D polyline */\n polyline: [number, number][];\n}\n\n/**\n * Result of external-geometry resolution: successfully projected links plus\n * per-link failures (with a human-readable reason) for the caller to report.\n */\nexport interface ExternalGeoResult {\n links: ExternalLink[];\n failures: { obj: string; sub: string; reason: string }[];\n}\n\n/** Quaternion (x,y,z,w) inverse-rotate + translate into sketch-local frame. */\nfunction makeInverseTransformer(q: [number, number, number, number], p: [number, number, number]) {\n const n = Math.hypot(q[0], q[1], q[2], q[3]);\n const [qx, qy, qz, qw] = [-q[0] / n, -q[1] / n, -q[2] / n, q[3] / n]; // conjugate\n return (w: [number, number, number]): [number, number, number] => {\n // local = R⁻¹ · (world − P): subtract the translation FIRST, then rotate\n // by the conjugate quaternion. GOTCHA (probe-hole-ext.ts): rotating first\n // and subtracting after (R⁻¹·v − P) is only correct for identity rotation\n // — with Sketch005's 90° placement it shifted projected points by the\n // rotated translation (−140,30 instead of (−40,40)) and the solver chased\n // the wrong frame (delta 1.0e2).\n const [vx, vy, vz] = [w[0] - p[0], w[1] - p[1], w[2] - p[2]];\n const tx = 2 * (qy * vz - qz * vy);\n const ty = 2 * (qz * vx - qx * vz);\n const tz = 2 * (qx * vy - qy * vx);\n const rx = vx + qw * tx + (qy * tz - qz * ty);\n const ry = vy + qw * ty + (qz * tx - qx * tz);\n const rz = vz + qw * tz + (qx * ty - qy * tx);\n return [rx, ry, rz];\n };\n}\n\nfunction placementOf(obj: FcstdObject): { q: [number, number, number, number]; p: [number, number, number] } {\n const el = obj.properties.get('Placement')?.children[0];\n const a = el?.attributes ?? {};\n return {\n p: [Number(a['Px'] ?? 0), Number(a['Py'] ?? 0), Number(a['Pz'] ?? 0)],\n q: [Number(a['Q0'] ?? 0), Number(a['Q1'] ?? 0), Number(a['Q2'] ?? 0), Number(a['Q3'] ?? 1)],\n };\n}\n\n/**\n * Resolve every external link of a sketch to sketch-local 2D polylines.\n *\n * @param externalGeoProp - the sketch's ExternalGeometry property.\n * @param doc - the parsed FCStd document, used to locate source objects and their shapes.\n * @param archive - the FCStd container, used to read the source `.brp` shape files.\n * @param sketchPlacement - the sketch's Placement property, whose inverse maps\n * source geometry into sketch-local coordinates.\n * @returns the resolved sketch-local polylines per link, plus a failure entry\n * (with reason) for every link that could not be resolved.\n */\nexport async function resolveExternalGeometry(\n externalGeoProp: FcstdProperty | undefined,\n doc: FcstdDocument,\n archive: FcstdArchive,\n sketchPlacement: FcstdProperty | undefined,\n): Promise<ExternalGeoResult> {\n const links: ExternalLink[] = [];\n const failures: ExternalGeoResult['failures'] = [];\n const listEl = externalGeoProp?.children[0];\n if (!listEl) return { links, failures };\n\n const skPl = placementOf({ name: '', type: '', properties: new Map([['Placement', sketchPlacement ?? { name: 'Placement', type: '', tagName: 'Property', children: [], valueXml: '', valueText: '', attributes: {} } as FcstdProperty]]) as never });\n const toLocal = makeInverseTransformer(skPl.q, skPl.p);\n\n const kernel: {\n fromBREP: (s: string) => unknown;\n wireframe: (s: unknown, deflection: number) => { points: Float32Array; edgeGroups: number[] };\n } = (await initOcctWasm()) as never;\n\n const brpCache = new Map<string, { points: Float32Array; edgeGroups: number[] } | undefined>();\n const wireframeOf = (objName: string) => {\n if (brpCache.has(objName)) return brpCache.get(objName);\n const src = doc.objects.find((o) => o.name === objName);\n const brpFile = src?.properties.get('Shape')?.children[0]?.attributes['file'];\n if (!brpFile) {\n brpCache.set(objName, undefined);\n return undefined;\n }\n const brp = memberText(archive, brpFile);\n if (!brp) {\n brpCache.set(objName, undefined);\n return undefined;\n }\n try {\n const shape = kernel.fromBREP(brp);\n const wf = kernel.wireframe(shape, 0.01);\n brpCache.set(objName, wf);\n return wf;\n } catch {\n brpCache.set(objName, undefined);\n return undefined;\n }\n };\n\n for (const link of listEl.children) {\n const obj = link.attributes['obj'] ?? '';\n const sub = link.attributes['sub'] ?? '';\n const ord = Number(sub.replace('Edge', ''));\n if (!obj || !sub.startsWith('Edge') || !Number.isInteger(ord) || ord < 1) {\n failures.push({ obj, sub, reason: `unsupported sub-element: ${sub}` });\n continue;\n }\n const wf = wireframeOf(obj);\n if (!wf) {\n failures.push({ obj, sub, reason: 'source shape not loadable' });\n continue;\n }\n const idx = ord - 1; // Edge13 → edgeGroups[12]\n const g0 = wf.edgeGroups[idx * 3];\n const g1 = wf.edgeGroups[idx * 3 + 1];\n if (g0 === undefined || g1 === undefined) {\n failures.push({ obj, sub, reason: `edge ordinal out of range (${wf.edgeGroups.length / 3} edges)` });\n continue;\n }\n const n = Math.floor(g1 / 3);\n const polyline: [number, number][] = [];\n for (let p = 0; p < n; p++) {\n const w: [number, number, number] = [\n wf.points[g0 + p * 3]!, wf.points[g0 + p * 3 + 1]!, wf.points[g0 + p * 3 + 2]!,\n ];\n const l = toLocal(w);\n polyline.push([l[0], l[1]]);\n }\n // drop consecutive duplicates\n const deduped = polyline.filter(\n (pt, i) => i === 0 || Math.hypot(pt[0] - polyline[i - 1]![0], pt[1] - polyline[i - 1]![1]) > 1e-9,\n );\n if (deduped.length >= 2) links.push({ obj, sub, polyline: deduped });\n else failures.push({ obj, sub, reason: 'degenerate polyline' });\n }\n return { links, failures };\n}\n"]}
|
|
@@ -11,9 +11,13 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { FcstdObject } from './document.js';
|
|
13
13
|
import { type ExpressionBinding } from './expressions.js';
|
|
14
|
+
/**
|
|
15
|
+
* One cad-op call in the M4 call plan (lowered to .fai.js by M5).
|
|
16
|
+
*/
|
|
14
17
|
export interface CadCall {
|
|
15
18
|
/** target variable name (partN, assigned by M5) */
|
|
16
19
|
out: string;
|
|
20
|
+
/** cad-op name, e.g. "cad.box" */
|
|
17
21
|
op: string;
|
|
18
22
|
/** positional + named params, JSON-serializable */
|
|
19
23
|
params: Record<string, unknown>;
|
|
@@ -50,6 +54,10 @@ export declare function jsExpr(code: string): JsExpr;
|
|
|
50
54
|
* @returns true when `v` is a `JsExpr` marker.
|
|
51
55
|
*/
|
|
52
56
|
export declare function isJsExpr(v: unknown): v is JsExpr;
|
|
57
|
+
/**
|
|
58
|
+
* Outcome of translating one FCStd object: a cad-op call plan, an explicit
|
|
59
|
+
* bake with reason, or preserved-only (no geometry emitted).
|
|
60
|
+
*/
|
|
53
61
|
export type TranslateVerdict = {
|
|
54
62
|
kind: 'translated';
|
|
55
63
|
calls: CadCall[];
|
|
@@ -61,14 +69,42 @@ export type TranslateVerdict = {
|
|
|
61
69
|
kind: 'preserved-only';
|
|
62
70
|
reason: string;
|
|
63
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* True when the object type is on the M4.1 translation whitelist.
|
|
74
|
+
*
|
|
75
|
+
* @param type - the FCStd object type, e.g. "Part::Box".
|
|
76
|
+
* @returns true when the type is whitelisted for translation.
|
|
77
|
+
*/
|
|
64
78
|
export declare function isWhitelisted(type: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* H10 (plan §3.1/§3.5): C4's Python exception, decided by PROPERTY presence —
|
|
81
|
+
* NOT by the `Python` type-name suffix. Matches the library profile's
|
|
82
|
+
* pythonObjects口径 (profile.mjs: type contains "Python" or carries
|
|
83
|
+
* Python/Proxy properties); here only the property evidence qualifies, so a
|
|
84
|
+
* Python-suffixed type without the property stays a plain translation gap.
|
|
85
|
+
* @param obj - the FCStd object to inspect.
|
|
86
|
+
* @returns true when the object is a Python-scripted feature whose serialized
|
|
87
|
+
* shape is opaque (legitimate `python-baked` under C4).
|
|
88
|
+
*/
|
|
89
|
+
export declare function isPythonOpaque(obj: FcstdObject): boolean;
|
|
65
90
|
/**
|
|
66
91
|
* M11.1/M11.2: the ExpressionEngine binding for `name`, if any. `value` is
|
|
67
92
|
* undefined for non-constant expressions (references/arithmetic) — the caller
|
|
68
93
|
* must bake with an explicit reason instead of estimating.
|
|
94
|
+
*
|
|
95
|
+
* @param obj - the FCStd object whose ExpressionEngine to inspect.
|
|
96
|
+
* @param name - the property name to look up.
|
|
97
|
+
* @returns the binding for `name`, or undefined when the object has no
|
|
98
|
+
* ExpressionEngine binding for it.
|
|
69
99
|
*/
|
|
70
100
|
export declare function expressionBindingOf(obj: FcstdObject, name: string): ExpressionBinding | undefined;
|
|
71
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* M11.2: detect a non-constant expression binding on a property.
|
|
103
|
+
*
|
|
104
|
+
* @param obj - the FCStd object whose ExpressionEngine to inspect.
|
|
105
|
+
* @param name - the property name to look up.
|
|
106
|
+
* @returns true when `name` has a binding that is NOT a constant expression.
|
|
107
|
+
*/
|
|
72
108
|
export declare function hasNonConstantBinding(obj: FcstdObject, name: string): boolean;
|
|
73
109
|
/**
|
|
74
110
|
* M9.1 — Pad/Pocket `Type` enumeration (App::PropertyEnumeration, stored as
|
|
@@ -79,6 +115,14 @@ export declare function hasNonConstantBinding(obj: FcstdObject, name: string): b
|
|
|
79
115
|
* A missing Type property means Length (0) — the FreeCAD default.
|
|
80
116
|
*/
|
|
81
117
|
export type FeatureType = 'Length' | 'ThroughAll' | 'UpToLast' | 'UpToFirst' | 'UpToFace' | 'TwoLengths' | 'unknown';
|
|
118
|
+
/**
|
|
119
|
+
* Read the Pad/Pocket `Type` enumeration of an object (M9.1).
|
|
120
|
+
*
|
|
121
|
+
* @param obj - the FCStd Pad or Pocket object.
|
|
122
|
+
* @param kind - which type-enum table to apply (Pad vs Pocket labels differ).
|
|
123
|
+
* @returns the parsed feature type; 'Length' when Type is missing, 'unknown'
|
|
124
|
+
* when the stored label/index is not recognized.
|
|
125
|
+
*/
|
|
82
126
|
export declare function featureTypeOf(obj: FcstdObject, kind: 'pad' | 'pocket'): FeatureType;
|
|
83
127
|
/**
|
|
84
128
|
* Parse a PartDesign ReferenceAxis reference into a 3D axis + pivot point.
|
|
@@ -88,12 +132,21 @@ export declare function featureTypeOf(obj: FcstdObject, kind: 'pad' | 'pocket'):
|
|
|
88
132
|
* that PartDesign revolves around = +Z) or an edge/vertex of another feature.
|
|
89
133
|
* Edge/vertex axes require resolving referenced geometry, which the port does
|
|
90
134
|
* not yet do (explicit downgrade, no silent loss).
|
|
135
|
+
*
|
|
136
|
+
* @param ref - the ReferenceAxis (or Direction) LinkSub string, may be undefined.
|
|
137
|
+
* @returns a unit axis and pivot point, or undefined when the reference names
|
|
138
|
+
* edge/vertex geometry (unsupported).
|
|
91
139
|
*/
|
|
92
140
|
export declare function parseReferenceAxis(ref: string | undefined): {
|
|
93
141
|
axis: [number, number, number];
|
|
94
142
|
at: [number, number, number];
|
|
95
143
|
} | undefined;
|
|
96
|
-
/**
|
|
144
|
+
/**
|
|
145
|
+
* Placement position (translation) of an object.
|
|
146
|
+
*
|
|
147
|
+
* @param obj - the FCStd object to read.
|
|
148
|
+
* @returns the (Px, Py, Pz) translation from its Placement, or (0,0,0) when absent.
|
|
149
|
+
*/
|
|
97
150
|
export declare function placementPos(obj: FcstdObject): [number, number, number];
|
|
98
151
|
/**
|
|
99
152
|
* M4 translate one object. `inputVar` maps a dependency object name to the
|
|
@@ -102,6 +155,15 @@ export declare function placementPos(obj: FcstdObject): [number, number, number]
|
|
|
102
155
|
* `docObjects` (optional) is the full document object list — needed by the
|
|
103
156
|
* UpToFace datum-plane path to read the target plane's Placement (plan
|
|
104
157
|
* extrude-upto-face §4.3-C1). When absent, UpToFace keeps the explicit bake.
|
|
158
|
+
*
|
|
159
|
+
* @param obj - the FCStd object to translate.
|
|
160
|
+
* @param inputVar - resolves a dependency object name to the variable holding
|
|
161
|
+
* its geometry (sketch contours or prior solid).
|
|
162
|
+
* @param docObjects - the full document object list, needed by the UpToFace
|
|
163
|
+
* datum-plane path; optional.
|
|
164
|
+
* @returns the cad-op call plan, or an explicit bake/preserve verdict with reason.
|
|
105
165
|
*/
|
|
106
|
-
export declare function translateObject(obj: FcstdObject, inputVar: (depName: string) => string | undefined, docObjects?: readonly FcstdObject[]
|
|
166
|
+
export declare function translateObject(obj: FcstdObject, inputVar: (depName: string) => string | undefined, docObjects?: readonly FcstdObject[],
|
|
167
|
+
/** H7: names of objects whose Shape is stored as a .brp member (probed from the ZIP). */
|
|
168
|
+
shapeCarriers?: ReadonlySet<string>): TranslateVerdict;
|
|
107
169
|
//# sourceMappingURL=feature-translate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-translate.d.ts","sourceRoot":"","sources":["../../src/fcstd/feature-translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGjF,MAAM,WAAW,OAAO;IACtB,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,gFAAgF;IAChF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,MAAM;IACrB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAEhD;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAuB/C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAeD
|
|
1
|
+
{"version":3,"file":"feature-translate.d.ts","sourceRoot":"","sources":["../../src/fcstd/feature-translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGjF;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,gFAAgF;IAChF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,MAAM;IACrB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAEhD;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAuB/C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAMxD;AAeD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAKjG;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7E;AAoBD;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GACnB,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;AAW/F;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAMnF;AAwED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,SAAS,CAYxI;AAWD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CASvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EACjD,UAAU,CAAC,EAAE,SAAS,WAAW,EAAE;AACnC,yFAAyF;AACzF,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAClC,gBAAgB,CAkgBlB"}
|
|
@@ -32,15 +32,40 @@ const WHITELIST = new Set([
|
|
|
32
32
|
'PartDesign::PolarPattern',
|
|
33
33
|
'PartDesign::Fillet',
|
|
34
34
|
'PartDesign::Chamfer',
|
|
35
|
-
// M13.1 (probed on real corpus —
|
|
35
|
+
// M13.1 (probed on real corpus — fcstd-port/tools/probe-m13-types.ts):
|
|
36
36
|
// Part::Compound carries a Links PropertyLinkList; Part::Sphere carries
|
|
37
37
|
// Radius (+ optional Angle like Cylinder).
|
|
38
38
|
'Part::Compound',
|
|
39
39
|
'Part::Sphere',
|
|
40
40
|
]);
|
|
41
|
+
/**
|
|
42
|
+
* True when the object type is on the M4.1 translation whitelist.
|
|
43
|
+
*
|
|
44
|
+
* @param type - the FCStd object type, e.g. "Part::Box".
|
|
45
|
+
* @returns true when the type is whitelisted for translation.
|
|
46
|
+
*/
|
|
41
47
|
export function isWhitelisted(type) {
|
|
42
48
|
return WHITELIST.has(type);
|
|
43
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* H10 (plan §3.1/§3.5): C4's Python exception, decided by PROPERTY presence —
|
|
52
|
+
* NOT by the `Python` type-name suffix. Matches the library profile's
|
|
53
|
+
* pythonObjects口径 (profile.mjs: type contains "Python" or carries
|
|
54
|
+
* Python/Proxy properties); here only the property evidence qualifies, so a
|
|
55
|
+
* Python-suffixed type without the property stays a plain translation gap.
|
|
56
|
+
* @param obj - the FCStd object to inspect.
|
|
57
|
+
* @returns true when the object is a Python-scripted feature whose serialized
|
|
58
|
+
* shape is opaque (legitimate `python-baked` under C4).
|
|
59
|
+
*/
|
|
60
|
+
export function isPythonOpaque(obj) {
|
|
61
|
+
for (const [name, prop] of obj.properties) {
|
|
62
|
+
if (name === 'Python' || name === 'Proxy')
|
|
63
|
+
return true;
|
|
64
|
+
if (prop.type === 'App::PropertyPythonObject')
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
44
69
|
function propNum(obj, name) {
|
|
45
70
|
// M11.1: an ExpressionEngine binding overrides the stored <Float> value
|
|
46
71
|
// (FreeCAD recomputes bound properties from expressions on load). A
|
|
@@ -59,6 +84,11 @@ function propNum(obj, name) {
|
|
|
59
84
|
* M11.1/M11.2: the ExpressionEngine binding for `name`, if any. `value` is
|
|
60
85
|
* undefined for non-constant expressions (references/arithmetic) — the caller
|
|
61
86
|
* must bake with an explicit reason instead of estimating.
|
|
87
|
+
*
|
|
88
|
+
* @param obj - the FCStd object whose ExpressionEngine to inspect.
|
|
89
|
+
* @param name - the property name to look up.
|
|
90
|
+
* @returns the binding for `name`, or undefined when the object has no
|
|
91
|
+
* ExpressionEngine binding for it.
|
|
62
92
|
*/
|
|
63
93
|
export function expressionBindingOf(obj, name) {
|
|
64
94
|
const bindings = parseExpressionEngine(obj.properties.get('ExpressionEngine'));
|
|
@@ -67,7 +97,13 @@ export function expressionBindingOf(obj, name) {
|
|
|
67
97
|
const norm = (p) => (p.startsWith('.') ? p.slice(1) : p);
|
|
68
98
|
return bindings.find((b) => norm(b.path) === name);
|
|
69
99
|
}
|
|
70
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* M11.2: detect a non-constant expression binding on a property.
|
|
102
|
+
*
|
|
103
|
+
* @param obj - the FCStd object whose ExpressionEngine to inspect.
|
|
104
|
+
* @param name - the property name to look up.
|
|
105
|
+
* @returns true when `name` has a binding that is NOT a constant expression.
|
|
106
|
+
*/
|
|
71
107
|
export function hasNonConstantBinding(obj, name) {
|
|
72
108
|
const b = expressionBindingOf(obj, name);
|
|
73
109
|
return b !== undefined && b.value === undefined;
|
|
@@ -95,6 +131,14 @@ const POCKET_TYPES = {
|
|
|
95
131
|
'0': 'Length', '1': 'ThroughAll', '2': 'UpToFirst', '3': 'UpToFace', '4': 'TwoLengths',
|
|
96
132
|
Length: 'Length', ThroughAll: 'ThroughAll', UpToFirst: 'UpToFirst', UpToFace: 'UpToFace', TwoLengths: 'TwoLengths',
|
|
97
133
|
};
|
|
134
|
+
/**
|
|
135
|
+
* Read the Pad/Pocket `Type` enumeration of an object (M9.1).
|
|
136
|
+
*
|
|
137
|
+
* @param obj - the FCStd Pad or Pocket object.
|
|
138
|
+
* @param kind - which type-enum table to apply (Pad vs Pocket labels differ).
|
|
139
|
+
* @returns the parsed feature type; 'Length' when Type is missing, 'unknown'
|
|
140
|
+
* when the stored label/index is not recognized.
|
|
141
|
+
*/
|
|
98
142
|
export function featureTypeOf(obj, kind) {
|
|
99
143
|
const el = obj.properties.get('Type')?.children[0];
|
|
100
144
|
const raw = el?.attributes['value'];
|
|
@@ -185,6 +229,10 @@ function edgeRefArgs(baseVar, ordinals) {
|
|
|
185
229
|
* that PartDesign revolves around = +Z) or an edge/vertex of another feature.
|
|
186
230
|
* Edge/vertex axes require resolving referenced geometry, which the port does
|
|
187
231
|
* not yet do (explicit downgrade, no silent loss).
|
|
232
|
+
*
|
|
233
|
+
* @param ref - the ReferenceAxis (or Direction) LinkSub string, may be undefined.
|
|
234
|
+
* @returns a unit axis and pivot point, or undefined when the reference names
|
|
235
|
+
* edge/vertex geometry (unsupported).
|
|
188
236
|
*/
|
|
189
237
|
export function parseReferenceAxis(ref) {
|
|
190
238
|
const at = [0, 0, 0];
|
|
@@ -213,7 +261,12 @@ export function parseReferenceAxis(ref) {
|
|
|
213
261
|
function profileLink(obj) {
|
|
214
262
|
return propLink(obj, 'Profile') ?? propLink(obj, 'Sketch');
|
|
215
263
|
}
|
|
216
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* Placement position (translation) of an object.
|
|
266
|
+
*
|
|
267
|
+
* @param obj - the FCStd object to read.
|
|
268
|
+
* @returns the (Px, Py, Pz) translation from its Placement, or (0,0,0) when absent.
|
|
269
|
+
*/
|
|
217
270
|
export function placementPos(obj) {
|
|
218
271
|
// Property → <PropertyPlacement Px=... Py=... Pz=.../>
|
|
219
272
|
const pp = obj.properties.get('Placement')?.children[0];
|
|
@@ -232,9 +285,34 @@ export function placementPos(obj) {
|
|
|
232
285
|
* `docObjects` (optional) is the full document object list — needed by the
|
|
233
286
|
* UpToFace datum-plane path to read the target plane's Placement (plan
|
|
234
287
|
* extrude-upto-face §4.3-C1). When absent, UpToFace keeps the explicit bake.
|
|
288
|
+
*
|
|
289
|
+
* @param obj - the FCStd object to translate.
|
|
290
|
+
* @param inputVar - resolves a dependency object name to the variable holding
|
|
291
|
+
* its geometry (sketch contours or prior solid).
|
|
292
|
+
* @param docObjects - the full document object list, needed by the UpToFace
|
|
293
|
+
* datum-plane path; optional.
|
|
294
|
+
* @returns the cad-op call plan, or an explicit bake/preserve verdict with reason.
|
|
235
295
|
*/
|
|
236
|
-
export function translateObject(obj, inputVar, docObjects
|
|
296
|
+
export function translateObject(obj, inputVar, docObjects,
|
|
297
|
+
/** H7: names of objects whose Shape is stored as a .brp member (probed from the ZIP). */
|
|
298
|
+
shapeCarriers) {
|
|
237
299
|
if (!isWhitelisted(obj.type)) {
|
|
300
|
+
// H10: property-evidenced Python features bake legitimately (C4) —
|
|
301
|
+
// auditMapping renames this reason to `python-baked`. Everything else is
|
|
302
|
+
// a plain translation gap.
|
|
303
|
+
if (isPythonOpaque(obj))
|
|
304
|
+
return { kind: 'baked', reason: 'python-opaque' };
|
|
305
|
+
// H7 first cut: a Part::Feature is a pure Shape carrier (corpus probe:
|
|
306
|
+
// property surface is Shape [+ShapeMaterial] only; geometry lives in the
|
|
307
|
+
// ZIP's .brp member). With shape evidence there is nothing to translate —
|
|
308
|
+
// the geometry is delivered via assets/ (build-fai-zip M2.3 already copies
|
|
309
|
+
// it), so record `translated` with no cad calls. Without evidence it is an
|
|
310
|
+
// explicit gap, never a silent bake.
|
|
311
|
+
if (obj.type === 'Part::Feature') {
|
|
312
|
+
if (shapeCarriers?.has(obj.name))
|
|
313
|
+
return { kind: 'translated', calls: [], reason: 'shape-asset' };
|
|
314
|
+
return { kind: 'baked', reason: 'shape-asset-missing' };
|
|
315
|
+
}
|
|
238
316
|
return { kind: 'baked', reason: `type-not-whitelisted: ${obj.type}` };
|
|
239
317
|
}
|
|
240
318
|
const out = obj.name; // M5 renames to partN
|