okgeometry-api 1.22.0 → 1.24.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/Brep.d.ts +11 -0
- package/dist/Brep.d.ts.map +1 -1
- package/dist/Brep.js +21 -0
- package/dist/Brep.js.map +1 -1
- package/dist/Line.d.ts +6 -0
- package/dist/Line.d.ts.map +1 -1
- package/dist/Line.js +8 -0
- package/dist/Line.js.map +1 -1
- package/dist/NurbsCurve.d.ts +8 -0
- package/dist/NurbsCurve.d.ts.map +1 -1
- package/dist/NurbsCurve.js +10 -0
- package/dist/NurbsCurve.js.map +1 -1
- package/dist/NurbsSurface.d.ts +8 -0
- package/dist/NurbsSurface.d.ts.map +1 -1
- package/dist/NurbsSurface.js +11 -0
- package/dist/NurbsSurface.js.map +1 -1
- package/dist/Point.d.ts +7 -0
- package/dist/Point.d.ts.map +1 -1
- package/dist/Point.js +12 -0
- package/dist/Point.js.map +1 -1
- package/dist/Polyline.d.ts +6 -0
- package/dist/Polyline.d.ts.map +1 -1
- package/dist/Polyline.js +8 -0
- package/dist/Polyline.js.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 +13 -0
- package/dist/wasm-bindings.d.ts.map +1 -1
- package/dist/wasm-bindings.js +20 -0
- package/dist/wasm-bindings.js.map +1 -1
- package/package.json +60 -60
- package/src/Brep.ts +24 -0
- package/src/Line.ts +47 -38
- package/src/NurbsCurve.ts +16 -0
- package/src/NurbsSurface.ts +19 -0
- package/src/Point.ts +161 -145
- package/src/Polyline.ts +9 -0
- package/src/wasm-base64.ts +1 -1
- package/src/wasm-bindings.d.ts +11 -0
- package/src/wasm-bindings.js +21 -0
package/package.json
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "okgeometry-api",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Geometry engine API for AEC applications - NURBS, meshes, booleans, intersections. Powered by Rust/WASM.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./dist/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist/",
|
|
16
|
-
"src/"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build:wasm": "node -e \"require('fs').rmSync('wasm',{recursive:true,force:true})\" && cd .. && wasm-pack build --target web --out-dir okgeometry-api/wasm",
|
|
20
|
-
"sync:wasm-bindings": "node scripts/sync-wasm-bindings.mjs",
|
|
21
|
-
"inline-wasm": "tsx scripts/inline-wasm.ts",
|
|
22
|
-
"build": "npm run build:wasm && npm run sync:wasm-bindings && npm run inline-wasm && tsc",
|
|
23
|
-
"bench:boolean-heavy": "npm run build && tsx scripts/bench-boolean-heavy.ts",
|
|
24
|
-
"bench:boolean-ab": "npm run build && tsx scripts/bench-boolean-ab.ts",
|
|
25
|
-
"bench:boolean-batch": "npm run build && tsx scripts/bench-boolean-batch.ts",
|
|
26
|
-
"bench:boolean-matrix": "tsx scripts/bench-boolean-matrix.ts",
|
|
27
|
-
"smoke:brep-boolean": "tsx scripts/smoke-brep-boolean.ts",
|
|
28
|
-
"prepublishOnly": "npm run build",
|
|
29
|
-
"smoke:brep-parametric": "tsx scripts/smoke-brep-parametric.ts",
|
|
30
|
-
"smoke:brep-from-mesh": "tsx scripts/smoke-brep-from-mesh.ts",
|
|
31
|
-
"smoke:brep-faces": "tsx scripts/smoke-brep-faces.ts",
|
|
32
|
-
"smoke:curve-intersections": "tsx scripts/smoke-curve-intersections.ts",
|
|
33
|
-
"smoke:brep-intersections": "tsx scripts/smoke-brep-intersections.ts",
|
|
34
|
-
"smoke:brep-sheet-boolean": "tsx scripts/smoke-brep-sheet-boolean.ts",
|
|
35
|
-
"smoke:geometry-boolean": "tsx scripts/smoke-geometry-boolean.ts",
|
|
36
|
-
"smoke:curve-region": "tsx scripts/smoke-curve-region.ts",
|
|
37
|
-
"smoke:sculpt": "tsx scripts/smoke-sculpt.ts",
|
|
38
|
-
"smoke:offset-chamfer": "tsx scripts/smoke-offset-chamfer.ts"
|
|
39
|
-
},
|
|
40
|
-
"keywords": [
|
|
41
|
-
"geometry",
|
|
42
|
-
"wasm",
|
|
43
|
-
"nurbs",
|
|
44
|
-
"mesh",
|
|
45
|
-
"boolean",
|
|
46
|
-
"cad",
|
|
47
|
-
"aec",
|
|
48
|
-
"3d"
|
|
49
|
-
],
|
|
50
|
-
"author": "Mostafa El Ayoubi",
|
|
51
|
-
"license": "Proprietary License",
|
|
52
|
-
"repository": {
|
|
53
|
-
"type": "git",
|
|
54
|
-
"url": "https://www.orkestra.online"
|
|
55
|
-
},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"tsx": "^4.7.0",
|
|
58
|
-
"typescript": "^5.4.0"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "okgeometry-api",
|
|
3
|
+
"version": "1.24.0",
|
|
4
|
+
"description": "Geometry engine API for AEC applications - NURBS, meshes, booleans, intersections. Powered by Rust/WASM.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/",
|
|
16
|
+
"src/"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build:wasm": "node -e \"require('fs').rmSync('wasm',{recursive:true,force:true})\" && cd .. && wasm-pack build --target web --out-dir okgeometry-api/wasm",
|
|
20
|
+
"sync:wasm-bindings": "node scripts/sync-wasm-bindings.mjs",
|
|
21
|
+
"inline-wasm": "tsx scripts/inline-wasm.ts",
|
|
22
|
+
"build": "npm run build:wasm && npm run sync:wasm-bindings && npm run inline-wasm && tsc",
|
|
23
|
+
"bench:boolean-heavy": "npm run build && tsx scripts/bench-boolean-heavy.ts",
|
|
24
|
+
"bench:boolean-ab": "npm run build && tsx scripts/bench-boolean-ab.ts",
|
|
25
|
+
"bench:boolean-batch": "npm run build && tsx scripts/bench-boolean-batch.ts",
|
|
26
|
+
"bench:boolean-matrix": "tsx scripts/bench-boolean-matrix.ts",
|
|
27
|
+
"smoke:brep-boolean": "tsx scripts/smoke-brep-boolean.ts",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"smoke:brep-parametric": "tsx scripts/smoke-brep-parametric.ts",
|
|
30
|
+
"smoke:brep-from-mesh": "tsx scripts/smoke-brep-from-mesh.ts",
|
|
31
|
+
"smoke:brep-faces": "tsx scripts/smoke-brep-faces.ts",
|
|
32
|
+
"smoke:curve-intersections": "tsx scripts/smoke-curve-intersections.ts",
|
|
33
|
+
"smoke:brep-intersections": "tsx scripts/smoke-brep-intersections.ts",
|
|
34
|
+
"smoke:brep-sheet-boolean": "tsx scripts/smoke-brep-sheet-boolean.ts",
|
|
35
|
+
"smoke:geometry-boolean": "tsx scripts/smoke-geometry-boolean.ts",
|
|
36
|
+
"smoke:curve-region": "tsx scripts/smoke-curve-region.ts",
|
|
37
|
+
"smoke:sculpt": "tsx scripts/smoke-sculpt.ts",
|
|
38
|
+
"smoke:offset-chamfer": "tsx scripts/smoke-offset-chamfer.ts"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"geometry",
|
|
42
|
+
"wasm",
|
|
43
|
+
"nurbs",
|
|
44
|
+
"mesh",
|
|
45
|
+
"boolean",
|
|
46
|
+
"cad",
|
|
47
|
+
"aec",
|
|
48
|
+
"3d"
|
|
49
|
+
],
|
|
50
|
+
"author": "Mostafa El Ayoubi",
|
|
51
|
+
"license": "Proprietary License",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "https://www.orkestra.online"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"tsx": "^4.7.0",
|
|
58
|
+
"typescript": "^5.4.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/Brep.ts
CHANGED
|
@@ -485,6 +485,30 @@ export class Brep {
|
|
|
485
485
|
);
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Wireframe of the whole BREP in ONE WASM crossing: per face, `uCount`
|
|
490
|
+
* curves running along u plus `vCount` along v, at evenly spaced INTERIOR
|
|
491
|
+
* normalized parameters (i+1)/(count+1), each clipped to that face's
|
|
492
|
+
* trimmed region. The body JSON is parsed once for the entire sweep, so
|
|
493
|
+
* this scales to large face counts where per-face
|
|
494
|
+
* {@link faceIsoCurvesTrimmedNormalized} calls would re-parse the body
|
|
495
|
+
* repeatedly. Boundary parameters are excluded (they coincide with the
|
|
496
|
+
* BREP's edges); faces that fail to evaluate are skipped atomically.
|
|
497
|
+
*/
|
|
498
|
+
wireframeCurves(uCount: number, vCount: number): NurbsCurve[] {
|
|
499
|
+
ensureInit();
|
|
500
|
+
const buf = wasm.brep_wireframe_curves(this.json, uCount, vCount);
|
|
501
|
+
// An empty buffer (not even a zero count header) means the call failed
|
|
502
|
+
// outright, e.g. unparseable JSON — surface the reason instead of
|
|
503
|
+
// pretending the wireframe is empty.
|
|
504
|
+
if (buf.length < 1) {
|
|
505
|
+
throw new Error(
|
|
506
|
+
`Brep.wireframeCurves() failed: ${wasm.geometry_last_error() || "unknown error"}`,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
return Brep.parseCurveList(buf);
|
|
510
|
+
}
|
|
511
|
+
|
|
488
512
|
/** Parse [count, (bufLen, curveData…)·count] into NurbsCurves. */
|
|
489
513
|
private static parseCurveList(buf: Float64Array): NurbsCurve[] {
|
|
490
514
|
if (buf.length < 1) return [];
|
package/src/Line.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { ensureInit } from "./engine.js";
|
|
2
|
-
import { Point } from "./Point.js";
|
|
3
|
-
import { Vec3 } from "./Vec3.js";
|
|
4
|
-
import { Mesh } from "./Mesh.js";
|
|
5
|
-
import { PolyCurve } from "./PolyCurve.js";
|
|
6
|
-
import { Polyline } from "./Polyline.js";
|
|
7
|
-
import type { Plane } from "./Plane.js";
|
|
8
|
-
import type { CurveOffsetOptions, RotationAxis } from "./types.js";
|
|
9
|
-
import * as wasm from "./wasm-bindings.js";
|
|
1
|
+
import { ensureInit } from "./engine.js";
|
|
2
|
+
import { Point } from "./Point.js";
|
|
3
|
+
import { Vec3 } from "./Vec3.js";
|
|
4
|
+
import { Mesh } from "./Mesh.js";
|
|
5
|
+
import { PolyCurve } from "./PolyCurve.js";
|
|
6
|
+
import { Polyline } from "./Polyline.js";
|
|
7
|
+
import type { Plane } from "./Plane.js";
|
|
8
|
+
import type { CurveOffsetOptions, RotationAxis } from "./types.js";
|
|
9
|
+
import * as wasm from "./wasm-bindings.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Immutable line segment defined by start and end points.
|
|
@@ -86,6 +86,15 @@ export class Line {
|
|
|
86
86
|
return new Line(this.start.add(offset), this.end.add(offset));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Apply a row-major 4x4 matrix to both endpoints.
|
|
91
|
+
* @param matrix - Row-major 4x4 matrix (16 entries)
|
|
92
|
+
* @returns New transformed line
|
|
93
|
+
*/
|
|
94
|
+
applyMatrix(matrix: number[] | Float64Array): Line {
|
|
95
|
+
return new Line(this.start.applyMatrix(matrix), this.end.applyMatrix(matrix));
|
|
96
|
+
}
|
|
97
|
+
|
|
89
98
|
/**
|
|
90
99
|
* Rotate this line around an axis.
|
|
91
100
|
* @param axis - Rotation axis (Vec3 through origin, or Line for arbitrary axis)
|
|
@@ -102,40 +111,40 @@ export class Line {
|
|
|
102
111
|
* @param normal - Reference normal for determining offset direction (default Z axis)
|
|
103
112
|
* @returns New offset line
|
|
104
113
|
*/
|
|
105
|
-
offset(distance: number, normal: Vec3 = Vec3.Z): Line {
|
|
106
|
-
ensureInit();
|
|
107
|
-
const r = wasm.line_offset(
|
|
108
|
-
this.start.x, this.start.y, this.start.z,
|
|
109
|
-
this.end.x, this.end.y, this.end.z,
|
|
114
|
+
offset(distance: number, normal: Vec3 = Vec3.Z): Line {
|
|
115
|
+
ensureInit();
|
|
116
|
+
const r = wasm.line_offset(
|
|
117
|
+
this.start.x, this.start.y, this.start.z,
|
|
118
|
+
this.end.x, this.end.y, this.end.z,
|
|
110
119
|
distance,
|
|
111
120
|
normal.x, normal.y, normal.z,
|
|
112
121
|
);
|
|
113
122
|
return new Line(
|
|
114
123
|
new Point(r[0], r[1], r[2]),
|
|
115
|
-
new Point(r[3], r[4], r[5]),
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Thicken this line into a closed PolyCurve suitable for extrusion.
|
|
121
|
-
* When `bothSides` is false, the source line forms one side of the result.
|
|
122
|
-
* When true, the thickness is added on each side of the line.
|
|
123
|
-
*
|
|
124
|
-
* If `normal` is omitted, the kernel will infer a stable fallback plane.
|
|
125
|
-
*/
|
|
126
|
-
thicken(
|
|
127
|
-
distance: number,
|
|
128
|
-
bothSides = false,
|
|
129
|
-
normal?: Vec3,
|
|
130
|
-
options: CurveOffsetOptions = {},
|
|
131
|
-
): PolyCurve {
|
|
132
|
-
return new Polyline([this.start, this.end]).thicken(distance, bothSides, normal, options);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Project this line onto a plane.
|
|
137
|
-
* @param plane - Target plane
|
|
138
|
-
* @param direction - Optional projection direction (default: perpendicular to plane)
|
|
124
|
+
new Point(r[3], r[4], r[5]),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Thicken this line into a closed PolyCurve suitable for extrusion.
|
|
130
|
+
* When `bothSides` is false, the source line forms one side of the result.
|
|
131
|
+
* When true, the thickness is added on each side of the line.
|
|
132
|
+
*
|
|
133
|
+
* If `normal` is omitted, the kernel will infer a stable fallback plane.
|
|
134
|
+
*/
|
|
135
|
+
thicken(
|
|
136
|
+
distance: number,
|
|
137
|
+
bothSides = false,
|
|
138
|
+
normal?: Vec3,
|
|
139
|
+
options: CurveOffsetOptions = {},
|
|
140
|
+
): PolyCurve {
|
|
141
|
+
return new Polyline([this.start, this.end]).thicken(distance, bothSides, normal, options);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Project this line onto a plane.
|
|
146
|
+
* @param plane - Target plane
|
|
147
|
+
* @param direction - Optional projection direction (default: perpendicular to plane)
|
|
139
148
|
* @returns New projected line
|
|
140
149
|
*/
|
|
141
150
|
projectOntoPlane(plane: Plane, direction?: Vec3): Line {
|
package/src/NurbsCurve.ts
CHANGED
|
@@ -363,6 +363,22 @@ export class NurbsCurve {
|
|
|
363
363
|
);
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Apply a row-major 4x4 AFFINE matrix to this curve. NURBS are invariant
|
|
368
|
+
* under affine maps of their control points, so rigid transforms, scaling
|
|
369
|
+
* (uniform or not) and shear are EXACT — weights and knots are unchanged.
|
|
370
|
+
* @param matrix - Row-major 4x4 matrix (16 entries)
|
|
371
|
+
* @returns New transformed curve
|
|
372
|
+
*/
|
|
373
|
+
applyMatrix(matrix: number[] | Float64Array): NurbsCurve {
|
|
374
|
+
return new NurbsCurve(
|
|
375
|
+
this.degree,
|
|
376
|
+
this.controlPoints.map(p => p.applyMatrix(matrix)),
|
|
377
|
+
this.weights,
|
|
378
|
+
this.knots
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
366
382
|
/**
|
|
367
383
|
* Rotate this curve around an axis.
|
|
368
384
|
* @param axis - Rotation axis (Vec3 through origin, or Line for arbitrary axis)
|
package/src/NurbsSurface.ts
CHANGED
|
@@ -81,6 +81,25 @@ export class NurbsSurface implements Surface {
|
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Apply a row-major 4x4 AFFINE matrix to this surface. NURBS are invariant
|
|
86
|
+
* under affine maps of their control net, so rigid transforms, scaling
|
|
87
|
+
* (uniform or not) and shear are EXACT — weights and knots are unchanged.
|
|
88
|
+
* @param matrix - Row-major 4x4 matrix (16 entries)
|
|
89
|
+
* @returns New transformed surface
|
|
90
|
+
*/
|
|
91
|
+
applyMatrix(matrix: number[] | Float64Array): NurbsSurface {
|
|
92
|
+
const newCps = this.controlPoints.map(row => row.map(p => p.applyMatrix(matrix)));
|
|
93
|
+
return new NurbsSurface(
|
|
94
|
+
this.degreeU,
|
|
95
|
+
this.degreeV,
|
|
96
|
+
newCps,
|
|
97
|
+
this.weights,
|
|
98
|
+
this.knotsU,
|
|
99
|
+
this.knotsV
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
84
103
|
/**
|
|
85
104
|
* Evaluate a point on the surface at parameters (u, v).
|
|
86
105
|
* @param u - Parameter in U direction [0, 1]
|
package/src/Point.ts
CHANGED
|
@@ -1,145 +1,161 @@
|
|
|
1
|
-
import { Vec3 } from "./Vec3.js";
|
|
2
|
-
import type { Plane } from "./Plane.js";
|
|
3
|
-
import type { RotationAxis } from "./types.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Immutable 3D point for representing positions in space.
|
|
7
|
-
* All operations return new Point instances.
|
|
8
|
-
*/
|
|
9
|
-
export class Point {
|
|
10
|
-
constructor(
|
|
11
|
-
public readonly x: number,
|
|
12
|
-
public readonly y: number,
|
|
13
|
-
public readonly z: number
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Compute the distance to another point.
|
|
18
|
-
* @param other - Target point
|
|
19
|
-
* @returns Euclidean distance between points
|
|
20
|
-
*/
|
|
21
|
-
distanceTo(other: Point): number {
|
|
22
|
-
const dx = this.x - other.x;
|
|
23
|
-
const dy = this.y - other.y;
|
|
24
|
-
const dz = this.z - other.z;
|
|
25
|
-
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Convert this point to a vector (from origin).
|
|
30
|
-
* @returns Vec3 with same coordinates
|
|
31
|
-
*/
|
|
32
|
-
toVec3(): Vec3 {
|
|
33
|
-
return new Vec3(this.x, this.y, this.z);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Add a vector to this point.
|
|
38
|
-
* @param v - Vector to add
|
|
39
|
-
* @returns New point offset by vector
|
|
40
|
-
*/
|
|
41
|
-
add(v: Vec3): Point {
|
|
42
|
-
return new Point(this.x + v.x, this.y + v.y, this.z + v.z);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Translate this point by an offset vector.
|
|
47
|
-
* Alias for add().
|
|
48
|
-
* @param offset - Translation vector
|
|
49
|
-
* @returns New translated point
|
|
50
|
-
*/
|
|
51
|
-
translate(offset: Vec3): Point {
|
|
52
|
-
return this.add(offset);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param
|
|
59
|
-
* @returns
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
*
|
|
113
|
-
* @
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
1
|
+
import { Vec3 } from "./Vec3.js";
|
|
2
|
+
import type { Plane } from "./Plane.js";
|
|
3
|
+
import type { RotationAxis } from "./types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Immutable 3D point for representing positions in space.
|
|
7
|
+
* All operations return new Point instances.
|
|
8
|
+
*/
|
|
9
|
+
export class Point {
|
|
10
|
+
constructor(
|
|
11
|
+
public readonly x: number,
|
|
12
|
+
public readonly y: number,
|
|
13
|
+
public readonly z: number
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compute the distance to another point.
|
|
18
|
+
* @param other - Target point
|
|
19
|
+
* @returns Euclidean distance between points
|
|
20
|
+
*/
|
|
21
|
+
distanceTo(other: Point): number {
|
|
22
|
+
const dx = this.x - other.x;
|
|
23
|
+
const dy = this.y - other.y;
|
|
24
|
+
const dz = this.z - other.z;
|
|
25
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Convert this point to a vector (from origin).
|
|
30
|
+
* @returns Vec3 with same coordinates
|
|
31
|
+
*/
|
|
32
|
+
toVec3(): Vec3 {
|
|
33
|
+
return new Vec3(this.x, this.y, this.z);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Add a vector to this point.
|
|
38
|
+
* @param v - Vector to add
|
|
39
|
+
* @returns New point offset by vector
|
|
40
|
+
*/
|
|
41
|
+
add(v: Vec3): Point {
|
|
42
|
+
return new Point(this.x + v.x, this.y + v.y, this.z + v.z);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Translate this point by an offset vector.
|
|
47
|
+
* Alias for add().
|
|
48
|
+
* @param offset - Translation vector
|
|
49
|
+
* @returns New translated point
|
|
50
|
+
*/
|
|
51
|
+
translate(offset: Vec3): Point {
|
|
52
|
+
return this.add(offset);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Apply a row-major 4x4 matrix to this point (same convention as
|
|
57
|
+
* Mesh.applyMatrix / Brep.applyMatrix).
|
|
58
|
+
* @param matrix - Row-major 4x4 matrix (16 entries)
|
|
59
|
+
* @returns New transformed point
|
|
60
|
+
*/
|
|
61
|
+
applyMatrix(matrix: number[] | Float64Array): Point {
|
|
62
|
+
if (matrix.length < 16) throw new Error("Point.applyMatrix: need 16 entries");
|
|
63
|
+
const m = matrix;
|
|
64
|
+
return new Point(
|
|
65
|
+
m[0] * this.x + m[1] * this.y + m[2] * this.z + m[3],
|
|
66
|
+
m[4] * this.x + m[5] * this.y + m[6] * this.z + m[7],
|
|
67
|
+
m[8] * this.x + m[9] * this.y + m[10] * this.z + m[11]
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Rotate around an axis by angle in radians using Rodrigues' formula.
|
|
73
|
+
* @param axis - Vec3 (rotation around origin) or Line (rotation around arbitrary axis)
|
|
74
|
+
* @param angle - Rotation angle in radians
|
|
75
|
+
* @returns Rotated point
|
|
76
|
+
*/
|
|
77
|
+
rotate(axis: RotationAxis, angle: number): Point {
|
|
78
|
+
if ('start' in axis && 'end' in axis) {
|
|
79
|
+
const dir = new Vec3(axis.end.x - axis.start.x, axis.end.y - axis.start.y, axis.end.z - axis.start.z);
|
|
80
|
+
const shifted = new Point(this.x - axis.start.x, this.y - axis.start.y, this.z - axis.start.z);
|
|
81
|
+
const rotated = shifted.rotate(dir, angle);
|
|
82
|
+
return new Point(rotated.x + axis.start.x, rotated.y + axis.start.y, rotated.z + axis.start.z);
|
|
83
|
+
}
|
|
84
|
+
const len = Math.sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z);
|
|
85
|
+
if (len < 1e-15) return this.clone();
|
|
86
|
+
const k = { x: axis.x / len, y: axis.y / len, z: axis.z / len };
|
|
87
|
+
const cos = Math.cos(angle);
|
|
88
|
+
const sin = Math.sin(angle);
|
|
89
|
+
const dot = k.x * this.x + k.y * this.y + k.z * this.z;
|
|
90
|
+
const cx = k.y * this.z - k.z * this.y;
|
|
91
|
+
const cy = k.z * this.x - k.x * this.z;
|
|
92
|
+
const cz = k.x * this.y - k.y * this.x;
|
|
93
|
+
return new Point(
|
|
94
|
+
this.x * cos + cx * sin + k.x * dot * (1 - cos),
|
|
95
|
+
this.y * cos + cy * sin + k.y * dot * (1 - cos),
|
|
96
|
+
this.z * cos + cz * sin + k.z * dot * (1 - cos),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Project this point onto a plane.
|
|
102
|
+
* @param plane - Target plane
|
|
103
|
+
* @param direction - Optional projection direction (default: perpendicular to plane)
|
|
104
|
+
* @returns Projected point on plane
|
|
105
|
+
*/
|
|
106
|
+
projectOntoPlane(plane: Plane, direction?: Vec3): Point {
|
|
107
|
+
return direction ? plane.projectPointAlongDirection(this, direction) : plane.projectPoint(this);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get the vector from another point to this point.
|
|
112
|
+
* @param other - Origin point
|
|
113
|
+
* @returns Vector from other to this
|
|
114
|
+
*/
|
|
115
|
+
sub(other: Point): Vec3 {
|
|
116
|
+
return new Vec3(this.x - other.x, this.y - other.y, this.z - other.z);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Create a copy of this point.
|
|
121
|
+
* @returns New point with same coordinates
|
|
122
|
+
*/
|
|
123
|
+
clone(): Point {
|
|
124
|
+
return new Point(this.x, this.y, this.z);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check equality with another point within tolerance.
|
|
129
|
+
* @param other - Point to compare
|
|
130
|
+
* @param eps - Tolerance (default 1e-10)
|
|
131
|
+
* @returns True if points are approximately equal
|
|
132
|
+
*/
|
|
133
|
+
equals(other: Point, eps = 1e-10): boolean {
|
|
134
|
+
return (
|
|
135
|
+
Math.abs(this.x - other.x) < eps &&
|
|
136
|
+
Math.abs(this.y - other.y) < eps &&
|
|
137
|
+
Math.abs(this.z - other.z) < eps
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Convert to array format.
|
|
143
|
+
* @returns Tuple [x, y, z]
|
|
144
|
+
*/
|
|
145
|
+
toArray(): [number, number, number] {
|
|
146
|
+
return [this.x, this.y, this.z];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create a Point from a plain object or JSON.
|
|
151
|
+
* @param json - Object with x, y, z properties
|
|
152
|
+
* @returns New Point instance
|
|
153
|
+
*/
|
|
154
|
+
static fromJSON(json: any): Point {
|
|
155
|
+
if (json instanceof Point) return json;
|
|
156
|
+
return new Point(json.x ?? 0, json.y ?? 0, json.z ?? 0);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Origin point (0, 0, 0) */
|
|
160
|
+
static readonly ORIGIN = new Point(0, 0, 0);
|
|
161
|
+
}
|
package/src/Polyline.ts
CHANGED
|
@@ -135,6 +135,15 @@ export class Polyline {
|
|
|
135
135
|
return new Polyline(this.points.map(p => p.add(offset)));
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Apply a row-major 4x4 matrix to every vertex.
|
|
140
|
+
* @param matrix - Row-major 4x4 matrix (16 entries)
|
|
141
|
+
* @returns New transformed polyline
|
|
142
|
+
*/
|
|
143
|
+
applyMatrix(matrix: number[] | Float64Array): Polyline {
|
|
144
|
+
return new Polyline(this.points.map(p => p.applyMatrix(matrix)));
|
|
145
|
+
}
|
|
146
|
+
|
|
138
147
|
/**
|
|
139
148
|
* Rotate this polyline around an axis.
|
|
140
149
|
* @param axis - Rotation axis (Vec3 through origin, or Line for arbitrary axis)
|