@itwin/core-geometry 5.2.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
  3. package/lib/cjs/curve/Arc3d.js +5 -7
  4. package/lib/cjs/curve/Arc3d.js.map +1 -1
  5. package/lib/cjs/curve/CurveOps.d.ts +2 -5
  6. package/lib/cjs/curve/CurveOps.d.ts.map +1 -1
  7. package/lib/cjs/curve/CurveOps.js +2 -5
  8. package/lib/cjs/curve/CurveOps.js.map +1 -1
  9. package/lib/cjs/curve/Query/PlanarSubdivision.d.ts +50 -15
  10. package/lib/cjs/curve/Query/PlanarSubdivision.d.ts.map +1 -1
  11. package/lib/cjs/curve/Query/PlanarSubdivision.js +102 -84
  12. package/lib/cjs/curve/Query/PlanarSubdivision.js.map +1 -1
  13. package/lib/cjs/curve/RegionOps.d.ts +44 -25
  14. package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
  15. package/lib/cjs/curve/RegionOps.js +74 -39
  16. package/lib/cjs/curve/RegionOps.js.map +1 -1
  17. package/lib/cjs/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
  18. package/lib/cjs/curve/RegionOpsClassificationSweeps.js +8 -8
  19. package/lib/cjs/curve/RegionOpsClassificationSweeps.js.map +1 -1
  20. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts +1 -0
  21. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  22. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js +102 -92
  23. package/lib/cjs/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  24. package/lib/cjs/geometry3d/GrowableXYArray.d.ts +2 -1
  25. package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
  26. package/lib/cjs/geometry3d/GrowableXYArray.js +2 -1
  27. package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
  28. package/lib/cjs/geometry3d/GrowableXYZArray.d.ts +2 -1
  29. package/lib/cjs/geometry3d/GrowableXYZArray.d.ts.map +1 -1
  30. package/lib/cjs/geometry3d/GrowableXYZArray.js +2 -1
  31. package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
  32. package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts +9 -16
  33. package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
  34. package/lib/cjs/geometry3d/IndexedXYZCollection.js +3 -3
  35. package/lib/cjs/geometry3d/IndexedXYZCollection.js.map +1 -1
  36. package/lib/cjs/geometry3d/PolylineOps.d.ts +2 -2
  37. package/lib/cjs/geometry3d/PolylineOps.js +2 -2
  38. package/lib/cjs/geometry3d/PolylineOps.js.map +1 -1
  39. package/lib/cjs/numerics/ClusterableArray.d.ts.map +1 -1
  40. package/lib/cjs/numerics/ClusterableArray.js +2 -2
  41. package/lib/cjs/numerics/ClusterableArray.js.map +1 -1
  42. package/lib/cjs/topology/Merging.d.ts +15 -7
  43. package/lib/cjs/topology/Merging.d.ts.map +1 -1
  44. package/lib/cjs/topology/Merging.js +15 -10
  45. package/lib/cjs/topology/Merging.js.map +1 -1
  46. package/lib/esm/curve/Arc3d.d.ts.map +1 -1
  47. package/lib/esm/curve/Arc3d.js +5 -7
  48. package/lib/esm/curve/Arc3d.js.map +1 -1
  49. package/lib/esm/curve/CurveOps.d.ts +2 -5
  50. package/lib/esm/curve/CurveOps.d.ts.map +1 -1
  51. package/lib/esm/curve/CurveOps.js +2 -5
  52. package/lib/esm/curve/CurveOps.js.map +1 -1
  53. package/lib/esm/curve/Query/PlanarSubdivision.d.ts +50 -15
  54. package/lib/esm/curve/Query/PlanarSubdivision.d.ts.map +1 -1
  55. package/lib/esm/curve/Query/PlanarSubdivision.js +102 -84
  56. package/lib/esm/curve/Query/PlanarSubdivision.js.map +1 -1
  57. package/lib/esm/curve/RegionOps.d.ts +44 -25
  58. package/lib/esm/curve/RegionOps.d.ts.map +1 -1
  59. package/lib/esm/curve/RegionOps.js +72 -37
  60. package/lib/esm/curve/RegionOps.js.map +1 -1
  61. package/lib/esm/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
  62. package/lib/esm/curve/RegionOpsClassificationSweeps.js +8 -8
  63. package/lib/esm/curve/RegionOpsClassificationSweeps.js.map +1 -1
  64. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts +1 -0
  65. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.d.ts.map +1 -1
  66. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js +102 -92
  67. package/lib/esm/curve/internalContexts/CurveCurveIntersectXY.js.map +1 -1
  68. package/lib/esm/geometry3d/GrowableXYArray.d.ts +2 -1
  69. package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
  70. package/lib/esm/geometry3d/GrowableXYArray.js +2 -1
  71. package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
  72. package/lib/esm/geometry3d/GrowableXYZArray.d.ts +2 -1
  73. package/lib/esm/geometry3d/GrowableXYZArray.d.ts.map +1 -1
  74. package/lib/esm/geometry3d/GrowableXYZArray.js +2 -1
  75. package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
  76. package/lib/esm/geometry3d/IndexedXYZCollection.d.ts +9 -16
  77. package/lib/esm/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
  78. package/lib/esm/geometry3d/IndexedXYZCollection.js +3 -3
  79. package/lib/esm/geometry3d/IndexedXYZCollection.js.map +1 -1
  80. package/lib/esm/geometry3d/PolylineOps.d.ts +2 -2
  81. package/lib/esm/geometry3d/PolylineOps.js +2 -2
  82. package/lib/esm/geometry3d/PolylineOps.js.map +1 -1
  83. package/lib/esm/numerics/ClusterableArray.d.ts.map +1 -1
  84. package/lib/esm/numerics/ClusterableArray.js +2 -2
  85. package/lib/esm/numerics/ClusterableArray.js.map +1 -1
  86. package/lib/esm/topology/Merging.d.ts +15 -7
  87. package/lib/esm/topology/Merging.d.ts.map +1 -1
  88. package/lib/esm/topology/Merging.js +15 -10
  89. package/lib/esm/topology/Merging.js.map +1 -1
  90. package/package.json +3 -3
