okgeometry-api 1.14.0 → 1.16.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/src/Polyline.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { ensureInit } from "./engine.js";
2
2
  import { Point } from "./Point.js";
3
3
  import { Vec3 } from "./Vec3.js";
4
- import { Mesh } from "./Mesh.js";
5
- import { Line } from "./Line.js";
6
- import { PolyCurve } from "./PolyCurve.js";
7
- import type { Plane } from "./Plane.js";
8
- import type { CurveOffsetOptions, RotationAxis } from "./types.js";
9
- import { pointsToCoords } from "./BufferCodec.js";
10
- import * as wasm from "./wasm-bindings.js";
4
+ import { Mesh } from "./Mesh.js";
5
+ import { Line } from "./Line.js";
6
+ import { PolyCurve } from "./PolyCurve.js";
7
+ import type { Plane } from "./Plane.js";
8
+ import type { CurveOffsetOptions, RotationAxis } from "./types.js";
9
+ import { pointsToCoords } from "./BufferCodec.js";
10
+ import * as wasm from "./wasm-bindings.js";
11
11
 
12
12
  /**
13
13
  * Open or closed polyline defined by a sequence of points.
@@ -50,6 +50,56 @@ export class Polyline {
50
50
  return this.points[0].equals(this.points[this.points.length - 1], eps);
51
51
  }
52
52
 
53
+ /**
54
+ * Compute all transversal crossing points of this polyline with a triangle
55
+ * mesh. Works on OPEN meshes (sheets) — the mesh is not required to be a
56
+ * closed volume. Hits are deduplicated and sorted along the polyline;
57
+ * coplanar sliding overlaps yield no hits.
58
+ *
59
+ * @param mesh - Mesh to intersect with (open or closed)
60
+ * @returns Crossings with the 3D point, segment index/parameter in [0, 1],
61
+ * and triangle index
62
+ */
63
+ intersectMesh(
64
+ mesh: Mesh,
65
+ ): { point: Point; segmentIndex: number; segmentT: number; triangleIndex: number }[] {
66
+ return mesh.intersectPolyline(this);
67
+ }
68
+
69
+ /**
70
+ * Split this polyline into pieces at every crossing with a mesh (open
71
+ * sheets allowed). Crossing points become the shared endpoints of adjacent
72
+ * pieces; a closed loop is opened at the first crossing (N crossings → N
73
+ * pieces), an open polyline yields N + 1 pieces. With no crossings the
74
+ * original polyline comes back as one piece. Pieces are NOT classified —
75
+ * see `clipBySheet` / `Mesh.clipPolyline` for classification.
76
+ *
77
+ * @param mesh - Mesh to split against (open or closed)
78
+ * @returns Polyline pieces in order along this polyline
79
+ */
80
+ splitByMesh(mesh: Mesh): Polyline[] {
81
+ return mesh.splitPolyline(this);
82
+ }
83
+
84
+ /**
85
+ * Clip this polyline by an OPEN oriented sheet: split it at every sheet
86
+ * crossing and classify each piece by the SIGNED SIDE of the sheet —
87
+ * `inside` = in FRONT of the sheet normal, `outside` = behind it (the
88
+ * sheet's stored winding defines the normals).
89
+ *
90
+ * This is side classification, NOT containment — unlike
91
+ * `Mesh.clipPolyline`, which requires a CLOSED volume: the sheet may be
92
+ * open, and pieces far from it still classify deterministically by the
93
+ * nearest facet's normal. Adjacent same-side pieces (a touch, not a
94
+ * crossing) merge back into one run; closed loops merge the run spanning
95
+ * the seam.
96
+ *
97
+ * @param sheet - Oriented sheet mesh (open or closed)
98
+ */
99
+ clipBySheet(sheet: Mesh): { inside: Polyline[]; outside: Polyline[] } {
100
+ return sheet.clipPolylineBySheet(this);
101
+ }
102
+
53
103
  /**
54
104
  * Extrude this polyline along a direction vector.
55
105
  * @param direction - Extrusion direction and magnitude
@@ -57,28 +107,28 @@ export class Polyline {
57
107
  * @param caps - Whether to cap the ends (default false)
58
108
  * @returns Mesh representing the extruded surface
59
109
  */
