@equinor/esv-intersection
Version:
Intersection component package with testing and automatic documentation.
86 lines (82 loc) • 2.4 kB
text/typescript
import Vector2 from '@equinor/videx-vector2';
import { Vector } from 'curve-interpolator/dist/src/core/interfaces';
type fx = (n: number) => Vector;
/*
* Methods for calculating length of a curve
*/
export class ArcLength {
/**
* Calculate using an adaptive bisect method
* @param {Number} func Curve function returning [x,y]
* @param {Number} minLimit Min limit
* @param {Number} maxLimit Max limit
* @param {Number} tolerance Result tolerance
* @param {Number} minDepth Min recursive depth before accepting solution
* @param {Number} maxDepth Max recursive depth
*/
static bisect(
func: fx,
minLimit = 0,
maxLimit = 1,
tolerance = 0.005,
minDepth = 4,
maxDepth = 10,
): number {
const calcRec = (
a: number,
b: number,
aVal: number[],
bVal: number[],
span: number,
tolerance: number,
depth = 0,
): number => {
const mid = (a + b) / 2;
const midVal = func(mid) as number[];
const spanA = Vector2.distance(aVal, midVal);
const spanB = Vector2.distance(midVal, bVal);
const length = spanA + spanB;
if (
(depth >= minDepth && Math.abs(length - span) < tolerance) ||
depth >= maxDepth
) {
return length;
}
const tol = tolerance / 2;
const d = depth + 1;
return (
calcRec(a, mid, aVal, midVal, spanA, tol, d) +
calcRec(mid, b, midVal, bVal, spanB, tol, d)
);
};
const aVal = func(minLimit) as number[];
const bVal = func(maxLimit) as number[];
const span = Vector2.distance(aVal, bVal);
const res = calcRec(minLimit, maxLimit, aVal, bVal, span, tolerance);
return res;
}
/**
* Calculate using trapezoid method
* @param {Number} func Curve function returning [x,y]
* @param {Number} minLimit Min limit
* @param {Number} maxLimit Max limit
* @param {Number} segments Number of segments
*/
static trapezoid(
func: fx,
minLimit = 0,
maxLimit = 1,
segments = 1000,
): number {
let length = 0;
let lastPos = func(minLimit) as number[];
const step = (maxLimit - minLimit) / (segments - 1);
for (let i = 1; i < segments; i++) {
const pos = func(minLimit + i * step) as number[];
const delta = Vector2.distance(lastPos, pos);
length += delta;
lastPos = pos;
}
return length;
}
}