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.
- package/LICENSE.txt +21 -504
- package/README.md +1 -1
- package/lib/dist/common/edge.d.ts +1 -1
- package/lib/dist/common/face.d.ts +1 -1
- package/lib/dist/common/scene-object.d.ts +6 -0
- package/lib/dist/common/scene-object.js +8 -0
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/common/shape-history-tracker.d.ts +1 -1
- package/lib/dist/common/shape.d.ts +1 -1
- package/lib/dist/common/solid.d.ts +1 -1
- package/lib/dist/common/transformable-primitive.d.ts +12 -1
- package/lib/dist/common/transformable-primitive.js +27 -0
- package/lib/dist/common/vertex.d.ts +1 -1
- package/lib/dist/common/wire.d.ts +1 -1
- package/lib/dist/core/2d/index.d.ts +1 -0
- package/lib/dist/core/2d/index.js +1 -0
- package/lib/dist/core/2d/text.d.ts +30 -0
- package/lib/dist/core/2d/text.js +37 -0
- package/lib/dist/core/helix.d.ts +20 -0
- package/lib/dist/core/helix.js +36 -0
- package/lib/dist/core/index.d.ts +3 -1
- package/lib/dist/core/index.js +2 -0
- package/lib/dist/core/interfaces.d.ts +180 -0
- package/lib/dist/core/wrap.d.ts +17 -0
- package/lib/dist/core/wrap.js +39 -0
- package/lib/dist/features/2d/text.d.ts +67 -0
- package/lib/dist/features/2d/text.js +320 -0
- package/lib/dist/features/cylinder.d.ts +3 -1
- package/lib/dist/features/cylinder.js +5 -2
- package/lib/dist/features/extrude-base.d.ts +1 -0
- package/lib/dist/features/extrude-to-face.d.ts +1 -0
- package/lib/dist/features/extrude-to-face.js +6 -0
- package/lib/dist/features/fillet.d.ts +1 -1
- package/lib/dist/features/helix.d.ts +41 -0
- package/lib/dist/features/helix.js +337 -0
- package/lib/dist/features/select.js +32 -8
- package/lib/dist/features/simple-extruder.d.ts +1 -1
- package/lib/dist/features/simple-extruder.js +7 -2
- package/lib/dist/features/sphere.d.ts +3 -1
- package/lib/dist/features/sphere.js +5 -2
- package/lib/dist/features/sweep.js +7 -2
- package/lib/dist/features/wrap.d.ts +39 -0
- package/lib/dist/features/wrap.js +116 -0
- package/lib/dist/filters/edge/belongs-to-face.d.ts +3 -1
- package/lib/dist/filters/edge/belongs-to-face.js +14 -10
- package/lib/dist/filters/filter.d.ts +1 -1
- package/lib/dist/filters/from-object.d.ts +1 -1
- package/lib/dist/filters/tangent-expander.d.ts +1 -1
- package/lib/dist/filters/tangent-expander.js +57 -40
- package/lib/dist/helpers/scene-helpers.d.ts +2 -0
- package/lib/dist/helpers/scene-helpers.js +1 -1
- package/lib/dist/index.d.ts +2 -0
- package/lib/dist/index.js +3 -1
- package/lib/dist/io/file-import.d.ts +7 -0
- package/lib/dist/io/file-import.js +28 -1
- package/lib/dist/io/font-registry.d.ts +45 -0
- package/lib/dist/io/font-registry.js +272 -0
- package/lib/dist/math/bspline-interpolation.d.ts +29 -0
- package/lib/dist/math/bspline-interpolation.js +194 -0
- package/lib/dist/oc/boolean-ops.d.ts +3 -1
- package/lib/dist/oc/boolean-ops.js +15 -1
- package/lib/dist/oc/color-transfer.d.ts +1 -1
- package/lib/dist/oc/constraints/constraint-helpers.d.ts +4 -4
- package/lib/dist/oc/constraints/curve/tangent-circle-solver.js +10 -9
- package/lib/dist/oc/constraints/curve/tangent-line-solver.js +5 -6
- package/lib/dist/oc/convert.d.ts +1 -1
- package/lib/dist/oc/draft-ops.d.ts +1 -1
- package/lib/dist/oc/edge-ops.d.ts +2 -2
- package/lib/dist/oc/edge-ops.js +13 -14
- package/lib/dist/oc/edge-props.d.ts +1 -1
- package/lib/dist/oc/edge-query.d.ts +1 -1
- package/lib/dist/oc/edge-query.js +3 -8
- package/lib/dist/oc/errors.d.ts +8 -0
- package/lib/dist/oc/errors.js +27 -0
- package/lib/dist/oc/explorer.d.ts +2 -2
- package/lib/dist/oc/extrude-ops.d.ts +28 -2
- package/lib/dist/oc/extrude-ops.js +56 -7
- package/lib/dist/oc/face-ops.d.ts +2 -1
- package/lib/dist/oc/face-ops.js +11 -0
- package/lib/dist/oc/face-props.d.ts +1 -1
- package/lib/dist/oc/face-query.d.ts +12 -1
- package/lib/dist/oc/face-query.js +39 -0
- package/lib/dist/oc/fillet-ops.d.ts +1 -1
- package/lib/dist/oc/fillet-ops.js +4 -4
- package/lib/dist/oc/geometry.d.ts +1 -1
- package/lib/dist/oc/geometry.js +12 -14
- package/lib/dist/oc/helix-ops.d.ts +37 -0
- package/lib/dist/oc/helix-ops.js +88 -0
- package/lib/dist/oc/hit-test.d.ts +1 -1
- package/lib/dist/oc/index.d.ts +4 -0
- package/lib/dist/oc/index.js +2 -0
- package/lib/dist/oc/init.d.ts +1 -1
- package/lib/dist/oc/init.js +1 -1
- package/lib/dist/oc/intersection.js +1 -1
- package/lib/dist/oc/io.d.ts +6 -6
- package/lib/dist/oc/io.js +31 -24
- package/lib/dist/oc/measure/classify.d.ts +34 -0
- package/lib/dist/oc/measure/classify.js +246 -0
- package/lib/dist/oc/measure/measure-ops.d.ts +9 -0
- package/lib/dist/oc/measure/measure-ops.js +210 -0
- package/lib/dist/oc/measure/measure-types.d.ts +39 -0
- package/lib/dist/oc/measure/measure-types.js +1 -0
- package/lib/dist/oc/measure/sampling.d.ts +9 -0
- package/lib/dist/oc/measure/sampling.js +77 -0
- package/lib/dist/oc/measure/vec.d.ts +13 -0
- package/lib/dist/oc/measure/vec.js +23 -0
- package/lib/dist/oc/mesh.d.ts +1 -1
- package/lib/dist/oc/mesh.js +40 -28
- package/lib/dist/oc/path-sampler.d.ts +29 -0
- package/lib/dist/oc/path-sampler.js +63 -0
- package/lib/dist/oc/props.d.ts +1 -1
- package/lib/dist/oc/props.js +4 -1
- package/lib/dist/oc/shape-hash.d.ts +26 -0
- package/lib/dist/oc/shape-hash.js +32 -0
- package/lib/dist/oc/shape-ops.d.ts +5 -3
- package/lib/dist/oc/shape-ops.js +6 -5
- package/lib/dist/oc/sweep-ops.d.ts +22 -1
- package/lib/dist/oc/sweep-ops.js +206 -18
- package/lib/dist/oc/text-outline.d.ts +62 -0
- package/lib/dist/oc/text-outline.js +212 -0
- package/lib/dist/oc/topology-index.d.ts +1 -1
- package/lib/dist/oc/vertex-ops.d.ts +1 -1
- package/lib/dist/oc/wire-ops.d.ts +1 -1
- package/lib/dist/oc/wire-ops.js +1 -1
- package/lib/dist/oc/wrap-development.d.ts +105 -0
- package/lib/dist/oc/wrap-development.js +179 -0
- package/lib/dist/oc/wrap-ops.d.ts +100 -0
- package/lib/dist/oc/wrap-ops.js +406 -0
- package/lib/dist/rendering/render-solid.js +10 -2
- package/lib/dist/scene-manager.d.ts +2 -0
- package/lib/dist/scene-manager.js +29 -0
- package/lib/dist/tests/features/cylinder-curve-filter.test.js +3 -3
- package/lib/dist/tests/features/extrude-to-face.test.js +38 -1
- package/lib/dist/tests/features/helix.test.d.ts +1 -0
- package/lib/dist/tests/features/helix.test.js +295 -0
- package/lib/dist/tests/features/repeat-primitive.test.d.ts +1 -0
- package/lib/dist/tests/features/repeat-primitive.test.js +60 -0
- package/lib/dist/tests/features/rib.test.js +6 -1
- package/lib/dist/tests/features/sweep.test.js +125 -1
- package/lib/dist/tests/features/text.test.d.ts +1 -0
- package/lib/dist/tests/features/text.test.js +347 -0
- package/lib/dist/tests/features/wrap-development.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-development.test.js +130 -0
- package/lib/dist/tests/features/wrap-extruded-target.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-extruded-target.test.js +106 -0
- package/lib/dist/tests/features/wrap-repeat.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-repeat.test.js +93 -0
- package/lib/dist/tests/features/wrap.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap.test.js +331 -0
- package/lib/dist/tests/math/bspline-interpolation.test.d.ts +1 -0
- package/lib/dist/tests/math/bspline-interpolation.test.js +119 -0
- package/lib/dist/tests/measure.test.d.ts +1 -0
- package/lib/dist/tests/measure.test.js +288 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/llm-docs/api/helix.md +64 -0
- package/llm-docs/api/index.json +11 -2
- package/llm-docs/api/text.md +52 -0
- package/llm-docs/api/types/helix.md +105 -0
- package/llm-docs/api/types/text.md +138 -0
- package/llm-docs/api/types/wrap.md +131 -0
- package/llm-docs/api/wrap.md +62 -0
- package/llm-docs/index.json +121 -1
- package/mcp/dist/server.js +20 -1
- package/mcp/dist/tools/inspection.d.ts +17 -0
- package/mcp/dist/tools/inspection.js +14 -0
- package/package.json +7 -3
- package/server/dist/fluidcad-server.d.ts +10 -0
- package/server/dist/fluidcad-server.js +10 -0
- package/server/dist/index.js +4 -2
- package/server/dist/preferences.d.ts +4 -0
- package/server/dist/preferences.js +2 -0
- package/server/dist/routes/measure.d.ts +3 -0
- package/server/dist/routes/measure.js +32 -0
- package/server/dist/routes/preferences.js +6 -0
- package/server/dist/routes/sketch-edits.js +2 -1
- package/ui/dist/assets/{index-CDJmUpFI.css → index-dAFdg2Un.css} +1 -1
- package/ui/dist/assets/{index-MRqwG9Vh.js → index-no7mtr5s.js} +149 -102
- package/ui/dist/index.html +2 -2
package/lib/dist/oc/wire-ops.js
CHANGED
|
@@ -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
|
+
}
|