fluidcad 0.0.36 → 0.0.37

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.
Files changed (178) hide show
  1. package/LICENSE.txt +21 -504
  2. package/README.md +1 -1
  3. package/lib/dist/common/edge.d.ts +1 -1
  4. package/lib/dist/common/face.d.ts +1 -1
  5. package/lib/dist/common/scene-object.d.ts +6 -0
  6. package/lib/dist/common/scene-object.js +8 -0
  7. package/lib/dist/common/shape-factory.d.ts +1 -1
  8. package/lib/dist/common/shape-history-tracker.d.ts +1 -1
  9. package/lib/dist/common/shape.d.ts +1 -1
  10. package/lib/dist/common/solid.d.ts +1 -1
  11. package/lib/dist/common/transformable-primitive.d.ts +12 -1
  12. package/lib/dist/common/transformable-primitive.js +27 -0
  13. package/lib/dist/common/vertex.d.ts +1 -1
  14. package/lib/dist/common/wire.d.ts +1 -1
  15. package/lib/dist/core/2d/index.d.ts +1 -0
  16. package/lib/dist/core/2d/index.js +1 -0
  17. package/lib/dist/core/2d/text.d.ts +30 -0
  18. package/lib/dist/core/2d/text.js +37 -0
  19. package/lib/dist/core/helix.d.ts +20 -0
  20. package/lib/dist/core/helix.js +36 -0
  21. package/lib/dist/core/index.d.ts +3 -1
  22. package/lib/dist/core/index.js +2 -0
  23. package/lib/dist/core/interfaces.d.ts +180 -0
  24. package/lib/dist/core/wrap.d.ts +17 -0
  25. package/lib/dist/core/wrap.js +39 -0
  26. package/lib/dist/features/2d/text.d.ts +67 -0
  27. package/lib/dist/features/2d/text.js +320 -0
  28. package/lib/dist/features/cylinder.d.ts +3 -1
  29. package/lib/dist/features/cylinder.js +5 -2
  30. package/lib/dist/features/extrude-base.d.ts +1 -0
  31. package/lib/dist/features/extrude-to-face.d.ts +1 -0
  32. package/lib/dist/features/extrude-to-face.js +6 -0
  33. package/lib/dist/features/fillet.d.ts +1 -1
  34. package/lib/dist/features/helix.d.ts +41 -0
  35. package/lib/dist/features/helix.js +337 -0
  36. package/lib/dist/features/select.js +32 -8
  37. package/lib/dist/features/simple-extruder.d.ts +1 -1
  38. package/lib/dist/features/simple-extruder.js +7 -2
  39. package/lib/dist/features/sphere.d.ts +3 -1
  40. package/lib/dist/features/sphere.js +5 -2
  41. package/lib/dist/features/sweep.js +7 -2
  42. package/lib/dist/features/wrap.d.ts +39 -0
  43. package/lib/dist/features/wrap.js +116 -0
  44. package/lib/dist/filters/edge/belongs-to-face.d.ts +3 -1
  45. package/lib/dist/filters/edge/belongs-to-face.js +14 -10
  46. package/lib/dist/filters/filter.d.ts +1 -1
  47. package/lib/dist/filters/from-object.d.ts +1 -1
  48. package/lib/dist/filters/tangent-expander.d.ts +1 -1
  49. package/lib/dist/filters/tangent-expander.js +57 -40
  50. package/lib/dist/helpers/scene-helpers.d.ts +2 -0
  51. package/lib/dist/helpers/scene-helpers.js +1 -1
  52. package/lib/dist/index.d.ts +2 -0
  53. package/lib/dist/index.js +3 -1
  54. package/lib/dist/io/file-import.d.ts +7 -0
  55. package/lib/dist/io/file-import.js +28 -1
  56. package/lib/dist/io/font-registry.d.ts +45 -0
  57. package/lib/dist/io/font-registry.js +272 -0
  58. package/lib/dist/math/bspline-interpolation.d.ts +29 -0
  59. package/lib/dist/math/bspline-interpolation.js +194 -0
  60. package/lib/dist/oc/boolean-ops.d.ts +3 -1
  61. package/lib/dist/oc/boolean-ops.js +15 -1
  62. package/lib/dist/oc/color-transfer.d.ts +1 -1
  63. package/lib/dist/oc/constraints/constraint-helpers.d.ts +4 -4
  64. package/lib/dist/oc/constraints/curve/tangent-circle-solver.js +10 -9
  65. package/lib/dist/oc/constraints/curve/tangent-line-solver.js +5 -6
  66. package/lib/dist/oc/convert.d.ts +1 -1
  67. package/lib/dist/oc/draft-ops.d.ts +1 -1
  68. package/lib/dist/oc/edge-ops.d.ts +2 -2
  69. package/lib/dist/oc/edge-ops.js +13 -14
  70. package/lib/dist/oc/edge-props.d.ts +1 -1
  71. package/lib/dist/oc/edge-query.d.ts +1 -1
  72. package/lib/dist/oc/edge-query.js +3 -8
  73. package/lib/dist/oc/errors.d.ts +8 -0
  74. package/lib/dist/oc/errors.js +27 -0
  75. package/lib/dist/oc/explorer.d.ts +2 -2
  76. package/lib/dist/oc/extrude-ops.d.ts +28 -2
  77. package/lib/dist/oc/extrude-ops.js +56 -7
  78. package/lib/dist/oc/face-ops.d.ts +2 -1
  79. package/lib/dist/oc/face-ops.js +11 -0
  80. package/lib/dist/oc/face-props.d.ts +1 -1
  81. package/lib/dist/oc/face-query.d.ts +12 -1
  82. package/lib/dist/oc/face-query.js +39 -0
  83. package/lib/dist/oc/fillet-ops.d.ts +1 -1
  84. package/lib/dist/oc/fillet-ops.js +4 -4
  85. package/lib/dist/oc/geometry.d.ts +1 -1
  86. package/lib/dist/oc/geometry.js +12 -14
  87. package/lib/dist/oc/helix-ops.d.ts +37 -0
  88. package/lib/dist/oc/helix-ops.js +88 -0
  89. package/lib/dist/oc/hit-test.d.ts +1 -1
  90. package/lib/dist/oc/index.d.ts +4 -0
  91. package/lib/dist/oc/index.js +2 -0
  92. package/lib/dist/oc/init.d.ts +1 -1
  93. package/lib/dist/oc/init.js +1 -1
  94. package/lib/dist/oc/intersection.js +1 -1
  95. package/lib/dist/oc/io.d.ts +6 -6
  96. package/lib/dist/oc/io.js +31 -24
  97. package/lib/dist/oc/measure/classify.d.ts +34 -0
  98. package/lib/dist/oc/measure/classify.js +246 -0
  99. package/lib/dist/oc/measure/measure-ops.d.ts +9 -0
  100. package/lib/dist/oc/measure/measure-ops.js +210 -0
  101. package/lib/dist/oc/measure/measure-types.d.ts +39 -0
  102. package/lib/dist/oc/measure/measure-types.js +1 -0
  103. package/lib/dist/oc/measure/sampling.d.ts +9 -0
  104. package/lib/dist/oc/measure/sampling.js +77 -0
  105. package/lib/dist/oc/measure/vec.d.ts +13 -0
  106. package/lib/dist/oc/measure/vec.js +23 -0
  107. package/lib/dist/oc/mesh.d.ts +1 -1
  108. package/lib/dist/oc/mesh.js +40 -28
  109. package/lib/dist/oc/path-sampler.d.ts +29 -0
  110. package/lib/dist/oc/path-sampler.js +63 -0
  111. package/lib/dist/oc/props.d.ts +1 -1
  112. package/lib/dist/oc/props.js +4 -1
  113. package/lib/dist/oc/shape-hash.d.ts +26 -0
  114. package/lib/dist/oc/shape-hash.js +32 -0
  115. package/lib/dist/oc/shape-ops.d.ts +5 -3
  116. package/lib/dist/oc/shape-ops.js +6 -5
  117. package/lib/dist/oc/sweep-ops.d.ts +22 -1
  118. package/lib/dist/oc/sweep-ops.js +206 -18
  119. package/lib/dist/oc/text-outline.d.ts +62 -0
  120. package/lib/dist/oc/text-outline.js +212 -0
  121. package/lib/dist/oc/topology-index.d.ts +1 -1
  122. package/lib/dist/oc/vertex-ops.d.ts +1 -1
  123. package/lib/dist/oc/wire-ops.d.ts +1 -1
  124. package/lib/dist/oc/wire-ops.js +1 -1
  125. package/lib/dist/oc/wrap-development.d.ts +105 -0
  126. package/lib/dist/oc/wrap-development.js +179 -0
  127. package/lib/dist/oc/wrap-ops.d.ts +100 -0
  128. package/lib/dist/oc/wrap-ops.js +406 -0
  129. package/lib/dist/rendering/render-solid.js +10 -2
  130. package/lib/dist/scene-manager.d.ts +2 -0
  131. package/lib/dist/scene-manager.js +29 -0
  132. package/lib/dist/tests/features/cylinder-curve-filter.test.js +3 -3
  133. package/lib/dist/tests/features/extrude-to-face.test.js +38 -1
  134. package/lib/dist/tests/features/helix.test.d.ts +1 -0
  135. package/lib/dist/tests/features/helix.test.js +295 -0
  136. package/lib/dist/tests/features/repeat-primitive.test.d.ts +1 -0
  137. package/lib/dist/tests/features/repeat-primitive.test.js +60 -0
  138. package/lib/dist/tests/features/rib.test.js +6 -1
  139. package/lib/dist/tests/features/sweep.test.js +125 -1
  140. package/lib/dist/tests/features/text.test.d.ts +1 -0
  141. package/lib/dist/tests/features/text.test.js +347 -0
  142. package/lib/dist/tests/features/wrap-development.test.d.ts +1 -0
  143. package/lib/dist/tests/features/wrap-development.test.js +130 -0
  144. package/lib/dist/tests/features/wrap-extruded-target.test.d.ts +1 -0
  145. package/lib/dist/tests/features/wrap-extruded-target.test.js +106 -0
  146. package/lib/dist/tests/features/wrap-repeat.test.d.ts +1 -0
  147. package/lib/dist/tests/features/wrap-repeat.test.js +93 -0
  148. package/lib/dist/tests/features/wrap.test.d.ts +1 -0
  149. package/lib/dist/tests/features/wrap.test.js +331 -0
  150. package/lib/dist/tests/math/bspline-interpolation.test.d.ts +1 -0
  151. package/lib/dist/tests/math/bspline-interpolation.test.js +119 -0
  152. package/lib/dist/tests/measure.test.d.ts +1 -0
  153. package/lib/dist/tests/measure.test.js +288 -0
  154. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  155. package/llm-docs/api/helix.md +64 -0
  156. package/llm-docs/api/index.json +11 -2
  157. package/llm-docs/api/text.md +52 -0
  158. package/llm-docs/api/types/helix.md +105 -0
  159. package/llm-docs/api/types/text.md +138 -0
  160. package/llm-docs/api/types/wrap.md +131 -0
  161. package/llm-docs/api/wrap.md +62 -0
  162. package/llm-docs/index.json +121 -1
  163. package/mcp/dist/server.js +20 -1
  164. package/mcp/dist/tools/inspection.d.ts +17 -0
  165. package/mcp/dist/tools/inspection.js +14 -0
  166. package/package.json +7 -3
  167. package/server/dist/fluidcad-server.d.ts +10 -0
  168. package/server/dist/fluidcad-server.js +10 -0
  169. package/server/dist/index.js +4 -2
  170. package/server/dist/preferences.d.ts +4 -0
  171. package/server/dist/preferences.js +2 -0
  172. package/server/dist/routes/measure.d.ts +3 -0
  173. package/server/dist/routes/measure.js +32 -0
  174. package/server/dist/routes/preferences.js +6 -0
  175. package/server/dist/routes/sketch-edits.js +2 -1
  176. package/ui/dist/assets/{index-CDJmUpFI.css → index-dAFdg2Un.css} +1 -1
  177. package/ui/dist/assets/{index-MRqwG9Vh.js → index-no7mtr5s.js} +149 -102
  178. package/ui/dist/index.html +2 -2
