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