@itwin/core-geometry 4.0.0-dev.23 → 4.0.0-dev.28

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.
Files changed (204) hide show
  1. package/CHANGELOG.md +7 -2
  2. package/lib/cjs/Geometry.d.ts +23 -0
  3. package/lib/cjs/Geometry.d.ts.map +1 -1
  4. package/lib/cjs/Geometry.js +25 -1
  5. package/lib/cjs/Geometry.js.map +1 -1
  6. package/lib/cjs/bspline/BSplineCurveOps.js +4 -5
  7. package/lib/cjs/bspline/BSplineCurveOps.js.map +1 -1
  8. package/lib/cjs/bspline/InterpolationCurve3d.js +7 -10
  9. package/lib/cjs/bspline/InterpolationCurve3d.js.map +1 -1
  10. package/lib/cjs/clipping/ClipPrimitive.js +2 -2
  11. package/lib/cjs/clipping/ClipPrimitive.js.map +1 -1
  12. package/lib/cjs/clipping/ClipUtils.js +4 -4
  13. package/lib/cjs/clipping/ClipUtils.js.map +1 -1
  14. package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
  15. package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
  16. package/lib/cjs/curve/CurveChainWithDistanceIndex.js +1 -1
  17. package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
  18. package/lib/cjs/curve/CurveCollection.js +1 -1
  19. package/lib/cjs/curve/CurveCollection.js.map +1 -1
  20. package/lib/cjs/curve/StrokeOptions.js +1 -2
  21. package/lib/cjs/curve/StrokeOptions.js.map +1 -1
  22. package/lib/cjs/curve/spiral/DirectSpiral3d.js +1 -2
  23. package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
  24. package/lib/cjs/curve/spiral/IntegratedSpiral3d.js +1 -2
  25. package/lib/cjs/curve/spiral/IntegratedSpiral3d.js.map +1 -1
  26. package/lib/cjs/geometry3d/BarycentricTriangle.d.ts +195 -8
  27. package/lib/cjs/geometry3d/BarycentricTriangle.d.ts.map +1 -1
  28. package/lib/cjs/geometry3d/BarycentricTriangle.js +459 -11
  29. package/lib/cjs/geometry3d/BarycentricTriangle.js.map +1 -1
  30. package/lib/cjs/geometry3d/GrowableFloat64Array.js +2 -2
  31. package/lib/cjs/geometry3d/GrowableFloat64Array.js.map +1 -1
  32. package/lib/cjs/geometry3d/GrowableXYArray.d.ts +1 -1
  33. package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
  34. package/lib/cjs/geometry3d/GrowableXYArray.js +2 -2
  35. package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
  36. package/lib/cjs/geometry3d/GrowableXYZArray.js +1 -1
  37. package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
  38. package/lib/cjs/geometry3d/IndexedXYCollection.d.ts +22 -7
  39. package/lib/cjs/geometry3d/IndexedXYCollection.d.ts.map +1 -1
  40. package/lib/cjs/geometry3d/IndexedXYCollection.js +41 -5
  41. package/lib/cjs/geometry3d/IndexedXYCollection.js.map +1 -1
  42. package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts +58 -4
  43. package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
  44. package/lib/cjs/geometry3d/IndexedXYZCollection.js +102 -4
  45. package/lib/cjs/geometry3d/IndexedXYZCollection.js.map +1 -1
  46. package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts +10 -0
  47. package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
  48. package/lib/cjs/geometry3d/Point2dArrayCarrier.js +14 -0
  49. package/lib/cjs/geometry3d/Point2dArrayCarrier.js.map +1 -1
  50. package/lib/cjs/geometry3d/Point2dVector2d.js +4 -6
  51. package/lib/cjs/geometry3d/Point2dVector2d.js.map +1 -1
  52. package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts +0 -6
  53. package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
  54. package/lib/cjs/geometry3d/Point3dArrayCarrier.js +0 -6
  55. package/lib/cjs/geometry3d/Point3dArrayCarrier.js.map +1 -1
  56. package/lib/cjs/geometry3d/Point3dVector3d.d.ts +1 -1
  57. package/lib/cjs/geometry3d/Point3dVector3d.js +6 -8
  58. package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
  59. package/lib/cjs/geometry3d/PointHelpers.d.ts +14 -1
  60. package/lib/cjs/geometry3d/PointHelpers.d.ts.map +1 -1
  61. package/lib/cjs/geometry3d/PointHelpers.js +33 -1
  62. package/lib/cjs/geometry3d/PointHelpers.js.map +1 -1
  63. package/lib/cjs/geometry3d/PolygonOps.d.ts +120 -10
  64. package/lib/cjs/geometry3d/PolygonOps.d.ts.map +1 -1
  65. package/lib/cjs/geometry3d/PolygonOps.js +413 -13
  66. package/lib/cjs/geometry3d/PolygonOps.js.map +1 -1
  67. package/lib/cjs/geometry3d/Ray3d.js +1 -1
  68. package/lib/cjs/geometry3d/Ray3d.js.map +1 -1
  69. package/lib/cjs/polyface/AuxData.js +1 -1
  70. package/lib/cjs/polyface/AuxData.js.map +1 -1
  71. package/lib/cjs/polyface/FacetLocationDetail.d.ts +264 -0
  72. package/lib/cjs/polyface/FacetLocationDetail.d.ts.map +1 -0
  73. package/lib/cjs/polyface/FacetLocationDetail.js +376 -0
  74. package/lib/cjs/polyface/FacetLocationDetail.js.map +1 -0
  75. package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
  76. package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
  77. package/lib/cjs/polyface/IndexedPolyfaceVisitor.js +5 -2
  78. package/lib/cjs/polyface/IndexedPolyfaceVisitor.js.map +1 -1
  79. package/lib/cjs/polyface/PolyfaceBuilder.d.ts +20 -14
  80. package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
  81. package/lib/cjs/polyface/PolyfaceBuilder.js +21 -17
  82. package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
  83. package/lib/cjs/polyface/PolyfaceClip.js +6 -7
  84. package/lib/cjs/polyface/PolyfaceClip.js.map +1 -1
  85. package/lib/cjs/polyface/PolyfaceData.d.ts +1 -1
  86. package/lib/cjs/polyface/PolyfaceData.d.ts.map +1 -1
  87. package/lib/cjs/polyface/PolyfaceData.js.map +1 -1
  88. package/lib/cjs/polyface/PolyfaceQuery.d.ts +22 -1
  89. package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
  90. package/lib/cjs/polyface/PolyfaceQuery.js +52 -2
  91. package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
  92. package/lib/cjs/serialization/BGFBReader.js +4 -4
  93. package/lib/cjs/serialization/BGFBReader.js.map +1 -1
  94. package/lib/cjs/serialization/IModelJsonSchema.js +1 -2
  95. package/lib/cjs/serialization/IModelJsonSchema.js.map +1 -1
  96. package/lib/cjs/solid/Sphere.d.ts +5 -5
  97. package/lib/cjs/solid/Sphere.js +5 -5
  98. package/lib/cjs/solid/Sphere.js.map +1 -1
  99. package/lib/cjs/solid/SweepContour.js +1 -1
  100. package/lib/cjs/solid/SweepContour.js.map +1 -1
  101. package/lib/cjs/topology/Triangulation.js +1 -1
  102. package/lib/cjs/topology/Triangulation.js.map +1 -1
  103. package/lib/esm/Geometry.d.ts +23 -0
  104. package/lib/esm/Geometry.d.ts.map +1 -1
  105. package/lib/esm/Geometry.js +24 -0
  106. package/lib/esm/Geometry.js.map +1 -1
  107. package/lib/esm/bspline/BSplineCurveOps.js +4 -5
  108. package/lib/esm/bspline/BSplineCurveOps.js.map +1 -1
  109. package/lib/esm/bspline/InterpolationCurve3d.js +7 -10
  110. package/lib/esm/bspline/InterpolationCurve3d.js.map +1 -1
  111. package/lib/esm/clipping/ClipPrimitive.js +2 -2
  112. package/lib/esm/clipping/ClipPrimitive.js.map +1 -1
  113. package/lib/esm/clipping/ClipUtils.js +4 -4
  114. package/lib/esm/clipping/ClipUtils.js.map +1 -1
  115. package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
  116. package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
  117. package/lib/esm/curve/CurveChainWithDistanceIndex.js +1 -1
  118. package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
  119. package/lib/esm/curve/CurveCollection.js +1 -1
  120. package/lib/esm/curve/CurveCollection.js.map +1 -1
  121. package/lib/esm/curve/StrokeOptions.js +1 -2
  122. package/lib/esm/curve/StrokeOptions.js.map +1 -1
  123. package/lib/esm/curve/spiral/DirectSpiral3d.js +1 -2
  124. package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
  125. package/lib/esm/curve/spiral/IntegratedSpiral3d.js +1 -2
  126. package/lib/esm/curve/spiral/IntegratedSpiral3d.js.map +1 -1
  127. package/lib/esm/geometry3d/BarycentricTriangle.d.ts +195 -8
  128. package/lib/esm/geometry3d/BarycentricTriangle.d.ts.map +1 -1
  129. package/lib/esm/geometry3d/BarycentricTriangle.js +459 -12
  130. package/lib/esm/geometry3d/BarycentricTriangle.js.map +1 -1
  131. package/lib/esm/geometry3d/GrowableFloat64Array.js +2 -2
  132. package/lib/esm/geometry3d/GrowableFloat64Array.js.map +1 -1
  133. package/lib/esm/geometry3d/GrowableXYArray.d.ts +1 -1
  134. package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
  135. package/lib/esm/geometry3d/GrowableXYArray.js +2 -2
  136. package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
  137. package/lib/esm/geometry3d/GrowableXYZArray.js +1 -1
  138. package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
  139. package/lib/esm/geometry3d/IndexedXYCollection.d.ts +22 -7
  140. package/lib/esm/geometry3d/IndexedXYCollection.d.ts.map +1 -1
  141. package/lib/esm/geometry3d/IndexedXYCollection.js +41 -5
  142. package/lib/esm/geometry3d/IndexedXYCollection.js.map +1 -1
  143. package/lib/esm/geometry3d/IndexedXYZCollection.d.ts +58 -4
  144. package/lib/esm/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
  145. package/lib/esm/geometry3d/IndexedXYZCollection.js +103 -5
  146. package/lib/esm/geometry3d/IndexedXYZCollection.js.map +1 -1
  147. package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts +10 -0
  148. package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
  149. package/lib/esm/geometry3d/Point2dArrayCarrier.js +14 -0
  150. package/lib/esm/geometry3d/Point2dArrayCarrier.js.map +1 -1
  151. package/lib/esm/geometry3d/Point2dVector2d.js +4 -6
  152. package/lib/esm/geometry3d/Point2dVector2d.js.map +1 -1
  153. package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts +0 -6
  154. package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
  155. package/lib/esm/geometry3d/Point3dArrayCarrier.js +0 -6
  156. package/lib/esm/geometry3d/Point3dArrayCarrier.js.map +1 -1
  157. package/lib/esm/geometry3d/Point3dVector3d.d.ts +1 -1
  158. package/lib/esm/geometry3d/Point3dVector3d.js +6 -8
  159. package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
  160. package/lib/esm/geometry3d/PointHelpers.d.ts +14 -1
  161. package/lib/esm/geometry3d/PointHelpers.d.ts.map +1 -1
  162. package/lib/esm/geometry3d/PointHelpers.js +33 -1
  163. package/lib/esm/geometry3d/PointHelpers.js.map +1 -1
  164. package/lib/esm/geometry3d/PolygonOps.d.ts +120 -10
  165. package/lib/esm/geometry3d/PolygonOps.d.ts.map +1 -1
  166. package/lib/esm/geometry3d/PolygonOps.js +412 -13
  167. package/lib/esm/geometry3d/PolygonOps.js.map +1 -1
  168. package/lib/esm/geometry3d/Ray3d.js +1 -1
  169. package/lib/esm/geometry3d/Ray3d.js.map +1 -1
  170. package/lib/esm/polyface/AuxData.js +1 -1
  171. package/lib/esm/polyface/AuxData.js.map +1 -1
  172. package/lib/esm/polyface/FacetLocationDetail.d.ts +264 -0
  173. package/lib/esm/polyface/FacetLocationDetail.d.ts.map +1 -0
  174. package/lib/esm/polyface/FacetLocationDetail.js +369 -0
  175. package/lib/esm/polyface/FacetLocationDetail.js.map +1 -0
  176. package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
  177. package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
  178. package/lib/esm/polyface/IndexedPolyfaceVisitor.js +5 -2
  179. package/lib/esm/polyface/IndexedPolyfaceVisitor.js.map +1 -1
  180. package/lib/esm/polyface/PolyfaceBuilder.d.ts +20 -14
  181. package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
  182. package/lib/esm/polyface/PolyfaceBuilder.js +21 -17
  183. package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
  184. package/lib/esm/polyface/PolyfaceClip.js +6 -7
  185. package/lib/esm/polyface/PolyfaceClip.js.map +1 -1
  186. package/lib/esm/polyface/PolyfaceData.d.ts +1 -1
  187. package/lib/esm/polyface/PolyfaceData.d.ts.map +1 -1
  188. package/lib/esm/polyface/PolyfaceData.js.map +1 -1
  189. package/lib/esm/polyface/PolyfaceQuery.d.ts +22 -1
  190. package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
  191. package/lib/esm/polyface/PolyfaceQuery.js +52 -2
  192. package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
  193. package/lib/esm/serialization/BGFBReader.js +4 -4
  194. package/lib/esm/serialization/BGFBReader.js.map +1 -1
  195. package/lib/esm/serialization/IModelJsonSchema.js +1 -2
  196. package/lib/esm/serialization/IModelJsonSchema.js.map +1 -1
  197. package/lib/esm/solid/Sphere.d.ts +5 -5
  198. package/lib/esm/solid/Sphere.js +5 -5
  199. package/lib/esm/solid/Sphere.js.map +1 -1
  200. package/lib/esm/solid/SweepContour.js +1 -1
  201. package/lib/esm/solid/SweepContour.js.map +1 -1
  202. package/lib/esm/topology/Triangulation.js +1 -1
  203. package/lib/esm/topology/Triangulation.js.map +1 -1
  204. package/package.json +4 -4
