frontend/src/bin/3dView/utils/grainFillBounds.ts

49 lines
1.5 KiB
TypeScript

/**
* Y bounds of filled grain volume — matches GrainFillFlat / GrainCableFill fallback volume math.
*/
export interface GrainYBounds {
minY: number;
maxY: number;
}
export function grainYBoundsFromFillPercent(
diameter: number,
sidewallHeight: number,
hopperHeight: number,
fillPercent: number
): GrainYBounds {
const radius = diameter / 2;
const sidewallBaseY = -sidewallHeight / 2;
const hopperTipY = sidewallBaseY - hopperHeight;
if (fillPercent <= 0) {
return { minY: sidewallBaseY, maxY: sidewallBaseY };
}
const cylinderVolume = Math.PI * radius * radius * sidewallHeight;
const hopperVolume =
hopperHeight > 0 ? (1 / 3) * Math.PI * radius * radius * hopperHeight : 0;
const totalVolume = cylinderVolume + hopperVolume;
const filledVolume = totalVolume * fillPercent;
if (hopperHeight > 0 && filledVolume <= hopperVolume) {
const ratio = filledVolume / hopperVolume;
const hopperFillHeight = hopperHeight * Math.pow(ratio, 1 / 3);
return {
minY: hopperTipY,
maxY: hopperTipY + hopperFillHeight,
};
}
const hopperFillHeight = hopperHeight;
const remainingVolume = filledVolume - hopperVolume;
const cylinderFillHeight = Math.max(
0,
remainingVolume / (Math.PI * radius * radius)
);
return {
minY: hopperHeight > 0 ? hopperTipY : sidewallBaseY,
maxY: sidewallBaseY + cylinderFillHeight,
};
}