@@ -262,7 +262,9 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
262
262
  // The fraction and extend parameters allow all combinations to be passed in.
263
263
  dispatchSegmentArc(cpA, extendA0, pointA0, fractionA0, pointA1, fractionA1, extendA1, arc, extendB0, extendB1, reversed) {
264
264
  const tol2 = this._coincidentGeometryContext.tolerance * this._coincidentGeometryContext.tolerance;
265
- let dist2;
265
+ const cosines = new GrowableFloat64Array(2);
266
+ const sines = new GrowableFloat64Array(2);
267
+ const radians = new GrowableFloat64Array(2);
266
268
  // Arc: X = C + cU + sV
267
269
  // Line: contains points A0,A1
268
270
  // Arc point colinear with line if det (A0, A1, X) = 0
@@ -282,27 +284,30 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
282
284
  const alpha = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.center);
283
285
  const beta = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.vector0);
284
286
  const gamma = Geometry.tripleProductPoint4dXYW(pointA0H, pointA1H, data.vector90);
285
- const cosines = new GrowableFloat64Array(2);
286
- const sines = new GrowableFloat64Array(2);
287
- const radians = new GrowableFloat64Array(2);
288
- const numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians);
289
- if (numRoots <= 0)
290
- return;
287
+ let numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians);
288
+ const closeApproach = (0 === numRoots);
289
+ if (closeApproach)
290
+ numRoots = 1; // we returned the arc's closest approach as the first "root"; if within tolerance and at endpoints, we record it
291
+ const acceptSolution = (iRoot, checkOnlyEndPointDistance = false) => {
292
+ const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(iRoot), data.vector90, sines.atUncheckedIndex(iRoot));
293
+ let fArc = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(iRoot), extendB0);
294
+ let fLine = SmallSystem.lineSegment3dHXYClosestPointUnbounded(pointA0H, pointA1H, arcPoint);
295
+ if (fLine === undefined)
296
+ return undefined;
297
+ if (!checkOnlyEndPointDistance && this.acceptFraction(extendA0, fLine, extendA1) && this.acceptFraction(extendB0, fArc, extendB1))
298
+ return { fLine, fArc };
299
+ // check for an endpoint intersection that is beyond parametric tolerance but within point tolerance
300
+ fLine = fLine < 0.5 ? 0 : 1;
301
+ fArc = data.sweep.fractionToSignedPeriodicFraction(fArc) < 0.5 ? 0 : 1;
302
+ const pointAH = fLine ? pointA1H : pointA0H;
303
+ const pointBH = fArc ? pointB1H : pointB0H;
304
+ const dist2 = pointAH.realDistanceSquaredXY(pointBH);
305
+ return (dist2 !== undefined && Geometry.isDistanceWithinTol(dist2, tol2)) ? { fLine, fArc } : undefined;
306
+ };
291
307
  for (let i = 0; i < numRoots; i++) {
292
- const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
293
- let arcFraction = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(i), extendB0);
294
- const lineFraction = SmallSystem.lineSegment3dHXYClosestPointUnbounded(pointA0H, pointA1H, arcPoint);
295
- if (lineFraction !== undefined) {
296
- if (this.acceptFraction(extendA0, lineFraction, extendA1) && this.acceptFraction(extendB0, arcFraction, extendB1)) {
297
- this.recordPointWithLocalFractions(lineFraction, cpA, fractionA0, fractionA1, arcFraction, arc, 0, 1, reversed);
298
- }
299
- else { // check for endpoint intersections beyond parametric tolerance but within point tolerance
300
- const pointAH = lineFraction < 0.5 ? pointA0H : pointA1H;
301
- const pointBH = (arcFraction = data.sweep.fractionToSignedPeriodicFraction(arcFraction)) < 0.5 ? pointB0H : pointB1H;
302
- if ((dist2 = pointAH.realDistanceSquaredXY(pointBH)) !== undefined && Geometry.isDistanceWithinTol(dist2, tol2))
303
- this.recordPointWithLocalFractions(lineFraction < 0.5 ? 0 : 1, cpA, fractionA0, fractionA1, arcFraction < 0.5 ? 0 : 1, arc, 0, 1, reversed);
304
- }
305
- }
308
+ const result = acceptSolution(i, closeApproach);
309
+ if (result)
310
+ this.recordPointWithLocalFractions(result.fLine, cpA, fractionA0, fractionA1, result.fArc, arc, 0, 1, reversed);
306
311
  }
