@code3d/core 0.0.1-alpha.11 → 0.0.1-alpha.13
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/README.md +55 -41
- package/bld/chunks/{chunk-HZRQUHM2.js → chunk-776Q5P2L.js} +2 -2
- package/bld/chunks/{chunk-QK6ZET47.js → chunk-N7JJWNVL.js} +3 -3
- package/bld/chunks/{chunk-CL3E2DE4.js → chunk-VFPWXSFD.js} +2 -2
- package/bld/chunks/{chunk-JBVIAMJ6.js → chunk-VINZNODV.js} +589 -26
- package/bld/chunks/chunk-VINZNODV.js.map +7 -0
- package/bld/library/extrude.d.ts +5 -0
- package/bld/library/extrude.d.ts.map +1 -1
- package/bld/library/index.d.ts +2 -2
- package/bld/library/index.d.ts.map +1 -1
- package/bld/library/index.js +17 -1
- package/bld/library/inspect.d.ts +3 -1
- package/bld/library/inspect.d.ts.map +1 -1
- package/bld/library/loft.d.ts +7 -1
- package/bld/library/loft.d.ts.map +1 -1
- package/bld/library/replicad.js +2 -2
- package/bld/library/runtime.d.ts +75 -8
- package/bld/library/runtime.d.ts.map +1 -1
- package/bld/node/index.js +19 -3
- package/bld/node/replicad.js +4 -4
- package/bld/tooling/index.js +2 -2
- package/docs/api.md +143 -13
- package/docs/local-coordinates.md +2 -0
- package/docs/runtime.md +52 -2
- package/docs/topology.md +6 -0
- package/docs/values.md +34 -31
- package/package.json +1 -1
- package/src/library/extrude.ts +129 -2
- package/src/library/index.ts +9 -0
- package/src/library/inspect.ts +4 -2
- package/src/library/loft.ts +67 -2
- package/src/library/runtime.ts +646 -8
- package/bld/chunks/chunk-JBVIAMJ6.js.map +0 -7
- /package/bld/chunks/{chunk-HZRQUHM2.js.map → chunk-776Q5P2L.js.map} +0 -0
- /package/bld/chunks/{chunk-QK6ZET47.js.map → chunk-N7JJWNVL.js.map} +0 -0
- /package/bld/chunks/{chunk-CL3E2DE4.js.map → chunk-VFPWXSFD.js.map} +0 -0
package/src/library/loft.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
assembleWire,
|
|
2
3
|
cast,
|
|
3
4
|
getOC,
|
|
5
|
+
measureVolume,
|
|
4
6
|
type AnyShape,
|
|
7
|
+
type Edge,
|
|
5
8
|
type Face,
|
|
6
9
|
type Wire,
|
|
7
10
|
type Shape3D,
|
|
@@ -19,6 +22,66 @@ import {
|
|
|
19
22
|
type TopologyInput,
|
|
20
23
|
type ShapeTopology,
|
|
21
24
|
} from './topology.js';
|
|
25
|
+
import type {Vec3} from './spatial.js';
|
|
26
|
+
|
|
27
|
+
/** Sweep a face along one open edge, keeping the authored starting frame. */
|
|
28
|
+
export function sweepWithTopology(
|
|
29
|
+
profile: TopologyInput,
|
|
30
|
+
path: Edge,
|
|
31
|
+
normal: Vec3,
|
|
32
|
+
): Readonly<{shape: Shape3D; topology: ShapeTopology}> {
|
|
33
|
+
if (path.isClosed || !(path.length > 1e-9))
|
|
34
|
+
throw new Error('Sweep spine must be a non-degenerate open curve.');
|
|
35
|
+
const start = path.pointAt(0);
|
|
36
|
+
let tangent: ReturnType<Edge['tangentAt']> | undefined;
|
|
37
|
+
try {
|
|
38
|
+
tangent = path.tangentAt(0);
|
|
39
|
+
const position = start.toTuple();
|
|
40
|
+
const direction = tangent.toTuple();
|
|
41
|
+
const magnitude = Math.hypot(...direction);
|
|
42
|
+
if (!(magnitude > 1e-9))
|
|
43
|
+
throw new Error('Sweep spine must have a non-zero starting tangent.');
|
|
44
|
+
if (Math.hypot(...position) > 1e-6)
|
|
45
|
+
throw new Error(
|
|
46
|
+
'Sweep profile origin must coincide with the spine start.',
|
|
47
|
+
);
|
|
48
|
+
if (
|
|
49
|
+
(normal[0] * direction[0] +
|
|
50
|
+
normal[1] * direction[1] +
|
|
51
|
+
normal[2] * direction[2]) /
|
|
52
|
+
magnitude <
|
|
53
|
+
1 - 1e-6
|
|
54
|
+
)
|
|
55
|
+
throw new Error(
|
|
56
|
+
'Sweep profile normal must point along the spine start tangent.',
|
|
57
|
+
);
|
|
58
|
+
} finally {
|
|
59
|
+
tangent?.delete();
|
|
60
|
+
start.delete();
|
|
61
|
+
}
|
|
62
|
+
const spine = assembleWire([path]);
|
|
63
|
+
let result: Readonly<{shape: Shape3D; topology: ShapeTopology}> | undefined;
|
|
64
|
+
try {
|
|
65
|
+
result = loftWithTopology([profile], spine, false);
|
|
66
|
+
if (!(Math.abs(measureVolume(result.shape)) > 0))
|
|
67
|
+
throw new Error('Sweep did not produce a non-degenerate solid.');
|
|
68
|
+
const validation = new (getOC().BRepCheck_Analyzer)(result.shape.wrapped);
|
|
69
|
+
try {
|
|
70
|
+
if (!validation.IsValid())
|
|
71
|
+
throw new Error(
|
|
72
|
+
'Sweep produced an invalid solid. Adjust the profile or path to avoid tight bends and intersections.',
|
|
73
|
+
);
|
|
74
|
+
} finally {
|
|
75
|
+
validation.delete();
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
result?.shape.delete();
|
|
80
|
+
throw error;
|
|
81
|
+
} finally {
|
|
82
|
+
spine.delete();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
22
85
|
|
|
23
86
|
export function loftWithTopology(
|
|
24
87
|
sections: readonly TopologyInput[],
|
|
@@ -48,7 +111,7 @@ export function loftWithTopology(
|
|
|
48
111
|
throw new Error('Loft sections must have matching hole counts.');
|
|
49
112
|
if (holes[0].length > 1)
|
|
50
113
|
throw new Error(
|
|
51
|
-
'
|
|
114
|
+
'A swept or lofted profile currently supports at most one hole; multiple holes need explicit correspondence.',
|
|
52
115
|
);
|
|
53
116
|
outer = loftContoursWithTopology(sections, spine, ruled);
|
|
54
117
|
if (!holes[0].length) {
|
|
@@ -115,7 +178,9 @@ function loftContoursWithTopology(
|
|
|
115
178
|
}
|
|
116
179
|
result = castOwnedShape3D(builder.Shape());
|
|
117
180
|
caps[0] = castOwnedShape(builder.FirstShape()) as Face;
|
|
118
|
-
|
|
181
|
+
// A single profile has one inherited start cap; its end cap is new topology.
|
|
182
|
+
if (sections.length > 1)
|
|
183
|
+
caps[sections.length - 1] = castOwnedShape(builder.LastShape()) as Face;
|
|
119
184
|
const topology = transferShapeTopology(
|
|
120
185
|
sections,
|
|
121
186
|
result,
|