@itwin/core-geometry 5.2.0-dev.8 → 5.3.0-dev.1

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 (438) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/lib/cjs/Geometry.d.ts +30 -10
  3. package/lib/cjs/Geometry.d.ts.map +1 -1
  4. package/lib/cjs/Geometry.js +74 -10
  5. package/lib/cjs/Geometry.js.map +1 -1
  6. package/lib/cjs/bspline/AkimaCurve3d.d.ts +19 -6
  7. package/lib/cjs/bspline/AkimaCurve3d.d.ts.map +1 -1
  8. package/lib/cjs/bspline/AkimaCurve3d.js +21 -5
  9. package/lib/cjs/bspline/AkimaCurve3d.js.map +1 -1
  10. package/lib/cjs/bspline/BSplineCurve.d.ts +3 -3
  11. package/lib/cjs/bspline/BSplineCurve.d.ts.map +1 -1
  12. package/lib/cjs/bspline/BSplineCurve.js +6 -6
  13. package/lib/cjs/bspline/BSplineCurve.js.map +1 -1
  14. package/lib/cjs/bspline/BSplineCurveOps.d.ts.map +1 -1
  15. package/lib/cjs/bspline/BSplineCurveOps.js +1 -1
  16. package/lib/cjs/bspline/BSplineCurveOps.js.map +1 -1
  17. package/lib/cjs/bspline/BezierCurveBase.d.ts +2 -2
  18. package/lib/cjs/bspline/BezierCurveBase.d.ts.map +1 -1
  19. package/lib/cjs/bspline/BezierCurveBase.js +4 -6
  20. package/lib/cjs/bspline/BezierCurveBase.js.map +1 -1
  21. package/lib/cjs/bspline/InterpolationCurve3d.d.ts +27 -17
  22. package/lib/cjs/bspline/InterpolationCurve3d.d.ts.map +1 -1
  23. package/lib/cjs/bspline/InterpolationCurve3d.js +17 -7
  24. package/lib/cjs/bspline/InterpolationCurve3d.js.map +1 -1
  25. package/lib/cjs/clipping/ClipPlane.d.ts +19 -6
  26. package/lib/cjs/clipping/ClipPlane.d.ts.map +1 -1
  27. package/lib/cjs/clipping/ClipPlane.js +17 -2
  28. package/lib/cjs/clipping/ClipPlane.js.map +1 -1
  29. package/lib/cjs/clipping/ClipUtils.d.ts +14 -1
  30. package/lib/cjs/clipping/ClipUtils.d.ts.map +1 -1
  31. package/lib/cjs/clipping/ClipUtils.js +21 -3
  32. package/lib/cjs/clipping/ClipUtils.js.map +1 -1
  33. package/lib/cjs/clipping/ConvexClipPlaneSet.d.ts +14 -11
  34. package/lib/cjs/clipping/ConvexClipPlaneSet.d.ts.map +1 -1
  35. package/lib/cjs/clipping/ConvexClipPlaneSet.js +23 -16
  36. package/lib/cjs/clipping/ConvexClipPlaneSet.js.map +1 -1
  37. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.d.ts +20 -3
  38. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.d.ts.map +1 -1
  39. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.js +22 -5
  40. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.js.map +1 -1
  41. package/lib/cjs/curve/Arc3d.d.ts +27 -17
  42. package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
  43. package/lib/cjs/curve/Arc3d.js +61 -35
  44. package/lib/cjs/curve/Arc3d.js.map +1 -1
  45. package/lib/cjs/curve/CurveCollection.d.ts +1 -0
  46. package/lib/cjs/curve/CurveCollection.d.ts.map +1 -1
  47. package/lib/cjs/curve/CurveCollection.js +1 -0
  48. package/lib/cjs/curve/CurveCollection.js.map +1 -1
  49. package/lib/cjs/curve/CurveLocationDetail.d.ts +8 -7
  50. package/lib/cjs/curve/CurveLocationDetail.d.ts.map +1 -1
  51. package/lib/cjs/curve/CurveLocationDetail.js.map +1 -1
  52. package/lib/cjs/curve/CurveOps.d.ts +51 -1
  53. package/lib/cjs/curve/CurveOps.d.ts.map +1 -1
  54. package/lib/cjs/curve/CurveOps.js +97 -3
  55. package/lib/cjs/curve/CurveOps.js.map +1 -1
  56. package/lib/cjs/curve/LineString3d.d.ts +4 -4
  57. package/lib/cjs/curve/LineString3d.d.ts.map +1 -1
  58. package/lib/cjs/curve/LineString3d.js +8 -8
  59. package/lib/cjs/curve/LineString3d.js.map +1 -1
  60. package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.js +3 -3
  61. package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.js.map +1 -1
  62. package/lib/cjs/curve/Query/PlanarSubdivision.d.ts +6 -2
  63. package/lib/cjs/curve/Query/PlanarSubdivision.d.ts.map +1 -1
  64. package/lib/cjs/curve/Query/PlanarSubdivision.js +12 -7
  65. package/lib/cjs/curve/Query/PlanarSubdivision.js.map +1 -1
  66. package/lib/cjs/curve/RegionOps.d.ts +9 -4
  67. package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
  68. package/lib/cjs/curve/RegionOps.js +10 -5
  69. package/lib/cjs/curve/RegionOps.js.map +1 -1
  70. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  71. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js +2 -1
  72. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  73. package/lib/cjs/curve/internalContexts/MultiChainCollector.d.ts +4 -4
  74. package/lib/cjs/curve/internalContexts/MultiChainCollector.d.ts.map +1 -1
  75. package/lib/cjs/curve/internalContexts/MultiChainCollector.js +21 -18
  76. package/lib/cjs/curve/internalContexts/MultiChainCollector.js.map +1 -1
  77. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.d.ts.map +1 -1
  78. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.js +30 -50
  79. package/lib/cjs/curve/internalContexts/PolygonOffsetContext.js.map +1 -1
  80. package/lib/cjs/curve/spiral/DirectSpiral3d.d.ts +2 -2
  81. package/lib/cjs/curve/spiral/DirectSpiral3d.d.ts.map +1 -1
  82. package/lib/cjs/curve/spiral/DirectSpiral3d.js +6 -2
  83. package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
  84. package/lib/cjs/curve/spiral/IntegratedSpiral3d.d.ts +2 -2
  85. package/lib/cjs/curve/spiral/IntegratedSpiral3d.d.ts.map +1 -1
  86. package/lib/cjs/curve/spiral/IntegratedSpiral3d.js +6 -2
  87. package/lib/cjs/curve/spiral/IntegratedSpiral3d.js.map +1 -1
  88. package/lib/cjs/curve/spiral/TransitionSpiral3d.d.ts +5 -1
  89. package/lib/cjs/curve/spiral/TransitionSpiral3d.d.ts.map +1 -1
  90. package/lib/cjs/curve/spiral/TransitionSpiral3d.js +0 -3
  91. package/lib/cjs/curve/spiral/TransitionSpiral3d.js.map +1 -1
  92. package/lib/cjs/geometry3d/AngleSweep.d.ts +6 -2
  93. package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
  94. package/lib/cjs/geometry3d/AngleSweep.js +12 -3
  95. package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
  96. package/lib/cjs/geometry3d/FrameBuilder.d.ts +2 -1
  97. package/lib/cjs/geometry3d/FrameBuilder.d.ts.map +1 -1
  98. package/lib/cjs/geometry3d/FrameBuilder.js +14 -18
  99. package/lib/cjs/geometry3d/FrameBuilder.js.map +1 -1
  100. package/lib/cjs/geometry3d/Matrix3d.d.ts +1 -1
  101. package/lib/cjs/geometry3d/Matrix3d.js +1 -1
  102. package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
  103. package/lib/cjs/geometry3d/Point2dVector2d.d.ts +18 -2
  104. package/lib/cjs/geometry3d/Point2dVector2d.d.ts.map +1 -1
  105. package/lib/cjs/geometry3d/Point2dVector2d.js +37 -4
  106. package/lib/cjs/geometry3d/Point2dVector2d.js.map +1 -1
  107. package/lib/cjs/geometry3d/Point3dVector3d.d.ts +1 -1
  108. package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
  109. package/lib/cjs/geometry3d/Point3dVector3d.js +1 -0
  110. package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
  111. package/lib/cjs/geometry3d/PointStreaming.d.ts +8 -0
  112. package/lib/cjs/geometry3d/PointStreaming.d.ts.map +1 -1
  113. package/lib/cjs/geometry3d/PointStreaming.js +18 -2
  114. package/lib/cjs/geometry3d/PointStreaming.js.map +1 -1
  115. package/lib/cjs/geometry3d/PolygonOps.d.ts +18 -9
  116. package/lib/cjs/geometry3d/PolygonOps.d.ts.map +1 -1
  117. package/lib/cjs/geometry3d/PolygonOps.js +53 -26
  118. package/lib/cjs/geometry3d/PolygonOps.js.map +1 -1
  119. package/lib/cjs/geometry3d/PolylineCompressionByEdgeOffset.d.ts +8 -2
  120. package/lib/cjs/geometry3d/PolylineCompressionByEdgeOffset.d.ts.map +1 -1
  121. package/lib/cjs/geometry3d/PolylineCompressionByEdgeOffset.js +10 -4
  122. package/lib/cjs/geometry3d/PolylineCompressionByEdgeOffset.js.map +1 -1
  123. package/lib/cjs/geometry3d/PolylineOps.d.ts +14 -3
  124. package/lib/cjs/geometry3d/PolylineOps.d.ts.map +1 -1
  125. package/lib/cjs/geometry3d/PolylineOps.js +20 -4
  126. package/lib/cjs/geometry3d/PolylineOps.js.map +1 -1
  127. package/lib/cjs/geometry3d/Range.d.ts +34 -32
  128. package/lib/cjs/geometry3d/Range.d.ts.map +1 -1
  129. package/lib/cjs/geometry3d/Range.js +28 -21
  130. package/lib/cjs/geometry3d/Range.js.map +1 -1
  131. package/lib/cjs/geometry3d/Ray2d.d.ts +16 -6
  132. package/lib/cjs/geometry3d/Ray2d.d.ts.map +1 -1
  133. package/lib/cjs/geometry3d/Ray2d.js +28 -4
  134. package/lib/cjs/geometry3d/Ray2d.js.map +1 -1
  135. package/lib/cjs/geometry3d/Ray3d.d.ts.map +1 -1
  136. package/lib/cjs/geometry3d/Ray3d.js +3 -4
  137. package/lib/cjs/geometry3d/Ray3d.js.map +1 -1
  138. package/lib/cjs/geometry3d/Transform.d.ts +1 -1
  139. package/lib/cjs/geometry3d/Transform.js +1 -1
  140. package/lib/cjs/geometry3d/Transform.js.map +1 -1
  141. package/lib/cjs/geometry3d/XYZProps.d.ts +12 -1
  142. package/lib/cjs/geometry3d/XYZProps.d.ts.map +1 -1
  143. package/lib/cjs/geometry3d/XYZProps.js +17 -2
  144. package/lib/cjs/geometry3d/XYZProps.js.map +1 -1
  145. package/lib/cjs/geometry4d/Matrix4d.d.ts +16 -0
  146. package/lib/cjs/geometry4d/Matrix4d.d.ts.map +1 -1
  147. package/lib/cjs/geometry4d/Matrix4d.js +26 -0
  148. package/lib/cjs/geometry4d/Matrix4d.js.map +1 -1
  149. package/lib/cjs/numerics/BezierPolynomials.d.ts.map +1 -1
  150. package/lib/cjs/numerics/BezierPolynomials.js +5 -9
  151. package/lib/cjs/numerics/BezierPolynomials.js.map +1 -1
  152. package/lib/cjs/numerics/SmallSystem.d.ts +13 -7
  153. package/lib/cjs/numerics/SmallSystem.d.ts.map +1 -1
  154. package/lib/cjs/numerics/SmallSystem.js +13 -7
  155. package/lib/cjs/numerics/SmallSystem.js.map +1 -1
  156. package/lib/cjs/polyface/Polyface.d.ts +1 -3
  157. package/lib/cjs/polyface/Polyface.d.ts.map +1 -1
  158. package/lib/cjs/polyface/Polyface.js +2 -6
  159. package/lib/cjs/polyface/Polyface.js.map +1 -1
  160. package/lib/cjs/polyface/PolyfaceBuilder.d.ts +25 -6
  161. package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
  162. package/lib/cjs/polyface/PolyfaceBuilder.js +59 -8
  163. package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
  164. package/lib/cjs/polyface/PolyfaceData.d.ts +2 -0
  165. package/lib/cjs/polyface/PolyfaceData.d.ts.map +1 -1
  166. package/lib/cjs/polyface/PolyfaceData.js +7 -3
  167. package/lib/cjs/polyface/PolyfaceData.js.map +1 -1
  168. package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
  169. package/lib/cjs/polyface/PolyfaceQuery.js +8 -10
  170. package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
  171. package/lib/cjs/polyface/RangeTree/Point3dArrayRangeTreeContext.d.ts +8 -5
  172. package/lib/cjs/polyface/RangeTree/Point3dArrayRangeTreeContext.d.ts.map +1 -1
  173. package/lib/cjs/polyface/RangeTree/Point3dArrayRangeTreeContext.js +8 -4
  174. package/lib/cjs/polyface/RangeTree/Point3dArrayRangeTreeContext.js.map +1 -1
  175. package/lib/cjs/polyface/RangeTree/PolyfaceRangeTreeContext.d.ts +3 -3
  176. package/lib/cjs/polyface/RangeTree/PolyfaceRangeTreeContext.d.ts.map +1 -1
  177. package/lib/cjs/polyface/RangeTree/PolyfaceRangeTreeContext.js +1 -1
  178. package/lib/cjs/polyface/RangeTree/PolyfaceRangeTreeContext.js.map +1 -1
  179. package/lib/cjs/polyface/RangeTree/RangeTreeNode.d.ts +4 -2
  180. package/lib/cjs/polyface/RangeTree/RangeTreeNode.d.ts.map +1 -1
  181. package/lib/cjs/polyface/RangeTree/RangeTreeNode.js +9 -12
  182. package/lib/cjs/polyface/RangeTree/RangeTreeNode.js.map +1 -1
  183. package/lib/cjs/polyface/RangeTree/RangeTreeSearchHandlers.d.ts +8 -3
  184. package/lib/cjs/polyface/RangeTree/RangeTreeSearchHandlers.d.ts.map +1 -1
  185. package/lib/cjs/polyface/RangeTree/RangeTreeSearchHandlers.js +13 -6
  186. package/lib/cjs/polyface/RangeTree/RangeTreeSearchHandlers.js.map +1 -1
  187. package/lib/cjs/serialization/DeepCompare.js +1 -1
  188. package/lib/cjs/serialization/DeepCompare.js.map +1 -1
  189. package/lib/cjs/serialization/GeometrySamples.d.ts +2 -1
  190. package/lib/cjs/serialization/GeometrySamples.d.ts.map +1 -1
  191. package/lib/cjs/serialization/GeometrySamples.js +2 -1
  192. package/lib/cjs/serialization/GeometrySamples.js.map +1 -1
  193. package/lib/cjs/topology/Graph.d.ts +38 -12
  194. package/lib/cjs/topology/Graph.d.ts.map +1 -1
  195. package/lib/cjs/topology/Graph.js +91 -23
  196. package/lib/cjs/topology/Graph.js.map +1 -1
  197. package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts +5 -4
  198. package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts.map +1 -1
  199. package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.js +6 -5
  200. package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.js.map +1 -1
  201. package/lib/cjs/topology/HalfEdgeGraphSearch.d.ts +20 -11
  202. package/lib/cjs/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
  203. package/lib/cjs/topology/HalfEdgeGraphSearch.js +43 -39
  204. package/lib/cjs/topology/HalfEdgeGraphSearch.js.map +1 -1
  205. package/lib/cjs/topology/Merging.d.ts +7 -4
  206. package/lib/cjs/topology/Merging.d.ts.map +1 -1
  207. package/lib/cjs/topology/Merging.js +16 -11
  208. package/lib/cjs/topology/Merging.js.map +1 -1
  209. package/lib/cjs/topology/Triangulation.d.ts +13 -11
  210. package/lib/cjs/topology/Triangulation.d.ts.map +1 -1
  211. package/lib/cjs/topology/Triangulation.js +40 -36
  212. package/lib/cjs/topology/Triangulation.js.map +1 -1
  213. package/lib/cjs/topology/Voronoi.d.ts +195 -0
  214. package/lib/cjs/topology/Voronoi.d.ts.map +1 -0
  215. package/lib/cjs/topology/Voronoi.js +700 -0
  216. package/lib/cjs/topology/Voronoi.js.map +1 -0
  217. package/lib/cjs/topology/XYParitySearchContext.d.ts +1 -1
  218. package/lib/cjs/topology/XYParitySearchContext.d.ts.map +1 -1
  219. package/lib/cjs/topology/XYParitySearchContext.js.map +1 -1
  220. package/lib/esm/Geometry.d.ts +30 -10
  221. package/lib/esm/Geometry.d.ts.map +1 -1
  222. package/lib/esm/Geometry.js +74 -10
  223. package/lib/esm/Geometry.js.map +1 -1
  224. package/lib/esm/bspline/AkimaCurve3d.d.ts +19 -6
  225. package/lib/esm/bspline/AkimaCurve3d.d.ts.map +1 -1
  226. package/lib/esm/bspline/AkimaCurve3d.js +21 -5
  227. package/lib/esm/bspline/AkimaCurve3d.js.map +1 -1
  228. package/lib/esm/bspline/BSplineCurve.d.ts +3 -3
  229. package/lib/esm/bspline/BSplineCurve.d.ts.map +1 -1
  230. package/lib/esm/bspline/BSplineCurve.js +6 -6
  231. package/lib/esm/bspline/BSplineCurve.js.map +1 -1
  232. package/lib/esm/bspline/BSplineCurveOps.d.ts.map +1 -1
  233. package/lib/esm/bspline/BSplineCurveOps.js +1 -1
  234. package/lib/esm/bspline/BSplineCurveOps.js.map +1 -1
  235. package/lib/esm/bspline/BezierCurveBase.d.ts +2 -2
  236. package/lib/esm/bspline/BezierCurveBase.d.ts.map +1 -1
  237. package/lib/esm/bspline/BezierCurveBase.js +4 -6
  238. package/lib/esm/bspline/BezierCurveBase.js.map +1 -1
  239. package/lib/esm/bspline/InterpolationCurve3d.d.ts +27 -17
  240. package/lib/esm/bspline/InterpolationCurve3d.d.ts.map +1 -1
  241. package/lib/esm/bspline/InterpolationCurve3d.js +17 -7
  242. package/lib/esm/bspline/InterpolationCurve3d.js.map +1 -1
  243. package/lib/esm/clipping/ClipPlane.d.ts +19 -6
  244. package/lib/esm/clipping/ClipPlane.d.ts.map +1 -1
  245. package/lib/esm/clipping/ClipPlane.js +17 -2
  246. package/lib/esm/clipping/ClipPlane.js.map +1 -1
  247. package/lib/esm/clipping/ClipUtils.d.ts +14 -1
  248. package/lib/esm/clipping/ClipUtils.d.ts.map +1 -1
  249. package/lib/esm/clipping/ClipUtils.js +21 -3
  250. package/lib/esm/clipping/ClipUtils.js.map +1 -1
  251. package/lib/esm/clipping/ConvexClipPlaneSet.d.ts +14 -11
  252. package/lib/esm/clipping/ConvexClipPlaneSet.d.ts.map +1 -1
  253. package/lib/esm/clipping/ConvexClipPlaneSet.js +23 -16
  254. package/lib/esm/clipping/ConvexClipPlaneSet.js.map +1 -1
  255. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.d.ts +20 -3
  256. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.d.ts.map +1 -1
  257. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.js +22 -5
  258. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.js.map +1 -1
  259. package/lib/esm/curve/Arc3d.d.ts +27 -17
  260. package/lib/esm/curve/Arc3d.d.ts.map +1 -1
  261. package/lib/esm/curve/Arc3d.js +61 -35
  262. package/lib/esm/curve/Arc3d.js.map +1 -1
  263. package/lib/esm/curve/CurveCollection.d.ts +1 -0
  264. package/lib/esm/curve/CurveCollection.d.ts.map +1 -1
  265. package/lib/esm/curve/CurveCollection.js +1 -0
  266. package/lib/esm/curve/CurveCollection.js.map +1 -1
  267. package/lib/esm/curve/CurveLocationDetail.d.ts +8 -7
  268. package/lib/esm/curve/CurveLocationDetail.d.ts.map +1 -1
  269. package/lib/esm/curve/CurveLocationDetail.js.map +1 -1
  270. package/lib/esm/curve/CurveOps.d.ts +51 -1
  271. package/lib/esm/curve/CurveOps.d.ts.map +1 -1
  272. package/lib/esm/curve/CurveOps.js +98 -4
  273. package/lib/esm/curve/CurveOps.js.map +1 -1
  274. package/lib/esm/curve/LineString3d.d.ts +4 -4
  275. package/lib/esm/curve/LineString3d.d.ts.map +1 -1
  276. package/lib/esm/curve/LineString3d.js +8 -8
  277. package/lib/esm/curve/LineString3d.js.map +1 -1
  278. package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.js +3 -3
  279. package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.js.map +1 -1
  280. package/lib/esm/curve/Query/PlanarSubdivision.d.ts +6 -2
  281. package/lib/esm/curve/Query/PlanarSubdivision.d.ts.map +1 -1
  282. package/lib/esm/curve/Query/PlanarSubdivision.js +12 -7
  283. package/lib/esm/curve/Query/PlanarSubdivision.js.map +1 -1
  284. package/lib/esm/curve/RegionOps.d.ts +9 -4
  285. package/lib/esm/curve/RegionOps.d.ts.map +1 -1
  286. package/lib/esm/curve/RegionOps.js +10 -5
  287. package/lib/esm/curve/RegionOps.js.map +1 -1
  288. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  289. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js +2 -1
  290. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  291. package/lib/esm/curve/internalContexts/MultiChainCollector.d.ts +4 -4
  292. package/lib/esm/curve/internalContexts/MultiChainCollector.d.ts.map +1 -1
  293. package/lib/esm/curve/internalContexts/MultiChainCollector.js +21 -18
  294. package/lib/esm/curve/internalContexts/MultiChainCollector.js.map +1 -1
  295. package/lib/esm/curve/internalContexts/PolygonOffsetContext.d.ts.map +1 -1
  296. package/lib/esm/curve/internalContexts/PolygonOffsetContext.js +30 -50
  297. package/lib/esm/curve/internalContexts/PolygonOffsetContext.js.map +1 -1
  298. package/lib/esm/curve/spiral/DirectSpiral3d.d.ts +2 -2
  299. package/lib/esm/curve/spiral/DirectSpiral3d.d.ts.map +1 -1
  300. package/lib/esm/curve/spiral/DirectSpiral3d.js +6 -2
  301. package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
  302. package/lib/esm/curve/spiral/IntegratedSpiral3d.d.ts +2 -2
  303. package/lib/esm/curve/spiral/IntegratedSpiral3d.d.ts.map +1 -1
  304. package/lib/esm/curve/spiral/IntegratedSpiral3d.js +6 -2
  305. package/lib/esm/curve/spiral/IntegratedSpiral3d.js.map +1 -1
  306. package/lib/esm/curve/spiral/TransitionSpiral3d.d.ts +5 -1
  307. package/lib/esm/curve/spiral/TransitionSpiral3d.d.ts.map +1 -1
  308. package/lib/esm/curve/spiral/TransitionSpiral3d.js +0 -3
  309. package/lib/esm/curve/spiral/TransitionSpiral3d.js.map +1 -1
  310. package/lib/esm/geometry3d/AngleSweep.d.ts +6 -2
  311. package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
  312. package/lib/esm/geometry3d/AngleSweep.js +12 -3
  313. package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
  314. package/lib/esm/geometry3d/FrameBuilder.d.ts +2 -1
  315. package/lib/esm/geometry3d/FrameBuilder.d.ts.map +1 -1
  316. package/lib/esm/geometry3d/FrameBuilder.js +14 -18
  317. package/lib/esm/geometry3d/FrameBuilder.js.map +1 -1
  318. package/lib/esm/geometry3d/Matrix3d.d.ts +1 -1
  319. package/lib/esm/geometry3d/Matrix3d.js +1 -1
  320. package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
  321. package/lib/esm/geometry3d/Point2dVector2d.d.ts +18 -2
  322. package/lib/esm/geometry3d/Point2dVector2d.d.ts.map +1 -1
  323. package/lib/esm/geometry3d/Point2dVector2d.js +37 -4
  324. package/lib/esm/geometry3d/Point2dVector2d.js.map +1 -1
  325. package/lib/esm/geometry3d/Point3dVector3d.d.ts +1 -1
  326. package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
  327. package/lib/esm/geometry3d/Point3dVector3d.js +1 -0
  328. package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
  329. package/lib/esm/geometry3d/PointStreaming.d.ts +8 -0
  330. package/lib/esm/geometry3d/PointStreaming.d.ts.map +1 -1
  331. package/lib/esm/geometry3d/PointStreaming.js +18 -2
  332. package/lib/esm/geometry3d/PointStreaming.js.map +1 -1
  333. package/lib/esm/geometry3d/PolygonOps.d.ts +18 -9
  334. package/lib/esm/geometry3d/PolygonOps.d.ts.map +1 -1
  335. package/lib/esm/geometry3d/PolygonOps.js +53 -26
  336. package/lib/esm/geometry3d/PolygonOps.js.map +1 -1
  337. package/lib/esm/geometry3d/PolylineCompressionByEdgeOffset.d.ts +8 -2
  338. package/lib/esm/geometry3d/PolylineCompressionByEdgeOffset.d.ts.map +1 -1
  339. package/lib/esm/geometry3d/PolylineCompressionByEdgeOffset.js +10 -4
  340. package/lib/esm/geometry3d/PolylineCompressionByEdgeOffset.js.map +1 -1
  341. package/lib/esm/geometry3d/PolylineOps.d.ts +14 -3
  342. package/lib/esm/geometry3d/PolylineOps.d.ts.map +1 -1
  343. package/lib/esm/geometry3d/PolylineOps.js +20 -4
  344. package/lib/esm/geometry3d/PolylineOps.js.map +1 -1
  345. package/lib/esm/geometry3d/Range.d.ts +34 -32
  346. package/lib/esm/geometry3d/Range.d.ts.map +1 -1
  347. package/lib/esm/geometry3d/Range.js +28 -21
  348. package/lib/esm/geometry3d/Range.js.map +1 -1
  349. package/lib/esm/geometry3d/Ray2d.d.ts +16 -6
  350. package/lib/esm/geometry3d/Ray2d.d.ts.map +1 -1
  351. package/lib/esm/geometry3d/Ray2d.js +28 -4
  352. package/lib/esm/geometry3d/Ray2d.js.map +1 -1
  353. package/lib/esm/geometry3d/Ray3d.d.ts.map +1 -1
  354. package/lib/esm/geometry3d/Ray3d.js +3 -4
  355. package/lib/esm/geometry3d/Ray3d.js.map +1 -1
  356. package/lib/esm/geometry3d/Transform.d.ts +1 -1
  357. package/lib/esm/geometry3d/Transform.js +1 -1
  358. package/lib/esm/geometry3d/Transform.js.map +1 -1
  359. package/lib/esm/geometry3d/XYZProps.d.ts +12 -1
  360. package/lib/esm/geometry3d/XYZProps.d.ts.map +1 -1
  361. package/lib/esm/geometry3d/XYZProps.js +16 -1
  362. package/lib/esm/geometry3d/XYZProps.js.map +1 -1
  363. package/lib/esm/geometry4d/Matrix4d.d.ts +16 -0
  364. package/lib/esm/geometry4d/Matrix4d.d.ts.map +1 -1
  365. package/lib/esm/geometry4d/Matrix4d.js +26 -0
  366. package/lib/esm/geometry4d/Matrix4d.js.map +1 -1
  367. package/lib/esm/numerics/BezierPolynomials.d.ts.map +1 -1
  368. package/lib/esm/numerics/BezierPolynomials.js +5 -9
  369. package/lib/esm/numerics/BezierPolynomials.js.map +1 -1
  370. package/lib/esm/numerics/SmallSystem.d.ts +13 -7
  371. package/lib/esm/numerics/SmallSystem.d.ts.map +1 -1
  372. package/lib/esm/numerics/SmallSystem.js +13 -7
  373. package/lib/esm/numerics/SmallSystem.js.map +1 -1
  374. package/lib/esm/polyface/Polyface.d.ts +1 -3
  375. package/lib/esm/polyface/Polyface.d.ts.map +1 -1
  376. package/lib/esm/polyface/Polyface.js +2 -6
  377. package/lib/esm/polyface/Polyface.js.map +1 -1
  378. package/lib/esm/polyface/PolyfaceBuilder.d.ts +25 -6
  379. package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
  380. package/lib/esm/polyface/PolyfaceBuilder.js +59 -8
  381. package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
  382. package/lib/esm/polyface/PolyfaceData.d.ts +2 -0
  383. package/lib/esm/polyface/PolyfaceData.d.ts.map +1 -1
  384. package/lib/esm/polyface/PolyfaceData.js +7 -3
  385. package/lib/esm/polyface/PolyfaceData.js.map +1 -1
  386. package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
  387. package/lib/esm/polyface/PolyfaceQuery.js +8 -10
  388. package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
  389. package/lib/esm/polyface/RangeTree/Point3dArrayRangeTreeContext.d.ts +8 -5
  390. package/lib/esm/polyface/RangeTree/Point3dArrayRangeTreeContext.d.ts.map +1 -1
  391. package/lib/esm/polyface/RangeTree/Point3dArrayRangeTreeContext.js +8 -4
  392. package/lib/esm/polyface/RangeTree/Point3dArrayRangeTreeContext.js.map +1 -1
  393. package/lib/esm/polyface/RangeTree/PolyfaceRangeTreeContext.d.ts +3 -3
  394. package/lib/esm/polyface/RangeTree/PolyfaceRangeTreeContext.d.ts.map +1 -1
  395. package/lib/esm/polyface/RangeTree/PolyfaceRangeTreeContext.js +1 -1
  396. package/lib/esm/polyface/RangeTree/PolyfaceRangeTreeContext.js.map +1 -1
  397. package/lib/esm/polyface/RangeTree/RangeTreeNode.d.ts +4 -2
  398. package/lib/esm/polyface/RangeTree/RangeTreeNode.d.ts.map +1 -1
  399. package/lib/esm/polyface/RangeTree/RangeTreeNode.js +9 -12
  400. package/lib/esm/polyface/RangeTree/RangeTreeNode.js.map +1 -1
  401. package/lib/esm/polyface/RangeTree/RangeTreeSearchHandlers.d.ts +8 -3
  402. package/lib/esm/polyface/RangeTree/RangeTreeSearchHandlers.d.ts.map +1 -1
  403. package/lib/esm/polyface/RangeTree/RangeTreeSearchHandlers.js +13 -6
  404. package/lib/esm/polyface/RangeTree/RangeTreeSearchHandlers.js.map +1 -1
  405. package/lib/esm/serialization/DeepCompare.js +1 -1
  406. package/lib/esm/serialization/DeepCompare.js.map +1 -1
  407. package/lib/esm/serialization/GeometrySamples.d.ts +2 -1
  408. package/lib/esm/serialization/GeometrySamples.d.ts.map +1 -1
  409. package/lib/esm/serialization/GeometrySamples.js +2 -1
  410. package/lib/esm/serialization/GeometrySamples.js.map +1 -1
  411. package/lib/esm/topology/Graph.d.ts +38 -12
  412. package/lib/esm/topology/Graph.d.ts.map +1 -1
  413. package/lib/esm/topology/Graph.js +92 -24
  414. package/lib/esm/topology/Graph.js.map +1 -1
  415. package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts +5 -4
  416. package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts.map +1 -1
  417. package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.js +6 -5
  418. package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.js.map +1 -1
  419. package/lib/esm/topology/HalfEdgeGraphSearch.d.ts +20 -11
  420. package/lib/esm/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
  421. package/lib/esm/topology/HalfEdgeGraphSearch.js +43 -39
  422. package/lib/esm/topology/HalfEdgeGraphSearch.js.map +1 -1
  423. package/lib/esm/topology/Merging.d.ts +7 -4
  424. package/lib/esm/topology/Merging.d.ts.map +1 -1
  425. package/lib/esm/topology/Merging.js +17 -12
  426. package/lib/esm/topology/Merging.js.map +1 -1
  427. package/lib/esm/topology/Triangulation.d.ts +13 -11
  428. package/lib/esm/topology/Triangulation.d.ts.map +1 -1
  429. package/lib/esm/topology/Triangulation.js +40 -36
  430. package/lib/esm/topology/Triangulation.js.map +1 -1
  431. package/lib/esm/topology/Voronoi.d.ts +195 -0
  432. package/lib/esm/topology/Voronoi.d.ts.map +1 -0
  433. package/lib/esm/topology/Voronoi.js +696 -0
  434. package/lib/esm/topology/Voronoi.js.map +1 -0
  435. package/lib/esm/topology/XYParitySearchContext.d.ts +1 -1
  436. package/lib/esm/topology/XYParitySearchContext.d.ts.map +1 -1
  437. package/lib/esm/topology/XYParitySearchContext.js.map +1 -1
  438. package/package.json +3 -3