307
312
  }
308
313
  else {
@@ -320,27 +325,30 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
320
325
  const alpha = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.center, 1);
321
326
  const beta = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector0, 0);
322
327
  const gamma = Geometry.tripleProductXYW(pointA0Local, 1, pointA1Local, 1, data.vector90, 0);
323
- const cosines = new GrowableFloat64Array(2);
324
- const sines = new GrowableFloat64Array(2);
325
- const radians = new GrowableFloat64Array(2);
326
- const numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians);
327
- if (numRoots <= 0)
328
- return;
328
+ let numRoots = AnalyticRoots.appendImplicitLineUnitCircleIntersections(alpha, beta, gamma, cosines, sines, radians);
329
+ const closeApproach = (0 === numRoots);
330
+ if (closeApproach)
331
+ numRoots = 1; // we returned the arc's closest approach as the first "root"; if within tolerance and at endpoints, we record it
332
+ const acceptSolution = (iRoot, checkOnlyEndPointDistance = false) => {
333
+ const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(iRoot), data.vector90, sines.atUncheckedIndex(iRoot));
334
+ let fArc = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(iRoot), extendB0);
335
+ let fLine = SmallSystem.lineSegment3dXYClosestPointUnbounded(pointA0Local, pointA1Local, arcPoint);
336
+ if (fLine === undefined)
337
+ return undefined;
338
+ if (!checkOnlyEndPointDistance && this.acceptFraction(extendA0, fLine, extendA1) && this.acceptFraction(extendB0, fArc, extendB1))
339
+ return { fLine, fArc };
340
+ // check for an endpoint intersection that is beyond parametric tolerance but within point tolerance
341
+ fLine = fLine < 0.5 ? 0 : 1;
342
+ fArc = data.sweep.fractionToSignedPeriodicFraction(fArc) < 0.5 ? 0 : 1;
343
+ const pointALocal = fLine ? pointA1Local : pointA0Local;
344
+ const pointBLocal = fArc ? pointB1Local : pointB0Local;
345
+ const dist2 = pointALocal.distanceSquaredXY(pointBLocal);
346
+ return Geometry.isDistanceWithinTol(dist2, tol2) ? { fLine, fArc } : undefined;
347
+ };
329
348
  for (let i = 0; i < numRoots; i++) {
330
- const arcPoint = data.center.plus2Scaled(data.vector0, cosines.atUncheckedIndex(i), data.vector90, sines.atUncheckedIndex(i));
331
- let arcFraction = data.sweep.radiansToSignedFraction(radians.atUncheckedIndex(i), extendB0);
332
- const lineFraction = SmallSystem.lineSegment3dXYClosestPointUnbounded(pointA0Local, pointA1Local, arcPoint);
333
- if (lineFraction !== undefined) {
334
- if (this.acceptFraction(extendA0, lineFraction, extendA1) && this.acceptFraction(extendB0, arcFraction, extendB1)) {
335
- this.recordPointWithLocalFractions(lineFraction, cpA, fractionA0, fractionA1, arcFraction, arc, 0, 1, reversed);
336
- }
337
- else { // check for endpoint intersections beyond parametric tolerance but within point tolerance
338
- const pointALocal = lineFraction < 0.5 ? pointA0Local : pointA1Local;
339
- const pointBLocal = (arcFraction = data.sweep.fractionToSignedPeriodicFraction(arcFraction)) < 0.5 ? pointB0Local : pointB1Local;
340
- if ((dist2 = pointALocal.distanceSquaredXY(pointBLocal)) !== undefined && Geometry.isDistanceWithinTol(dist2, tol2))
341
- this.recordPointWithLocalFractions(lineFraction < 0.5 ? 0 : 1, cpA, fractionA0, fractionA1, arcFraction < 0.5 ? 0 : 1, arc, 0, 1, reversed);
342
- }
343
- }
349
+ const result = acceptSolution(i, closeApproach);
350
+ if (result)
351
+ this.recordPointWithLocalFractions(result.fLine, cpA, fractionA0, fractionA1, result.fArc, arc, 0, 1, reversed);
344
352
  }
