@itwin/core-geometry 5.13.0-dev.3 → 5.13.0-dev.5
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/CHANGELOG.md +12 -1
- package/lib/cjs/curve/Arc3d.d.ts +1 -1
- package/lib/cjs/curve/Arc3d.js +1 -1
- package/lib/cjs/curve/Arc3d.js.map +1 -1
- package/lib/cjs/curve/CurveFactory.d.ts +14 -6
- package/lib/cjs/curve/CurveFactory.d.ts.map +1 -1
- package/lib/cjs/curve/CurveFactory.js +11 -1
- package/lib/cjs/curve/CurveFactory.js.map +1 -1
- package/lib/cjs/curve/LineSegment3d.d.ts +6 -1
- package/lib/cjs/curve/LineSegment3d.d.ts.map +1 -1
- package/lib/cjs/curve/LineSegment3d.js +8 -1
- package/lib/cjs/curve/LineSegment3d.js.map +1 -1
- package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.d.ts +9 -4
- package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.d.ts.map +1 -1
- package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.js +25 -16
- package/lib/cjs/curve/Query/ConsolidateAdjacentPrimitivesContext.js.map +1 -1
- package/lib/cjs/curve/Query/PlanarSubdivision.d.ts.map +1 -1
- package/lib/cjs/curve/Query/PlanarSubdivision.js +1 -3
- package/lib/cjs/curve/Query/PlanarSubdivision.js.map +1 -1
- package/lib/cjs/curve/RegionOps.d.ts +25 -3
- package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
- package/lib/cjs/curve/RegionOps.js +2 -1
- package/lib/cjs/curve/RegionOps.js.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts +4 -0
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js +132 -106
- package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
- package/lib/cjs/curve/spiral/TransitionSpiral3d.d.ts +5 -0
- package/lib/cjs/curve/spiral/TransitionSpiral3d.d.ts.map +1 -1
- package/lib/cjs/curve/spiral/TransitionSpiral3d.js +7 -0
- package/lib/cjs/curve/spiral/TransitionSpiral3d.js.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.d.ts +2 -2
- package/lib/cjs/geometry3d/AngleSweep.js +2 -2
- package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
- package/lib/cjs/geometry3d/Range.d.ts +8 -0
- package/lib/cjs/geometry3d/Range.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Range.js +16 -0
- package/lib/cjs/geometry3d/Range.js.map +1 -1
- package/lib/esm/curve/Arc3d.d.ts +1 -1
- package/lib/esm/curve/Arc3d.js +1 -1
- package/lib/esm/curve/Arc3d.js.map +1 -1
- package/lib/esm/curve/CurveFactory.d.ts +14 -6
- package/lib/esm/curve/CurveFactory.d.ts.map +1 -1
- package/lib/esm/curve/CurveFactory.js +11 -1
- package/lib/esm/curve/CurveFactory.js.map +1 -1
- package/lib/esm/curve/LineSegment3d.d.ts +6 -1
- package/lib/esm/curve/LineSegment3d.d.ts.map +1 -1
- package/lib/esm/curve/LineSegment3d.js +8 -1
- package/lib/esm/curve/LineSegment3d.js.map +1 -1
- package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.d.ts +9 -4
- package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.d.ts.map +1 -1
- package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.js +25 -16
- package/lib/esm/curve/Query/ConsolidateAdjacentPrimitivesContext.js.map +1 -1
- package/lib/esm/curve/Query/PlanarSubdivision.d.ts.map +1 -1
- package/lib/esm/curve/Query/PlanarSubdivision.js +2 -4
- package/lib/esm/curve/Query/PlanarSubdivision.js.map +1 -1
- package/lib/esm/curve/RegionOps.d.ts +25 -3
- package/lib/esm/curve/RegionOps.d.ts.map +1 -1
- package/lib/esm/curve/RegionOps.js +2 -1
- package/lib/esm/curve/RegionOps.js.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts +4 -0
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js +132 -106
- package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
- package/lib/esm/curve/spiral/TransitionSpiral3d.d.ts +5 -0
- package/lib/esm/curve/spiral/TransitionSpiral3d.d.ts.map +1 -1
- package/lib/esm/curve/spiral/TransitionSpiral3d.js +7 -0
- package/lib/esm/curve/spiral/TransitionSpiral3d.js.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.d.ts +2 -2
- package/lib/esm/geometry3d/AngleSweep.js +2 -2
- package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
- package/lib/esm/geometry3d/Range.d.ts +8 -0
- package/lib/esm/geometry3d/Range.d.ts.map +1 -1
- package/lib/esm/geometry3d/Range.js +16 -0
- package/lib/esm/geometry3d/Range.js.map +1 -1
- package/package.json +3 -3
|
@@ -284,124 +284,149 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
|
|
|
284
284
|
this.computeSegmentSegment3D(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, cpB, extendB0, pointB0, fractionB0, pointB1, fractionB1, extendB1, reversed);
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// The fraction and extend parameters allow all combinations to be passed in.
|
|
290
|
-
dispatchSegmentArc(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed) {
|
|
287
|
+
/** Implementation of dispatchSegmentArc under affine transform. KEEP IN SYNC WITH computeSegmentArcHomogeneous. */
|
|
288
|
+
computeSegmentArc(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed) {
|
|
291
289
|
const tol2 = this._coincidentGeometryContext.tolerance * this._coincidentGeometryContext.tolerance;
|
|
292
290
|
const cosines = new GrowableFloat64Array(2);
|
|
293
291
|
const sines = new GrowableFloat64Array(2);
|
|
294
292
|
const radians = new GrowableFloat64Array(2);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
numAccepted++;
|
|
330
|
-
}
|
|
293
|
+
const recordIfNearIntersection = (fA, fB, d2) => {
|
|
294
|
+
if (!Geometry.isDistanceWithinTol(d2, tol2))
|
|
295
|
+
return false;
|
|
296
|
+
this.recordPointWithLocalFractions(fA, cpA, fractionA0, fractionA1, fB, arc, 0, 1, reversed);
|
|
297
|
+
return true;
|
|
298
|
+
};
|
|
299
|
+
const data = arc.toTransformedVectors(this._worldToLocalAffine);
|
|
300
|
+
let pointA0Local = pointA0;
|
|
301
|
+
let pointA1Local = pointA1;
|
|
302
|
+
const pointB0Local = arc.startPoint();
|
|
303
|
+
const pointB1Local = arc.endPoint();
|
|
304
|
+
if (this._worldToLocalAffine) {
|
|
305
|
+
pointA0Local = this._worldToLocalAffine.multiplyPoint3d(pointA0);
|
|
306
|
+
pointA1Local = this._worldToLocalAffine.multiplyPoint3d(pointA1);
|
|
307
|
+
this._worldToLocalAffine.multiplyXYAndZInPlace(pointB0Local);
|
|
308
|
+
this._worldToLocalAffine.multiplyXYAndZInPlace(pointB1Local);
|
|
309
|
+
}
|
|
310
|
+
const alpha = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.center, 1);
|
|
311
|
+
const beta = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector0, 0);
|
|
312
|
+
const gamma = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector90, 0);
|
|
313
|
+
// note really tight tol for tangency since below we check closest approach also
|
|
314
|
+
let numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians, tol2);
|
|
315
|
+
const closeApproach = (0 === numRoots);
|
|
316
|
+
if (closeApproach)
|
|
317
|
+
numRoots = 1; // we returned the closest approach instead: first entry is the arc point, which is all we need
|
|
318
|
+
const roots = [];
|
|
319
|
+
for (let i = 0; i < numRoots; i++) {
|
|
320
|
+
const arcPt = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
|
|
321
|
+
const fArc = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(i), extendB0); // exterior fraction sign based on extend flags
|
|
322
|
+
const fArcNearest01 = data.sweep.fractionToSignedPeriodicFraction(fArc, undefined); // exterior fraction sign based on proximity to 0/1
|
|
323
|
+
const fLine = SmallSystem.lineSegment3dXYClosestPointUnbounded(pointA0Local, pointA1Local, arcPt);
|
|
324
|
+
if (fLine !== undefined) {
|
|
325
|
+
const linePt = pointA0Local.interpolate(fLine, pointA1Local);
|
|
326
|
+
roots.push({ fArc, fArcNearest01, fLine, arcPt, linePt });
|
|
331
327
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
dist2.push({ d2, fA: 0, fB: 1 });
|
|
343
|
-
d2 = pointA1H.realDistanceSquaredXY(pointB0H);
|
|
344
|
-
if (d2 !== undefined)
|
|
345
|
-
dist2.push({ d2, fA: 1, fB: 0 });
|
|
346
|
-
d2 = pointA1H.realDistanceSquaredXY(pointB1H);
|
|
347
|
-
if (d2 !== undefined)
|
|
348
|
-
dist2.push({ d2, fA: 1, fB: 1 });
|
|
349
|
-
dist2.sort((a, b) => a.d2 - b.d2);
|
|
350
|
-
if (Geometry.isDistanceWithinTol(dist2[0].d2, tol2))
|
|
351
|
-
this.recordPointWithLocalFractions(dist2[0].fA, cpA, fractionA0, fractionA1, dist2[0].fB, arc, 0, 1, reversed);
|
|
328
|
+
}
|
|
329
|
+
// range-test and record roots
|
|
330
|
+
for (const root of roots) {
|
|
331
|
+
const { fArc, fArcNearest01, fLine, arcPt, linePt } = root;
|
|
332
|
+
if (closeApproach && !Geometry.isDistanceWithinTol(arcPt.distanceSquaredXY(linePt), tol2)) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (this.acceptFraction(extendA0, fLine, extendA1) && this.acceptFraction(extendB0, fArc, extendB1)) {
|
|
336
|
+
this.recordPointWithLocalFractions(fLine, cpA, fractionA0, fractionA1, fArc, arc, 0, 1, reversed);
|
|
337
|
+
continue;
|
|
352
338
|
}
|
|
339
|
+
// since line-arc chains are so common, look for near-endpoint intersections using distance tol, which is often relatively looser than fraction tol
|
|
340
|
+
const inArcRange = extendB0 || extendB1 || Geometry.isIn01(fArc);
|
|
341
|
+
const inLineRange = (extendA0 && fLine < 0) || (extendA1 && fLine > 1) || Geometry.isIn01(fLine);
|
|
342
|
+
let accepted = false;
|
|
343
|
+
if (inArcRange && !inLineRange) // check tangency near line endpoint
|
|
344
|
+
accepted = recordIfNearIntersection(fLine < 0 ? 0 : 1, fArc, (fLine < 0 ? pointA0Local : pointA1Local).distanceSquaredXY(arcPt));
|
|
345
|
+
else if (!inArcRange && inLineRange) // check tangency near arc endpoint
|
|
346
|
+
accepted = recordIfNearIntersection(fLine, fArcNearest01 < 0 ? 0 : 1, linePt.distanceSquaredXY(fArcNearest01 < 0 ? pointB0Local : pointB1Local));
|
|
347
|
+
if (!accepted) // check intersection between nearest endpoints
|
|
348
|
+
recordIfNearIntersection(fLine < 0.5 ? 0 : 1, fArcNearest01 < 0.5 ? 0 : 1, (fLine < 0.5 ? pointA0Local : pointA1Local).distanceSquaredXY(fArcNearest01 < 0.5 ? pointB0Local : pointB1Local));
|
|
353
349
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
350
|
+
}
|
|
351
|
+
/** Implementation of dispatchSegmentArc under perspective transform. KEEP IN SYNC WITH computeSegmentArc. */
|
|
352
|
+
computeSegmentArcHomogeneous(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed) {
|
|
353
|
+
if (!this._worldToLocalPerspective)
|
|
354
|
+
return;
|
|
355
|
+
const tol2 = this._coincidentGeometryContext.tolerance * this._coincidentGeometryContext.tolerance;
|
|
356
|
+
const cosines = new GrowableFloat64Array(2);
|
|
357
|
+
const sines = new GrowableFloat64Array(2);
|
|
358
|
+
const radians = new GrowableFloat64Array(2);
|
|
359
|
+
const recordIfNearIntersection = (fA, fB, d2) => {
|
|
360
|
+
if (d2 === undefined || !Geometry.isDistanceWithinTol(d2, tol2))
|
|
361
|
+
return false;
|
|
362
|
+
this.recordPointWithLocalFractions(fA, cpA, fractionA0, fractionA1, fB, arc, 0, 1, reversed);
|
|
363
|
+
return true;
|
|
364
|
+
};
|
|
365
|
+
const data = arc.toTransformedPoint4d(this._worldToLocalPerspective);
|
|
366
|
+
const pointA0H = this._worldToLocalPerspective.multiplyPoint3d(pointA0, 1);
|
|
367
|
+
const pointA1H = this._worldToLocalPerspective.multiplyPoint3d(pointA1, 1);
|
|
368
|
+
const pointB0H = this._worldToLocalPerspective.multiplyPoint3d(arc.startPoint(), 1);
|
|
369
|
+
const pointB1H = this._worldToLocalPerspective.multiplyPoint3d(arc.endPoint(), 1);
|
|
370
|
+
const alpha = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.center);
|
|
371
|
+
const beta = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.vector0);
|
|
372
|
+
const gamma = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.vector90);
|
|
373
|
+
// note really tight tol for tangency since below we check closest approach also
|
|
374
|
+
let numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians, tol2);
|
|
375
|
+
const closeApproach = (0 === numRoots);
|
|
376
|
+
if (closeApproach)
|
|
377
|
+
numRoots = 1; // we returned the closest approach instead: first entry is the arc point, which is all we need
|
|
378
|
+
const roots = [];
|
|
379
|
+
for (let i = 0; i < numRoots; i++) {
|
|
380
|
+
const arcPt = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
|
|
381
|
+
const fArc = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(i), extendB0); // exterior fraction sign based on extend flags
|
|
382
|
+
const fArcNearest01 = data.sweep.fractionToSignedPeriodicFraction(fArc, undefined); // exterior fraction sign based on proximity to 0/1
|
|
383
|
+
const fLine = SmallSystem.lineSegment3dHXYClosestPointUnbounded(pointA0H, pointA1H, arcPt);
|
|
384
|
+
if (fLine !== undefined) {
|
|
385
|
+
const linePt = pointA0H.interpolate(fLine, pointA1H);
|
|
386
|
+
roots.push({ fArc, fArcNearest01, fLine, arcPt, linePt });
|
|
361
387
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
let numAccepted = 0;
|
|
370
|
-
for (let i = 0; i < numRoots; i++) {
|
|
371
|
-
const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
|
|
372
|
-
const fArc = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(i), extendB0);
|
|
373
|
-
const fLine = SmallSystem.lineSegment3dXYClosestPointUnbounded(pointA0Local, pointA1Local, arcPoint);
|
|
374
|
-
if (fLine === undefined)
|
|
388
|
+
}
|
|
389
|
+
// range-test and record roots
|
|
390
|
+
for (const root of roots) {
|
|
391
|
+
const { fArc, fArcNearest01, fLine, arcPt, linePt } = root;
|
|
392
|
+
if (closeApproach) {
|
|
393
|
+
const dist2 = arcPt.realDistanceSquaredXY(linePt);
|
|
394
|
+
if (dist2 === undefined || !Geometry.isDistanceWithinTol(dist2, tol2))
|
|
375
395
|
continue;
|
|
376
|
-
if (closeApproach) {
|
|
377
|
-
const linePoint = pointA0Local.interpolate(fLine, pointA1Local);
|
|
378
|
-
if (!Geometry.isDistanceWithinTol(arcPoint.distanceSquaredXY(linePoint), tol2))
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
if (this.acceptFraction(extendA0, fLine, extendA1) && this.acceptFraction(extendB0, fArc, extendB1)) {
|
|
382
|
-
this.recordPointWithLocalFractions(fLine, cpA, fractionA0, fractionA1, fArc, arc, 0, 1, reversed);
|
|
383
|
-
numAccepted++;
|
|
384
|
-
}
|
|
385
396
|
}
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const pointB1Local = arc.endPoint();
|
|
390
|
-
if (this._worldToLocalAffine) {
|
|
391
|
-
this._worldToLocalAffine.multiplyXYAndZInPlace(pointB0Local);
|
|
392
|
-
this._worldToLocalAffine.multiplyXYAndZInPlace(pointB1Local);
|
|
393
|
-
}
|
|
394
|
-
const dist2 = [];
|
|
395
|
-
dist2.push({ d2: pointA0Local.distanceSquaredXY(pointB0Local), fA: 0, fB: 0 });
|
|
396
|
-
dist2.push({ d2: pointA0Local.distanceSquaredXY(pointB1Local), fA: 0, fB: 1 });
|
|
397
|
-
dist2.push({ d2: pointA1Local.distanceSquaredXY(pointB0Local), fA: 1, fB: 0 });
|
|
398
|
-
dist2.push({ d2: pointA1Local.distanceSquaredXY(pointB1Local), fA: 1, fB: 1 });
|
|
399
|
-
dist2.sort((a, b) => a.d2 - b.d2);
|
|
400
|
-
if (Geometry.isDistanceWithinTol(dist2[0].d2, tol2))
|
|
401
|
-
this.recordPointWithLocalFractions(dist2[0].fA, cpA, fractionA0, fractionA1, dist2[0].fB, arc, 0, 1, reversed);
|
|
397
|
+
if (this.acceptFraction(extendA0, fLine, extendA1) && this.acceptFraction(extendB0, fArc, extendB1)) {
|
|
398
|
+
this.recordPointWithLocalFractions(fLine, cpA, fractionA0, fractionA1, fArc, arc, 0, 1, reversed);
|
|
399
|
+
continue;
|
|
402
400
|
}
|
|
401
|
+
// since line-arc chains are so common, look for near-endpoint intersections using distance tol, which is often relatively looser than fraction tol
|
|
402
|
+
const inArcRange = extendB0 || extendB1 || Geometry.isIn01(fArc);
|
|
403
|
+
const inLineRange = (extendA0 && fLine < 0) || (extendA1 && fLine > 1) || Geometry.isIn01(fLine);
|
|
404
|
+
let accepted = false;
|
|
405
|
+
if (inArcRange && !inLineRange) // check tangency near line endpoint
|
|
406
|
+
accepted = recordIfNearIntersection(fLine < 0 ? 0 : 1, fArc, (fLine < 0 ? pointA0H : pointA1H).realDistanceSquaredXY(arcPt));
|
|
407
|
+
else if (!inArcRange && inLineRange) // check tangency near arc endpoint
|
|
408
|
+
accepted = recordIfNearIntersection(fLine, fArcNearest01 < 0 ? 0 : 1, linePt.realDistanceSquaredXY(fArcNearest01 < 0 ? pointB0H : pointB1H));
|
|
409
|
+
if (!accepted) // check intersection between nearest endpoints
|
|
410
|
+
recordIfNearIntersection(fLine < 0.5 ? 0 : 1, fArcNearest01 < 0.5 ? 0 : 1, (fLine < 0.5 ? pointA0H : pointA1H).realDistanceSquaredXY(fArcNearest01 < 0.5 ? pointB0H : pointB1H));
|
|
403
411
|
}
|
|
404
412
|
}
|
|
413
|
+
// Caller accesses data from a linestring or segment and passes it here.
|
|
414
|
+
// The line segment in question might be (a) a full line segment or (b) a fragment within a linestring.
|
|
415
|
+
// The fraction and extend parameters allow all combinations to be passed in.
|
|
416
|
+
dispatchSegmentArc(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed) {
|
|
417
|
+
// Arc: X(theta) = C + cos(theta)·U + sin(theta)·V
|
|
418
|
+
// Line: contains points A0,A1
|
|
419
|
+
// Arc point X is colinear (intersects) with line if det(A0, A1, X) = 0 with homogeneous xyw points and vectors
|
|
420
|
+
// This leads to
|
|
421
|
+
// det(A0, A1, C) + cos(theta) det(A0, A1, U) + sin(theta) det(A0, A1, V) = 0
|
|
422
|
+
// or
|
|
423
|
+
// alpha + beta cos(theta) + gamma sin(theta) = 0
|
|
424
|
+
// solve for theta; evaluate points; project back to line
|
|
425
|
+
if (this._worldToLocalPerspective)
|
|
426
|
+
this.computeSegmentArcHomogeneous(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed);
|
|
427
|
+
else
|
|
428
|
+
this.computeSegmentArc(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed);
|
|
429
|
+
}
|
|
405
430
|
/**
|
|
406
431
|
* Compute the intersection of two xy-arcs.
|
|
407
432
|
* * Each matrix has [U V C] in (x,y,w) form from homogeneous projection (local to world).
|
|
@@ -896,7 +921,8 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
|
|
|
896
921
|
let converged = newtonSearcher.runIterations();
|
|
897
922
|
const fractionA = newtonSearcher.getU();
|
|
898
923
|
const fractionB = newtonSearcher.getV();
|
|
899
|
-
|
|
924
|
+
// note looser tol for spiral, which can have high order tangency at start/end
|
|
925
|
+
if (this.acceptFraction(extendA0, fractionA, extendA1) && this.acceptFraction(false, fractionB, false, Geometry.smallFraction)) {
|
|
900
926
|
const pointA = curveA.fractionToPoint(fractionA, CurveCurveIntersectXY._workPointA0);
|
|
901
927
|
const pointB = spiralB.fractionToPoint(fractionB, CurveCurveIntersectXY._workPointB0);
|
|
902
928
|
if (!converged) // Newton may have found close points even if it didn't converge parametrically
|