// GEO01 stretch S4: angles from coordinates, and the orientation test.//// Build and run (Developer PowerShell for Visual Studio 2026):// cl /std:c++latest /O2 /EHsc /nologo angles.cpp && .\angles.exe// or with g++ or clang++:// g++ -std=c++23 -O2 angles.cpp -o angles && ./angles//// What it shows: measured in floating point, a triangle's three angles add to 180 degrees only// approximately, within about 1e-13 degrees. That is evidence for Theorem 1.3, never a proof of it.// The sign of the cross product you compute along the way is the orientation test, the predicate// the computational-geometry bridge (B4) is built on.#include<algorithm>#include<array>#include<cmath>#include<cstdio>#include<numbers>#include<random>structVec{doublex,y;};Vecoperator-(Veca,Vecb){return{a.x-b.x,a.y-b.y};}doubledot(Vecu,Vecv){returnu.x*v.x+u.y*v.y;}// The 2D cross product: the signed area of the parallelogram spanned by u and v.doublecross(Vecu,Vecv){returnu.x*v.y-u.y*v.x;}// Orientation of the path a -> b -> c: positive for a left (counterclockwise) turn,// negative for a right turn, zero when the three points are collinear.doubleorient(Veca,Vecb,Vecc){returncross(b-a,c-a);}// The non-reflex angle at vertex b, between the rays b->a and b->c, in degrees (0 to 180).doubleangle_at(Veca,Vecb,Vecc){// TODO: return the angle at b between rays b->a and b->c, in degrees.return0.0;}intmain(){// 1. Three angles whose values you know.constVeco{0,0},e{1,0},n{0,1},w{-1,0},ne{1,1};std::printf("right angle %8.3f (want 90)\n",angle_at(e,o,n));std::printf("45 degrees %8.3f (want 45)\n",angle_at(e,o,ne));std::printf("straight angle %8.3f (want 180)\n",angle_at(e,o,w));std::printf("zero angle %8.3f (want 0)\n",angle_at(e,o,Vec{2,0}));std::printf("tiny angle %.3e (want about 5.73e-07)\n",angle_at(Vec{1,1e-8},o,e));// 2. A million random triangles: how far from 180 do the angle sums stray?std::mt19937_64rng(2026);std::uniform_real_distribution<double>coord(-1000.0,1000.0);doubleworst=0.0;for(inti=0;i<1'000'000;++i){conststd::array<Vec,3>t{Vec{coord(rng),coord(rng)},Vec{coord(rng),coord(rng)},Vec{coord(rng),coord(rng)}};constdoublesum=angle_at(t[2],t[0],t[1])+angle_at(t[0],t[1],t[2])+angle_at(t[1],t[2],t[0]);worst=std::max(worst,std::abs(sum-180.0));}std::printf("worst |angle sum - 180| over 1e6 random triangles: %.2e degrees\n",worst);// 3. The orientation test.std::printf("orient(o, e, n) = %+.1f (left turn)\n",orient(o,e,n));std::printf("orient(o, n, e) = %+.1f (right turn)\n",orient(o,n,e));std::printf("orient(o, e, (2,0)) = %+.1f (collinear)\n",orient(o,e,Vec{2,0}));}