1 import Base 2 3 # --- Vec3: a 3D point/vector over F32. Data so it copies freely with `+`. --- 4 5 type Vec3 is Data: 6 V3{x: F32, y: F32, z: F32} 7 8 def Vec3.add(+a: Vec3, +b: Vec3) -> Vec3: 9 match a b: 10 case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: 11 V3{(ax + bx : F32), (ay + by : F32), (az + bz : F32)} 12 13 def Vec3.sub(+a: Vec3, +b: Vec3) -> Vec3: 14 match a b: 15 case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: 16 V3{(ax - bx : F32), (ay - by : F32), (az - bz : F32)} 17 18 def Vec3.scale(+s: F32, +v: Vec3) -> Vec3: 19 match v: 20 case V3{+x, +y, +z}: 21 V3{(s * x : F32), (s * y : F32), (s * z : F32)} 22 23 def Vec3.dot(+a: Vec3, +b: Vec3) -> F32: 24 match a b: 25 case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: 26 (((ax * bx : F32) + (ay * by : F32) : F32) + (az * bz : F32) : F32) 27 28 def Vec3.norm2(+v: Vec3) -> F32: 29 Vec3.dot(v, v) 30 31 def Vec3.dist2(+a: Vec3, +b: Vec3) -> F32: 32 Vec3.norm2(Vec3.sub(a, b)) 33 34 def Vec3.dist(+a: Vec3, +b: Vec3) -> F32: 35 F32.sqrt(Vec3.dist2(a, b)) 36 37 def Vec3.midpoint(+a: Vec3, +b: Vec3) -> Vec3: 38 Vec3.scale(0.5, Vec3.add(a, b)) 39 40 def Vec3.cross(+a: Vec3, +b: Vec3) -> Vec3: 41 match a b: 42 case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: 43 V3{((ay * bz : F32) - (az * by : F32) : F32), ((az * bx : F32) - (ax * bz : F32) : F32), ((ax * by : F32) - (ay * bx : F32) : F32)} 44 45 def Vec3.sum_coords(v: Vec3) -> F32: 46 match v: 47 case V3{x, y, z}: 48 ((x + y : F32) + z : F32) 49 50 def Vec3.neg(+v: Vec3) -> Vec3: 51 match v: 52 case V3{+x, +y, +z}: 53 V3{(0.0 - x : F32), (0.0 - y : F32), (0.0 - z : F32)} 54 55 def lerp1(+a: F32, +b: F32, +t: F32) -> F32: 56 (a + ((b - a : F32) * t : F32) : F32) 57 58 def Vec3.lerp(+a: Vec3, +b: Vec3, +t: F32) -> Vec3: 59 match a b: 60 case V3{+ax, +ay, +az} V3{+bx, +by, +bz}: 61 V3{lerp1(ax, bx, t), lerp1(ay, by, t), lerp1(az, bz, t)} 62 63 # Cosine of the angle between a and b. Undefined for zero vectors. 64 def Vec3.cos_angle(+a: Vec3, +b: Vec3) -> F32: 65 (Vec3.dot(a, b) / F32.sqrt((Vec3.norm2(a) * Vec3.norm2(b) : F32)) : F32) 66 67 def Vec3.angle(+a: Vec3, +b: Vec3) -> F32: 68 F32.acos(Vec3.cos_angle(a, b)) 69 70 # Squared area of triangle (a, b, c): |cross(b-a, c-a)|^2 / 4. 71 def Vec3.tri_area2(+a: Vec3, +b: Vec3, +c: Vec3) -> F32: 72 (Vec3.norm2(Vec3.cross(Vec3.sub(b, a), Vec3.sub(c, a))) / 4.0 : F32)