@@ -5,10 +5,98 @@
5
5
  /** @packageDocumentation
6
6
  * @module CartesianGeometry
7
7
  */
8
- import { Geometry } from "../Geometry";
9
- import { Point3d } from "./Point3dVector3d";
8
+ import { assert } from "@itwin/core-bentley";
9
+ import { Geometry, PolygonLocation } from "../Geometry";
10
+ import { Matrix3d } from "./Matrix3d";
11
+ import { Point3d, Vector3d } from "./Point3dVector3d";
12
+ import { Ray3d } from "./Ray3d";
10
13
  /**
11
- * 3 points defining a triangle to be evaluated with Barycentric coordinates.
14
+ * Carries data about a location in the plane of a triangle.
15
+ * * Each instance carries both world and barycentric coordinates for the point, and provides query services on the latter.
16
+ * * No tolerance is used when querying barycentric coordinates (e.g., `isInsideOrOn`, `classify`). Use `snapLocalToEdge`
17
+ * to adjust the barycentric coordinates to a triangle edge if they lie within a parametric tolerance.
18
+ *
19
+ * Properties of the barycentric coordinates (b0, b1, b2) of a point p in the plane of a triangle T with vertices p0, p1, p2:
20
+ * * 1 = b0 + b1 + b2
21
+ * * p = b0 * p0 + b1 * p1 + b2 * p2
22
+ * * If T is spanned by the vectors U=p1-p0 and V=p2-p0, then the vector P=p-p0 can be written P = b1 * U + b2 * V.
23
+ * * The coordinates are all nonnegative if and only if p is inside or on T.
24
+ * * Exactly one coordinate is zero if and only if p lies on an (infinitely extended) edge of T.
25
+ * * Exactly two coordinates are zero if and only if p coincides with a vertex of T.
26
+ * @public
27
+ */
28
+ export class TriangleLocationDetail {
29
+ constructor() {
30
+ this.world = new Point3d();
31
+ this.local = new Point3d();
32
+ this.a = 0.0;
33
+ this.closestEdgeIndex = 0;
34
+ this.closestEdgeParam = 0.0;
35
+ }
36
+ /** Invalidate this detail. */
37
+ invalidate() {
38
+ this.world.setZero();
39
+ this.local.setZero();
40
+ this.a = 0.0;
41
+ this.closestEdgeIndex = 0;
42
+ this.closestEdgeParam = 0.0;
43
+ }
44
+ /** Create an invalid detail.
45
+ * @param result optional pre-allocated object to fill and return
46
+ */
47
+ static create(result) {
48
+ if (undefined === result)
49
+ result = new TriangleLocationDetail();
50
+ else
51
+ result.invalidate();
52
+ return result;
53
+ }
54
+ /** Set the instance contents from the other detail.
55
+ * @param other detail to clone
56
+ */
57
+ copyContentsFrom(other) {
58
+ this.world.setFrom(other.world);
59
+ this.local.setFrom(other.local);
60
+ this.a = other.a;
61
+ this.closestEdgeIndex = other.closestEdgeIndex;
62
+ this.closestEdgeParam = other.closestEdgeParam;
63
+ }
64
+ /** Whether this detail is invalid. */
65
+ get isValid() {
66
+ return !this.local.isZero;
67
+ }
68
+ /** Queries the barycentric coordinates to determine whether this instance specifies a location inside or on the triangle.
69
+ * @see classify
70
+ */
71
+ get isInsideOrOn() {
72
+ return this.isValid && this.local.x >= 0.0 && this.local.y >= 0.0 && this.local.z >= 0.0;
73
+ }
74
+ /** Queries this detail to classify the location of this instance with respect to the triangle.
75
+ * @returns location code
76
+ * @see isInsideOrOn
77
+ */
78
+ get classify() {
79
+ if (!this.isValid)
80
+ return PolygonLocation.Unknown;
81
+ if (this.isInsideOrOn) {
82
+ let numZero = 0;
83
+ if (Math.abs(this.local.x) === 0.0)
84
+ ++numZero;
85
+ if (Math.abs(this.local.y) === 0.0)
86
+ ++numZero;
87
+ if (Math.abs(this.local.z) === 0.0)
88
+ ++numZero;
89
+ if (2 === numZero)
90
+ return PolygonLocation.OnPolygonVertex;
91
+ if (1 === numZero)
92
+ return PolygonLocation.OnPolygonEdgeInterior;
93
+ return PolygonLocation.InsidePolygonProjectsToEdgeInterior;
94
+ }
95
+ return (this.closestEdgeParam === 0.0) ? PolygonLocation.OutsidePolygonProjectsToVertex : PolygonLocation.OutsidePolygonProjectsToEdgeInterior;
96
+ }
97
+ }
98
+ /**
99
+ * 3 points defining a triangle to be evaluated with barycentric coordinates.
12
100
  * @public
13
101
  */
