okgeometry-api 1.2.0 → 1.4.0
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/Line.d.ts +10 -1
- package/dist/Line.d.ts.map +1 -1
- package/dist/Line.js +11 -0
- package/dist/Line.js.map +1 -1
- package/dist/Mesh.d.ts +123 -9
- package/dist/Mesh.d.ts.map +1 -1
- package/dist/Mesh.js +401 -26
- package/dist/Mesh.js.map +1 -1
- package/dist/MeshSurface.d.ts +32 -0
- package/dist/MeshSurface.d.ts.map +1 -0
- package/dist/MeshSurface.js +51 -0
- package/dist/MeshSurface.js.map +1 -0
- package/dist/NurbsCurve.d.ts +50 -2
- package/dist/NurbsCurve.d.ts.map +1 -1
- package/dist/NurbsCurve.js +76 -2
- package/dist/NurbsCurve.js.map +1 -1
- package/dist/NurbsSurface.d.ts +9 -1
- package/dist/NurbsSurface.d.ts.map +1 -1
- package/dist/NurbsSurface.js +12 -3
- package/dist/NurbsSurface.js.map +1 -1
- package/dist/PolyCurve.d.ts +21 -3
- package/dist/PolyCurve.d.ts.map +1 -1
- package/dist/PolyCurve.js +82 -38
- package/dist/PolyCurve.js.map +1 -1
- package/dist/Polygon.d.ts +13 -2
- package/dist/Polygon.d.ts.map +1 -1
- package/dist/Polygon.js +21 -3
- package/dist/Polygon.js.map +1 -1
- package/dist/Polyline.d.ts +19 -2
- package/dist/Polyline.d.ts.map +1 -1
- package/dist/Polyline.js +38 -6
- package/dist/Polyline.js.map +1 -1
- package/dist/Surface.d.ts +17 -0
- package/dist/Surface.d.ts.map +1 -0
- package/dist/Surface.js +2 -0
- package/dist/Surface.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wasm-base64.d.ts +1 -1
- package/dist/wasm-base64.d.ts.map +1 -1
- package/dist/wasm-base64.js +1 -1
- package/dist/wasm-base64.js.map +1 -1
- package/dist/wasm-bindings.d.ts +132 -2
- package/dist/wasm-bindings.d.ts.map +1 -1
- package/dist/wasm-bindings.js +207 -2
- package/dist/wasm-bindings.js.map +1 -1
- package/package.json +1 -1
- package/src/Line.ts +38 -20
- package/src/Mesh.ts +909 -464
- package/src/MeshSurface.ts +72 -0
- package/src/NurbsCurve.ts +103 -3
- package/src/NurbsSurface.ts +28 -13
- package/src/PolyCurve.ts +157 -85
- package/src/Polygon.ts +34 -4
- package/src/Polyline.ts +74 -24
- package/src/Surface.ts +18 -0
- package/src/index.ts +5 -0
- package/src/types.ts +15 -0
- package/src/wasm-base64.ts +1 -1
- package/src/wasm-bindings.d.ts +101 -2
- package/src/wasm-bindings.js +218 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ensureInit } from "./engine.js";
|
|
2
|
+
import { decodePointResult } from "./BufferCodec.js";
|
|
3
|
+
import type { Mesh, MeshPlanarFace } from "./Mesh.js";
|
|
4
|
+
import { Point } from "./Point.js";
|
|
5
|
+
import type { Surface } from "./Surface.js";
|
|
6
|
+
import { Vec3 } from "./Vec3.js";
|
|
7
|
+
import * as wasm from "./wasm-bindings.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Logical planar surface extracted from a coplanar connected face group on a mesh.
|
|
11
|
+
* Mirrors the `NurbsSurface` query API for evaluation and normals.
|
|
12
|
+
*/
|
|
13
|
+
export class MeshSurface implements Surface {
|
|
14
|
+
constructor(
|
|
15
|
+
public readonly mesh: Mesh,
|
|
16
|
+
public readonly face: MeshPlanarFace,
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
get index(): number {
|
|
20
|
+
return this.face.index;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get seedTriangleIndex(): number {
|
|
24
|
+
return this.face.seedTriangleIndex;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get triangleIndices(): number[] {
|
|
28
|
+
return this.face.triangleIndices;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get triangleCount(): number {
|
|
32
|
+
return this.face.triangleCount;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get centroid(): Point {
|
|
36
|
+
return this.face.centroid;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get faceNormal(): Vec3 {
|
|
40
|
+
return this.face.normal;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get area(): number {
|
|
44
|
+
return this.face.area;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Evaluate a point on this planar mesh surface.
|
|
49
|
+
* Parameters map across the face group's local 2D bounds.
|
|
50
|
+
* Returns `Point(NaN, NaN, NaN)` when the query falls outside the actual face region.
|
|
51
|
+
*/
|
|
52
|
+
evaluate(u: number, v: number): Point {
|
|
53
|
+
ensureInit();
|
|
54
|
+
return decodePointResult(
|
|
55
|
+
wasm.mesh_planar_face_evaluate(
|
|
56
|
+
this.mesh.vertexCount,
|
|
57
|
+
this.mesh.rawBuffer,
|
|
58
|
+
this.seedTriangleIndex,
|
|
59
|
+
u,
|
|
60
|
+
v,
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Unit normal of this planar mesh surface.
|
|
67
|
+
* The result is constant across the entire face group.
|
|
68
|
+
*/
|
|
69
|
+
normal(_u: number, _v: number): Vec3 {
|
|
70
|
+
return this.faceNormal;
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/NurbsCurve.ts
CHANGED
|
@@ -4,9 +4,10 @@ import { Vec3 } from "./Vec3.js";
|
|
|
4
4
|
import { Plane } from "./Plane.js";
|
|
5
5
|
import { Mesh } from "./Mesh.js";
|
|
6
6
|
import { Polyline } from "./Polyline.js";
|
|
7
|
+
import { PolyCurve } from "./PolyCurve.js";
|
|
7
8
|
import type { Line } from "./Line.js";
|
|
8
9
|
import type { Arc } from "./Arc.js";
|
|
9
|
-
import type { RotationAxis } from "./types.js";
|
|
10
|
+
import type { CurveOffsetOptions, RotationAxis } from "./types.js";
|
|
10
11
|
import * as wasm from "./wasm-bindings.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -160,12 +161,81 @@ export class NurbsCurve {
|
|
|
160
161
|
* @param distance - Offset distance
|
|
161
162
|
* @param normal - Reference normal for determining offset direction
|
|
162
163
|
* @param samples - Number of sample points (default 64)
|
|
164
|
+
* @param arcSamples - Number of samples per exact arc segment in the returned polyline(s)
|
|
165
|
+
* @param options - Offset options such as join style
|
|
163
166
|
* @returns Offset polyline approximation
|
|
164
167
|
*/
|
|
165
|
-
offset(
|
|
168
|
+
offset(
|
|
169
|
+
distance: number,
|
|
170
|
+
normal?: Vec3,
|
|
171
|
+
samples = 64,
|
|
172
|
+
arcSamples = 32,
|
|
173
|
+
options: CurveOffsetOptions = {},
|
|
174
|
+
): Polyline {
|
|
175
|
+
const results = this.offsetAll(distance, normal, samples, arcSamples, options);
|
|
176
|
+
if (results.length === 1) return results[0];
|
|
177
|
+
if (results.length === 0) {
|
|
178
|
+
throw new Error("NurbsCurve.offset() collapsed and produced no valid result polylines");
|
|
179
|
+
}
|
|
180
|
+
throw new Error(
|
|
181
|
+
`NurbsCurve.offset() produced ${results.length} result polylines. Use NurbsCurve.offsetAll() instead.`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Offset this curve by a distance and return every sampled result polyline.
|
|
187
|
+
* Note: NURBS offset is approximated by sampling and offsetting as polyline.
|
|
188
|
+
* @param distance - Offset distance
|
|
189
|
+
* @param normal - Reference normal for determining offset direction
|
|
190
|
+
* @param samples - Number of sample points used to approximate the source curve
|
|
191
|
+
* @param arcSamples - Number of samples per exact arc segment in the returned polylines
|
|
192
|
+
* @param options - Offset options such as join style
|
|
193
|
+
* @returns Every valid offset polyline approximation
|
|
194
|
+
*/
|
|
195
|
+
offsetAll(
|
|
196
|
+
distance: number,
|
|
197
|
+
normal?: Vec3,
|
|
198
|
+
samples = 64,
|
|
199
|
+
arcSamples = 32,
|
|
200
|
+
options: CurveOffsetOptions = {},
|
|
201
|
+
): Polyline[] {
|
|
166
202
|
const pts = this.sample(samples);
|
|
167
203
|
const pl = new Polyline(pts);
|
|
168
|
-
return pl.
|
|
204
|
+
return pl.offsetAll(distance, normal, arcSamples, options);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Thicken this curve into a closed PolyCurve.
|
|
209
|
+
* Note: this is approximated by sampling the NURBS curve into a polyline first.
|
|
210
|
+
*
|
|
211
|
+
* When `bothSides` is false, the sampled source curve forms one side of the
|
|
212
|
+
* result. When true, the distance is applied on each side of the sampled curve.
|
|
213
|
+
*/
|
|
214
|
+
thicken(
|
|
215
|
+
distance: number,
|
|
216
|
+
bothSides = false,
|
|
217
|
+
normal?: Vec3,
|
|
218
|
+
samples = 64,
|
|
219
|
+
options: CurveOffsetOptions = {},
|
|
220
|
+
): PolyCurve {
|
|
221
|
+
const pts = this.sample(samples);
|
|
222
|
+
return new Polyline(pts).thicken(distance, bothSides, normal, options);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Extrude this curve along a direction vector.
|
|
227
|
+
* Note: this is approximated by sampling the NURBS curve into a polyline
|
|
228
|
+
* first. Open curves produce an open sheet; closed curves an uncapped tube
|
|
229
|
+
* unless `caps` is true (see extrudeAsSolid for a boolean-ready solid).
|
|
230
|
+
* @param direction - Extrusion direction and magnitude
|
|
231
|
+
* @param segments - Number of segments along the extrusion (default 1)
|
|
232
|
+
* @param caps - Whether to cap the ends of a closed profile (default false)
|
|
233
|
+
* @param samples - Number of curve samples used for tessellation (default 64)
|
|
234
|
+
* @returns Mesh representing the extruded surface
|
|
235
|
+
*/
|
|
236
|
+
extrude(direction: Vec3, segments = 1, caps = false, samples = 64): Mesh {
|
|
237
|
+
const pts = this.sample(samples);
|
|
238
|
+
return new Polyline(pts).extrude(direction, segments, caps);
|
|
169
239
|
}
|
|
170
240
|
|
|
171
241
|
/**
|
|
@@ -178,6 +248,36 @@ export class NurbsCurve {
|
|
|
178
248
|
return Mesh.extrudeCurveAsSolid(this, direction, segments);
|
|
179
249
|
}
|
|
180
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Build a NURBS curve from raw control points with kernel-managed knots and
|
|
253
|
+
* uniform weights.
|
|
254
|
+
*
|
|
255
|
+
* Open curves use a clamped uniform knot vector (curve interpolates the first
|
|
256
|
+
* and last control points). Closed curves are periodic (C^{degree-1}
|
|
257
|
+
* continuous loops); the first control point must NOT be repeated at the end.
|
|
258
|
+
*
|
|
259
|
+
* @param degree - Requested degree (clamped by the kernel to the valid range)
|
|
260
|
+
* @param controlPoints - Control points (min 2 open / 3 closed)
|
|
261
|
+
* @param closed - Build a periodic closed loop (default false)
|
|
262
|
+
* @returns New NurbsCurve instance
|
|
263
|
+
*/
|
|
264
|
+
static fromPoints(degree: number, controlPoints: Point[], closed = false): NurbsCurve {
|
|
265
|
+
ensureInit();
|
|
266
|
+
const coords = new Float64Array(controlPoints.length * 3);
|
|
267
|
+
for (let i = 0; i < controlPoints.length; i++) {
|
|
268
|
+
coords[i * 3] = controlPoints[i].x;
|
|
269
|
+
coords[i * 3 + 1] = controlPoints[i].y;
|
|
270
|
+
coords[i * 3 + 2] = controlPoints[i].z;
|
|
271
|
+
}
|
|
272
|
+
const buf = wasm.build_nurbs_curve(degree, coords, closed);
|
|
273
|
+
if (buf.length < 2) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
`NurbsCurve.fromPoints failed (degree ${degree}, ${controlPoints.length} points, closed=${closed})`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
return NurbsCurve.fromData(buf);
|
|
279
|
+
}
|
|
280
|
+
|
|
181
281
|
/**
|
|
182
282
|
* Decode a NurbsCurve from WASM flat buffer.
|
|
183
283
|
* @param data - Buffer in format [degree, num_cp, xyz..., w..., k...]
|
package/src/NurbsSurface.ts
CHANGED
|
@@ -5,13 +5,18 @@ import { Plane } from "./Plane.js";
|
|
|
5
5
|
import { Mesh } from "./Mesh.js";
|
|
6
6
|
import { Polyline } from "./Polyline.js";
|
|
7
7
|
import { Polygon } from "./Polygon.js";
|
|
8
|
-
import { Line } from "./Line.js";
|
|
9
|
-
import { Arc } from "./Arc.js";
|
|
10
|
-
import { PolyCurve } from "./PolyCurve.js";
|
|
11
|
-
import { NurbsCurve } from "./NurbsCurve.js";
|
|
12
|
-
import type {
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
8
|
+
import { Line } from "./Line.js";
|
|
9
|
+
import { Arc } from "./Arc.js";
|
|
10
|
+
import { PolyCurve } from "./PolyCurve.js";
|
|
11
|
+
import { NurbsCurve } from "./NurbsCurve.js";
|
|
12
|
+
import type { Surface } from "./Surface.js";
|
|
13
|
+
import type { LoftableCurve, RotationAxis } from "./types.js";
|
|
14
|
+
import {
|
|
15
|
+
decodePointResult,
|
|
16
|
+
decodeVec3Result,
|
|
17
|
+
parsePolylineBuffer as parsePolylineBuf,
|
|
18
|
+
} from "./BufferCodec.js";
|
|
19
|
+
import * as wasm from "./wasm-bindings.js";
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* Non-Uniform Rational B-Spline (NURBS) surface backed by WASM.
|
|
@@ -19,7 +24,7 @@ import * as wasm from "./wasm-bindings.js";
|
|
|
19
24
|
*
|
|
20
25
|
* WASM data format: [degree_u, degree_v, num_u, num_v, ...cp(flat)..., ...weights..., ...knots_u..., ...knots_v...]
|
|
21
26
|
*/
|
|
22
|
-
export class NurbsSurface {
|
|
27
|
+
export class NurbsSurface implements Surface {
|
|
23
28
|
private _data: Float64Array;
|
|
24
29
|
|
|
25
30
|
/**
|
|
@@ -82,11 +87,21 @@ export class NurbsSurface {
|
|
|
82
87
|
* @param v - Parameter in V direction [0, 1]
|
|
83
88
|
* @returns Point on surface at (u, v)
|
|
84
89
|
*/
|
|
85
|
-
evaluate(u: number, v: number): Point {
|
|
86
|
-
ensureInit();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
evaluate(u: number, v: number): Point {
|
|
91
|
+
ensureInit();
|
|
92
|
+
return decodePointResult(wasm.nurbs_surface_evaluate(this._data, u, v));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Evaluate the unit normal on the surface at parameters (u, v).
|
|
97
|
+
* @param u - Parameter in U direction [0, 1]
|
|
98
|
+
* @param v - Parameter in V direction [0, 1]
|
|
99
|
+
* @returns Unit surface normal at (u, v)
|
|
100
|
+
*/
|
|
101
|
+
normal(u: number, v: number): Vec3 {
|
|
102
|
+
ensureInit();
|
|
103
|
+
return decodeVec3Result(wasm.nurbs_surface_normal(this._data, u, v));
|
|
104
|
+
}
|
|
90
105
|
|
|
91
106
|
/**
|
|
92
107
|
* Tessellate this surface into a triangle mesh.
|
package/src/PolyCurve.ts
CHANGED
|
@@ -6,15 +6,31 @@ import { Vec3 } from "./Vec3.js";
|
|
|
6
6
|
import { Mesh } from "./Mesh.js";
|
|
7
7
|
import { NurbsCurve } from "./NurbsCurve.js";
|
|
8
8
|
import type { Plane } from "./Plane.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
CurveOffsetJoinStyle,
|
|
11
|
+
CurveOffsetOptions,
|
|
12
|
+
CurveSegment,
|
|
13
|
+
RotationAxis,
|
|
14
|
+
} from "./types.js";
|
|
10
15
|
import { SegmentTypeCode } from "./types.js";
|
|
11
16
|
import { pointsToCoords } from "./BufferCodec.js";
|
|
12
17
|
import * as wasm from "./wasm-bindings.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
function offsetJoinStyleCode(style: CurveOffsetJoinStyle | undefined): number {
|
|
20
|
+
switch (style ?? "miter") {
|
|
21
|
+
case "round":
|
|
22
|
+
return 1;
|
|
23
|
+
case "bevel":
|
|
24
|
+
return 2;
|
|
25
|
+
default:
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Composite curve made of sequential Line and Arc segments.
|
|
32
|
+
*/
|
|
33
|
+
export class PolyCurve {
|
|
18
34
|
public readonly segments: CurveSegment[];
|
|
19
35
|
|
|
20
36
|
constructor(segments: CurveSegment[]) {
|
|
@@ -199,10 +215,10 @@ export class PolyCurve {
|
|
|
199
215
|
}
|
|
200
216
|
|
|
201
217
|
/** Decode a PolyCurve from WASM segment buffer [count, type, ...data, ...] */
|
|
202
|
-
static fromSegmentData(buf: Float64Array | number[]): PolyCurve {
|
|
203
|
-
const count = buf[0];
|
|
204
|
-
const segs: CurveSegment[] = [];
|
|
205
|
-
let idx = 1;
|
|
218
|
+
static fromSegmentData(buf: Float64Array | number[]): PolyCurve {
|
|
219
|
+
const count = buf[0];
|
|
220
|
+
const segs: CurveSegment[] = [];
|
|
221
|
+
let idx = 1;
|
|
206
222
|
for (let i = 0; i < count; i++) {
|
|
207
223
|
const type = buf[idx++];
|
|
208
224
|
if (type === SegmentTypeCode.Line) {
|
|
@@ -221,9 +237,32 @@ export class PolyCurve {
|
|
|
221
237
|
segs.push(new Arc(center, radius, startAngle, endAngle, normal));
|
|
222
238
|
idx += 9;
|
|
223
239
|
}
|
|
224
|
-
}
|
|
225
|
-
return new PolyCurve(segs);
|
|
226
|
-
}
|
|
240
|
+
}
|
|
241
|
+
return new PolyCurve(segs);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Decode multiple PolyCurves from WASM buffer [curveCount, curveLen, curveData..., ...] */
|
|
245
|
+
static fromSegmentDataSet(buf: Float64Array | number[]): PolyCurve[] {
|
|
246
|
+
const data = buf instanceof Float64Array ? buf : new Float64Array(buf);
|
|
247
|
+
const curveCount = Math.max(0, Math.floor(data[0] ?? 0));
|
|
248
|
+
const curves: PolyCurve[] = [];
|
|
249
|
+
let idx = 1;
|
|
250
|
+
|
|
251
|
+
for (let i = 0; i < curveCount; i++) {
|
|
252
|
+
const curveLen = Math.max(0, Math.floor(data[idx++] ?? -1));
|
|
253
|
+
if (curveLen <= 0 || idx + curveLen > data.length) {
|
|
254
|
+
throw new Error("PolyCurve.fromSegmentDataSet() received invalid curve set buffer");
|
|
255
|
+
}
|
|
256
|
+
curves.push(PolyCurve.fromSegmentData(data.slice(idx, idx + curveLen)));
|
|
257
|
+
idx += curveLen;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (idx !== data.length) {
|
|
261
|
+
throw new Error("PolyCurve.fromSegmentDataSet() received trailing buffer data");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return curves;
|
|
265
|
+
}
|
|
227
266
|
|
|
228
267
|
/**
|
|
229
268
|
* Chamfer corners of this PolyCurve by cutting each corner with a straight segment.
|
|
@@ -263,76 +302,109 @@ export class PolyCurve {
|
|
|
263
302
|
return PolyCurve.fromSegmentData(buf);
|
|
264
303
|
}
|
|
265
304
|
|
|
266
|
-
/**
|
|
267
|
-
* Offset this PolyCurve by a distance in the given plane.
|
|
268
|
-
*
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
305
|
+
/**
|
|
306
|
+
* Offset this PolyCurve by a distance in the given plane.
|
|
307
|
+
* Preserves exact line/arc segments where possible and applies the requested outside-corner join style.
|
|
308
|
+
* Defaults to `miter`.
|
|
309
|
+
*/
|
|
310
|
+
offset(distance: number, normal?: Vec3, options: CurveOffsetOptions = {}): PolyCurve {
|
|
311
|
+
const results = this.offsetAll(distance, normal, options);
|
|
312
|
+
if (results.length === 1) return results[0];
|
|
313
|
+
if (results.length === 0) {
|
|
314
|
+
throw new Error("PolyCurve.offset() collapsed and produced no valid result curves");
|
|
315
|
+
}
|
|
316
|
+
throw new Error(
|
|
317
|
+
`PolyCurve.offset() produced ${results.length} result curves. Use PolyCurve.offsetAll() instead.`,
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Offset this PolyCurve by a distance in the given plane and return every exact result curve.
|
|
323
|
+
* Defaults to `miter`.
|
|
324
|
+
*/
|
|
325
|
+
offsetAll(distance: number, normal?: Vec3, options: CurveOffsetOptions = {}): PolyCurve[] {
|
|
326
|
+
ensureInit();
|
|
327
|
+
if (this.segments.length < 1) {
|
|
328
|
+
throw new Error("PolyCurve.offsetAll() requires at least 1 segment");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const nx = normal?.x ?? 0, ny = normal?.y ?? 0, nz = normal?.z ?? 0;
|
|
332
|
+
const joinStyleCode = offsetJoinStyleCode(options.joinStyle);
|
|
333
|
+
const result = wasm.offset_polycurve_all(this.toSegmentData(), distance, nx, ny, nz, joinStyleCode);
|
|
334
|
+
if (result.length < 1) {
|
|
335
|
+
throw new Error("PolyCurve.offsetAll() failed - WASM returned empty result");
|
|
336
|
+
}
|
|
337
|
+
return PolyCurve.fromSegmentDataSet(result);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Thicken this open PolyCurve into a single closed loop.
|
|
342
|
+
* When `bothSides` is false, the source curve forms one side and the offset
|
|
343
|
+
* curve forms the other. When true, the distance is applied on each side of
|
|
344
|
+
* the source curve, doubling the overall width.
|
|
345
|
+
*
|
|
346
|
+
* For line-like inputs where the plane is ambiguous, provide `normal`.
|
|
347
|
+
*/
|
|
348
|
+
thicken(
|
|
349
|
+
distance: number,
|
|
350
|
+
bothSides = false,
|
|
351
|
+
normal?: Vec3,
|
|
352
|
+
options: CurveOffsetOptions = {},
|
|
353
|
+
): PolyCurve {
|
|
354
|
+
ensureInit();
|
|
355
|
+
if (this.segments.length < 1) {
|
|
356
|
+
throw new Error("PolyCurve.thicken() requires at least 1 segment");
|
|
357
|
+
}
|
|
358
|
+
if (!Number.isFinite(distance) || distance <= 0) {
|
|
359
|
+
throw new Error("PolyCurve.thicken() requires a positive distance");
|
|
360
|
+
}
|
|
361
|
+
if (this.isClosed()) {
|
|
362
|
+
throw new Error("PolyCurve.thicken() requires an open curve");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const nx = normal?.x ?? 0, ny = normal?.y ?? 0, nz = normal?.z ?? 0;
|
|
366
|
+
const joinStyleCode = offsetJoinStyleCode(options.joinStyle);
|
|
367
|
+
const result = wasm.thicken_polycurve(
|
|
368
|
+
this.toSegmentData(),
|
|
369
|
+
distance,
|
|
370
|
+
bothSides,
|
|
371
|
+
nx,
|
|
372
|
+
ny,
|
|
373
|
+
nz,
|
|
374
|
+
joinStyleCode,
|
|
375
|
+
);
|
|
376
|
+
if (result.length < 1) {
|
|
377
|
+
throw new Error("PolyCurve.thicken() failed - WASM returned empty result");
|
|
378
|
+
}
|
|
379
|
+
return PolyCurve.fromSegmentData(result);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Convert to an exact NURBS curve representation via WASM.
|
|
384
|
+
* Lines become degree-1 NURBS, Arcs become degree-2 rational NURBS.
|
|
385
|
+
* All segments are degree-elevated to a common degree and joined.
|
|
317
386
|
*/
|
|
318
|
-
toNurbs(): NurbsCurve {
|
|
319
|
-
ensureInit();
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
segData.push(
|
|
330
|
-
segData.push(seg.
|
|
331
|
-
segData.push(seg.
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
387
|
+
toNurbs(): NurbsCurve {
|
|
388
|
+
ensureInit();
|
|
389
|
+
const buf = wasm.polycurve_to_nurbs(this.toSegmentData());
|
|
390
|
+
if (buf.length < 2) throw new Error("Failed to convert PolyCurve to NURBS");
|
|
391
|
+
return NurbsCurve.fromData(buf);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private toSegmentData(): Float64Array {
|
|
395
|
+
const segData: number[] = [this.segments.length];
|
|
396
|
+
for (const seg of this.segments) {
|
|
397
|
+
if (seg instanceof Line) {
|
|
398
|
+
segData.push(SegmentTypeCode.Line);
|
|
399
|
+
segData.push(seg.start.x, seg.start.y, seg.start.z);
|
|
400
|
+
segData.push(seg.end.x, seg.end.y, seg.end.z);
|
|
401
|
+
} else {
|
|
402
|
+
segData.push(SegmentTypeCode.Arc);
|
|
403
|
+
segData.push(seg.center.x, seg.center.y, seg.center.z);
|
|
404
|
+
segData.push(seg.normal.x, seg.normal.y, seg.normal.z);
|
|
405
|
+
segData.push(seg.radius, seg.startAngle, seg.endAngle);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return new Float64Array(segData);
|
|
409
|
+
}
|
|
410
|
+
}
|
package/src/Polygon.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Point } from "./Point.js";
|
|
|
2
2
|
import { Vec3 } from "./Vec3.js";
|
|
3
3
|
import { Polyline } from "./Polyline.js";
|
|
4
4
|
import type { Plane } from "./Plane.js";
|
|
5
|
-
import type { RotationAxis } from "./types.js";
|
|
5
|
+
import type { CurveOffsetOptions, RotationAxis } from "./types.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A closed polygon defined by vertices.
|
|
@@ -55,11 +55,41 @@ export class Polygon extends Polyline {
|
|
|
55
55
|
* Offset this polygon perpendicular to its edges.
|
|
56
56
|
* @param distance - Offset distance
|
|
57
57
|
* @param normal - Reference normal for determining offset direction
|
|
58
|
+
* @param arcSamples - Number of samples per arc join in the returned polygon(s)
|
|
59
|
+
* @param options - Offset options such as join style
|
|
58
60
|
* @returns New offset polygon
|
|
59
61
|
*/
|
|
60
|
-
override offset(
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
override offset(
|
|
63
|
+
distance: number,
|
|
64
|
+
normal?: Vec3,
|
|
65
|
+
arcSamples = 32,
|
|
66
|
+
options: CurveOffsetOptions = {},
|
|
67
|
+
): Polygon {
|
|
68
|
+
const results = this.offsetAll(distance, normal, arcSamples, options);
|
|
69
|
+
if (results.length === 1) return results[0];
|
|
70
|
+
if (results.length === 0) {
|
|
71
|
+
throw new Error("Polygon.offset() collapsed and produced no valid result polygons");
|
|
72
|
+
}
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Polygon.offset() produced ${results.length} result polygons. Use Polygon.offsetAll() instead.`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Offset this polygon and return every sampled result polygon.
|
|
80
|
+
* @param distance - Offset distance
|
|
81
|
+
* @param normal - Reference normal for determining offset direction
|
|
82
|
+
* @param arcSamples - Number of samples per exact arc segment in the returned polygons
|
|
83
|
+
* @param options - Offset options such as join style
|
|
84
|
+
* @returns Every valid offset polygon
|
|
85
|
+
*/
|
|
86
|
+
offsetAll(
|
|
87
|
+
distance: number,
|
|
88
|
+
normal?: Vec3,
|
|
89
|
+
arcSamples = 32,
|
|
90
|
+
options: CurveOffsetOptions = {},
|
|
91
|
+
): Polygon[] {
|
|
92
|
+
return super.offsetAll(distance, normal, arcSamples, options).map(polyline => new Polygon(polyline.points));
|
|
63
93
|
}
|
|
64
94
|
|
|
65
95
|
/**
|