345
353
  }
346
354
  }
@@ -363,12 +371,23 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
363
371
  localB.coffs[0], localB.coffs[3], localB.coffs[6], // vector0 xyw
364
372
  localB.coffs[1], localB.coffs[4], localB.coffs[7], // vector90 xyw
365
373
  ellipseRadians, circleRadians);
374
+ const tol2 = this._coincidentGeometryContext.tolerance * this._coincidentGeometryContext.tolerance;
366
375
  // the intersections are transform-invariant, so the solution angles apply directly to the input arcs
367
376
  for (let i = 0; i < ellipseRadians.length; i++) {
368
- const fractionA = cpA.sweep.radiansToSignedFraction(circleRadians[i], extendA0);
369
- const fractionB = cpB.sweep.radiansToSignedFraction(ellipseRadians[i], extendB0);
370
- if (this.acceptFraction(extendA0, fractionA, extendA1) && this.acceptFraction(extendB0, fractionB, extendB1))
377
+ let fractionA = cpA.sweep.radiansToSignedFraction(circleRadians[i], extendA0);
378
+ let fractionB = cpB.sweep.radiansToSignedFraction(ellipseRadians[i], extendB0);
379
+ if (this.acceptFraction(extendA0, fractionA, extendA1) && this.acceptFraction(extendB0, fractionB, extendB1)) {
371
380
  this.recordPointWithLocalFractions(fractionA, cpA, 0, 1, fractionB, cpB, 0, 1, reversed);
381
+ }
382
+ else { // check for endpoint intersection beyond angular tolerance but within point tolerance
383
+ fractionA = cpA.sweep.fractionToSignedPeriodicFraction(fractionA) < 0.5 ? 0 : 1;
384
+ fractionB = cpB.sweep.fractionToSignedPeriodicFraction(fractionB) < 0.5 ? 0 : 1;
385
+ const endPointA = cpA.fractionToPoint(fractionA, CurveCurveIntersectXY._workPointAA0);
386
+ const endPointB = cpB.fractionToPoint(fractionB, CurveCurveIntersectXY._workPointBB0);
387
+ const dist2 = endPointA.distanceSquaredXY(endPointB);
388
+ if (Geometry.isDistanceWithinTol(dist2, tol2))
389
+ this.recordPointWithLocalFractions(fractionA, cpA, 0, 1, fractionB, cpB, 0, 1, reversed);
390
+ }
372
391
  }
