@itwin/core-geometry 5.9.0-dev.7 → 5.9.0-dev.9
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/Geometry.d.ts +8 -6
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +8 -6
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/curve/Arc3d.d.ts +7 -0
- package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
- package/lib/cjs/curve/Arc3d.js +11 -0
- package/lib/cjs/curve/Arc3d.js.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts +11 -2
- package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js +25 -15
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/cjs/curve/CurveCollection.d.ts +15 -6
- package/lib/cjs/curve/CurveCollection.d.ts.map +1 -1
- package/lib/cjs/curve/CurveCollection.js +15 -6
- package/lib/cjs/curve/CurveCollection.js.map +1 -1
- package/lib/cjs/curve/CurveCurve.d.ts +1 -1
- package/lib/cjs/curve/CurveCurve.d.ts.map +1 -1
- package/lib/cjs/curve/CurveCurve.js +2 -1
- package/lib/cjs/curve/CurveCurve.js.map +1 -1
- package/lib/cjs/curve/CurveLocationDetail.d.ts +21 -0
- package/lib/cjs/curve/CurveLocationDetail.d.ts.map +1 -1
- package/lib/cjs/curve/CurveLocationDetail.js +59 -0
- package/lib/cjs/curve/CurveLocationDetail.js.map +1 -1
- package/lib/cjs/curve/CurvePrimitive.d.ts +13 -12
- package/lib/cjs/curve/CurvePrimitive.d.ts.map +1 -1
- package/lib/cjs/curve/CurvePrimitive.js +12 -11
- package/lib/cjs/curve/CurvePrimitive.js.map +1 -1
- package/lib/cjs/curve/RegionOps.d.ts +17 -4
- package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
- package/lib/cjs/curve/RegionOps.js +114 -18
- package/lib/cjs/curve/RegionOps.js.map +1 -1
- package/lib/cjs/curve/RegionOpsClassificationSweeps.d.ts +3 -11
- package/lib/cjs/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
- package/lib/cjs/curve/RegionOpsClassificationSweeps.js +1 -91
- package/lib/cjs/curve/RegionOpsClassificationSweeps.js.map +1 -1
- package/lib/cjs/curve/StrokeOptions.d.ts +13 -6
- package/lib/cjs/curve/StrokeOptions.d.ts.map +1 -1
- package/lib/cjs/curve/StrokeOptions.js +13 -6
- package/lib/cjs/curve/StrokeOptions.js.map +1 -1
- package/lib/cjs/curve/internalContexts/AnnounceTangentStrokeHandler.d.ts +1 -1
- package/lib/cjs/curve/internalContexts/AnnounceTangentStrokeHandler.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/AnnounceTangentStrokeHandler.js +1 -2
- package/lib/cjs/curve/internalContexts/AnnounceTangentStrokeHandler.js.map +1 -1
- package/lib/cjs/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.d.ts +1 -1
- package/lib/cjs/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.js +1 -2
- package/lib/cjs/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.js.map +1 -1
- package/lib/cjs/curve/internalContexts/ClosestPointStrokeHandler.d.ts +1 -1
- package/lib/cjs/curve/internalContexts/ClosestPointStrokeHandler.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/ClosestPointStrokeHandler.js +1 -2
- package/lib/cjs/curve/internalContexts/ClosestPointStrokeHandler.js.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.d.ts +113 -103
- package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.js +368 -337
- package/lib/cjs/curve/internalContexts/CurveCurveCloseApproachXY.js.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts +2 -3
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js +20 -32
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
- package/lib/cjs/curve/spiral/DirectSpiral3d.d.ts +1 -2
- package/lib/cjs/curve/spiral/DirectSpiral3d.d.ts.map +1 -1
- package/lib/cjs/curve/spiral/DirectSpiral3d.js +9 -3
- package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.d.ts +1 -2
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.d.ts.map +1 -1
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.js +10 -4
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.js.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.d.ts +3 -1
- package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.js +6 -2
- package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
- package/lib/cjs/geometry3d/GeometryHandler.d.ts +33 -4
- package/lib/cjs/geometry3d/GeometryHandler.d.ts.map +1 -1
- package/lib/cjs/geometry3d/GeometryHandler.js +79 -1
- package/lib/cjs/geometry3d/GeometryHandler.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts +9 -6
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.js +20 -10
- package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.d.ts +9 -6
- package/lib/cjs/geometry3d/GrowableXYZArray.d.ts.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.js +20 -10
- package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.d.ts +4 -4
- package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.js +5 -4
- package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
- package/lib/cjs/numerics/BezierPolynomials.d.ts.map +1 -1
- package/lib/cjs/numerics/BezierPolynomials.js +1 -1
- package/lib/cjs/numerics/BezierPolynomials.js.map +1 -1
- package/lib/cjs/numerics/Newton.d.ts +44 -13
- package/lib/cjs/numerics/Newton.d.ts.map +1 -1
- package/lib/cjs/numerics/Newton.js +73 -23
- package/lib/cjs/numerics/Newton.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts +14 -14
- package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.js +14 -14
- package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/cjs/serialization/BGFBReader.js +2 -2
- package/lib/cjs/serialization/BGFBReader.js.map +1 -1
- package/lib/cjs/topology/Graph.d.ts +15 -15
- package/lib/cjs/topology/Graph.d.ts.map +1 -1
- package/lib/cjs/topology/Graph.js +1 -1
- package/lib/cjs/topology/Graph.js.map +1 -1
- package/lib/cjs/topology/HalfEdgeGraphSearch.d.ts +3 -3
- package/lib/cjs/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
- package/lib/cjs/topology/HalfEdgeGraphSearch.js.map +1 -1
- package/lib/esm/Geometry.d.ts +8 -6
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +8 -6
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/curve/Arc3d.d.ts +7 -0
- package/lib/esm/curve/Arc3d.d.ts.map +1 -1
- package/lib/esm/curve/Arc3d.js +11 -0
- package/lib/esm/curve/Arc3d.js.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts +11 -2
- package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js +25 -15
- package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/esm/curve/CurveCollection.d.ts +15 -6
- package/lib/esm/curve/CurveCollection.d.ts.map +1 -1
- package/lib/esm/curve/CurveCollection.js +15 -6
- package/lib/esm/curve/CurveCollection.js.map +1 -1
- package/lib/esm/curve/CurveCurve.d.ts +1 -1
- package/lib/esm/curve/CurveCurve.d.ts.map +1 -1
- package/lib/esm/curve/CurveCurve.js +2 -1
- package/lib/esm/curve/CurveCurve.js.map +1 -1
- package/lib/esm/curve/CurveLocationDetail.d.ts +21 -0
- package/lib/esm/curve/CurveLocationDetail.d.ts.map +1 -1
- package/lib/esm/curve/CurveLocationDetail.js +59 -0
- package/lib/esm/curve/CurveLocationDetail.js.map +1 -1
- package/lib/esm/curve/CurvePrimitive.d.ts +13 -12
- package/lib/esm/curve/CurvePrimitive.d.ts.map +1 -1
- package/lib/esm/curve/CurvePrimitive.js +12 -11
- package/lib/esm/curve/CurvePrimitive.js.map +1 -1
- package/lib/esm/curve/RegionOps.d.ts +17 -4
- package/lib/esm/curve/RegionOps.d.ts.map +1 -1
- package/lib/esm/curve/RegionOps.js +116 -20
- package/lib/esm/curve/RegionOps.js.map +1 -1
- package/lib/esm/curve/RegionOpsClassificationSweeps.d.ts +3 -11
- package/lib/esm/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
- package/lib/esm/curve/RegionOpsClassificationSweeps.js +2 -92
- package/lib/esm/curve/RegionOpsClassificationSweeps.js.map +1 -1
- package/lib/esm/curve/StrokeOptions.d.ts +13 -6
- package/lib/esm/curve/StrokeOptions.d.ts.map +1 -1
- package/lib/esm/curve/StrokeOptions.js +13 -6
- package/lib/esm/curve/StrokeOptions.js.map +1 -1
- package/lib/esm/curve/internalContexts/AnnounceTangentStrokeHandler.d.ts +1 -1
- package/lib/esm/curve/internalContexts/AnnounceTangentStrokeHandler.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/AnnounceTangentStrokeHandler.js +1 -2
- package/lib/esm/curve/internalContexts/AnnounceTangentStrokeHandler.js.map +1 -1
- package/lib/esm/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.d.ts +1 -1
- package/lib/esm/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.js +1 -2
- package/lib/esm/curve/internalContexts/AppendPlaneIntersectionStrokeHandler.js.map +1 -1
- package/lib/esm/curve/internalContexts/ClosestPointStrokeHandler.d.ts +1 -1
- package/lib/esm/curve/internalContexts/ClosestPointStrokeHandler.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/ClosestPointStrokeHandler.js +1 -2
- package/lib/esm/curve/internalContexts/ClosestPointStrokeHandler.js.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.d.ts +113 -103
- package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.js +370 -339
- package/lib/esm/curve/internalContexts/CurveCurveCloseApproachXY.js.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts +2 -3
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js +20 -32
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
- package/lib/esm/curve/spiral/DirectSpiral3d.d.ts +1 -2
- package/lib/esm/curve/spiral/DirectSpiral3d.d.ts.map +1 -1
- package/lib/esm/curve/spiral/DirectSpiral3d.js +9 -3
- package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/esm/curve/spiral/IntegratedSpiral3d.d.ts +1 -2
- package/lib/esm/curve/spiral/IntegratedSpiral3d.d.ts.map +1 -1
- package/lib/esm/curve/spiral/IntegratedSpiral3d.js +10 -4
- package/lib/esm/curve/spiral/IntegratedSpiral3d.js.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.d.ts +3 -1
- package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.js +6 -2
- package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
- package/lib/esm/geometry3d/GeometryHandler.d.ts +33 -4
- package/lib/esm/geometry3d/GeometryHandler.d.ts.map +1 -1
- package/lib/esm/geometry3d/GeometryHandler.js +77 -0
- package/lib/esm/geometry3d/GeometryHandler.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.d.ts +9 -6
- package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.js +20 -10
- package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.d.ts +9 -6
- package/lib/esm/geometry3d/GrowableXYZArray.d.ts.map +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.js +20 -10
- package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.d.ts +4 -4
- package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.js +5 -4
- package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
- package/lib/esm/numerics/BezierPolynomials.d.ts.map +1 -1
- package/lib/esm/numerics/BezierPolynomials.js +1 -1
- package/lib/esm/numerics/BezierPolynomials.js.map +1 -1
- package/lib/esm/numerics/Newton.d.ts +44 -13
- package/lib/esm/numerics/Newton.d.ts.map +1 -1
- package/lib/esm/numerics/Newton.js +71 -22
- package/lib/esm/numerics/Newton.js.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts +14 -14
- package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.js +14 -14
- package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/esm/serialization/BGFBReader.js +2 -2
- package/lib/esm/serialization/BGFBReader.js.map +1 -1
- package/lib/esm/topology/Graph.d.ts +15 -15
- package/lib/esm/topology/Graph.d.ts.map +1 -1
- package/lib/esm/topology/Graph.js +1 -1
- package/lib/esm/topology/Graph.js.map +1 -1
- package/lib/esm/topology/HalfEdgeGraphSearch.d.ts +3 -3
- package/lib/esm/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
- package/lib/esm/topology/HalfEdgeGraphSearch.js.map +1 -1
- package/package.json +3 -3
- package/lib/cjs/curve/internalContexts/NewtonRtoRStrokeHandler.d.ts +0 -23
- package/lib/cjs/curve/internalContexts/NewtonRtoRStrokeHandler.d.ts.map +0 -1
- package/lib/cjs/curve/internalContexts/NewtonRtoRStrokeHandler.js +0 -37
- package/lib/cjs/curve/internalContexts/NewtonRtoRStrokeHandler.js.map +0 -1
- package/lib/esm/curve/internalContexts/NewtonRtoRStrokeHandler.d.ts +0 -23
- package/lib/esm/curve/internalContexts/NewtonRtoRStrokeHandler.d.ts.map +0 -1
- package/lib/esm/curve/internalContexts/NewtonRtoRStrokeHandler.js +0 -33
- package/lib/esm/curve/internalContexts/NewtonRtoRStrokeHandler.js.map +0 -1
|
@@ -21,9 +21,13 @@ const SmallSystem_1 = require("../../numerics/SmallSystem");
|
|
|
21
21
|
const Arc3d_1 = require("../Arc3d");
|
|
22
22
|
const CurveChainWithDistanceIndex_1 = require("../CurveChainWithDistanceIndex");
|
|
23
23
|
const CurveCollection_1 = require("../CurveCollection");
|
|
24
|
+
const CurveCurve_1 = require("../CurveCurve");
|
|
24
25
|
const CurveLocationDetail_1 = require("../CurveLocationDetail");
|
|
26
|
+
const CurvePrimitive_1 = require("../CurvePrimitive");
|
|
25
27
|
const LineSegment3d_1 = require("../LineSegment3d");
|
|
26
28
|
const LineString3d_1 = require("../LineString3d");
|
|
29
|
+
const ProxyCurve_1 = require("../ProxyCurve");
|
|
30
|
+
const TransitionSpiral3d_1 = require("../spiral/TransitionSpiral3d");
|
|
27
31
|
// cspell:word XYRR currentdFdX
|
|
28
32
|
/**
|
|
29
33
|
* Handler class for XY close approach between _geometryB and another geometry.
|
|
@@ -41,9 +45,6 @@ const LineString3d_1 = require("../LineString3d");
|
|
|
41
45
|
*/
|
|
42
46
|
class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometryHandler {
|
|
43
47
|
_geometryB;
|
|
44
|
-
setGeometryB(geometryB) {
|
|
45
|
-
this._geometryB = geometryB;
|
|
46
|
-
}
|
|
47
48
|
/**
|
|
48
49
|
* Maximum XY distance (z is ignored). Approach larger than this is not interesting.
|
|
49
50
|
* This is caller defined and can be undefined.
|
|
@@ -51,6 +52,8 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
51
52
|
_maxDistanceToAccept;
|
|
52
53
|
/** Squared max distance. Default is [[Geometry.smallMetricDistanceSquared]]. */
|
|
53
54
|
_maxDistanceSquared;
|
|
55
|
+
_xyTolerance;
|
|
56
|
+
_newtonTolerance;
|
|
54
57
|
/**
|
|
55
58
|
* Start and end points of line segments that meet closest approach criteria, i.e., they are perpendicular to
|
|
56
59
|
* both curves and their length is smaller than _maxDistanceToAccept.
|
|
@@ -64,18 +67,28 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
64
67
|
/**
|
|
65
68
|
* Constructor.
|
|
66
69
|
* @param geometryB second curve for intersection. Saved for reference by specific handler methods.
|
|
70
|
+
* @param xyTolerance optional tolerance for comparing xy points (default [[Geometry.smallMetricDistance]]).
|
|
71
|
+
* @param newtonTolerance optional relative fraction tolerance for Newton iteration (default [[Geometry.smallNewtonStep]]).
|
|
67
72
|
*/
|
|
68
|
-
constructor(geometryB) {
|
|
73
|
+
constructor(geometryB, xyTolerance = Geometry_1.Geometry.smallMetricDistance, newtonTolerance = Geometry_1.Geometry.smallNewtonStep) {
|
|
69
74
|
super();
|
|
70
|
-
this.
|
|
75
|
+
this._geometryB = geometryB instanceof ProxyCurve_1.ProxyCurve ? geometryB.proxyCurve : geometryB;
|
|
71
76
|
this._maxDistanceSquared = Geometry_1.Geometry.smallMetricDistanceSquared;
|
|
72
|
-
this.
|
|
77
|
+
this._xyTolerance = xyTolerance;
|
|
78
|
+
this._newtonTolerance = newtonTolerance;
|
|
79
|
+
const compare = CurveLocationDetail_1.CurveLocationDetailPair.comparePairsByPoints(xyTolerance, true);
|
|
80
|
+
this._results = new core_bentley_1.SortedArray(compare, core_bentley_1.DuplicatePolicy.Retain);
|
|
73
81
|
}
|
|
74
82
|
/** Set the (possibly undefined) max XY distance (z is ignored) to accept. */
|
|
75
83
|
set maxDistanceToAccept(value) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this._maxDistanceSquared =
|
|
84
|
+
if (value === undefined) {
|
|
85
|
+
this._maxDistanceToAccept = undefined;
|
|
86
|
+
this._maxDistanceSquared = Geometry_1.Geometry.smallMetricDistanceSquared;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this._maxDistanceToAccept = Math.abs(value);
|
|
90
|
+
this._maxDistanceSquared = value * value;
|
|
91
|
+
}
|
|
79
92
|
}
|
|
80
93
|
/** Access the (possibly undefined) max XY distance (z is ignored) to accept. */
|
|
81
94
|
get maxDistanceToAccept() {
|
|
@@ -85,9 +98,14 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
85
98
|
get isMaxDistanceSet() {
|
|
86
99
|
return this._maxDistanceToAccept !== undefined && this._maxDistanceToAccept > 0;
|
|
87
100
|
}
|
|
88
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Reset the geometry.
|
|
103
|
+
* * Undefined inputs are ignored.
|
|
104
|
+
* * All other instance data is unchanged, including accumulated intersections.
|
|
105
|
+
*/
|
|
89
106
|
resetGeometry(geometryB) {
|
|
90
|
-
|
|
107
|
+
if (geometryB)
|
|
108
|
+
this._geometryB = geometryB;
|
|
91
109
|
}
|
|
92
110
|
/** returns true if `fraction` is in [0,1] within tolerance */
|
|
93
111
|
acceptFraction(fraction, fractionTol = 1.0e-12) {
|
|
@@ -97,131 +115,103 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
97
115
|
return false;
|
|
98
116
|
return true;
|
|
99
117
|
}
|
|
100
|
-
/**
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*/
|
|
104
|
-
grabPairedResults(reinitialize = false) {
|
|
105
|
-
const result = this._results;
|
|
106
|
-
if (reinitialize)
|
|
107
|
-
this._results = [];
|
|
108
|
-
return result;
|
|
118
|
+
/** Extract (and clear) the results, structured as an array of CurveLocationDetailPair. */
|
|
119
|
+
grabPairedResults() {
|
|
120
|
+
return this._results.extractArray();
|
|
109
121
|
}
|
|
110
122
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
123
|
+
* Create and record a close-approach pair from raw curve/fraction/point data.
|
|
124
|
+
* * If points are undefined, they are computed from the fractions via `fractionToPoint`.
|
|
125
|
+
* * Fractions are global (i.e., relative to the full curve, not a sub-segment).
|
|
126
|
+
* * The pair is recorded only if the XY distance is within `_maxDistanceSquared`.
|
|
127
|
+
* @param cpA first curve
|
|
128
|
+
* @param fA global fraction on cpA
|
|
129
|
+
* @param pointA point on cpA at fA, or undefined to compute from fA
|
|
130
|
+
* @param cpB second curve
|
|
131
|
+
* @param fB global fraction on cpB
|
|
132
|
+
* @param pointB point on cpB at fB, or undefined to compute from fB
|
|
133
|
+
* @param reversed if true, swap detailA and detailB before recording
|
|
113
134
|
*/
|
|
114
|
-
|
|
135
|
+
testAndRecordPointPair(cpA, fA, pointA, cpB, fB, pointB, reversed) {
|
|
136
|
+
if (!pointA)
|
|
137
|
+
pointA = cpA.fractionToPoint(fA);
|
|
138
|
+
if (!pointB)
|
|
139
|
+
pointB = cpB.fractionToPoint(fB);
|
|
115
140
|
const d2 = pointA.distanceSquaredXY(pointB);
|
|
116
|
-
if (d2
|
|
141
|
+
if (d2 <= this._maxDistanceSquared) {
|
|
117
142
|
const d = Math.sqrt(d2);
|
|
118
143
|
const detailA = CurveLocationDetail_1.CurveLocationDetail.createCurveFractionPointDistance(cpA, fA, pointA, d);
|
|
119
144
|
const detailB = CurveLocationDetail_1.CurveLocationDetail.createCurveFractionPointDistance(cpB, fB, pointB, d);
|
|
145
|
+
detailA.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
146
|
+
detailB.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
120
147
|
const pair = CurveLocationDetail_1.CurveLocationDetailPair.createCapture(detailA, detailB);
|
|
121
148
|
if (reversed)
|
|
122
149
|
pair.swapDetails();
|
|
123
|
-
this._results.
|
|
150
|
+
this._results.insert(pair);
|
|
124
151
|
}
|
|
125
152
|
}
|
|
126
153
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* @param
|
|
131
|
-
* @param
|
|
132
|
-
* @param localFractionB a fraction on second curve
|
|
133
|
-
* @param cpB the second curve
|
|
134
|
-
* @param fractionB0 start of the second curve
|
|
135
|
-
* @param fractionB1 end of the second curve
|
|
136
|
-
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
|
|
154
|
+
* Record a pre-built close-approach pair with global fractions already set.
|
|
155
|
+
* * Computes and stores the XY distance on both details.
|
|
156
|
+
* * The pair is recorded only if the XY distance is within `_maxDistanceSquared`.
|
|
157
|
+
* @param pair details with global fractions and points already set; modified in place
|
|
158
|
+
* @param reversed if true, swap detailA and detailB before recording
|
|
137
159
|
*/
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
const globalFractionB = Geometry_1.Geometry.interpolate(fractionB0, localFractionB, fractionB1);
|
|
141
|
-
// ignore duplicate of most recent approach
|
|
142
|
-
const numPrevious = this._results.length;
|
|
143
|
-
if (numPrevious > 0) {
|
|
144
|
-
const oldDetailA = this._results[numPrevious - 1].detailA;
|
|
145
|
-
const oldDetailB = this._results[numPrevious - 1].detailB;
|
|
146
|
-
if (reversed) {
|
|
147
|
-
if (oldDetailB.isSameCurveAndFraction({ curve: cpA, fraction: globalFractionA }) &&
|
|
148
|
-
oldDetailA.isSameCurveAndFraction({ curve: cpB, fraction: globalFractionB }))
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
if (oldDetailA.isSameCurveAndFraction({ curve: cpA, fraction: globalFractionA }) &&
|
|
153
|
-
oldDetailB.isSameCurveAndFraction({ curve: cpB, fraction: globalFractionB }))
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const pointA = cpA.fractionToPoint(globalFractionA);
|
|
158
|
-
const pointB = cpB.fractionToPoint(globalFractionB);
|
|
159
|
-
const d2 = pointA.distanceSquaredXY(pointB);
|
|
160
|
+
testAndRecordPair(pair, reversed) {
|
|
161
|
+
const d2 = pair.detailA.point.distanceSquaredXY(pair.detailB.point);
|
|
160
162
|
if (d2 > this._maxDistanceSquared)
|
|
161
163
|
return;
|
|
162
164
|
const d = Math.sqrt(d2);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
detailB.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
165
|
+
pair.detailA.a = pair.detailB.a = d;
|
|
166
|
+
pair.detailA.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
167
|
+
pair.detailB.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
167
168
|
if (reversed)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
this._results.push(new CurveLocationDetail_1.CurveLocationDetailPair(detailA, detailB));
|
|
169
|
+
pair.swapDetails();
|
|
170
|
+
this._results.insert(pair);
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
173
|
-
*
|
|
174
|
-
* *
|
|
175
|
-
* *
|
|
176
|
-
*
|
|
177
|
-
* @param
|
|
178
|
-
* @param
|
|
179
|
-
* @param
|
|
180
|
-
* @param
|
|
181
|
-
* @param
|
|
182
|
-
* @param
|
|
183
|
-
* @param
|
|
173
|
+
* Convert a close-approach pair from local (sub-segment) fractions to global fractions, then record it.
|
|
174
|
+
* * Local fractions in the pair are interpolated into the global fraction ranges.
|
|
175
|
+
* * Points are recomputed from the parent curves at the global fractions.
|
|
176
|
+
* * The pair is recorded only if the XY distance is within `_maxDistanceSquared`.
|
|
177
|
+
* @param pair local details (curve unspecified); modified in place with global fractions, curves, and points
|
|
178
|
+
* @param cpA parent curve A
|
|
179
|
+
* @param fractionA0 global fraction corresponding to local fraction 0 on curve A
|
|
180
|
+
* @param fractionA1 global fraction corresponding to local fraction 1 on curve A
|
|
181
|
+
* @param cpB parent curve B
|
|
182
|
+
* @param fractionB0 global fraction corresponding to local fraction 0 on curve B
|
|
183
|
+
* @param fractionB1 global fraction corresponding to local fraction 1 on curve B
|
|
184
|
+
* @param reversed if true, swap detailA and detailB before recording
|
|
184
185
|
*/
|
|
185
|
-
|
|
186
|
+
testAndRecordLocalPair(pair, cpA, fractionA0, fractionA1, cpB, fractionB0, fractionB1, reversed) {
|
|
186
187
|
const globalFractionA = Geometry_1.Geometry.interpolate(fractionA0, pair.detailA.fraction, fractionA1);
|
|
187
188
|
const globalFractionB = Geometry_1.Geometry.interpolate(fractionB0, pair.detailB.fraction, fractionB1);
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
if (oldDetailA.isSameCurveAndFraction({ curve: cpA, fraction: globalFractionA }) &&
|
|
200
|
-
oldDetailB.isSameCurveAndFraction({ curve: cpB, fraction: globalFractionB }))
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
// recompute the points just in case
|
|
205
|
-
CurveLocationDetail_1.CurveLocationDetail.createCurveEvaluatedFraction(cpA, globalFractionA, pair.detailA);
|
|
206
|
-
CurveLocationDetail_1.CurveLocationDetail.createCurveEvaluatedFraction(cpB, globalFractionB, pair.detailB);
|
|
207
|
-
pair.detailA.a = pair.detailB.a = pair.detailA.point.distanceXY(pair.detailB.point);
|
|
189
|
+
const pointA = cpA.fractionToPoint(globalFractionA);
|
|
190
|
+
const pointB = cpB.fractionToPoint(globalFractionB);
|
|
191
|
+
const d2 = pointA.distanceSquaredXY(pointB);
|
|
192
|
+
if (d2 > this._maxDistanceSquared)
|
|
193
|
+
return;
|
|
194
|
+
const d = Math.sqrt(d2);
|
|
195
|
+
CurveLocationDetail_1.CurveLocationDetail.createCurveFractionPointDistance(cpA, globalFractionA, pointA, d, pair.detailA);
|
|
196
|
+
CurveLocationDetail_1.CurveLocationDetail.createCurveFractionPointDistance(cpB, globalFractionB, pointB, d, pair.detailB);
|
|
208
197
|
pair.detailA.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
209
198
|
pair.detailB.setIntervalRole(CurveLocationDetail_1.CurveIntervalRole.isolated);
|
|
210
199
|
if (reversed)
|
|
211
200
|
pair.swapDetails();
|
|
212
|
-
this._results.
|
|
201
|
+
this._results.insert(pair);
|
|
213
202
|
}
|
|
214
|
-
|
|
203
|
+
/** Modify the current closest approach if the inputs are closer. */
|
|
204
|
+
static updatePointToSegmentDistance(closestApproach, fractionA, pointA, fractionB, pointB0, pointB1, maxDistanceSquared) {
|
|
215
205
|
let updated = false;
|
|
216
206
|
if (fractionB < 0)
|
|
217
207
|
fractionB = 0;
|
|
218
208
|
else if (fractionB > 1)
|
|
219
209
|
fractionB = 1;
|
|
220
|
-
|
|
221
|
-
const distanceSquared =
|
|
210
|
+
const pointB = pointB0.interpolate(fractionB, pointB1, this._workPointB);
|
|
211
|
+
const distanceSquared = pointB.distanceSquaredXY(pointA);
|
|
222
212
|
if (distanceSquared <= Math.min(maxDistanceSquared, closestApproach.detailA.a)) {
|
|
223
213
|
closestApproach.detailA.setFP(fractionA, pointA, undefined, distanceSquared);
|
|
224
|
-
closestApproach.detailB.setFP(fractionB,
|
|
214
|
+
closestApproach.detailB.setFP(fractionB, pointB, undefined, distanceSquared);
|
|
225
215
|
updated = true;
|
|
226
216
|
}
|
|
227
217
|
return updated;
|
|
@@ -234,8 +224,9 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
234
224
|
* @param b0 start point of line b
|
|
235
225
|
* @param b1 end point of line b
|
|
236
226
|
* @param maxDistanceSquared maximum distance squared (assumed to be positive)
|
|
237
|
-
* @returns
|
|
238
|
-
|
|
227
|
+
* @returns a pair of details for the closest approach, or `undefined` if no approach is within `maxDistanceSquared`.
|
|
228
|
+
* `detailA.fraction` is the fraction on segment a; `detailB.fraction` is the fraction on segment b. Returned
|
|
229
|
+
* details store the *squared* distance in the `a` property.
|
|
239
230
|
*/
|
|
240
231
|
static segmentSegmentBoundedApproach(a0, a1, b0, b1, maxDistanceSquared) {
|
|
241
232
|
const ux = a1.x - a0.x;
|
|
@@ -264,23 +255,23 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
264
255
|
const uu = Geometry_1.Geometry.hypotenuseSquaredXY(ux, uy);
|
|
265
256
|
if (hab0 * hab0 <= maxDistanceSquared * uu) { // test distance of b0 to u
|
|
266
257
|
const fractionA = Geometry_1.Geometry.safeDivideFraction(Geometry_1.Geometry.dotProductXYXY(ux, uy, e00x, e00y), uu, 0.0);
|
|
267
|
-
if (this.updatePointToSegmentDistance(0, b0, a0, a1,
|
|
258
|
+
if (this.updatePointToSegmentDistance(closestApproach, 0, b0, fractionA, a0, a1, maxDistanceSquared))
|
|
268
259
|
reversed = true;
|
|
269
260
|
}
|
|
270
261
|
if (hab1 * hab1 <= maxDistanceSquared * uu) { // test distance of b1 to u
|
|
271
262
|
const fractionA = Geometry_1.Geometry.safeDivideFraction(Geometry_1.Geometry.dotProductXYXY(ux, uy, e01x, e01y), uu, 0.0);
|
|
272
|
-
if (this.updatePointToSegmentDistance(1, b1, a0, a1,
|
|
263
|
+
if (this.updatePointToSegmentDistance(closestApproach, 1, b1, fractionA, a0, a1, maxDistanceSquared))
|
|
273
264
|
reversed = true;
|
|
274
265
|
}
|
|
275
266
|
const vv = Geometry_1.Geometry.hypotenuseSquaredXY(vx, vy);
|
|
276
267
|
if (hba0 * hba0 <= maxDistanceSquared * vv) { // test distance of a0 to v
|
|
277
268
|
const fractionB = Geometry_1.Geometry.safeDivideFraction(-Geometry_1.Geometry.dotProductXYXY(vx, vy, e00x, e00y), vv, 0.0);
|
|
278
|
-
if (this.updatePointToSegmentDistance(0, a0, b0, b1,
|
|
269
|
+
if (this.updatePointToSegmentDistance(closestApproach, 0, a0, fractionB, b0, b1, maxDistanceSquared))
|
|
279
270
|
reversed = false;
|
|
280
271
|
}
|
|
281
272
|
if (hba1 * hba1 <= maxDistanceSquared * vv) { // test distance of a1 to v
|
|
282
273
|
const fractionB = Geometry_1.Geometry.safeDivideFraction(-Geometry_1.Geometry.dotProductXYXY(vx, vy, e10x, e10y), vv, 0.0);
|
|
283
|
-
if (this.updatePointToSegmentDistance(1, a1, b0, b1,
|
|
274
|
+
if (this.updatePointToSegmentDistance(closestApproach, 1, a1, fractionB, b0, b1, maxDistanceSquared))
|
|
284
275
|
reversed = false;
|
|
285
276
|
}
|
|
286
277
|
if (closestApproach.detailA.a > maxDistanceSquared)
|
|
@@ -290,96 +281,30 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
290
281
|
return closestApproach;
|
|
291
282
|
}
|
|
292
283
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* Optionally, record close approaches of one curve's points if they fall between the other curve's points.
|
|
296
|
-
* * If an input curve is a LineString3d, then the corresponding fractions must define a segment of the line string.
|
|
284
|
+
* Compute closest approaches from the endpoints of each curve (if open) to the other curve.
|
|
285
|
+
* Record a [[CurveLocationDetailPair]] if such a distance is less than [[maxDistance]].
|
|
297
286
|
* @param cpA curveA
|
|
298
|
-
* @param fA0 fraction0 on curveA
|
|
299
|
-
* @param fA1 fraction1 on curveA
|
|
300
|
-
* @param testProjectionOnA whether to record projections of the given curveB points onto curveA
|
|
301
287
|
* @param cpB curveB
|
|
302
|
-
* @param
|
|
303
|
-
* @param fB1 fraction0 on curveB
|
|
304
|
-
* @param testProjectionOnB whether to record projections of the given curveA points onto curveB
|
|
305
|
-
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
|
|
288
|
+
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to curveA).
|
|
306
289
|
*/
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
this.testAndRecordPointPairApproach(cpA, fA0, pointA0, cpB, fB1, pointB1, reversed);
|
|
315
|
-
this.testAndRecordPointPairApproach(cpA, fA1, pointA1, cpB, fB1, pointB1, reversed);
|
|
316
|
-
if (testProjectionOnB) {
|
|
317
|
-
this.testAndRecordProjection(cpA, fA0, pointA0, cpB, fB0, fB1, reversed);
|
|
318
|
-
this.testAndRecordProjection(cpA, fA1, pointA1, cpB, fB0, fB1, reversed);
|
|
319
|
-
}
|
|
320
|
-
if (testProjectionOnA) {
|
|
321
|
-
this.testAndRecordProjection(cpB, fB0, pointB0, cpA, fA0, fA1, !reversed);
|
|
322
|
-
this.testAndRecordProjection(cpB, fB1, pointB1, cpA, fA0, fA1, !reversed);
|
|
290
|
+
testAndRecordEndPointApproaches(cpA, cpB, reversed) {
|
|
291
|
+
const pt = CurveCurveCloseApproachXY._workPointB;
|
|
292
|
+
// in closest approach context, endpoints of full sweep arcs are artificial locations, and thus ignored
|
|
293
|
+
const isClosedArc = (curve) => curve instanceof Arc3d_1.Arc3d && curve.sweep.isFullCircle;
|
|
294
|
+
if (!isClosedArc(cpA)) {
|
|
295
|
+
this.testAndRecordProjection(cpA, 0, cpA.startPoint(pt), cpB, reversed);
|
|
296
|
+
this.testAndRecordProjection(cpA, 1, cpA.endPoint(pt), cpB, reversed);
|
|
323
297
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
* Currently, this function only supports Arc3d and LineSegment.
|
|
328
|
-
* Note that this function doesn't handle endpoints.
|
|
329
|
-
*/
|
|
330
|
-
getPointCurveClosestApproachXYNewton(curveP, pointQ) {
|
|
331
|
-
if (!(curveP instanceof Arc3d_1.Arc3d) && !(curveP instanceof LineSegment3d_1.LineSegment3d)) {
|
|
332
|
-
(0, core_bentley_1.assert)(false, "getPointCurveClosestApproachXYNewton only supports Arc3d and LineSegment");
|
|
333
|
-
}
|
|
334
|
-
const seeds = [0.2, 0.4, 0.6, 0.8]; // HEURISTIC: arcs have up to 4 perpendiculars; lines have only 1
|
|
335
|
-
const newtonEvaluator = new Newton_1.CurvePointCloseApproachXYRtoRD(curveP, pointQ);
|
|
336
|
-
const newtonSearcher = new Newton_1.Newton1dUnbounded(newtonEvaluator, 100); // observed convergence to 1.0e-11 in 66 iters
|
|
337
|
-
let minCloseApproachLength = Geometry_1.Geometry.largeCoordinateResult;
|
|
338
|
-
let minCurvePFraction;
|
|
339
|
-
let minPointP;
|
|
340
|
-
for (const seed of seeds) {
|
|
341
|
-
newtonSearcher.setX(seed);
|
|
342
|
-
if (newtonSearcher.runIterations()) {
|
|
343
|
-
const curvePFraction = newtonSearcher.getX();
|
|
344
|
-
if (this.acceptFraction(curvePFraction)) {
|
|
345
|
-
const pointP = curveP.fractionToPoint(curvePFraction);
|
|
346
|
-
const closeApproachLength = pointP.distanceSquaredXY(pointQ);
|
|
347
|
-
if (closeApproachLength < minCloseApproachLength) {
|
|
348
|
-
minCloseApproachLength = closeApproachLength;
|
|
349
|
-
minCurvePFraction = curvePFraction;
|
|
350
|
-
minPointP = pointP;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
298
|
+
if (!isClosedArc(cpB)) {
|
|
299
|
+
this.testAndRecordProjection(cpB, 0, cpB.startPoint(pt), cpA, !reversed);
|
|
300
|
+
this.testAndRecordProjection(cpB, 1, cpB.endPoint(pt), cpA, !reversed);
|
|
354
301
|
}
|
|
355
|
-
if (minCurvePFraction && minPointP)
|
|
356
|
-
return CurveLocationDetail_1.CurveLocationDetail.createCurveFractionPoint(curveP, minCurvePFraction, minPointP);
|
|
357
|
-
return undefined;
|
|
358
302
|
}
|
|
359
|
-
/**
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
*/
|
|
365
|
-
testAndRecordProjection(cpA, fA, pointA, cpB, fB0, fB1, reversed) {
|
|
366
|
-
let detail;
|
|
367
|
-
if (cpB instanceof LineString3d_1.LineString3d) {
|
|
368
|
-
const segParamsB = cpB.globalFractionToSegmentIndexAndLocalFraction(fB0 <= fB1 ? fB0 : fB1);
|
|
369
|
-
const segIndexB = (segParamsB.fraction < 0.999999) ? segParamsB.index : segParamsB.index + 1;
|
|
370
|
-
const segmentB = cpB.getIndexedSegment(segIndexB);
|
|
371
|
-
if (segmentB && (detail = this.getPointCurveClosestApproachXYNewton(segmentB, pointA)))
|
|
372
|
-
LineString3d_1.LineString3d.convertLocalToGlobalDetail(detail, segIndexB, cpB.numEdges(), cpB);
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
detail = this.getPointCurveClosestApproachXYNewton(cpB, pointA);
|
|
376
|
-
}
|
|
377
|
-
if (detail) {
|
|
378
|
-
const fB = Geometry_1.Geometry.restrictToInterval(detail.fraction, fB0, fB1);
|
|
379
|
-
if (fB === detail.fraction) { // if fraction is within fB0 and fB1
|
|
380
|
-
this.testAndRecordPointPairApproach(cpA, fA, pointA, cpB, detail.fraction, detail.point, reversed);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
303
|
+
/** Find the closest xy approach between `pointA` and `cpB`. */
|
|
304
|
+
testAndRecordProjection(cpA, fA, pointA, cpB, reversed) {
|
|
305
|
+
const detail = cpB.closestPointXY(pointA);
|
|
306
|
+
if (detail)
|
|
307
|
+
this.testAndRecordPointPair(cpA, fA, pointA, cpB, detail.fraction, detail.point, reversed);
|
|
383
308
|
}
|
|
384
309
|
/**
|
|
385
310
|
* Compute closest xy approach of two line segments.
|
|
@@ -387,63 +312,50 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
387
312
|
* Record with fraction mapping.
|
|
388
313
|
* * The fraction mappings allow portions of a linestring to be passed here.
|
|
389
314
|
*/
|
|
390
|
-
|
|
315
|
+
computeSegmentSegment(cpA, pointA0, fractionA0, pointA1, fractionA1, cpB, pointB0, fractionB0, pointB1, fractionB1, reversed) {
|
|
391
316
|
// compute a pair with fractions local to segments
|
|
392
317
|
const approach = CurveCurveCloseApproachXY.segmentSegmentBoundedApproach(pointA0, pointA1, pointB0, pointB1, this._maxDistanceSquared);
|
|
393
318
|
// adjust the pair to refer to input curves and global fractions, then record it if new
|
|
394
319
|
if (approach) {
|
|
395
320
|
approach.detailA.setCurve(cpA);
|
|
396
321
|
approach.detailB.setCurve(cpB);
|
|
397
|
-
this.
|
|
322
|
+
this.testAndRecordLocalPair(approach, cpA, fractionA0, fractionA1, cpB, fractionB0, fractionB1, reversed);
|
|
398
323
|
}
|
|
399
324
|
}
|
|
400
|
-
/** Low level dispatch of segment with segment. */
|
|
401
|
-
dispatchSegmentSegment(cpA, pointA0, fractionA0, pointA1, fractionA1, cpB, pointB0, fractionB0, pointB1, fractionB1, reversed) {
|
|
402
|
-
this.computeSegmentSegment3D(cpA, pointA0, fractionA0, pointA1, fractionA1, cpB, pointB0, fractionB0, pointB1, fractionB1, reversed);
|
|
403
|
-
}
|
|
404
325
|
/**
|
|
405
326
|
* Compute the perpendiculars between a line segment and an arc, without extending either curve.
|
|
406
327
|
* * One or two perpendiculars will be found.
|
|
407
328
|
* * Each perpendicular segment starts or ends on the arc where the arc tangent is parallel to the line tangent.
|
|
408
|
-
*
|
|
409
|
-
* @param
|
|
410
|
-
* @param
|
|
411
|
-
* @param
|
|
412
|
-
* @param pointA1 end point of the segment
|
|
413
|
-
* @param fractionA1 fraction of the end of the segment
|
|
414
|
-
* @param arc the arc
|
|
415
|
-
* @param reversed swap the details in the recorded pair (default: false)
|
|
329
|
+
* @param startA line segment start point
|
|
330
|
+
* @param endA line segment end point
|
|
331
|
+
* @param arcB the arc
|
|
332
|
+
* @param announce callback to receive line and arc fractions and optional points of each perpendicular segment computed.
|
|
416
333
|
*/
|
|
417
|
-
|
|
418
|
-
const dotUT =
|
|
419
|
-
const dotVT =
|
|
334
|
+
announceAllPerpendicularsSegmentArcBounded(startA, endA, arcB, announce) {
|
|
335
|
+
const dotUT = arcB.vector0.crossProductStartEndXY(startA, endA);
|
|
336
|
+
const dotVT = arcB.vector90.crossProductStartEndXY(startA, endA);
|
|
420
337
|
const parallelRadians = Math.atan2(dotVT, dotUT);
|
|
421
338
|
for (const radians1 of [parallelRadians, parallelRadians + Math.PI]) {
|
|
422
|
-
const arcPoint =
|
|
423
|
-
const
|
|
424
|
-
if (this.acceptFraction(
|
|
425
|
-
const
|
|
426
|
-
if (
|
|
427
|
-
|
|
339
|
+
const arcPoint = arcB.radiansToPoint(radians1);
|
|
340
|
+
const arcFraction = arcB.sweep.radiansToSignedPeriodicFraction(radians1);
|
|
341
|
+
if (this.acceptFraction(arcFraction)) { // reject solution outside arc sweep
|
|
342
|
+
const lineFraction = SmallSystem_1.SmallSystem.lineSegment3dXYClosestPointUnbounded(startA, endA, arcPoint);
|
|
343
|
+
if (lineFraction !== undefined && this.acceptFraction(lineFraction))
|
|
344
|
+
announce(lineFraction, undefined, arcFraction, arcPoint);
|
|
428
345
|
}
|
|
429
346
|
}
|
|
430
347
|
}
|
|
431
348
|
/**
|
|
432
|
-
*
|
|
433
|
-
* Find close approaches within maxDistance between a line segments (pointA0, pointA1) and an arc.
|
|
349
|
+
* Find close approaches within maxDistance between a line segment and an arc.
|
|
434
350
|
* To consider:
|
|
435
351
|
* 1) intersection between arc and segment.
|
|
436
|
-
* 2) endpoints to endpoints or endpoints projection to the other curve.
|
|
437
|
-
* 3) arc tangent parallel to line segment
|
|
438
|
-
* @param
|
|
439
|
-
* @param
|
|
440
|
-
* @param
|
|
441
|
-
* @param pointA1 end point of the segment
|
|
442
|
-
* @param fractionA1 fraction of the end of the segment
|
|
443
|
-
* @param arc the arc
|
|
444
|
-
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
|
|
352
|
+
* 2) endpoints to endpoints, or endpoints projection to the other curve.
|
|
353
|
+
* 3) arc tangent parallel to line segment
|
|
354
|
+
* @param lineA the line segment
|
|
355
|
+
* @param arcB the arc
|
|
356
|
+
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to arcA).
|
|
445
357
|
*/
|
|
446
|
-
|
|
358
|
+
computeSegmentArc(lineA, arcB, reversed) {
|
|
447
359
|
// 1) intersection between arc and line segment (or string).
|
|
448
360
|
// Suppose:
|
|
449
361
|
// Arc: X = C + cU + sV where c = cos(theta) and s = sin(theta)
|
|
@@ -454,45 +366,45 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
454
366
|
// evaluate points.
|
|
455
367
|
// project back to line.
|
|
456
368
|
let intersectionFound = false;
|
|
457
|
-
const data =
|
|
458
|
-
const
|
|
459
|
-
const
|
|
460
|
-
const
|
|
461
|
-
const beta = Geometry_1.Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector0, 0); // det(A0, A1, U)
|
|
462
|
-
const gamma = Geometry_1.Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector90, 0); // det(A0, A1, V)
|
|
369
|
+
const data = arcB.toTransformedVectors();
|
|
370
|
+
const alpha = Geometry_1.Geometry.tripleProductXYW(lineA.point0Ref, 1, lineA.point1Ref, 1, data.center, 1); // det(A0, A1, C)
|
|
371
|
+
const beta = Geometry_1.Geometry.tripleProductXYW(lineA.point0Ref, 1, lineA.point1Ref, 1, data.vector0, 0); // det(A0, A1, U)
|
|
372
|
+
const gamma = Geometry_1.Geometry.tripleProductXYW(lineA.point0Ref, 1, lineA.point1Ref, 1, data.vector90, 0); // det(A0, A1, V)
|
|
463
373
|
const cosines = new GrowableFloat64Array_1.GrowableFloat64Array(2);
|
|
464
374
|
const sines = new GrowableFloat64Array_1.GrowableFloat64Array(2);
|
|
465
375
|
const radians = new GrowableFloat64Array_1.GrowableFloat64Array(2);
|
|
466
|
-
const numRoots = Polynomials_1.AnalyticRoots.appendImplicitLineUnitCircleIntersections(
|
|
467
|
-
alpha, beta, gamma, cosines, sines, radians);
|
|
376
|
+
const numRoots = Polynomials_1.AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians);
|
|
468
377
|
for (let i = 0; i < numRoots; i++) {
|
|
469
378
|
const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
|
|
470
379
|
const arcFraction = data.sweep.radiansToSignedPeriodicFraction(radians.atUncheckedIndex(i));
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
380
|
+
if (this.acceptFraction(arcFraction)) { // reject solution outside arc sweep
|
|
381
|
+
const lineFraction = SmallSystem_1.SmallSystem.lineSegment3dXYClosestPointUnbounded(lineA.point0Ref, lineA.point1Ref, arcPoint);
|
|
382
|
+
if (lineFraction !== undefined && this.acceptFraction(lineFraction)) {
|
|
383
|
+
this.testAndRecordPointPair(lineA, lineFraction, undefined, arcB, arcFraction, arcPoint, reversed);
|
|
384
|
+
intersectionFound = true;
|
|
385
|
+
}
|
|
476
386
|
}
|
|
477
387
|
}
|
|
478
388
|
if (intersectionFound)
|
|
479
389
|
return;
|
|
480
|
-
// 2) endpoints to endpoints or endpoints projection to the other curve.
|
|
481
|
-
this.
|
|
482
|
-
// 3) arc tangent parallel to line segment
|
|
390
|
+
// 2) endpoints to endpoints, or endpoints projection to the other curve.
|
|
391
|
+
this.testAndRecordEndPointApproaches(lineA, arcB, reversed);
|
|
392
|
+
// 3) arc tangent parallel to line segment.
|
|
483
393
|
// If line does not intersect the arc, then the closest (and/or the furthest) point on arc to the line is a
|
|
484
394
|
// point where the tangent line on arc at that point is parallel to the line.
|
|
485
|
-
this.
|
|
395
|
+
this.announceAllPerpendicularsSegmentArcBounded(lineA.point0Ref, lineA.point1Ref, arcB, (lineFraction, linePoint, arcFraction, arcPoint) => this.testAndRecordPointPair(lineA, lineFraction, linePoint, arcB, arcFraction, arcPoint, reversed));
|
|
486
396
|
}
|
|
487
397
|
/**
|
|
488
398
|
* Compute segments perpendicular to two elliptical arcs, without extending either curve.
|
|
489
399
|
* * Perpendiculars from an endpoint are not explicitly computed.
|
|
490
400
|
* * Intersections are also found by this search: they are reported as zero-length segments.
|
|
401
|
+
* @param arcA first arc
|
|
402
|
+
* @param arcB second arc
|
|
491
403
|
* @param reversed swap the details in the recorded pair (default: false)
|
|
492
404
|
*/
|
|
493
|
-
allPerpendicularsArcArcBounded(
|
|
494
|
-
const newtonEvaluator = new Newton_1.CurveCurveCloseApproachXYRRtoRRD(
|
|
495
|
-
// HEURISTIC: 2 ellipses have up to 8 perpendiculars
|
|
405
|
+
allPerpendicularsArcArcBounded(arcA, arcB, reversed = false) {
|
|
406
|
+
const newtonEvaluator = new Newton_1.CurveCurveCloseApproachXYRRtoRRD(arcA, arcB);
|
|
407
|
+
// HEURISTIC: 2 ellipses have up to 8 perpendiculars
|
|
496
408
|
const seedDelta = 1 / 10; // denominator 9 fails the unit test
|
|
497
409
|
const seedStart = seedDelta / 2;
|
|
498
410
|
const newtonSearcher = new Newton_1.Newton2dUnboundedWithDerivative(newtonEvaluator, 100); // observed convergence to 1.0e-11 in 49 iters
|
|
@@ -500,10 +412,10 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
500
412
|
for (let seedV = seedStart; seedV < 1; seedV += seedDelta) {
|
|
501
413
|
newtonSearcher.setUV(seedU, seedV);
|
|
502
414
|
if (newtonSearcher.runIterations()) {
|
|
503
|
-
const
|
|
504
|
-
const
|
|
505
|
-
if (this.acceptFraction(
|
|
506
|
-
this.
|
|
415
|
+
const fractionA = newtonSearcher.getU();
|
|
416
|
+
const fractionB = newtonSearcher.getV();
|
|
417
|
+
if (this.acceptFraction(fractionA) && this.acceptFraction(fractionB)) {
|
|
418
|
+
this.testAndRecordPointPair(arcA, fractionA, undefined, arcB, fractionB, undefined, reversed);
|
|
507
419
|
}
|
|
508
420
|
}
|
|
509
421
|
}
|
|
@@ -518,7 +430,7 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
518
430
|
if (!rangeB.intersectsRangeXY(rangeA))
|
|
519
431
|
return;
|
|
520
432
|
// 1) endpoints to endpoints or endpoints projection to the other curve
|
|
521
|
-
this.
|
|
433
|
+
this.testAndRecordEndPointApproaches(cpA, cpB, reversed);
|
|
522
434
|
// 2) perpendicular line between 2 arcs (includes intersections)
|
|
523
435
|
this.allPerpendicularsArcArcBounded(cpA, cpB, reversed);
|
|
524
436
|
}
|
|
@@ -561,7 +473,7 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
561
473
|
const fB1 = (i + 1 === numB - 1) ? 1.0 : (i + 1) * deltaFracB; // make sure we nail the end fraction
|
|
562
474
|
lsB.packedPoints.getPoint3dAtUncheckedPointIndex(i, pointB0);
|
|
563
475
|
lsB.packedPoints.getPoint3dAtUncheckedPointIndex(i + 1, pointB1);
|
|
564
|
-
this.
|
|
476
|
+
this.computeSegmentSegment(segA, pointA0, 0.0, pointA1, 1.0, lsB, pointB0, fB0, pointB1, fB1, reversed);
|
|
565
477
|
}
|
|
566
478
|
}
|
|
567
479
|
/** Detail computation for arc approaching linestring. */
|
|
@@ -572,72 +484,28 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
572
484
|
rangeA.expandInPlace(this._maxDistanceToAccept);
|
|
573
485
|
if (!rangeB.intersectsRangeXY(rangeA))
|
|
574
486
|
return;
|
|
575
|
-
const
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
487
|
+
const v0 = CurveCurveCloseApproachXY._workPointBB0;
|
|
488
|
+
const v1 = CurveCurveCloseApproachXY._workPointBB1;
|
|
489
|
+
// 1. record intersections
|
|
490
|
+
const intersections = CurveCurve_1.CurveCurve.intersectionXYPairs(arcA, false, lsB, false, this._xyTolerance);
|
|
491
|
+
for (const intersection of intersections)
|
|
492
|
+
this.testAndRecordPair(intersection, reversed);
|
|
493
|
+
// 2. record linestring interior vertex projections onto arc
|
|
494
|
+
const fStep = Geometry_1.Geometry.safeDivideFraction(1.0, lsB.numEdges(), 0);
|
|
495
|
+
for (let i = 1; i < lsB.numEdges(); ++i)
|
|
496
|
+
this.testAndRecordProjection(lsB, i * fStep, lsB.pointAtUnchecked(i, v0), arcA, !reversed);
|
|
497
|
+
// 3. record arc/linestring endpoint projections onto linestring/arc
|
|
498
|
+
this.testAndRecordEndPointApproaches(arcA, lsB, reversed);
|
|
499
|
+
// 4. record perpendiculars from within a segment to the arc
|
|
500
|
+
lsB.startPoint(v0);
|
|
501
|
+
for (let iSeg = 0; iSeg < lsB.numEdges(); ++iSeg, v0.setFrom(v1)) {
|
|
502
|
+
lsB.pointAtUnchecked(iSeg + 1, v1);
|
|
503
|
+
this.announceAllPerpendicularsSegmentArcBounded(v0, v1, arcA, (lineFraction, linePoint, arcFraction, arcPoint) => {
|
|
504
|
+
const fLineString = lsB.segmentIndexAndLocalFractionToGlobalFraction(iSeg, lineFraction);
|
|
505
|
+
this.testAndRecordPointPair(arcA, arcFraction, arcPoint, lsB, fLineString, linePoint, reversed);
|
|
506
|
+
});
|
|
589
507
|
}
|
|
590
508
|
}
|
|
591
|
-
/** Low level dispatch of curve collection. */
|
|
592
|
-
dispatchCurveCollection(geomA, geomAHandler) {
|
|
593
|
-
const geomB = this._geometryB; // save
|
|
594
|
-
if (!geomB || !geomB.children || !(geomB instanceof CurveCollection_1.CurveCollection))
|
|
595
|
-
return;
|
|
596
|
-
for (const child of geomB.children) {
|
|
597
|
-
this.resetGeometry(child);
|
|
598
|
-
geomAHandler(geomA);
|
|
599
|
-
}
|
|
600
|
-
this._geometryB = geomB; // restore
|
|
601
|
-
}
|
|
602
|
-
/** Low level dispatch to geomA given a CurveChainWithDistanceIndex in geometryB. */
|
|
603
|
-
dispatchCurveChainWithDistanceIndex(geomA, geomAHandler) {
|
|
604
|
-
if (!this._geometryB || !(this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex))
|
|
605
|
-
return;
|
|
606
|
-
if (geomA instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
607
|
-
(0, core_bentley_1.assert)(false, "call handleCurveChainWithDistanceIndex(geomA) instead");
|
|
608
|
-
}
|
|
609
|
-
const index0 = this._results.length;
|
|
610
|
-
const geomB = this._geometryB; // save
|
|
611
|
-
for (const child of geomB.path.children) {
|
|
612
|
-
this.resetGeometry(child);
|
|
613
|
-
geomAHandler(geomA);
|
|
614
|
-
}
|
|
615
|
-
this.resetGeometry(geomB); // restore
|
|
616
|
-
this._results = CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex.convertChildDetailToChainDetail(this._results, index0, undefined, geomB, true);
|
|
617
|
-
}
|
|
618
|
-
/** Double dispatch handler for strongly typed segment. */
|
|
619
|
-
handleLineSegment3d(segmentA) {
|
|
620
|
-
if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
621
|
-
const segmentB = this._geometryB;
|
|
622
|
-
this.dispatchSegmentSegment(segmentA, segmentA.point0Ref, 0.0, segmentA.point1Ref, 1.0, segmentB, segmentB.point0Ref, 0.0, segmentB.point1Ref, 1.0, false);
|
|
623
|
-
}
|
|
624
|
-
else if (this._geometryB instanceof LineString3d_1.LineString3d) {
|
|
625
|
-
this.computeSegmentLineString(segmentA, this._geometryB, false);
|
|
626
|
-
}
|
|
627
|
-
else if (this._geometryB instanceof Arc3d_1.Arc3d) {
|
|
628
|
-
this.dispatchSegmentArc(segmentA, segmentA.point0Ref, 0.0, segmentA.point1Ref, 1.0, this._geometryB, false);
|
|
629
|
-
}
|
|
630
|
-
else if (this._geometryB instanceof BSplineCurve_1.BSplineCurve3d) {
|
|
631
|
-
this.dispatchSegmentBsplineCurve(segmentA, this._geometryB, false);
|
|
632
|
-
}
|
|
633
|
-
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
634
|
-
this.dispatchCurveCollection(segmentA, this.handleLineSegment3d.bind(this));
|
|
635
|
-
}
|
|
636
|
-
else if (this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
637
|
-
this.dispatchCurveChainWithDistanceIndex(segmentA, this.handleLineSegment3d.bind(this));
|
|
638
|
-
}
|
|
639
|
-
return undefined;
|
|
640
|
-
}
|
|
641
509
|
/**
|
|
642
510
|
* Set bits for comparison to range xy
|
|
643
511
|
* * bit 0x01 => x smaller than range.low.x
|
|
@@ -710,27 +578,86 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
710
578
|
// DO NOT study the segment in detail if both bitB bits are on for any of the 4 planes
|
|
711
579
|
// (i.e., no intersection between rangeA1 and the range around line segment [B0,B1])
|
|
712
580
|
if ((bitB0 & bitB1) === 0)
|
|
713
|
-
this.
|
|
581
|
+
this.computeSegmentSegment(lsA, pointA0, fA0, pointA1, fA1, lsB, pointB0, fB0, pointB1, fB1, reversed);
|
|
714
582
|
}
|
|
715
583
|
}
|
|
716
584
|
}
|
|
717
585
|
}
|
|
718
586
|
}
|
|
587
|
+
/** Low level dispatch of curve collection. */
|
|
588
|
+
dispatchCurveCollection(geomA, geomAHandler) {
|
|
589
|
+
const geomB = this._geometryB; // save
|
|
590
|
+
if (!geomB || !geomB.children || !(geomB instanceof CurveCollection_1.CurveCollection))
|
|
591
|
+
return;
|
|
592
|
+
for (const child of geomB.children) {
|
|
593
|
+
this.resetGeometry(child);
|
|
594
|
+
geomAHandler(geomA);
|
|
595
|
+
}
|
|
596
|
+
this._geometryB = geomB; // restore
|
|
597
|
+
}
|
|
598
|
+
/** Low level dispatch to geomA given a CurveChainWithDistanceIndex in geometryB. */
|
|
599
|
+
dispatchCurveChainWithDistanceIndex(geomA, geomAHandler) {
|
|
600
|
+
if (!this._geometryB || !(this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex))
|
|
601
|
+
return;
|
|
602
|
+
if (geomA instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex)
|
|
603
|
+
(0, core_bentley_1.assert)(false, "call handleCurveChainWithDistanceIndex(geomA) instead");
|
|
604
|
+
const saveResults = this.grabPairedResults();
|
|
605
|
+
const geomB = this._geometryB;
|
|
606
|
+
for (const child of geomB.path.children) {
|
|
607
|
+
this.resetGeometry(child);
|
|
608
|
+
geomAHandler(geomA);
|
|
609
|
+
}
|
|
610
|
+
this.resetGeometry(geomB);
|
|
611
|
+
const childResults = this._results.extractArray();
|
|
612
|
+
childResults.forEach((pair) => {
|
|
613
|
+
CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex.convertChildDetailToChainDetailSingle(pair, undefined, geomB);
|
|
614
|
+
this._results.insert(pair);
|
|
615
|
+
});
|
|
616
|
+
saveResults.forEach((pair) => this._results.insert(pair));
|
|
617
|
+
}
|
|
618
|
+
/** Double dispatch handler for strongly typed segment. */
|
|
619
|
+
handleLineSegment3d(segmentA) {
|
|
620
|
+
if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
621
|
+
const segmentB = this._geometryB;
|
|
622
|
+
this.computeSegmentSegment(segmentA, segmentA.point0Ref, 0.0, segmentA.point1Ref, 1.0, segmentB, segmentB.point0Ref, 0.0, segmentB.point1Ref, 1.0, false);
|
|
623
|
+
}
|
|
624
|
+
else if (this._geometryB instanceof LineString3d_1.LineString3d) {
|
|
625
|
+
this.computeSegmentLineString(segmentA, this._geometryB, false);
|
|
626
|
+
}
|
|
627
|
+
else if (this._geometryB instanceof Arc3d_1.Arc3d) {
|
|
628
|
+
this.computeSegmentArc(segmentA, this._geometryB, false);
|
|
629
|
+
}
|
|
630
|
+
else if (this._geometryB instanceof BSplineCurve_1.BSplineCurve3d) {
|
|
631
|
+
this.dispatchSegmentBsplineCurve(segmentA, this._geometryB, false);
|
|
632
|
+
}
|
|
633
|
+
else if (this._geometryB instanceof TransitionSpiral3d_1.TransitionSpiral3d) {
|
|
634
|
+
this.dispatchCurveSpiral(segmentA, this._geometryB, false);
|
|
635
|
+
}
|
|
636
|
+
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
637
|
+
this.dispatchCurveCollection(segmentA, this.handleLineSegment3d.bind(this));
|
|
638
|
+
}
|
|
639
|
+
else if (this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
640
|
+
this.dispatchCurveChainWithDistanceIndex(segmentA, this.handleLineSegment3d.bind(this));
|
|
641
|
+
}
|
|
642
|
+
return undefined;
|
|
643
|
+
}
|
|
719
644
|
/** Double dispatch handler for strongly typed linestring. */
|
|
720
645
|
handleLineString3d(lsA) {
|
|
721
|
-
if (this._geometryB instanceof
|
|
722
|
-
const lsB = this._geometryB;
|
|
723
|
-
this.computeLineStringLineString(lsA, lsB, false);
|
|
724
|
-
}
|
|
725
|
-
else if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
646
|
+
if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
726
647
|
this.computeSegmentLineString(this._geometryB, lsA, true);
|
|
727
648
|
}
|
|
649
|
+
else if (this._geometryB instanceof LineString3d_1.LineString3d) {
|
|
650
|
+
this.computeLineStringLineString(lsA, this._geometryB, false);
|
|
651
|
+
}
|
|
728
652
|
else if (this._geometryB instanceof Arc3d_1.Arc3d) {
|
|
729
653
|
this.computeArcLineString(this._geometryB, lsA, true);
|
|
730
654
|
}
|
|
731
655
|
else if (this._geometryB instanceof BSplineCurve_1.BSplineCurve3d) {
|
|
732
656
|
this.dispatchLineStringBSplineCurve(lsA, this._geometryB, false);
|
|
733
657
|
}
|
|
658
|
+
else if (this._geometryB instanceof TransitionSpiral3d_1.TransitionSpiral3d) {
|
|
659
|
+
this.dispatchCurveSpiral(lsA, this._geometryB, false);
|
|
660
|
+
}
|
|
734
661
|
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
735
662
|
this.dispatchCurveCollection(lsA, this.handleLineString3d.bind(this));
|
|
736
663
|
}
|
|
@@ -740,46 +667,146 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
740
667
|
return undefined;
|
|
741
668
|
}
|
|
742
669
|
/** Double dispatch handler for strongly typed arc. */
|
|
743
|
-
handleArc3d(
|
|
670
|
+
handleArc3d(arcA) {
|
|
744
671
|
if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
745
|
-
this.
|
|
672
|
+
this.computeSegmentArc(this._geometryB, arcA, true);
|
|
746
673
|
}
|
|
747
674
|
else if (this._geometryB instanceof LineString3d_1.LineString3d) {
|
|
748
|
-
this.computeArcLineString(
|
|
675
|
+
this.computeArcLineString(arcA, this._geometryB, false);
|
|
749
676
|
}
|
|
750
677
|
else if (this._geometryB instanceof Arc3d_1.Arc3d) {
|
|
751
|
-
this.dispatchArcArc(
|
|
678
|
+
this.dispatchArcArc(arcA, this._geometryB, false);
|
|
752
679
|
}
|
|
753
680
|
else if (this._geometryB instanceof BSplineCurve_1.BSplineCurve3d) {
|
|
754
|
-
this.dispatchArcBsplineCurve3d(
|
|
681
|
+
this.dispatchArcBsplineCurve3d(arcA, this._geometryB, false);
|
|
682
|
+
}
|
|
683
|
+
else if (this._geometryB instanceof TransitionSpiral3d_1.TransitionSpiral3d) {
|
|
684
|
+
this.dispatchCurveSpiral(arcA, this._geometryB, false);
|
|
755
685
|
}
|
|
756
686
|
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
757
|
-
this.dispatchCurveCollection(
|
|
687
|
+
this.dispatchCurveCollection(arcA, this.handleArc3d.bind(this));
|
|
758
688
|
}
|
|
759
689
|
else if (this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
760
|
-
this.dispatchCurveChainWithDistanceIndex(
|
|
690
|
+
this.dispatchCurveChainWithDistanceIndex(arcA, this.handleArc3d.bind(this));
|
|
761
691
|
}
|
|
762
692
|
return undefined;
|
|
763
693
|
}
|
|
764
694
|
/** Double dispatch handler for strongly typed bspline curve. */
|
|
765
|
-
handleBSplineCurve3d(
|
|
695
|
+
handleBSplineCurve3d(curveA) {
|
|
766
696
|
if (this._geometryB instanceof LineSegment3d_1.LineSegment3d) {
|
|
767
|
-
this.dispatchSegmentBsplineCurve(this._geometryB,
|
|
697
|
+
this.dispatchSegmentBsplineCurve(this._geometryB, curveA, true);
|
|
768
698
|
}
|
|
769
699
|
else if (this._geometryB instanceof LineString3d_1.LineString3d) {
|
|
770
|
-
this.dispatchLineStringBSplineCurve(this._geometryB,
|
|
700
|
+
this.dispatchLineStringBSplineCurve(this._geometryB, curveA, true);
|
|
771
701
|
}
|
|
772
702
|
else if (this._geometryB instanceof Arc3d_1.Arc3d) {
|
|
773
|
-
this.dispatchArcBsplineCurve3d(this._geometryB,
|
|
703
|
+
this.dispatchArcBsplineCurve3d(this._geometryB, curveA, true);
|
|
774
704
|
}
|
|
775
705
|
else if (this._geometryB instanceof BSplineCurve_1.BSplineCurve3dBase) {
|
|
776
|
-
this.dispatchBSplineCurve3dBSplineCurve3d(
|
|
706
|
+
this.dispatchBSplineCurve3dBSplineCurve3d(curveA, this._geometryB, false);
|
|
707
|
+
}
|
|
708
|
+
else if (this._geometryB instanceof TransitionSpiral3d_1.TransitionSpiral3d) {
|
|
709
|
+
this.dispatchCurveSpiral(curveA, this._geometryB, false);
|
|
777
710
|
}
|
|
778
711
|
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
779
|
-
this.dispatchCurveCollection(
|
|
712
|
+
this.dispatchCurveCollection(curveA, this.handleBSplineCurve3d.bind(this));
|
|
780
713
|
}
|
|
781
714
|
else if (this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
782
|
-
this.dispatchCurveChainWithDistanceIndex(
|
|
715
|
+
this.dispatchCurveChainWithDistanceIndex(curveA, this.handleBSplineCurve3d.bind(this));
|
|
716
|
+
}
|
|
717
|
+
return undefined;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Process seeds for xy close approach between the curve and spiral.
|
|
721
|
+
* * Refine each result via Newton iteration. If it doesn't converge, remove it.
|
|
722
|
+
* @param seeds The initial seed results to refine.
|
|
723
|
+
* @param curveA The other curve primitive. May also be a transition spiral.
|
|
724
|
+
* @param spiralB The transition spiral.
|
|
725
|
+
* @param reversed whether `spiralB` data is in `detailA` of each recorded pair, and `curveA` data in `detailB`.
|
|
726
|
+
*/
|
|
727
|
+
refineSpiralResultsByNewton(seeds, curveA, spiralB, reversed = false) {
|
|
728
|
+
const xyMatchingFunction = new Newton_1.CurveCurveCloseApproachXYRRtoRRD(curveA, spiralB);
|
|
729
|
+
const newtonSearcher = new Newton_1.Newton2dUnboundedWithDerivative(xyMatchingFunction, 50, this._newtonTolerance); // seen: 47
|
|
730
|
+
for (const seed of seeds) {
|
|
731
|
+
const detailA = reversed ? seed.detailB : seed.detailA;
|
|
732
|
+
const detailB = reversed ? seed.detailA : seed.detailB;
|
|
733
|
+
(0, core_bentley_1.assert)(detailB.curve instanceof LineString3d_1.LineString3d, "Caller has discretized the spiral");
|
|
734
|
+
newtonSearcher.setUV(detailA.fraction, detailB.fraction); // use linestring fraction as spiral param; it generally yields a closer point than fractional length!
|
|
735
|
+
if (newtonSearcher.runIterations()) {
|
|
736
|
+
const fractionA = newtonSearcher.getU();
|
|
737
|
+
const fractionB = newtonSearcher.getV();
|
|
738
|
+
if (this.acceptFraction(fractionA) && this.acceptFraction(fractionB))
|
|
739
|
+
this.testAndRecordPointPair(curveA, fractionA, undefined, spiralB, fractionB, undefined, reversed);
|
|
740
|
+
} // ignore failure to converge
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Append stroke points and return the line string.
|
|
745
|
+
* * This is a convenient wrapper for [[CurvePrimitive.emitStrokes]] but the analogous instance method cannot be added
|
|
746
|
+
* to that class due to the ensuing recursion with subclass [[LineString3d]].
|
|
747
|
+
* @param options options for stroking the instance curve.
|
|
748
|
+
* @param result object to receive appended stroke points; if omitted, a new object is created, populated, and returned.
|
|
749
|
+
*/
|
|
750
|
+
strokeCurve(curve, options, result) {
|
|
751
|
+
const ls = result ? result : LineString3d_1.LineString3d.create();
|
|
752
|
+
curve.emitStrokes(ls, options);
|
|
753
|
+
return ls;
|
|
754
|
+
}
|
|
755
|
+
/** Find and return the close approaches between curveA and the discretization of curveB. */
|
|
756
|
+
computeDiscreteCloseApproachResults(curveA, lsB, reversed) {
|
|
757
|
+
const maxDist = this.maxDistanceToAccept;
|
|
758
|
+
const saveResults = this.grabPairedResults(); // save current results
|
|
759
|
+
const geomB = this._geometryB;
|
|
760
|
+
this.maxDistanceToAccept = maxDist ? maxDist * 1.2 : undefined; // HEURISTIC: allow slack for Newton seeds
|
|
761
|
+
this.resetGeometry(curveA);
|
|
762
|
+
this.handleLineString3d(lsB); // populate empty results with discrete solutions
|
|
763
|
+
if (!reversed) {
|
|
764
|
+
// handleLineString3d put lsB data into detailA, so if we aren't reversing, we need to swap
|
|
765
|
+
for (const result of this._results)
|
|
766
|
+
result.swapDetails();
|
|
767
|
+
}
|
|
768
|
+
this.resetGeometry(geomB);
|
|
769
|
+
this.maxDistanceToAccept = maxDist;
|
|
770
|
+
const discreteResults = this._results.extractArray();
|
|
771
|
+
saveResults.forEach((pair) => this._results.insert(pair)); // restore current results
|
|
772
|
+
return discreteResults;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Compute the XY close approach of a curve and a spiral.
|
|
776
|
+
* @param curveA curve to find its close approach with spiralB. May also be a transition spiral.
|
|
777
|
+
* @param spiralB transition spiral to find its close approach with curveA.
|
|
778
|
+
* @param reversed whether `spiralB` data will be recorded in `detailA` of each result, and `curveA` data in `detailB`.
|
|
779
|
+
*/
|
|
780
|
+
dispatchCurveSpiral(curveA, spiralB, reversed) {
|
|
781
|
+
// explicit search for intersections (Newton converges too slowly on DirectSpiral3d tangent intersections)
|
|
782
|
+
const intersections = CurveCurve_1.CurveCurve.intersectionXYPairs(curveA, false, spiralB, false, this._xyTolerance);
|
|
783
|
+
for (const intersection of intersections)
|
|
784
|
+
this.testAndRecordPair(intersection, reversed);
|
|
785
|
+
// append seeds computed by solving the discretized spiral close approach problem, then refine the seeds via Newton
|
|
786
|
+
let cpA = curveA;
|
|
787
|
+
if (curveA instanceof TransitionSpiral3d_1.TransitionSpiral3d)
|
|
788
|
+
cpA = this.strokeCurve(curveA);
|
|
789
|
+
const cpB = this.strokeCurve(spiralB);
|
|
790
|
+
const seeds = this.computeDiscreteCloseApproachResults(cpA, cpB, reversed);
|
|
791
|
+
this.refineSpiralResultsByNewton(seeds, curveA, spiralB, reversed);
|
|
792
|
+
if (curveA instanceof LineString3d_1.LineString3d) { // explicitly test corners (where Newton converges too slowly)
|
|
793
|
+
const fStep = Geometry_1.Geometry.safeDivideFraction(1.0, curveA.numEdges(), 0);
|
|
794
|
+
const v0 = CurveCurveCloseApproachXY._workPointBB0;
|
|
795
|
+
for (let i = 1; i < curveA.numEdges(); ++i)
|
|
796
|
+
this.testAndRecordProjection(curveA, i * fStep, curveA.pointAtUnchecked(i, v0), spiralB, reversed);
|
|
797
|
+
}
|
|
798
|
+
this.testAndRecordEndPointApproaches(curveA, spiralB, reversed);
|
|
799
|
+
}
|
|
800
|
+
/** Double dispatch handler for strongly typed spiral curve. */
|
|
801
|
+
handleTransitionSpiral(spiral) {
|
|
802
|
+
if (this._geometryB instanceof CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex) {
|
|
803
|
+
this.dispatchCurveChainWithDistanceIndex(spiral, this.handleTransitionSpiral.bind(this));
|
|
804
|
+
}
|
|
805
|
+
else if (this._geometryB instanceof CurvePrimitive_1.CurvePrimitive) {
|
|
806
|
+
this.dispatchCurveSpiral(this._geometryB, spiral, true);
|
|
807
|
+
}
|
|
808
|
+
else if (this._geometryB instanceof CurveCollection_1.CurveCollection) {
|
|
809
|
+
this.dispatchCurveCollection(spiral, this.handleTransitionSpiral.bind(this));
|
|
783
810
|
}
|
|
784
811
|
return undefined;
|
|
785
812
|
}
|
|
@@ -787,7 +814,11 @@ class CurveCurveCloseApproachXY extends GeometryHandler_1.RecurseToCurvesGeometr
|
|
|
787
814
|
handleCurveChainWithDistanceIndex(chain) {
|
|
788
815
|
super.handleCurveChainWithDistanceIndex(chain);
|
|
789
816
|
// if _geometryB is also a CurveChainWithDistanceIndex, it will already have been converted by dispatchCurveChainWithDistanceIndex
|
|
790
|
-
|
|
817
|
+
const childResults = this._results.extractArray();
|
|
818
|
+
childResults.forEach((pair) => {
|
|
819
|
+
CurveChainWithDistanceIndex_1.CurveChainWithDistanceIndex.convertChildDetailToChainDetailSingle(pair, chain, undefined);
|
|
820
|
+
this._results.insert(pair);
|
|
821
|
+
});
|
|
791
822
|
}
|
|
792
823
|
/** Double dispatch handler for strongly typed homogeneous bspline curve .. */
|
|
793
824
|
handleBSplineCurve3dH(_curve) {
|