fluidcad 0.0.35 → 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 (186) hide show
  1. package/LICENSE.txt +21 -504
  2. package/README.md +1 -1
  3. package/bin/commands/login.js +33 -5
  4. package/bin/commands/mcp.js +3 -2
  5. package/bin/commands/publish.js +103 -8
  6. package/bin/lib/api-client.js +8 -0
  7. package/bin/lib/model-config.js +27 -4
  8. package/bin/lib/prompt.js +97 -0
  9. package/lib/dist/common/edge.d.ts +1 -1
  10. package/lib/dist/common/face.d.ts +1 -1
  11. package/lib/dist/common/scene-object.d.ts +6 -0
  12. package/lib/dist/common/scene-object.js +8 -0
  13. package/lib/dist/common/shape-factory.d.ts +1 -1
  14. package/lib/dist/common/shape-history-tracker.d.ts +1 -1
  15. package/lib/dist/common/shape.d.ts +1 -1
  16. package/lib/dist/common/solid.d.ts +1 -1
  17. package/lib/dist/common/transformable-primitive.d.ts +12 -1
  18. package/lib/dist/common/transformable-primitive.js +27 -0
  19. package/lib/dist/common/vertex.d.ts +1 -1
  20. package/lib/dist/common/wire.d.ts +1 -1
  21. package/lib/dist/core/2d/index.d.ts +1 -0
  22. package/lib/dist/core/2d/index.js +1 -0
  23. package/lib/dist/core/2d/text.d.ts +30 -0
  24. package/lib/dist/core/2d/text.js +37 -0
  25. package/lib/dist/core/helix.d.ts +20 -0
  26. package/lib/dist/core/helix.js +36 -0
  27. package/lib/dist/core/index.d.ts +3 -1
  28. package/lib/dist/core/index.js +2 -0
  29. package/lib/dist/core/interfaces.d.ts +180 -0
  30. package/lib/dist/core/wrap.d.ts +17 -0
  31. package/lib/dist/core/wrap.js +39 -0
  32. package/lib/dist/features/2d/text.d.ts +67 -0
  33. package/lib/dist/features/2d/text.js +320 -0
  34. package/lib/dist/features/cylinder.d.ts +3 -1
  35. package/lib/dist/features/cylinder.js +5 -2
  36. package/lib/dist/features/extrude-base.d.ts +1 -0
  37. package/lib/dist/features/extrude-to-face.d.ts +1 -0
  38. package/lib/dist/features/extrude-to-face.js +6 -0
  39. package/lib/dist/features/fillet.d.ts +1 -1
  40. package/lib/dist/features/helix.d.ts +41 -0
  41. package/lib/dist/features/helix.js +337 -0
  42. package/lib/dist/features/select.js +32 -8
  43. package/lib/dist/features/simple-extruder.d.ts +1 -1
  44. package/lib/dist/features/simple-extruder.js +7 -2
  45. package/lib/dist/features/sphere.d.ts +3 -1
  46. package/lib/dist/features/sphere.js +5 -2
  47. package/lib/dist/features/sweep.js +7 -2
  48. package/lib/dist/features/wrap.d.ts +39 -0
  49. package/lib/dist/features/wrap.js +116 -0
  50. package/lib/dist/filters/edge/belongs-to-face.d.ts +3 -1
  51. package/lib/dist/filters/edge/belongs-to-face.js +14 -10
  52. package/lib/dist/filters/filter.d.ts +1 -1
  53. package/lib/dist/filters/from-object.d.ts +1 -1
  54. package/lib/dist/filters/tangent-expander.d.ts +1 -1
  55. package/lib/dist/filters/tangent-expander.js +57 -40
  56. package/lib/dist/helpers/scene-helpers.d.ts +2 -0
  57. package/lib/dist/helpers/scene-helpers.js +1 -1
  58. package/lib/dist/index.d.ts +2 -0
  59. package/lib/dist/index.js +3 -1
  60. package/lib/dist/io/file-import.d.ts +7 -0
  61. package/lib/dist/io/file-import.js +28 -1
  62. package/lib/dist/io/font-registry.d.ts +45 -0
  63. package/lib/dist/io/font-registry.js +272 -0
  64. package/lib/dist/math/bspline-interpolation.d.ts +29 -0
  65. package/lib/dist/math/bspline-interpolation.js +194 -0
  66. package/lib/dist/oc/boolean-ops.d.ts +3 -1
  67. package/lib/dist/oc/boolean-ops.js +15 -1
  68. package/lib/dist/oc/color-transfer.d.ts +1 -1
  69. package/lib/dist/oc/constraints/constraint-helpers.d.ts +4 -4
  70. package/lib/dist/oc/constraints/curve/tangent-circle-solver.js +10 -9
  71. package/lib/dist/oc/constraints/curve/tangent-line-solver.js +5 -6
  72. package/lib/dist/oc/convert.d.ts +1 -1
  73. package/lib/dist/oc/draft-ops.d.ts +1 -1
  74. package/lib/dist/oc/edge-ops.d.ts +2 -2
  75. package/lib/dist/oc/edge-ops.js +13 -14
  76. package/lib/dist/oc/edge-props.d.ts +1 -1
  77. package/lib/dist/oc/edge-query.d.ts +1 -1
  78. package/lib/dist/oc/edge-query.js +3 -8
  79. package/lib/dist/oc/errors.d.ts +8 -0
  80. package/lib/dist/oc/errors.js +27 -0
  81. package/lib/dist/oc/explorer.d.ts +2 -2
  82. package/lib/dist/oc/extrude-ops.d.ts +28 -2
  83. package/lib/dist/oc/extrude-ops.js +56 -7
  84. package/lib/dist/oc/face-ops.d.ts +2 -1
  85. package/lib/dist/oc/face-ops.js +11 -0
  86. package/lib/dist/oc/face-props.d.ts +1 -1
  87. package/lib/dist/oc/face-query.d.ts +12 -1
  88. package/lib/dist/oc/face-query.js +39 -0
  89. package/lib/dist/oc/fillet-ops.d.ts +1 -1
  90. package/lib/dist/oc/fillet-ops.js +4 -4
  91. package/lib/dist/oc/geometry.d.ts +1 -1
  92. package/lib/dist/oc/geometry.js +12 -14
  93. package/lib/dist/oc/helix-ops.d.ts +37 -0
  94. package/lib/dist/oc/helix-ops.js +88 -0
  95. package/lib/dist/oc/hit-test.d.ts +1 -1
  96. package/lib/dist/oc/index.d.ts +4 -0
  97. package/lib/dist/oc/index.js +2 -0
  98. package/lib/dist/oc/init.d.ts +1 -1
  99. package/lib/dist/oc/init.js +1 -1
  100. package/lib/dist/oc/intersection.js +1 -1
  101. package/lib/dist/oc/io.d.ts +6 -6
  102. package/lib/dist/oc/io.js +31 -24
  103. package/lib/dist/oc/measure/classify.d.ts +34 -0
  104. package/lib/dist/oc/measure/classify.js +246 -0
  105. package/lib/dist/oc/measure/measure-ops.d.ts +9 -0
  106. package/lib/dist/oc/measure/measure-ops.js +210 -0
  107. package/lib/dist/oc/measure/measure-types.d.ts +39 -0
  108. package/lib/dist/oc/measure/measure-types.js +1 -0
  109. package/lib/dist/oc/measure/sampling.d.ts +9 -0
  110. package/lib/dist/oc/measure/sampling.js +77 -0
  111. package/lib/dist/oc/measure/vec.d.ts +13 -0
  112. package/lib/dist/oc/measure/vec.js +23 -0
  113. package/lib/dist/oc/mesh.d.ts +1 -1
  114. package/lib/dist/oc/mesh.js +40 -28
  115. package/lib/dist/oc/path-sampler.d.ts +29 -0
  116. package/lib/dist/oc/path-sampler.js +63 -0
  117. package/lib/dist/oc/props.d.ts +1 -1
  118. package/lib/dist/oc/props.js +4 -1
  119. package/lib/dist/oc/shape-hash.d.ts +26 -0
  120. package/lib/dist/oc/shape-hash.js +32 -0
  121. package/lib/dist/oc/shape-ops.d.ts +5 -3
  122. package/lib/dist/oc/shape-ops.js +6 -5
  123. package/lib/dist/oc/sweep-ops.d.ts +22 -1
  124. package/lib/dist/oc/sweep-ops.js +206 -18
  125. package/lib/dist/oc/text-outline.d.ts +62 -0
  126. package/lib/dist/oc/text-outline.js +212 -0
  127. package/lib/dist/oc/topology-index.d.ts +1 -1
  128. package/lib/dist/oc/vertex-ops.d.ts +1 -1
  129. package/lib/dist/oc/wire-ops.d.ts +1 -1
  130. package/lib/dist/oc/wire-ops.js +1 -1
  131. package/lib/dist/oc/wrap-development.d.ts +105 -0
  132. package/lib/dist/oc/wrap-development.js +179 -0
  133. package/lib/dist/oc/wrap-ops.d.ts +100 -0
  134. package/lib/dist/oc/wrap-ops.js +406 -0
  135. package/lib/dist/rendering/render-solid.js +10 -2
  136. package/lib/dist/scene-manager.d.ts +2 -0
  137. package/lib/dist/scene-manager.js +29 -0
  138. package/lib/dist/tests/features/cylinder-curve-filter.test.js +3 -3
  139. package/lib/dist/tests/features/extrude-to-face.test.js +38 -1
  140. package/lib/dist/tests/features/helix.test.d.ts +1 -0
  141. package/lib/dist/tests/features/helix.test.js +295 -0
  142. package/lib/dist/tests/features/repeat-primitive.test.d.ts +1 -0
  143. package/lib/dist/tests/features/repeat-primitive.test.js +60 -0
  144. package/lib/dist/tests/features/rib.test.js +6 -1
  145. package/lib/dist/tests/features/sweep.test.js +125 -1
  146. package/lib/dist/tests/features/text.test.d.ts +1 -0
  147. package/lib/dist/tests/features/text.test.js +347 -0
  148. package/lib/dist/tests/features/wrap-development.test.d.ts +1 -0
  149. package/lib/dist/tests/features/wrap-development.test.js +130 -0
  150. package/lib/dist/tests/features/wrap-extruded-target.test.d.ts +1 -0
  151. package/lib/dist/tests/features/wrap-extruded-target.test.js +106 -0
  152. package/lib/dist/tests/features/wrap-repeat.test.d.ts +1 -0
  153. package/lib/dist/tests/features/wrap-repeat.test.js +93 -0
  154. package/lib/dist/tests/features/wrap.test.d.ts +1 -0
  155. package/lib/dist/tests/features/wrap.test.js +331 -0
  156. package/lib/dist/tests/math/bspline-interpolation.test.d.ts +1 -0
  157. package/lib/dist/tests/math/bspline-interpolation.test.js +119 -0
  158. package/lib/dist/tests/measure.test.d.ts +1 -0
  159. package/lib/dist/tests/measure.test.js +288 -0
  160. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  161. package/llm-docs/api/helix.md +64 -0
  162. package/llm-docs/api/index.json +11 -2
  163. package/llm-docs/api/text.md +52 -0
  164. package/llm-docs/api/types/helix.md +105 -0
  165. package/llm-docs/api/types/text.md +138 -0
  166. package/llm-docs/api/types/wrap.md +131 -0
  167. package/llm-docs/api/wrap.md +62 -0
  168. package/llm-docs/index.json +121 -1
  169. package/mcp/dist/server.js +20 -1
  170. package/mcp/dist/tools/inspection.d.ts +17 -0
  171. package/mcp/dist/tools/inspection.js +14 -0
  172. package/package.json +7 -3
  173. package/server/dist/fluidcad-server.d.ts +29 -0
  174. package/server/dist/fluidcad-server.js +40 -0
  175. package/server/dist/index.js +4 -2
  176. package/server/dist/model-package/pack.js +7 -6
  177. package/server/dist/model-package/types.d.ts +4 -3
  178. package/server/dist/preferences.d.ts +4 -0
  179. package/server/dist/preferences.js +2 -0
  180. package/server/dist/routes/measure.d.ts +3 -0
  181. package/server/dist/routes/measure.js +32 -0
  182. package/server/dist/routes/preferences.js +6 -0
  183. package/server/dist/routes/sketch-edits.js +2 -1
  184. package/ui/dist/assets/{index-CDJmUpFI.css → index-dAFdg2Un.css} +1 -1
  185. package/ui/dist/assets/{index-MRqwG9Vh.js → index-no7mtr5s.js} +149 -102
  186. package/ui/dist/index.html +2 -2