60
- extrude(direction: Vec3, segments = 1, caps = false): Mesh {
61
- ensureInit();
62
- const buf = wasm.extrude_polyline(
63
- this.toCoords(),
64
- direction.x, direction.y, direction.z,
110
+ extrude(direction: Vec3, segments = 1, caps = false): Mesh {
111
+ ensureInit();
112
+ const buf = wasm.extrude_polyline(
113
+ this.toCoords(),
114
+ direction.x, direction.y, direction.z,
65
115
  segments, caps
66
- );
67
- return Mesh.fromBuffer(buf);
68
- }
69
-
70
- /**
71
- * Extrude this closed polyline into a trusted solid suitable for booleans.
72
- * @param direction - Extrusion direction and magnitude
73
- * @returns Closed mesh solid ready for boolean operations
74
- */
75
- extrudeAsSolid(direction: Vec3): Mesh {
76
- return Mesh.extrudeCurveAsSolid(this, direction);
77
- }
78
-
79
- /**
80
- * Translate this polyline by an offset vector.
81
- * @param offset - Translation vector
116
+ );
117
+ return Mesh.fromBuffer(buf);
118
+ }
119
+
120
+ /**
121
+ * Extrude this closed polyline into a trusted solid suitable for booleans.
122
+ * @param direction - Extrusion direction and magnitude
123
+ * @returns Closed mesh solid ready for boolean operations
124
+ */
125
+ extrudeAsSolid(direction: Vec3): Mesh {
126
+ return Mesh.extrudeCurveAsSolid(this, direction);
127
+ }
128
+
129
+ /**
130
+ * Translate this polyline by an offset vector.
131
+ * @param offset - Translation vector
82
132
  * @returns New translated polyline
83
133
  */
84
134
  translate(offset: Vec3): Polyline {
@@ -95,73 +145,73 @@ export class Polyline {
95
145
  return new Polyline(this.points.map(p => p.rotate(axis, angle)));
96
146
  }
97
147
 
98
- /**
99
- * Offset this polyline perpendicular to its segments.
100
- * @param distance - Offset distance
101
- * @param normal - Reference normal for determining offset direction
102
- * @param arcSamples - Number of samples per arc join in the returned polyline(s)
103
- * @param options - Offset options such as join style
104
- * @returns New offset polyline
105
- */
106
- offset(
107
- distance: number,
108
- normal?: Vec3,
109
- arcSamples = 32,
110
- options: CurveOffsetOptions = {},
111
- ): Polyline {
112
- const results = this.offsetAll(distance, normal, arcSamples, options);
113
- if (results.length === 1) return results[0];
114
- if (results.length === 0) {
115
- throw new Error("Polyline.offset() collapsed and produced no valid result polylines");
116
- }
117
- throw new Error(
118
- `Polyline.offset() produced ${results.length} result polylines. Use Polyline.offsetAll() instead.`,
119
- );
120
- }
121
-
122
- /**
123
- * Offset this polyline and return every sampled result polyline.
124
- * @param distance - Offset distance
125
- * @param normal - Reference normal for determining offset direction
126
- * @param arcSamples - Number of samples per exact arc segment in the returned polylines
127
- * @param options - Offset options such as join style
128
- * @returns Every valid offset polyline
129
- */
130
- offsetAll(
131
- distance: number,
132
- normal?: Vec3,
133
- arcSamples = 32,
134
- options: CurveOffsetOptions = {},
135
- ): Polyline[] {
136
- const exact = this.toPolyCurve().offsetAll(distance, normal, options);
137
- const samples = Number.isFinite(arcSamples) ? Math.max(3, Math.floor(arcSamples)) : 32;
138
- return exact.map(curve => new Polyline(curve.sample(samples)));
139
- }
140
-
141
- /**
142
- * Thicken this open polyline into a closed PolyCurve suitable for extrusion.
143
- * When `bothSides` is false, the source polyline forms one side of the result.
144
- * When true, the thickness is added on each side of the source polyline.
145
- */
146
- thicken(
147
- distance: number,
148
- bothSides = false,
149
- normal?: Vec3,
150
- options: CurveOffsetOptions = {},
151
- ): PolyCurve {
152
- if (this.points.length < 2) {
153
- throw new Error("Polyline.thicken() requires at least 2 points");
154
- }
155
- if (this.isClosed()) {
156
- throw new Error("Polyline.thicken() requires an open polyline");
157
- }
158
- return this.toPolyCurve().thicken(distance, bothSides, normal, options);
159
- }
160
-
161
- /**
162
- * Project this polyline onto a plane.
163
- * @param plane - Target plane
164
- * @param direction - Optional projection direction (default: perpendicular to plane)
148
+ /**
149
+ * Offset this polyline perpendicular to its segments.
150
+ * @param distance - Offset distance
151
+ * @param normal - Reference normal for determining offset direction
152
+ * @param arcSamples - Number of samples per arc join in the returned polyline(s)
153
+ * @param options - Offset options such as join style
154
+ * @returns New offset polyline
155
+ */
156
+ offset(
157
+ distance: number,
158
+ normal?: Vec3,
159
+ arcSamples = 32,
160
+ options: CurveOffsetOptions = {},
161
+ ): Polyline {
162
+ const results = this.offsetAll(distance, normal, arcSamples, options);
163
+ if (results.length === 1) return results[0];
164
+ if (results.length === 0) {
165
+ throw new Error("Polyline.offset() collapsed and produced no valid result polylines");
166
+ }
167
+ throw new Error(
168
+ `Polyline.offset() produced ${results.length} result polylines. Use Polyline.offsetAll() instead.`,
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Offset this polyline and return every sampled result polyline.
174
+ * @param distance - Offset distance
175
+ * @param normal - Reference normal for determining offset direction
176
+ * @param arcSamples - Number of samples per exact arc segment in the returned polylines
177
+ * @param options - Offset options such as join style
178
+ * @returns Every valid offset polyline
179
+ */
180
+ offsetAll(
181
+ distance: number,
182
+ normal?: Vec3,
183
+ arcSamples = 32,
184
+ options: CurveOffsetOptions = {},
185
+ ): Polyline[] {
186
+ const exact = this.toPolyCurve().offsetAll(distance, normal, options);
187
+ const samples = Number.isFinite(arcSamples) ? Math.max(3, Math.floor(arcSamples)) : 32;
188
+ return exact.map(curve => new Polyline(curve.sample(samples)));
189
+ }
190
+
191
+ /**
192
+ * Thicken this open polyline into a closed PolyCurve suitable for extrusion.
193
+ * When `bothSides` is false, the source polyline forms one side of the result.
194
+ * When true, the thickness is added on each side of the source polyline.
195
+ */
196
+ thicken(
197
+ distance: number,
198
+ bothSides = false,
199
+ normal?: Vec3,
200
+ options: CurveOffsetOptions = {},
201
+ ): PolyCurve {
202
+ if (this.points.length < 2) {
203
+ throw new Error("Polyline.thicken() requires at least 2 points");
204
+ }
205
+ if (this.isClosed()) {
206
+ throw new Error("Polyline.thicken() requires an open polyline");
207
+ }
208
+ return this.toPolyCurve().thicken(distance, bothSides, normal, options);
209
+ }
210
+
211
+ /**
212
+ * Project this polyline onto a plane.
213
+ * @param plane - Target plane
214
+ * @param direction - Optional projection direction (default: perpendicular to plane)
165
215
  * @returns New projected polyline
166
216
  */
167
217
  projectOntoPlane(plane: Plane, direction?: Vec3): Polyline {