@@ -34,20 +34,21 @@ export class HalfEdgeGraphFromIndexedLoopsContext {
34
34
  * * One of that mated pair becomes a HalfEdge in this loop.
35
35
  * * The other is "unmatched" and gets the EXTERIOR mask.
36
36
  * * When announceMatedHalfEdges(halfEdge) is called:
37
- * * halfEdge and its mate are "new"
38
- * * all coordinates are zeros.
37
+ * * halfEdge and its mate are "new".
39
38
  * * each contains (as its `i` property) one index of the [indexA,indexB] pair.
40
- * * those coordinates and indices will never be referenced again by this construction sequence -- the caller is free to mutate them as needed.
39
+ * * all coordinates are zeros.
40
+ * * these coordinates and indices will never be referenced again by this construction sequence.
41
+ * * typically the caller sets the halfEdge/mate coordinates in this callback.
41
42
  * * if [indexB, indexA] appeared previously (and its outer HalfEdge was left "unmatched"),
42
43
  * the "unmatched" HalfEdge is used in the loop being constructed, and its EXTERIOR mask is cleared.
43
44
  * @param indices Array of indices around the loop. This is accessed cyclically, so first and last indices should be different.
44
45
  * @param announceMatedHalfEdges optional function to be called as mated pairs are created. At the call,
45
- * the given HalfEdge and its mate will have a pair of successive indices from the array.
46
+ * the given HalfEdge and its mate will have a pair of successive indices from the array in their `i` property.
46
47
  */
47
48
  insertLoop(indices, announceMatedHalfEdges) {
48
49
  const n = indices.length;
49
50
  if (n > 2) {
50
- let index0 = indices[indices.length - 1];
51
+ let index0 = indices[n - 1];
51
52
  this._halfEdgesAroundCurrentLoop.length = 0;
52
53
  for (const index1 of indices) {
53
54
  const insideString = this.indexPairToString(index0, index1);
@@ -1 +1 @@
1
- {"version":3,"file":"HalfEdgeGraphFromIndexedLoopsContext.js","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphFromIndexedLoopsContext.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAE/F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhE;;GAEG;AAEH;;;;;;;GAOG;AACH,MAAM,OAAO,oCAAoC;IAC/C;QACE,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAG,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,EAAG,CAAC;QACnC,IAAI,CAAC,2BAA2B,GAAG,EAAE,CAAC;IACxC,CAAC;IACO,eAAe,CAAwB;IACvC,MAAM,CAAgB;IAC9B,IAAW,KAAK,KAAmB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA,CAAC;IAEvD,oCAAoC;IAC5B,2BAA2B,CAAa;IACxC,iBAAiB,CAAC,MAAc,EAAE,MAAc;QACtD,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IACrD,CAAC;IACD;;;;;;;;;;;;;;;OAeG;IACI,UAAU,CAAC,OAAiB,EAAE,sBAAqD;QACxF,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC7D,MAAM,6CAA6C,GAAyB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAE,YAAY,CAAC,CAAC;gBACpH,IAAI,6CAA6C,KAAK,SAAS,EAAC,CAAC;oBAC/D,iEAAiE;oBACjE,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,uDAAuD;oBACtH,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC1E,IAAI,sBAAsB,KAAK,SAAS;wBACtC,sBAAsB,CAAE,qBAAqB,CAAC,CAAC;oBACjD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAE,aAAa,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;oBACzE,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAE,qBAAqB,CAAC,CAAC;oBAC9D,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;gBACjE,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAE,6CAA6C,CAAC,CAAC;oBACtF,6CAA6C,CAAC,SAAS,CAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;gBAClF,CAAC;gBACD,MAAM,GAAG,MAAM,CAAC;YAClB,CAAC;YACD,IAAI,SAAS,GAAG,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC9F,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,2BAA2B,EAAC,CAAC;gBACxD,MAAM,SAAS,GAAG,SAAS,CAAC,aAAa,CAAC;gBAC1C,QAAQ,CAAC,KAAK,CAAE,SAAS,EAAE,SAAS,CAAC,CAAC;gBACtC,SAAS,GAAG,SAAS,CAAC;YACxB,CAAC;YACD,OAAO,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n\nimport { HalfEdge, HalfEdgeGraph, HalfEdgeMask } from \"./Graph\";\n\n/** @packageDocumentation\n * @module Topology\n */\n\n/**\n * Context for building a half edge graph from loops defined only by indices.\n * * Direct use case:\n * * Create the context.\n * * Repeatedly call insertLoop(indicesAroundLoop) to announce various loops.\n * * Finish by accessing the graph property.\n * @internal\n */\nexport class HalfEdgeGraphFromIndexedLoopsContext {\n public constructor(){\n this._unmatchedEdges = new Map ();\n this._graph = new HalfEdgeGraph ();\n this._halfEdgesAroundCurrentLoop = [];\n }\n private _unmatchedEdges: Map<string, HalfEdge>;\n private _graph: HalfEdgeGraph;\n public get graph(): HalfEdgeGraph {return this._graph;}\n\n // for multiple uses by insert loop.\n private _halfEdgesAroundCurrentLoop: HalfEdge[];\n private indexPairToString(index0: number, index1: number): string{\n return `${index0.toString()},${index1.toString()}`;\n }\n /** Create a loop with specified indices at its vertices.\n * * For an edge with index pair [indexA, indexB]:\n * * if [indexB, indexA] has never appeared, a HalfEdge mated pair is created.\n * * One of that mated pair becomes a HalfEdge in this loop.\n * * The other is \"unmatched\" and gets the EXTERIOR mask.\n * * When announceMatedHalfEdges(halfEdge) is called:\n * * halfEdge and its mate are \"new\"\n * * all coordinates are zeros.\n * * each contains (as its `i` property) one index of the [indexA,indexB] pair.\n * * those coordinates and indices will never be referenced again by this construction sequence -- the caller is free to mutate them as needed.\n * * if [indexB, indexA] appeared previously (and its outer HalfEdge was left \"unmatched\"),\n * the \"unmatched\" HalfEdge is used in the loop being constructed, and its EXTERIOR mask is cleared.\n * @param indices Array of indices around the loop. This is accessed cyclically, so first and last indices should be different.\n * @param announceMatedHalfEdges optional function to be called as mated pairs are created. At the call,\n * the given HalfEdge and its mate will have a pair of successive indices from the array.\n */\n public insertLoop(indices: number[], announceMatedHalfEdges?: (halfEdge: HalfEdge) => void): HalfEdge | undefined{\n const n = indices.length;\n if (n > 2) {\n let index0 = indices[indices.length - 1];\n this._halfEdgesAroundCurrentLoop.length = 0;\n for (const index1 of indices) {\n const insideString = this.indexPairToString (index0, index1);\n const halfEdgePreviouslyConstructedFromOppositeSide: HalfEdge | undefined = this._unmatchedEdges.get (insideString);\n if (halfEdgePreviouslyConstructedFromOppositeSide === undefined){\n // This is the first appearance of this edge in either direction.\n const outsideString = this.indexPairToString (index1, index0); // string referencing the \"other\" side of the new edge.\n const newHalfEdgeAroundLoop = this._graph.createEdgeIdId (index0, index1);\n if (announceMatedHalfEdges !== undefined)\n announceMatedHalfEdges (newHalfEdgeAroundLoop);\n this._unmatchedEdges.set (outsideString, newHalfEdgeAroundLoop.edgeMate);\n this._halfEdgesAroundCurrentLoop.push (newHalfEdgeAroundLoop);\n newHalfEdgeAroundLoop.edgeMate.setMask (HalfEdgeMask.EXTERIOR);\n } else {\n this._halfEdgesAroundCurrentLoop.push (halfEdgePreviouslyConstructedFromOppositeSide);\n halfEdgePreviouslyConstructedFromOppositeSide.clearMask (HalfEdgeMask.EXTERIOR);\n }\n index0 = index1;\n }\n let halfEdgeA = this._halfEdgesAroundCurrentLoop[this._halfEdgesAroundCurrentLoop.length - 1];\n for (const halfEdgeB of this._halfEdgesAroundCurrentLoop){\n const halfEdgeC = halfEdgeA.faceSuccessor;\n HalfEdge.pinch (halfEdgeB, halfEdgeC);\n halfEdgeA = halfEdgeB;\n }\n return this._halfEdgesAroundCurrentLoop[0];\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"HalfEdgeGraphFromIndexedLoopsContext.js","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphFromIndexedLoopsContext.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAE/F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhE;;GAEG;AAEH;;;;;;;GAOG;AACH,MAAM,OAAO,oCAAoC;IAC/C;QACE,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAG,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,EAAG,CAAC;QACnC,IAAI,CAAC,2BAA2B,GAAG,EAAE,CAAC;IACxC,CAAC;IACO,eAAe,CAAwB;IACvC,MAAM,CAAgB;IAC9B,IAAW,KAAK,KAAmB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA,CAAC;IAEvD,oCAAoC;IAC5B,2BAA2B,CAAa;IACxC,iBAAiB,CAAC,MAAc,EAAE,MAAc;QACtD,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IACrD,CAAC;IACD;;;;;;;;;;;;;;;;OAgBG;IACI,UAAU,CAAC,OAAiB,EAAE,sBAAqD;QACxF,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,IAAI,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC7D,MAAM,6CAA6C,GAAyB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAE,YAAY,CAAC,CAAC;gBACpH,IAAI,6CAA6C,KAAK,SAAS,EAAE,CAAC;oBAChE,iEAAiE;oBACjE,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,uDAAuD;oBACtH,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAE,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC1E,IAAI,sBAAsB,KAAK,SAAS;wBACtC,sBAAsB,CAAE,qBAAqB,CAAC,CAAC;oBACjD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAE,aAAa,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;oBACzE,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAE,qBAAqB,CAAC,CAAC;oBAC9D,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;gBACjE,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAE,6CAA6C,CAAC,CAAC;oBACtF,6CAA6C,CAAC,SAAS,CAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;gBAClF,CAAC;gBACD,MAAM,GAAG,MAAM,CAAC;YAClB,CAAC;YACD,IAAI,SAAS,GAAG,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC9F,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,2BAA2B,EAAC,CAAC;gBACxD,MAAM,SAAS,GAAG,SAAS,CAAC,aAAa,CAAC;gBAC1C,QAAQ,CAAC,KAAK,CAAE,SAAS,EAAE,SAAS,CAAC,CAAC;gBACtC,SAAS,GAAG,SAAS,CAAC;YACxB,CAAC;YACD,OAAO,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n\nimport { HalfEdge, HalfEdgeGraph, HalfEdgeMask } from \"./Graph\";\n\n/** @packageDocumentation\n * @module Topology\n */\n\n/**\n * Context for building a half edge graph from loops defined only by indices.\n * * Direct use case:\n * * Create the context.\n * * Repeatedly call insertLoop(indicesAroundLoop) to announce various loops.\n * * Finish by accessing the graph property.\n * @internal\n */\nexport class HalfEdgeGraphFromIndexedLoopsContext {\n public constructor(){\n this._unmatchedEdges = new Map ();\n this._graph = new HalfEdgeGraph ();\n this._halfEdgesAroundCurrentLoop = [];\n }\n private _unmatchedEdges: Map<string, HalfEdge>;\n private _graph: HalfEdgeGraph;\n public get graph(): HalfEdgeGraph {return this._graph;}\n\n // for multiple uses by insert loop.\n private _halfEdgesAroundCurrentLoop: HalfEdge[];\n private indexPairToString(index0: number, index1: number): string{\n return `${index0.toString()},${index1.toString()}`;\n }\n /** Create a loop with specified indices at its vertices.\n * * For an edge with index pair [indexA, indexB]:\n * * if [indexB, indexA] has never appeared, a HalfEdge mated pair is created.\n * * One of that mated pair becomes a HalfEdge in this loop.\n * * The other is \"unmatched\" and gets the EXTERIOR mask.\n * * When announceMatedHalfEdges(halfEdge) is called:\n * * halfEdge and its mate are \"new\".\n * * each contains (as its `i` property) one index of the [indexA,indexB] pair.\n * * all coordinates are zeros.\n * * these coordinates and indices will never be referenced again by this construction sequence.\n * * typically the caller sets the halfEdge/mate coordinates in this callback.\n * * if [indexB, indexA] appeared previously (and its outer HalfEdge was left \"unmatched\"),\n * the \"unmatched\" HalfEdge is used in the loop being constructed, and its EXTERIOR mask is cleared.\n * @param indices Array of indices around the loop. This is accessed cyclically, so first and last indices should be different.\n * @param announceMatedHalfEdges optional function to be called as mated pairs are created. At the call,\n * the given HalfEdge and its mate will have a pair of successive indices from the array in their `i` property.\n */\n public insertLoop(indices: number[], announceMatedHalfEdges?: (halfEdge: HalfEdge) => void): HalfEdge | undefined{\n const n = indices.length;\n if (n > 2) {\n let index0 = indices[n - 1];\n this._halfEdgesAroundCurrentLoop.length = 0;\n for (const index1 of indices) {\n const insideString = this.indexPairToString (index0, index1);\n const halfEdgePreviouslyConstructedFromOppositeSide: HalfEdge | undefined = this._unmatchedEdges.get (insideString);\n if (halfEdgePreviouslyConstructedFromOppositeSide === undefined) {\n // This is the first appearance of this edge in either direction.\n const outsideString = this.indexPairToString (index1, index0); // string referencing the \"other\" side of the new edge.\n const newHalfEdgeAroundLoop = this._graph.createEdgeIdId (index0, index1);\n if (announceMatedHalfEdges !== undefined)\n announceMatedHalfEdges (newHalfEdgeAroundLoop);\n this._unmatchedEdges.set (outsideString, newHalfEdgeAroundLoop.edgeMate);\n this._halfEdgesAroundCurrentLoop.push (newHalfEdgeAroundLoop);\n newHalfEdgeAroundLoop.edgeMate.setMask (HalfEdgeMask.EXTERIOR);\n } else {\n this._halfEdgesAroundCurrentLoop.push (halfEdgePreviouslyConstructedFromOppositeSide);\n halfEdgePreviouslyConstructedFromOppositeSide.clearMask (HalfEdgeMask.EXTERIOR);\n }\n index0 = index1;\n }\n let halfEdgeA = this._halfEdgesAroundCurrentLoop[this._halfEdgesAroundCurrentLoop.length - 1];\n for (const halfEdgeB of this._halfEdgesAroundCurrentLoop){\n const halfEdgeC = halfEdgeA.faceSuccessor;\n HalfEdge.pinch (halfEdgeB, halfEdgeC);\n halfEdgeA = halfEdgeB;\n }\n return this._halfEdgesAroundCurrentLoop[0];\n }\n return undefined;\n }\n}\n"]}
@@ -109,17 +109,25 @@ export declare class HalfEdgeGraphSearch {
109
109
  */
110
110
  static collectConnectedComponentsWithExteriorParityMasks(graph: HalfEdgeGraph, parityEdgeTester: HalfEdgeTestObject | undefined, parityMask?: HalfEdgeMask): HalfEdge[][];
111
111
  /**
112
- * Breadth First Search through connected component of a graph.
113
- * @param component vector of nodes, one per face.
114
- * @param seed seed node in component.
115
- * @param visitMask mask to apply to visited nodes. Assumed cleared throughout component.
116
- * @param ignoreMask (optional) mask preset on faces to ignore. Default value is `HalfEdgeMask.EXTERIOR` to
117
- * ignore exterior faces. Pass `HalfEdgeMask.NULL_MASK` to process all faces.
118
- * @param maxFaceCount (optional) maximum number of faces in the component. Should be positive; otherwise
119
- * `Infinity` is used.
120
- * @returns node at which to start next component if maximum face count exceeded, or undefined.
112
+ * Breadth-first search through the connected component defined by `seed` and `ignoreMask`.
113
+ * @param seed a HalfEdge in the component from which to start the search.
114
+ * @param visitMask a mask to apply to visited nodes. Assumed cleared throughout component before first call.
115
+ * @param ignoreMask (optional) mask preset on faces that are to be treated as _outside_ the component.
116
+ * Default value is `HalfEdgeMask.EXTERIOR` to ignore exterior faces.
117
+ * Pass `HalfEdgeMask.NULL_MASK` to process all faces of the component.
118
+ * Note that if `ignoreMask` is set on both sides of an edge, both adjacent faces will be ignored; thus it
119
+ * is generally more useful if set on only one side of an edge.
120
+ * @param maxFaceCount (optional) maximum number of faces to search in the component. If nonpositive or
121
+ * `undefined`, `Infinity` is used.
122
+ * @param result optional array to append with HalfEdges and return as the `faces` array. This array is not
123
+ * emptied first, so callers can send it into a subsequent call to continue searching the component at `nextSeed`.
124
+ * @returns `faces` consists of one edge per face of the component; `nextSeed` is the seed at which to start
125
+ * the next call if `maxFaceCount` is exceeded (otherwise it is `undefined`).
121
126
  */
122
- private static exploreComponent;
127
+ static exploreComponent(seed: HalfEdge, visitMask: HalfEdgeMask, ignoreMask?: HalfEdgeMask, maxFaceCount?: number, result?: HalfEdge[]): {
128
+ faces: HalfEdge[];
129
+ nextSeed: HalfEdge | undefined;
130
+ };
123
131
  /**
124
132
  * Collect connected components of the graph (via Breadth First Search).
125
133
  * @param graph graph to inspect.
@@ -133,12 +141,13 @@ export declare class HalfEdgeGraphSearch {
133
141
  static collectConnectedComponents(graph: HalfEdgeGraph, maxFaceCount?: number, ignoreMask?: HalfEdgeMask): HalfEdge[][];
134
142
  /**
135
143
  * Test if test point (xTest,yTest) is inside/outside a face or on an edge.
144
+ * * NOTE: a point outside the graph (in the exterior face) returns -1.
136
145
  * @param seedNode any node on the face loop.
137
146
  * @param xTest x coordinate of the test point.
138
147
  * @param yTest y coordinate of the test point.
139
148
  * @returns 0 if ON, 1 if IN, -1 if OUT.
140
149
  */
141
- static pointInOrOnFaceXY(seedNode: HalfEdge, xTest: number, yTest: number): number | undefined;
150
+ static pointInOrOnFaceXY(seedNode: HalfEdge, xTest: number, yTest: number): number;
142
151
  /**
143
152
  * Collect boundary edges starting from `seed`.
144
153
  * * If `seed` is not a boundary node or is already visited, the function exists early.
@@ -1 +1 @@
1
- {"version":3,"file":"HalfEdgeGraphSearch.d.ts","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphSearch.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,yBAAyB,EAAgB,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/H,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CAChC;AACD;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,YAAY,CAAU;IAC9B;;;;OAIG;gBACgB,IAAI,EAAE,YAAY,EAAE,WAAW,GAAE,OAAc;IAIlE,0EAA0E;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO;CAGzC;AACD;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B;;;;OAIG;WACW,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM;IAGpD;;;;;;OAMG;WACW,sBAAsB,CAClC,MAAM,EAAE,aAAa,GAAG,QAAQ,EAAE,EAClC,eAAe,GAAE,OAAe,EAChC,YAAY,GAAE,oBAAyE,GACtF,iBAAiB,CAAC,QAAQ,CAAC;IAa9B;;;;;OAKG;WACW,mBAAmB,CAC/B,uBAAuB,EAAE,aAAa,GAAG,QAAQ,EAAE,EAAE,gBAAgB,CAAC,EAAE,oBAAoB,GAC3F,QAAQ,GAAG,SAAS;IAIvB;;;;;;OAMG;WACW,iBAAiB,CAC7B,MAAM,EAAE,aAAa,GAAG,QAAQ,EAAE,EAClC,8BAA8B,GAAE,OAAc,EAC9C,4BAA4B,GAAE,MAAU,GACvC,OAAO;IA6BV;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;IASxC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2BlC;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,8BAA8B;IAgB7C,sHAAsH;IACtH,OAAO,CAAC,MAAM,CAAC,8BAA8B;IAM7C;;;;;;;;;;;;;OAaG;WACW,iDAAiD,CAC7D,KAAK,EAAE,aAAa,EACpB,gBAAgB,EAAE,kBAAkB,GAAG,SAAS,EAChD,UAAU,GAAE,YAAqC,GAChD,QAAQ,EAAE,EAAE;IAgBf;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IA4C/B;;;;;;;;;OASG;WACW,0BAA0B,CACtC,KAAK,EAAE,aAAa,EACpB,YAAY,GAAE,MAAiB,EAC/B,UAAU,GAAE,YAAoC,GAC/C,QAAQ,EAAE,EAAE;IAkCf;;;;;;OAMG;WACW,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA2BrG;;;;;;;;OAQG;WACW,mCAAmC,CAC/C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,YAAY,EACvB,cAAc,EAAE,yBAAyB,EACzC,sBAAsB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAChE,IAAI;IAoBP;;;;;;;;;OASG;WACW,mCAAmC,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,GAAG,QAAQ,EAAE,EAAE;CAkBlH"}
1
+ {"version":3,"file":"HalfEdgeGraphSearch.d.ts","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphSearch.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACjH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CAChC;AACD;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,YAAY,CAAU;IAC9B;;;;OAIG;gBACgB,IAAI,EAAE,YAAY,EAAE,WAAW,GAAE,OAAc;IAIlE,0EAA0E;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO;CAGzC;AACD;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B;;;;OAIG;WACW,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM;IAGpD;;;;;;OAMG;WACW,sBAAsB,CAClC,MAAM,EAAE,aAAa,GAAG,QAAQ,EAAE,EAClC,eAAe,GAAE,OAAe,EAChC,YAAY,GAAE,oBAAyE,GACtF,iBAAiB,CAAC,QAAQ,CAAC;IAa9B;;;;;OAKG;WACW,mBAAmB,CAC/B,uBAAuB,EAAE,aAAa,GAAG,QAAQ,EAAE,EAAE,gBAAgB,CAAC,EAAE,oBAAoB,GAC3F,QAAQ,GAAG,SAAS;IAIvB;;;;;;OAMG;WACW,iBAAiB,CAC7B,MAAM,EAAE,aAAa,GAAG,QAAQ,EAAE,EAClC,8BAA8B,GAAE,OAAc,EAC9C,4BAA4B,GAAE,MAAU,GACvC,OAAO;IA6BV;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;IASxC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2BlC;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,8BAA8B;IAgB7C,sHAAsH;IACtH,OAAO,CAAC,MAAM,CAAC,8BAA8B;IAM7C;;;;;;;;;;;;;OAaG;WACW,iDAAiD,CAC7D,KAAK,EAAE,aAAa,EACpB,gBAAgB,EAAE,kBAAkB,GAAG,SAAS,EAChD,UAAU,GAAE,YAAqC,GAChD,QAAQ,EAAE,EAAE;IAgBf;;;;;;;;;;;;;;;OAeG;WACW,gBAAgB,CAC5B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,YAAY,EACvB,UAAU,GAAE,YAAoC,EAChD,YAAY,GAAE,MAAiB,EAC/B,MAAM,CAAC,EAAE,QAAQ,EAAE,GAClB;QAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAA;KAAC;IAoCvD;;;;;;;;;OASG;WACW,0BAA0B,CACtC,KAAK,EAAE,aAAa,EACpB,YAAY,GAAE,MAAiB,EAC/B,UAAU,GAAE,YAAoC,GAC/C,QAAQ,EAAE,EAAE;IAmCf;;;;;;;OAOG;WACW,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IA2BzF;;;;;;;;OAQG;WACW,mCAAmC,CAC/C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,YAAY,EACvB,cAAc,EAAE,yBAAyB,EACzC,sBAAsB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAChE,IAAI;IAoBP;;;;;;;;;OASG;WACW,mCAAmC,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,GAAG,QAAQ,EAAE,EAAE;CAkBlH"}
@@ -227,53 +227,55 @@ export class HalfEdgeGraphSearch {
227
227
  return components;
228
228
  }
229
229
  /**
230
- * Breadth First Search through connected component of a graph.
231
- * @param component vector of nodes, one per face.
232
- * @param seed seed node in component.
233
- * @param visitMask mask to apply to visited nodes. Assumed cleared throughout component.
234
- * @param ignoreMask (optional) mask preset on faces to ignore. Default value is `HalfEdgeMask.EXTERIOR` to
235
- * ignore exterior faces. Pass `HalfEdgeMask.NULL_MASK` to process all faces.
236
- * @param maxFaceCount (optional) maximum number of faces in the component. Should be positive; otherwise
237
- * `Infinity` is used.
238
- * @returns node at which to start next component if maximum face count exceeded, or undefined.
230
+ * Breadth-first search through the connected component defined by `seed` and `ignoreMask`.
231
+ * @param seed a HalfEdge in the component from which to start the search.
232
+ * @param visitMask a mask to apply to visited nodes. Assumed cleared throughout component before first call.
233
+ * @param ignoreMask (optional) mask preset on faces that are to be treated as _outside_ the component.
234
+ * Default value is `HalfEdgeMask.EXTERIOR` to ignore exterior faces.
235
+ * Pass `HalfEdgeMask.NULL_MASK` to process all faces of the component.
236
+ * Note that if `ignoreMask` is set on both sides of an edge, both adjacent faces will be ignored; thus it
237
+ * is generally more useful if set on only one side of an edge.
238
+ * @param maxFaceCount (optional) maximum number of faces to search in the component. If nonpositive or
239
+ * `undefined`, `Infinity` is used.
240
+ * @param result optional array to append with HalfEdges and return as the `faces` array. This array is not
241
+ * emptied first, so callers can send it into a subsequent call to continue searching the component at `nextSeed`.
242
+ * @returns `faces` consists of one edge per face of the component; `nextSeed` is the seed at which to start
243
+ * the next call if `maxFaceCount` is exceeded (otherwise it is `undefined`).
239
244
  */
240
- static exploreComponent(component, seed, visitMask, ignoreMask = HalfEdgeMask.EXTERIOR, maxFaceCount = Infinity) {
245
+ static exploreComponent(seed, visitMask, ignoreMask = HalfEdgeMask.EXTERIOR, maxFaceCount = Infinity, result) {
241
246
  if (maxFaceCount <= 0)
242
247
  maxFaceCount = Infinity;
243
248
  const boundaryMask = visitMask | ignoreMask;
244
249
  let numFaces = 0;
245
250
  const candidates = []; // the queue
251
+ const faces = result ? result : [];
246
252
  candidates.push(seed);
247
- while (candidates.length !== 0 && numFaces < maxFaceCount) {
248
- // shift is O(n) and may be inefficient for large queues; if needed, we can replace
249
- // queue by circular array or implement the queue using 2 stacks; both are O(1)
253
+ while (candidates.length > 0 && numFaces < maxFaceCount) {
254
+ // TODO: shift is O(n) thus inefficient for large queues. If needed, we can
255
+ // replace the queue by a circular array or use 2 stacks; both are O(1).
250
256
  const node = candidates.shift();
251
- if (node.isMaskSet(boundaryMask))
252
- continue;
253
- component.push(node);
254
- ++numFaces;
255
- const enqueueNeighboringFaces = (heNode) => {
256
- heNode.setMask(visitMask);
257
- const neighbor = heNode.vertexSuccessor;
258
- if (!neighbor.isMaskSet(boundaryMask))
259
- candidates.push(neighbor);
260
- };
261
- node.collectAroundFace(enqueueNeighboringFaces);
257
+ if (node && !node.isMaskSet(boundaryMask)) {
258
+ faces.push(node);
259
+ ++numFaces;
260
+ node.collectAroundFace((he) => {
261
+ he.setMask(visitMask);
262
+ const neighbor = he.vertexSuccessor;
263
+ if (!neighbor.isMaskSet(boundaryMask))
264
+ candidates.push(neighbor); // enqueue neighboring face
265
+ });
266
+ }
262
267
  }
263
268
  if (candidates.length === 0)
264
- return undefined;
265
- else {
266
- const front = candidates[0];
267
- while (candidates.length !== 0) {
268
- // try to find a node at the boundary of both the geometry and previous component
269
- const node = candidates.shift(); // shift may be inefficient for large queues
270
- if (node.vertexSuccessor.isMaskSet(ignoreMask))
271
- return node;
272
- if (node.edgeMate.isMaskSet(ignoreMask))
273
- return node;
269
+ return { faces, nextSeed: undefined };
270
+ // try to find a node at the boundary of the current component and the next
271
+ let nextSeed = candidates[0];
272
+ for (const candidate of candidates) {
273
+ if (candidate.vertexSuccessor.isMaskSet(ignoreMask) || candidate.edgeMate.isMaskSet(ignoreMask)) {
274
+ nextSeed = candidate;
275
+ break;
274
276
  }
275
- return front;
276
277
  }
278
+ return { faces, nextSeed };
277
279
  }
278
280
  /**
279
281
  * Collect connected components of the graph (via Breadth First Search).
@@ -290,6 +292,7 @@ export class HalfEdgeGraphSearch {
290
292
  if (graph.countMask(ignoreMask) === 0)
291
293
  ignoreMask = HalfEdgeMask.NULL_MASK;
292
294
  const visitMask = HalfEdgeMask.VISITED;
295
+ graph.clearMask(visitMask);
293
296
  const boundaryMask = visitMask | ignoreMask;
294
297
  // Starting with the input node, look ahead for a boundary face. Failing that, return the input node.
295
298
  // Starting all floods at the boundary reduces the chance of ending up with a ring-shaped component at the boundary.
@@ -309,10 +312,10 @@ export class HalfEdgeGraphSearch {
309
312
  const i0 = findNextFloodSeed(i);
310
313
  let seed = graph.allHalfEdges[i0];
311
314
  do { // flood this component
312
- const component = [];
313
- seed = HalfEdgeGraphSearch.exploreComponent(component, seed, visitMask, ignoreMask, maxFaceCount);
314
- if (component.length !== 0)
315
- components.push(component);
315
+ const result = HalfEdgeGraphSearch.exploreComponent(seed, visitMask, ignoreMask, maxFaceCount);
316
+ seed = result.nextSeed;
317
+ if (result.faces.length > 0)
318
+ components.push(result.faces); // each sub-component of length <= maxFaceCount is treated as a component
316
319
  } while (seed !== undefined);
317
320
  if (!graph.allHalfEdges[i].isMaskSet(visitMask))
318
321
  --i; // reprocess this node
@@ -321,6 +324,7 @@ export class HalfEdgeGraphSearch {
321
324
  }
322
325
  /**
323
326
  * Test if test point (xTest,yTest) is inside/outside a face or on an edge.
327
+ * * NOTE: a point outside the graph (in the exterior face) returns -1.
324
328
  * @param seedNode any node on the face loop.
325
329
  * @param xTest x coordinate of the test point.
326
330
  * @param yTest y coordinate of the test point.
@@ -1 +1 @@
1
- {"version":3,"file":"HalfEdgeGraphSearch.js","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphSearch.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAE/F;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAY,aAAa,EAAE,YAAY,EAAiE,MAAM,SAAS,CAAC;AAC/H,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAShE;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACrB,WAAW,CAAe;IAC1B,YAAY,CAAU;IAC9B;;;;OAIG;IACH,YAAmB,IAAkB,EAAE,cAAuB,IAAI;QAChE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IAClC,CAAC;IACD,0EAA0E;IACnE,QAAQ,CAAC,IAAc;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC;IAChE,CAAC;CACF;AACD;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;;;OAIG;IACI,MAAM,CAAC,cAAc,CAAC,IAAc;QACzC,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD;;;;;;OAMG;IACI,MAAM,CAAC,sBAAsB,CAClC,MAAkC,EAClC,kBAA2B,KAAK,EAChC,eAAqC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,cAAc,CAAC,IAAI,CAAC;QAEvF,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAW,eAAe,CAAC,CAAC;QAChE,IAAI,QAAoB,CAAC;QACzB,IAAI,MAAM,YAAY,aAAa;YACjC,QAAQ,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;;YAErC,QAAQ,GAAG,MAAM,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD;;;;;OAKG;IACI,MAAM,CAAC,mBAAmB,CAC/B,uBAAmD,EAAE,gBAAuC;QAE5F,MAAM,OAAO,GAAG,mBAAmB,CAAC,sBAAsB,CAAC,uBAAuB,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;QAC7G,OAAO,OAAO,CAAC,mBAAmB,CAAC;IACrC,CAAC;IACD;;;;;;OAMG;IACI,MAAM,CAAC,iBAAiB,CAC7B,MAAkC,EAClC,iCAA0C,IAAI,EAC9C,+BAAuC,CAAC;QAExC,IAAI,QAAoB,CAAC;QACzB,IAAI,MAAM,YAAY,aAAa;YACjC,QAAQ,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;;YAErC,QAAQ,GAAG,MAAM,CAAC;QACpB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,qBAAqB,GAAG,CAAC,CAAC;QAC9B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC7C,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;gBACnC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;oBACb,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;wBACjB,qBAAqB,EAAE,CAAC;wBACxB,IAAI,qBAAqB,GAAG,4BAA4B;4BACtD,OAAO,KAAK,CAAC;oBACjB,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,WAAW,EAAE,CAAC;oBACd,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;wBACpB,IAAI,CAAC,8BAA8B;4BACjC,OAAO,KAAK,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD;;;;;;OAMG;IACK,MAAM,CAAC,yBAAyB,CACtC,QAAkB,EAAE,IAAY,EAAE,YAAwB,EAAE,eAA2B;QAEvF,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,QAAQ,CAAC,iBAAiB,CAAC,CAAC,IAAc,EAAE,EAAE;YAC5C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACnB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IACD;;;;;;;;;;;;;OAaG;IACK,MAAM,CAAC,mBAAmB,CAChC,QAAkB,EAClB,SAAuB,EACvB,gBAAgD,EAChD,UAAwB;QAExB,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC;YAC/B,OAAO,KAAK,CAAC,CAAC,cAAc;QAC9B,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;QACxC,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,wDAAwD;QACxD,mBAAmB,CAAC,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAChF,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;YACvB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC;YACxB,IAAI,CAAC,IAAI;gBACP,SAAS;YACX,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,IAAI,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;gBACvC,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;oBACnD,QAAQ,GAAG,CAAC,QAAQ,CAAC;gBACvB,mBAAmB,CAAC,yBAAyB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;YACrG,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD;;;;;;;;;OASG;IACK,MAAM,CAAC,8BAA8B,CAAC,UAAwB,EAAE,KAAiB;QACvF,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACxE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,6CAA6C;QAC/C,CAAC;aAAM,IAAI,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YAClD,oCAAoC;QACtC,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;gBAC7B,IAAI,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;oBACnC,QAAQ,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,sHAAsH;IAC9G,MAAM,CAAC,8BAA8B,CAAC,UAAwB,EAAE,UAAwB;QAC9F,IAAI,UAAU,KAAK,YAAY,CAAC,SAAS;YACvC,OAAO;QACT,KAAK,MAAM,gBAAgB,IAAI,UAAU;YACvC,mBAAmB,CAAC,8BAA8B,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IACrF,CAAC;IACD;;;;;;;;;;;;;OAaG;IACI,MAAM,CAAC,iDAAiD,CAC7D,KAAoB,EACpB,gBAAgD,EAChD,aAA2B,YAAY,CAAC,SAAS;QAEjD,+EAA+E;QAC/E,MAAM,UAAU,GAAG,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;QACxC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC1B,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC1C,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,CAAC,CAAC;gBAC5G,mGAAmG;gBACnG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,mBAAmB,CAAC,8BAA8B,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC3E,OAAO,UAAU,CAAC;IACpB,CAAC;IACD;;;;;;;;;;OAUG;IACK,MAAM,CAAC,gBAAgB,CAC7B,SAAqB,EACrB,IAAc,EACd,SAAuB,EACvB,aAA2B,YAAY,CAAC,QAAQ,EAChD,eAAuB,QAAQ;QAE/B,IAAI,YAAY,IAAI,CAAC;YACnB,YAAY,GAAG,QAAQ,CAAC;QAC1B,MAAM,YAAY,GAAiB,SAAS,GAAG,UAAU,CAAC;QAC1D,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,MAAM,UAAU,GAAe,EAAE,CAAC,CAAC,YAAY;QAC/C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC1D,mFAAmF;YACnF,+EAA+E;YAC/E,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAG,CAAC;YACjC,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;gBAC9B,SAAS;YACX,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,EAAE,QAAQ,CAAC;YACX,MAAM,uBAAuB,GAAiB,CAAC,MAAgB,EAAE,EAAE;gBACjE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,eAAe,CAAC;gBACxC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC;oBACnC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YACzB,OAAO,SAAS,CAAC;aACd,CAAC;YACJ,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,iFAAiF;gBACjF,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAG,CAAC,CAAC,4CAA4C;gBAC9E,IAAI,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,UAAU,CAAC;oBAC5C,OAAO,IAAI,CAAC;gBACd,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC;oBACrC,OAAO,IAAI,CAAC;YAChB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD;;;;;;;;;OASG;IACI,MAAM,CAAC,0BAA0B,CACtC,KAAoB,EACpB,eAAuB,QAAQ,EAC/B,aAA2B,YAAY,CAAC,QAAQ;QAEhD,MAAM,UAAU,GAAiB,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;YACnC,UAAU,GAAG,YAAY,CAAC,SAAS,CAAC;QACtC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,MAAM,YAAY,GAAiB,SAAS,GAAG,UAAU,CAAC;QAC1D,qGAAqG;QACrG,oHAAoH;QACpH,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAE;YAC1C,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC;uBAC7C,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC5D,KAAK,GAAG,CAAC,CAAC;oBACV,MAAM;gBACR,CAAC;YACH,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC;gBAC/C,SAAS;YACX,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,IAAI,GAAyB,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YACxD,GAAG,CAAC,CAAC,uBAAuB;gBAC1B,MAAM,SAAS,GAAe,EAAE,CAAC;gBACjC,IAAI,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;gBAClG,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;oBACxB,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC,QAAQ,IAAI,KAAK,SAAS,EAAE;YAC7B,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;gBAC7C,EAAE,CAAC,CAAC,CAAC,sBAAsB;QAC/B,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD;;;;;;OAMG;IACI,MAAM,CAAC,iBAAiB,CAAC,QAAkB,EAAE,KAAa,EAAE,KAAa;QAC9E,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxD,wFAAwF;QACxF,IAAI,KAAK,GAAG,QAAQ,CAAC;QACrB,IAAI,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC;QACnC,QAAS,KAAK,GAAG,KAAK,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC1D,MAAM;YACR,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvB,0DAA0D;gBAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC/D,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;YACD,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC;QAC9B,CAAC;QACD,iHAAiH;QACjH,IAAI,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC;QAChC,SAAU,CAAC;YACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvC,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;YAClC,CAAC;YACD,IAAI,KAAK,KAAK,KAAK;gBACjB,MAAM;YACR,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC;QAC9B,CAAC;QACD,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;IAClC,CAAC;IACD;;;;;;;;OAQG;IACI,MAAM,CAAC,mCAAmC,CAC/C,IAAc,EACd,SAAuB,EACvB,cAAyC,EACzC,sBAAiE;QAEjE,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACxB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;YACtC,IAAI,qBAAqB,GAAG,UAAU,CAAC;YACvC,SAAU,CAAC;gBACT,IAAI,qBAAqB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,uBAAuB;oBACnE,OAAO;gBACT,IAAI,cAAc,CAAC,qBAAqB,CAAC,EAAE,CAAC;oBAC1C,IAAI,GAAG,qBAAqB,CAAC;oBAC7B,MAAM;gBACR,CAAC;gBACD,qBAAqB,GAAG,qBAAqB,CAAC,iBAAiB,CAAC;gBAChE,IAAI,qBAAqB,KAAK,UAAU;oBACtC,MAAM,CAAC,8FAA8F;YACzG,CAAC;QACH,CAAC;IACH,CAAC;IACD;;;;;;;;;OASG;IACI,MAAM,CAAC,mCAAmC,CAAC,KAAoB,EAAE,YAA0B;QAChG,+EAA+E;QAC/E,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,cAAc,GAAG,CAAC,IAAc,EAAW,EAAE;YACjD,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACvF,CAAC,CAAC;QACF,MAAM,sBAAsB,GAAG,CAAC,IAAc,EAAE,OAAe,EAAE,EAAE;YACjE,IAAI,OAAO,KAAK,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACtC,IAAI,CAAC,mCAAmC,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC;QACpG,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;CACF","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n\n/** @packageDocumentation\n * @module Topology\n */\nimport { Range1d } from \"../geometry3d/Range\";\nimport { HalfEdge, HalfEdgeGraph, HalfEdgeMask, HalfEdgeToBooleanFunction, NodeFunction, NodeToNumberFunction } from \"./Graph\";\nimport { SignedDataSummary } from \"./SignedDataSummary\";\nimport { XYParitySearchContext } from \"./XYParitySearchContext\";\n\n/**\n * Interface for an object that executes boolean tests on edges.\n * @internal\n */\nexport interface HalfEdgeTestObject {\n testEdge(h: HalfEdge): boolean;\n}\n/**\n * Class to test match of half edge mask.\n * @internal\n */\nexport class HalfEdgeMaskTester {\n private _targetMask: HalfEdgeMask;\n private _targetValue: boolean;\n /**\n * Constructor\n * @param mask mask to test in `testEdge` function\n * @param targetValue value to match for true return\n */\n public constructor(mask: HalfEdgeMask, targetValue: boolean = true) {\n this._targetMask = mask;\n this._targetValue = targetValue;\n }\n /** Return true if the value of the targetMask matches the targetValue. */\n public testEdge(edge: HalfEdge): boolean {\n return edge.isMaskSet(this._targetMask) === this._targetValue;\n }\n}\n/**\n * Class for different types of searches for HalfEdgeGraph.\n * @internal\n */\nexport class HalfEdgeGraphSearch {\n /**\n * Static method for face area computation -- useful as function parameter in `collectFaceAreaSummary`.\n * * This simply calls `node.signedFaceArea()`\n * @param node instance for signedFaceArea call.\n */\n public static signedFaceArea(node: HalfEdge): number {\n return node.signedFaceArea();\n }\n /**\n * Return a summary of face data (e.g., area) as computed by the callback on the faces of the graph.\n * * Callers with curved edge graphs must supply their own area function.\n * @param source graph or array of nodes to examine.\n * @param collectAllNodes flag to pass to the `SignedDataSummary` constructor to control collection of nodes.\n * @param areaFunction function to obtain area (or other numeric value). Default computes polygonal face area.\n */\n public static collectFaceAreaSummary(\n source: HalfEdgeGraph | HalfEdge[],\n collectAllNodes: boolean = false,\n areaFunction: NodeToNumberFunction = (node) => HalfEdgeGraphSearch.signedFaceArea(node),\n ): SignedDataSummary<HalfEdge> {\n const result = new SignedDataSummary<HalfEdge>(collectAllNodes);\n let allFaces: HalfEdge[];\n if (source instanceof HalfEdgeGraph)\n allFaces = source.collectFaceLoops();\n else\n allFaces = source;\n for (const node of allFaces) {\n const area = areaFunction(node);\n result.announceItem(node, area);\n }\n return result;\n }\n /**\n * Search the graph for the face with the most negative area.\n * * If the graph has exactly one connected component, this is its outer face.\n * @param oneCandidateNodePerFace graph or an array containing one node from each face to be considered.\n * @returns node on the negative area face with largest absolute area, or `undefined` if no negative area face.\n */\n public static findMinimumAreaFace(\n oneCandidateNodePerFace: HalfEdgeGraph | HalfEdge[], faceAreaFunction?: NodeToNumberFunction,\n ): HalfEdge | undefined {\n const summary = HalfEdgeGraphSearch.collectFaceAreaSummary(oneCandidateNodePerFace, false, faceAreaFunction);\n return summary.largestNegativeItem;\n }\n /**\n * Test if the graph is triangulated.\n * * Return `false` if:\n * * number of positive area faces with more than 3 edges is larger than `numPositiveExceptionsAllowed`.\n * * graph has more than 1 negative area face when `allowMultipleNegativeAreaFaces` is `false`.\n * * 2-edge faces are ignored.\n */\n public static isTriangulatedCCW(\n source: HalfEdgeGraph | HalfEdge[],\n allowMultipleNegativeAreaFaces: boolean = true,\n numPositiveExceptionsAllowed: number = 0,\n ): boolean {\n let allFaces: HalfEdge[];\n if (source instanceof HalfEdgeGraph)\n allFaces = source.collectFaceLoops();\n else\n allFaces = source;\n let numNegative = 0;\n let numPositiveExceptions = 0;\n for (const node of allFaces) {\n const numEdges = node.countEdgesAroundFace();\n if (numEdges >= 3) {\n const area = node.signedFaceArea();\n if (area > 0) {\n if (numEdges > 3) {\n numPositiveExceptions++;\n if (numPositiveExceptions > numPositiveExceptionsAllowed)\n return false;\n }\n } else {\n numNegative++;\n if (numNegative > 1) {\n if (!allowMultipleNegativeAreaFaces)\n return false;\n }\n }\n }\n }\n return true;\n }\n /**\n * Process a face during graph traversal.\n * @param faceSeed a node in the face.\n * @param mask mask to set on each node of the face.\n * @param allNodeStack array appended with each node of the face.\n * @param onePerFaceStack array appended with `faceSeed`.\n */\n private static pushAndMaskAllNodesInFace(\n faceSeed: HalfEdge, mask: number, allNodeStack: HalfEdge[], onePerFaceStack: HalfEdge[],\n ): void {\n onePerFaceStack.push(faceSeed);\n faceSeed.collectAroundFace((node: HalfEdge) => {\n node.setMask(mask);\n allNodeStack.push(node);\n });\n }\n /**\n * Traverse (via Depth First Search) to all accessible faces from the given seed.\n * @param faceSeed first node to start the traverse.\n * @param visitMask mask applied to all faces as visited.\n * @param parityEdgeTester function to test if an edge is adjacent to two faces of opposite parity, e.g., a boundary\n * edge that separates an \"interior\" face and an \"exterior\" face. If `parityEdgeTester` is not supplied and `parityMask`\n * is supplied, the default parity rule is to alternate parity state in a \"bullseye\" pattern starting at the seed face,\n * with each successive concentric ring of faces at constant topological distance from the seed face receiving the\n * opposite parity state of the previous ring.\n * @param parityMask mask to apply to the first face and faces that share the same parity as the first face, as\n * determined by the parity rule. If this is `NULL_MASK`, there is no record of parity. If (non-null) parity mask\n * is given, on return it is entirely set or entirely clear around each face.\n * @returns an array that contains one representative node in each face of the connected component.\n */\n private static parityFloodFromSeed(\n faceSeed: HalfEdge,\n visitMask: HalfEdgeMask,\n parityEdgeTester: HalfEdgeTestObject | undefined,\n parityMask: HalfEdgeMask,\n ): HalfEdge[] {\n const faces: HalfEdge[] = [];\n if (faceSeed.isMaskSet(visitMask))\n return faces; // empty array\n const allMasks = parityMask | visitMask;\n const stack: HalfEdge[] = [];\n // the seed face is arbitrarily assigned the parity mask\n HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(faceSeed, allMasks, stack, faces);\n while (stack.length > 0) {\n const p = stack.pop()!;\n const mate = p.edgeMate;\n if (!mate)\n continue;\n if (!mate.isMaskSet(visitMask)) {\n let newState = p.isMaskSet(parityMask);\n if (!parityEdgeTester || parityEdgeTester.testEdge(p))\n newState = !newState;\n HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(mate, newState ? allMasks : visitMask, stack, faces);\n }\n }\n return faces;\n }\n /**\n * * Correct the parity mask in the faces of a component.\n * * It is assumed that the parity mask is applied _consistently_ throughout the supplied faces, but maybe\n * not _correctly_.\n * * A consistently applied parity mask is \"correct\" if it is set on the negative area (\"exterior\") face of\n * a connected component.\n * * This method finds a face with negative area and toggles the mask throughout the input faces if this face\n * lacks the parity mask.\n * * In a properly merged planar subdivision there should be only one true negative area face per component.\n */\n private static correctParityInSingleComponent(parityMask: HalfEdgeMask, faces: HalfEdge[]): void {\n const exteriorHalfEdge = HalfEdgeGraphSearch.findMinimumAreaFace(faces);\n if (!exteriorHalfEdge) {\n // graph has all degenerate faces; do nothing\n } else if (exteriorHalfEdge.isMaskSet(parityMask)) {\n // all should be well; nothing to do\n } else {\n for (const faceSeed of faces) {\n if (faceSeed.isMaskSet(parityMask)) {\n faceSeed.clearMaskAroundFace(parityMask);\n } else {\n faceSeed.setMaskAroundFace(parityMask);\n }\n }\n }\n }\n /** Apply `correctParityInSingleComponent` to each array in components (quick exit if `parityMask` is `NULL_MASK`). */\n private static correctParityInComponentArrays(parityMask: HalfEdgeMask, components: HalfEdge[][]): void {\n if (parityMask === HalfEdgeMask.NULL_MASK)\n return;\n for (const facesInComponent of components)\n HalfEdgeGraphSearch.correctParityInSingleComponent(parityMask, facesInComponent);\n }\n /**\n * Collect connected components of the graph (via Depth First Search).\n * @param graph graph to inspect.\n * @param parityEdgeTester (optional) function to test if an edge is adjacent to two faces of opposite parity,\n * e.g., a boundary edge that separates an \"interior\" face and an \"exterior\" face. If `parityEdgeTester` is not\n * supplied and `parityMask` is supplied, the default parity rule is to alternate parity state in a \"bullseye\"\n * pattern starting at the seed face, with each successive concentric ring of faces at constant topological\n * distance from the seed face receiving the opposite parity state of the previous ring.\n * @param parityMask (optional) mask to apply to the first face and faces that share the same parity as the\n * first face, as determined by the parity rule. If this is `NULL_MASK` (default), there is no record of parity.\n * If (non-null) parity mask is given, on return it is entirely set or entirely clear around each face.\n * @returns the components of the graph, each component represented by an array of nodes, one node per face\n * of the component. In other words, entry [i][j] is a HalfEdge in the j_th face loop of the i_th component.\n */\n public static collectConnectedComponentsWithExteriorParityMasks(\n graph: HalfEdgeGraph,\n parityEdgeTester: HalfEdgeTestObject | undefined,\n parityMask: HalfEdgeMask = HalfEdgeMask.NULL_MASK,\n ): HalfEdge[][] {\n // Illustration of the algorithm can be found at geometry/internaldocs/Graph.md\n const components = [];\n const visitMask = HalfEdgeMask.VISITED;\n const allMasks = parityMask | visitMask;\n graph.clearMask(allMasks);\n for (const faceSeed of graph.allHalfEdges) {\n if (!faceSeed.isMaskSet(visitMask)) {\n const newFaces = HalfEdgeGraphSearch.parityFloodFromSeed(faceSeed, visitMask, parityEdgeTester, parityMask);\n // parityFloodFromSeed does not return an empty array because it is called on an unvisited faceSeed\n components.push(newFaces);\n }\n }\n HalfEdgeGraphSearch.correctParityInComponentArrays(parityMask, components);\n return components;\n }\n /**\n * Breadth First Search through connected component of a graph.\n * @param component vector of nodes, one per face.\n * @param seed seed node in component.\n * @param visitMask mask to apply to visited nodes. Assumed cleared throughout component.\n * @param ignoreMask (optional) mask preset on faces to ignore. Default value is `HalfEdgeMask.EXTERIOR` to\n * ignore exterior faces. Pass `HalfEdgeMask.NULL_MASK` to process all faces.\n * @param maxFaceCount (optional) maximum number of faces in the component. Should be positive; otherwise\n * `Infinity` is used.\n * @returns node at which to start next component if maximum face count exceeded, or undefined.\n */\n private static exploreComponent(\n component: HalfEdge[],\n seed: HalfEdge,\n visitMask: HalfEdgeMask,\n ignoreMask: HalfEdgeMask = HalfEdgeMask.EXTERIOR,\n maxFaceCount: number = Infinity,\n ): HalfEdge | undefined {\n if (maxFaceCount <= 0)\n maxFaceCount = Infinity;\n const boundaryMask: HalfEdgeMask = visitMask | ignoreMask;\n let numFaces = 0;\n const candidates: HalfEdge[] = []; // the queue\n candidates.push(seed);\n while (candidates.length !== 0 && numFaces < maxFaceCount) {\n // shift is O(n) and may be inefficient for large queues; if needed, we can replace\n // queue by circular array or implement the queue using 2 stacks; both are O(1)\n const node = candidates.shift()!;\n if (node.isMaskSet(boundaryMask))\n continue;\n component.push(node);\n ++numFaces;\n const enqueueNeighboringFaces: NodeFunction = (heNode: HalfEdge) => {\n heNode.setMask(visitMask);\n const neighbor = heNode.vertexSuccessor;\n if (!neighbor.isMaskSet(boundaryMask))\n candidates.push(neighbor);\n };\n node.collectAroundFace(enqueueNeighboringFaces);\n }\n if (candidates.length === 0)\n return undefined;\n else {\n const front = candidates[0];\n while (candidates.length !== 0) {\n // try to find a node at the boundary of both the geometry and previous component\n const node = candidates.shift()!; // shift may be inefficient for large queues\n if (node.vertexSuccessor.isMaskSet(ignoreMask))\n return node;\n if (node.edgeMate.isMaskSet(ignoreMask))\n return node;\n }\n return front;\n }\n }\n /**\n * Collect connected components of the graph (via Breadth First Search).\n * @param graph graph to inspect.\n * @param maxFaceCount (optional) maximum number of faces in each component. Should be positive; otherwise\n * `Infinity` is used.\n * @param ignoreMask (optional) mask preset on faces to ignore. Default value is `HalfEdgeMask.EXTERIOR` to ignore\n * exterior faces. Pass `HalfEdgeMask.NULL_MASK` to process all faces.\n * @returns the components of the graph, each component represented by an array of nodes, one node per face\n * of the component. In other words, entry [i][j] is a HalfEdge in the j_th face loop of the i_th component.\n */\n public static collectConnectedComponents(\n graph: HalfEdgeGraph,\n maxFaceCount: number = Infinity,\n ignoreMask: HalfEdgeMask = HalfEdgeMask.EXTERIOR,\n ): HalfEdge[][] {\n const components: HalfEdge[][] = [];\n if (graph.countMask(ignoreMask) === 0)\n ignoreMask = HalfEdgeMask.NULL_MASK;\n const visitMask = HalfEdgeMask.VISITED;\n const boundaryMask: HalfEdgeMask = visitMask | ignoreMask;\n // Starting with the input node, look ahead for a boundary face. Failing that, return the input node.\n // Starting all floods at the boundary reduces the chance of ending up with a ring-shaped component at the boundary.\n const findNextFloodSeed = (index: number) => {\n for (let i = index; i < graph.countNodes(); ++i) {\n if (!graph.allHalfEdges[i].isMaskSet(boundaryMask)\n && graph.allHalfEdges[i].edgeMate.isMaskSet(boundaryMask)) {\n index = i;\n break;\n }\n }\n return index;\n };\n for (let i = 0; i < graph.countNodes(); ++i) {\n if (graph.allHalfEdges[i].isMaskSet(boundaryMask))\n continue;\n const i0 = findNextFloodSeed(i);\n let seed: HalfEdge | undefined = graph.allHalfEdges[i0];\n do { // flood this component\n const component: HalfEdge[] = [];\n seed = HalfEdgeGraphSearch.exploreComponent(component, seed, visitMask, ignoreMask, maxFaceCount);\n if (component.length !== 0)\n components.push(component);\n } while (seed !== undefined);\n if (!graph.allHalfEdges[i].isMaskSet(visitMask))\n --i; // reprocess this node\n }\n return components;\n }\n /**\n * Test if test point (xTest,yTest) is inside/outside a face or on an edge.\n * @param seedNode any node on the face loop.\n * @param xTest x coordinate of the test point.\n * @param yTest y coordinate of the test point.\n * @returns 0 if ON, 1 if IN, -1 if OUT.\n */\n public static pointInOrOnFaceXY(seedNode: HalfEdge, xTest: number, yTest: number): number | undefined {\n const context = new XYParitySearchContext(xTest, yTest);\n // walk around looking for an accepted node to start the search (seedNode is usually ok)\n let nodeA = seedNode;\n let nodeB = seedNode.faceSuccessor;\n for (; ; nodeA = nodeB) {\n if (context.tryStartEdge(nodeA.x, nodeA.y, nodeB.x, nodeB.y))\n break;\n if (nodeB === seedNode) {\n // the test point and the face are all on line \"y = yTest\"\n const range = Range1d.createXX(nodeB.x, nodeB.faceSuccessor.x);\n return range.containsX(xTest) ? 0 : -1;\n }\n nodeB = nodeA.faceSuccessor;\n }\n // nodeB is the real start node for search, so stop when we revisit it. For each edge, accumulate parity and hits\n let nodeC = nodeB.faceSuccessor;\n for (; ;) {\n if (!context.advance(nodeC.x, nodeC.y)) {\n return context.classifyCounts();\n }\n if (nodeC === nodeB)\n break;\n nodeC = nodeC.faceSuccessor;\n }\n return context.classifyCounts();\n }\n /**\n * Collect boundary edges starting from `seed`.\n * * If `seed` is not a boundary node or is already visited, the function exists early.\n * @param seed start node.\n * @param visitMask mask to set on processed nodes.\n * @param isBoundaryEdge function to test if an edge in a boundary edge.\n * @param announceEdgeInBoundary callback invoked on each edge in the boundary loop in order. The counter is zero\n * for the first edge, and incremented with each successive edge.\n */\n public static collectExtendedBoundaryLoopFromSeed(\n seed: HalfEdge,\n visitMask: HalfEdgeMask,\n isBoundaryEdge: HalfEdgeToBooleanFunction,\n announceEdgeInBoundary: (edge: HalfEdge, counter: number) => void,\n ): void {\n let counter = 0;\n while (!seed.getMask(visitMask) && isBoundaryEdge(seed)) {\n announceEdgeInBoundary(seed, counter++);\n seed.setMask(visitMask);\n const vertexBase = seed.faceSuccessor;\n let candidateAroundVertex = vertexBase;\n for (; ;) {\n if (candidateAroundVertex.getMask(visitMask)) // end of boundary loop\n return;\n if (isBoundaryEdge(candidateAroundVertex)) {\n seed = candidateAroundVertex;\n break;\n }\n candidateAroundVertex = candidateAroundVertex.vertexPredecessor;\n if (candidateAroundVertex === vertexBase)\n break; // prevent infinite loop in case exteriorMask is not set on the edge mate of the boundary edge\n }\n }\n }\n /**\n * Collect boundary edges in the graph.\n * * A boundary edge is defined by `exteriorMask` being set on only its \"exterior\" edge mate.\n * * Each boundary edge is identified in the output by its edge mate that lacks `exteriorMask`.\n * * Each inner array is ordered in the output so that its boundary edges form a connected path. If `exteriorMask`\n * is preset consistently around each \"exterior\" face, these paths are loops.\n * @param graph the graph to query\n * @param exteriorMask mask preset on exactly one side of boundary edges\n * @returns array of boundary loops, each loop an array of the unmasked mates of boundary edges\n */\n public static collectExtendedBoundaryLoopsInGraph(graph: HalfEdgeGraph, exteriorMask: HalfEdgeMask): HalfEdge[][] {\n // Illustration of the algorithm can be found at geometry/internaldocs/Graph.md\n const loops: HalfEdge[][] = [];\n const visitMask = graph.grabMask(true);\n const isBoundaryEdge = (edge: HalfEdge): boolean => {\n return edge.getMask(exteriorMask) === 0 && edge.edgeMate.getMask(exteriorMask) !== 0;\n };\n const announceEdgeInBoundary = (edge: HalfEdge, counter: number) => {\n if (counter === 0)\n loops.push([]);\n loops[loops.length - 1].push(edge);\n };\n for (const seed of graph.allHalfEdges) {\n this.collectExtendedBoundaryLoopFromSeed(seed, visitMask, isBoundaryEdge, announceEdgeInBoundary);\n }\n graph.dropMask(visitMask);\n return loops;\n }\n}\n"]}
1
+ {"version":3,"file":"HalfEdgeGraphSearch.js","sourceRoot":"","sources":["../../../src/topology/HalfEdgeGraphSearch.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n\n/** @packageDocumentation\n * @module Topology\n */\nimport { Range1d } from \"../geometry3d/Range\";\nimport { HalfEdge, HalfEdgeGraph, HalfEdgeMask, HalfEdgeToBooleanFunction, NodeToNumberFunction } from \"./Graph\";\nimport { SignedDataSummary } from \"./SignedDataSummary\";\nimport { XYParitySearchContext } from \"./XYParitySearchContext\";\n\n/**\n * Interface for an object that executes boolean tests on edges.\n * @internal\n */\nexport interface HalfEdgeTestObject {\n testEdge(h: HalfEdge): boolean;\n}\n/**\n * Class to test match of half edge mask.\n * @internal\n */\nexport class HalfEdgeMaskTester {\n private _targetMask: HalfEdgeMask;\n private _targetValue: boolean;\n /**\n * Constructor\n * @param mask mask to test in `testEdge` function\n * @param targetValue value to match for true return\n */\n public constructor(mask: HalfEdgeMask, targetValue: boolean = true) {\n this._targetMask = mask;\n this._targetValue = targetValue;\n }\n /** Return true if the value of the targetMask matches the targetValue. */\n public testEdge(edge: HalfEdge): boolean {\n return edge.isMaskSet(this._targetMask) === this._targetValue;\n }\n}\n/**\n * Class for different types of searches for HalfEdgeGraph.\n * @internal\n */\nexport class HalfEdgeGraphSearch {\n /**\n * Static method for face area computation -- useful as function parameter in `collectFaceAreaSummary`.\n * * This simply calls `node.signedFaceArea()`\n * @param node instance for signedFaceArea call.\n */\n public static signedFaceArea(node: HalfEdge): number {\n return node.signedFaceArea();\n }\n /**\n * Return a summary of face data (e.g., area) as computed by the callback on the faces of the graph.\n * * Callers with curved edge graphs must supply their own area function.\n * @param source graph or array of nodes to examine.\n * @param collectAllNodes flag to pass to the `SignedDataSummary` constructor to control collection of nodes.\n * @param areaFunction function to obtain area (or other numeric value). Default computes polygonal face area.\n */\n public static collectFaceAreaSummary(\n source: HalfEdgeGraph | HalfEdge[],\n collectAllNodes: boolean = false,\n areaFunction: NodeToNumberFunction = (node) => HalfEdgeGraphSearch.signedFaceArea(node),\n ): SignedDataSummary<HalfEdge> {\n const result = new SignedDataSummary<HalfEdge>(collectAllNodes);\n let allFaces: HalfEdge[];\n if (source instanceof HalfEdgeGraph)\n allFaces = source.collectFaceLoops();\n else\n allFaces = source;\n for (const node of allFaces) {\n const area = areaFunction(node);\n result.announceItem(node, area);\n }\n return result;\n }\n /**\n * Search the graph for the face with the most negative area.\n * * If the graph has exactly one connected component, this is its outer face.\n * @param oneCandidateNodePerFace graph or an array containing one node from each face to be considered.\n * @returns node on the negative area face with largest absolute area, or `undefined` if no negative area face.\n */\n public static findMinimumAreaFace(\n oneCandidateNodePerFace: HalfEdgeGraph | HalfEdge[], faceAreaFunction?: NodeToNumberFunction,\n ): HalfEdge | undefined {\n const summary = HalfEdgeGraphSearch.collectFaceAreaSummary(oneCandidateNodePerFace, false, faceAreaFunction);\n return summary.largestNegativeItem;\n }\n /**\n * Test if the graph is triangulated.\n * * Return `false` if:\n * * number of positive area faces with more than 3 edges is larger than `numPositiveExceptionsAllowed`.\n * * graph has more than 1 negative area face when `allowMultipleNegativeAreaFaces` is `false`.\n * * 2-edge faces are ignored.\n */\n public static isTriangulatedCCW(\n source: HalfEdgeGraph | HalfEdge[],\n allowMultipleNegativeAreaFaces: boolean = true,\n numPositiveExceptionsAllowed: number = 0,\n ): boolean {\n let allFaces: HalfEdge[];\n if (source instanceof HalfEdgeGraph)\n allFaces = source.collectFaceLoops();\n else\n allFaces = source;\n let numNegative = 0;\n let numPositiveExceptions = 0;\n for (const node of allFaces) {\n const numEdges = node.countEdgesAroundFace();\n if (numEdges >= 3) {\n const area = node.signedFaceArea();\n if (area > 0) {\n if (numEdges > 3) {\n numPositiveExceptions++;\n if (numPositiveExceptions > numPositiveExceptionsAllowed)\n return false;\n }\n } else {\n numNegative++;\n if (numNegative > 1) {\n if (!allowMultipleNegativeAreaFaces)\n return false;\n }\n }\n }\n }\n return true;\n }\n /**\n * Process a face during graph traversal.\n * @param faceSeed a node in the face.\n * @param mask mask to set on each node of the face.\n * @param allNodeStack array appended with each node of the face.\n * @param onePerFaceStack array appended with `faceSeed`.\n */\n private static pushAndMaskAllNodesInFace(\n faceSeed: HalfEdge, mask: number, allNodeStack: HalfEdge[], onePerFaceStack: HalfEdge[],\n ): void {\n onePerFaceStack.push(faceSeed);\n faceSeed.collectAroundFace((node: HalfEdge) => {\n node.setMask(mask);\n allNodeStack.push(node);\n });\n }\n /**\n * Traverse (via Depth First Search) to all accessible faces from the given seed.\n * @param faceSeed first node to start the traverse.\n * @param visitMask mask applied to all faces as visited.\n * @param parityEdgeTester function to test if an edge is adjacent to two faces of opposite parity, e.g., a boundary\n * edge that separates an \"interior\" face and an \"exterior\" face. If `parityEdgeTester` is not supplied and `parityMask`\n * is supplied, the default parity rule is to alternate parity state in a \"bullseye\" pattern starting at the seed face,\n * with each successive concentric ring of faces at constant topological distance from the seed face receiving the\n * opposite parity state of the previous ring.\n * @param parityMask mask to apply to the first face and faces that share the same parity as the first face, as\n * determined by the parity rule. If this is `NULL_MASK`, there is no record of parity. If (non-null) parity mask\n * is given, on return it is entirely set or entirely clear around each face.\n * @returns an array that contains one representative node in each face of the connected component.\n */\n private static parityFloodFromSeed(\n faceSeed: HalfEdge,\n visitMask: HalfEdgeMask,\n parityEdgeTester: HalfEdgeTestObject | undefined,\n parityMask: HalfEdgeMask,\n ): HalfEdge[] {\n const faces: HalfEdge[] = [];\n if (faceSeed.isMaskSet(visitMask))\n return faces; // empty array\n const allMasks = parityMask | visitMask;\n const stack: HalfEdge[] = [];\n // the seed face is arbitrarily assigned the parity mask\n HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(faceSeed, allMasks, stack, faces);\n while (stack.length > 0) {\n const p = stack.pop()!;\n const mate = p.edgeMate;\n if (!mate)\n continue;\n if (!mate.isMaskSet(visitMask)) {\n let newState = p.isMaskSet(parityMask);\n if (!parityEdgeTester || parityEdgeTester.testEdge(p))\n newState = !newState;\n HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(mate, newState ? allMasks : visitMask, stack, faces);\n }\n }\n return faces;\n }\n /**\n * * Correct the parity mask in the faces of a component.\n * * It is assumed that the parity mask is applied _consistently_ throughout the supplied faces, but maybe\n * not _correctly_.\n * * A consistently applied parity mask is \"correct\" if it is set on the negative area (\"exterior\") face of\n * a connected component.\n * * This method finds a face with negative area and toggles the mask throughout the input faces if this face\n * lacks the parity mask.\n * * In a properly merged planar subdivision there should be only one true negative area face per component.\n */\n private static correctParityInSingleComponent(parityMask: HalfEdgeMask, faces: HalfEdge[]): void {\n const exteriorHalfEdge = HalfEdgeGraphSearch.findMinimumAreaFace(faces);\n if (!exteriorHalfEdge) {\n // graph has all degenerate faces; do nothing\n } else if (exteriorHalfEdge.isMaskSet(parityMask)) {\n // all should be well; nothing to do\n } else {\n for (const faceSeed of faces) {\n if (faceSeed.isMaskSet(parityMask)) {\n faceSeed.clearMaskAroundFace(parityMask);\n } else {\n faceSeed.setMaskAroundFace(parityMask);\n }\n }\n }\n }\n /** Apply `correctParityInSingleComponent` to each array in components (quick exit if `parityMask` is `NULL_MASK`). */\n private static correctParityInComponentArrays(parityMask: HalfEdgeMask, components: HalfEdge[][]): void {\n if (parityMask === HalfEdgeMask.NULL_MASK)\n return;\n for (const facesInComponent of components)\n HalfEdgeGraphSearch.correctParityInSingleComponent(parityMask, facesInComponent);\n }\n /**\n * Collect connected components of the graph (via Depth First Search).\n * @param graph graph to inspect.\n * @param parityEdgeTester (optional) function to test if an edge is adjacent to two faces of opposite parity,\n * e.g., a boundary edge that separates an \"interior\" face and an \"exterior\" face. If `parityEdgeTester` is not\n * supplied and `parityMask` is supplied, the default parity rule is to alternate parity state in a \"bullseye\"\n * pattern starting at the seed face, with each successive concentric ring of faces at constant topological\n * distance from the seed face receiving the opposite parity state of the previous ring.\n * @param parityMask (optional) mask to apply to the first face and faces that share the same parity as the\n * first face, as determined by the parity rule. If this is `NULL_MASK` (default), there is no record of parity.\n * If (non-null) parity mask is given, on return it is entirely set or entirely clear around each face.\n * @returns the components of the graph, each component represented by an array of nodes, one node per face\n * of the component. In other words, entry [i][j] is a HalfEdge in the j_th face loop of the i_th component.\n */\n public static collectConnectedComponentsWithExteriorParityMasks(\n graph: HalfEdgeGraph,\n parityEdgeTester: HalfEdgeTestObject | undefined,\n parityMask: HalfEdgeMask = HalfEdgeMask.NULL_MASK,\n ): HalfEdge[][] {\n // Illustration of the algorithm can be found at geometry/internaldocs/Graph.md\n const components = [];\n const visitMask = HalfEdgeMask.VISITED;\n const allMasks = parityMask | visitMask;\n graph.clearMask(allMasks);\n for (const faceSeed of graph.allHalfEdges) {\n if (!faceSeed.isMaskSet(visitMask)) {\n const newFaces = HalfEdgeGraphSearch.parityFloodFromSeed(faceSeed, visitMask, parityEdgeTester, parityMask);\n // parityFloodFromSeed does not return an empty array because it is called on an unvisited faceSeed\n components.push(newFaces);\n }\n }\n HalfEdgeGraphSearch.correctParityInComponentArrays(parityMask, components);\n return components;\n }\n /**\n * Breadth-first search through the connected component defined by `seed` and `ignoreMask`.\n * @param seed a HalfEdge in the component from which to start the search.\n * @param visitMask a mask to apply to visited nodes. Assumed cleared throughout component before first call.\n * @param ignoreMask (optional) mask preset on faces that are to be treated as _outside_ the component.\n * Default value is `HalfEdgeMask.EXTERIOR` to ignore exterior faces.\n * Pass `HalfEdgeMask.NULL_MASK` to process all faces of the component.\n * Note that if `ignoreMask` is set on both sides of an edge, both adjacent faces will be ignored; thus it\n * is generally more useful if set on only one side of an edge.\n * @param maxFaceCount (optional) maximum number of faces to search in the component. If nonpositive or\n * `undefined`, `Infinity` is used.\n * @param result optional array to append with HalfEdges and return as the `faces` array. This array is not\n * emptied first, so callers can send it into a subsequent call to continue searching the component at `nextSeed`.\n * @returns `faces` consists of one edge per face of the component; `nextSeed` is the seed at which to start\n * the next call if `maxFaceCount` is exceeded (otherwise it is `undefined`).\n */\n public static exploreComponent(\n seed: HalfEdge,\n visitMask: HalfEdgeMask,\n ignoreMask: HalfEdgeMask = HalfEdgeMask.EXTERIOR,\n maxFaceCount: number = Infinity,\n result?: HalfEdge[],\n ): { faces: HalfEdge[], nextSeed: HalfEdge | undefined} {\n if (maxFaceCount <= 0)\n maxFaceCount = Infinity;\n const boundaryMask: HalfEdgeMask = visitMask | ignoreMask;\n let numFaces = 0;\n const candidates: HalfEdge[] = []; // the queue\n const faces: HalfEdge[] = result ? result : [];\n candidates.push(seed);\n while (candidates.length > 0 && numFaces < maxFaceCount) {\n // TODO: shift is O(n) thus inefficient for large queues. If needed, we can\n // replace the queue by a circular array or use 2 stacks; both are O(1).\n const node = candidates.shift();\n if (node && !node.isMaskSet(boundaryMask)) {\n faces.push(node);\n ++numFaces;\n node.collectAroundFace((he: HalfEdge) => {\n he.setMask(visitMask);\n const neighbor = he.vertexSuccessor;\n if (!neighbor.isMaskSet(boundaryMask))\n candidates.push(neighbor); // enqueue neighboring face\n });\n }\n }\n if (candidates.length === 0)\n return { faces, nextSeed: undefined };\n\n // try to find a node at the boundary of the current component and the next\n let nextSeed = candidates[0];\n for (const candidate of candidates) {\n if (candidate.vertexSuccessor.isMaskSet(ignoreMask) || candidate.edgeMate.isMaskSet(ignoreMask)) {\n nextSeed = candidate;\n break;\n }\n }\n return { faces, nextSeed };\n }\n /**\n * Collect connected components of the graph (via Breadth First Search).\n * @param graph graph to inspect.\n * @param maxFaceCount (optional) maximum number of faces in each component. Should be positive; otherwise\n * `Infinity` is used.\n * @param ignoreMask (optional) mask preset on faces to ignore. Default value is `HalfEdgeMask.EXTERIOR` to ignore\n * exterior faces. Pass `HalfEdgeMask.NULL_MASK` to process all faces.\n * @returns the components of the graph, each component represented by an array of nodes, one node per face\n * of the component. In other words, entry [i][j] is a HalfEdge in the j_th face loop of the i_th component.\n */\n public static collectConnectedComponents(\n graph: HalfEdgeGraph,\n maxFaceCount: number = Infinity,\n ignoreMask: HalfEdgeMask = HalfEdgeMask.EXTERIOR,\n ): HalfEdge[][] {\n const components: HalfEdge[][] = [];\n if (graph.countMask(ignoreMask) === 0)\n ignoreMask = HalfEdgeMask.NULL_MASK;\n const visitMask = HalfEdgeMask.VISITED;\n graph.clearMask(visitMask);\n const boundaryMask: HalfEdgeMask = visitMask | ignoreMask;\n // Starting with the input node, look ahead for a boundary face. Failing that, return the input node.\n // Starting all floods at the boundary reduces the chance of ending up with a ring-shaped component at the boundary.\n const findNextFloodSeed = (index: number) => {\n for (let i = index; i < graph.countNodes(); ++i) {\n if (!graph.allHalfEdges[i].isMaskSet(boundaryMask)\n && graph.allHalfEdges[i].edgeMate.isMaskSet(boundaryMask)) {\n index = i;\n break;\n }\n }\n return index;\n };\n for (let i = 0; i < graph.countNodes(); ++i) {\n if (graph.allHalfEdges[i].isMaskSet(boundaryMask))\n continue;\n const i0 = findNextFloodSeed(i);\n let seed: HalfEdge | undefined = graph.allHalfEdges[i0];\n do { // flood this component\n const result = HalfEdgeGraphSearch.exploreComponent(seed, visitMask, ignoreMask, maxFaceCount);\n seed = result.nextSeed;\n if (result.faces.length > 0)\n components.push(result.faces); // each sub-component of length <= maxFaceCount is treated as a component\n } while (seed !== undefined);\n if (!graph.allHalfEdges[i].isMaskSet(visitMask))\n --i; // reprocess this node\n }\n return components;\n }\n /**\n * Test if test point (xTest,yTest) is inside/outside a face or on an edge.\n * * NOTE: a point outside the graph (in the exterior face) returns -1.\n * @param seedNode any node on the face loop.\n * @param xTest x coordinate of the test point.\n * @param yTest y coordinate of the test point.\n * @returns 0 if ON, 1 if IN, -1 if OUT.\n */\n public static pointInOrOnFaceXY(seedNode: HalfEdge, xTest: number, yTest: number): number {\n const context = new XYParitySearchContext(xTest, yTest);\n // walk around looking for an accepted node to start the search (seedNode is usually ok)\n let nodeA = seedNode;\n let nodeB = seedNode.faceSuccessor;\n for (; ; nodeA = nodeB) {\n if (context.tryStartEdge(nodeA.x, nodeA.y, nodeB.x, nodeB.y))\n break;\n if (nodeB === seedNode) {\n // the test point and the face are all on line \"y = yTest\"\n const range = Range1d.createXX(nodeB.x, nodeB.faceSuccessor.x);\n return range.containsX(xTest) ? 0 : -1;\n }\n nodeB = nodeA.faceSuccessor;\n }\n // nodeB is the real start node for search, so stop when we revisit it. For each edge, accumulate parity and hits\n let nodeC = nodeB.faceSuccessor;\n for (; ;) {\n if (!context.advance(nodeC.x, nodeC.y)) {\n return context.classifyCounts();\n }\n if (nodeC === nodeB)\n break;\n nodeC = nodeC.faceSuccessor;\n }\n return context.classifyCounts();\n }\n /**\n * Collect boundary edges starting from `seed`.\n * * If `seed` is not a boundary node or is already visited, the function exists early.\n * @param seed start node.\n * @param visitMask mask to set on processed nodes.\n * @param isBoundaryEdge function to test if an edge in a boundary edge.\n * @param announceEdgeInBoundary callback invoked on each edge in the boundary loop in order. The counter is zero\n * for the first edge, and incremented with each successive edge.\n */\n public static collectExtendedBoundaryLoopFromSeed(\n seed: HalfEdge,\n visitMask: HalfEdgeMask,\n isBoundaryEdge: HalfEdgeToBooleanFunction,\n announceEdgeInBoundary: (edge: HalfEdge, counter: number) => void,\n ): void {\n let counter = 0;\n while (!seed.getMask(visitMask) && isBoundaryEdge(seed)) {\n announceEdgeInBoundary(seed, counter++);\n seed.setMask(visitMask);\n const vertexBase = seed.faceSuccessor;\n let candidateAroundVertex = vertexBase;\n for (; ;) {\n if (candidateAroundVertex.getMask(visitMask)) // end of boundary loop\n return;\n if (isBoundaryEdge(candidateAroundVertex)) {\n seed = candidateAroundVertex;\n break;\n }\n candidateAroundVertex = candidateAroundVertex.vertexPredecessor;\n if (candidateAroundVertex === vertexBase)\n break; // prevent infinite loop in case exteriorMask is not set on the edge mate of the boundary edge\n }\n }\n }\n /**\n * Collect boundary edges in the graph.\n * * A boundary edge is defined by `exteriorMask` being set on only its \"exterior\" edge mate.\n * * Each boundary edge is identified in the output by its edge mate that lacks `exteriorMask`.\n * * Each inner array is ordered in the output so that its boundary edges form a connected path. If `exteriorMask`\n * is preset consistently around each \"exterior\" face, these paths are loops.\n * @param graph the graph to query\n * @param exteriorMask mask preset on exactly one side of boundary edges\n * @returns array of boundary loops, each loop an array of the unmasked mates of boundary edges\n */\n public static collectExtendedBoundaryLoopsInGraph(graph: HalfEdgeGraph, exteriorMask: HalfEdgeMask): HalfEdge[][] {\n // Illustration of the algorithm can be found at geometry/internaldocs/Graph.md\n const loops: HalfEdge[][] = [];\n const visitMask = graph.grabMask(true);\n const isBoundaryEdge = (edge: HalfEdge): boolean => {\n return edge.getMask(exteriorMask) === 0 && edge.edgeMate.getMask(exteriorMask) !== 0;\n };\n const announceEdgeInBoundary = (edge: HalfEdge, counter: number) => {\n if (counter === 0)\n loops.push([]);\n loops[loops.length - 1].push(edge);\n };\n for (const seed of graph.allHalfEdges) {\n this.collectExtendedBoundaryLoopFromSeed(seed, visitMask, isBoundaryEdge, announceEdgeInBoundary);\n }\n graph.dropMask(visitMask);\n return loops;\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { LineSegment3d } from "../curve/LineSegment3d";
2
2
  import { MultiLineStringDataVariant } from "../geometry3d/IndexedXYZCollection";
3
- import { Range3d } from "../geometry3d/Range";
3
+ import { Range2d, Range3d } from "../geometry3d/Range";
4
4
  import { ClusterableArray } from "../numerics/ClusterableArray";
5
5
  import { HalfEdge, HalfEdgeGraph, HalfEdgeMask } from "./Graph";
6
6
  export declare class GraphSplitData {
@@ -39,7 +39,10 @@ export declare class HalfEdgeGraphOps {
39
39
  * @param targetB target vertex of second vector
40
40
  */
41
41
  static crossProductToTargets(base: HalfEdge, targetA: HalfEdge, targetB: HalfEdge): number;
42
- static graphRange(graph: HalfEdgeGraph): Range3d;
42
+ /** Compute the range of the graph's vertices. */
43
+ static graphRange(graph: Readonly<HalfEdgeGraph>): Range3d;
44
+ /** Compute the xy-range of the graph's vertices. */
45
+ static graphRangeXY(graph: Readonly<HalfEdgeGraph>): Range2d;
43
46
  /** Returns an array of all nodes (both ends) of edges created from segments. */
44
47
  static segmentArrayToGraphEdges(segments: LineSegment3d[], returnGraph: HalfEdgeGraph, mask: HalfEdgeMask): HalfEdge[];
45
48
  /**
@@ -122,7 +125,7 @@ export declare class HalfEdgeGraphMerge {
122
125
  * * If there are edge crossings, the graph can be a (highly complicated) Klein bottle topology.
123
126
  * * Mask.NULL_FACE is cleared throughout and applied within null faces.
124
127
  */
125
- static clusterAndMergeXYTheta(graph: HalfEdgeGraph, outboundRadiansFunction?: (he: HalfEdge) => number): void;
128
+ static clusterAndMergeXYTheta(graph: HalfEdgeGraph, outboundRadiansFunction?: (he: HalfEdge) => number, clusterTol?: number): void;
126
129
  private static buildVerticalSweepPriorityQueue;
127
130
  private static computeIntersectionFractionsOnEdges;
128
131
  /**
@@ -130,7 +133,7 @@ export declare class HalfEdgeGraphMerge {
130
133
  * * This is a large operation.
131
134
  * @param graph
132
135
  */
133
- static splitIntersectingEdges(graph: HalfEdgeGraph): GraphSplitData;
136
+ static splitIntersectingEdges(graph: HalfEdgeGraph, distanceTol?: number, fractionTol?: number): GraphSplitData;
134
137
  /**
135
138
  * Returns a graph structure formed from the given LineSegment array
136
139
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Merging.d.ts","sourceRoot":"","sources":["../../../src/topology/Merging.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Merging.d.ts","sourceRoot":"","sources":["../../../src/topology/Merging.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import { assert } from "@itwin/core-bentley";
9
9
  import { LineSegment3d } from "../curve/LineSegment3d";
10
10
  import { Geometry } from "../Geometry";
11
11
  import { Angle } from "../geometry3d/Angle";
12
- import { Range3d } from "../geometry3d/Range";
12
+ import { Range2d, Range3d } from "../geometry3d/Range";
13
13
  import { ClusterableArray } from "../numerics/ClusterableArray";
14
14
  import { SmallSystem } from "../numerics/SmallSystem";
15
15
  import { HalfEdge, HalfEdgeGraph, HalfEdgeMask } from "./Graph";
@@ -79,8 +79,7 @@ export class HalfEdgeGraphOps {
79
79
  static crossProductToTargets(base, targetA, targetB) {
80
80
  return Geometry.crossProductXYXY(targetA.x - base.x, targetA.y - base.y, targetB.x - base.x, targetB.y - base.y);
81
81
  }
82
- // ---------------------------------------------------------------------------------------------------------------------
83
- // ----------------------------------------------------------------------------------------------------------------------
82
+ /** Compute the range of the graph's vertices. */
84
83
  static graphRange(graph) {
85
84
  const range = Range3d.create();
86
85
  for (const node of graph.allHalfEdges) {
@@ -88,6 +87,14 @@ export class HalfEdgeGraphOps {
88
87
  }
89
88
  return range;
90
89
  }
90
+ /** Compute the xy-range of the graph's vertices. */
91
+ static graphRangeXY(graph) {
92
+ const range = Range2d.createNull();
93
+ for (const node of graph.allHalfEdges) {
94
+ range.extendXY(node.x, node.y);
95
+ }
96
+ return range;
97
+ }
91
98
  /** Returns an array of all nodes (both ends) of edges created from segments. */
92
99
  static segmentArrayToGraphEdges(segments, returnGraph, mask) {
93
100
  const result = [];
@@ -326,7 +333,7 @@ export class HalfEdgeGraphMerge {
326
333
  * * If there are edge crossings, the graph can be a (highly complicated) Klein bottle topology.
327
334
  * * Mask.NULL_FACE is cleared throughout and applied within null faces.
328
335
  */
329
- static clusterAndMergeXYTheta(graph, outboundRadiansFunction) {
336
+ static clusterAndMergeXYTheta(graph, outboundRadiansFunction, clusterTol = Geometry.smallMetricDistance) {
330
337
  const allNodes = graph.allHalfEdges;
331
338
  const numNodes = allNodes.length;
332
339
  graph.clearMask(HalfEdgeMask.NULL_FACE);
@@ -338,7 +345,6 @@ export class HalfEdgeGraphMerge {
338
345
  HalfEdge.pinch(nodeA, nodeA.vertexSuccessor); // pull it out of its current vertex loop.
339
346
  clusters.addDirect(xA, yA, 0.0, i);
340
347
  }
341
- const clusterTol = Geometry.smallMetricDistance;
342
348
  const order = clusters.clusterIndicesLexical(clusterTol);
343
349
  let k0 = 0;
344
350
  const numK = order.length;
@@ -499,32 +505,31 @@ export class HalfEdgeGraphMerge {
499
505
  * * This is a large operation.
500
506
  * @param graph
501
507
  */
502
- static splitIntersectingEdges(graph) {
508
+ static splitIntersectingEdges(graph, distanceTol = Geometry.smallMetricDistance, fractionTol = 1.0e-8) {
503
509
  const data = new GraphSplitData();
504
510
  const sweepHeap = this.buildVerticalSweepPriorityQueue(graph);
505
511
  let nodeA0, nodeB1;
506
- const smallFraction = 1.0e-8;
512
+ const smallFraction = fractionTol;
507
513
  const largeFraction = 1.0 - smallFraction;
508
514
  let i;
509
515
  let nodeB0;
510
- const distTol = Geometry.smallMetricDistance;
511
516
  while (undefined !== (nodeA0 = sweepHeap.priorityQueue.pop())) {
512
517
  data.numUpEdge++;
513
518
  const n0 = sweepHeap.activeEdges.length;
514
- sweepHeap.removeArrayMembersWithY1Below(nodeA0.y - distTol);
519
+ sweepHeap.removeArrayMembersWithY1Below(nodeA0.y - distanceTol);
515
520
  data.numPopOut += n0 - sweepHeap.activeEdges.length;
516
521
  for (i = 0; i < sweepHeap.activeEdges.length; i++) {
517
522
  nodeB0 = sweepHeap.activeEdges[i];
518
523
  nodeB1 = nodeB0.faceSuccessor;
519
- if (Geometry.isSameCoordinateXY(nodeA0.x, nodeA0.y, nodeB0.x, nodeB0.y, distTol)) {
524
+ if (Geometry.isSameCoordinateXY(nodeA0.x, nodeA0.y, nodeB0.x, nodeB0.y, distanceTol)) {
520
525
  data.numA0B0++;
521
526
  }
522
- else if (Geometry.isSameCoordinateXY(nodeB1.x, nodeB1.y, nodeA0.x, nodeA0.y, distTol)) {
527
+ else if (Geometry.isSameCoordinateXY(nodeB1.x, nodeB1.y, nodeA0.x, nodeA0.y, distanceTol)) {
523
528
  data.numA0B1++;
524
529
  }
525
530
  else {
526
531
  data.numIntersectionTest++;
527
- const fractions = this.computeIntersectionFractionsOnEdges(nodeA0, nodeB0, distTol);
532
+ const fractions = this.computeIntersectionFractionsOnEdges(nodeA0, nodeB0, distanceTol);
528
533
  if (fractions) {
529
534
  const splitAndPush = (node, fraction) => {
530
535
  if (fraction !== undefined && fraction > smallFraction && fraction < largeFraction) {