impl/typescript.ts
1,876 bytes · the TypeScript implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { atan } from "./math_atan.ts"; ← from math.atan ^1.0.0 · built alongside by fune
import { roundFloat } from "./math_round_float.ts"; ← from math.round-float ^1.0.0 · built alongside by fune
import { type RoofPitch, type RoofType } from "./construction_roof_pitch_types.ts";
// 180 / pi as a double, written out so no language computes it differently.
const DEGREES_PER_RADIAN = 57.29577951308232;
const LIMIT = 10000;
function checkLength(name: string, value: number, allowZero: boolean): void {
const ok = typeof value === "number" && Number.isFinite(value) && value <= LIMIT && (allowZero ? value >= 0 : value > 0);
if (!ok) {
const want = allowZero ? "zero or more" : "greater than zero";
throw new RangeError(`${name} must be a finite number of metres, ${want} and at most ${LIMIT}, received ${String(value)}`);
}
}
/**
* Pitch, rafter length and slope area of a duo- or mono-pitch roof.
*
* The area is worked from the unrounded rafter, not the one rounded to a
* millimetre for display: over a long roof the difference shows in the
* second decimal place.
*/
export function roofPitch(span: number, rise: number, roofLength: number, roofType: RoofType): RoofPitch {
checkLength("span", span, false);
checkLength("rise", rise, true);
checkLength("roofLength", roofLength, false);
let run: number;
let slopes: number;
if (roofType === "duo") {
run = span / 2;
slopes = 2;
} else if (roofType === "mono") {
run = span;
slopes = 1;
} else {
throw new RangeError(`unknown roof type "${String(roofType)}"`);
}
const radians = atan(rise / run);
// sqrt is one of the operations IEEE 754 requires to be correctly rounded,
// so Math.sqrt is the same double in every language.
const rafter = Math.sqrt(run * run + rise * rise);
return {
pitchDegrees: roundFloat(radians * DEGREES_PER_RADIAN, 2),
rafterLength: roundFloat(rafter, 3),
roofArea: roundFloat(rafter * roofLength * slopes, 2),
};
}