Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion common/api/core-geometry.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1711,7 +1711,7 @@ export class CurveLocationDetail {
isSameCurveAndFraction(other: CurveLocationDetail | {
curve: CurvePrimitive;
fraction: number;
}): boolean;
}, fractionTol?: number): boolean;
point: Point3d;
point1?: Point3d;
pointQ: Point3d;
Expand Down Expand Up @@ -2224,6 +2224,7 @@ export class Geometry {
static isSameCoordinateSquared(x: number, y: number, tolerance?: number): boolean;
static isSameCoordinateWithToleranceFactor(x: number, y: number, toleranceFactor: number): boolean;
static isSameCoordinateXY(x0: number, y0: number, x1: number, y1: number, tolerance?: number): boolean;
static isSameFraction(x: number, y: number, tolerance?: number): boolean;
static isSamePoint2d(dataA: Point2d, dataB: Point2d, tolerance?: number): boolean;
static isSamePoint3d(dataA: Point3d, dataB: Point3d, tolerance?: number): boolean;
static isSamePoint3dXY(dataA: Point3d, dataB: Point3d, tolerance?: number): boolean;
Expand Down
9 changes: 9 additions & 0 deletions core/geometry/src/Geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,15 @@ export class Geometry {
d = -d;
return d <= tolerance;
}
/**
* Toleranced test for equivalent fractions.
* @param x first fraction to compare
* @param y second fraction to compare
* @param tolerance maximum difference between fractions considered equivalent, defaulting to [[smallFraction]].
*/
public static isSameFraction(x: number, y: number, tolerance: number = Geometry.smallFraction): boolean {
return this.isSameCoordinate(x, y, tolerance);
}
/**
* Boolean test for metric coordinate near-equality (i.e., if `x` and `y` are almost equal) using
* `tolerance = toleranceFactor * smallMetricDistance`
Expand Down
2 changes: 1 addition & 1 deletion core/geometry/src/curve/CurveCurve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class CurveCurve {
for (let i = 0; i < primitives.length; i++) {
const curveA = primitives[i];
for (let j = i + 1; j < primitives.length; j++) {
handler.resetGeometry(primitives[j]);
handler.resetGeometryB(primitives[j]);
curveA.dispatchToGeometryHandler(handler);
}
}
Expand Down
9 changes: 6 additions & 3 deletions core/geometry/src/curve/CurveLocationDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,12 @@ export class CurveLocationDetail {
}
return detailB;
}
/** Compare only the curve and fraction of this detail with `other`. */
public isSameCurveAndFraction(other: CurveLocationDetail | { curve: CurvePrimitive, fraction: number }): boolean {
return this.curve === other.curve && Geometry.isAlmostEqualNumber(this.fraction, other.fraction);
/**
* Compare only the curve and fraction of this detail with `other`.
* @param fractionTol optional relative tolerance for comparing fractions with [[Geometry.isAlmostEqualNumber]].
*/
public isSameCurveAndFraction(other: CurveLocationDetail | { curve: CurvePrimitive, fraction: number }, fractionTol?: number): boolean {
return this.curve === other.curve && Geometry.isAlmostEqualNumber(this.fraction, other.fraction, fractionTol);
}
/**
* Transform the detail in place.
Expand Down
3 changes: 2 additions & 1 deletion core/geometry/src/curve/CurvePrimitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,9 @@ export abstract class CurvePrimitive extends GeometryQuery {
public abstract fractionToPointAndDerivative(fraction: number, result?: Ray3d): Ray3d;
/**
* Returns a ray whose origin is the curve point and direction is the unit tangent.
* @param fraction fractional position on the curve
* @param fraction fractional position on the curve.
* @param result optional preallocated ray.
* @returns tangent ray with normalized direction or zero vector if the derivative vanishes.
*/
public fractionToPointAndUnitTangent(fraction: number, result?: Ray3d): Ray3d {
const ray = this.fractionToPointAndDerivative(fraction, result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export class ClosestPointStrokeHandler extends NewtonRtoRStrokeHandler implement
this._workPoint = Point3d.create();
this._workRay = Ray3d.createZero();
this._closestPoint = result;
if (this._closestPoint)
this._closestPoint.a = Geometry.largeCoordinateResult
this._extend = extend ?? false;
this.startCurvePrimitive(undefined);
this._newtonSolver = new Newton1dUnboundedApproximateDerivative(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ export class CurveCurveCloseApproachXY extends RecurseToCurvesGeometryHandler {
): void {
const d2 = pointA.distanceSquaredXY(pointB);
if (d2 < this._maxDistanceSquared) {
const detailA = CurveLocationDetail.createCurveFractionPoint(cpA, fA, pointA);
const detailB = CurveLocationDetail.createCurveFractionPoint(cpB, fB, pointB);
const d = Math.sqrt(d2);
const detailA = CurveLocationDetail.createCurveFractionPointDistance(cpA, fA, pointA, d);
const detailB = CurveLocationDetail.createCurveFractionPointDistance(cpB, fB, pointB, d);
const pair = CurveLocationDetailPair.createCapture(detailA, detailB);
if (reversed)
pair.swapDetails();
Expand All @@ -143,7 +144,6 @@ export class CurveCurveCloseApproachXY extends RecurseToCurvesGeometryHandler {
* @param fractionB0 start of the second curve
* @param fractionB1 end of the second curve
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
* @param intervalDetails optional CurveLocationDetailPair
*/
private recordPointWithLocalFractions(
localFractionA: number,
Expand All @@ -155,25 +155,12 @@ export class CurveCurveCloseApproachXY extends RecurseToCurvesGeometryHandler {
fractionB0: number,
fractionB1: number,
reversed: boolean,
intervalDetails?: undefined | CurveLocationDetailPair,
): void {
let globalFractionA, globalFractionB;
let globalFractionA1, globalFractionB1;
const isInterval = intervalDetails !== undefined &&
intervalDetails.detailA.hasFraction1 &&
intervalDetails.detailB.hasFraction1;
if (isInterval) {
globalFractionA = Geometry.interpolate(fractionA0, intervalDetails.detailA.fraction, fractionA1);
globalFractionB = Geometry.interpolate(fractionB0, intervalDetails.detailB.fraction, fractionB1);
globalFractionA1 = Geometry.interpolate(fractionA0, intervalDetails.detailA.fraction1!, fractionA1);
globalFractionB1 = Geometry.interpolate(fractionB0, intervalDetails.detailB.fraction1!, fractionB1);
} else {
globalFractionA = globalFractionA1 = Geometry.interpolate(fractionA0, localFractionA, fractionA1);
globalFractionB = globalFractionB1 = Geometry.interpolate(fractionB0, localFractionB, fractionB1);
}
const globalFractionA = Geometry.interpolate(fractionA0, localFractionA, fractionA1);
const globalFractionB = Geometry.interpolate(fractionB0, localFractionB, fractionB1);
// ignore duplicate of most recent approach
const numPrevious = this._results.length;
if (numPrevious > 0 && !isInterval) {
if (numPrevious > 0) {
const oldDetailA = this._results[numPrevious - 1].detailA;
const oldDetailB = this._results[numPrevious - 1].detailB;
if (reversed) {
Expand All @@ -186,27 +173,20 @@ export class CurveCurveCloseApproachXY extends RecurseToCurvesGeometryHandler {
return;
}
}
const detailA = CurveLocationDetail.createCurveFractionPoint(
cpA, globalFractionA, cpA.fractionToPoint(globalFractionA),
);
const detailB = CurveLocationDetail.createCurveFractionPoint(
cpB, globalFractionB, cpB.fractionToPoint(globalFractionB),
);
if (isInterval) {
detailA.captureFraction1Point1(globalFractionA1, cpA.fractionToPoint(globalFractionA1));
detailB.captureFraction1Point1(globalFractionB1, cpB.fractionToPoint(globalFractionB1));
} else {
const d2 = detailA.point.distanceSquaredXY(detailB.point);
if (d2 > this._maxDistanceSquared)
return;
detailA.setIntervalRole(CurveIntervalRole.isolated);
detailB.setIntervalRole(CurveIntervalRole.isolated);
}
if (reversed) {
const pointA = cpA.fractionToPoint(globalFractionA);
const pointB = cpB.fractionToPoint(globalFractionB);
const d2 = pointA.distanceSquaredXY(pointB);
if (d2 > this._maxDistanceSquared)
return;
const d = Math.sqrt(d2);
const detailA = CurveLocationDetail.createCurveFractionPointDistance(cpA, globalFractionA, pointA, d);
const detailB = CurveLocationDetail.createCurveFractionPointDistance(cpB, globalFractionB, pointB, d);
detailA.setIntervalRole(CurveIntervalRole.isolated);
detailB.setIntervalRole(CurveIntervalRole.isolated);
if (reversed)
this._results.push(new CurveLocationDetailPair(detailB, detailA));
} else {
else
this._results.push(new CurveLocationDetailPair(detailA, detailB));
}
}
/**
* Capture a close approach pair that has point and local fraction but not curve.
Expand Down Expand Up @@ -251,47 +231,13 @@ export class CurveCurveCloseApproachXY extends RecurseToCurvesGeometryHandler {
// recompute the points just in case
CurveLocationDetail.createCurveEvaluatedFraction(cpA, globalFractionA, pair.detailA);
CurveLocationDetail.createCurveEvaluatedFraction(cpB, globalFractionB, pair.detailB);
pair.detailA.a = pair.detailB.a = pair.detailA.point.distanceXY(pair.detailB.point);
pair.detailA.setIntervalRole(CurveIntervalRole.isolated);
pair.detailB.setIntervalRole(CurveIntervalRole.isolated);
if (reversed)
pair.swapDetails();
this._results.push(pair);
}
/**
* Emit recordPoint for multiple pairs (on full curve) if within maxDistance.
* @param cpA first curve primitive (possibly different from curve in detailA, but fraction compatible)
* @param cpB second curve primitive (possibly different from curve in detailA, but fraction compatible)
* @param pairs array of pairs
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
*/
public recordPairs(
cpA: CurvePrimitive, cpB: CurvePrimitive, pairs: CurveLocationDetailPair[] | undefined, reversed: boolean,
): void {
if (pairs !== undefined) {
for (const p of pairs) {
this.recordPointWithLocalFractions(
p.detailA.fraction, cpA, 0, 1, p.detailB.fraction, cpB, 0, 1, reversed, p,
);
}
}
}
/**
* Record fully assembled (but possibly reversed) detail pair.
* @param detailA first detail
* @param detailB second detail
* @param reversed whether to reverse the details in the pair (e.g., so that detailB refers to geometryB).
*/
public captureDetailPair(
detailA: CurveLocationDetail | undefined, detailB: CurveLocationDetail | undefined, reversed: boolean,
): void {
if (detailA && detailB) {
if (reversed) {
this._results.push(CurveLocationDetailPair.createCapture(detailB, detailA));
} else {
this._results.push(CurveLocationDetailPair.createCapture(detailA, detailB));
}
}
}
private static updatePointToSegmentDistance(
fractionA: number,
pointA: Point3d,
Expand Down
Loading
Loading