|
|
@ -605,53 +605,14 @@ export function handleCloseUpDisplay(p, plotScales) { |
|
|
export function drawCovarianceEllipse( |
|
|
export function drawCovarianceEllipse( |
|
|
p, |
|
|
p, |
|
|
position, |
|
|
position, |
|
|
covarianceP, |
|
|
|
|
|
|
|
|
radii, |
|
|
|
|
|
angle, |
|
|
plotScales, |
|
|
plotScales, |
|
|
isStationary |
|
|
isStationary |
|
|
) { |
|
|
) { |
|
|
// Only draw the ellipse for tracks that are not stationary.
|
|
|
// Only draw the ellipse for tracks that are not stationary.
|
|
|
if (isStationary) return; |
|
|
if (isStationary) return; |
|
|
|
|
|
|
|
|
const pPos = [ |
|
|
|
|
|
[covarianceP[0][0], covarianceP[0][1]], |
|
|
|
|
|
[covarianceP[1][0], covarianceP[1][1]], |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const a = pPos[0][0]; |
|
|
|
|
|
const b = pPos[0][1]; |
|
|
|
|
|
const d = pPos[1][1]; |
|
|
|
|
|
const trace = a + d; |
|
|
|
|
|
const determinant = a * d - b * b; |
|
|
|
|
|
|
|
|
|
|
|
//const lambda1 = trace / 2 + Math.sqrt(Math.pow(trace, 2) / 4 - determinant);
|
|
|
|
|
|
//const lambda2 = trace / 2 - Math.sqrt(Math.pow(trace, 2) / 4 - determinant);
|
|
|
|
|
|
// --- START: New robust calculation with logging ---
|
|
|
|
|
|
let sqrtTermVal = Math.pow(trace, 2) / 4 - determinant; |
|
|
|
|
|
|
|
|
|
|
|
// Check for a negative value, which causes NaN errors
|
|
|
|
|
|
if (sqrtTermVal < 0) { |
|
|
|
|
|
// Log a warning so we know it happened, as you suggested
|
|
|
|
|
|
console.warn( |
|
|
|
|
|
`Clamping negative sqrtTermVal in frame ${appState.currentFrame} to prevent NaN. Original value: ${sqrtTermVal}` |
|
|
|
|
|
); |
|
|
|
|
|
// Clamp the value to 0. This allows drawing to continue instead of breaking.
|
|
|
|
|
|
sqrtTermVal = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const sqrtTerm = Math.sqrt(sqrtTermVal); |
|
|
|
|
|
const lambda1 = trace / 2 + sqrtTerm; |
|
|
|
|
|
const lambda2 = trace / 2 - sqrtTerm; |
|
|
|
|
|
// --- END: New robust calculation with logging ---
|
|
|
|
|
|
const chi2 = 5.991; |
|
|
|
|
|
const majorAxis = Math.sqrt(chi2 * lambda1); |
|
|
|
|
|
const minorAxis = Math.sqrt(chi2 * lambda2); |
|
|
|
|
|
|
|
|
|
|
|
let eigenvector = [1, 0]; |
|
|
|
|
|
if (b !== 0) { |
|
|
|
|
|
eigenvector = [lambda1 - d, b]; |
|
|
|
|
|
} |
|
|
|
|
|
const angle = Math.atan2(eigenvector[1], eigenvector[0]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [radiusA, radiusB] = radii; |
|
|
p.push(); |
|
|
p.push(); |
|
|
p.noFill(); |
|
|
p.noFill(); |
|
|
p.stroke(255, 0, 0, 150); |
|
|
p.stroke(255, 0, 0, 150); |
|
|
@ -661,13 +622,53 @@ export function drawCovarianceEllipse( |
|
|
position[1] * plotScales.plotScaleY |
|
|
position[1] * plotScales.plotScaleY |
|
|
); |
|
|
); |
|
|
p.rotate(angle); |
|
|
p.rotate(angle); |
|
|
p.ellipse( |
|
|
|
|
|
0, |
|
|
|
|
|
0, |
|
|
|
|
|
majorAxis * 2 * plotScales.plotScaleX, |
|
|
|
|
|
minorAxis * 2 * plotScales.plotScaleY |
|
|
|
|
|
|
|
|
p.ellipse(0,0, |
|
|
|
|
|
radiusA * 2 * plotScales.plotScaleX, // multiplied by 2 because ellipse function
|
|
|
|
|
|
radiusB * 2 * plotScales.plotScaleY // in p5 library expect
|
|
|
); |
|
|
); |
|
|
p.pop(); |
|
|
p.pop(); |
|
|
|
|
|
|
|
|
|
|
|
//---old ellipse logic using covariance from data directly//
|
|
|
|
|
|
// const pPos = [
|
|
|
|
|
|
// [covarianceP[0][0], covarianceP[0][1]],
|
|
|
|
|
|
// [covarianceP[1][0], covarianceP[1][1]],
|
|
|
|
|
|
// ];
|
|
|
|
|
|
|
|
|
|
|
|
// const a = pPos[0][0];
|
|
|
|
|
|
// const b = pPos[0][1];
|
|
|
|
|
|
// const d = pPos[1][1];
|
|
|
|
|
|
// const trace = a + d;
|
|
|
|
|
|
// const determinant = a * d - b * b;
|
|
|
|
|
|
|
|
|
|
|
|
//const lambda1 = trace / 2 + Math.sqrt(Math.pow(trace, 2) / 4 - determinant);
|
|
|
|
|
|
//const lambda2 = trace / 2 - Math.sqrt(Math.pow(trace, 2) / 4 - determinant);
|
|
|
|
|
|
// --- START: New robust calculation with logging ---
|
|
|
|
|
|
// let sqrtTermVal = Math.pow(trace, 2) / 4 - determinant;
|
|
|
|
|
|
|
|
|
|
|
|
// Check for a negative value, which causes NaN errors
|
|
|
|
|
|
// if (sqrtTermVal < 0) {
|
|
|
|
|
|
// // Log a warning so we know it happened, as you suggested
|
|
|
|
|
|
// console.warn(
|
|
|
|
|
|
// `Clamping negative sqrtTermVal in frame ${appState.currentFrame} to prevent NaN. Original value: ${sqrtTermVal}`
|
|
|
|
|
|
// );
|
|
|
|
|
|
// // Clamp the value to 0. This allows drawing to continue instead of breaking.
|
|
|
|
|
|
// sqrtTermVal = 0;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// const sqrtTerm = Math.sqrt(sqrtTermVal);
|
|
|
|
|
|
// const lambda1 = trace / 2 + sqrtTerm;
|
|
|
|
|
|
// const lambda2 = trace / 2 - sqrtTerm;
|
|
|
|
|
|
// // --- END: New robust calculation with logging ---
|
|
|
|
|
|
// const chi2 = 5.991;
|
|
|
|
|
|
// const majorAxis = Math.sqrt(chi2 * lambda1);
|
|
|
|
|
|
// const minorAxis = Math.sqrt(chi2 * lambda2);
|
|
|
|
|
|
|
|
|
|
|
|
// let eigenvector = [1, 0];
|
|
|
|
|
|
// if (b !== 0) {
|
|
|
|
|
|
// eigenvector = [lambda1 - d, b];
|
|
|
|
|
|
// }
|
|
|
|
|
|
// const angle = Math.atan2(eigenvector[1], eigenvector[0]);
|
|
|
|
|
|
//---old ellipse logic using covariance from data directly//
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// In src/drawUtils.js
|
|
|
// In src/drawUtils.js
|
|
|
|