@itwin/core-geometry 4.0.0-dev.70 → 4.0.0-dev.72
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/CHANGELOG.md +36 -3
- package/lib/cjs/curve/Query/PlanarSubdivision.d.ts +7 -1
- package/lib/cjs/curve/Query/PlanarSubdivision.d.ts.map +1 -1
- package/lib/cjs/curve/Query/PlanarSubdivision.js +14 -12
- package/lib/cjs/curve/Query/PlanarSubdivision.js.map +1 -1
- package/lib/cjs/curve/RegionOps.d.ts +2 -2
- package/lib/cjs/curve/RegionOps.js +2 -2
- package/lib/cjs/curve/RegionOps.js.map +1 -1
- package/lib/cjs/geometry3d/BarycentricTriangle.d.ts +134 -90
- package/lib/cjs/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/cjs/geometry3d/BarycentricTriangle.js +192 -129
- package/lib/cjs/geometry3d/BarycentricTriangle.js.map +1 -1
- package/lib/cjs/geometry3d/Ray3d.d.ts +38 -34
- package/lib/cjs/geometry3d/Ray3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Ray3d.js +48 -45
- package/lib/cjs/geometry3d/Ray3d.js.map +1 -1
- package/lib/esm/curve/Query/PlanarSubdivision.d.ts +7 -1
- package/lib/esm/curve/Query/PlanarSubdivision.d.ts.map +1 -1
- package/lib/esm/curve/Query/PlanarSubdivision.js +14 -12
- package/lib/esm/curve/Query/PlanarSubdivision.js.map +1 -1
- package/lib/esm/curve/RegionOps.d.ts +2 -2
- package/lib/esm/curve/RegionOps.js +2 -2
- package/lib/esm/curve/RegionOps.js.map +1 -1
- package/lib/esm/geometry3d/BarycentricTriangle.d.ts +134 -90
- package/lib/esm/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/esm/geometry3d/BarycentricTriangle.js +192 -129
- package/lib/esm/geometry3d/BarycentricTriangle.js.map +1 -1
- package/lib/esm/geometry3d/Ray3d.d.ts +38 -34
- package/lib/esm/geometry3d/Ray3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Ray3d.js +48 -45
- package/lib/esm/geometry3d/Ray3d.js.map +1 -1
- package/package.json +5 -5
|
@@ -15,17 +15,23 @@ const Point3dVector3d_1 = require("./Point3dVector3d");
|
|
|
15
15
|
const Ray3d_1 = require("./Ray3d");
|
|
16
16
|
/**
|
|
17
17
|
* Carries data about a location in the plane of a triangle.
|
|
18
|
-
* * Each instance carries both world and barycentric coordinates for the point, and provides query
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* * Each instance carries both world and barycentric coordinates for the point, and provides query
|
|
19
|
+
* services on the latter.
|
|
20
|
+
* * No tolerance is used when querying barycentric coordinates (e.g., `isInsideOrOn`, `classify`). Use
|
|
21
|
+
* [[BarycentricTriangle.snapLocationToEdge]] to adjust the barycentric coordinates to a triangle edge
|
|
22
|
+
* if they lie within a distance or parametric tolerance.
|
|
21
23
|
*
|
|
22
|
-
* Properties of the barycentric coordinates (b0, b1, b2) of a point p in the plane of a triangle
|
|
23
|
-
*
|
|
24
|
-
* *
|
|
25
|
-
* *
|
|
26
|
-
* *
|
|
27
|
-
*
|
|
28
|
-
* *
|
|
24
|
+
* Properties of the barycentric coordinates `(b0, b1, b2)` of a point `p` in the plane of a triangle
|
|
25
|
+
* `T` with vertices `v0, v1, v2`:
|
|
26
|
+
* * `1 = b0 + b1 + b2`
|
|
27
|
+
* * `p = b0 * v0 + b1 * v1 + b2 * v2`
|
|
28
|
+
* * If T is spanned by the vectors `U = v1 - v0` and `V = v2 - v0`, then the vector `P = p - v0` can
|
|
29
|
+
* be written `P = b1 * U + b2 * V`.
|
|
30
|
+
* * The coordinates are all nonnegative if and only if `p` is inside or on `T`.
|
|
31
|
+
* * Exactly one coordinate is zero if and only if `p` lies on an (infinitely extended) edge of `T`.
|
|
32
|
+
* * Exactly two coordinates are zero if and only if `p` coincides with a vertex of `T`.
|
|
33
|
+
* * Note that if `p` can be written as a linear combination of the vertices of `T` using scales that do
|
|
34
|
+
* NOT sum to 1, then `p` is not coplanar with `T`
|
|
29
35
|
* @public
|
|
30
36
|
*/
|
|
31
37
|
class TriangleLocationDetail {
|
|
@@ -36,7 +42,7 @@ class TriangleLocationDetail {
|
|
|
36
42
|
this.closestEdgeIndex = 0;
|
|
37
43
|
this.closestEdgeParam = 0.0;
|
|
38
44
|
}
|
|
39
|
-
/** Invalidate this detail. */
|
|
45
|
+
/** Invalidate this detail (set all attributes to zero) . */
|
|
40
46
|
invalidate() {
|
|
41
47
|
this.world.setZero();
|
|
42
48
|
this.local.setZero();
|
|
@@ -44,7 +50,8 @@ class TriangleLocationDetail {
|
|
|
44
50
|
this.closestEdgeIndex = 0;
|
|
45
51
|
this.closestEdgeParam = 0.0;
|
|
46
52
|
}
|
|
47
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Create an invalid detail.
|
|
48
55
|
* @param result optional pre-allocated object to fill and return
|
|
49
56
|
*/
|
|
50
57
|
static create(result) {
|
|
@@ -54,7 +61,8 @@ class TriangleLocationDetail {
|
|
|
54
61
|
result.invalidate();
|
|
55
62
|
return result;
|
|
56
63
|
}
|
|
57
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Set the instance contents from the `other` detail.
|
|
58
66
|
* @param other detail to clone
|
|
59
67
|
*/
|
|
60
68
|
copyContentsFrom(other) {
|
|
@@ -68,13 +76,16 @@ class TriangleLocationDetail {
|
|
|
68
76
|
get isValid() {
|
|
69
77
|
return !this.local.isZero;
|
|
70
78
|
}
|
|
71
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Queries the barycentric coordinates to determine whether this instance specifies a location inside or
|
|
81
|
+
* on the triangle.
|
|
72
82
|
* @see classify
|
|
73
83
|
*/
|
|
74
84
|
get isInsideOrOn() {
|
|
75
85
|
return this.isValid && this.local.x >= 0.0 && this.local.y >= 0.0 && this.local.z >= 0.0;
|
|
76
86
|
}
|
|
77
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Queries this detail to classify the location of this instance with respect to the triangle.
|
|
78
89
|
* @returns location code
|
|
79
90
|
* @see isInsideOrOn
|
|
80
91
|
*/
|
|
@@ -95,7 +106,9 @@ class TriangleLocationDetail {
|
|
|
95
106
|
return Geometry_1.PolygonLocation.OnPolygonEdgeInterior;
|
|
96
107
|
return Geometry_1.PolygonLocation.InsidePolygonProjectsToEdgeInterior;
|
|
97
108
|
}
|
|
98
|
-
return (this.closestEdgeParam === 0.0) ?
|
|
109
|
+
return (this.closestEdgeParam === 0.0) ?
|
|
110
|
+
Geometry_1.PolygonLocation.OutsidePolygonProjectsToVertex :
|
|
111
|
+
Geometry_1.PolygonLocation.OutsidePolygonProjectsToEdgeInterior;
|
|
99
112
|
}
|
|
100
113
|
}
|
|
101
114
|
exports.TriangleLocationDetail = TriangleLocationDetail;
|
|
@@ -104,7 +117,8 @@ exports.TriangleLocationDetail = TriangleLocationDetail;
|
|
|
104
117
|
* @public
|
|
105
118
|
*/
|
|
106
119
|
class BarycentricTriangle {
|
|
107
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Constructor.
|
|
108
122
|
* * Point references are CAPTURED
|
|
109
123
|
*/
|
|
110
124
|
constructor(point0, point1, point2) {
|
|
@@ -118,7 +132,26 @@ class BarycentricTriangle {
|
|
|
118
132
|
this.edgeLength2.push(point0.distanceSquared(point1));
|
|
119
133
|
}
|
|
120
134
|
/**
|
|
121
|
-
*
|
|
135
|
+
* Copy contents of (not pointers to) the given points. A vertex is zeroed if its corresponding input point
|
|
136
|
+
* is undefined.
|
|
137
|
+
*/
|
|
138
|
+
set(point0, point1, point2) {
|
|
139
|
+
this.points[0].setFromPoint3d(point0);
|
|
140
|
+
this.points[1].setFromPoint3d(point1);
|
|
141
|
+
this.points[2].setFromPoint3d(point2);
|
|
142
|
+
this.edgeLength2[0] = this.points[1].distanceSquared(this.points[2]);
|
|
143
|
+
this.edgeLength2[1] = this.points[0].distanceSquared(this.points[2]);
|
|
144
|
+
this.edgeLength2[2] = this.points[0].distanceSquared(this.points[1]);
|
|
145
|
+
}
|
|
146
|
+
/** Copy all values from `other` */
|
|
147
|
+
setFrom(other) {
|
|
148
|
+
for (let i = 0; i < 3; ++i) {
|
|
149
|
+
this.points[i].setFromPoint3d(other.points[i]);
|
|
150
|
+
this.edgeLength2[i] = other.edgeLength2[i];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create a `BarycentricTriangle` with coordinates given by enumerated x,y,z of the 3 points.
|
|
122
155
|
* @param result optional pre-allocated triangle.
|
|
123
156
|
*/
|
|
124
157
|
static createXYZXYZXYZ(x0, y0, z0, x1, y1, z1, x2, y2, z2, result) {
|
|
@@ -129,7 +162,7 @@ class BarycentricTriangle {
|
|
|
129
162
|
result.points[2].set(x2, y2, z2);
|
|
130
163
|
return result;
|
|
131
164
|
}
|
|
132
|
-
/**
|
|
165
|
+
/** Create a triangle with coordinates cloned from given points. */
|
|
133
166
|
static create(point0, point1, point2, result) {
|
|
134
167
|
if (!result)
|
|
135
168
|
return new this(point0.clone(), point1.clone(), point2.clone());
|
|
@@ -140,46 +173,76 @@ class BarycentricTriangle {
|
|
|
140
173
|
clone(result) {
|
|
141
174
|
return BarycentricTriangle.create(this.points[0], this.points[1], this.points[2], result);
|
|
142
175
|
}
|
|
143
|
-
/** Return area divided by sum of squared lengths. */
|
|
144
|
-
get aspectRatio() {
|
|
145
|
-
return Geometry_1.Geometry.safeDivideFraction(this.area, this.edgeLengthSquared(0) + this.edgeLengthSquared(1) + this.edgeLengthSquared(2), 0);
|
|
146
|
-
}
|
|
147
176
|
/** Return the area of the triangle. */
|
|
148
177
|
get area() {
|
|
178
|
+
// The magnitude of the cross product A × B is the area of the parallelogram spanned by A and B.
|
|
149
179
|
return 0.5 * this.points[0].crossProductToPointsMagnitude(this.points[1], this.points[2]);
|
|
150
180
|
}
|
|
151
|
-
/**
|
|
181
|
+
/**
|
|
182
|
+
* Compute squared length of the triangle edge opposite the vertex with the given index.
|
|
183
|
+
* @see [[edgeStartVertexIndexToOppositeVertexIndex]]
|
|
184
|
+
*/
|
|
185
|
+
edgeLengthSquared(oppositeVertexIndex) {
|
|
186
|
+
return this.edgeLength2[Geometry_1.Geometry.cyclic3dAxis(oppositeVertexIndex)];
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Compute length of the triangle edge opposite the vertex with the given index.
|
|
190
|
+
* @see [[edgeStartVertexIndexToOppositeVertexIndex]]
|
|
191
|
+
*/
|
|
192
|
+
edgeLength(oppositeVertexIndex) {
|
|
193
|
+
return Math.sqrt(this.edgeLengthSquared(oppositeVertexIndex));
|
|
194
|
+
}
|
|
195
|
+
/** Return area divided by sum of squared lengths. */
|
|
196
|
+
get aspectRatio() {
|
|
197
|
+
return Geometry_1.Geometry.safeDivideFraction(this.area, this.edgeLengthSquared(0) + this.edgeLengthSquared(1) + this.edgeLengthSquared(2), 0);
|
|
198
|
+
}
|
|
199
|
+
/** Return the perimeter of the triangle. */
|
|
152
200
|
get perimeter() {
|
|
153
201
|
return this.edgeLength(0) + this.edgeLength(1) + this.edgeLength(2);
|
|
154
202
|
}
|
|
155
|
-
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
203
|
+
/**
|
|
204
|
+
* Return the unit normal of the triangle.
|
|
205
|
+
* @param result optional pre-allocated vector to fill and return.
|
|
206
|
+
* @returns unit normal, or undefined if cross product length is too small.
|
|
207
|
+
*/
|
|
208
|
+
normal(result) {
|
|
209
|
+
const cross = this.points[0].crossProductToPoints(this.points[1], this.points[2], result);
|
|
210
|
+
if (cross.tryNormalizeInPlace())
|
|
211
|
+
return cross;
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Sum the triangle points with given scales.
|
|
216
|
+
* * If the scales sum to 1, they are barycentric coordinates, and hence the result point is in the plane of
|
|
217
|
+
* the triangle. If all coordinates are non-negative then the result point is inside the triangle.
|
|
218
|
+
* * If the scales do not sum to 1, the point is inside the triangle scaled (by the scale sum) from the origin.
|
|
158
219
|
* @param b0 scale to apply to vertex 0
|
|
159
220
|
* @param b1 scale to apply to vertex 1
|
|
160
221
|
* @param b2 scale to apply to vertex 2
|
|
161
222
|
* @param result optional pre-allocated point to fill and return
|
|
162
223
|
* @return linear combination of the vertices of this triangle
|
|
163
|
-
* @see pointToFraction
|
|
224
|
+
* @see [[pointToFraction]]
|
|
164
225
|
*/
|
|
165
226
|
fractionToPoint(b0, b1, b2, result) {
|
|
227
|
+
// p = b0 * v0 + b1 * v1 + b2 * v2
|
|
166
228
|
return Point3dVector3d_1.Point3d.createAdd3Scaled(this.points[0], b0, this.points[1], b1, this.points[2], b2, result);
|
|
167
229
|
}
|
|
168
|
-
/**
|
|
230
|
+
/**
|
|
231
|
+
* Compute the projection of the given `point` onto the plane of this triangle.
|
|
169
232
|
* @param point point p to project
|
|
170
233
|
* @param result optional pre-allocated object to fill and return
|
|
171
|
-
* @returns details d of the projection point P =
|
|
234
|
+
* @returns details d of the projection point `P = d.world`:
|
|
172
235
|
* * `d.isValid` returns true if and only if `this.normal()` is defined.
|
|
173
236
|
* * `d.classify` can be used to determine where P lies with respect to the triangle.
|
|
174
|
-
* * `d.a` is the signed projection distance: P = p + a *
|
|
175
|
-
* @see fractionToPoint
|
|
237
|
+
* * `d.a` is the signed projection distance: `P = p + a * this.normal()`.
|
|
238
|
+
* @see [[fractionToPoint]]
|
|
176
239
|
*/
|
|
177
240
|
pointToFraction(point, result) {
|
|
178
241
|
const normal = BarycentricTriangle._workVector0 = this.normal(BarycentricTriangle._workVector0);
|
|
179
242
|
if (undefined === normal)
|
|
180
243
|
return TriangleLocationDetail.create(result);
|
|
181
244
|
const ray = BarycentricTriangle._workRay = Ray3d_1.Ray3d.create(point, normal, BarycentricTriangle._workRay);
|
|
182
|
-
return this.intersectRay3d(ray, result); // is free to use workVector0
|
|
245
|
+
return this.intersectRay3d(ray, result); // intersectRay3d is free to use workVector0
|
|
183
246
|
}
|
|
184
247
|
/** Convert from opposite-vertex to start-vertex edge indexing. */
|
|
185
248
|
static edgeOppositeVertexIndexToStartVertexIndex(edgeIndex) {
|
|
@@ -189,7 +252,8 @@ class BarycentricTriangle {
|
|
|
189
252
|
static edgeStartVertexIndexToOppositeVertexIndex(startVertexIndex) {
|
|
190
253
|
return Geometry_1.Geometry.cyclic3dAxis(startVertexIndex - 1);
|
|
191
254
|
}
|
|
192
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Examine a point's barycentric coordinates to determine if it lies inside the triangle but not on an edge/vertex.
|
|
193
257
|
* * No parametric tolerance is used.
|
|
194
258
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
195
259
|
* @returns whether the point with barycentric coordinates is strictly inside the triangle.
|
|
@@ -197,7 +261,8 @@ class BarycentricTriangle {
|
|
|
197
261
|
static isInsideTriangle(b0, b1, b2) {
|
|
198
262
|
return b0 > 0 && b1 > 0 && b2 > 0;
|
|
199
263
|
}
|
|
200
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* Examine a point's barycentric coordinates to determine if it lies inside the triangle or on an edge/vertex.
|
|
201
266
|
* * No parametric tolerance is used.
|
|
202
267
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
203
268
|
* @returns whether the point with barycentric coordinates is inside or on the triangle.
|
|
@@ -205,12 +270,15 @@ class BarycentricTriangle {
|
|
|
205
270
|
static isInsideOrOnTriangle(b0, b1, b2) {
|
|
206
271
|
return b0 >= 0 && b1 >= 0 && b2 >= 0;
|
|
207
272
|
}
|
|
208
|
-
/**
|
|
273
|
+
/**
|
|
274
|
+
* Examine a point's barycentric coordinates to determine if it lies outside an edge of the triangle.
|
|
209
275
|
* * No parametric tolerance is used.
|
|
210
276
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
211
|
-
* @returns index
|
|
277
|
+
* @returns edge index i (opposite vertex i) for which b_i < 0 and b_j >= 0, and b_k >= 0. Otherwise, returns -1.
|
|
212
278
|
*/
|
|
213
279
|
static isInRegionBeyondEdge(b0, b1, b2) {
|
|
280
|
+
// Note: the 3 regions (specified by the following if statements) are defined by extending the triangle
|
|
281
|
+
// edges to infinity and not by perpendicular lines to the edges (which gives smaller regions)
|
|
214
282
|
if (b0 < 0 && b1 >= 0 && b2 >= 0)
|
|
215
283
|
return 0;
|
|
216
284
|
if (b0 >= 0 && b1 < 0 && b2 >= 0)
|
|
@@ -219,12 +287,15 @@ class BarycentricTriangle {
|
|
|
219
287
|
return 2;
|
|
220
288
|
return -1;
|
|
221
289
|
}
|
|
222
|
-
/**
|
|
290
|
+
/**
|
|
291
|
+
* Examine a point's barycentric coordinates to determine if it lies outside a vertex of the triangle.
|
|
223
292
|
* * No parametric tolerance is used.
|
|
224
293
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
225
|
-
* @returns index of vertex i for which
|
|
294
|
+
* @returns index of vertex i for which b_j < 0 and b_k < 0. Otherwise, returns -1.
|
|
226
295
|
*/
|
|
227
296
|
static isInRegionBeyondVertex(b0, b1, b2) {
|
|
297
|
+
// Note: the 3 regions (specified by the following if statements) are defined by extending the triangle
|
|
298
|
+
// edges to infinity and not by perpendicular lines to the edges (which gives larger regions)
|
|
228
299
|
if (b1 < 0 && b2 < 0)
|
|
229
300
|
return 0;
|
|
230
301
|
if (b0 < 0 && b2 < 0)
|
|
@@ -233,10 +304,11 @@ class BarycentricTriangle {
|
|
|
233
304
|
return 2;
|
|
234
305
|
return -1;
|
|
235
306
|
}
|
|
236
|
-
/**
|
|
307
|
+
/**
|
|
308
|
+
* Examine a point's barycentric coordinates to determine if it lies on a vertex of the triangle.
|
|
237
309
|
* * No parametric tolerance is used.
|
|
238
310
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
239
|
-
* @returns index of vertex i for which b_i = 1 and b_j = b_k = 0,
|
|
311
|
+
* @returns index of vertex i for which b_i = 1 and b_j = b_k = 0. Otherwise, returns -1.
|
|
240
312
|
*/
|
|
241
313
|
static isOnVertex(b0, b1, b2) {
|
|
242
314
|
if (b0 === 1 && b1 === 0 && b2 === 0)
|
|
@@ -247,10 +319,11 @@ class BarycentricTriangle {
|
|
|
247
319
|
return 2;
|
|
248
320
|
return -1;
|
|
249
321
|
}
|
|
250
|
-
/**
|
|
322
|
+
/**
|
|
323
|
+
* Examine a point's barycentric coordinates to determine if it lies on a bounded edge of the triangle.
|
|
251
324
|
* * No parametric tolerance is used.
|
|
252
325
|
* * It is assumed b0 + b1 + b2 = 1.
|
|
253
|
-
* @returns index
|
|
326
|
+
* @returns edge index i (opposite vertex i) for which b_i = 0, b_j > 0, and b_k > 0. Otherwise, returns -1.
|
|
254
327
|
*/
|
|
255
328
|
static isOnBoundedEdge(b0, b1, b2) {
|
|
256
329
|
if (b0 === 0 && b1 > 0 && b2 > 0)
|
|
@@ -274,35 +347,70 @@ class BarycentricTriangle {
|
|
|
274
347
|
i = 2;
|
|
275
348
|
return i;
|
|
276
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Compute the squared distance between two points given by their barycentric coordinates.
|
|
352
|
+
* * It is assumed that a0 + a1 + a2 = b0 + b1 + b2 = 1.
|
|
353
|
+
*/
|
|
354
|
+
distanceSquared(a0, a1, a2, b0, b1, b2) {
|
|
355
|
+
// The barycentric displacement vector distance formula
|
|
356
|
+
// More details can be found at https://web.evanchen.cc/handouts/bary/bary-full.pdf
|
|
357
|
+
return -this.edgeLengthSquared(0) * (b1 - a1) * (b2 - a2)
|
|
358
|
+
- this.edgeLengthSquared(1) * (b2 - a2) * (b0 - a0)
|
|
359
|
+
- this.edgeLengthSquared(2) * (b0 - a0) * (b1 - a1);
|
|
360
|
+
}
|
|
277
361
|
/** Return the index of the closest triangle vertex to the point given by its barycentric coordinates. */
|
|
278
362
|
closestVertexIndex(b0, b1, b2) {
|
|
279
363
|
return BarycentricTriangle.indexOfMinimum((i) => {
|
|
280
364
|
const a = BarycentricTriangle._workPoint = Point3dVector3d_1.Point3d.createZero(BarycentricTriangle._workPoint);
|
|
281
|
-
a.setAt(i, 1.0);
|
|
282
|
-
return this.distanceSquared(a.x, a.y, a.z, b0, b1, b2);
|
|
365
|
+
a.setAt(i, 1.0); // "a" is (1,0,0) or (0,1,0) or (0,0,1) so "a" represents vertex i
|
|
366
|
+
return this.distanceSquared(a.x, a.y, a.z, b0, b1, b2); // distance between the point and vertex i
|
|
283
367
|
});
|
|
284
368
|
}
|
|
285
|
-
/** Compute
|
|
369
|
+
/** Compute dot product of the edge vectors based at the vertex with the given index. */
|
|
370
|
+
dotProductOfEdgeVectorsAtVertex(baseVertexIndex) {
|
|
371
|
+
const i = Geometry_1.Geometry.cyclic3dAxis(baseVertexIndex);
|
|
372
|
+
const j = Geometry_1.Geometry.cyclic3dAxis(i + 1);
|
|
373
|
+
const k = Geometry_1.Geometry.cyclic3dAxis(j + 1);
|
|
374
|
+
return Geometry_1.Geometry.dotProductXYZXYZ(this.points[j].x - this.points[i].x, this.points[j].y - this.points[i].y, this.points[j].z - this.points[i].z, this.points[k].x - this.points[i].x, this.points[k].y - this.points[i].y, this.points[k].z - this.points[i].z);
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Compute the projection of barycentric point p onto the (unbounded) edge e_k(v_i,v_j) of the triangle T(v_i,v_j,v_k).
|
|
286
378
|
* @param k vertex v_k is opposite the edge e_k
|
|
287
379
|
* @param b barycentric coordinates of point to project
|
|
288
|
-
* @returns parameter
|
|
289
|
-
* * the projection point is q = v_i +
|
|
290
|
-
* * the barycentric coords of the projection are q_ijk = (1 -
|
|
380
|
+
* @returns parameter f along e_k, such that:
|
|
381
|
+
* * the projection point is q = v_i + f * (v_j - v_i)
|
|
382
|
+
* * the barycentric coords of the projection are q_ijk = (1 - f, f, 0)
|
|
291
383
|
*/
|
|
292
384
|
computeProjectionToEdge(k, b) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
385
|
+
/**
|
|
386
|
+
* We know p = (b_i*v_i) + (b_j*v_j) + (b_k*v_k) and 1 = b_i + b_j + b_k.
|
|
387
|
+
* Let U = v_j - v_i and V = v_k - v_i and P = p - v_i.
|
|
388
|
+
* First we prove P = b_jU + b_kV.
|
|
389
|
+
* P = (b_i * v_i) + (b_j * v_j) + (b_k * v_k) - v_i
|
|
390
|
+
* = (b_i * v_i) + (b_j * (v_j-v_i)) + (b_j * v_i) + (b_k * (v_k-v_i)) + (b_k * v_i) - v_i
|
|
391
|
+
* = (b_i * v_i) + (b_j * U) + (b_j * v_i) + (b_k * V) + (b_k * v_i) - v_i
|
|
392
|
+
* = (b_j * U) + (b_k * V) + ((b_i + b_j + b_k) * v_i) - v_i
|
|
393
|
+
* = (b_j * U) + (b_k * V) + v_i - v_i
|
|
394
|
+
* = (b_j * U) + (b_k * V)
|
|
395
|
+
* So we know p - v_i = b_jU + b_kV and q - v_i = fU
|
|
396
|
+
* Therefore, 0 = (p - q).(v_j - v_i)
|
|
397
|
+
* = ((p-v_i) - (q-v_i)).(v_j - v_i)
|
|
398
|
+
* = (b_jU + b_kV - fU).U
|
|
399
|
+
* = b_jU.U + b_kU.V - fU.U
|
|
400
|
+
* Thus f = b_j + b_k(U.V/U.U)
|
|
401
|
+
*/
|
|
296
402
|
k = Geometry_1.Geometry.cyclic3dAxis(k);
|
|
297
403
|
const i = Geometry_1.Geometry.cyclic3dAxis(k + 1);
|
|
298
404
|
const j = Geometry_1.Geometry.cyclic3dAxis(i + 1);
|
|
299
405
|
return b[j] + b[k] * this.dotProductOfEdgeVectorsAtVertex(i) / this.edgeLengthSquared(k);
|
|
300
406
|
}
|
|
301
|
-
/**
|
|
407
|
+
/**
|
|
408
|
+
* Compute the projection of a barycentric point p to the triangle T(v_0,v_1,v_2).
|
|
302
409
|
* @param b0 barycentric coordinate of p corresponding to v_0
|
|
303
410
|
* @param b1 barycentric coordinate of p corresponding to v_1
|
|
304
411
|
* @param b2 barycentric coordinate of p corresponding to v_2
|
|
305
|
-
* @returns closest edge start vertex index i and projection parameter
|
|
412
|
+
* @returns closest edge start vertex index i and projection parameter f such that the projection
|
|
413
|
+
* q = v_i + f * (v_j - v_i).
|
|
306
414
|
*/
|
|
307
415
|
closestPoint(b0, b1, b2) {
|
|
308
416
|
const b = [b0, b1, b2];
|
|
@@ -311,7 +419,7 @@ class BarycentricTriangle {
|
|
|
311
419
|
if (BarycentricTriangle.isInsideTriangle(b0, b1, b2)) { // projects to any edge
|
|
312
420
|
edgeIndex = BarycentricTriangle.indexOfMinimum((i) => {
|
|
313
421
|
// We want smallest projection distance d_i of p to e_i.
|
|
314
|
-
// Since
|
|
422
|
+
// Since b_i=d_i|e_i|/2A we can compare quantities b_i/|e_i|.
|
|
315
423
|
return b[i] * b[i] / this.edgeLengthSquared(i); // avoid sqrt
|
|
316
424
|
});
|
|
317
425
|
edgeParam = this.computeProjectionToEdge(edgeIndex, b);
|
|
@@ -352,20 +460,24 @@ class BarycentricTriangle {
|
|
|
352
460
|
closestEdgeParam: edgeParam,
|
|
353
461
|
};
|
|
354
462
|
}
|
|
355
|
-
/**
|
|
463
|
+
/**
|
|
464
|
+
* Compute the intersection of a line (parameterized as a ray) with the plane of this triangle.
|
|
356
465
|
* @param ray infinite line to intersect, as a ray
|
|
357
466
|
* @param result optional pre-allocated object to fill and return
|
|
358
|
-
* @returns details d of the line-plane intersection `d.
|
|
359
|
-
* * `d.
|
|
467
|
+
* @returns details d of the line-plane intersection point `d.world`:
|
|
468
|
+
* * `d.a` is the intersection parameter along the ray.
|
|
469
|
+
* * The line intersects the plane of the triangle if and only if `d.isValid` returns true.
|
|
470
|
+
* * The ray intersects the plane of the triangle if and only if `d.isValid` returns true and `d.a` >= 0.
|
|
471
|
+
* * The ray intersects the triangle if and only if `d.isValid` returns true, `d.a` >= 0, and `d.isInsideOrOn`
|
|
472
|
+
* returns true.
|
|
360
473
|
* * `d.classify` can be used to determine where the intersection lies with respect to the triangle.
|
|
361
|
-
*
|
|
362
|
-
* @see pointToFraction
|
|
474
|
+
* @see [[pointToFraction]]
|
|
363
475
|
*/
|
|
364
476
|
intersectRay3d(ray, result) {
|
|
365
477
|
result = TriangleLocationDetail.create(result);
|
|
366
478
|
// Let r0 = ray.origin, d = ray.direction. Write intersection point p two ways for unknown scalars s,b0,b1,b2:
|
|
367
|
-
// r0 + s*d = p = b0*
|
|
368
|
-
// Subtract
|
|
479
|
+
// r0 + s*d = p = b0*v0 + b1*v1 + b2*v2
|
|
480
|
+
// Subtract v0 from both ends, let u=v1-v0, v=v2-v0, c=r0-v0, and enforce b0+b1+b2=1:
|
|
369
481
|
// b1*u + b2*v - s*d = c
|
|
370
482
|
// This is a linear system Mx=c where M has columns u,v,d and solution x=(b1,b2,-s).
|
|
371
483
|
const r0 = ray.origin;
|
|
@@ -385,22 +497,25 @@ class BarycentricTriangle {
|
|
|
385
497
|
result.closestEdgeParam = proj.closestEdgeParam;
|
|
386
498
|
return result;
|
|
387
499
|
}
|
|
388
|
-
/**
|
|
500
|
+
/**
|
|
501
|
+
* Compute the intersection of a line (parameterized as a line segment) with the plane of this triangle.
|
|
389
502
|
* @param point0 start point of segment on line to intersect
|
|
390
503
|
* @param point1 end point of segment on line to intersect
|
|
391
504
|
* @param result optional pre-allocated object to fill and return
|
|
392
|
-
* @returns details d of the line-plane intersection `d.
|
|
505
|
+
* @returns details d of the line-plane intersection point `d.world`:
|
|
393
506
|
* * `d.isValid` returns true if and only if the line intersects the plane.
|
|
394
507
|
* * `d.classify` can be used to determine where the intersection lies with respect to the triangle.
|
|
395
508
|
* * `d.a` is the intersection parameter. If `d.a` is in [0,1], the segment intersects the plane of the triangle.
|
|
396
|
-
* @see intersectRay3d
|
|
509
|
+
* @see [[intersectRay3d]]
|
|
397
510
|
*/
|
|
398
511
|
intersectSegment(point0, point1, result) {
|
|
399
512
|
BarycentricTriangle._workRay = Ray3d_1.Ray3d.createStartEnd(point0, point1, BarycentricTriangle._workRay);
|
|
400
513
|
return this.intersectRay3d(BarycentricTriangle._workRay, result);
|
|
401
514
|
}
|
|
402
|
-
/**
|
|
403
|
-
*
|
|
515
|
+
/**
|
|
516
|
+
* Adjust the location to the closest edge of the triangle if within either given tolerance.
|
|
517
|
+
* @param location details of a point in the plane of the triangle (note that `location.local` and
|
|
518
|
+
* `location.world` possibly updated to lie on the triangle closest edge)
|
|
404
519
|
* @param distanceTolerance absolute distance tolerance (or zero to ignore)
|
|
405
520
|
* @param parameterTolerance barycentric coordinate fractional tolerance (or zero to ignore)
|
|
406
521
|
* @return whether the location was adjusted
|
|
@@ -451,26 +566,11 @@ class BarycentricTriangle {
|
|
|
451
566
|
}
|
|
452
567
|
return false;
|
|
453
568
|
}
|
|
454
|
-
/** Copy all values from `other`
|
|
455
|
-
*/
|
|
456
|
-
setFrom(other) {
|
|
457
|
-
for (let i = 0; i < 3; ++i) {
|
|
458
|
-
this.points[i].setFromPoint3d(other.points[i]);
|
|
459
|
-
this.edgeLength2[i] = other.edgeLength2[i];
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
/** Copy contents of (not pointers to) the given points. A vertex is zeroed if its corresponding input point is undefined. */
|
|
463
|
-
set(point0, point1, point2) {
|
|
464
|
-
this.points[0].setFromPoint3d(point0);
|
|
465
|
-
this.points[1].setFromPoint3d(point1);
|
|
466
|
-
this.points[2].setFromPoint3d(point2);
|
|
467
|
-
this.edgeLength2[0] = this.points[1].distanceSquared(this.points[2]);
|
|
468
|
-
this.edgeLength2[1] = this.points[0].distanceSquared(this.points[2]);
|
|
469
|
-
this.edgeLength2[2] = this.points[0].distanceSquared(this.points[1]);
|
|
470
|
-
}
|
|
471
569
|
/**
|
|
472
|
-
*
|
|
473
|
-
* *
|
|
570
|
+
* Return the dot product of the scaled normals of the two triangles.
|
|
571
|
+
* * The sign of the return value is useful for determining the triangles' relative orientation:
|
|
572
|
+
* positive (negative) means the normals point into the same (opposite) half-space determined by
|
|
573
|
+
* one of the triangles' planes; zero means the triangles are perpendicular.
|
|
474
574
|
*/
|
|
475
575
|
dotProductOfCrossProductsFromOrigin(other) {
|
|
476
576
|
BarycentricTriangle._workVector0 = this.points[0].crossProductToPoints(this.points[1], this.points[2], BarycentricTriangle._workVector0);
|
|
@@ -479,8 +579,7 @@ class BarycentricTriangle {
|
|
|
479
579
|
}
|
|
480
580
|
/** Return the centroid of the 3 points. */
|
|
481
581
|
centroid(result) {
|
|
482
|
-
//
|
|
483
|
-
// Do the scale as true division (rather than multiply by precomputed 1/3). This might protect one bit of result.
|
|
582
|
+
// Do the scale as true division (rather than multiply by precomputed 1/3). This might protect one bit of result.
|
|
484
583
|
return Point3dVector3d_1.Point3d.create((this.points[0].x + this.points[1].x + this.points[2].x) / 3.0, (this.points[0].y + this.points[1].y + this.points[2].y) / 3.0, (this.points[0].z + this.points[1].z + this.points[2].z) / 3.0, result);
|
|
485
584
|
}
|
|
486
585
|
/** Return the incenter of the triangle. */
|
|
@@ -502,47 +601,11 @@ class BarycentricTriangle {
|
|
|
502
601
|
const scale = Geometry_1.Geometry.safeDivideFraction(1.0, x + y + z, 0.0);
|
|
503
602
|
return this.fractionToPoint(scale * x, scale * y, scale * z, result);
|
|
504
603
|
}
|
|
505
|
-
/**
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const cross = this.points[0].crossProductToPoints(this.points[1], this.points[2], result);
|
|
511
|
-
if (cross.tryNormalizeInPlace())
|
|
512
|
-
return cross;
|
|
513
|
-
return undefined;
|
|
514
|
-
}
|
|
515
|
-
/** test for point-by-point `isAlmostEqual` relationship. */
|
|
516
|
-
isAlmostEqual(other) {
|
|
517
|
-
return this.points[0].isAlmostEqual(other.points[0])
|
|
518
|
-
&& this.points[1].isAlmostEqual(other.points[1])
|
|
519
|
-
&& this.points[2].isAlmostEqual(other.points[2]);
|
|
520
|
-
}
|
|
521
|
-
/** Compute length of the triangle edge opposite the vertex with the given index.
|
|
522
|
-
* @see edgeStartVertexIndexToOppositeVertexIndex
|
|
523
|
-
*/
|
|
524
|
-
edgeLength(oppositeVertexIndex) {
|
|
525
|
-
return Math.sqrt(this.edgeLengthSquared(oppositeVertexIndex));
|
|
526
|
-
}
|
|
527
|
-
/** Compute squared length of the triangle edge opposite the vertex with the given index.
|
|
528
|
-
* @see edgeStartVertexIndexToOppositeVertexIndex
|
|
529
|
-
*/
|
|
530
|
-
edgeLengthSquared(oppositeVertexIndex) {
|
|
531
|
-
return this.edgeLength2[Geometry_1.Geometry.cyclic3dAxis(oppositeVertexIndex)];
|
|
532
|
-
}
|
|
533
|
-
/** Compute dot product of the edge vectors based at the vertex with the given index. */
|
|
534
|
-
dotProductOfEdgeVectorsAtVertex(baseVertexIndex) {
|
|
535
|
-
const i = Geometry_1.Geometry.cyclic3dAxis(baseVertexIndex);
|
|
536
|
-
const j = Geometry_1.Geometry.cyclic3dAxis(i + 1);
|
|
537
|
-
const k = Geometry_1.Geometry.cyclic3dAxis(j + 1);
|
|
538
|
-
return Geometry_1.Geometry.dotProductXYZXYZ(this.points[j].x - this.points[i].x, this.points[j].y - this.points[i].y, this.points[j].z - this.points[i].z, this.points[k].x - this.points[i].x, this.points[k].y - this.points[i].y, this.points[k].z - this.points[i].z);
|
|
539
|
-
}
|
|
540
|
-
/** Compute the squared distance between two points given by their barycentric coordinates.
|
|
541
|
-
* * It is assumed that a0 + a1 + a2 = b0 + b1 + b2 = 1.
|
|
542
|
-
*/
|
|
543
|
-
distanceSquared(a0, a1, a2, b0, b1, b2) {
|
|
544
|
-
// the barycentric displacement vector distance formula
|
|
545
|
-
return -this.edgeLengthSquared(0) * (b1 - a1) * (b2 - a2) - this.edgeLengthSquared(1) * (b2 - a2) * (b0 - a0) - this.edgeLengthSquared(2) * (b0 - a0) * (b1 - a1);
|
|
604
|
+
/** Test for point-by-point `isAlmostEqual` relationship. */
|
|
605
|
+
isAlmostEqual(other, tol) {
|
|
606
|
+
return this.points[0].isAlmostEqual(other.points[0], tol)
|
|
607
|
+
&& this.points[1].isAlmostEqual(other.points[1], tol)
|
|
608
|
+
&& this.points[2].isAlmostEqual(other.points[2], tol);
|
|
546
609
|
}
|
|
547
610
|
}
|
|
548
611
|
exports.BarycentricTriangle = BarycentricTriangle;
|