373
392
  }
374
393
  }
@@ -381,6 +400,15 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
381
400
  * 5- Convert intersection angles to fractions and record intersections.
382
401
  */
383
402
  dispatchArcArc(cpA, extendA0, extendA1, cpB, extendB0, extendB1, reversed) {
403
+ // overlap handling. perspective is not handled.
404
+ if (this._coincidentGeometryContext && !this._worldToLocalPerspective && !this._worldToLocalAffine) {
405
+ const pairs = this._coincidentGeometryContext.coincidentArcIntersectionXY(cpA, cpB, true);
406
+ if (pairs) {
407
+ this.recordPairs(cpA, cpB, pairs, reversed);
408
+ return;
409
+ }
410
+ }
411
+ // look for isolated intersections
384
412
  let matrixA;
385
413
  let matrixB;
386
414
  if (this._worldToLocalPerspective) {
@@ -397,27 +425,13 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
397
425
  }
398
426
  const conditionA = matrixA.conditionNumber();
399
427
  const conditionB = matrixB.conditionNumber();
400
- // pick the arc that is closest to circular.
428
+ // order the arcs so that the first one we pass in is closer to circular
401
429
  if (conditionA > conditionB)
402
430
  this.dispatchArcArcThisOrder(cpA, matrixA, extendA0, extendA1, cpB, matrixB, extendB0, extendB1, reversed);
403
431
  else
404
432
  this.dispatchArcArcThisOrder(cpB, matrixB, extendB0, extendB1, cpA, matrixA, extendA0, extendA1, !reversed);
405
- // overlap handling. perspective is not handled.
406
- if (!this._coincidentGeometryContext) {
407
- // do nothing
408
- }
409
- else if (this._worldToLocalPerspective) {
410
- // do nothing
411
- }
412
- else if (this._worldToLocalAffine) {
413
- // do nothing
414
- }
415
- else {
416
- const pairs = this._coincidentGeometryContext.coincidentArcIntersectionXY(cpA, cpB, true);
417
- if (pairs !== undefined)
418
- this.recordPairs(cpA, cpB, pairs, reversed);
419
- }
420
433
  }
434
+ /** Compute the intersection of an arc and a B-spline curve. */
421
435
  dispatchArcBsplineCurve3d(cpA, extendA0, extendA1, cpB, extendB0, extendB1, reversed) {
422
436
  // Arc: X = C + cU + sV
423
437
  // implicitize the arc as viewed. This "3d" matrix is homogeneous "XYW" not "xyz"
@@ -432,8 +446,6 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
432
446
  }
433
447
  // The worldToLocal has moved the arc vectors into local space.
434
448
  // matrixA captures the xyw parts (ignoring z)
435
- // for any point in world space,
436
- // THIS CODE ONLY WORKS FOR
437
449
  const matrixAInverse = matrixA.inverse();
