pub mod combinations;
pub mod database;
pub mod pattern;
pub mod solve;
use rkyv::{Archive, Deserialize, Serialize};
use crate::{Quaternion, StarCatalog};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolveStatus {
MatchFound,
NoMatch,
Timeout,
TooFew,
}
#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
pub struct DatabaseProperties {
pub pattern_bins: u32,
pub pattern_max_error: f32,
pub max_fov_rad: f32,
pub min_fov_rad: f32,
pub star_max_magnitude: f32,
pub num_patterns: u32,
pub epoch_equinox: u16,
pub epoch_proper_motion_year: f32,
pub verification_stars_per_fov: u32,
pub lattice_field_oversampling: u32,
pub patterns_per_lattice_field: u32,
}
#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
pub struct SolverDatabase {
pub star_catalog: StarCatalog,
pub star_vectors: Vec<[f32; 3]>,
pub star_catalog_ids: Vec<u64>,
pub pattern_catalog: Vec<[u32; 4]>,
pub pattern_largest_edge: Vec<f32>,
pub pattern_key_hashes: Vec<u16>,
pub props: DatabaseProperties,
}
pub struct GenerateDatabaseConfig {
pub max_fov_deg: f32,
pub min_fov_deg: Option<f32>,
pub star_max_magnitude: Option<f32>,
pub pattern_max_error: f32,
pub lattice_field_oversampling: u32,
pub patterns_per_lattice_field: u32,
pub verification_stars_per_fov: u32,
pub multiscale_step: f32,
pub epoch_proper_motion_year: Option<f64>,
pub catalog_nside: u32,
}
impl Default for GenerateDatabaseConfig {
fn default() -> Self {
Self {
max_fov_deg: 30.0,
min_fov_deg: None,
star_max_magnitude: None,
pattern_max_error: 0.001,
lattice_field_oversampling: 100,
patterns_per_lattice_field: 50,
verification_stars_per_fov: 150,
multiscale_step: 1.5,
epoch_proper_motion_year: Some(2025.0),
catalog_nside: 16,
}
}
}
pub struct SolveConfig {
pub fov_estimate_rad: f32,
pub fov_max_error_rad: Option<f32>,
pub match_radius: f32,
pub match_threshold: f64,
pub solve_timeout_ms: Option<u64>,
pub match_max_error: Option<f32>,
}
impl SolveConfig {
pub fn new(fov_estimate_rad: f32) -> Self {
Self {
fov_estimate_rad,
fov_max_error_rad: None,
match_radius: 0.01,
match_threshold: 1e-5,
solve_timeout_ms: Some(5000),
match_max_error: None,
}
}
}
#[derive(Debug, Clone)]
pub struct SolveResult {
pub quaternion: Option<Quaternion>,
pub fov_rad: Option<f32>,
pub num_matches: Option<u32>,
pub rmse_rad: Option<f32>,
pub p90e_rad: Option<f32>,
pub max_err_rad: Option<f32>,
pub prob: Option<f64>,
pub solve_time_ms: f32,
pub status: SolveStatus,
pub matched_catalog_ids: Vec<u64>,
pub matched_centroid_indices: Vec<usize>,
}
impl SolveResult {
pub(crate) fn failure(status: SolveStatus, solve_time_ms: f32) -> Self {
Self {
quaternion: None,
fov_rad: None,
num_matches: None,
rmse_rad: None,
p90e_rad: None,
max_err_rad: None,
prob: None,
solve_time_ms,
status,
matched_catalog_ids: Vec::new(),
matched_centroid_indices: Vec::new(),
}
}
}