More refactoring

This commit is contained in:
Dominic Ferrando
2025-09-15 11:56:18 -04:00
parent 0ea5a54986
commit 8c523b4e12
+33 -22
View File
@@ -50,6 +50,17 @@ export class LevelCalculator {
return resultLevel; return resultLevel;
} }
findNearestStandards(standards: Standard[], target: number, getValue: (x: Metrics) => number) {
const lowerStandard = [...standards]
.sort((a, b) => getValue(a.metrics) - getValue(b.metrics))
.reverse()
.find((s) => getValue(s.metrics) <= target) ?? standards.at(0)!;
const upperStandard = [...standards]
.sort((a, b) => getValue(a.metrics) - getValue(b.metrics))
.find((s) => getValue(s.metrics) >= target) ?? standards.at(-1)!;
return { lowerStandard, upperStandard };
}
compressLevels( compressLevels(
levels: Levels, levels: Levels,
targetLevelsAmount: number, targetLevelsAmount: number,
@@ -122,25 +133,22 @@ export class LevelCalculator {
return interpolatedLevels; return interpolatedLevels;
} }
interpolateByBodyWeight( interpolateByWeight(
targetAge: number, targetAge: number,
bodyWeightKG: number, targetWeight: number,
standardsArr: Standard[], standards: Standard[],
): Levels | null { ): Levels {
const ageFilteredStandards = standardsArr.filter((s) => s.metrics.age === targetAge); const ageFilteredStandards = standards.filter((s) => s.metrics.age === targetAge);
if (ageFilteredStandards[0].metrics.weight === -1) return ageFilteredStandards[0].levels; if (ageFilteredStandards[0].metrics.weight === -1) return ageFilteredStandards[0].levels;
const weightArray = [...new Set(ageFilteredStandards.map((s) => s.metrics.weight))].sort((a, b) => a - b); const { upperStandard, lowerStandard } = this.findNearestStandards(ageFilteredStandards, targetWeight, m => m.weight);
const { lower, upper } = findNearestPoints(bodyWeightKG, weightArray); const weightLower = lowerStandard.metrics.weight;
const weightUpper = upperStandard.metrics.weight;
const weightLower = ageFilteredStandards.find((s) => s.metrics.weight === lower); let weightRatio = weightUpper === weightLower ? 1 : (targetWeight - weightLower) / (weightUpper - weightLower);
const weightUpper = ageFilteredStandards.find((s) => s.metrics.weight === upper);
if (!weightLower || !weightUpper) return null;
let weightRatio = upper === lower ? 1 : (bodyWeightKG - lower) / (upper - lower);
weightRatio = Math.max(0, Math.min(1, weightRatio)); weightRatio = Math.max(0, Math.min(1, weightRatio));
return this.interpolateLevels(weightLower.levels, weightUpper.levels, weightRatio); return this.interpolateLevels(lowerStandard.levels, upperStandard.levels, weightRatio);
} }
getInterpolatedActivityStandard( getInterpolatedActivityStandard(
@@ -152,27 +160,30 @@ export class LevelCalculator {
levels: {} levels: {}
}; };
// Filter dataset // Filter by gender
const standardsByGender = standards[activity] const standardsByGender = standards[activity]
.filter(a => a.metrics.gender === metrics.gender); .filter(a => a.metrics.gender === metrics.gender);
if (standardsByGender.length === 0) return interpolatedStandard; if (standardsByGender.length === 0) return interpolatedStandard;
// Age interpolation // Find nearest age standards
const ageArray = [...new Set(standardsByGender.map((s) => s.metrics.age))].sort((a, b) => a - b); const { lowerStandard, upperStandard } = this.findNearestStandards(standardsByGender, metrics.age, m => m.age);
const { lower: ageLower, upper: ageUpper } = findNearestPoints(metrics.age, ageArray); const ageLower = lowerStandard.metrics.age;
const ageUpper = upperStandard.metrics.age;
const lowerValues = this.interpolateByBodyWeight(ageLower, metrics.weight, standardsByGender); // Interpolate by weight
const upperValues = this.interpolateByBodyWeight(ageUpper, metrics.weight, standardsByGender); const lowerLevels = this.interpolateByWeight(ageLower, metrics.weight, standardsByGender);
if (!lowerValues || !upperValues) return interpolatedStandard; const upperLevels = this.interpolateByWeight(ageUpper, metrics.weight, standardsByGender);
// Interpolate by age
let ageRatio = ageUpper === ageLower ? 1 : (metrics.age - ageLower) / (ageUpper - ageLower); let ageRatio = ageUpper === ageLower ? 1 : (metrics.age - ageLower) / (ageUpper - ageLower);
ageRatio = Math.max(0, Math.min(1, ageRatio)); ageRatio = Math.max(0, Math.min(1, ageRatio));
const levels = this.interpolateLevels(lowerLevels, upperLevels, ageRatio);
const levels = this.interpolateLevels(lowerValues, upperValues, ageRatio); // Post-process
const expandedLevels = this.expandLevels(levels, this.cfg.expandIters); const expandedLevels = this.expandLevels(levels, this.cfg.expandIters);
const compressedLevels = this.compressLevels(expandedLevels, this.cfg.compressTo); const compressedLevels = this.compressLevels(expandedLevels, this.cfg.compressTo);
interpolatedStandard.levels = compressedLevels; interpolatedStandard.levels = compressedLevels;
return interpolatedStandard; return interpolatedStandard;
} }