14
102
  export class BarycentricTriangle {
@@ -20,6 +108,10 @@ export class BarycentricTriangle {
20
108
  this.points.push(point0);
21
109
  this.points.push(point1);
22
110
  this.points.push(point2);
111
+ this.edgeLength2 = [];
112
+ this.edgeLength2.push(point1.distanceSquared(point2));
113
+ this.edgeLength2.push(point0.distanceSquared(point2));
114
+ this.edgeLength2.push(point0.distanceSquared(point1));
23
115
  }
24
116
  /**
25
117
  * Return a `BarycentricTriangle` with coordinates given by enumerated x,y,z of the 3 points.
@@ -46,31 +138,331 @@ export class BarycentricTriangle {
46
138
  }
47
139
  /** Return area divided by sum of squared lengths. */
48
140
  get aspectRatio() {
49
- return Geometry.safeDivideFraction(0.5 * this.points[0].crossProductToPointsMagnitude(this.points[1], this.points[2]), (this.points[0].distanceSquared(this.points[1]) + this.points[1].distanceSquared(this.points[2]) + this.points[2].distanceSquared(this.points[0])), 0);
141
+ return Geometry.safeDivideFraction(this.area, this.edgeLengthSquared(0) + this.edgeLengthSquared(1) + this.edgeLengthSquared(2), 0);
50
142
  }
51
143
  /** Return the area of the triangle. */
52
144
  get area() {
53
145
  return 0.5 * this.points[0].crossProductToPointsMagnitude(this.points[1], this.points[2]);
54
146
  }
147
+ /** Return the perimeter of the triangle */
148
+ get perimeter() {
149
+ return this.edgeLength(0) + this.edgeLength(1) + this.edgeLength(2);
150
+ }
55
151
  /** Sum the points with given scales.
56
- * * In normal use, the scales will add to 1 and the result point is in the plane of the triangle.
57
- * * If scales do not add to 1, the point is in the triangle scaled (by the scale sum) from the origin.
152
+ * * If the scales sum to 1, they are barycentric coordinates, and hence the result point is in the plane of the triangle.
153
+ * * If the scales do not sum to 1, the point is in the triangle scaled (by the scale sum) from the origin.
154
+ * @param b0 scale to apply to vertex 0
155
+ * @param b1 scale to apply to vertex 1
156
+ * @param b2 scale to apply to vertex 2
157
+ * @param result optional pre-allocated point to fill and return
158
+ * @return linear combination of the vertices of this triangle
159
+ * @see pointToFraction
160
+ */
161
+ fractionToPoint(b0, b1, b2, result) {
162
+ return Point3d.createAdd3Scaled(this.points[0], b0, this.points[1], b1, this.points[2], b2, result);
163
+ }
164
+ /** Compute the projection of the given point onto the plane of this triangle.
165
+ * @param point point p to project
166
+ * @param result optional pre-allocated object to fill and return
167
+ * @returns details d of the projection point P = `d.point`:
168
+ * * `d.isValid` returns true if and only if `this.normal()` is defined.
169
+ * * `d.classify` can be used to determine where P lies with respect to the triangle.
170
+ * * `d.a` is the signed projection distance: P = p + a * `this.normal()`.
171
+ * @see fractionToPoint
172
+ */
173
+ pointToFraction(point, result) {
174
+ const normal = BarycentricTriangle._workVector0 = this.normal(BarycentricTriangle._workVector0);
175
+ if (undefined === normal)
176
+ return TriangleLocationDetail.create(result);
177
+ const ray = BarycentricTriangle._workRay = Ray3d.create(point, normal, BarycentricTriangle._workRay);
178
+ return this.intersectRay3d(ray, result); // is free to use workVector0
179
+ }
180
+ /** Convert from opposite-vertex to start-vertex edge indexing. */
181
+ static edgeOppositeVertexIndexToStartVertexIndex(edgeIndex) {
182
+ return Geometry.cyclic3dAxis(edgeIndex + 1);
183
+ }
184
+ /** Convert from start-vertex to opposite-vertex edge indexing. */
185
+ static edgeStartVertexIndexToOppositeVertexIndex(startVertexIndex) {
186
+ return Geometry.cyclic3dAxis(startVertexIndex - 1);
187
+ }
188
+ /** Examine a point's barycentric coordinates to determine if it lies inside the triangle but not on an edge/vertex.
189
+ * * No parametric tolerance is used.
190
+ * * It is assumed b0 + b1 + b2 = 1.
191
+ * @returns whether the point with barycentric coordinates is strictly inside the triangle.
192
+ */
193
+ static isInsideTriangle(b0, b1, b2) {
194
+ return b0 > 0 && b1 > 0 && b2 > 0;
195
+ }
196
+ /** Examine a point's barycentric coordinates to determine if it lies inside the triangle or on an edge/vertex.
197
+ * * No parametric tolerance is used.
198
+ * * It is assumed b0 + b1 + b2 = 1.
199
+ * @returns whether the point with barycentric coordinates is inside or on the triangle.
200
+ */
201
+ static isInsideOrOnTriangle(b0, b1, b2) {
202
+ return b0 >= 0 && b1 >= 0 && b2 >= 0;
203
+ }
204
+ /** Examine a point's barycentric coordinates to determine if it lies "outside" an edge of the triangle.
205
+ * * No parametric tolerance is used.
206
+ * * It is assumed b0 + b1 + b2 = 1.
207
+ * @returns index of vertex/edge i for which b_i < 0 and b_j >= 0 and b_k >= 0, or -1
58
208
  */
59
- fractionToPoint(a0, a1, a2, result) {
60
- return Point3d.createAdd3Scaled(this.points[0], a0, this.points[1], a1, this.points[2], a2, result);
209
+ static isInRegionBeyondEdge(b0, b1, b2) {
210
+ if (b0 < 0 && b1 >= 0 && b2 >= 0)
211
+ return 0;
212
+ if (b0 >= 0 && b1 < 0 && b2 >= 0)
213
+ return 1;
214
+ if (b0 >= 0 && b1 >= 0 && b2 < 0)
215
+ return 2;
216
+ return -1;
217
+ }
218
+ /** Examine a point's barycentric coordinates to determine if it lies "outside" a vertex of the triangle.
219
+ * * No parametric tolerance is used.
220
+ * * It is assumed b0 + b1 + b2 = 1.
221
+ * @returns index of vertex i for which and b_j < 0 and b_k < 0, or -1
222
+ */
223
+ static isInRegionBeyondVertex(b0, b1, b2) {
224
+ if (b1 < 0 && b2 < 0)
225
+ return 0;
226
+ if (b0 < 0 && b2 < 0)
227
+ return 1;
228
+ if (b0 < 0 && b1 < 0)
229
+ return 2;
230
+ return -1;
231
+ }
232
+ /** Examine a point's barycentric coordinates to determine if it lies on a vertex of the triangle.
233
+ * * No parametric tolerance is used.
234
+ * * It is assumed b0 + b1 + b2 = 1.
235
+ * @returns index of vertex i for which b_i = 1 and b_j = b_k = 0, or -1
236
+ */
237
+ static isOnVertex(b0, b1, b2) {
238
+ if (b0 === 1 && b1 === 0 && b2 === 0)
239
+ return 0;
240
+ if (b0 === 0 && b1 === 1 && b2 === 0)
241
+ return 1;
242
+ if (b0 === 0 && b1 === 0 && b2 === 1)
243
+ return 2;
244
+ return -1;
245
+ }
246
+ /** Examine a point's barycentric coordinates to determine if it lies on a bounded edge of the triangle.
247
+ * * No parametric tolerance is used.
248
+ * * It is assumed b0 + b1 + b2 = 1.
249
+ * @returns index of vertex/edge i for which b_i = 0 and b_j > 0 and b_k > 0, or -1
250
+ */
251
+ static isOnBoundedEdge(b0, b1, b2) {
252
+ if (b0 === 0 && b1 > 0 && b2 > 0)
253
+ return 0;
254
+ if (b0 > 0 && b1 === 0 && b2 > 0)
255
+ return 1;
256
+ if (b0 > 0 && b1 > 0 && b2 === 0)
257
+ return 2;
258
+ return -1;
259
+ }
260
+ /** @returns edge/vertex index (0,1,2) for which the function has a minimum value */
261
+ static indexOfMinimum(fn) {
262
+ let i = 0;
263
+ let min = fn(0);
264
+ const val = fn(1);
265
+ if (min > val) {
266
+ i = 1;
267
+ min = val;
268
+ }
269
+ if (min > fn(2))
270
+ i = 2;
271
+ return i;
272
+ }
273
+ /** Return the index of the closest triangle vertex to the point given by its barycentric coordinates. */
274
+ closestVertexIndex(b0, b1, b2) {
275
+ return BarycentricTriangle.indexOfMinimum((i) => {
276
+ const a = BarycentricTriangle._workPoint = Point3d.createZero(BarycentricTriangle._workPoint);
277
+ a.setAt(i, 1.0);
278
+ return this.distanceSquared(a.x, a.y, a.z, b0, b1, b2);
279
+ });
280
+ }
281
+ /** 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).
282
+ * @param k vertex v_k is opposite the edge e_k
283
+ * @param b barycentric coordinates of point to project
284
+ * @returns parameter s along e_k, such that:
285
+ * * the projection point is q = v_i + s * (v_j - v_i)
286
+ * * the barycentric coords of the projection are q_ijk = (1 - s, s, 0)
287
+ */
288
+ computeProjectionToEdge(k, b) {
289
+ // Let U=v_j-v_i and V=v_k-v_i. Then
290
+ // 0 = (p-q).(v_j-v_i) = ((p-v_i)-(q-v_i)).(v_j-v_i) = (b[j]U + b[k]V - sU).U = b[j]U.U + b[k]U.V - sU.U
291
+ // Thus s = b[j] + b[k]U.V/U.U
292
+ k = Geometry.cyclic3dAxis(k);
293
+ const i = Geometry.cyclic3dAxis(k + 1);
294
+ const j = Geometry.cyclic3dAxis(i + 1);
295
+ return b[j] + b[k] * this.dotProductOfEdgeVectorsAtVertex(i) / this.edgeLengthSquared(k);
296
+ }
297
+ /** Compute the projection of a barycentric point p to the triangle T(v_0,v_1,v_2).
298
+ * @param b0 barycentric coordinate of p corresponding to v_0
299
+ * @param b1 barycentric coordinate of p corresponding to v_1
300
+ * @param b2 barycentric coordinate of p corresponding to v_2
301
+ * @returns closest edge start vertex index i and projection parameter u such that the projection q = v_i + u * (v_j - v_i).
302
+ */
303
+ closestPoint(b0, b1, b2) {
304
+ const b = [b0, b1, b2];
305
+ let edgeIndex = -1; // opposite-vertex index
306
+ let edgeParam = 0.0;
307
+ if (BarycentricTriangle.isInsideTriangle(b0, b1, b2)) { // projects to any edge
308
+ edgeIndex = BarycentricTriangle.indexOfMinimum((i) => {
309
+ // We want smallest projection distance d_i of p to e_i.
310
+ // Since b[i]=d_i|e_i|/2A we can compare quantities b[i]/|e_i|.
311
+ return b[i] * b[i] / this.edgeLengthSquared(i); // avoid sqrt
312
+ });
313
+ edgeParam = this.computeProjectionToEdge(edgeIndex, b);
314
+ }
315
+ else if ((edgeIndex = BarycentricTriangle.isInRegionBeyondVertex(b0, b1, b2)) >= 0) { // projects to other edges, or any vertex
316
+ edgeIndex = Geometry.cyclic3dAxis(edgeIndex + 1);
317
+ edgeParam = this.computeProjectionToEdge(edgeIndex, b);
318
+ if (edgeParam < 0 || edgeParam > 1) {
319
+ edgeIndex = Geometry.cyclic3dAxis(edgeIndex + 1);
320
+ edgeParam = this.computeProjectionToEdge(edgeIndex, b);
321
+ if (edgeParam < 0 || edgeParam > 1) {
322
+ edgeParam = 0.0;
323
+ edgeIndex = BarycentricTriangle.edgeStartVertexIndexToOppositeVertexIndex(this.closestVertexIndex(b0, b1, b2));
324
+ }
325
+ }
326
+ }
327
+ else if ((edgeIndex = BarycentricTriangle.isInRegionBeyondEdge(b0, b1, b2)) >= 0) { // projects to the edge or its vertices
328
+ edgeParam = this.computeProjectionToEdge(edgeIndex, b);
329
+ if (edgeParam < 0) {
330
+ edgeParam = 0.0; // start of this edge
331
+ }
332
+ else if (edgeParam > 1) {
333
+ edgeParam = 0.0;
334
+ edgeIndex = Geometry.cyclic3dAxis(edgeIndex + 1); // end of this edge = start of next edge
335
+ }
336
+ }
337
+ else if ((edgeIndex = BarycentricTriangle.isOnBoundedEdge(b0, b1, b2)) >= 0) {
338
+ edgeParam = 1 - b[BarycentricTriangle.edgeOppositeVertexIndexToStartVertexIndex(edgeIndex)];
339
+ }
340
+ else if ((edgeIndex = BarycentricTriangle.isOnVertex(b0, b1, b2)) >= 0) {
341
+ edgeParam = 0.0;
342
+ edgeIndex = BarycentricTriangle.edgeStartVertexIndexToOppositeVertexIndex(edgeIndex);
343
+ }
344
+ // invalid edgeIndex shouldn't happen, but propagate it anyway
345
+ assert(edgeIndex === 0 || edgeIndex === 1 || edgeIndex === 2);
346
+ return {
347
+ closestEdgeIndex: (edgeIndex < 0) ? -1 : BarycentricTriangle.edgeOppositeVertexIndexToStartVertexIndex(edgeIndex),
348
+ closestEdgeParam: edgeParam,
349
+ };
350
+ }
351
+ /** Compute the intersection of a line (parameterized as a ray) with the plane of this triangle.
352
+ * @param ray infinite line to intersect, as a ray
353
+ * @param result optional pre-allocated object to fill and return
354
+ * @returns details d of the line-plane intersection `d.point`:
355
+ * * `d.isValid` returns true if and only if the line intersects the plane.
356
+ * * `d.classify` can be used to determine where the intersection lies with respect to the triangle.
357
+ * * `d.a` is the intersection parameter. If `d.a` >= 0, the ray intersects the plane of the triangle.
358
+ * @see pointToFraction
359
+ */
360
+ intersectRay3d(ray, result) {
361
+ result = TriangleLocationDetail.create(result);
362
+ // Let r0 = ray.origin, d = ray.direction. Write intersection point p two ways for unknown scalars s,b0,b1,b2:
363
+ // r0 + s*d = p = b0*p0 + b1*p1 + b2*p2
364
+ // Subtract p0 from both ends, let u=p1-p0, v=p2-p0, c=r0-p0, and enforce b0+b1+b2=1:
365
+ // b1*u + b2*v - s*d = c
366
+ // This is a linear system Mx=c where M has columns u,v,d and solution x=(b1,b2,-s).
367
+ const r0 = ray.origin;
368
+ const d = ray.direction;
369
+ const u = BarycentricTriangle._workVector0 = Vector3d.createStartEnd(this.points[0], this.points[1], BarycentricTriangle._workVector0);
370
+ const v = BarycentricTriangle._workVector1 = Vector3d.createStartEnd(this.points[0], this.points[2], BarycentricTriangle._workVector1);
371
+ const M = BarycentricTriangle._workMatrix = Matrix3d.createColumns(u, v, d, BarycentricTriangle._workMatrix);
372
+ const c = Vector3d.createStartEnd(this.points[0], r0, BarycentricTriangle._workVector0); // reuse workVector0
373
+ const solution = BarycentricTriangle._workVector1; // reuse workVector1
374
+ if (undefined === M.multiplyInverse(c, solution))
375
+ return result; // invalid
376
+ result.a = -solution.z;
377
+ ray.fractionToPoint(result.a, result.world);
378
+ result.local.set(1.0 - solution.x - solution.y, solution.x, solution.y);
379
+ const proj = this.closestPoint(result.local.x, result.local.y, result.local.z);
380
+ result.closestEdgeIndex = proj.closestEdgeIndex;
381
+ result.closestEdgeParam = proj.closestEdgeParam;
382
+ return result;
383
+ }
384
+ /** Compute the intersection of a line (parameterized as a line segment) with the plane of this triangle.
385
+ * @param point0 start point of segment on line to intersect
386
+ * @param point1 end point of segment on line to intersect
387
+ * @param result optional pre-allocated object to fill and return
388
+ * @returns details d of the line-plane intersection `d.point`:
389
+ * * `d.isValid` returns true if and only if the line intersects the plane.
390
+ * * `d.classify` can be used to determine where the intersection lies with respect to the triangle.
391
+ * * `d.a` is the intersection parameter. If `d.a` is in [0,1], the segment intersects the plane of the triangle.
392
+ * @see intersectRay3d
393
+ */
394
+ intersectSegment(point0, point1, result) {
395
+ BarycentricTriangle._workRay = Ray3d.createStartEnd(point0, point1, BarycentricTriangle._workRay);
396
+ return this.intersectRay3d(BarycentricTriangle._workRay, result);
397
+ }
398
+ /** Adjust the location to an edge of the triangle if within either given tolerance.
399
+ * @param location details of a point in the plane of the triangle, `location.local` and `location.world` possibly updated to lie on a triangle edge
400
+ * @param distanceTolerance absolute distance tolerance (or zero to ignore)
401
+ * @param parameterTolerance barycentric coordinate fractional tolerance (or zero to ignore)
402
+ * @return whether the location was adjusted
403
+ */
404
+ snapLocationToEdge(location, distanceTolerance = Geometry.smallMetricDistance, parameterTolerance = Geometry.smallFraction) {
405
+ if (!location.isValid)
406
+ return false;
407
+ // first try parametric tol to zero barycentric coordinate (no vertices or world distances used!)
408
+ if (parameterTolerance > 0.0) {
409
+ let numSnapped = 0;
410
+ let newSum = 0.0;
411
+ for (let i = 0; i < 3; i++) {
412
+ const barycentricDist = Math.abs(location.local.at(i));
413
+ if (barycentricDist > 0.0 && barycentricDist < parameterTolerance) {
414
+ location.local.setAt(i, 0.0);
415
+ numSnapped++;
416
+ }
417
+ newSum += location.local.at(i);
418
+ }
419
+ if (numSnapped > 0 && newSum > 0.0) {
420
+ location.local.scaleInPlace(1.0 / newSum);
421
+ if (1 === numSnapped) {
422
+ location.closestEdgeIndex = BarycentricTriangle.edgeOppositeVertexIndexToStartVertexIndex(BarycentricTriangle.isOnBoundedEdge(location.local.x, location.local.y, location.local.z));
423
+ location.closestEdgeParam = 1.0 - location.local.at(location.closestEdgeIndex);
424
+ }
425
+ else { // 2 snapped, at vertex
426
+ location.closestEdgeIndex = BarycentricTriangle.isOnVertex(location.local.x, location.local.y, location.local.z);
427
+ location.closestEdgeParam = 0.0;
428
+ }
429
+ this.fractionToPoint(location.local.x, location.local.y, location.local.z, location.world);
430
+ return true;
431
+ }
432
+ }
433
+ // failing that, try distance tol to closest edge projection
434
+ if (distanceTolerance > 0.0) {
435
+ const i = location.closestEdgeIndex;
436
+ const j = (i + 1) % 3;
437
+ const k = (j + 1) % 3;
438
+ const edgeProjection = BarycentricTriangle._workPoint = this.points[i].interpolate(location.closestEdgeParam, this.points[j], BarycentricTriangle._workPoint);
439
+ const dist = location.world.distance(edgeProjection);
440
+ if (dist > 0.0 && dist < distanceTolerance) {
441
+ location.local.setAt(i, 1.0 - location.closestEdgeParam);
442
+ location.local.setAt(j, location.closestEdgeParam);
443
+ location.local.setAt(k, 0.0);
444
+ location.world.setFrom(edgeProjection);
445
+ return true;
446
+ }
447
+ }
448
+ return false;
61
449
  }
62
450
  /** Copy all values from `other`
63
451
  */
64
452
  setFrom(other) {
65
- this.points[0].setFromPoint3d(other.points[0]);
66
- this.points[1].setFromPoint3d(other.points[1]);
67
- this.points[2].setFromPoint3d(other.points[2]);
453
+ for (let i = 0; i < 3; ++i) {
454
+ this.points[i].setFromPoint3d(other.points[i]);
455
+ this.edgeLength2[i] = other.edgeLength2[i];
456
+ }
68
457
  }
69
- /** copy contents of (not pointers to) the given points. */
458
+ /** Copy contents of (not pointers to) the given points. A vertex is zeroed if its corresponding input point is undefined. */
70
459
  set(point0, point1, point2) {
71
460
  this.points[0].setFromPoint3d(point0);
72
461
  this.points[1].setFromPoint3d(point1);
73
462
  this.points[2].setFromPoint3d(point2);
463
+ this.edgeLength2[0] = this.points[1].distanceSquared(this.points[2]);
464
+ this.edgeLength2[1] = this.points[0].distanceSquared(this.points[2]);
465
+ this.edgeLength2[2] = this.points[0].distanceSquared(this.points[1]);
74
466
  }
75
467
  /**
76
468
  * * For `this` and `other` BarycentricTriangles, compute cross products of vectors from point0 to point1 and from point0 to point2.
@@ -87,11 +479,66 @@ export class BarycentricTriangle {
87
479
  // Do the scale as true division (rather than multiply by precomputed 1/3). This might protect one bit of result.
88
480
  return 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);
89
481
  }
482
+ /** Return the incenter of the triangle. */
483
+ incenter(result) {
484
+ const a = this.edgeLength(0);
485
+ const b = this.edgeLength(1);
486
+ const c = this.edgeLength(2);
487
+ const scale = Geometry.safeDivideFraction(1.0, a + b + c, 0.0);
488
+ return this.fractionToPoint(scale * a, scale * b, scale * c, result);
489
+ }
490
+ /** Return the circumcenter of the triangle. */
491
+ circumcenter(result) {
492
+ const a2 = this.edgeLengthSquared(0);
493
+ const b2 = this.edgeLengthSquared(1);
494
+ const c2 = this.edgeLengthSquared(2);
495
+ const x = a2 * (b2 + c2 - a2);
496
+ const y = b2 * (c2 + a2 - b2);
497
+ const z = c2 * (a2 + b2 - c2);
498
+ const scale = Geometry.safeDivideFraction(1.0, x + y + z, 0.0);
499
+ return this.fractionToPoint(scale * x, scale * y, scale * z, result);
500
+ }
501
+ /** Return the unit normal of the triangle.
502
+ * @param result optional pre-allocated vector to fill and return.
503
+ * @returns unit normal, or undefined if cross product length is too small.
504
+ */
505
+ normal(result) {
506
+ const cross = this.points[0].crossProductToPoints(this.points[1], this.points[2], result);
507
+ if (cross.tryNormalizeInPlace())
508
+ return cross;
509
+ return undefined;
510
+ }
90
511
  /** test for point-by-point `isAlmostEqual` relationship. */
91
512
  isAlmostEqual(other) {
92
513
  return this.points[0].isAlmostEqual(other.points[0])
93
514
  && this.points[1].isAlmostEqual(other.points[1])
94
515
  && this.points[2].isAlmostEqual(other.points[2]);
95
516
  }
517
+ /** Compute length of the triangle edge opposite the vertex with the given index.
518
+ * @see edgeStartVertexIndexToOppositeVertexIndex
519
+ */
520
+ edgeLength(oppositeVertexIndex) {
521
+ return Math.sqrt(this.edgeLengthSquared(oppositeVertexIndex));
522
+ }
523
+ /** Compute squared length of the triangle edge opposite the vertex with the given index.
524
+ * @see edgeStartVertexIndexToOppositeVertexIndex
525
+ */
526
+ edgeLengthSquared(oppositeVertexIndex) {
527
+ return this.edgeLength2[Geometry.cyclic3dAxis(oppositeVertexIndex)];
528
+ }
529
+ /** Compute dot product of the edge vectors based at the vertex with the given index. */
530
+ dotProductOfEdgeVectorsAtVertex(baseVertexIndex) {
531
+ const i = Geometry.cyclic3dAxis(baseVertexIndex);
532
+ const j = Geometry.cyclic3dAxis(i + 1);
533
+ const k = Geometry.cyclic3dAxis(j + 1);
534
+ return 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);
535
+ }
536
+ /** Compute the squared distance between two points given by their barycentric coordinates.
537
+ * * It is assumed that a0 + a1 + a2 = b0 + b1 + b2 = 1.
538
+ */
539
+ distanceSquared(a0, a1, a2, b0, b1, b2) {
540
+ // the barycentric displacement vector distance formula
541
+ return -this.edgeLengthSquared(0) * (b1 - a1) * (b2 - a2) - this.edgeLengthSquared(1) * (b2 - a2) * (b0 - a0) - this.edgeLengthSquared(2) * (b0 - a0) * (b1 - a1);
542
+ }
96
543
  }
97
544
  //# sourceMappingURL=BarycentricTriangle.js.map