Bosatsu packages

Yichus/Geometry

Builtin package (resource geometry.bosatsu). This is the complete package source used by this build. The export list names its public API; definitions below give the types and behavior.

New to the API? Start with Make a calculator or Build an API, then use this page to look up a definition.

package Yichus/Geometry

from Yichus/Num/Float64 import (
  Float64,
  addf, subf, mulf, divf,
  abs_Float64,
  int_to_Float64
)

export (
  Line(),
  Point(),
  intersect,
  shift,
  y_at,
  horizontal,
  triangle_area,
  trapezoid_area,
  area_between
)

exposes (Yichus/Num/Float64)

# Closed-form Euclidean helpers for calculator graphs.
# A Line is P = intercept + slope * q. Intersections and areas are
# ordinary Bosatsu bindings, so Why/Math explore them like any other value.

struct Line(slope: Float64, intercept: Float64)
struct Point(x: Float64, y: Float64)

def zero() -> Float64:
  int_to_Float64(0)

def half() -> Float64:
  divf(int_to_Float64(1), int_to_Float64(2))

def y_at(line: Line, x: Float64) -> Float64:
  Line(slope, intercept) = line
  addf(intercept, mulf(slope, x))

def shift(line: Line, dy: Float64) -> Line:
  Line(slope, intercept) = line
  Line(slope, addf(intercept, dy))

def horizontal(y: Float64) -> Line:
  Line(zero(), y)

# q = (b0 - a0) / (a1 - b1) so a0 + a1*q = b0 + b1*q.
# Parallel lines have no unique crossing: the division is by zero and the
# result is IEEE infinity/NaN, never a fabricated finite point. The graph
# runtime surfaces non-finite marks visibly instead of drawing them.
def intersect(a: Line, b: Line) -> Point:
  Line(a1, a0) = a
  Line(b1, b0) = b
  q = divf(subf(b0, a0), subf(a1, b1))
  Point(q, y_at(a, q))

def triangle_area(p1: Point, p2: Point, p3: Point) -> Float64:
  Point(x1, y1) = p1
  Point(x2, y2) = p2
  Point(x3, y3) = p3
  term1 = mulf(x1, subf(y2, y3))
  term2 = mulf(x2, subf(y3, y1))
  term3 = mulf(x3, subf(y1, y2))
  mulf(half(), abs_Float64(addf(term1, addf(term2, term3))))

# Area of the trapezoid between two y-pairs over [x0, x1].
# Sign follows (upper - lower); callers that want magnitude use abs.
def trapezoid_area(
  x0: Float64,
  x1: Float64,
  y_upper_0: Float64,
  y_upper_1: Float64,
  y_lower_0: Float64,
  y_lower_1: Float64
) -> Float64:
  width = subf(x1, x0)
  left = subf(y_upper_0, y_lower_0)
  right = subf(y_upper_1, y_lower_1)
  mulf(width, mulf(half(), addf(left, right)))

def area_between(upper: Line, lower: Line, x0: Float64, x1: Float64) -> Float64:
  y_u0 = y_at(upper, x0)
  y_u1 = y_at(upper, x1)
  y_l0 = y_at(lower, x0)
  y_l1 = y_at(lower, x1)
  abs_Float64(trapezoid_area(x0, x1, y_u0, y_u1, y_l0, y_l1))