@@ -1,6 +1,7 @@
1
1
  import { Matrix4 } from "../../math/matrix4.js";
2
2
  import { Edge, Face } from "../../common/shapes.js";
3
3
  import { Solid } from "../../common/solid.js";
4
+ import { ShapeHasher } from "../../oc/shape-hash.js";
4
5
  import { FilterBase } from "../filter-base.js";
5
6
  import { FilterBuilderBase } from "../filter-builder-base.js";
6
7
  declare abstract class BelongsToFaceFilterBase extends FilterBase<Edge> {
@@ -8,8 +9,9 @@ declare abstract class BelongsToFaceFilterBase extends FilterBase<Edge> {
8
9
  protected scopeSolids: Solid[];
9
10
  protected scopeFaces: Face[];
10
11
  protected faceByHash: Map<number, Face[]>;
12
+ protected shapeHasher: ShapeHasher | null;
11
13
  constructor(faceFilterBuilders: FilterBuilderBase<Face>[]);
12
- setScopeIndex(solids: Solid[], extraFaces: Face[], faceByHash: Map<number, Face[]>): void;
14
+ setScopeIndex(solids: Solid[], extraFaces: Face[], faceByHash: Map<number, Face[]>, hasher: ShapeHasher): void;
13
15
  protected findContainingFaces(edge: Edge): Face[];
14
16
  }
15
17
  export declare class BelongsToFaceFilter extends BelongsToFaceFilterBase {
@@ -7,14 +7,16 @@ class BelongsToFaceFilterBase extends FilterBase {
7
7
  scopeSolids = [];
8
8
  scopeFaces = [];
9
9
  faceByHash = new Map();
10
+ shapeHasher = null;
10
11
  constructor(faceFilterBuilders) {
11
12
  super();
12
13
  this.faceFilterBuilders = faceFilterBuilders;
13
14
  }
14
- setScopeIndex(solids, extraFaces, faceByHash) {
15
+ setScopeIndex(solids, extraFaces, faceByHash, hasher) {
15
16
  this.scopeSolids = solids;
16
17
  this.scopeFaces = extraFaces;
17
18
  this.faceByHash = faceByHash;
19
+ this.shapeHasher = hasher;
18
20
  }
19
21
  findContainingFaces(edge) {
20
22
  const edgeShape = edge.getShape();
@@ -24,7 +26,7 @@ class BelongsToFaceFilterBase extends FilterBase {
24
26
  const index = solid.getEdgeToFacesIndex();
25
27
  const rawFaces = TopologyIndex.seekShapes(index, edgeShape);
26
28
  for (const raw of rawFaces) {
27
- const wrapper = resolveFaceWrapper(raw, this.faceByHash);
29
+ const wrapper = resolveFaceWrapper(raw, this.faceByHash, this.shapeHasher);
28
30
  if (wrapper && !seen.has(wrapper)) {
29
31
  seen.add(wrapper);
30
32
  result.push(wrapper);
@@ -93,9 +95,9 @@ export class NotBelongsToFaceFilter extends BelongsToFaceFilterBase {
93
95
  return new NotBelongsToFaceFilter(transformed);
94
96
  }
95
97
  }
96
- function resolveFaceWrapper(rawFace, faceByHash) {
97
- const hash = rawFace.HashCode(2147483647);
98
- const bucket = faceByHash.get(hash);
98
+ function resolveFaceWrapper(rawFace, faceByHash, hasher) {
99
+ const hash = hasher ? hasher.key(rawFace) : null;
100
+ const bucket = hash !== null ? faceByHash.get(hash) : undefined;
99
101
  if (bucket) {
100
102
  for (const candidate of bucket) {
101
103
  if (candidate.getShape().IsSame(rawFace)) {
@@ -106,11 +108,13 @@ function resolveFaceWrapper(rawFace, faceByHash) {
106
108
  // Not in scope (e.g. neighbor face from another part / out-of-scope solid).
107
109
  // Wrap on the fly so the face filters can still evaluate it.
108
110
  const wrapped = Face.fromTopoDSFace(Explorer.toFace(rawFace));
109
- if (!bucket) {
110
- faceByHash.set(hash, [wrapped]);
111
- }
112
- else {
113
- bucket.push(wrapped);
111
+ if (hash !== null) {
112
+ if (!bucket) {
113
+ faceByHash.set(hash, [wrapped]);
114
+ }
115
+ else {
116
+ bucket.push(wrapped);
117
+ }
114
118
  }
115
119
  return wrapped;
116
120
  }
@@ -4,5 +4,5 @@ export declare class ShapeFilter {
4
4
  private shapes;
5
5
  private builders;
6
6
  constructor(shapes: Shape[], ...filterBuilders: FilterBuilderBase[]);
7
- apply(): Shape<import("occjs-wrapper").TopoDS_Shape>[];
7
+ apply(): Shape<import("ocjs-fluidcad").TopoDS_Shape>[];
8
8
  }
@@ -1,4 +1,4 @@
1
- import type { TopTools_MapOfShape } from "occjs-wrapper";
1
+ import type { TopTools_MapOfShape } from "ocjs-fluidcad";
2
2
  import { Matrix4 } from "../math/matrix4.js";
3
3
  import { Shape } from "../common/shapes.js";
4
4
  import { ShapeType } from "../common/shape-type.js";
@@ -1,4 +1,4 @@
1
- import type { TopoDS_Edge } from "occjs-wrapper";
1
+ import type { TopoDS_Edge } from "ocjs-fluidcad";
2
2
  import { Shape, Edge, Face } from "../common/shapes.js";
3
3
  export declare class TangentExpander {
4
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { getOC } from "../oc/init.js";
2
+ import { ShapeHasher } from "../oc/shape-hash.js";
2
3
  export class TangentExpander {
3
4
  /**
4
5
  * Expands a set of seed shapes to include all transitively tangent-connected
@@ -20,48 +21,64 @@ export class TangentExpander {
20
21
  * and their tangent vectors at that vertex are parallel.
21
22
  */
22
23
  static expandEdges(seeds, pool) {
23
- // Build vertex edge adjacency map for efficient lookup
24
- const vertexToEdges = TangentExpander.buildVertexToEdgeMap(pool);
25
- const included = new Set(seeds);
26
- const queue = [...seeds];
27
- while (queue.length > 0) {
28
- const current = queue.shift();
29
- const neighbors = TangentExpander.getAdjacentEdges(current, vertexToEdges);
30
- for (const candidate of neighbors) {
31
- if (included.has(candidate)) {
32
- continue;
33
- }
34
- if (TangentExpander.areEdgesTangent(current, candidate)) {
35
- included.add(candidate);
36
- queue.push(candidate);
24
+ // Interns shapes for IsSame-consistent Map keys (replaces TopoDS_Shape.HashCode,
25
+ // removed in OCCT 8.0); scoped to this expansion and freed below.
26
+ const hasher = new ShapeHasher();
27
+ try {
28
+ // Build vertex edge adjacency map for efficient lookup
29
+ const vertexToEdges = TangentExpander.buildVertexToEdgeMap(pool, hasher);
30
+ const included = new Set(seeds);
31
+ const queue = [...seeds];
32
+ while (queue.length > 0) {
33
+ const current = queue.shift();
34
+ const neighbors = TangentExpander.getAdjacentEdges(current, vertexToEdges, hasher);
35
+ for (const candidate of neighbors) {
36
+ if (included.has(candidate)) {
37
+ continue;
38
+ }
39
+ if (TangentExpander.areEdgesTangent(current, candidate)) {
40
+ included.add(candidate);
41
+ queue.push(candidate);
42
+ }
37
43
  }
38
44
  }
45
+ return [...included];
46
+ }
47
+ finally {
48
+ hasher.delete();
39
49
  }
40
- return [...included];
41
50
  }
42
51
  /**
43
52
  * BFS expansion for faces. Two faces are tangent if they share an edge
44
53
  * and have G1 or higher continuity across that edge.
45
54
  */
46
55
  static expandFaces(seeds, pool) {
47
- // Build edge face adjacency map
48
- const edgeToFaces = TangentExpander.buildEdgeToFaceMap(pool);
49
- const included = new Set(seeds);
50
- const queue = [...seeds];
51
- while (queue.length > 0) {
52
- const current = queue.shift();
53
- const neighbors = TangentExpander.getAdjacentFaces(current, edgeToFaces);
54
- for (const [candidate, sharedEdge] of neighbors) {
55
- if (included.has(candidate)) {
56
- continue;
57
- }
58
- if (TangentExpander.areFacesTangent(current, candidate, sharedEdge)) {
59
- included.add(candidate);
60
- queue.push(candidate);
56
+ // Interns shapes for IsSame-consistent Map keys (replaces TopoDS_Shape.HashCode,
57
+ // removed in OCCT 8.0); scoped to this expansion and freed below.
58
+ const hasher = new ShapeHasher();
59
+ try {
60
+ // Build edge face adjacency map
61
+ const edgeToFaces = TangentExpander.buildEdgeToFaceMap(pool, hasher);
62
+ const included = new Set(seeds);
63
+ const queue = [...seeds];
64
+ while (queue.length > 0) {
65
+ const current = queue.shift();
66
+ const neighbors = TangentExpander.getAdjacentFaces(current, edgeToFaces, hasher);
67
+ for (const [candidate, sharedEdge] of neighbors) {
68
+ if (included.has(candidate)) {
69
+ continue;
70
+ }
71
+ if (TangentExpander.areFacesTangent(current, candidate, sharedEdge)) {
72
+ included.add(candidate);
73
+ queue.push(candidate);
74
+ }
61
75
  }
62
76
  }
77
+ return [...included];
78
+ }
79
+ finally {
80
+ hasher.delete();
63
81
  }
64
- return [...included];
65
82
  }
66
83
  /**
67
84
  * Checks if two edges are tangent at a shared vertex by comparing
@@ -89,10 +106,10 @@ export class TangentExpander {
89
106
  }
90
107
  // Get raw curves and parameters at the shared vertex
91
108
  const curve1Handle = oc.BRep_Tool.Curve(e1Raw, 0, 1);
92
- const curve1 = curve1Handle.get();
109
+ const curve1 = curve1Handle.returnValue;
93
110
  const param1 = oc.BRep_Tool.Parameter(v1, e1Raw);
94
111
  const curve2Handle = oc.BRep_Tool.Curve(e2Raw, 0, 1);
95
- const curve2 = curve2Handle.get();
112
+ const curve2 = curve2Handle.returnValue;
96
113
  const param2 = oc.BRep_Tool.Parameter(v2, e2Raw);
97
114
  // Evaluate tangent vectors using D1
98
115
  const pnt1 = new oc.gp_Pnt();
@@ -144,7 +161,7 @@ export class TangentExpander {
144
161
  /**
145
162
  * Builds a map from vertex TShape hash to the list of edges that share that vertex.
146
163
  */
147
- static buildVertexToEdgeMap(edges) {
164
+ static buildVertexToEdgeMap(edges, hasher) {
148
165
  const oc = getOC();
149
166
  const map = new Map();
150
167
  for (const edge of edges) {
@@ -152,7 +169,7 @@ export class TangentExpander {
152
169
  const first = oc.TopExp.FirstVertex(raw, true);
153
170
  const last = oc.TopExp.LastVertex(raw, true);
154
171
  for (const vertex of [first, last]) {
155
- const hash = vertex.HashCode(2147483647);
172
+ const hash = hasher.key(vertex);
156
173
  if (!map.has(hash)) {
157
174
  map.set(hash, []);
158
175
  }
@@ -164,12 +181,12 @@ export class TangentExpander {
164
181
  /**
165
182
  * Builds a map from edge TShape hash to the list of faces that share that edge.
166
183
  */
167
- static buildEdgeToFaceMap(faces) {
184
+ static buildEdgeToFaceMap(faces, hasher) {
168
185
  const map = new Map();
169
186
  for (const face of faces) {
170
187
  const faceEdges = face.getEdges();
171
188
  for (const edge of faceEdges) {
172
- const hash = edge.getShape().HashCode(2147483647);
189
+ const hash = hasher.key(edge.getShape());
173
190
  if (!map.has(hash)) {
174
191
  map.set(hash, []);
175
192
  }
@@ -181,14 +198,14 @@ export class TangentExpander {
181
198
  /**
182
199
  * Returns edges from the adjacency map that share a vertex with the given edge.
183
200
  */
184
- static getAdjacentEdges(edge, vertexToEdges) {
201
+ static getAdjacentEdges(edge, vertexToEdges, hasher) {
185
202
  const oc = getOC();
186
203
  const raw = edge.getShape();
187
204
  const first = oc.TopExp.FirstVertex(raw, true);
188
205
  const last = oc.TopExp.LastVertex(raw, true);
189
206
  const neighbors = new Set();
190
207
  for (const vertex of [first, last]) {
191
- const hash = vertex.HashCode(2147483647);
208
+ const hash = hasher.key(vertex);
192
209
  const candidates = vertexToEdges.get(hash);
193
210
  if (candidates) {
194
211
  for (const c of candidates) {
@@ -204,11 +221,11 @@ export class TangentExpander {
204
221
  * Returns faces from the adjacency map that share an edge with the given face,
205
222
  * along with the shared edge's raw TopoDS_Edge.
206
223
  */
207
- static getAdjacentFaces(face, edgeToFaces) {
224
+ static getAdjacentFaces(face, edgeToFaces, hasher) {
208
225
  const result = [];
209
226
  const faceEdges = face.getEdges();
210
227
  for (const edge of faceEdges) {
211
- const hash = edge.getShape().HashCode(2147483647);
228
+ const hash = hasher.key(edge.getShape());
212
229
  const candidates = edgeToFaces.get(hash);
213
230
  if (candidates) {
214
231
  for (const c of candidates) {
@@ -7,6 +7,7 @@ export declare function fuseWithSceneObjects(sceneObjects: SceneObject[], extrus
7
7
  glue?: 'full' | 'shift';
8
8
  recordHistoryFor?: SceneObject;
9
9
  profiler?: Profiler;
10
+ skipSimplify?: boolean;
10
11
  }): {
11
12
  newShapes: Shape<any>[];
12
13
  modifiedShapes: any[];
@@ -21,6 +22,7 @@ export declare function fuseWithSceneObjects(sceneObjects: SceneObject[], extrus
21
22
  };
22
23
  export declare function cutWithSceneObjects(sceneObjects: SceneObject[], toolShapes: Shape[], plane: Plane, distance: number, caller: SceneObject, options?: {
23
24
  recordHistoryFor?: SceneObject;
25
+ skipSimplify?: boolean;
24
26
  }): {
25
27
  cleanedShapes: Shape[];
26
28
  stockShapes: Shape[];
@@ -302,7 +302,7 @@ export function cutWithSceneObjects(sceneObjects, toolShapes, plane, distance, c
302
302
  const list = cutResult.modified(shape);
303
303
  if (list.length) {
304
304
  for (const newShape of list) {
305
- const cleanup = ShapeOps.cleanShapeWithLineage(newShape);
305
+ const cleanup = ShapeOps.cleanShapeWithLineage(newShape, { skipSimplify: options?.skipSimplify });
306
306
  caller.addShape(cleanup.shape);
307
307
  cleanedShapes.push(cleanup.shape);
308
308
  cleanups.push(cleanup);
@@ -22,6 +22,7 @@ export type { ParamDefinition, MultiControlType, SelectOption, ParamVal, ParamSc
22
22
  export { setAssetProvider } from './io/file-import.js';
23
23
  export type { AssetProvider } from './io/file-import.js';
24
24
  export { getSceneManager } from './scene-manager.js';
25
+ export { describeOcException } from './oc/errors.js';
25
26
  export interface FluidCADOptions {
26
27
  mesh?: {
27
28
  lineDeflection?: number;
@@ -42,6 +43,7 @@ export declare function init(options?: FluidCADOptions): Promise<{
42
43
  getShapeProperties(scene: Scene, shapeId: string): import("./oc/props.js").ShapeProperties | null;
43
44
  getFaceProperties(scene: Scene, shapeId: string, faceIndex: number): import("./oc/face-props.js").FaceProperties | null;
44
45
  getEdgeProperties(scene: Scene, shapeId: string, edgeIndex: number): import("./oc/edge-props.js").EdgeProperties | null;
46
+ measure(scene: Scene, refs: import("./oc/index.js").MeasureEntityRef[]): import("./oc/index.js").MeasureResult | null;
45
47
  exportShapes(scene: Scene, shapeIds: string[], options: import("./io/file-export.js").ExportOptions): {
46
48
  data: string | Uint8Array;
47
49
  fileName: string;
package/lib/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { loadOC } from "./load.js";
2
+ import { FontRegistry } from "./io/font-registry.js";
2
3
  import { createManager, getCurrentScene, getSceneManager } from "./scene-manager.js";
3
4
  import { parse as parseStackTrace } from "stacktrace-parser";
4
5
  export function captureSourceLocation() {
@@ -91,8 +92,9 @@ export function registerBuilder(builder) {
91
92
  export { createParamRegistry, getParamRegistry } from './param-registry.js';
92
93
  export { setAssetProvider } from './io/file-import.js';
93
94
  export { getSceneManager } from './scene-manager.js';
95
+ export { describeOcException } from './oc/errors.js';
94
96
  export async function init(options) {
95
- await loadOC();
97
+ await Promise.all([loadOC(), FontRegistry.init()]);
96
98
  const existing = getSceneManager();
97
99
  if (existing) {
98
100
  return existing;
@@ -7,6 +7,13 @@ import { Solid } from "../common/solid.js";
7
7
  */
8
8
  export type AssetProvider = (workspaceRelPath: string) => Uint8Array | null;
9
9
  export declare function setAssetProvider(provider: AssetProvider | null): void;
10
+ /**
11
+ * Reads a workspace asset as raw bytes (e.g. a font file). Consults the
12
+ * AssetProvider first (hub mode), then the workspace filesystem. Paths are
13
+ * workspace-relative and confined to the workspace root (no `..` traversal).
14
+ * Returns null when the asset cannot be found.
15
+ */
16
+ export declare function readWorkspaceAssetBytes(relPath: string): Uint8Array | null;
10
17
  export declare class FileImport {
11
18
  static deserializeShapes(fileName: string): Solid[];
12
19
  static serializeShape(shape: Shape, workspacePath: string, fileName: string): void;
@@ -1,5 +1,5 @@
1
1
  import * as fs from "fs";
2
- import { join } from "path";
2
+ import { join, resolve, sep } from "path";
3
3
  import { OcIO } from "../oc/io.js";
4
4
  import { getSceneManager } from "../scene-manager.js";
5
5
  let assetProvider = null;
@@ -20,6 +20,33 @@ function readWorkspaceAsset(relPath) {
20
20
  }
21
21
  return { text: fs.readFileSync(filePath, 'utf8'), exists: true };
22
22
  }
23
+ /**
24
+ * Reads a workspace asset as raw bytes (e.g. a font file). Consults the
25
+ * AssetProvider first (hub mode), then the workspace filesystem. Paths are
26
+ * workspace-relative and confined to the workspace root (no `..` traversal).
27
+ * Returns null when the asset cannot be found.
28
+ */
29
+ export function readWorkspaceAssetBytes(relPath) {
30
+ if (assetProvider) {
31
+ const bytes = assetProvider(relPath);
32
+ if (bytes) {
33
+ return bytes;
34
+ }
35
+ }
36
+ const sceneManager = getSceneManager();
37
+ if (!sceneManager) {
38
+ return null;
39
+ }
40
+ const root = resolve(sceneManager.rootPath);
41
+ const filePath = resolve(root, relPath);
42
+ if (filePath !== root && !filePath.startsWith(root + sep)) {
43
+ return null;
44
+ }
45
+ if (!fs.existsSync(filePath)) {
46
+ return null;
47
+ }
48
+ return fs.readFileSync(filePath);
49
+ }
23
50
  export class FileImport {
24
51
  static deserializeShapes(fileName) {
25
52
  if (!fileName.endsWith(('.brep'))) {
@@ -0,0 +1,45 @@
1
+ import type { Font } from "fontkit";
2
+ /**
3
+ * Resolves font names/paths to ready-to-use fontkit `Font` instances.
4
+ *
5
+ * `init()` enumerates system fonts (via `get-system-fonts`) once per process and
6
+ * builds a family -> variants index (via `fontkit`). `resolve()` is synchronous
7
+ * so it can be called from `SceneObject.build()`; it requires `init()` to have
8
+ * completed first, mirroring `getOC()` / `loadOC()`.
9
+ */
10
+ export declare class FontRegistry {
11
+ private static index;
12
+ private static allFiles;
13
+ private static fontCache;
14
+ static init(): Promise<void>;
15
+ /**
16
+ * Resolves a font request into a ready fontkit `Font`. Never returns null:
17
+ * falls back through aliases -> default families -> any available font, and
18
+ * only throws if the machine has no usable fonts at all.
19
+ */
20
+ static resolve(opts: {
21
+ font?: string;
22
+ weight?: number;
23
+ italic?: boolean;
24
+ }): Font;
25
+ private static ensureInit;
26
+ /** Collects a family's variants plus its alias families' variants, unsorted. */
27
+ private static collectVariants;
28
+ /**
29
+ * Sorts variants by italic match then nearest weight, and opens the first that
30
+ * actually renders (skipping fonts that throw on outline access).
31
+ */
32
+ private static openFirstRenderable;
33
+ /** Opens and validates a variant; caches the result, including known-bad (null). */
34
+ private static openVariant;
35
+ /** All indexed system font family names (lowercased). Useful for tooling/tests. */
36
+ static availableFamilies(): string[];
37
+ private static tryOpenFile;
38
+ /**
39
+ * A font is usable only if its outlines compute without throwing. Fonts that
40
+ * declare an fvar variation axis but lack the variable outline tables
41
+ * (gvar/glyf or CFF2) throw lazily when glyph paths are accessed.
42
+ */
43
+ private static canRender;
44
+ private static loadLocalFile;
45
+ }