From 375d87a9b0ec1cf2fffd705adb870c86144d2400 Mon Sep 17 00:00:00 2001 From: Johannes Hofmann Date: Mon, 26 Oct 2026 20:05:20 +0100 Subject: Replace the C++ implementation with the Rust port The Rust port (formerly gipfel-rs) is now the official successor to the FLTK/GSL C++ code base. This squashes the port into a single commit and removes the C++ sources (they remain in the git history below). Layout: crates/gipfel-core headless core: hills, panorama geometry, projections (maxima-generated derivatives), pure-Rust LM fit, gipfel: JPEG comment + EXIF I/O, profiles, stitching crates/gipfel-cli command-line tools (export, info, stitch, profiles) crates/gipfel-app Cosmic DE (libcosmic) GUI, binary name `gipfel` codegen/ maxima scripts + regen.sh for the projection code tests/ golden files + C++ reference harnesses (historical) The original README is kept for now; it will be updated to describe the Rust build. gipfel.dat, AUTHORS, ChangeLog and NEWS are unchanged. --- crates/gipfel-core/src/projection/mod.rs | 174 +++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 crates/gipfel-core/src/projection/mod.rs (limited to 'crates/gipfel-core/src/projection/mod.rs') diff --git a/crates/gipfel-core/src/projection/mod.rs b/crates/gipfel-core/src/projection/mod.rs new file mode 100644 index 0000000..65b74e5 --- /dev/null +++ b/crates/gipfel-core/src/projection/mod.rs @@ -0,0 +1,174 @@ +//! Projections: image coordinates as a function of azimuth/elevation angle, +//! with symbolically pre-generated derivatives (see `codegen/`). +//! +//! Faithful port of gipfel's `ProjectionLSQ.{H,cxx}`, `ProjectionRectilinear.*` +//! and `ProjectionCylindrical.*`. + +pub mod cylindrical; +pub mod rectilinear; + +pub const NAN: f64 = f64::NAN; + +/// The 7 fitted view parameters (radians where angular). +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct ViewParams { + /// azimuth of image center, radians + pub a_center: f64, + /// focal scale (pixels) + pub scale: f64, + /// pitch angle of image center (camera nose up), radians + pub a_pitch: f64, + /// camera roll, radians + pub a_roll: f64, + /// radial distortion coefficient 0 + pub k0: f64, + /// radial distortion coefficient 1 + pub k1: f64, + /// distortion center x, pixels + pub x0: f64, +} + +impl ViewParams { + pub fn new() -> Self { + ViewParams { + a_center: 0.0, + scale: 3500.0, + a_pitch: 0.0, + a_roll: 0.0, + k0: 0.0, + k1: 0.0, + x0: 0.0, + } + } +} + +/// The 9 arguments every generated macro function takes. +#[derive(Clone, Copy, Debug)] +pub struct ProjArgs { + pub c_view: f64, + pub c_pitch: f64, + pub c_roll: f64, + pub scale: f64, + pub k0: f64, + pub k1: f64, + pub x0: f64, + pub m_view: f64, + pub m_elev: f64, +} + +impl ProjArgs { + pub fn from_params(p: &ViewParams, m_view: f64, m_elev: f64) -> Self { + ProjArgs { + c_view: p.a_center, + c_pitch: p.a_pitch, + c_roll: p.a_roll, + scale: p.scale, + k0: p.k0, + k1: p.k1, + x0: p.x0, + m_view, + m_elev, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ProjectionType { + Rectilinear = 0, + Cylindrical = 1, +} + +/// A projection plus its symbolic partial derivatives w.r.t. the view +/// parameters. Methods default to `NAN`, matching the C++ base class. +pub trait Projection: Send + Sync { + /// half-width of the visible azimuth range, radians + fn get_view_angle(&self) -> f64; + + fn mac_x(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dc_view(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dc_pitch(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dc_roll(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dscale(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dk0(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dk1(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_x_dx0(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dc_view(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dc_pitch(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dc_roll(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dscale(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dk0(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dk1(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + fn mac_y_dx0(&self, a: ProjArgs) -> f64 { + let _ = a; + NAN + } + + /// Project azimuth/elevation to image coordinates (relative to image center), + /// normalizing azimuth around the view center like the C++ original. + fn get_coordinates(&self, alph: f64, elev: f64, parms: &ViewParams) -> (f64, f64) { + let mut alph = alph; + let pi = crate::hill::PI; + + if alph - parms.a_center > pi { + alph -= 2.0 * pi; + } else if alph - parms.a_center < -pi { + alph += 2.0 * pi; + } + + let args = ProjArgs::from_params(parms, alph, elev); + (self.mac_x(args), self.mac_y(args)) + } +} + +pub fn projection_from_type(t: ProjectionType) -> Box { + match t { + ProjectionType::Rectilinear => Box::new(rectilinear::ProjectionRectilinear), + ProjectionType::Cylindrical => Box::new(cylindrical::ProjectionCylindrical), + } +} -- cgit v1.2.3