@itwin/core-geometry 4.3.0-dev.8 → 4.3.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.
Files changed (336) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/lib/cjs/Geometry.d.ts +14 -2
  3. package/lib/cjs/Geometry.d.ts.map +1 -1
  4. package/lib/cjs/Geometry.js +20 -9
  5. package/lib/cjs/Geometry.js.map +1 -1
  6. package/lib/cjs/bspline/BSpline1dNd.d.ts +12 -2
  7. package/lib/cjs/bspline/BSpline1dNd.d.ts.map +1 -1
  8. package/lib/cjs/bspline/BSpline1dNd.js +27 -17
  9. package/lib/cjs/bspline/BSpline1dNd.js.map +1 -1
  10. package/lib/cjs/bspline/BSplineCurve.d.ts +30 -16
  11. package/lib/cjs/bspline/BSplineCurve.d.ts.map +1 -1
  12. package/lib/cjs/bspline/BSplineCurve.js +68 -44
  13. package/lib/cjs/bspline/BSplineCurve.js.map +1 -1
  14. package/lib/cjs/bspline/BSplineCurve3dH.d.ts +27 -20
  15. package/lib/cjs/bspline/BSplineCurve3dH.d.ts.map +1 -1
  16. package/lib/cjs/bspline/BSplineCurve3dH.js +136 -87
  17. package/lib/cjs/bspline/BSplineCurve3dH.js.map +1 -1
  18. package/lib/cjs/bspline/BSplineSurface.d.ts +138 -74
  19. package/lib/cjs/bspline/BSplineSurface.d.ts.map +1 -1
  20. package/lib/cjs/bspline/BSplineSurface.js +242 -119
  21. package/lib/cjs/bspline/BSplineSurface.js.map +1 -1
  22. package/lib/cjs/bspline/Bezier1dNd.d.ts +18 -4
  23. package/lib/cjs/bspline/Bezier1dNd.d.ts.map +1 -1
  24. package/lib/cjs/bspline/Bezier1dNd.js +19 -5
  25. package/lib/cjs/bspline/Bezier1dNd.js.map +1 -1
  26. package/lib/cjs/bspline/BezierCurve3dH.d.ts.map +1 -1
  27. package/lib/cjs/bspline/BezierCurve3dH.js +2 -1
  28. package/lib/cjs/bspline/BezierCurve3dH.js.map +1 -1
  29. package/lib/cjs/bspline/KnotVector.d.ts +30 -33
  30. package/lib/cjs/bspline/KnotVector.d.ts.map +1 -1
  31. package/lib/cjs/bspline/KnotVector.js +76 -69
  32. package/lib/cjs/bspline/KnotVector.js.map +1 -1
  33. package/lib/cjs/clipping/ClipUtils.d.ts +32 -5
  34. package/lib/cjs/clipping/ClipUtils.d.ts.map +1 -1
  35. package/lib/cjs/clipping/ClipUtils.js +92 -11
  36. package/lib/cjs/clipping/ClipUtils.js.map +1 -1
  37. package/lib/cjs/core-geometry.d.ts +0 -2
  38. package/lib/cjs/core-geometry.d.ts.map +1 -1
  39. package/lib/cjs/core-geometry.js +0 -2
  40. package/lib/cjs/core-geometry.js.map +1 -1
  41. package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
  42. package/lib/cjs/curve/Arc3d.js +5 -5
  43. package/lib/cjs/curve/Arc3d.js.map +1 -1
  44. package/lib/cjs/curve/CurveLocationDetail.d.ts +1 -4
  45. package/lib/cjs/curve/CurveLocationDetail.d.ts.map +1 -1
  46. package/lib/cjs/curve/CurveLocationDetail.js +4 -10
  47. package/lib/cjs/curve/CurveLocationDetail.js.map +1 -1
  48. package/lib/cjs/curve/CurveOps.d.ts +4 -5
  49. package/lib/cjs/curve/CurveOps.d.ts.map +1 -1
  50. package/lib/cjs/curve/CurveOps.js +1 -1
  51. package/lib/cjs/curve/CurveOps.js.map +1 -1
  52. package/lib/cjs/curve/CurveTypes.d.ts +14 -2
  53. package/lib/cjs/curve/CurveTypes.d.ts.map +1 -1
  54. package/lib/cjs/curve/CurveTypes.js.map +1 -1
  55. package/lib/cjs/curve/LineString3d.d.ts +3 -2
  56. package/lib/cjs/curve/LineString3d.d.ts.map +1 -1
  57. package/lib/cjs/curve/LineString3d.js +1 -0
  58. package/lib/cjs/curve/LineString3d.js.map +1 -1
  59. package/lib/cjs/curve/PointString3d.d.ts +2 -1
  60. package/lib/cjs/curve/PointString3d.d.ts.map +1 -1
  61. package/lib/cjs/curve/PointString3d.js.map +1 -1
  62. package/lib/cjs/curve/RegionOps.d.ts +5 -11
  63. package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
  64. package/lib/cjs/curve/RegionOps.js.map +1 -1
  65. package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.d.ts +15 -9
  66. package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.d.ts.map +1 -1
  67. package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.js +68 -56
  68. package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.js.map +1 -1
  69. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts +14 -16
  70. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  71. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js +51 -69
  72. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  73. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXYZ.d.ts.map +1 -1
  74. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXYZ.js +3 -2
  75. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXYZ.js.map +1 -1
  76. package/lib/cjs/curve/internalContexts/MultiChainCollector.d.ts +2 -3
  77. package/lib/cjs/curve/internalContexts/MultiChainCollector.d.ts.map +1 -1
  78. package/lib/cjs/curve/internalContexts/MultiChainCollector.js.map +1 -1
  79. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.d.ts +4 -4
  80. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.d.ts.map +1 -1
  81. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.js +38 -36
  82. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.js.map +1 -1
  83. package/lib/cjs/geometry3d/Angle.d.ts +0 -1
  84. package/lib/cjs/geometry3d/Angle.d.ts.map +1 -1
  85. package/lib/cjs/geometry3d/Angle.js +0 -1
  86. package/lib/cjs/geometry3d/Angle.js.map +1 -1
  87. package/lib/cjs/geometry3d/CoincidentGeometryOps.d.ts +21 -5
  88. package/lib/cjs/geometry3d/CoincidentGeometryOps.d.ts.map +1 -1
  89. package/lib/cjs/geometry3d/CoincidentGeometryOps.js +71 -45
  90. package/lib/cjs/geometry3d/CoincidentGeometryOps.js.map +1 -1
  91. package/lib/cjs/geometry3d/Matrix3d.d.ts +20 -13
  92. package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
  93. package/lib/cjs/geometry3d/Matrix3d.js +28 -21
  94. package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
  95. package/lib/cjs/geometry3d/Point3dVector3d.d.ts +11 -2
  96. package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
  97. package/lib/cjs/geometry3d/Point3dVector3d.js +16 -5
  98. package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
  99. package/lib/cjs/geometry3d/PointHelpers.d.ts +58 -20
  100. package/lib/cjs/geometry3d/PointHelpers.d.ts.map +1 -1
  101. package/lib/cjs/geometry3d/PointHelpers.js +213 -62
  102. package/lib/cjs/geometry3d/PointHelpers.js.map +1 -1
  103. package/lib/cjs/geometry3d/Segment1d.d.ts +5 -1
  104. package/lib/cjs/geometry3d/Segment1d.d.ts.map +1 -1
  105. package/lib/cjs/geometry3d/Segment1d.js +11 -7
  106. package/lib/cjs/geometry3d/Segment1d.js.map +1 -1
  107. package/lib/cjs/geometry3d/Transform.d.ts +4 -5
  108. package/lib/cjs/geometry3d/Transform.d.ts.map +1 -1
  109. package/lib/cjs/geometry3d/Transform.js +4 -5
  110. package/lib/cjs/geometry3d/Transform.js.map +1 -1
  111. package/lib/cjs/geometry4d/Point4d.d.ts +13 -0
  112. package/lib/cjs/geometry4d/Point4d.d.ts.map +1 -1
  113. package/lib/cjs/geometry4d/Point4d.js +21 -0
  114. package/lib/cjs/geometry4d/Point4d.js.map +1 -1
  115. package/lib/cjs/numerics/BezierPolynomials.d.ts +88 -64
  116. package/lib/cjs/numerics/BezierPolynomials.d.ts.map +1 -1
  117. package/lib/cjs/numerics/BezierPolynomials.js +92 -73
  118. package/lib/cjs/numerics/BezierPolynomials.js.map +1 -1
  119. package/lib/cjs/numerics/Newton.d.ts +143 -61
  120. package/lib/cjs/numerics/Newton.d.ts.map +1 -1
  121. package/lib/cjs/numerics/Newton.js +233 -66
  122. package/lib/cjs/numerics/Newton.js.map +1 -1
  123. package/lib/cjs/numerics/PascalCoefficients.d.ts +8 -12
  124. package/lib/cjs/numerics/PascalCoefficients.d.ts.map +1 -1
  125. package/lib/cjs/numerics/PascalCoefficients.js +10 -12
  126. package/lib/cjs/numerics/PascalCoefficients.js.map +1 -1
  127. package/lib/cjs/numerics/Polynomials.d.ts +6 -10
  128. package/lib/cjs/numerics/Polynomials.d.ts.map +1 -1
  129. package/lib/cjs/numerics/Polynomials.js +6 -10
  130. package/lib/cjs/numerics/Polynomials.js.map +1 -1
  131. package/lib/cjs/polyface/PolyfaceBuilder.d.ts +3 -0
  132. package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
  133. package/lib/cjs/polyface/PolyfaceBuilder.js +13 -2
  134. package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
  135. package/lib/cjs/polyface/PolyfaceData.d.ts +1 -1
  136. package/lib/cjs/polyface/PolyfaceData.js +1 -1
  137. package/lib/cjs/polyface/PolyfaceData.js.map +1 -1
  138. package/lib/cjs/polyface/PolyfaceQuery.d.ts +38 -11
  139. package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
  140. package/lib/cjs/polyface/PolyfaceQuery.js +93 -16
  141. package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
  142. package/lib/cjs/serialization/BGFBReader.d.ts +10 -10
  143. package/lib/cjs/serialization/BGFBReader.d.ts.map +1 -1
  144. package/lib/cjs/serialization/BGFBReader.js +69 -42
  145. package/lib/cjs/serialization/BGFBReader.js.map +1 -1
  146. package/lib/cjs/serialization/BGFBWriter.d.ts +8 -8
  147. package/lib/cjs/serialization/BGFBWriter.d.ts.map +1 -1
  148. package/lib/cjs/serialization/BGFBWriter.js +80 -55
  149. package/lib/cjs/serialization/BGFBWriter.js.map +1 -1
  150. package/lib/cjs/serialization/GeometrySamples.d.ts.map +1 -1
  151. package/lib/cjs/serialization/GeometrySamples.js +6 -8
  152. package/lib/cjs/serialization/GeometrySamples.js.map +1 -1
  153. package/lib/cjs/serialization/IModelJsonSchema.d.ts +8 -14
  154. package/lib/cjs/serialization/IModelJsonSchema.d.ts.map +1 -1
  155. package/lib/cjs/serialization/IModelJsonSchema.js +85 -259
  156. package/lib/cjs/serialization/IModelJsonSchema.js.map +1 -1
  157. package/lib/cjs/serialization/SerializationHelpers.d.ts +109 -0
  158. package/lib/cjs/serialization/SerializationHelpers.d.ts.map +1 -0
  159. package/lib/cjs/serialization/SerializationHelpers.js +591 -0
  160. package/lib/cjs/serialization/SerializationHelpers.js.map +1 -0
  161. package/lib/cjs/topology/Graph.d.ts +399 -366
  162. package/lib/cjs/topology/Graph.d.ts.map +1 -1
  163. package/lib/cjs/topology/Graph.js +531 -464
  164. package/lib/cjs/topology/Graph.js.map +1 -1
  165. package/lib/cjs/topology/MaskManager.d.ts +8 -9
  166. package/lib/cjs/topology/MaskManager.d.ts.map +1 -1
  167. package/lib/cjs/topology/MaskManager.js +11 -12
  168. package/lib/cjs/topology/MaskManager.js.map +1 -1
  169. package/lib/esm/Geometry.d.ts +14 -2
  170. package/lib/esm/Geometry.d.ts.map +1 -1
  171. package/lib/esm/Geometry.js +20 -9
  172. package/lib/esm/Geometry.js.map +1 -1
  173. package/lib/esm/bspline/BSpline1dNd.d.ts +12 -2
  174. package/lib/esm/bspline/BSpline1dNd.d.ts.map +1 -1
  175. package/lib/esm/bspline/BSpline1dNd.js +27 -17
  176. package/lib/esm/bspline/BSpline1dNd.js.map +1 -1
  177. package/lib/esm/bspline/BSplineCurve.d.ts +30 -16
  178. package/lib/esm/bspline/BSplineCurve.d.ts.map +1 -1
  179. package/lib/esm/bspline/BSplineCurve.js +68 -44
  180. package/lib/esm/bspline/BSplineCurve.js.map +1 -1
  181. package/lib/esm/bspline/BSplineCurve3dH.d.ts +27 -20
  182. package/lib/esm/bspline/BSplineCurve3dH.d.ts.map +1 -1
  183. package/lib/esm/bspline/BSplineCurve3dH.js +137 -88
  184. package/lib/esm/bspline/BSplineCurve3dH.js.map +1 -1
  185. package/lib/esm/bspline/BSplineSurface.d.ts +138 -74
  186. package/lib/esm/bspline/BSplineSurface.d.ts.map +1 -1
  187. package/lib/esm/bspline/BSplineSurface.js +242 -119
  188. package/lib/esm/bspline/BSplineSurface.js.map +1 -1
  189. package/lib/esm/bspline/Bezier1dNd.d.ts +18 -4
  190. package/lib/esm/bspline/Bezier1dNd.d.ts.map +1 -1
  191. package/lib/esm/bspline/Bezier1dNd.js +19 -5
  192. package/lib/esm/bspline/Bezier1dNd.js.map +1 -1
  193. package/lib/esm/bspline/BezierCurve3dH.d.ts.map +1 -1
  194. package/lib/esm/bspline/BezierCurve3dH.js +2 -1
  195. package/lib/esm/bspline/BezierCurve3dH.js.map +1 -1
  196. package/lib/esm/bspline/KnotVector.d.ts +30 -33
  197. package/lib/esm/bspline/KnotVector.d.ts.map +1 -1
  198. package/lib/esm/bspline/KnotVector.js +76 -69
  199. package/lib/esm/bspline/KnotVector.js.map +1 -1
  200. package/lib/esm/clipping/ClipUtils.d.ts +32 -5
  201. package/lib/esm/clipping/ClipUtils.d.ts.map +1 -1
  202. package/lib/esm/clipping/ClipUtils.js +92 -11
  203. package/lib/esm/clipping/ClipUtils.js.map +1 -1
  204. package/lib/esm/core-geometry.d.ts +0 -2
  205. package/lib/esm/core-geometry.d.ts.map +1 -1
  206. package/lib/esm/core-geometry.js +0 -2
  207. package/lib/esm/core-geometry.js.map +1 -1
  208. package/lib/esm/curve/Arc3d.d.ts.map +1 -1
  209. package/lib/esm/curve/Arc3d.js +5 -5
  210. package/lib/esm/curve/Arc3d.js.map +1 -1
  211. package/lib/esm/curve/CurveLocationDetail.d.ts +1 -4
  212. package/lib/esm/curve/CurveLocationDetail.d.ts.map +1 -1
  213. package/lib/esm/curve/CurveLocationDetail.js +4 -10
  214. package/lib/esm/curve/CurveLocationDetail.js.map +1 -1
  215. package/lib/esm/curve/CurveOps.d.ts +4 -5
  216. package/lib/esm/curve/CurveOps.d.ts.map +1 -1
  217. package/lib/esm/curve/CurveOps.js +1 -1
  218. package/lib/esm/curve/CurveOps.js.map +1 -1
  219. package/lib/esm/curve/CurveTypes.d.ts +14 -2
  220. package/lib/esm/curve/CurveTypes.d.ts.map +1 -1
  221. package/lib/esm/curve/CurveTypes.js.map +1 -1
  222. package/lib/esm/curve/LineString3d.d.ts +3 -2
  223. package/lib/esm/curve/LineString3d.d.ts.map +1 -1
  224. package/lib/esm/curve/LineString3d.js +1 -0
  225. package/lib/esm/curve/LineString3d.js.map +1 -1
  226. package/lib/esm/curve/PointString3d.d.ts +2 -1
  227. package/lib/esm/curve/PointString3d.d.ts.map +1 -1
  228. package/lib/esm/curve/PointString3d.js.map +1 -1
  229. package/lib/esm/curve/RegionOps.d.ts +5 -11
  230. package/lib/esm/curve/RegionOps.d.ts.map +1 -1
  231. package/lib/esm/curve/RegionOps.js.map +1 -1
  232. package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.d.ts +15 -9
  233. package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.d.ts.map +1 -1
  234. package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.js +69 -57
  235. package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.js.map +1 -1
  236. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts +14 -16
  237. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  238. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js +51 -68
  239. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  240. package/lib/esm/curve/internalContexts/CurveCurveIntersectXYZ.d.ts.map +1 -1
  241. package/lib/esm/curve/internalContexts/CurveCurveIntersectXYZ.js +3 -2
  242. package/lib/esm/curve/internalContexts/CurveCurveIntersectXYZ.js.map +1 -1
  243. package/lib/esm/curve/internalContexts/MultiChainCollector.d.ts +2 -3
  244. package/lib/esm/curve/internalContexts/MultiChainCollector.d.ts.map +1 -1
  245. package/lib/esm/curve/internalContexts/MultiChainCollector.js.map +1 -1
  246. package/lib/esm/curve/internalContexts/PolygonOffsetContext.d.ts +4 -4
  247. package/lib/esm/curve/internalContexts/PolygonOffsetContext.d.ts.map +1 -1
  248. package/lib/esm/curve/internalContexts/PolygonOffsetContext.js +38 -36
  249. package/lib/esm/curve/internalContexts/PolygonOffsetContext.js.map +1 -1
  250. package/lib/esm/geometry3d/Angle.d.ts +0 -1
  251. package/lib/esm/geometry3d/Angle.d.ts.map +1 -1
  252. package/lib/esm/geometry3d/Angle.js +0 -1
  253. package/lib/esm/geometry3d/Angle.js.map +1 -1
  254. package/lib/esm/geometry3d/CoincidentGeometryOps.d.ts +21 -5
  255. package/lib/esm/geometry3d/CoincidentGeometryOps.d.ts.map +1 -1
  256. package/lib/esm/geometry3d/CoincidentGeometryOps.js +71 -45
  257. package/lib/esm/geometry3d/CoincidentGeometryOps.js.map +1 -1
  258. package/lib/esm/geometry3d/Matrix3d.d.ts +20 -13
  259. package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
  260. package/lib/esm/geometry3d/Matrix3d.js +28 -21
  261. package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
  262. package/lib/esm/geometry3d/Point3dVector3d.d.ts +11 -2
  263. package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
  264. package/lib/esm/geometry3d/Point3dVector3d.js +16 -5
  265. package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
  266. package/lib/esm/geometry3d/PointHelpers.d.ts +58 -20
  267. package/lib/esm/geometry3d/PointHelpers.d.ts.map +1 -1
  268. package/lib/esm/geometry3d/PointHelpers.js +213 -62
  269. package/lib/esm/geometry3d/PointHelpers.js.map +1 -1
  270. package/lib/esm/geometry3d/Segment1d.d.ts +5 -1
  271. package/lib/esm/geometry3d/Segment1d.d.ts.map +1 -1
  272. package/lib/esm/geometry3d/Segment1d.js +11 -7
  273. package/lib/esm/geometry3d/Segment1d.js.map +1 -1
  274. package/lib/esm/geometry3d/Transform.d.ts +4 -5
  275. package/lib/esm/geometry3d/Transform.d.ts.map +1 -1
  276. package/lib/esm/geometry3d/Transform.js +4 -5
  277. package/lib/esm/geometry3d/Transform.js.map +1 -1
  278. package/lib/esm/geometry4d/Point4d.d.ts +13 -0
  279. package/lib/esm/geometry4d/Point4d.d.ts.map +1 -1
  280. package/lib/esm/geometry4d/Point4d.js +21 -0
  281. package/lib/esm/geometry4d/Point4d.js.map +1 -1
  282. package/lib/esm/numerics/BezierPolynomials.d.ts +88 -64
  283. package/lib/esm/numerics/BezierPolynomials.d.ts.map +1 -1
  284. package/lib/esm/numerics/BezierPolynomials.js +92 -73
  285. package/lib/esm/numerics/BezierPolynomials.js.map +1 -1
  286. package/lib/esm/numerics/Newton.d.ts +143 -61
  287. package/lib/esm/numerics/Newton.d.ts.map +1 -1
  288. package/lib/esm/numerics/Newton.js +229 -65
  289. package/lib/esm/numerics/Newton.js.map +1 -1
  290. package/lib/esm/numerics/PascalCoefficients.d.ts +8 -12
  291. package/lib/esm/numerics/PascalCoefficients.d.ts.map +1 -1
  292. package/lib/esm/numerics/PascalCoefficients.js +10 -12
  293. package/lib/esm/numerics/PascalCoefficients.js.map +1 -1
  294. package/lib/esm/numerics/Polynomials.d.ts +6 -10
  295. package/lib/esm/numerics/Polynomials.d.ts.map +1 -1
  296. package/lib/esm/numerics/Polynomials.js +6 -10
  297. package/lib/esm/numerics/Polynomials.js.map +1 -1
  298. package/lib/esm/polyface/PolyfaceBuilder.d.ts +3 -0
  299. package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
  300. package/lib/esm/polyface/PolyfaceBuilder.js +13 -2
  301. package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
  302. package/lib/esm/polyface/PolyfaceData.d.ts +1 -1
  303. package/lib/esm/polyface/PolyfaceData.js +1 -1
  304. package/lib/esm/polyface/PolyfaceData.js.map +1 -1
  305. package/lib/esm/polyface/PolyfaceQuery.d.ts +38 -11
  306. package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
  307. package/lib/esm/polyface/PolyfaceQuery.js +93 -16
  308. package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
  309. package/lib/esm/serialization/BGFBReader.d.ts +10 -10
  310. package/lib/esm/serialization/BGFBReader.d.ts.map +1 -1
  311. package/lib/esm/serialization/BGFBReader.js +69 -42
  312. package/lib/esm/serialization/BGFBReader.js.map +1 -1
  313. package/lib/esm/serialization/BGFBWriter.d.ts +8 -8
  314. package/lib/esm/serialization/BGFBWriter.d.ts.map +1 -1
  315. package/lib/esm/serialization/BGFBWriter.js +80 -55
  316. package/lib/esm/serialization/BGFBWriter.js.map +1 -1
  317. package/lib/esm/serialization/GeometrySamples.d.ts.map +1 -1
  318. package/lib/esm/serialization/GeometrySamples.js +7 -9
  319. package/lib/esm/serialization/GeometrySamples.js.map +1 -1
  320. package/lib/esm/serialization/IModelJsonSchema.d.ts +8 -14
  321. package/lib/esm/serialization/IModelJsonSchema.d.ts.map +1 -1
  322. package/lib/esm/serialization/IModelJsonSchema.js +86 -260
  323. package/lib/esm/serialization/IModelJsonSchema.js.map +1 -1
  324. package/lib/esm/serialization/SerializationHelpers.d.ts +109 -0
  325. package/lib/esm/serialization/SerializationHelpers.d.ts.map +1 -0
  326. package/lib/esm/serialization/SerializationHelpers.js +588 -0
  327. package/lib/esm/serialization/SerializationHelpers.js.map +1 -0
  328. package/lib/esm/topology/Graph.d.ts +399 -366
  329. package/lib/esm/topology/Graph.d.ts.map +1 -1
  330. package/lib/esm/topology/Graph.js +531 -464
  331. package/lib/esm/topology/Graph.js.map +1 -1
  332. package/lib/esm/topology/MaskManager.d.ts +8 -9
  333. package/lib/esm/topology/MaskManager.d.ts.map +1 -1
  334. package/lib/esm/topology/MaskManager.js +11 -12
  335. package/lib/esm/topology/MaskManager.js.map +1 -1
  336. package/package.json +3 -4
