Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { Loop } from "../Loop";
import { Path } from "../Path";
import { ProxyCurve } from "../ProxyCurve";
import { TransitionSpiral3d } from "../spiral/TransitionSpiral3d";
import { CurveCurve } from "../CurveCurve";

// cspell:word XYRR
/**
Expand Down Expand Up @@ -1057,7 +1058,8 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
const spiralApproximation = LineString3d.create();
this._geometryB.emitStrokes(spiralApproximation);
const numPreviousResults = this._results.length;
this.computeSegmentLineString(segmentA, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
// this.computeSegmentLineString(segmentA, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(segmentA, spiralApproximation, Geometry.smallMetricDistance));
const numberOfNewResults = this._results.length - numPreviousResults;
this.refineSpiralResultsByNewton(segmentA, this._geometryB, numberOfNewResults);
} else if (this._geometryB instanceof CurveCollection) {
Expand Down Expand Up @@ -1088,7 +1090,8 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
const spiralApproximation = LineString3d.create();
this._geometryB.emitStrokes(spiralApproximation);
const numPreviousResults = this._results.length;
this.computeLineStringLineString(lsA, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
// this.computeLineStringLineString(lsA, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(lsA, spiralApproximation, Geometry.smallMetricDistance));
const numberOfNewResults = this._results.length - numPreviousResults;
this.refineSpiralResultsByNewton(lsA, this._geometryB, numberOfNewResults);
} else if (this._geometryB instanceof CurveCollection) {
Expand Down Expand Up @@ -1119,7 +1122,8 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
const spiralApproximation = LineString3d.create();
this._geometryB.emitStrokes(spiralApproximation);
const numPreviousResults = this._results.length;
this.computeArcLineString(arc0, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
// this.computeArcLineString(arc0, this._extendA0, this._extendA1, spiralApproximation, false, false, false);
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(arc0, spiralApproximation, Geometry.smallMetricDistance));
const numberOfNewResults = this._results.length - numPreviousResults;
this.refineSpiralResultsByNewton(arc0, this._geometryB, numberOfNewResults);
} else if (this._geometryB instanceof CurveCollection) {
Expand Down Expand Up @@ -1150,7 +1154,8 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
const spiralApproximation = LineString3d.create();
this._geometryB.emitStrokes(spiralApproximation);
const numPreviousResults = this._results.length;
this.dispatchLineStringBSplineCurve(spiralApproximation, false, false, curve, this._extendA0, this._extendA1, true);
// this.dispatchLineStringBSplineCurve(spiralApproximation, false, false, curve, this._extendA0, this._extendA1, true);
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(curve, spiralApproximation, Geometry.smallMetricDistance));
const numberOfNewResults = this._results.length - numPreviousResults;
this.refineSpiralResultsByNewton(curve, this._geometryB, numberOfNewResults);
} else if (this._geometryB instanceof CurveCollection) {
Expand All @@ -1177,6 +1182,10 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
for (const detail of resultsToBeRefined) {
let spiralFraction = reversed ? detail.detailA.fraction : detail.detailB.fraction;
let otherFraction = reversed ? detail.detailB.fraction : detail.detailA.fraction;
if (spiral.fractionToPoint(spiralFraction).isAlmostEqualXY(otherCurve.fractionToPoint(otherFraction))) { // already an accurate intersection
this.recordPointWithLocalFractions(otherFraction, otherCurve, 0, 1, spiralFraction, spiral, 0, 1, reversed);
continue;
}
const xyMatchingFunction = new CurveCurveIntersectionXYRRToRRD(spiral, otherCurve);
const newtonSearcher = new Newton2dUnboundedWithDerivative(xyMatchingFunction);
newtonSearcher.setUV(spiralFraction, otherFraction);
Expand All @@ -1190,11 +1199,20 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
}
/** Double dispatch handler for strongly typed spiral curve. */
public override handleTransitionSpiral(spiral: TransitionSpiral3d): any {
if (this._geometryB instanceof CurvePrimitive) { // this also handles CurveChainWithDistanceIndex
if (this._geometryB instanceof CurveChainWithDistanceIndex) {
this.dispatchCurveChainWithDistanceIndex(spiral, this.handleTransitionSpiral.bind(this));
} else if (this._geometryB instanceof CurvePrimitive) {
const spiralApproximation = LineString3d.create();
spiral.emitStrokes(spiralApproximation);
const geomBApproximation = LineString3d.create();
if (this._geometryB instanceof TransitionSpiral3d)
this._geometryB.emitStrokes(geomBApproximation);
const numPreviousResults = this._results.length;
this.handleLineString3d(spiralApproximation);
// this.handleLineString3d(spiralApproximation);
if (this._geometryB instanceof TransitionSpiral3d)
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(spiralApproximation, geomBApproximation, Geometry.smallMetricDistance));
else
this._results.push(...CurveCurve.closeApproachProjectedXYPairs(spiralApproximation, this._geometryB, Geometry.smallMetricDistance));
const numberOfNewResults = this._results.length - numPreviousResults;
this.refineSpiralResultsByNewton(this._geometryB, spiral, numberOfNewResults, true);
} else if (this._geometryB instanceof CurveCollection) {
Expand Down
52 changes: 37 additions & 15 deletions core/geometry/src/test/curve/CurveCurveIntersectXY.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2503,11 +2503,13 @@ describe("CurveCurveIntersectXY", () => {
}
// curve primitives
const lineSegment0 = LineSegment3d.create(Point3d.create(70, 30), Point3d.create(70, -30));
const lineSegment1 = LineSegment3d.create(Point3d.create(-20, 0), Point3d.create(100, 0));
const lineString0 = LineString3d.create(
Point3d.create(20, 20), Point3d.create(40, 20), Point3d.create(70, -40),
Point3d.create(90, -40), Point3d.create(70, 20), Point3d.create(130, 20),
);
const arc0 = Arc3d.createXY(Point3d.create(50, 10), 30);
const arc1 = Arc3d.createXY(Point3d.create(0, -30), 30);
const bspline0 = BSplineCurve3d.createUniformKnots(
[
Point3d.create(70, 50, 0),
Expand All @@ -2520,28 +2522,30 @@ describe("CurveCurveIntersectXY", () => {
)!;
// curve collection (path-loop), curve chain, and bag of curves
const lineString1 = LineString3d.create(Point3d.create(-36.33, 64.45), Point3d.create(8.34, 120.78), Point3d.create(76.58, -7));
const arc1 = Arc3d.create(
const arc2 = Arc3d.create(
Point3d.create(80, 40), Vector3d.create(10, 0), Vector3d.create(0, 50), AngleSweep.createStartEndDegrees(250, 90),
);
const arc2 = Arc3d.create(
const arc3 = Arc3d.create(
Point3d.create(70, -40), Vector3d.create(20, 0), Vector3d.create(0, 20), AngleSweep.createStartEndDegrees(0, -180),
);
const lineString2 = LineString3d.create(Point3d.create(80, 90), Point3d.create(90, -100), Point3d.create(40, -100));
const lineString3 = LineString3d.create(Point3d.create(50, -40), Point3d.create(0, -40), Point3d.create(0, 0));
const lineSegment1 = LineSegment3d.create(Point3d.create(40, -100), Point3d.create(40, 30));
const lineSegment2 = LineSegment3d.create(Point3d.create(40, 30), Point3d.create(70, -70));
const lineSegment3 = LineSegment3d.create(Point3d.create(60, -50), Point3d.create(90, -40));
const path0 = Path.create(arc1, lineString2, lineSegment1, lineSegment2, integratedSpirals[1]);
const path1 = Path.create(lineSegment3, arc2, lineString3, integratedSpirals[0]);
const loop = Path.create(lineString1, arc1, lineString2, lineSegment1, lineSegment2, integratedSpirals[1]);
const lineSegment2 = LineSegment3d.create(Point3d.create(40, -100), Point3d.create(40, 30));
const lineSegment3 = LineSegment3d.create(Point3d.create(40, 30), Point3d.create(70, -70));
const lineSegment4 = LineSegment3d.create(Point3d.create(60, -50), Point3d.create(90, -40));
const path0 = Path.create(arc2, lineString2, lineSegment2, lineSegment3, integratedSpirals[1]);
const path1 = Path.create(lineSegment4, arc3, lineString3, integratedSpirals[0]);
const loop = Path.create(lineString1, arc2, lineString2, lineSegment2, lineSegment3, integratedSpirals[1]);
const curveChain0 = CurveChainWithDistanceIndex.createCapture(path0);
const curveChain1 = CurveChainWithDistanceIndex.createCapture(path1);
const bagOfCurves = BagOfCurves.create(path0, arc0, lineString0);

const curves: AnyCurve[] = [
lineSegment1,
lineSegment0,
lineString0,
arc0,
arc1,
bspline0,
// add rotated and non-planar spirals
integratedSpirals[1],
Expand Down Expand Up @@ -2581,14 +2585,14 @@ describe("CurveCurveIntersectXY", () => {
bagOfCurves,
];
const numExpectedIntersections = [
1, 3, 2, 1, // curve primitives other than spirals
1, 1, 3, 2, 1, 1, // curve primitives other than spirals
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // rotated and non-planar integrated spirals
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1, 1, 1, 1, 1, 1, 1, 1 // rotated and non-planar direct spirals
5, 6, 5, 10, // path, loop, curve chain, and bag of curves
];
ck.testCoordinate(curves.length, numExpectedIntersections.length, "matching arrays");
// spiral vs all curves
const test = (spiral: TransitionSpiral3d) => {
const test0 = (spiral: TransitionSpiral3d) => {
for (let j = 0; j < curves.length; j++) {
const curve = curves[j];
const numExpectedIntersection = numExpectedIntersections[j];
Expand All @@ -2600,22 +2604,40 @@ describe("CurveCurveIntersectXY", () => {
}
for (let i = 0; i < integratedSpirals.length; i++) // skip rotated and non-planar integrated spirals
if (i % 3 === 0)
test(integratedSpirals[i]);
test0(integratedSpirals[i]);
dx += 250;
for (let i = 0; i < directSpirals.length; i++) // skip rotated and non-planar direct spirals
if (i % 3 === 0)
test(directSpirals[i]);
// curve chain/collection vs curve chain/collection
test0(directSpirals[i]);
dx = 0;
dy = 6000;
const numExpected = 12;
dy = 6400;
let numExpected = 12;
// curve chain/collection vs curve chain/collection
visualizeAndTestSpiralIntersection(ck, allGeometry, curveChain0, curveChain1, numExpected, dx, dy);
dy += 200;
visualizeAndTestSpiralIntersection(ck, allGeometry, path0, path1, numExpected, dx, dy);
dy += 200;
visualizeAndTestSpiralIntersection(ck, allGeometry, curveChain0, path1, numExpected, dx, dy);
dy += 200;
visualizeAndTestSpiralIntersection(ck, allGeometry, curveChain1, path0, numExpected, dx, dy);
// tangency at the interior of the spiral
dy += 200;
numExpected = 1;
const test1 = (spiral: TransitionSpiral3d) => {
const ray = spiral.fractionToPointAndDerivative(0.5);
const ls = LineString3d.create(
ray.origin.plusScaled(ray.direction.normalize()!, 50), ray.origin.plusScaled(ray.direction.normalize()!, -50)
);
visualizeAndTestSpiralIntersection(ck, allGeometry, spiral, ls, numExpected, dx, dy);
dx += 200;
}
for (let i = 0; i < integratedSpirals.length; i++) // skip rotated and non-planar integrated spirals
if (i % 3 === 0)
test1(integratedSpirals[i]);
dx += 250;
for (let i = 0; i < directSpirals.length; i++) // skip rotated and non-planar direct spirals
if (i % 3 === 0)
test1(directSpirals[i]);

GeometryCoreTestIO.saveGeometry(allGeometry, "CurveCurveIntersectXY", "SpiralIntersection");
expect(ck.getNumErrors()).toBe(0);
Expand Down
Loading