123456789101112131415161718192021222324252627282930(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Stereographic.mli *)(* the horizontal frame as vectors: x east, y north, z up *)letvector(h:Celestial.horizontal):float*float*float=(cosh.alt*.sinh.az,cosh.alt*.cosh.az,sinh.alt)letproject~(view:Celestial.horizontal)(p:Celestial.horizontal):(float*float)option=letfx,fy,fz=vectorviewin(* the screen's right: horizontal, towards increasing azimuth *)letrx,ry=(cosview.az,-.sinview.az)in(* its up: right x forward, towards the zenith *)letux,uy,uz=(ry*.fz,-.(rx*.fz),(rx*.fy)-.(ry*.fx))inletpx,py,pz=vectorpinletx=(px*.rx)+.(py*.ry)andy=(px*.ux)+.(py*.uy)+.(pz*.uz)inletz=(px*.fx)+.(py*.fy)+.(pz*.fz)inifz<-0.85thenNoneelseSome(2.*.x/.(1.+.z),2.*.y/.(1.+.z))(* the horizon's nearest point is [a] below the centre, at
* -2 tan (a/2), its furthest 180 - a above it, at 2 cot (a/2) *)lethorizon(a:float):float*float=(2./.tana,2./.sina)