platesolve 0.0.1-wip

A library to perform astronomical plate solving for images
Documentation
use acap::{Euclidean, EuclideanDistance, NearestNeighbors, Proximity};
use acap::vp::VpTree;

#[derive(Copy, Clone, PartialEq)]
pub struct StarQuadEntry {
    x: f32,
    y: f32,
    distance: EuclideanDistance<f32>,
}

#[derive(Copy, Clone, PartialEq)]
pub struct StarQuad {
    x: f32,
    y: f32,
    closest_points: [StarQuadEntry; 3],
}

impl StarQuad {
    pub fn generate_normalized_hashes(&self) -> [f32; 6] {
        let mut largest_distance = EuclideanDistance::try_from(0.).unwrap();
        let mut hash_codes = [0_f32; 6];

        let closest1 = self.closest_points[0];
        hash_codes[0] = closest1.distance.squared_value();
        if closest1.distance > largest_distance {
            largest_distance = closest1.distance;
        }

        let closest2 = self.closest_points[1];
        hash_codes[1] = closest2.distance.squared_value();
        if closest2.distance > largest_distance {
            largest_distance = closest2.distance;
        }

        let closest3 = self.closest_points[2];
        hash_codes[2] = closest3.distance.squared_value();
        if closest3.distance > largest_distance {
            largest_distance = closest3.distance;
        }

        let distance =
            Euclidean([closest1.x, closest1.y]).distance(&Euclidean([closest2.x, closest2.y]));

        if distance > largest_distance {
            largest_distance = distance;
        }
        hash_codes[3] = distance.squared_value();

        let distance =
            Euclidean([closest1.x, closest1.y]).distance(&Euclidean([closest3.x, closest3.y]));

        if distance > largest_distance {
            largest_distance = distance;
        }
        hash_codes[4] = distance.squared_value();

        let distance =
            Euclidean([closest2.x, closest2.y]).distance(&Euclidean([closest3.x, closest3.y]));

        if distance > largest_distance {
            largest_distance = distance;
        }
        hash_codes[5] = distance.squared_value();

        let largest_distance = largest_distance.squared_value();
        for code in hash_codes.iter_mut() {
            *code /= largest_distance;
        }

        hash_codes
    }
}

pub struct StarQuads(pub Vec<StarQuad>);

impl StarQuads {
    pub fn iter(&self) -> impl Iterator<Item = &StarQuad> {
        self.0.iter()
    }
}

impl From<Vec<Euclidean<[f32; 2]>>> for StarQuads {
    fn from(value: Vec<Euclidean<[f32; 2]>>) -> Self {
        let tree = VpTree::balanced(value);
        let mut star_quads = vec![];

        for point in &tree {
            let neighbours = tree
                .k_nearest(point, 3)
                .iter()
                .map(|item| StarQuadEntry {
                    x: item.item.0[0],
                    y: item.item.0[1],
                    distance: item.distance,
                })
                .collect::<Vec<_>>();

            star_quads.push(StarQuad {
                x: point.0[0],
                y: point.0[1],
                closest_points: [neighbours[0], neighbours[1], neighbours[2]],
            })
        }

        Self(star_quads)
    }
}