@@ -12,18 +12,16 @@ import { Point2d, Vector2d } from "../geometry3d/Point2dVector2d";
12
12
  import { Point3d, Vector3d } from "../geometry3d/Point3dVector3d";
13
13
  import { SmallSystem } from "../numerics/Polynomials";
14
14
  import { MaskManager } from "./MaskManager";
15
- // import { GraphChecker } from "../test/topology/Graph.test";
15
+ // import { GraphChecker } from "../test/topology/Graph.test"; // used for debugging
16
16
  /* eslint-disable @typescript-eslint/no-this-alias */
17
- // cspell:word CONSTU
18
- // cspell:word CONSTV
19
- // cspell:word USEAM
20
- // cspell:word VSEAM
17
+ // cspell:word CONSTU CONSTV USEAM VSEAM internaldocs
21
18
  /**
22
19
  * * Each node of the graph has a mask member.
23
20
  * * The mask member is a number which is used as set of single bit boolean values.
24
21
  * * Particular meanings of the various bits are HIGHLY application dependent.
25
22
  * * The EXTERIOR mask bit is widely used to mark nodes that are "outside" the active areas
26
- * * The PRIMARY_EDGE bit is widely used to indicate linework created directly from input data, hence protected from triangle edge flipping.
23
+ * * The PRIMARY_EDGE bit is widely used to indicate linework created directly from input data, hence protected from
24
+ * triangle edge flipping.
27
25
  * * The BOUNDARY bit is widely used to indicate that crossing this edge is a transition from outside to inside.
28
26
  * * VISITED is used locally in many searches.
29
27
  * * Never use VISITED unless the search logic is highly self contained.
@@ -31,17 +29,6 @@ import { MaskManager } from "./MaskManager";
31
29
  */
32
30
  export var HalfEdgeMask;
33
31
  (function (HalfEdgeMask) {
34
- /** Mask commonly set consistently around exterior faces.
35
- * * A boundary edge with interior to one side, exterior to the other will have EXTERIOR only on the outside.
36
- * * An an edge inserted "within a purely exterior face" can have EXTERIOR on both sides.
37
- * * An interior edge (such as added during triangulation) will have no EXTERIOR bits.
38
- */
39
- HalfEdgeMask[HalfEdgeMask["EXTERIOR"] = 1] = "EXTERIOR";
40
- /** Mask commonly set (on both sides) of original geometry edges that are transition from outside from to inside.
41
- * * At the moment of creating an edge from primary user boundary loop coordinates, the fact that an edge is BOUNDARY is often clear even though
42
- * there is uncertainty about which side should be EXTERIOR.
43
- */
44
- HalfEdgeMask[HalfEdgeMask["BOUNDARY_EDGE"] = 2] = "BOUNDARY_EDGE";
45
32
  // REMARK: Various mask names are COMMENTED here for reference to native legacy code.
46
33
  // CONSTU_MASK = 0x00000004,
47
34
  // CONSTV_MASK = 0x00000008,
@@ -50,21 +37,37 @@ export var HalfEdgeMask;
50
37
  // BOUNDARY_VERTEX_MASK = 0x00000040,
51
38
  // PRIMARY_VERTEX_MASK = 0x00000080,
52
39
  // DIRECTED_EDGE_MASK = 0x00000100,
53
- /** Mask commonly set (on both sides) of original geometry edges, but NOT indicating that the edge is certainly a boundary between outside and inside.
54
- * * For instance, if geometry is provided as stray sticks (not loops), it can be marked PRIMARY_EDGE but neither BOUNDARY_EDGE nor EXTERIOR_EDGE
40
+ /**
41
+ * Mask commonly set consistently around exterior faces.
42
+ * * A boundary edge with interior to one side, exterior to the other, will have EXTERIOR only on the outside.
43
+ * * An an edge inserted "within a purely exterior face" can have EXTERIOR on both sides.
44
+ * * An interior edge (such as added during triangulation) will have no EXTERIOR bits.
45
+ */
46
+ HalfEdgeMask[HalfEdgeMask["EXTERIOR"] = 1] = "EXTERIOR";
47
+ /**
48
+ * Mask commonly set (on both sides) of original geometry edges that are transition from outside from to inside.
49
+ * * At the moment of creating an edge from primary user boundary loop coordinates, the fact that an edge is BOUNDARY
50
+ * is often clear even though there is uncertainty about which side should be EXTERIOR.
51
+ */
52
+ HalfEdgeMask[HalfEdgeMask["BOUNDARY_EDGE"] = 2] = "BOUNDARY_EDGE";
53
+ /**
54
+ * Mask commonly set (on both sides) of original geometry edges, but NOT indicating that the edge is certainly a
55
+ * boundary between outside and inside.
56
+ * * For instance, if geometry is provided as stray sticks (not loops), it can be marked PRIMARY_EDGE but neither
57
+ * BOUNDARY_EDGE nor EXTERIOR_EDGE.
55
58
  */
56
59
  HalfEdgeMask[HalfEdgeMask["PRIMARY_EDGE"] = 4] = "PRIMARY_EDGE";
57
- /** Mask used for low level searches to identify previously-visited nodes */
60
+ /** Mask used for low level searches to identify previously-visited nodes. */
58
61
  HalfEdgeMask[HalfEdgeMask["VISITED"] = 16] = "VISITED";
59
- /** Mask applied to triangles by earcut triangulator */
62
+ /** Mask applied to triangles by earcut triangulator. */
60
63
  HalfEdgeMask[HalfEdgeMask["TRIANGULATED_FACE"] = 256] = "TRIANGULATED_FACE";
61
- /** mask applied in a face with 2 edges. */
64
+ /** Mask applied in a face with 2 edges. */
62
65
  HalfEdgeMask[HalfEdgeMask["NULL_FACE"] = 512] = "NULL_FACE";
63
- /** no mask bits */
66
+ /** No mask bits. */
64
67
  HalfEdgeMask[HalfEdgeMask["NULL_MASK"] = 0] = "NULL_MASK";
65
- /** The "upper 12 " bits of 32 bit integer. */
68
+ /** The "upper 12" bits of 32 bit integer reserved for grab/drop. */
66
69
  HalfEdgeMask[HalfEdgeMask["ALL_GRAB_DROP_MASKS"] = 4293918720] = "ALL_GRAB_DROP_MASKS";
67
- /** all mask bits */
70
+ /** All mask bits */
68
71
  HalfEdgeMask[HalfEdgeMask["ALL_MASK"] = 4294967295] = "ALL_MASK";
69
72
  // informal convention on preassigned mask bit numbers:
70
73
  // byte0 (EXTERIOR, BOUNDARY_EDGE, PRIMARY_EDGE) -- edge properties
@@ -72,35 +75,61 @@ export var HalfEdgeMask;
72
75
  // byte2 (TRIANGULATED_FACE, NULL_FACE) -- face properties.
73
76
  })(HalfEdgeMask || (HalfEdgeMask = {}));
