Compare commits

..

1 Commits

Author SHA1 Message Date
CodeRabbit Fixer
9e8a8ee041 fix: Optimize monotone interpolator by precomputing segment constants (#9111)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:00:45 +01:00

View File

@@ -51,6 +51,17 @@ export function createMonotoneInterpolator(
}
}
const segCount = n - 1
const segDx = new Float64Array(segCount)
const segM0dx = new Float64Array(segCount)
const segM1dx = new Float64Array(segCount)
for (let i = 0; i < segCount; i++) {
const dx = xs[i + 1] - xs[i]
segDx[i] = dx
segM0dx[i] = slopes[i] * dx
segM1dx[i] = slopes[i + 1] * dx
}
return (x: number): number => {
if (x <= xs[0]) return ys[0]
if (x >= xs[n - 1]) return ys[n - 1]
@@ -63,7 +74,7 @@ export function createMonotoneInterpolator(
else hi = mid
}
const dx = xs[hi] - xs[lo]
const dx = segDx[lo]
if (dx === 0) return ys[lo]
const t = (x - xs[lo]) / dx
@@ -75,39 +86,10 @@ export function createMonotoneInterpolator(
const h01 = -2 * t3 + 3 * t2
const h11 = t3 - t2
return (
h00 * ys[lo] +
h10 * dx * slopes[lo] +
h01 * ys[hi] +
h11 * dx * slopes[hi]
)
return h00 * ys[lo] + h10 * segM0dx[lo] + h01 * ys[hi] + h11 * segM1dx[lo]
}
}
function quickSelect(arr: Uint32Array, k: number): number {
let lo = 0
let hi = arr.length - 1
while (lo < hi) {
const pivot = arr[hi]
let i = lo
for (let j = lo; j < hi; j++) {
if (arr[j] <= pivot) {
const tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
i++
}
}
const tmp = arr[i]
arr[i] = arr[hi]
arr[hi] = tmp
if (i === k) return arr[i]
else if (i < k) lo = i + 1
else hi = i - 1
}
return arr[lo]
}
/**
* Convert a 256-bin histogram into an SVG path string.
* Normalizes using the 99.5th percentile to avoid outlier spikes.
@@ -115,8 +97,8 @@ function quickSelect(arr: Uint32Array, k: number): number {
export function histogramToPath(histogram: Uint32Array): string {
if (!histogram.length) return ''
const copy = new Uint32Array(histogram)
const max = quickSelect(copy, Math.floor(255 * 0.995))
const sorted = Array.from(histogram).sort((a, b) => a - b)
const max = sorted[Math.floor(255 * 0.995)]
if (max === 0) return ''
const invMax = 1 / max