438
450
  if (matrixAInverse) {
439
451
  const orderF = cpB.order; // order of the beziers for simple coordinates
@@ -452,36 +464,34 @@ export class CurveCurveIntersectXY extends RecurseToCurvesGeometryHandler {
452
464
  const awy = matrixAInverse.at(2, 1);
453
465
  const awz = 0.0;
454
466
  const aww = matrixAInverse.at(2, 2);
455
- if (matrixAInverse) {
456
- let bezier;
457
- for (let spanIndex = 0;; spanIndex++) {
458
- bezier = cpB.getSaturatedBezierSpan3dH(spanIndex, bezier);
459
- if (!bezier)
460
- break;
461
- if (this._worldToLocalPerspective)
462
- bezier.tryMultiplyMatrix4dInPlace(this._worldToLocalPerspective);
463
- else if (this._worldToLocalAffine)
464
- bezier.tryTransformInPlace(this._worldToLocalAffine);
465
- univariateBezierG.zero();
466
- bezier.poleProductsXYZW(coffF, axx, axy, axz, axw);
467
- univariateBezierG.addSquaredSquaredBezier(coffF, 1.0);
468
- bezier.poleProductsXYZW(coffF, ayx, ayy, ayz, ayw);
469
- univariateBezierG.addSquaredSquaredBezier(coffF, 1.0);
470
- bezier.poleProductsXYZW(coffF, awx, awy, awz, aww);
471
- univariateBezierG.addSquaredSquaredBezier(coffF, -1.0);
472
- const roots = univariateBezierG.roots(0.0, true);
473
- if (roots) {
474
- for (const root of roots) {
475
- const fractionB = bezier.fractionToParentFraction(root);
476
- // The univariate bezier (which has been transformed by the view transform) evaluates into xyw space
477
- const bcurvePoint4d = bezier.fractionToPoint4d(root);
478
- const c = bcurvePoint4d.dotProductXYZW(axx, axy, axz, axw);
479
- const s = bcurvePoint4d.dotProductXYZW(ayx, ayy, ayz, ayw);
480
- const arcFraction = cpA.sweep.radiansToSignedFraction(Math.atan2(s, c), extendA0);
481
- if (this.acceptFraction(extendA0, arcFraction, extendA1) &&
482
- this.acceptFraction(extendB0, fractionB, extendB1)) {
483
- this.recordPointWithLocalFractions(arcFraction, cpA, 0, 1, fractionB, cpB, 0, 1, reversed);
484
- }
467
+ let bezier;
468
+ for (let spanIndex = 0;; spanIndex++) {
469
+ bezier = cpB.getSaturatedBezierSpan3dH(spanIndex, bezier);
470
+ if (!bezier)
471
+ break;
472
+ if (this._worldToLocalPerspective)
473
+ bezier.tryMultiplyMatrix4dInPlace(this._worldToLocalPerspective);
474
+ else if (this._worldToLocalAffine)
475
+ bezier.tryTransformInPlace(this._worldToLocalAffine);
476
+ univariateBezierG.zero();
477
+ bezier.poleProductsXYZW(coffF, axx, axy, axz, axw);
478
+ univariateBezierG.addSquaredSquaredBezier(coffF, 1.0);
479
+ bezier.poleProductsXYZW(coffF, ayx, ayy, ayz, ayw);
480
+ univariateBezierG.addSquaredSquaredBezier(coffF, 1.0);
481
+ bezier.poleProductsXYZW(coffF, awx, awy, awz, aww);
482
+ univariateBezierG.addSquaredSquaredBezier(coffF, -1.0);
483
+ const roots = univariateBezierG.roots(0.0, true);
484
+ if (roots) {
485
+ for (const root of roots) {
486
+ const fractionB = bezier.fractionToParentFraction(root);
487
+ // The univariate bezier (which has been transformed by the view transform) evaluates into xyw space
488
+ const bcurvePoint4d = bezier.fractionToPoint4d(root);
489
+ const c = bcurvePoint4d.dotProductXYZW(axx, axy, axz, axw);
490
+ const s = bcurvePoint4d.dotProductXYZW(ayx, ayy, ayz, ayw);
491
+ const arcFraction = cpA.sweep.radiansToSignedFraction(Math.atan2(s, c), extendA0);
492
+ if (this.acceptFraction(extendA0, arcFraction, extendA1) &&
493
+ this.acceptFraction(extendB0, fractionB, extendB1)) {
494
+ this.recordPointWithLocalFractions(arcFraction, cpA, 0, 1, fractionB, cpB, 0, 1, reversed);
485
495
  }
486
496
  }
487
497
  }