Functional Weave
Code in Python

construction.roof-pitch@1.0.0

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),
  };
}