@@ -103,7 +103,7 @@ export class WireOps {
103
103
  fixer.FixGaps2d();
104
104
  fixer.FixEdgeCurves();
105
105
  fixer.FixConnected(oc.Precision.Confusion());
106
- fixer.FixReorder();
106
+ fixer.FixReorder(true);
107
107
  fixer.Perform();
108
108
  const fixed = fixer.Wire();
109
109
  fixer.delete();
@@ -0,0 +1,105 @@
1
+ import { Plane } from "../math/plane.js";
2
+ import { Point, Point2D } from "../math/point.js";
3
+ import { Vector3d } from "../math/vector3d.js";
4
+ export interface UV {
5
+ u: number;
6
+ v: number;
7
+ }
8
+ /** Geometry of a cylindrical target surface, extracted from its `gp_Cylinder`. */
9
+ export interface CylinderSpec {
10
+ origin: Point;
11
+ axisDir: Vector3d;
12
+ radius: number;
13
+ }
14
+ /** Geometry of a conical target surface, extracted from its `gp_Cone`. */
15
+ export interface ConeSpec {
16
+ origin: Point;
17
+ axisDir: Vector3d;
18
+ /** Radius in the frame's reference plane (at v = 0). */
19
+ refRadius: number;
20
+ /** Cone half-angle. Negative angles are normalized by reversing the axis. */
21
+ semiAngle: number;
22
+ }
23
+ export type Development = CylinderDevelopment | ConeDevelopment;
24
+ /**
25
+ * Isometric (arc-length preserving) development of a sketch plane onto a
26
+ * developable surface — a true wrap, not a projection.
27
+ *
28
+ * The mapping is anchored at the sketch plane origin: its radial projection
29
+ * onto the surface becomes the anchor point, and the surface frame is
30
+ * recentered so the anchor sits at u = 0, keeping wrapped geometry away from
31
+ * the parametric seam.
32
+ *
33
+ * In-plane orientation is derived from the surface rather than assumed: the
34
+ * projection of the surface meridian onto the sketch plane maps to +v, and
35
+ * the perpendicular in-plane direction maps to +u with its sign matched to
36
+ * the projection of the surface's +u tangent. For the canonical sketch on a
37
+ * tangent plane this is the exact development; for tilted planes it degrades
38
+ * gracefully to the nearest isometry.
39
+ */
40
+ export declare abstract class SurfaceDevelopment {
41
+ /** Frame origin (on the surface axis). */
42
+ readonly origin: Point;
43
+ /** Frame Z — the surface axis. */
44
+ readonly axisDir: Vector3d;
45
+ /** Frame X — points from the axis toward the sketch anchor (u = 0). */
46
+ readonly xDir: Vector3d;
47
+ /** Frame Y — completes the right-handed frame (+u tangent at the anchor). */
48
+ readonly yDir: Vector3d;
49
+ /** In-plane unit direction (sketch coords) that maps to +u (around the surface). */
50
+ private readonly sDir;
51
+ /** In-plane unit direction (sketch coords) that maps to +v (along the meridian). */
52
+ private readonly hDir;
53
+ protected constructor(plane: Plane, origin: Point, axisDir: Vector3d, xDir: Vector3d, meridianDir: Vector3d);
54
+ private static projectIntoPlane;
55
+ /** Sketch-plane point → development coordinates (s along +u, h along +v). */
56
+ protected develop(p: Point2D): {
57
+ s: number;
58
+ h: number;
59
+ };
60
+ /**
61
+ * Whether the mapping preserves winding: a counter-clockwise loop in
62
+ * sketch-plane coordinates (around the plane normal) stays counter-clockwise
63
+ * in UV. The (s, h) basis decides it — the u and v scales are positive.
64
+ */
65
+ isOrientationPreserving(): boolean;
66
+ /** Maps a sketch-plane point to parameters on the recentered surface. */
67
+ abstract toUV(p: Point2D): UV;
68
+ /** Evaluates the recentered surface at the given parameters. */
69
+ abstract evalPoint(uv: UV): Point;
70
+ /** Normal distance from a 3D point to the surface. */
71
+ abstract distanceTo(p: Point): number;
72
+ /** Outward surface normal at (the radial projection of) the given point. */
73
+ abstract surfaceNormalAt(p: Point): Vector3d;
74
+ /** Decomposes a point into axial height and radial offset in the surface frame. */
75
+ protected radialSplit(p: Point): {
76
+ z: number;
77
+ radialDist: number;
78
+ radialDir: Vector3d;
79
+ };
80
+ }
81
+ export declare class CylinderDevelopment extends SurfaceDevelopment {
82
+ readonly kind: "cylinder";
83
+ readonly radius: number;
84
+ /** Axial height of the sketch anchor in the surface frame. */
85
+ private readonly v0;
86
+ constructor(spec: CylinderSpec, plane: Plane);
87
+ toUV(p: Point2D): UV;
88
+ evalPoint(uv: UV): Point;
89
+ distanceTo(p: Point): number;
90
+ surfaceNormalAt(p: Point): Vector3d;
91
+ }
92
+ export declare class ConeDevelopment extends SurfaceDevelopment {
93
+ readonly kind: "cone";
94
+ readonly refRadius: number;
95
+ readonly semiAngle: number;
96
+ /** Slant distance from the apex to the v = 0 circle (= refRadius / sin(semiAngle)). */
97
+ private readonly apexSlant;
98
+ /** Slant distance from the apex to the sketch anchor. */
99
+ private readonly anchorSlant;
100
+ constructor(spec: ConeSpec, plane: Plane);
101
+ toUV(p: Point2D): UV;
102
+ evalPoint(uv: UV): Point;
103
+ distanceTo(p: Point): number;
104
+ surfaceNormalAt(p: Point): Vector3d;
105
+ }
@@ -0,0 +1,179 @@
1
+ import { Point2D } from "../math/point.js";
2
+ const EPSILON = 1e-9;
3
+ const DIRECTION_EPSILON = 1e-6;
4
+ /**
5
+ * Computes the anchor frame of a development: the sketch plane origin is
6
+ * projected radially onto the surface, and the frame's X direction points
7
+ * from the axis toward that anchor so the anchor sits at u = 0.
8
+ */
9
+ function anchorFrame(origin, axisDir, plane) {
10
+ const toPlaneOrigin = origin.vectorTo(plane.origin);
11
+ const z0 = toPlaneOrigin.dot(axisDir);
12
+ const radial = toPlaneOrigin.subtract(axisDir.multiply(z0));
13
+ if (radial.length() < EPSILON) {
14
+ throw new Error("wrap(): the sketch plane origin must not lie on the target surface axis");
15
+ }
16
+ return { xDir: radial.normalize(), z0 };
17
+ }
18
+ /**
19
+ * Isometric (arc-length preserving) development of a sketch plane onto a
20
+ * developable surface — a true wrap, not a projection.
21
+ *
22
+ * The mapping is anchored at the sketch plane origin: its radial projection
23
+ * onto the surface becomes the anchor point, and the surface frame is
24
+ * recentered so the anchor sits at u = 0, keeping wrapped geometry away from
25
+ * the parametric seam.
26
+ *
27
+ * In-plane orientation is derived from the surface rather than assumed: the
28
+ * projection of the surface meridian onto the sketch plane maps to +v, and
29
+ * the perpendicular in-plane direction maps to +u with its sign matched to
30
+ * the projection of the surface's +u tangent. For the canonical sketch on a
31
+ * tangent plane this is the exact development; for tilted planes it degrades
32
+ * gracefully to the nearest isometry.
33
+ */
34
+ export class SurfaceDevelopment {
35
+ /** Frame origin (on the surface axis). */
36
+ origin;
37
+ /** Frame Z — the surface axis. */
38
+ axisDir;
39
+ /** Frame X — points from the axis toward the sketch anchor (u = 0). */
40
+ xDir;
41
+ /** Frame Y — completes the right-handed frame (+u tangent at the anchor). */
42
+ yDir;
43
+ /** In-plane unit direction (sketch coords) that maps to +u (around the surface). */
44
+ sDir;
45
+ /** In-plane unit direction (sketch coords) that maps to +v (along the meridian). */
46
+ hDir;
47
+ constructor(plane, origin, axisDir, xDir, meridianDir) {
48
+ this.origin = origin;
49
+ this.axisDir = axisDir;
50
+ this.xDir = xDir;
51
+ this.yDir = axisDir.cross(xDir).normalize();
52
+ this.hDir = SurfaceDevelopment.projectIntoPlane(plane, meridianDir, "wrap(): the sketch plane is perpendicular to the target surface axis");
53
+ const uImage = SurfaceDevelopment.projectIntoPlane(plane, this.yDir, "wrap(): the sketch plane must not contain the target surface axis");
54
+ const perp = new Point2D(-this.hDir.y, this.hDir.x);
55
+ const towardU = perp.x * uImage.x + perp.y * uImage.y;
56
+ this.sDir = towardU >= 0 ? perp : new Point2D(-perp.x, -perp.y);
57
+ }
58
+ static projectIntoPlane(plane, dir, errorMessage) {
59
+ const inPlane = dir.subtract(plane.normal.multiply(dir.dot(plane.normal)));
60
+ if (inPlane.length() < DIRECTION_EPSILON) {
61
+ throw new Error(errorMessage);
62
+ }
63
+ const unit = inPlane.normalize();
64
+ return new Point2D(unit.dot(plane.xDirection), unit.dot(plane.yDirection));
65
+ }
66
+ /** Sketch-plane point → development coordinates (s along +u, h along +v). */
67
+ develop(p) {
68
+ return {
69
+ s: p.x * this.sDir.x + p.y * this.sDir.y,
70
+ h: p.x * this.hDir.x + p.y * this.hDir.y,
71
+ };
72
+ }
73
+ /**
74
+ * Whether the mapping preserves winding: a counter-clockwise loop in
75
+ * sketch-plane coordinates (around the plane normal) stays counter-clockwise
76
+ * in UV. The (s, h) basis decides it — the u and v scales are positive.
77
+ */
78
+ isOrientationPreserving() {
79
+ return this.sDir.x * this.hDir.y - this.sDir.y * this.hDir.x > 0;
80
+ }
81
+ /** Decomposes a point into axial height and radial offset in the surface frame. */
82
+ radialSplit(p) {
83
+ const w = this.origin.vectorTo(p);
84
+ const z = w.dot(this.axisDir);
85
+ const radial = w.subtract(this.axisDir.multiply(z));
86
+ const radialDist = radial.length();
87
+ const radialDir = radialDist < EPSILON ? this.xDir : radial.normalize();
88
+ return { z, radialDist, radialDir };
89
+ }
90
+ }
91
+ export class CylinderDevelopment extends SurfaceDevelopment {
92
+ kind = 'cylinder';
93
+ radius;
94
+ /** Axial height of the sketch anchor in the surface frame. */
95
+ v0;
96
+ constructor(spec, plane) {
97
+ const axisDir = spec.axisDir.normalize();
98
+ const { xDir, z0 } = anchorFrame(spec.origin, axisDir, plane);
99
+ super(plane, spec.origin, axisDir, xDir, axisDir);
100
+ this.radius = spec.radius;
101
+ this.v0 = z0;
102
+ }
103
+ toUV(p) {
104
+ const { s, h } = this.develop(p);
105
+ return { u: s / this.radius, v: this.v0 + h };
106
+ }
107
+ evalPoint(uv) {
108
+ return this.origin
109
+ .add(this.xDir.multiply(this.radius * Math.cos(uv.u)))
110
+ .add(this.yDir.multiply(this.radius * Math.sin(uv.u)))
111
+ .add(this.axisDir.multiply(uv.v));
112
+ }
113
+ distanceTo(p) {
114
+ return Math.abs(this.radialSplit(p).radialDist - this.radius);
115
+ }
116
+ surfaceNormalAt(p) {
117
+ return this.radialSplit(p).radialDir;
118
+ }
119
+ }
120
+ export class ConeDevelopment extends SurfaceDevelopment {
121
+ kind = 'cone';
122
+ refRadius;
123
+ semiAngle;
124
+ /** Slant distance from the apex to the v = 0 circle (= refRadius / sin(semiAngle)). */
125
+ apexSlant;
126
+ /** Slant distance from the apex to the sketch anchor. */
127
+ anchorSlant;
128
+ constructor(spec, plane) {
129
+ // Normalize to a positive half-angle so the slant grows with +v; a
130
+ // negative gp_Cone angle describes the same surface with a reversed axis.
131
+ let axisDir = spec.axisDir.normalize();
132
+ let semiAngle = spec.semiAngle;
133
+ if (semiAngle < 0) {
134
+ axisDir = axisDir.negate();
135
+ semiAngle = -semiAngle;
136
+ }
137
+ const { xDir, z0 } = anchorFrame(spec.origin, axisDir, plane);
138
+ const meridianDir = xDir.multiply(Math.sin(semiAngle)).add(axisDir.multiply(Math.cos(semiAngle)));
139
+ super(plane, spec.origin, axisDir, xDir, meridianDir);
140
+ this.refRadius = spec.refRadius;
141
+ this.semiAngle = semiAngle;
142
+ this.apexSlant = spec.refRadius / Math.sin(semiAngle);
143
+ this.anchorSlant = this.apexSlant + z0 / Math.cos(semiAngle);
144
+ if (this.anchorSlant < EPSILON) {
145
+ throw new Error("wrap(): the sketch plane origin projects onto the apex of the conical target face");
146
+ }
147
+ }
148
+ toUV(p) {
149
+ const { s, h } = this.develop(p);
150
+ // The cone develops into a planar sector around the apex, which sits at
151
+ // distance `anchorSlant` behind the sketch anchor along -h. Develop the
152
+ // point in polar coordinates around it: slant = planar radius, surface
153
+ // angle = planar angle / sin(semiAngle).
154
+ const fromApexH = this.anchorSlant + h;
155
+ const rho = Math.hypot(s, fromApexH);
156
+ if (rho < EPSILON) {
157
+ throw new Error("wrap(): the sketch extends across the apex of the conical target face");
158
+ }
159
+ const phi = Math.atan2(s, fromApexH);
160
+ return { u: phi / Math.sin(this.semiAngle), v: rho - this.apexSlant };
161
+ }
162
+ evalPoint(uv) {
163
+ const r = this.refRadius + uv.v * Math.sin(this.semiAngle);
164
+ return this.origin
165
+ .add(this.xDir.multiply(r * Math.cos(uv.u)))
166
+ .add(this.yDir.multiply(r * Math.sin(uv.u)))
167
+ .add(this.axisDir.multiply(uv.v * Math.cos(this.semiAngle)));
168
+ }
169
+ distanceTo(p) {
170
+ const { z, radialDist } = this.radialSplit(p);
171
+ const surfaceRadius = this.refRadius + z * Math.tan(this.semiAngle);
172
+ return Math.abs((radialDist - surfaceRadius) * Math.cos(this.semiAngle));
173
+ }
174
+ surfaceNormalAt(p) {
175
+ const { radialDir } = this.radialSplit(p);
176
+ return radialDir.multiply(Math.cos(this.semiAngle))
177
+ .subtract(this.axisDir.multiply(Math.sin(this.semiAngle)));
178
+ }
179
+ }
@@ -0,0 +1,100 @@
1
+ import { Face } from "../common/face.js";
2
+ import { Shape } from "../common/shape.js";
3
+ import { Plane } from "../math/plane.js";
4
+ import { Development } from "./wrap-development.js";
5
+ export interface WrapResult {
6
+ solids: Shape[];
7
+ /** Faces lying on the target surface (the base of the wrap). */
8
+ startFaces: Face[];
9
+ /** Faces offset from the target surface by the wrap thickness. */
10
+ endFaces: Face[];
11
+ /** Wall faces generated from the outer boundary of each region. */
12
+ sideFaces: Face[];
13
+ /** Wall faces generated from sketch holes inside a region. */
14
+ internalFaces: Face[];
15
+ }
16
+ export declare class WrapOps {
17
+ /**
18
+ * Wraps planar sketch region faces onto the surface of `targetFace` and
19
+ * thickens them by `thickness` measured along the surface normal. Positive
20
+ * thickness grows out of the material (emboss), negative grows into it
21
+ * (deboss tool). Returns the thickened solids with their faces classified.
22
+ *
23
+ * The pad base lies EXACTLY on the target surface. Downstream booleans
24
+ * resolve that coincident-face contact via their fuzzy tolerance and
25
+ * same-domain handling; do not be tempted to sink the base slightly past
26
+ * the surface to "help" them — the resulting wall∕target section curves
27
+ * are approximated by OCCT and oscillate visibly near the wall joints.
28
+ */
29
+ static wrap(regionFaces: Face[], sketchPlane: Plane, targetFace: Face, thickness: number): WrapResult;
30
+ /** Builds the development mapping for the target face's underlying surface. */
31
+ static createDevelopment(targetFace: Face, sketchPlane: Plane): Development;
32
+ /**
33
+ * Whether the target face's material-outward normal points toward the
34
+ * surface axis (a bore wall) rather than away from it (an outer wall).
35
+ * The TopAbs orientation flag alone cannot tell: prism-swept lateral
36
+ * faces carry a reverse-parameterized surface (intrinsic normal inward,
37
+ * flag REVERSED) yet still face away from the axis.
38
+ */
39
+ private static isInwardFacing;
40
+ /** Builds the recentered Geom surface (sketch anchor at u = 0). */
41
+ private static makeSurface;
42
+ /** Maps one planar region face onto the surface as a face with pcurve boundaries. */
43
+ private static wrapRegion;
44
+ /**
45
+ * Enforces the winding the face builder needs: the outer boundary
46
+ * counter-clockwise in UV (material to its left on the surface), holes
47
+ * clockwise. The mapped wire inherits the planar wire's winding through the
48
+ * development (possibly mirrored), so measure the source and reverse the UV
49
+ * wire when it lands the wrong way.
50
+ */
51
+ private static orientUvWire;
52
+ /** Maps a planar wire into a wire of edges with pcurves on the surface. */
53
+ private static mapWire;
54
+ /**
55
+ * Maps one sketch edge onto the surface, following the source wire's
56
+ * traversal direction (reversed edges are sampled back to front) so the
57
+ * assembled UV wire winds the same way as the planar wire it came from.
58
+ * Straight edges on cylinders map to exact UV lines (the development is
59
+ * affine there); everything else is sampled along the curve and fitted with
60
+ * a 2D B-spline. Closed edges (e.g. full circles) are split into two halves
61
+ * so the resulting wire has topologically distinct vertices.
62
+ */
63
+ private static mapEdge;
64
+ private static mapPoint;
65
+ private static makeFittedUvEdge;
66
+ private static makeUvLineEdge;
67
+ /**
68
+ * Interpolates the developed UV samples of one sketch edge with a 2D
69
+ * B-spline that passes exactly through every sample (so adjacent wire
70
+ * edges meet bit-exactly — no endpoint snapping needed).
71
+ *
72
+ * The poles/knots are computed in-house: fluidcad-ocjs currently
73
+ * miscompiles `Geom2dAPI_PointsToBSpline` — both its array constructors
74
+ * (NaN poles) and its `Init` path (the "fit" of a clean semicircle bulged
75
+ * 70% past the samples). `Geom2d_BSplineCurve`'s array constructor is
76
+ * unaffected.
77
+ */
78
+ private static fitUvCurve;
79
+ /** Thickens the wrapped face along the surface normal into a solid. */
80
+ private static thicken;
81
+ /**
82
+ * Classifies the thickened solid's faces. The wrapped base face survives
83
+ * thickening unchanged (start); the only other face whose normal is aligned
84
+ * with the surface normal is the offset face (end); the remaining walls are
85
+ * split into internal (sharing an edge with a sketch hole) and side.
86
+ */
87
+ private static classify;
88
+ private static collectHoleEdges;
89
+ private static sharesEdgeWith;
90
+ /**
91
+ * Samples the face at the middle of its UV bounds: the surface point and
92
+ * the material-outward normal (oriented by the face's TopAbs flag) at that
93
+ * SAME parameter. Classification compares this normal against the
94
+ * development normal at the sampled point — sampling both at one location
95
+ * keeps the comparison angle-independent on periodic surfaces, where the
96
+ * normal rotates with u (a normal taken anywhere else drifts by the angular
97
+ * distance and breaks the alignment test past ~45°).
98
+ */
99
+ private static probeFace;
100
+ }