okgeometry-api 1.2.0 → 1.2.1
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 +82 -9
- package/dist/Mesh.d.ts.map +1 -1
- package/dist/Mesh.js +329 -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 +24 -2
- package/dist/NurbsCurve.d.ts.map +1 -1
- package/dist/NurbsCurve.js +34 -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 +65 -2
- package/dist/wasm-bindings.d.ts.map +1 -1
- package/dist/wasm-bindings.js +100 -2
- package/dist/wasm-bindings.js.map +1 -1
- package/package.json +1 -1
- package/src/Line.ts +38 -20
- package/src/Mesh.ts +538 -184
- package/src/MeshSurface.ts +72 -0
- package/src/NurbsCurve.ts +80 -26
- 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 +43 -2
- package/src/wasm-bindings.js +105 -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
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ensureInit } from "./engine.js";
|
|
2
2
|
import { Point } from "./Point.js";
|
|
3
|
-
import { Vec3 } from "./Vec3.js";
|
|
4
|
-
import { Plane } from "./Plane.js";
|
|
5
|
-
import { Mesh } from "./Mesh.js";
|
|
6
|
-
import { Polyline } from "./Polyline.js";
|
|
7
|
-
import
|
|
8
|
-
import type {
|
|
9
|
-
import type {
|
|
10
|
-
import
|
|
3
|
+
import { Vec3 } from "./Vec3.js";
|
|
4
|
+
import { Plane } from "./Plane.js";
|
|
5
|
+
import { Mesh } from "./Mesh.js";
|
|
6
|
+
import { Polyline } from "./Polyline.js";
|
|
7
|
+
import { PolyCurve } from "./PolyCurve.js";
|
|
8
|
+
import type { Line } from "./Line.js";
|
|
9
|
+
import type { Arc } from "./Arc.js";
|
|
10
|
+
import type { CurveOffsetOptions, RotationAxis } from "./types.js";
|
|
11
|
+
import * as wasm from "./wasm-bindings.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Non-Uniform Rational B-Spline (NURBS) curve backed by WASM.
|
|
@@ -154,24 +155,77 @@ export class NurbsCurve {
|
|
|
154
155
|
);
|
|
155
156
|
}
|
|
156
157
|
|
|
157
|
-
/**
|
|
158
|
-
* Offset this curve by a distance.
|
|
159
|
-
* Note: NURBS offset is approximated by sampling and offsetting as polyline.
|
|
160
|
-
* @param distance - Offset distance
|
|
161
|
-
* @param normal - Reference normal for determining offset direction
|
|
162
|
-
* @param samples - Number of sample points (default 64)
|
|
163
|
-
* @
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Offset this curve by a distance.
|
|
160
|
+
* Note: NURBS offset is approximated by sampling and offsetting as polyline.
|
|
161
|
+
* @param distance - Offset distance
|
|
162
|
+
* @param normal - Reference normal for determining offset direction
|
|
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
|
|
166
|
+
* @returns Offset polyline approximation
|
|
167
|
+
*/
|
|
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[] {
|
|
202
|
+
const pts = this.sample(samples);
|
|
203
|
+
const pl = new Polyline(pts);
|
|
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 closed NURBS curve into a trusted solid suitable for booleans.
|
|
227
|
+
* @param direction - Extrusion direction and magnitude
|
|
228
|
+
* @param segments - Number of curve samples used for tessellation (default 64)
|
|
175
229
|
* @returns Closed mesh solid ready for boolean operations
|
|
176
230
|
*/
|
|
177
231
|
extrudeAsSolid(direction: Vec3, segments = 64): Mesh {
|
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
|
/**
|