74
77
  /**
78
+ * A HalfEdge is "one side of an edge" in a structure of faces, edges and vertices. From a node there are
79
+ * navigational links to:
80
+ * * "faceSuccessor" -- the next half edge in a loop around a face.
81
+ * * "facePredecessor" -- the previous half edge in a loop around a face.
82
+ * * "edgeMate" -- the node's partner on the other side of the edge.
83
+ *
84
+ * The next, prev, and mate are the essential connectivity. Additional node content is for application-specific
85
+ * uses. The most useful ones are:
86
+ * * x,y -- coordinates in the xy plane
87
+ * * z -- z coordinate. This is normally ignored during planar setup, but used for output.
88
+ * * maskBits -- an integer value manipulated as individual bits.
75
89
  *
76
- * * A HalfEdge is "one side of an edge" in a structure of faces, edges and vertices. From a node there are navigational links to:
77
- * ** "faceSuccessor" -- the next half edge in a loop around a face.
78
- * ** "facePredecessor" -- the previous half edge in a loop around a face.
79
- * ** "edgeMate" -- the node's partner on the other side of the edge.
80
- * * The next, prev, and mate are the essential connectivity. Additional node content is for application-specific
81
- * uses. The most useful ones are:
82
- * ** x,y -- coordinates in the xy plane
83
- * ** z -- z coordinate. This is normally ignored during planar setup, but used for output.
84
- * ** buffer -- a integer value manipulated as individual bits.
85
- * * In properly connected planar graph, interior face loops are counterclockwise. But that property (along with
86
- * expected masking) is a result of extensive validation of inputs, and is not true in intermediate phases
87
- * of graph manipulation.
90
+ * In properly connected planar graph, interior face loops are counterclockwise. But that property (along with
91
+ * expected masking) is a result of extensive validation of inputs, and is not true in intermediate phases of
92
+ * graph manipulation.
88
93
  * @internal
89
94
  */
