import Base # --- Vec3: a 3D point/vector over F32. Data so it copies freely with `+`. --- type Vec3 is Data: V3{x: F32, y: F32, z: F32} def Vec3.add(+a: Vec3, +b: Vec3) -> Vec3: match a b: case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: V3{(ax + bx : F32), (ay + by : F32), (az + bz : F32)} def Vec3.sub(+a: Vec3, +b: Vec3) -> Vec3: match a b: case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: V3{(ax - bx : F32), (ay - by : F32), (az - bz : F32)} def Vec3.scale(+s: F32, +v: Vec3) -> Vec3: match v: case V3{+x, +y, +z}: V3{(s * x : F32), (s * y : F32), (s * z : F32)} def Vec3.dot(+a: Vec3, +b: Vec3) -> F32: match a b: case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: (((ax * bx : F32) + (ay * by : F32) : F32) + (az * bz : F32) : F32) def Vec3.norm2(+v: Vec3) -> F32: Vec3.dot(v, v) def Vec3.dist2(+a: Vec3, +b: Vec3) -> F32: Vec3.norm2(Vec3.sub(a, b)) def Vec3.dist(+a: Vec3, +b: Vec3) -> F32: F32.sqrt(Vec3.dist2(a, b)) def Vec3.midpoint(+a: Vec3, +b: Vec3) -> Vec3: Vec3.scale(0.5, Vec3.add(a, b)) def Vec3.cross(+a: Vec3, +b: Vec3) -> Vec3: match a b: case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: V3{((ay * bz : F32) - (az * by : F32) : F32), ((az * bx : F32) - (ax * bz : F32) : F32), ((ax * by : F32) - (ay * bx : F32) : F32)} def Vec3.sum_coords(v: Vec3) -> F32: match v: case V3{x, y, z}: ((x + y : F32) + z : F32) def Vec3.neg(+v: Vec3) -> Vec3: match v: case V3{+x, +y, +z}: V3{(0.0 - x : F32), (0.0 - y : F32), (0.0 - z : F32)} def lerp1(+a: F32, +b: F32, +t: F32) -> F32: (a + ((b - a : F32) * t : F32) : F32) def Vec3.lerp(+a: Vec3, +b: Vec3, +t: F32) -> Vec3: match a b: case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: V3{lerp1(ax, bx, t), lerp1(ay, by, t), lerp1(az, bz, t)} # Cosine of the angle between a and b. Undefined for zero vectors. def Vec3.cos_angle(+a: Vec3, +b: Vec3) -> F32: (Vec3.dot(a, b) / F32.sqrt((Vec3.norm2(a) * Vec3.norm2(b) : F32)) : F32) def Vec3.angle(+a: Vec3, +b: Vec3) -> F32: F32.acos(Vec3.cos_angle(a, b)) # Squared area of triangle (a, b, c): |cross(b-a, c-a)|^2 / 4. def Vec3.tri_area2(+a: Vec3, +b: Vec3, +c: Vec3) -> F32: (Vec3.norm2(Vec3.cross(Vec3.sub(b, a), Vec3.sub(c, a))) / 4.0 : F32)