Diffstat (limited to 'src/kd.rs')
-rw-r--r--src/kd.rs219
1 files changed, 0 insertions, 219 deletions
diff --git a/src/kd.rs b/src/kd.rs
deleted file mode 100644
index e7de645..0000000
--- a/src/kd.rs
+++ /dev/null
@@ -1,219 +0,0 @@
-use atools::prelude::*;
-
-pub struct KD {
- median: [f32; 4],
- normal: [f32; 4],
- index: u32,
- left: Option<Box<KD>>,
- right: Option<Box<KD>>,
- depth: u32,
-}
-
-impl std::fmt::Debug for KD {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "#{} {:?}", self.index, self.median)?;
- let d = self.depth as usize;
- if let Some(ref left) = self.left {
- write!(f, "\n{} ⬅️ {left:?}", " ".repeat(d))?;
- }
- if let Some(ref right) = self.right {
- write!(f, "\n{} ➡️ {right:?}", " ".repeat(d))?;
- }
-
- Ok(())
- }
-}
-
-struct KDNearest {
- index: u32,
- distance: f32,
-}
-
-trait Dot {
- fn dot(self, other: Self) -> f32;
-}
-
-impl Dot for [f32; 4] {
- fn dot(self, other: Self) -> f32 {
- self.amul(other).sum()
- }
-}
-
-impl KD {
- pub fn new(colors: &[[f32; 4]]) -> Self {
- assert!(colors.len() < u32::MAX as usize);
- let colors = colors.iter().copied().zip(0u32..).collect::<Vec<_>>();
- Self::_new(&mut { colors }, 0).unwrap()
- }
-
- fn _new(colors: &mut [([f32; 4], u32)], depth: u32) -> Option<KD> {
- if colors.len() == 0 {
- return None;
- };
-
- let middle = colors.len() / 2;
-
- let mut sum = [0.; 4];
- let mut sum2 = [0.; 4];
- for &(c, _) in colors.iter() {
- sum = sum.aadd(c);
- sum2 = sum2.aadd(c.amul(c));
- }
- let [r, g, b, a] = { sum2.asub(sum.amul(sum).mul(1.0 / colors.len() as f32)) };
-
- let normal = [
- (r > g && r > b && r > a) as u8 as f32,
- (g > b && g > a) as u8 as f32,
- (b > a) as u8 as f32,
- 1.,
- ];
- // colors.sort_by(|(a, _), (b, _)| );
- let (before, median, after) = colors.select_nth_unstable_by(middle, |(a, _), (b, _)| {
- a.dot(normal).partial_cmp(&b.dot(normal)).unwrap()
- });
- Some(KD {
- median: median.0,
- index: median.1,
- left: KD::_new(before, depth + 1).map(Box::new),
- right: KD::_new(after, depth + 1).map(Box::new),
- normal,
- depth,
- })
- }
-
- fn _find_nearest(&self, needle: [f32; 4], mut limit: f32) -> Option<KDNearest> {
- let mut result = None;
-
- let diff = needle.asub(self.median);
- let distance = diff.dot(diff).sqrt();
-
- if distance < limit {
- limit = distance;
- result = Some(KDNearest {
- index: self.index,
- distance,
- })
- }
-
- let dot = diff.dot(self.normal);
- if dot <= 0.0 {
- if let Some(ref left) = self.left
- && let Some(nearest) = left._find_nearest(needle, limit)
- {
- limit = nearest.distance;
- result = Some(nearest);
- }
-
- if -dot < limit {
- if let Some(ref right) = self.right
- && let Some(nearest) = right._find_nearest(needle, limit)
- {
- result = Some(nearest);
- }
- }
- } else {
- if let Some(ref right) = self.right
- && let Some(nearest) = right._find_nearest(needle, limit)
- {
- limit = nearest.distance;
- result = Some(nearest);
- }
-
- if dot < limit {
- if let Some(ref left) = self.left
- && let Some(nearest) = left._find_nearest(needle, limit)
- {
- result = Some(nearest);
- }
- }
- }
-
- result
- }
-
- fn _find_nearest_excepting(
- &self,
- needle: [f32; 4],
- mut limit: f32,
- ignore_index: u32,
- ) -> Option<KDNearest> {
- let mut result = None;
-
- let diff = needle.asub(self.median);
- let distance = diff.dot(diff).sqrt();
-
- if distance < limit && self.index != ignore_index {
- limit = distance;
- result = Some(KDNearest {
- index: self.index,
- distance,
- })
- }
-
- let dot = diff.dot(self.normal);
- if dot <= 0.0 {
- if let Some(ref left) = self.left
- && let Some(nearest) = left._find_nearest_excepting(needle, limit, ignore_index)
- {
- limit = nearest.distance;
- result = Some(nearest);
- }
-
- if -dot < limit {
- if let Some(ref right) = self.right
- && let Some(nearest) =
- right._find_nearest_excepting(needle, limit, ignore_index)
- {
- result = Some(nearest);
- }
- }
- } else {
- if let Some(ref right) = self.right
- && let Some(nearest) = right._find_nearest_excepting(needle, limit, ignore_index)
- {
- limit = nearest.distance;
- result = Some(nearest);
- }
-
- if dot < limit {
- if let Some(ref left) = self.left
- && let Some(nearest) = left._find_nearest_excepting(needle, limit, ignore_index)
- {
- result = Some(nearest);
- }
- }
- }
-
- result
- }
-
- pub fn find_nearest(&self, color: [f32; 4]) -> u32 {
- self._find_nearest(color, f32::MAX)
- .map(|x| x.index)
- .unwrap_or(0)
- }
-
- pub fn space(&self, colors: &[[f32; 4]]) -> f32 {
- let mut i = colors
- .iter()
- .zip(0..)
- .map(|(c, i)| {
- self._find_nearest_excepting(*c, f32::MAX, i)
- .unwrap()
- .distance
- })
- .array_chunks::<256>();
-
- let (c, sum) = i.by_ref().fold((0.0, 0.0), |(c, sum), chunk| {
- let y = sum_block(chunk) - c;
- let t = sum + y;
- ((t - sum) - y, t)
- });
- (sum + (i.into_remainder().map(sum_block).unwrap_or(0.) - c)) / colors.len() as f32
- }
-}
-
-use std::intrinsics::fadd_algebraic;
-fn sum_block(arr: impl IntoIterator<Item = f32>) -> f32 {
- arr.into_iter().fold(0.0, |x, y| fadd_algebraic(x, y))
-}