90
95
  class HalfEdge {
91
- /** id assigned sequentially during construction --- useful for debugging. */
92
- get id() { return this._id; }
93
- /** previous half edge "around the face"
94
- */
95
- get facePredecessor() { return this._facePredecessor; }
96
- /** next half edge "around the face" */
97
- get faceSuccessor() { return this._faceSuccessor; }
98
- /** Half edge on the other side of this edge.
99
- */
100
- get edgeMate() { return this._edgeMate; }
101
- /** Take numStep face steps and return y coordinate
102
- * * positive steps are through faceSuccessor
103
- * * negative steps are through facePredecessor
96
+ /** Immutable ID assigned sequentially during construction --- useful for debugging. */
97
+ get id() {
98
+ return this._id;
99
+ }
100
+ /** Previous half edge "around the face" */
101
+ get facePredecessor() {
102
+ return this._facePredecessor;
103
+ }
104
+ /** Next half edge "around the face" */
105
+ get faceSuccessor() {
106
+ return this._faceSuccessor;
107
+ }
108
+ /** Half edge on the other side of this edge. */
109
+ get edgeMate() {
110
+ return this._edgeMate;
111
+ }
112
+ constructor(x = 0, y = 0, z = 0, i = 0) {
113
+ this._id = HalfEdge._totalNodesCreated++;
114
+ this.i = i;
115
+ this.maskBits = 0x00000000;
116
+ this.x = x;
117
+ this.y = y;
118
+ this.z = z;
119
+ // explicit init to undefined is important for performance here
120
+ this.sortAngle = undefined;
121
+ this.sortData = undefined;
122
+ this.edgeTag = undefined;
123
+ this.faceTag = undefined;
124
+ // always created in pairs, init here to make TS compiler and JS runtime happy
125
+ this._facePredecessor = this;
126
+ this._faceSuccessor = this;
127
+ this._edgeMate = this;
128
+ }
129
+ /**
130
+ * Take numStep face steps and return y coordinate.
131
+ * * Positive steps are through faceSuccessor.
132
+ * * Negative steps are through facePredecessor.
104
133
  */
105
134
  faceStepY(numStep) {
106
135
  let node = this;
@@ -113,12 +142,13 @@ class HalfEdge {
113
142
  return node.y;
114
143
  }
115
144
  /**
116
- * * Create 2 half edges.
145
+ * Create 2 half edges.
117
146
  * * The two edges are joined as edgeMate pair.
118
147
  * * The two edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
119
- * @returns Returns the reference to the first half edge created
148
+ * @returns the reference to the first half edge created.
120
149
  */
121
150
  static createHalfEdgePair(heArray) {
151
+ // Visualization can be found at geometry/internaldocs/Graph.md
122
152
  const a = new HalfEdge();
123
153
  const b = new HalfEdge();
124
154
  if (heArray) {
@@ -134,8 +164,8 @@ class HalfEdge {
134
164
  * * Create 2 half edges.
135
165
  * * The two edges are joined as edgeMate pair.
136
166
  * * The two edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
137
- * * Properties x,y,z,i are inserted in each
138
- * @returns Returns the reference to the first half edge created
167
+ * * Properties x,y,z,i are inserted in each half edge.
168
+ * @returns the reference to the first half edge created.
139
169
  */
140
170
  static createHalfEdgePairWithCoordinates(xA = 0, yA = 0, zA = 0, iA = 0, xB = 0, yB = 0, zB = 0, iB = 0, heArray) {
141
171
  const a = HalfEdge.createHalfEdgePair(heArray);
@@ -151,32 +181,32 @@ class HalfEdge {
151
181
  return a;
152
182
  }
153
183
  /**
154
- * * set heA <==> heB pointer relation through heA._faceSuccessor and heB._facePredecessor
184
+ * * Set heA <==> heB pointer relation through heA._faceSuccessor and heB._facePredecessor.
155
185
  * * This changes heA._faceSuccessor and heB._facePredecessor, but not heA._facePredecessor and heB._faceSuccessor.
156
- * * this must always be done with another call to reestablish the entire double-linked list.
186
+ * * This must always be done with another call to setFaceLinks(heB,heA) in order to re-establish the entire
187
+ * double-linked list.
157
188
  */
158
189
  static setFaceLinks(heA, heB) {
159
190
  heA._faceSuccessor = heB;
160
191
  heB._facePredecessor = heA;
161
192
  }
162
- /**
163
- * * set heA <==> heB pointer relation edgeMate
164
- */
193
+ /** set heA <==> heB pointer relation edgeMate. */
165
194
  static setEdgeMates(heA, heB) {
166
195
  heA._edgeMate = heB;
167
196
  heB._edgeMate = heA;
168
197
  }
169
198
  /**
170
- * * Create a new vertex within the edge from base.
171
- * * Insert it "within" the base edge.
172
- * * This requires two new half edges.
173
- * * if the base is undefined, create a single-edge loop.
174
- * * This (unlike pinch) breaks the edgeMate pairing of the base edge.
175
- * * This preserves xyz and i properties at all existing vertices.
176
- * * on each side, if edgeTag is present it is copied to the new edge.
177
- * @returns Returns the reference to the half edge created.
199
+ * Create a new vertex within the edge beginning at `baseA`.
200
+ * * This creates two new nodes in their own vertex loop.
201
+ * * If the base is undefined, create a single-edge loop.
202
+ * * Existing nodes stay in their face and vertex loops and retain xyz and i values.
203
+ * * Unlike [[pinch]], this breaks the edgeMate pairing of the input edge:
204
+ * each node of the input edge gets a new node as its edge mate.
205
+ * * On each side of the edge, if edgeTag is present, it is copied to the new node on that side.
206
+ * @returns reference to the half edge created, the new face successor of `baseA`.
178
207
  */
179
208
  static splitEdge(baseA, xA = 0, yA = 0, zA = 0, iA = 0, heArray) {
209
+ // Visualization can be found at geometry/internaldocs/Graph.md
180
210
  const newA = new HalfEdge(xA, yA, zA, iA);
181
211
  const newB = new HalfEdge(xA, yA, zA, iA);
182
212
  if (heArray) {
@@ -192,10 +222,12 @@ class HalfEdge {
192
222
  const nextA = baseA._faceSuccessor;
193
223
  const mateA = baseA._edgeMate;
194
224
  const vPredA = mateA._faceSuccessor;
225
+ // insert newA and newB between existing half edges
195
226
  HalfEdge.setFaceLinks(newA, nextA);
196
227
  HalfEdge.setFaceLinks(baseA, newA);
197
228
  HalfEdge.setFaceLinks(mateA, newB);
198
229
  HalfEdge.setFaceLinks(newB, vPredA);
230
+ // set correct edge mates
199
231
  HalfEdge.setEdgeMates(newA, mateA);
200
232
  HalfEdge.setEdgeMates(newB, baseA);
201
233
  this.transferEdgeProperties(baseA, newA);
@@ -204,29 +236,26 @@ class HalfEdge {
204
236
  return newA;
205
237
  }
206
238
  /**
207
- * * Create a new sliver face "inside" an existing edge.
208
- * * Insert it "within" the base edge.
209
- * * This requires two new half edges.
210
- * * if the base is undefined, create a single-edge loop.
211
- * * This (unlike pinch) breaks the edgeMate pairing of the base edge.
212
- * * This preserves xyz and i properties at all existing vertices.
213
- * * The two new half edges are a sliver face (via their predecessor and successor)
214
- * * Each new edge mates to one existing edge.
215
- * @returns Returns the reference to the half edge created.
239
+ * Create a new sliver face "inside" an existing edge.
240
+ * * This creates two nodes that are each face predecessor and successor to the other.
241
+ * * Existing nodes stay in their face and vertex loops and retain xyz and i values.
242
+ * * Unlike [[pinch]], this breaks the edgeMate pairing of the input edge:
243
+ * each node of the input edge gets a new node as its edge mate.
244
+ * * New nodes get the xyz and i values shared by the nodes in the vertex loops into which they are placed.
245
+ * * New nodes' faceTag and edgeTag are `undefined`.
246
+ * @returns reference to the half edge created in the vertex loop of baseA.
216
247
  */
217
248
  static splitEdgeCreateSliverFace(baseA, heArray) {
218
- // raw edges ...
249
+ // Visualization can be found at geometry/internaldocs/Graph.md
250
+ const baseB = baseA.edgeMate;
219
251
  const newA = new HalfEdge();
220
252
  const newB = new HalfEdge();
221
- const baseB = baseA.edgeMate;
222
253
  if (heArray) {
223
254
  heArray.push(newA);
224
255
  heArray.push(newB);
225
256
  }
226
257
  newA._faceSuccessor = newA._facePredecessor = newB;
227
258
  newB._faceSuccessor = newB._facePredecessor = newA;
228
- // newA is in vertex loop with baseA etc.
229
- // newA mates to baseB
230
259
  HalfEdge.setEdgeMates(newA, baseB);
231
260
  HalfEdge.setEdgeMates(newB, baseA);
232
261
  newA.copyDataFrom(baseA, true, true, false, false);
@@ -234,11 +263,9 @@ class HalfEdge {
234
263
  return newA;
235
264
  }
236
265
  /**
237
- * Copy "edge based" content of fromNode to toNode
266
+ * Copy "edge based" content of `fromNode` to `toNode`:
238
267
  * * edgeTag
239
- * * masks in _edgePropertyMasks: EXTERIOR, BOUNDARY_EDGE, NULL_FACE, PRIMARY_EDGE
240
- * @param fromNode
241
- * @param toNode
268
+ * * masks EXTERIOR, BOUNDARY_EDGE, NULL_FACE, PRIMARY_EDGE
242
269
  */
243
270
  static transferEdgeProperties(fromNode, toNode) {
244
271
  toNode.edgeTag = fromNode.edgeTag;
@@ -249,49 +276,38 @@ class HalfEdge {
249
276
  toNode.clearMask(mask);
250
277
  }
251
278
  }
252
- constructor(x = 0, y = 0, z = 0, i = 0) {
253
- this._id = HalfEdge._totalNodesCreated++;
254
- this.i = i;
255
- this.maskBits = 0x00000000;
256
- this.x = x;
257
- this.y = y;
258
- this.z = z;
259
- // Explicit init to undefined is important for performance here
260
- this.sortAngle = undefined;
261
- this.sortData = undefined;
262
- this.edgeTag = undefined;
263
- this.faceTag = undefined;
264
- // Always created in pairs, init here to make TS compiler and JS runtime happy
265
- this._facePredecessor = this;
266
- this._faceSuccessor = this;
267
- this._edgeMate = this;
279
+ /** Return the next half edge around this vertex in the CCW direction. */
280
+ get vertexSuccessor() {
281
+ return this.facePredecessor.edgeMate;
282
+ }
283
+ /** Return the next half edge around this vertex in the CW direction. */
284
+ get vertexPredecessor() {
285
+ return this.edgeMate.faceSuccessor;
268
286
  }
269
287
  /**
270
- * Return the next outbound half edge around this vertex in the CCW direction
271
- */
272
- get vertexSuccessor() { return this.facePredecessor.edgeMate; }
273
- /**
274
- * Return the next outbound half edge around this vertex in the CW direction
275
- */
276
- get vertexPredecessor() { return this.edgeMate.faceSuccessor; }
277
- /**
278
- * Set mask bits on this HalfEdge
279
- * @param mask mask to apply
288
+ * Set mask bits on this HalfEdge.
289
+ * @param mask mask bits to apply
280
290
  */
281
- setMask(mask) { this.maskBits |= mask; }
291
+ setMask(mask) {
292
+ this.maskBits |= mask;
293
+ }
282
294
  /**
283
- * Get mask bits from this HalfEdge
284
- * @param mask mask to query
295
+ * Get mask bits from this HalfEdge.
296
+ * @param mask mask bits to query
285
297
  */
286
- getMask(mask) { return (this.maskBits & mask); }
298
+ getMask(mask) {
299
+ return (this.maskBits & mask);
300
+ }
287
301
  /**
288
- * Clear mask bits from this HalfEdge
289
- * @param mask mask to clear
302
+ * Clear mask bits from this HalfEdge.
303
+ * @param mask mask bits to clear
290
304
  */
291
- clearMask(mask) { this.maskBits &= ~mask; }
305
+ clearMask(mask) {
306
+ this.maskBits &= ~mask;
307
+ }
292
308
  /**
293
309
  * Set a mask at all nodes around a vertex.
294
- * @param mask mask to apply to the half edges around this HalfEdge's vertex loop
310
+ * @param mask mask to apply to the half edges around this HalfEdge's vertex loop.
295
311
  */
296
312
  setMaskAroundVertex(mask) {
297
313
  let node = this;
@@ -300,10 +316,7 @@ class HalfEdge {
300
316
  node = node.vertexSuccessor;
301
317
  } while (node !== this);
302
318
  }
303
- /**
304
- * Set x,y,z at all nodes around a vertex.
305
- * @param mask mask to apply to the half edges around this HalfEdge's vertex loop
306
- */
319
+ /** Set x,y,z at all nodes around a vertex. */
307
320
  setXYZAroundVertex(x, y, z) {
308
321
  let node = this;
309
322
  do {
@@ -315,7 +328,7 @@ class HalfEdge {
315
328
  }
316
329
  /**
317
330
  * Apply a mask to all edges around a face.
318
- * @param mask mask to apply to the half edges around this HalfEdge's face loop
331
+ * @param mask mask to apply to the half edges around this HalfEdge's face loop.
319
332
  */
320
333
  setMaskAroundFace(mask) {
321
334
  let node = this;
@@ -326,7 +339,7 @@ class HalfEdge {
326
339
  }
327
340
  /**
328
341
  * Apply a mask to both sides of an edge.
329
- * @param mask mask to apply to this edge and its `edgeMate`
342
+ * @param mask mask to apply to this edge and its edgeMate.
330
343
  */
331
344
  setMaskAroundEdge(mask) {
332
345
  this.setMask(mask);
@@ -334,7 +347,7 @@ class HalfEdge {
334
347
  }
335
348
  /**
336
349
  * Clear a mask on both sides of an edge.
337
- * @param mask mask to clear on this edge and its `edgeMate`
350
+ * @param mask mask to clear on this edge and its edgeMate.
338
351
  */
339
352
  clearMaskAroundEdge(mask) {
340
353
  this.clearMask(mask);
@@ -350,7 +363,7 @@ class HalfEdge {
350
363
  } while (node !== this);
351
364
  return count;
352
365
  }
353
- /** Return true if other is in the vertex loop around this. */
366
+ /** Return true if `other` node is in the vertex loop around `this` node. */
354
367
  findAroundVertex(other) {
355
368
  let node = this;
356
369
  do {
@@ -360,7 +373,7 @@ class HalfEdge {
360
373
  } while (node !== this);
361
374
  return false;
362
375
  }
363
- /** Return true if other is in the face loop around this. */
376
+ /** Return true if `other` node is in the face loop around `this` node. */
364
377
  findAroundFace(other) {
365
378
  let node = this;
366
379
  do {
@@ -371,7 +384,9 @@ class HalfEdge {
371
384
  return false;
372
385
  }
373
386
  /**
374
- * @return whether the mask is set (or unset) on all nodes of the face loop
387
+ * Returns whether the mask is set or unset on all nodes of the face loop.
388
+ * @param mask the mask to check.
389
+ * @param value true for mask set and false for mask unset.
375
390
  */
376
391
  isMaskedAroundFace(mask, value = true) {
377
392
  let node = this;
@@ -392,10 +407,10 @@ class HalfEdge {
392
407
  return true;
393
408
  }
394
409
  /**
395
- * Apply a edgeTag and mask to all edges around a face.
396
- * optionally apply it to all edge mates.
397
- * @param edgeTag tag to apply
398
- * @param bothSides If true, also apply the tag to the mates around the face.
410
+ * Apply a mask and edgeTag to all edges around a face. Optionally apply it to all edge mates.
411
+ * @param mask mask to apply.
412
+ * @param tag edgeTag to apply
413
+ * @param applyToMate If true, also apply the tag to the edge mates around the face.
399
414
  */
400
415
  setMaskAndEdgeTagAroundFace(mask, tag, applyToMate = false) {
401
416
  let node = this;
@@ -404,8 +419,8 @@ class HalfEdge {
404
419
  node.edgeTag = tag;
405
420
  if (applyToMate) {
406
421
  const mate = node.edgeMate;
407
- mate.edgeTag = tag;
408
422
  mate.setMask(mask);
423
+ mate.edgeTag = tag;
409
424
  }
410
425
  node = node.faceSuccessor;
411
426
  } while (node !== this);
@@ -420,7 +435,11 @@ class HalfEdge {
420
435
  } while (node !== this);
421
436
  return count;
422
437
  }
423
- /** Returns the number of nodes found with the given mask value around this vertex loop. */
438
+ /**
439
+ * Returns the number of nodes that match (or do not match) the given mask value around this face loop.
440
+ * @param mask the mask to check.
441
+ * @param value true for mask match and false for mask not match.
442
+ */
424
443
  countMaskAroundFace(mask, value = true) {
425
444
  let count = 0;
426
445
  let node = this;
@@ -440,7 +459,11 @@ class HalfEdge {
440
459
  }
441
460
  return count;
442
461
  }
443
- /** Returns the number of nodes found with the given mask value around this vertex loop. */
462
+ /**
463
+ * Returns the number of nodes that match (or do not match) the given mask value around this vertex loop.
464
+ * @param mask the mask to check.
465
+ * @param value true for mask match and false for mask not match.
466
+ */
444
467
  countMaskAroundVertex(mask, value = true) {
445
468
  let count = 0;
446
469
  let node = this;
@@ -460,7 +483,12 @@ class HalfEdge {
460
483
  }
461
484
  return count;
462
485
  }
463
- /** Returns the first node with given mask value around this vertex loop. */
486
+ /**
487
+ * Returns the first node that matches (or does not match) the given mask value around this vertex loop, starting
488
+ * with the instance node and proceeding via vertex successors.
489
+ * @param mask the mask to check.
490
+ * @param value true for mask match and false for mask not match.
491
+ */
464
492
  findMaskAroundVertex(mask, value = true) {
465
493
  let node = this;
466
494
  do {
@@ -470,7 +498,12 @@ class HalfEdge {
470
498
  } while (node !== this);
471
499
  return undefined;
472
500
  }
473
- /** Returns the first node with given mask value around this face loop. */
501
+ /**
502
+ * Returns the first node that matches (or does not match) the given mask value around this face loop, starting
503
+ * with the instance node and proceeding via face successors.
504
+ * @param mask the mask to check.
505
+ * @param value true for mask match and false for mask not match.
506
+ */
474
507
  findMaskAroundFace(mask, value = true) {
475
508
  let node = this;
476
509
  do {
@@ -480,7 +513,12 @@ class HalfEdge {
480
513
  } while (node !== this);
481
514
  return undefined;
482
515
  }
483
- /** Returns the first node with given mask value on this edge (i.e. examining this and this.mate) */
516
+ /**
517
+ * Returns the first node that matches (or does not match) the given mask value around this edge, starting
518
+ * with the instance node and then checking its edge mate.
519
+ * @param mask the mask to check.
520
+ * @param value true for mask match and false for mask not match.
521
+ */
484
522
  findMaskAroundEdge(mask, value = true) {
485
523
  if (this.isMaskSet(mask) === value)
486
524
  return this;
@@ -489,8 +527,9 @@ class HalfEdge {
489
527
  return mate;
490
528
  return undefined;
491
529
  }
492
- /** Set a mask, and return prior value.
493
- * @param mask mask to apply
530
+ /**
531
+ * Set a mask and return prior value.
532
+ * @param mask mask to apply.
494
533
  */
495
534
  testAndSetMask(mask) {
496
535
  const oldMask = this.maskBits & mask;
@@ -498,8 +537,8 @@ class HalfEdge {
498
537
  return oldMask;
499
538
  }
500
539
  /**
501
- * Set (copy) the this.x, this.y, this.z from node.x, node.y, node.z
502
- * @param node node containing xyz
540
+ * Set `this.x`, `this.y`, `this.z` from `node.x`, `node.y`, `node.z`.
541
+ * @param node node containing xyz.
503
542
  */
504
543
  setXYZFrom(node) {
505
544
  this.x = node.x;
@@ -507,7 +546,7 @@ class HalfEdge {
507
546
  this.z = node.z;
508
547
  }
509
548
  /**
510
- * Set (copy) the this.x, this.y, this.z from xyz.x, xyz.y, xyz.z
549
+ * Set `this.x`, `this.y`, `this.z` from `xyz.x`, `xyz.y`, `xyz.z`.
511
550
  * @param node source with x,y,z properties
512
551
  */
513
552
  setXYZ(xyz) {
@@ -516,32 +555,37 @@ class HalfEdge {
516
555
  this.z = xyz.z;
517
556
  }
518
557
  /**
519
- * Test if mask bits are set in the node's bitMask.
520
- * @return Return true (as a simple boolean, not a mask) if any bits of the mask parameter match bits of the node's bitMask
558
+ * Test if any of the `mask` bits are set in the node's bitMask.
559
+ * @return true (as a simple boolean, not a mask) if any bits of the `mask` match bits of the node's bitMask.
521
560
  */
522
- isMaskSet(mask) { return (this.maskBits & mask) !== 0; }
523
- /** (static!) method to test if a mask is set on a node.
524
- * This is used as filter in searches.
525
- * @returns true iff `node.isMaskSet (mask)`
561
+ isMaskSet(mask) {
562
+ return (this.maskBits & mask) !== 0;
563
+ }
564
+ /**
565
+ * Static method to test if any of the `mask` bits are set in the `node`'s bitMask.
566
+ * * This is used as filter in searches.
567
+ * @returns `node.isMaskSet(mask)`
526
568
  */
527
569
  static filterIsMaskOn(node, mask) {
528
570
  return node.isMaskSet(mask);
529
571
  }
530
- /** (static!) method to test if a mask is set on a node.
531
- * This is used as filter in searches.
532
- * @returns true iff `!node.isMaskSet (mask)`
572
+ /**
573
+ * Static method to test if any of the `mask` bits are set in the `node`'s bitMask.
574
+ * * This is used as filter in searches.
575
+ * @returns `!node.isMaskSet(mask)`
533
576
  */
534
577
  static filterIsMaskOff(node, mask) {
535
578
  return !node.isMaskSet(mask);
536
579
  }
537
580
  /**
538
581
  * Create an edge with initial id,x,y at each end.
539
- * @param id0 id for first node
540
- * @param x0 x coordinate for first node
541
- * @param y0 y coordinate for first node
542
- * @param id1 id for second node
543
- * @param x1 x coordinate for second node
544
- * @param y1 y coordinate for second node
582
+ * @param id0 id for first node.
583
+ * @param x0 x coordinate for first node.
584
+ * @param y0 y coordinate for first node.
585
+ * @param id1 id for second node.
586
+ * @param x1 x coordinate for second node.
587
+ * @param y1 y coordinate for second node.
588
+ * @returns the reference to the new node at (x0,y0).
545
589
  */
546
590
  static createEdgeXYXY(id0, x0, y0, id1, x1, y1) {
547
591
  const node0 = new HalfEdge(x0, y0);
@@ -552,15 +596,15 @@ class HalfEdge {
552
596
  node1._id = id1;
553
597
  return node0;
554
598
  }
555
- /** "pinch" ...
556
- *
557
- * * is the universal manipulator for manipulating a node's next and prev pointers
558
- * * swaps face predecessors of nodeA and nodeB.
559
- * * is its own inverse.
560
- * * if nodeA, nodeB are in different face loops, the loops join to one loop.
561
- * * if nodeA, nodeB are in the same face loop, the loop splits into two loops.
599
+ /**
600
+ *"Pinch" is the universal operator for manipulating a node's next and previous pointers.
601
+ * * It is its own inverse: applying it twice on the same inputs (i.e., `pinch(a,b); pinch(a,b);`) gets back to
602
+ * where you started.
603
+ * * If the inputs are in different face loops, the loops join to one face loop after the pinch.
604
+ * * If the inputs are in the same face loop, the loop splits into two face loops after the pinch.
562
605
  */
563
606
  static pinch(nodeA, nodeB) {
607
+ // Visualization can be found at geometry/internaldocs/Graph.md
564
608
  if (nodeA !== nodeB) {
565
609
  const predA = nodeA._facePredecessor;
566
610
  const predB = nodeB._facePredecessor;
@@ -572,17 +616,19 @@ class HalfEdge {
572
616
  }
573
617
  /**
574
618
  * Pinch this half edge out of its base vertex loop.
575
- * @return the surviving HalfEdge in the vertex loop, or undefined if the instance HalfEdge is already dangling
619
+ * @return the surviving HalfEdge in the vertex loop or `undefined` if the instance HalfEdge is already dangling.
576
620
  */
577
621
  yankFromVertexLoop() {
578
622
  const other = this.edgeMate.faceSuccessor;
579
623
  if (other === this)
580
624
  return undefined;
625
+ // at this point "other" is the vertex predecessor of "this"
581
626
  HalfEdge.pinch(this, other);
582
627
  return other;
583
628
  }
584
- /** Turn all pointers to undefined so garbage collector can reuse the object.
585
- * This is to be called only by a Graph object that is being decommissioned.
629
+ /**
630
+ * Turn all pointers to `undefined` so garbage collector can reuse the object.
631
+ * * This is to be called only by a Graph object that is being decommissioned.
586
632
  */
587
633
  decommission() {
588
634
  this._facePredecessor = undefined;
@@ -590,27 +636,34 @@ class HalfEdge {
590
636
  this._edgeMate = undefined;
591
637
  }
592
638
  /** Return the node. This identity function is useful as the NodeFunction in collector methods. */
593
- static nodeToSelf(node) { return node; }
594
- /** Return the id of a node. Useful for collector methods. */
595
- static nodeToId(node) { return node.id; }
596
- /** Return the id of a node.Useful for collector methods. */
597
- static nodeToIdString(node) { return node.id.toString(); }
598
- /** Return the [id, [x,y]] of a node. Useful for collector methods. */
639
+ static nodeToSelf(node) {
640
+ return node;
641
+ }
642
+ /** Return the id of a node. Useful for collector methods. */
643
+ static nodeToId(node) {
644
+ return node.id;
645
+ }
646
+ /** Return the id of a node as string. Useful for collector methods. */
647
+ static nodeToIdString(node) {
648
+ return node.id.toString();
649
+ }
650
+ /** Return the [id, mask, [x,y]] of a node. Useful for collector methods. */
599
651
  static nodeToIdMaskXY(node) {
600
652
  return { id: node.id, mask: HalfEdge.nodeToMaskString(node), xy: [node.x, node.y] };
601
653
  }
602
- /** Return the [id, [x,y]] of a node. Useful for collector methods. */
654
+ /** Return the [id, mask, [x,y]] of a node as string. Useful for collector methods. */
603
655
  static nodeToIdXYString(node) {
604
656
  const s = `${node.id.toString()}+${HalfEdge.nodeToMaskString(node)}[${node.x},${node.y}]`;
605
657
  return s;
606
658
  }
607
- /** Return the [id, [x,y],z] of a node. Useful for collector methods. */
659
+ /** Return the [id, [x,y,z]] of a node as string. Useful for collector methods. */
608
660
  static nodeToIdXYZString(node) {
609
661
  return `[${node.id.toString()}: ${node.x},${node.y},${node.z}]`;
610
662
  }
611
- /** Create a string representation of the mask
663
+ /**
664
+ * Create a string representation of the mask.
612
665
  * * Null mask is empty string.
613
- * * Appended characters B,P,X for Boundary, Primary, Exterior mask bits.
666
+ * * Appended characters B,P,X,N are for BOUNDARY_EDGE, PRIMARY_EDGE, EXTERIOR, and NULL_FACE mask bits.
614
667
  */
615
668
  static nodeToMaskString(node) {
616
669
  let s = "";
@@ -624,49 +677,46 @@ class HalfEdge {
624
677
  s += "N";
625
678
  return s;
626
679
  }
627
- /** Return [x,y] with coordinates of node */
628
- static nodeToXY(node) { return [node.x, node.y]; }
629
- /** Return Vector2d to face successor, with only xy coordinates */
680
+ /** Return [x,y] with coordinates of node. */
681
+ static nodeToXY(node) {
682
+ return [node.x, node.y];
683
+ }
684
+ /** Return Vector2d from `this` to face successor (with only xy coordinates). */
630
685
  vectorToFaceSuccessorXY(result) {
631
686
  return Vector2d.create(this.faceSuccessor.x - this.x, this.faceSuccessor.y - this.y, result);
632
687
  }
633
- /** Return Vector3d to face successor */
688
+ /** Return Vector3d from `this` to face successor. */
634
689
  vectorToFaceSuccessor(result) {
635
690
  const other = this.faceSuccessor;
636
691
  return Vector3d.create(other.x - this.x, other.y - this.y, other.z - this.z, result);
637
692
  }
638
- /** Return Vector3d to face successor */
693
+ /** Return Vector3d from `this` to face successor. */
639
694
  vectorToFacePredecessor(result) {
640
695
  const other = this.facePredecessor;
641
696
  return Vector3d.create(other.x - this.x, other.y - this.y, other.z - this.z, result);
642
697
  }
643
- /** test if spaceNode is in the sector at sectorNode */
698
+ /** Test if `spaceNode` is in the sector at `sectorNode`. */
644
699
  static isNodeVisibleInSector(spaceNode, sectorNode) {
645
- // remark: fussy details ported from native code.
646
- // The obscure cases seemed "unlikely" at first. But preexisting unit tests for triangulation pinged just about everything.
647
- // So it really matters to do the "0" cases this way.
648
- // (As usual, hard coded zero is suspect, but it seems to work nicely in the discrete decisions.)
700
+ // remark: fussy details ported from native code. The obscure cases seemed "unlikely" at first. But pre-existing
701
+ // unit tests for triangulation pinged just about everything. So it really matters to do the "0" cases this way
702
+ // (as usual, hard coded zero is suspect, but it seems to work nicely in the discrete decisions).
649
703
  if (sectorNode.vertexSuccessor === sectorNode)
650
704
  return true;
651
705
  const successor = sectorNode.faceSuccessor;
652
706
  const predecessor = sectorNode.facePredecessor;
653
707
  const successorCross = this.crossProductXYToTargets(sectorNode, successor, spaceNode);
654
708
  const predecessorCross = this.crossProductXYToTargets(predecessor, sectorNode, spaceNode);
655
- // simplest case: two positives
709
+ // simplest case: two positives
656
710
  if (successorCross > 0.0 && predecessorCross > 0.0)
657
711
  return true;
658
712
  const sectorCross = this.crossProductXYToTargets(predecessor, sectorNode, successor);
659
713
  if (predecessorCross <= 0.0 && successorCross <= 0.0) {
660
714
  if (predecessorCross === 0.0 && successorCross === 0.0 && sectorCross === 0.0) {
661
- /* Everything is on a line.*/
662
- /* If the sector is a degenerate face, nodeP can only be
663
- in if it is the other node in the degenerate face.
664
- */
715
+ // Everything is on a line. If the sector is a degenerate face, nodeP
716
+ // can only be in if it is the other node in the degenerate face.
665
717
  if (predecessor === successor && sectorNode.vertexSuccessor !== sectorNode)
666
718
  return spaceNode === successor;
667
- /* Sector is 360 degrees. Call it in only if vector from predP
668
- to sectorP points forward to nodeP.
669
- */
719
+ // Sector is 360 degrees. Call it in only if vector from predP to sectorP points forward to nodeP.
670
720
  return HalfEdge.dotProductNodeToNodeVectorsXY(predecessor, sectorNode, sectorNode, spaceNode) > 0.0;
671
721
  }
672
722
  else {
@@ -675,56 +725,59 @@ class HalfEdge {
675
725
  }
676
726
  else {
677
727
  if (sectorCross === 0.0 && predecessorCross !== 0.0 && successorCross !== 0.0) {
678
- // The incoming and outgoing edges at the sector are identical direction.
679
- // We have to decide if this node is inside the degenerate face (i.e. a geometrically empty sector)
680
- // or outside (i.e. a nearly complete sector).
681
- // In the inside case, the face is just two nodes.
682
- // Exact equality for zero is ok because cross product should be using identical
683
- // coordinates in subtracted terms. (All furrow eyebrows in unison ....)
728
+ // The incoming and outgoing edges at the sector are identical direction. We have to decide if this node is
729
+ // inside the degenerate face (i.e. a geometrically empty sector) or outside (i.e. a nearly complete sector).
730
+ // In the inside case, the face is just two nodes. Exact equality for zero is ok because cross product should
731
+ // be using identical coordinates in subtracted terms (all furrow eyebrows in unison).
684
732
  return predecessor !== successor;
685
733
  }
686
734
  return sectorCross < 0.0;
687
735
  }
688
736
  }
689
- /** Returns Return cross product (2d) of vectors from baseA to targetA and baseB to targetB */
737
+ /** Returns 2D cross product of vectors from `base` to `targetA` and from `base` to `targetB`. */
690
738
  static crossProductXYToTargets(base, targetA, targetB) {
691
739
  return Geometry.crossProductXYXY(targetA.x - base.x, targetA.y - base.y, targetB.x - base.x, targetB.y - base.y);
692
740
  }
693
- /** Returns Return dot product (2d) of vectors along two edges. */
741
+ /** Returns 2D dot product of vectors from `baseA` to `targetA` and from `baseB` to `targetB`. */
694
742
  static dotProductNodeToNodeVectorsXY(baseA, targetA, baseB, targetB) {
695
743
  return Geometry.dotProductXYXY(targetA.x - baseA.x, targetA.y - baseA.y, targetB.x - baseB.x, targetB.y - baseB.y);
696
744
  }
697
- /** Return cross product (2d) of vectors from nodeA to nodeB and nodeB to nodeC
698
- */
745
+ /** Return 2D cross product of vectors from `nodeA` to `nodeB` and from `nodeB` to `nodeC`. */
699
746
  static crossProductXYAlongChain(nodeA, nodeB, nodeC) {
700
747
  return Geometry.crossProductXYXY(nodeB.x - nodeA.x, nodeB.y - nodeA.y, nodeC.x - nodeB.x, nodeC.y - nodeB.y);
701
748
  }
702
749
  /**
703
750
  * Compute whether the sector defined by the chain of nodes is convex.
751
+ * * This function is determining if, in the traversal of the HalfEdges in a face loop, a corner makes a left turn
752
+ * (convex) or a right turn (not-convex). Note that if we have a convex face, then to traverse it in ccw orientation,
753
+ * we always do left turns. However, if the face is not convex, we make both left and right turns.
704
754
  * * This computation ignores z-coordinates and connectivity, so the nodes are not required to be in the same face loop.
705
- * @param nodeA the first node in the chain, nominally the face predecessor of nodeB
706
- * @param nodeB the second node in the chain; the node at the sector vertex
707
- * @param nodeC the third node in the chain, nominally the face successor of nodeB
708
- * @param signedAreaTol optional signed area tolerance to use in test for parallel vectors.
709
- * Typically this is a fraction of the sector's face's signed area. We can't compute area here, so if undefined, zero tolerance is used.
710
- * @returns true iff the sector is convex
755
+ * @param nodeA the first node in the chain, nominally the face predecessor of nodeB.
756
+ * @param nodeB the second node in the chain; the node at the sector vertex.
757
+ * @param nodeC the third node in the chain, nominally the face successor of nodeB.
758
+ * @param signedAreaTol optional signed area tolerance to use in test for parallel vectors. Typically this is a
759
+ * fraction of the sector's face's signed area. We can't compute area here, so if undefined, zero tolerance is used.
760
+ * @returns true iff the sector is convex. A degenerate sector, where the incident edges overlap, returns false.
711
761
  */
712
762
  static isSectorConvex(nodeA, nodeB, nodeC, signedAreaTol = 0) {
713
763
  const signedSectorArea = 0.5 * HalfEdge.crossProductXYAlongChain(nodeA, nodeB, nodeC);
714
764
  signedAreaTol = signedAreaTol ?? 0.0;
715
765
  if (Math.abs(signedSectorArea) <= Math.abs(signedAreaTol)) {
716
- // the sector vectors are nearly parallel or antiparallel; only the former is deemed convex.
766
+ // the sector vectors are nearly parallel or anti-parallel; only the former is deemed convex.
717
767
  return HalfEdge.dotProductNodeToNodeVectorsXY(nodeA, nodeB, nodeB, nodeC) > 0.0;
718
768
  }
719
- return signedSectorArea > -signedAreaTol; // call it convex even if we are a little bit on the other side of zero
769
+ // // sector is convex if the area is positive. Call it convex even if we are a little bit on the other side of zero.
770
+ return signedSectorArea > -signedAreaTol;
720
771
  }
721
772
  /**
722
773
  * Compute whether the sector at this node is convex.
774
+ * * This function is determining if, in the traversal of the HalfEdges in a face loop, a corner makes a left turn
775
+ * (convex) or a right turn (not-convex). Note that if we have a convex face, then to traverse it in ccw orientation,
776
+ * we always do left turns. However, if the face is not convex, we make both left and right turns.
723
777
  * * This computation ignores z-coordinates.
724
- * @param signedAreaTol optional signed area tolerance to use in test for parallel vectors.
725
- * If undefined, a fraction ([[Geometry.smallMetricDistanceSquared]]) of the computed signed area is used.
726
- * Pass zero to skip toleranced computation.
727
- * @returns true iff the sector is convex and its two edges are not antiparallel.
778
+ * @param signedAreaTol optional signed area tolerance to use in test for parallel vectors. If undefined, a fraction
779
+ * (`Geometry.smallMetricDistanceSquared`) of the computed signed area is used. Pass 0 to skip toleranced computation.
780
+ * @returns true iff the sector is convex. A degenerate sector, where the incident edges overlap, returns false.
728
781
  */
729
782
  isSectorConvex(signedAreaTol) {
730
783
  if (signedAreaTol === undefined)
@@ -733,10 +786,11 @@ class HalfEdge {
733
786
  }
734
787
  /**
735
788
  * Compute whether this face is convex.
789
+ * * Note that if we have a convex face, then to traverse it in ccw orientation, we always do left turns.
790
+ * However, if the face is not convex, we make both left and right turns.
736
791
  * * This computation ignores z-coordinates.
737
- * @param tolerance optional relative tolerance to use in test for parallel vectors.
738
- * Default value is [[Geometry.smallMetricDistanceSquared]].
739
- * Pass zero to skip toleranced computation.
792
+ * @param tolerance optional relative tolerance to use in test for parallel vectors. Default value is
793
+ * `Geometry.smallMetricDistanceSquared`. Pass 0 to skip toleranced computation.
740
794
  * @returns true iff this face is convex.
741
795
  */
742
796
  isFaceConvex(tolerance = Geometry.smallMetricDistanceSquared) {
@@ -749,83 +803,80 @@ class HalfEdge {
749
803
  } while (node !== this);
750
804
  return true;
751
805
  }
752
- /**
753
- * Isolate the edge from the graph by yanking each end from its vertex loop.
754
- */
806
+ /** Isolate the edge from the graph by yanking each end from its vertex loop. */
755
807
  isolateEdge() {
756
808
  const mate = this.edgeMate;
757
809
  this.yankFromVertexLoop();
758
810
  mate.yankFromVertexLoop();
759
811
  }
760
- /**
761
- * @return whether this edge is isolated from the rest of the graph.
762
- */
812
+ /** Specify whether this edge is isolated from the rest of the graph. */
763
813
  get isIsolatedEdge() {
764
814
  return this === this.vertexSuccessor && this.edgeMate === this.edgeMate.vertexSuccessor;
765
815
  }
766
- /** Return true if `this` is lexically below `other`, comparing y first then x. */
816
+ /** Return true if `this` is lexically below `other`. We compare y first, then x, and ignore z. */
767
817
  belowYX(other) {
768
- // Check y's
769
- // if (!Geometry.isSameCoordinate(a.y, b.y))
770
818
  if (this.y < other.y)
771
819
  return true;
772
820
  if (this.y > other.y)
773
821
  return false;
774
- // same y.
775
- // Check x's
776
822
  if (this.x < other.x)
777
823
  return true;
778
824
  return false;
779
825
  }
780
- /** Returns Returns true if the node does NOT have Mask.EXTERIOR_MASK set. */
781
- static testNodeMaskNotExterior(node) { return !node.isMaskSet(HalfEdgeMask.EXTERIOR); }
782
- /** Returns Returns true if the edge mate has Mask.EXTERIOR_MASK set. */
783
- static testMateMaskExterior(node) { return node.edgeMate.isMaskSet(HalfEdgeMask.EXTERIOR); }
784
- /** Returns radians between this edge and its face predecessor edge, using all three coordinates x,y,z and given normal to resolve sweep direction.
785
- * * The returned angle is positive, i.e. may be larger than PI radians.
786
- */
826
+ /** Returns `true` if the node does NOT have `Mask.EXTERIOR_MASK` set. */
827
+ static testNodeMaskNotExterior(node) {
828
+ return !node.isMaskSet(HalfEdgeMask.EXTERIOR);
829
+ }
830
+ /** Returns `true` if the edge mate has `Mask.EXTERIOR_MASK` set. */
831
+ static testMateMaskExterior(node) {
832
+ return node.edgeMate.isMaskSet(HalfEdgeMask.EXTERIOR);
833
+ }
834
+ /**
835
+ * Returns radians between this edge and its face predecessor edge, using all three coordinates x,y,z and
836
+ * given normal to resolve sweep direction.
837
+ * * The returned angle is non-negative: 0 <= radians < 2*PI.
838
+ */
787
839
  static sectorSweepRadiansXYZ(node, normal) {
788
- const nodeB = node.faceSuccessor;
789
- const nodeC = node.facePredecessor;
790
- return Angle.orientedRadiansBetweenVectorsXYZ(nodeB.x - node.x, nodeB.y - node.y, nodeB.z - node.z, nodeC.x - node.x, nodeC.y - node.y, nodeC.z - node.z, normal.x, normal.y, normal.z, true);
840
+ const suc = node.faceSuccessor;
841
+ const pred = node.facePredecessor;
842
+ return Angle.orientedRadiansBetweenVectorsXYZ(suc.x - node.x, suc.y - node.y, suc.z - node.z, pred.x - node.x, pred.y - node.y, pred.z - node.z, normal.x, normal.y, normal.z, true);
791
843
  }
792
- /** Returns Returns true if the face has positive area in xy parts. */
844
+ /** Returns true if the face has positive area in xy parts. */
793
845
  static testFacePositiveAreaXY(node) {
794
846
  return node.countEdgesAroundFace() > 2 && node.signedFaceArea() > 0.0;
795
847
  }
796
- /** Return true if x and y coordinates of this and other are exactly equal */
848
+ /** Return true if x and y coordinates of `this` and `other` are exactly equal .*/
797
849
  isEqualXY(other) {
798
850
  return this.x === other.x && this.y === other.y;
799
851
  }
800
- /** Return distance between xy coordinates of this and other node */
852
+ /** Return distance between xy coordinates of `this` and `other` node. */
801
853
  distanceXY(other) {
802
854
  return Geometry.distanceXYXY(this.x, this.y, other.x, other.y);
803
855
  }
804
- /** Return distance between xyz coordinates of this and other node */
856
+ /** Return distance between xyz coordinates of `this` and `other` node. */
805
857
  distanceXYZ(other) {
806
858
  return Geometry.distanceXYZXYZ(this.x, this.y, this.z, other.x, other.y, other.z);
807
859
  }
808
860
  /**
809
- *
810
- * * Evaluate f(node) at each node around a face loop.
811
- * * Collect the function values.
812
- * @returns Return the array of function values.
861
+ * Evaluate `f(node)` at each node around `this` node's face loop. Collect the function values.
862
+ * @param f optional node function. If `undefined`, collect the nodes themselves.
863
+ * @returns the array of function values.
813
864
  */
814
865
  collectAroundFace(f) {
815
866
  const nodes = [];
816
867
  let node = this;
817
868
  do {
818
- nodes.push(f ? f(node) : node);
869
+ nodes.push(f ? f(node) : node); // push the node itself if "f" is undefined
819
870
  node = node.faceSuccessor;
820
871
  } while (node !== this);
821
872
  return nodes;
822
873
  }
823
874
  /**
824
- * search around a vertex for nodes that have a specified mask setting.
825
- * @param vertexSeed first node to search
826
- * @param mask target mask
827
- * @param value target value for mask on half edges.
828
- * @param collectedNodes optional array to be cleared and receive masked nodes
875
+ * Search around `this` node's vertex loop for nodes with the specified mask value.
876
+ * * Returned nodes satisfy `node.isMaskSet(mask) === value`.
877
+ * @param mask target mask.
878
+ * @param value target boolean value for mask on half edges.
879
+ * @param result optional array to be cleared and receive masked nodes.
829
880
  */
830
881
  collectMaskedEdgesAroundVertex(mask, value = true, result) {
831
882
  if (result === undefined)
@@ -841,25 +892,23 @@ class HalfEdge {
841
892
  return result;
842
893
  }
843
894
  /**
844
- *
845
- * * Evaluate f(node) at each outbound node around this node's vertex loop.
846
- * * Collect the function values.
847
- * @returns Return the array of function values.
895
+ * Evaluate `f(node)` at each node around `this` node's vertex loop. Collect the function values.
896
+ * @param f optional node function. If `undefined`, collect the nodes themselves.
897
+ * @returns the array of function values.
848
898
  */
849
899
  collectAroundVertex(f) {
850
900
  const nodes = [];
851
901
  let node = this;
852
902
  do {
853
- nodes.push(f ? f(node) : node);
903
+ nodes.push(f ? f(node) : node); // push the node itself if "f" is undefined
854
904
  node = node.vertexSuccessor;
855
905
  } while (node !== this);
856
906
  return nodes;
857
907
  }
858
908
  /**
859
- *
860
- * * Evaluate f(node) at each node around a face loop.
861
- * * Sum the function values
862
- * @returns Return the sum
909
+ * Evaluate `f(node)` at each node around `this` node's face loop. Sum the function values.
910
+ * @param f node to number function.
911
+ * @returns the sum of function values.
863
912
  */
864
913
  sumAroundFace(f) {
865
914
  let node = this;
@@ -871,10 +920,9 @@ class HalfEdge {
871
920
  return sum;
872
921
  }
873
922
  /**
874
- *
875
- * * Evaluate f(node) at each outbound node around this node's vertex loop.
876
- * * Sum the function values
877
- * @returns Return the sum
923
+ * Evaluate `f(node)` at each node around `this` node's vertex loop. Sum the function values.
924
+ * @param f node to number function.
925
+ * @returns the sum of function values.
878
926
  */
879
927
  sumAroundVertex(f) {
880
928
  let node = this;
@@ -885,7 +933,7 @@ class HalfEdge {
885
933
  } while (node !== this);
886
934
  return sum;
887
935
  }
888
- /** For all the nodes in the face loop of the given node, clear out the mask given */
936
+ /** Clear the given mask bits for all nodes in `this` node's face loop. */
889
937
  clearMaskAroundFace(mask) {
890
938
  let node = this;
891
939
  do {
@@ -893,7 +941,7 @@ class HalfEdge {
893
941
  node = node.faceSuccessor;
894
942
  } while (node !== this);
895
943
  }
896
- /** For all the nodes in the vertex loop of the given node, clear out the mask given */
944
+ /** Clear out the given mask bits for all nodes in `this` node's vertex loop. */
897
945
  clearMaskAroundVertex(mask) {
898
946
  let node = this;
899
947
  do {
@@ -902,29 +950,39 @@ class HalfEdge {
902
950
  } while (node !== this);
903
951
  }
904
952
  /**
905
- * Compute the signed sum of xy areas of triangles from first node to edges.
953
+ * Compute the signed xy area of `this` node's face.
906
954
  * * A positive area is counterclockwise.
907
955
  * * A negative area is clockwise.
908
- * @returns signed area of this node's face
956
+ * @returns signed area of `this` node's face.
909
957
  */
910
958
  signedFaceArea() {
911
959
  let sum = 0;
912
- // sum area of trapezoids.
913
- // * the formula in the loop gives twice the area (because it does not average the y values).
914
- // * this is fixed up at the end by a single multiply by 0.5
915
- // * individual trapezoid heights are measured from y at the start node to keep area values numerical smaller.
960
+ // We start from `this` node and traverse the face, forming trapezoids with vertical bases.
961
+ // Some trapezoids will have a zero-length base, e.g., a triangle.
962
+ // Trapezoid bases are measured from `this.y` to keep area values numerically smaller.
963
+ // Split each trapezoid into two triangles whose y-coordinates are above/below `this.y`.
964
+ // Each trapezoid's signed area is computed by summing the signed areas of these two triangles.
965
+ // Area signs depend on careful assignment of signs to trapezoid height (relative to `this.x`) and trapezoid
966
+ // bases (relative to `this.y`).
967
+ // Some trapezoids have signed areas outside the face that are cancelled out by subsequent trapezoids.
968
+ // The formula in the loop accumulates twice the trapezoid areas, so at the end we halve the sum.
969
+ // Illustration of the algorithm can be found at geometry/internaldocs/Graph.md
970
+ let x0 = this.x;
971
+ let x1 = 0.0;
916
972
  const y0 = this.y;
917
973
  let dy0 = 0.0;
918
974
  let dy1 = 0.0;
919
- let x0 = this.x;
920
- let x1;
921
975
  let node1;
922
976
  let node0 = this;
923
977
  do {
924
978
  node1 = node0.faceSuccessor;
925
979
  x1 = node1.x;
926
980
  dy1 = node1.y - y0;
927
- sum += (x0 - x1) * (dy0 + dy1);
981
+ // When trapezoid bases dy0 and dy1 have opposite sign, this product is (twice) the difference of the areas
982
+ // of the trapezoid above and below y=y0. This is equal to (twice) the difference of the areas of the congruent
983
+ // triangles formed by the trapezoid diagonals and bases, a consequence of the other two triangles having equal
984
+ // area, and thus cancelling out.
985
+ sum += (x0 - x1) * (dy0 + dy1); // twice trapezoid area = trapezoid height * sum of trapezoid bases
928
986
  x0 = x1;
929
987
  dy0 = dy1;
930
988
  node0 = node1;
@@ -932,108 +990,105 @@ class HalfEdge {
932
990
  return 0.5 * sum;
933
991
  }
934
992
  /**
935
- * interpolate xy coordinates between this node and its face successor.
993
+ * Interpolate xy coordinates between `this` node and its face successor.
936
994
  * @param fraction fractional position along this edge.
937
- * @param result xy coordinates
995
+ * @param result optional point to populate and return.
938
996
  */
939
997
  fractionToPoint2d(fraction, result) {
940
- const node1 = this.faceSuccessor;
941
- return Point2d.create(this.x + (node1.x - this.x) * fraction, this.y + (node1.y - this.y) * fraction, result);
998
+ const suc = this.faceSuccessor;
999
+ return Point2d.create(this.x + (suc.x - this.x) * fraction, this.y + (suc.y - this.y) * fraction, result);
942
1000
  }
943
1001
  /**
944
- * interpolate xy coordinates between this node and its face successor.
1002
+ * Interpolate xyz coordinates between `this` node and its face successor.
945
1003
  * @param fraction fractional position along this edge.
946
- * @param result xy coordinates
1004
+ * @param result optional point to populate and return.
947
1005
  */
948
1006
  fractionToPoint3d(fraction, result) {
949
- const node1 = this.faceSuccessor;
950
- return Point3d.create(this.x + (node1.x - this.x) * fraction, this.y + (node1.y - this.y) * fraction, this.z + (node1.z - this.z) * fraction, result);
1007
+ const suc = this.faceSuccessor;
1008
+ return Point3d.create(this.x + (suc.x - this.x) * fraction, this.y + (suc.y - this.y) * fraction, this.z + (suc.z - this.z) * fraction, result);
951
1009
  }
952
1010
  /**
953
- * * interpolate xy coordinates at fractionAlong between this node and its face successor.
954
- * * shift to left by fractionPerpendicular
955
- * @param fraction fractional position along this edge.
956
- * @param result xy coordinates
1011
+ * Interpolate xy coordinates at `fractionAlong` between this node and its face successor. Then shift perpendicular
1012
+ * to the left of this edge by `fractionPerpendicular`.
1013
+ * @param fractionAlong fractional position along this edge.
1014
+ * @param fractionPerpendicular fractional position along the left perpendicular with the same length as this edge.
1015
+ * @param result optional xy coordinates.
957
1016
  */
958
1017
  fractionAlongAndPerpendicularToPoint2d(fractionAlong, fractionPerpendicular, result) {
959
- const node1 = this.faceSuccessor;
960
- const dx = node1.x - this.x;
961
- const dy = node1.y - this.y;
1018
+ const suc = this.faceSuccessor;
1019
+ const dx = suc.x - this.x;
1020
+ const dy = suc.y - this.y;
962
1021
  return Point2d.create(this.x + dx * fractionAlong - dy * fractionPerpendicular, this.y + dy * fractionAlong + dx * fractionPerpendicular, result);
963
1022
  }
964
- /**
965
- * return the 3d coordinates at this half edge base
966
- */
1023
+ /** Return the 3d coordinates at this half edge. */
967
1024
  getPoint3d(result) {
968
1025
  return Point3d.create(this.x, this.y, this.z, result);
969
1026
  }
970
- /**
971
- * return the 2d coordinates at this half edge base
972
- */
1027
+ /** Return the 2d coordinates at this half edge. */
973
1028
  getPoint2d(result) {
974
1029
  return Point2d.create(this.x, this.y, result);
975
1030
  }
976
- /**
977
- * return a 3d vector from start to end of this half edge.
978
- */
1031
+ /** Return a 3d vector from start to end of this half edge. */
979
1032
  getVector3dAlongEdge(result) {
980
- const nodeB = this.faceSuccessor;
981
- return Vector3d.create(nodeB.x - this.x, nodeB.y - this.y, nodeB.z - this.z, result);
1033
+ const suc = this.faceSuccessor;
1034
+ return Vector3d.create(suc.x - this.x, suc.y - this.y, suc.z - this.z, result);
982
1035
  }
983
- /**
984
- * return a 2d vector from start to end of this half edge
985
- */
1036
+ /** Return a 2d vector from start to end of this half edge. */
986
1037
  getVector2dAlongEdge(result) {
987
- const nodeB = this.faceSuccessor;
988
- return Vector2d.create(nodeB.x - this.x, nodeB.y - this.y, result);
1038
+ const suc = this.faceSuccessor;
1039
+ return Vector2d.create(suc.x - this.x, suc.y - this.y, result);
989
1040
  }
990
1041
  /**
991
- * Return the interpolated x coordinate between this node and its face successor.
1042
+ * Return the interpolated x coordinate between `this` node and its face successor.
992
1043
  * @param fraction fractional position along this edge.
993
1044
  */
994
1045
  fractionToX(fraction) {
995
- const node1 = this.faceSuccessor;
996
- return this.x + (node1.x - this.x) * fraction;
1046
+ const suc = this.faceSuccessor;
1047
+ return this.x + (suc.x - this.x) * fraction;
997
1048
  }
998
1049
  /**
999
- * Return the interpolated y coordinate between this node and its face successor.
1050
+ * Return the interpolated y coordinate between `this` node and its face successor.
1000
1051
  * @param fraction fractional position along this edge.
1001
1052
  */
1002
1053
  fractionToY(fraction) {
1003
- const node1 = this.faceSuccessor;
1004
- return this.y + (node1.y - this.y) * fraction;
1054
+ const suc = this.faceSuccessor;
1055
+ return this.y + (suc.y - this.y) * fraction;
1005
1056
  }
1006
1057
  /**
1007
- * Return the interpolated z coordinate between this node and its face successor.
1058
+ * Return the interpolated z coordinate between `this` node and its face successor.
1008
1059
  * @param fraction fractional position along this edge.
1009
1060
  */
1010
1061
  fractionToZ(fraction) {
1011
- const node1 = this.faceSuccessor;
1012
- return this.z + (node1.z - this.z) * fraction;
1062
+ const suc = this.faceSuccessor;
1063
+ return this.z + (suc.z - this.z) * fraction;
1013
1064
  }
1014
1065
  /**
1015
- * * Compute fractional coordinates of the intersection of edges from given base nodes
1066
+ * Compute fractional coordinates of the intersection of edges from given base nodes.
1016
1067
  * * If parallel or colinear, return undefined.
1017
1068
  * * If (possibly extended) lines intersect, return the fractions of intersection as x,y in the result.
1018
- * @param nodeA0 Base node of edge A
1019
- * @param nodeB0 Base node of edge B
1020
- * @param result optional preallocated result
1069
+ * @param nodeA0 base node of edge A.
1070
+ * @param nodeB0 base node of edge B.
1071
+ * @param result optional preallocated result.
1021
1072
  */
1022
1073
  static transverseIntersectionFractions(nodeA0, nodeB0, result) {
1023
1074
  const nodeA1 = nodeA0.faceSuccessor;
1024
1075
  const nodeB1 = nodeB0.faceSuccessor;
1025
1076
  if (!result)
1026
1077
  result = Vector2d.create();
1078
+ // To find the fraction of intersection (ta,tb), you need to solve these 2 equations:
1079
+ // (nodeA1.x - nodeA0.x)ta + (nodeB0.x - nodeB1.x)tb = nodeB0.x - nodeA0.x
1080
+ // (nodeA1.y - nodeA0.y)ta + (nodeB0.y - nodeB1.y)tb = nodeB0.y - nodeA0.y
1081
+ // Proof can be found at geometry/internaldocs/Graph.md
1027
1082
  if (SmallSystem.linearSystem2d(nodeA1.x - nodeA0.x, nodeB0.x - nodeB1.x, nodeA1.y - nodeA0.y, nodeB0.y - nodeB1.y, nodeB0.x - nodeA0.x, nodeB0.y - nodeA0.y, result))
1028
1083
  return result;
1029
1084
  return undefined;
1030
1085
  }
1031
1086
  /**
1032
- * * Compute fractional coordinates of the intersection of a horizontal line with an edge.
1087
+ * Compute fractional position (possibly outside 0..1) of the intersection of a horizontal line with an edge.
1033
1088
  * * If the edge is horizontal with (approximate) identical y, return the node.
1034
- * * If the edge is horizontal with different y, return undefined.
1035
- * * If the edge is not horizontal, return the fractional position (possibly outside 0..1) of the intersection.
1036
- * @param node0 Base node of edge
1089
+ * * If the edge is horizontal with different y, return `undefined`.
1090
+ * @param node0 base node of edge.
1091
+ * @param y y coordinate of the horizontal line.
1037
1092
  */
1038
1093
  static horizontalScanFraction(node0, y) {
1039
1094
  const node1 = node0.faceSuccessor;
@@ -1042,13 +1097,16 @@ class HalfEdge {
1042
1097
  return node0;
1043
1098
  if (Geometry.isSameCoordinate(dy, 0.0))
1044
1099
  return undefined;
1100
+ // parametric equation of line is (1-t)y0 + ty1 which is equal to y at the intersection so
1101
+ // (1-t)y0 + ty1 = y or t = (y-y0)/(y1-y0)
1045
1102
  return Geometry.conditionalDivideFraction(y - node0.y, dy);
1046
1103
  }
1047
1104
  /**
1048
- * * Compute fractional coordinates of the intersection of a horizontal line with an edge.
1049
- * * If the edge is horizontal return undefined (no test for horizontal at y!!!)
1050
- * * If the edge is not horizontal and y is between its end y's, return the fraction
1051
- * @param node0 Base node of edge
1105
+ * Compute fractional position (inside 0..1) of the intersection of a horizontal line with an edge.
1106
+ * * If fractional position is outside 0..1, return `undefined`.
1107
+ * * If the edge is horizontal return `undefined` (no test for horizontal at y).
1108
+ * @param node0 base node of edge.
1109
+ * @param y y coordinate of the horizontal line.
1052
1110
  */
1053
1111
  static horizontalScanFraction01(node0, y) {
1054
1112
  const node1 = node0.faceSuccessor;
@@ -1063,12 +1121,12 @@ class HalfEdge {
1063
1121
  return undefined;
1064
1122
  }
1065
1123
  /**
1066
- * Copy various data from source to this.
1067
- * @param source other half edge.
1068
- * @param XYZ copy simple coordinates
1069
- * @param copyVertexData true to copy data belonging to the vertex. (i.e. the "i" member)
1070
- * @param copyVertexData true to copy data belonging to the edge. (i.e. call transferEdgeData)
1071
- * @param copyFaceData true to copy faceTag
1124
+ * Copy various data from source to `this`.
1125
+ * @param source source half edge.
1126
+ * @param copyXYZ true to copy xyz coordinates.
1127
+ * @param copyVertexData true to copy data belonging to the vertex (i.e. the `i` member).
1128
+ * @param copyEdgeData true to copy data belonging to the edge (i.e. edge masks, `edgeTag`).
1129
+ * @param copyFaceData true to copy `faceTag`.
1072
1130
  */
1073
1131
  copyDataFrom(source, copyXYZ, copyVertexData, copyEdgeData, copyFaceData) {
1074
1132
  if (copyXYZ) {
@@ -1088,13 +1146,16 @@ class HalfEdge {
1088
1146
  }
1089
1147
  }
1090
1148
  }
1091
- HalfEdge._edgePropertyMasks = [HalfEdgeMask.BOUNDARY_EDGE, HalfEdgeMask.EXTERIOR, HalfEdgeMask.PRIMARY_EDGE, HalfEdgeMask.NULL_FACE];
1092
1149
  HalfEdge._totalNodesCreated = 0;
1150
+ /** Edge property masks. */
1151
+ HalfEdge._edgePropertyMasks = [
1152
+ HalfEdgeMask.BOUNDARY_EDGE, HalfEdgeMask.EXTERIOR, HalfEdgeMask.PRIMARY_EDGE, HalfEdgeMask.NULL_FACE,
1153
+ ];
1093
1154
  export { HalfEdge };
1094
1155
  /**
1095
1156
  * A HalfEdgeGraph has:
1096
- * * An array of (pointers to ) HalfEdge objects.
1097
- * * A pool of masks for grab/drop use by algorithms.
1157
+ * * An array of (pointers to) HalfEdge objects.
1158
+ * * A pool of masks for grab/drop used by algorithms.
1098
1159
  * @internal
1099
1160
  */
1100
1161
  export class HalfEdgeGraph {
@@ -1103,7 +1164,8 @@ export class HalfEdgeGraph {
1103
1164
  this.allHalfEdges = [];
1104
1165
  this._maskManager = MaskManager.create(HalfEdgeMask.ALL_GRAB_DROP_MASKS);
1105
1166
  }
1106
- /** Ask for a mask (from the graph's free pool.) for caller's use.
1167
+ /**
1168
+ * Ask for a mask (from the graph's free pool) for caller's use.
1107
1169
  * * Optionally clear the mask throughout the graph.
1108
1170
  */
1109
1171
  grabMask(clearInAllHalfEdges = true) {
@@ -1113,49 +1175,49 @@ export class HalfEdgeGraph {
1113
1175
  }
1114
1176
  return mask;
1115
1177
  }
1178
+ /** Return `mask` to the free pool. */
1179
+ dropMask(mask) {
1180
+ this._maskManager.dropMask(mask);
1181
+ }
1116
1182
  /**
1117
- * Return `mask` to the free pool.
1118
- */
1119
- dropMask(mask) { this._maskManager.dropMask(mask); }
1120
- /**
1121
- * * Create 2 half edges forming 2 vertices, 1 edge, and 1 face
1122
- * * The two edges are joined as edgeMate pair.
1123
- * * The two edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1124
- * * The two edges are added to the graph's HalfEdge set
1125
- * @returns Return pointer to the first half edge created.
1183
+ * Create 2 half edges forming 2 vertices, 1 edge, and 1 face.
1184
+ * * The two half edges are joined as edgeMate pair.
1185
+ * * The two half edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1186
+ * * The two half edges are added to the graph's HalfEdge set.
1187
+ * @returns pointer to the first half edge created.
1126
1188
  */
1127
1189
  createEdgeXYZXYZ(xA = 0, yA = 0, zA = 0, iA = 0, xB = 0, yB = 0, zB = 0, iB = 0) {
1128
- const a = HalfEdge.createHalfEdgePairWithCoordinates(xA, yA, zA, iA, xB, yB, zB, iB, this.allHalfEdges);
1129
- return a;
1190
+ return HalfEdge.createHalfEdgePairWithCoordinates(xA, yA, zA, iA, xB, yB, zB, iB, this.allHalfEdges);
1130
1191
  }
1131
1192
  /**
1132
- * * Create 2 half edges forming 2 vertices, 1 edge, and 1 face
1133
- * * The two edges are joined as edgeMate pair.
1134
- * * The two edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1135
- * * The two edges are added to the graph's HalfEdge set
1193
+ * Create 2 half edges forming 2 vertices, 1 edge, and 1 face.
1194
+ * * The two half edges are joined as edgeMate pair.
1195
+ * * The two half edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1196
+ * * The two half edges are added to the graph's HalfEdge set.
1136
1197
  * * Coordinates are set to zero.
1137
- * * ids are installed in the two half edges.
1138
- * @returns Return pointer to the first half edge created. (This has idA as its id.)
1198
+ * * IDs are installed in the two half edges.
1199
+ * @returns pointer to the first half edge created, with ID set to iA.
1139
1200
  */
1140
1201
  createEdgeIdId(iA = 0, iB = 0) {
1141
- const a = HalfEdge.createHalfEdgePairWithCoordinates(0.0, 0.0, 0.0, iA, 0.0, 0.0, 0.0, iB, this.allHalfEdges);
1142
- return a;
1202
+ return HalfEdge.createHalfEdgePairWithCoordinates(0.0, 0.0, 0.0, iA, 0.0, 0.0, 0.0, iB, this.allHalfEdges);
1143
1203
  }
1144
1204
  /**
1145
- * * create an edge from coordinates x,y,z to (the tail of) an existing half edge.
1146
- * @returns Return pointer to the half edge with tail at x,y,z
1205
+ * Create an edge from coordinates x,y,z connected to the graph at the vertex of the given `node`.
1206
+ * @returns pointer to the dangling node at x,y,z.
1147
1207
  */
1148
1208
  createEdgeXYZHalfEdge(xA = 0, yA = 0, zA = 0, iA = 0, node, iB = 0) {
1209
+ // Visualization can be found at geometry/internaldocs/Graph.md
1149
1210
  const a = HalfEdge.createHalfEdgePairWithCoordinates(xA, yA, zA, iA, node.x, node.y, node.z, iB, this.allHalfEdges);
1150
1211
  const b = a.faceSuccessor;
1151
1212
  HalfEdge.pinch(node, b);
1152
1213
  return a;
1153
1214
  }
1154
1215
  /**
1155
- * * create an edge from coordinates x,y,z to (the tail of) an existing half edge.
1156
- * @returns Return pointer to the half edge with tail at x,y,z
1216
+ * Create an edge from the vertex of `nodeA` to the vertex of `nodeB`.
1217
+ * @returns pointer to the new half edge at the vertex of `nodeA`.
1157
1218
  */
1158
1219
  createEdgeHalfEdgeHalfEdge(nodeA, idA, nodeB, idB = 0) {
1220
+ // Visualization can be found at geometry/internaldocs/Graph.md
1159
1221
  const a = HalfEdge.createHalfEdgePairWithCoordinates(nodeA.x, nodeA.y, nodeA.z, idA, nodeB.x, nodeB.y, nodeB.z, idB, this.allHalfEdges);
1160
1222
  const b = a.faceSuccessor;
1161
1223
  HalfEdge.pinch(nodeA, a);
@@ -1163,56 +1225,56 @@ export class HalfEdgeGraph {
1163
1225
  return a;
1164
1226
  }
1165
1227
  /**
1166
- * * Create 2 half edges forming 2 vertices, 1 edge, and 1 face
1167
- * * The two edges are joined as edgeMate pair.
1168
- * * The two edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1169
- * * The two edges are added to the graph's HalfEdge set
1170
- * @returns Return pointer to the first half edge created.
1228
+ * Create 2 half edges forming 2 vertices, 1 edge, and 1 face
1229
+ * * The two half edges are joined as edgeMate pair.
1230
+ * * The two half edges are a 2-half-edge face loop in both the faceSuccessor and facePredecessor directions.
1231
+ * * The two half edges are added to the graph's HalfEdge set.
1232
+ * @returns pointer to the first half edge created, with coordinates `xyz0`.
1171
1233
  */
1172
1234
  createEdgeXYAndZ(xyz0, id0, xyz1, id1) {
1173
- const a = HalfEdge.createHalfEdgePairWithCoordinates(xyz0.x, xyz0.y, xyz0.z, id0, xyz1.x, xyz1.y, xyz1.z, id1, this.allHalfEdges);
1174
- return a;
1235
+ return HalfEdge.createHalfEdgePairWithCoordinates(xyz0.x, xyz0.y, xyz0.z, id0, xyz1.x, xyz1.y, xyz1.z, id1, this.allHalfEdges);
1175
1236
  }
1176
1237
  /**
1177
- * * Insert a vertex in the edge beginning at base.
1178
- * * this creates two half edges.
1179
- * * The base of the new edge is 'after' the (possibly undefined) start node in its face loop.
1180
- * * The existing mate retains its base xyz and i properties but is no longer the mate of base.
1181
- * * The base and existing mate each become mates with a new half edge.
1182
- * @returns Returns the reference to the half edge created.
1238
+ * Create a new vertex within the edge beginning at `base`.
1239
+ * * This creates two new nodes in their own vertex loop.
1240
+ * * If the base is undefined, create a single-edge loop.
1241
+ * * Existing nodes stay in their face and vertex loops and retain xyz and i values.
1242
+ * * Unlike [[pinch]], this breaks the edgeMate pairing of the input edge:
1243
+ * each node of the input edge gets a new node as its edge mate.
1244
+ * * On each side of the edge, if edgeTag is present, it is copied to the new node on that side.
1245
+ * @returns reference to the half edge created, the new face successor of `base`.
1183
1246
  */
1184
1247
  splitEdge(base, xA = 0, yA = 0, zA = 0, iA = 0) {
1185
- const he = HalfEdge.splitEdge(base, xA, yA, zA, iA, this.allHalfEdges);
1186
- return he;
1248
+ return HalfEdge.splitEdge(base, xA, yA, zA, iA, this.allHalfEdges);
1187
1249
  }
1188
1250
  /**
1189
- * * Create a sliver face "within" an edge.
1190
- * * this creates two half edges.
1191
- * * The existing edges both stay in their same face loops and retain coordinates and i value.
1192
- * * Each existing edge's mate is a new edge (rather than original mate)
1193
- * * Coordinates are copied to the new edges at respective vertices.
1194
- * * New faceTag and edgeTag undefined.
1195
- * * i members are copied around their respective vertices.
1196
- * @returns Returns the reference to the half edge created.
1251
+ * Create a new sliver face "inside" an existing edge.
1252
+ * * This creates two nodes that are each face predecessor and successor to the other.
1253
+ * * Existing nodes stay in their face and vertex loops and retain xyz and i values.
1254
+ * * Unlike [[pinch]], this breaks the edgeMate pairing of the input edge:
1255
+ * each node of the input edge gets a new node as its edge mate.
1256
+ * * New nodes get the xyz and i values shared by the nodes in the vertex loops into which they are placed.
1257
+ * * New nodes' faceTag and edgeTag are `undefined`.
1258
+ * @returns reference to the half edge created in the vertex loop of baseA.
1197
1259
  */
1198
1260
  splitEdgeCreateSliverFace(base) {
1199
- const he = HalfEdge.splitEdgeCreateSliverFace(base, this.allHalfEdges);
1200
- return he;
1261
+ return HalfEdge.splitEdgeCreateSliverFace(base, this.allHalfEdges);
1201
1262
  }
1202
1263
  /**
1203
- * * Insert a vertex in the edge beginning at base, with coordinates specified as a fraction along the existing edge.
1204
- * * this creates two half edges.
1205
- * * The base of the new edge is 'after' the (possibly undefined) start node in its face loop.
1206
- * * The existing mate retains its base xyz and i properties but is no longer the mate of base.
1207
- * * The base and existing mate each become mates with a new half edge.
1208
- * @returns Returns the reference to the half edge created.
1264
+ * Create a new vertex within the edge beginning at `base`, with coordinates specified by a fraction along the edge.
1265
+ * * This creates two new nodes in their own vertex loop.
1266
+ * * Existing nodes stay in their face and vertex loops and retain xyz and i values.
1267
+ * * Unlike [[pinch]], this breaks the edgeMate pairing of the input edge:
1268
+ * each node of the input edge gets a new node as its edge mate.
1269
+ * * On each side of the edge, if edgeTag is present, it is copied to the new node on that side.
1270
+ * @returns reference to the half edge created, the new face successor of `base`.
1209
1271
  */
1210
1272
  splitEdgeAtFraction(base, fraction) {
1211
- const he = HalfEdge.splitEdge(base, base.fractionToX(fraction), base.fractionToY(fraction), base.fractionToZ(fraction), 0, this.allHalfEdges);
1212
- return he;
1273
+ return HalfEdge.splitEdge(base, base.fractionToX(fraction), base.fractionToY(fraction), base.fractionToZ(fraction), 0, this.allHalfEdges);
1213
1274
  }
1214
- /** This is a destructor-like action that eliminates all interconnection among the graph's nodes.
1215
- * After this is called the graph is unusable.
1275
+ /**
1276
+ * This is a destructor-like action that eliminates all inter-connections among the graph's nodes.
1277
+ * After this is called, the graph is unusable.
1216
1278
  */
1217
1279
  decommission() {
1218
1280
  for (const node of this.allHalfEdges) {
@@ -1221,8 +1283,9 @@ export class HalfEdgeGraph {
1221
1283
  this.allHalfEdges.length = 0;
1222
1284
  this.allHalfEdges = undefined;
1223
1285
  }
1224
- /** create two nodes of a new edge.
1225
- * @returns Return one of the two nodes, which the caller may consider as the start of the edge.
1286
+ /**
1287
+ * Create two nodes of a new edge.
1288
+ * @returns the reference to the new node at (x0,y0).
1226
1289
  */
1227
1290
  addEdgeXY(x0, y0, x1, y1) {
1228
1291
  const baseNode = HalfEdge.createEdgeXYXY(this._numNodesCreated, x0, y0, this._numNodesCreated + 1, x1, y1);
@@ -1231,17 +1294,17 @@ export class HalfEdgeGraph {
1231
1294
  this.allHalfEdges.push(baseNode.faceSuccessor);
1232
1295
  return baseNode;
1233
1296
  }
1234
- /** Clear selected bits in all nodes of the graph. */
1297
+ /** Clear selected `mask` bits in all nodes of the graph. */
1235
1298
  clearMask(mask) {
1236
1299
  for (const node of this.allHalfEdges)
1237
1300
  node.maskBits &= ~mask;
1238
1301
  }
1239
- /** Set selected bits in all nodes of the graph. */
1302
+ /** Set selected `mask` bits in all nodes of the graph. */
1240
1303
  setMask(mask) {
1241
1304
  for (const node of this.allHalfEdges)
1242
1305
  node.maskBits |= mask;
1243
1306
  }
1244
- /** toggle selected bits in all nodes of the graph. */
1307
+ /** Toggle selected `mask` bits in all nodes of the graph. */
1245
1308
  reverseMask(mask) {
1246
1309
  for (const node of this.allHalfEdges) {
1247
1310
  node.maskBits ^= mask;
@@ -1258,10 +1321,11 @@ export class HalfEdgeGraph {
1258
1321
  n++;
1259
1322
  return n;
1260
1323
  }
1261
- /** Return an array LineSegment3d.
1262
- * * The array has one segment per edge
1324
+ /**
1325
+ * Return an array of LineSegment3d.
1326
+ * * The array has one segment per edge.
1263
1327
  * * The coordinates are taken from a node and its face successor.
1264
- * * On each edge, the line segment start at the HalfEdge with lower id than its edgeMate.
1328
+ * * On each edge, the line segment starts at the HalfEdge with lower ID than its edgeMate.
1265
1329
  */
1266
1330
  collectSegments() {
1267
1331
  const segments = [];
@@ -1271,24 +1335,27 @@ export class HalfEdgeGraph {
1271
1335
  }
1272
1336
  return segments;
1273
1337
  }
1274
- /** Returns the number of vertex loops in a graph structure */
1338
+ /** Returns the number of vertex loops in a graph structure. */
1275
1339
  countVertexLoops() {
1276
1340
  this.clearMask(HalfEdgeMask.VISITED);
1277
1341
  let count = 0;
1278
- this.announceVertexLoops((_graph, _seed) => { count++; return true; });
1342
+ this.announceVertexLoops((_graph, _seed) => {
1343
+ count++;
1344
+ return true;
1345
+ });
1279
1346
  return count;
1280
1347
  }
1281
- /** Returns the number of face loops */
1348
+ /** Returns the number of face loops in a graph structure. */
1282
1349
  countFaceLoops() {
1283
1350
  this.clearMask(HalfEdgeMask.VISITED);
1284
1351
  let count = 0;
1285
- this.announceFaceLoops((_graph, _seed) => { count++; return true; });
1352
+ this.announceFaceLoops((_graph, _seed) => {
1353
+ count++;
1354
+ return true;
1355
+ });
1286
1356
  return count;
1287
1357
  }
1288
- /**
1289
- * Returns the number of face loops satisfying a filter function with mask argument.
1290
- *
1291
- */
1358
+ /** Returns the number of face loops satisfying a filter function with mask argument. */
1292
1359
  countFaceLoopsWithMaskFilter(filter, mask) {
1293
1360
  this.clearMask(HalfEdgeMask.VISITED);
1294
1361
  let count = 0;
@@ -1299,32 +1366,47 @@ export class HalfEdgeGraph {
1299
1366
  });
1300
1367
  return count;
1301
1368
  }
1302
- /** Returns an array of nodes, where each node represents a starting point of a face loop.
1303
- */
1369
+ /** Returns an array of nodes, where each node represents a starting point of a vertex loop. */
1370
+ collectVertexLoops() {
1371
+ const returnArray = [];
1372
+ this.announceVertexLoops((_graph, node) => {
1373
+ returnArray.push(node);
1374
+ return true;
1375
+ });
1376
+ return returnArray;
1377
+ }
1378
+ /** Returns an array of nodes, where each node represents a starting point of a face loop. */
1304
1379
  collectFaceLoops() {
1305
1380
  const returnArray = [];
1306
- this.announceFaceLoops((_graph, node) => { returnArray.push(node); return true; });
1381
+ this.announceFaceLoops((_graph, node) => {
1382
+ returnArray.push(node);
1383
+ return true;
1384
+ });
1307
1385
  return returnArray;
1308
1386
  }
1309
- /** Returns an array of nodes, where each node represents a starting point of a vertex loop.
1387
+ /**
1388
+ * Visit each vertex loop of the graph once.
1389
+ * * Call the `announceVertex` function.
1390
+ * * Continue search if `announceVertex(graph, node)` returns `true`.
1391
+ * * Terminate search if `announceVertex(graph, node)` returns `false`.
1392
+ * @param announceVertex function to apply at one node of each vertex.
1310
1393
  */
1311
- collectVertexLoops() {
1394
+ announceVertexLoops(announceVertex) {
1312
1395
  this.clearMask(HalfEdgeMask.VISITED);
1313
- const returnArray = [];
1314
1396
  for (const node of this.allHalfEdges) {
1315
1397
  if (node.getMask(HalfEdgeMask.VISITED))
1316
1398
  continue;
1317
- returnArray.push(node);
1318
1399
  node.setMaskAroundVertex(HalfEdgeMask.VISITED);
1400
+ if (!announceVertex(this, node))
1401
+ break;
1319
1402
  }
1320
- return returnArray;
1321
1403
  }
1322
1404
  /**
1323
- * * Visit each facet of the graph once.
1324
- * * Call the announceFace function
1325
- * * continue search if announceFace(graph, node) returns true
1326
- * * terminate search if announce face (graph, node) returns false
1327
- * @param announceFace function to apply at one node of each face.
1405
+ * Visit each facet of the graph once.
1406
+ * * Call the `announceFace` function.
1407
+ * * Continue search if `announceFace(graph, node)` returns `true`.
1408
+ * * Terminate search if `announceFace(graph, node)` returns `false`.
1409
+ * @param announceFace function to apply at one node of each face.
1328
1410
  */
1329
1411
  announceFaceLoops(announceFace) {
1330
1412
  this.clearMask(HalfEdgeMask.VISITED);
@@ -1337,13 +1419,13 @@ export class HalfEdgeGraph {
1337
1419
  }
1338
1420
  }
1339
1421
  /**
1340
- * * Visit each edge of the graph once.
1341
- * * Call the announceEdge function.
1342
- * * the edge mate will NOT appear in an announceEdge call.
1343
- * * continue search if announceEdge(graph, node) returns true
1344
- * * terminate search if announceEdge (graph, node) returns false
1345
- * @param announceEdge function to apply at one node of each edge.
1346
- */
1422
+ * Visit each edge of the graph once.
1423
+ * * Call the `announceEdge` function.
1424
+ * * The edge mate will NOT appear in an announceEdge call.
1425
+ * * Continue search if `announceEdge(graph, node)` returns `true`.
1426
+ * * Terminate search if `announceEdge(graph, node)` returns `false`.
1427
+ * @param announceEdge function to apply at one node of each edge.
1428
+ */
1347
1429
  announceEdges(announceEdge) {
1348
1430
  this.clearMask(HalfEdgeMask.VISITED);
1349
1431
  for (const node of this.allHalfEdges) {
@@ -1357,28 +1439,11 @@ export class HalfEdgeGraph {
1357
1439
  }
1358
1440
  }
1359
1441
  /**
1360
- * * Visit each vertex loop of the graph once.
1361
- * * Call the announceVertex function
1362
- * * continue search if announceVertex(graph, node) returns true
1363
- * * terminate search if announce vertex (graph, node) returns false
1364
- * @param announceVertex function to apply at one node of each face.
1365
- */
1366
- announceVertexLoops(announceVertex) {
1367
- this.clearMask(HalfEdgeMask.VISITED);
1368
- for (const node of this.allHalfEdges) {
1369
- if (node.getMask(HalfEdgeMask.VISITED))
1370
- continue;
1371
- node.setMaskAroundVertex(HalfEdgeMask.VISITED);
1372
- if (!announceVertex(this, node))
1373
- break;
1374
- }
1375
- }
1376
- /**
1377
- * * Visit each half edge (node) of the graph once.
1378
- * * Call the announceNode function
1379
- * * continue search if announceNode(graph, node) returns true
1380
- * * terminate search if announce face (graph, node) returns false
1381
- * @param announceNode function to apply at one node of each face.
1442
+ * Visit each half edge (node) of the graph once.
1443
+ * * Call the `announceNode` function.
1444
+ * * Continue search if `announceNode(graph, node)` returns `true`.
1445
+ * * Terminate search if `announceFace(graph, node)` returns `false`.
1446
+ * @param announceNode function to apply at each node.
1382
1447
  */
1383
1448
  announceNodes(announceNode) {
1384
1449
  for (const node of this.allHalfEdges) {
@@ -1386,8 +1451,10 @@ export class HalfEdgeGraph {
1386
1451
  break;
1387
1452
  }
1388
1453
  }
1389
- /** Return the number of nodes in the graph */
1390
- countNodes() { return this.allHalfEdges.length; }
1454
+ /** Return the number of nodes in the graph. */
1455
+ countNodes() {
1456
+ return this.allHalfEdges.length;
1457
+ }
1391
1458
  /** Apply transform to the xyz coordinates in the graph. */
1392
1459
  transformInPlace(transform) {
1393
1460
  for (const node of this.allHalfEdges) {
@@ -1395,8 +1462,8 @@ export class HalfEdgeGraph {
1395
1462
  }
1396
1463
  }
1397
1464
  /**
1398
- * disconnect and delete all nodes that satisfy a filter condition.
1399
- * @param deleteThisNode returns true to delete the corresponding edge. Should act symmetrically on the edgeMate.
1465
+ * Disconnect and delete all nodes that satisfy a filter condition.
1466
+ * @param deleteThisNode returns true to delete the corresponding node. Should act symmetrically on the edgeMate.
1400
1467
  * @returns the number of nodes deleted (twice the number of deleted edges).
1401
1468
  */
1402
1469
  yankAndDeleteEdges(deleteThisNode) {
@@ -1405,9 +1472,9 @@ export class HalfEdgeGraph {
1405
1472
  for (let i = 0; i < numTotal; i++) {
1406
1473
  const candidate = this.allHalfEdges[i];
1407
1474
  if (!deleteThisNode(candidate))
1408
- this.allHalfEdges[numAccepted++] = candidate;
1475
+ this.allHalfEdges[numAccepted++] = candidate; // overwrite a previously "deleted node"
1409
1476
  else
1410
- candidate.yankFromVertexLoop(); // ASSUME callback symmetry so we eventually yank the mate!
1477
+ candidate.yankFromVertexLoop(); // assume callback symmetry so we eventually yank the mate
1411
1478
  }
1412
1479
  const numDeleted = numTotal - numAccepted;
1413
1480
  this.allHalfEdges.length = numAccepted;