This commit is contained in:
EvilMuffinHa 2022-06-17 00:27:18 -04:00
parent ac732863d3
commit 07468785b9
3 changed files with 76 additions and 14 deletions

14
Cargo.lock generated
View File

@ -139,13 +139,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hilbert"
version = "0.1.0"
dependencies = [
"image",
]
[[package]] [[package]]
name = "image" name = "image"
version = "0.23.14" version = "0.23.14"
@ -324,6 +317,13 @@ dependencies = [
"weezl", "weezl",
] ]
[[package]]
name = "voronoi"
version = "0.1.0"
dependencies = [
"image",
]
[[package]] [[package]]
name = "weezl" name = "weezl"
version = "0.1.6" version = "0.1.6"

View File

@ -1,5 +1,5 @@
[package] [package]
name = "hilbert" name = "voronoi"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"

View File

@ -27,7 +27,12 @@ impl<const N: usize> Distance<N> for Manhattan<N> {
} }
impl<const N: usize> Distance<N> for HilbertPoly { impl<const N: usize> Distance<N> for HilbertPoly {
fn dist(&self, a: [f64; N], b: [f64; N]) -> Result<f64, &'static str> { fn dist(&self, a: [f64; N], b: [f64; N]) -> Result<f64, &'static str> {
if a == b {
return Ok(0.0);
}
// ("#0: {:?} {:?}", a, b);
// 2d Hilbert Convex Polygon, 3d is slightly different as it will be to a side (edge of // 2d Hilbert Convex Polygon, 3d is slightly different as it will be to a side (edge of
// convex set ) // convex set )
@ -57,6 +62,7 @@ impl<const N: usize> Distance<N> for HilbertPoly {
} }
// Check if points are both inside the set // Check if points are both inside the set
let (mut i, mut j, mut c) = (0, self.vertices.len() - 1, false); let (mut i, mut j, mut c) = (0, self.vertices.len() - 1, false);
loop { loop {
if i >= self.vertices.len() { if i >= self.vertices.len() {
@ -94,6 +100,37 @@ impl<const N: usize> Distance<N> for HilbertPoly {
return Err("Second point not in set."); return Err("Second point not in set.");
} }
// Check if points are on the boundary
//
let c = edges.clone().into_iter().map(|e| [[e[0][0] - a[0], e[0][1] - a[1]], [e[1][0] - a[0], e[1][1] - a[1]]]).map(|s| {
let ab = f64::sqrt(s[0][0] * s[0][0] + s[0][1] * s[0][1]);
let bc = f64::sqrt(s[1][0] * s[1][0] + s[1][1] * s[1][1]);
let ac = f64::sqrt((s[1][0] - s[0][0]) * (s[1][0] - s[0][0]) + (s[1][1] - s[0][1]) * (s[1][1] - s[0][1]));
// ("#1: boundary check: {} {}", f64::round(ab + bc), f64::round(ac));
if f64::round(ab + bc) != f64::round(ac) {
return true;
}
false
}).all(|x| x);
if !c {
return Err("First point not in set.");
}
let c = edges.clone().into_iter().map(|e| [[e[0][0] - b[0], e[0][1] - b[1]], [e[1][0] - b[0], e[1][1] - b[1]]]).map(|s| {
let ab = f64::sqrt(s[0][0] * s[0][0] + s[0][1] * s[0][1]);
let bc = f64::sqrt(s[1][0] * s[1][0] + s[1][1] * s[1][1]);
let ac = f64::sqrt((s[1][0] - s[0][0]) * (s[1][0] - s[0][0]) + (s[1][1] - s[0][1]) * (s[1][1] - s[0][1]));
if f64::round(ab + bc) != f64::round(ac) {
return true;
}
false
}).all(|x| x);
if !c {
return Err("Second point not in set.");
}
// Intersect the line with each polygon side // Intersect the line with each polygon side
let slope = (b[1] - a[1]) / (b[0] - a[0]); let slope = (b[1] - a[1]) / (b[0] - a[0]);
let p_intersect = edges.into_iter().map(|p| { let p_intersect = edges.into_iter().map(|p| {
@ -101,14 +138,17 @@ impl<const N: usize> Distance<N> for HilbertPoly {
let d = edge_slope - slope; let d = edge_slope - slope;
if d == 0.0 { if d == 0.0 {
None None
} else if d == f64::INFINITY || d == f64::NEG_INFINITY {
Some([a[0], edge_slope * a[0] - edge_slope * p[0][0] + p[0][1]])
} else { } else {
// ("#2: slopes: {:?} {:?} {} {} {:?}", a, b, slope, edge_slope, d);
Some([((edge_slope * p[0][0] - p[0][1]) - (slope * a[0] - a[1])) / d, ((slope * (edge_slope * p[0][0] - p[0][1])) - (edge_slope * (slope * a[0] - a[1]))) / d]) Some([((edge_slope * p[0][0] - p[0][1]) - (slope * a[0] - a[1])) / d, ((slope * (edge_slope * p[0][0] - p[0][1])) - (edge_slope * (slope * a[0] - a[1]))) / d])
} }
}).filter(|x| x.is_some()).map(|x| x.map_or([0.0, 0.0], |x| x)).collect::<Vec<[f64; 2]>>(); }).filter(|x| x.is_some()).map(|x| x.map_or([0.0, 0.0], |x| x)).collect::<Vec<[f64; 2]>>();
// Find the closest distance // Find the closest distance
let a_closest = p_intersect.clone().into_iter().map(|p| (p, (p[0] - a[0]) * (p[0] - a[0]) + (p[1] - a[1]) * (p[1] - a[1]))).min_by(|a, b| a.1.partial_cmp(&b.1).unwrap()).unwrap(); let a_closest = p_intersect.clone().into_iter().map(|p| (p, (p[0] - a[0]) * (p[0] - a[0]) + (p[1] - a[1]) * (p[1] - a[1]))).min_by(|a, b| a.1.partial_cmp(&b.1).unwrap()).unwrap();
let b_closest = p_intersect.into_iter().map(|p| (p, (p[0] - b[0]) * (p[0] - b[0]) + (p[1] - b[1]) * (p[1] - b[1]))).min_by(|a, b| a.1.partial_cmp(&b.1).unwrap()).unwrap(); let b_closest = p_intersect.into_iter().map(|p| (p, (p[0] - b[0]) * (p[0] - b[0]) + (p[1] - b[1]) * (p[1] - b[1]))).filter(|p| p.0 != a_closest.0).min_by(|a, b| a.1.partial_cmp(&b.1).unwrap()).unwrap();
let pb = f64::sqrt((a_closest.0[0] - b[0]) * (a_closest.0[0] - b[0]) + (a_closest.0[1] - b[1]) * (a_closest.0[1] - b[1])); let pb = f64::sqrt((a_closest.0[0] - b[0]) * (a_closest.0[0] - b[0]) + (a_closest.0[1] - b[1]) * (a_closest.0[1] - b[1]));
let pa = f64::sqrt(a_closest.1); let pa = f64::sqrt(a_closest.1);
@ -119,23 +159,45 @@ impl<const N: usize> Distance<N> for HilbertPoly {
} }
} }
fn naive_voronoi_2d(metric: &mut dyn Distance<2>, w: u32, h: u32, points: Vec<(u32, u32)>) { fn naive_voronoi_2d(metric: &mut dyn Distance<2>, w: u32, h: u32, points: Vec<(u32, u32, Rgb<u8>)>) -> RgbImage {
let mut image: RgbImage = ImageBuffer::new(w, h); let mut image: RgbImage = ImageBuffer::new(w, h);
// All points must be in the width / height // All points must be in the width / height
for p in points { for p in points.clone() {
assert!(p.0 <= w); assert!(p.0 <= w);
assert!(p.1 <= h); assert!(p.1 <= h);
} }
for i in 0..w { for i in 0..w {
for j in 0..h { for j in 0..h {
let c = points.clone().into_iter().map(|p| metric.dist([i as f64, j as f64], [p.0 as f64, p.1 as f64]) /* ("#3: points for dist: ({} {}) ({} {}) {:?}", i, j, p.0, p.1, u)*/);
if c.clone().map(|d| d.is_ok()).all(|x| x) {
let closest = c.clone().map(|d| d.unwrap()).enumerate().min_by(|a, b| a.1.partial_cmp(&b.1).unwrap()).unwrap();
if closest.1 == 0.0 {
*image.get_pixel_mut(i, j) = Rgb([0, 0, 0]);
} else {
*image.get_pixel_mut(i, j) = points[closest.0].2;
}
} else {
*image.get_pixel_mut(i, j) = Rgb([255, 255, 255]);
}
} }
} }
image
} }
fn main() { fn main() {
let triangle = HilbertPoly { vertices: vec![[-8.0, 0.0], [8.0, 0.0], [0.0, 8.0]] }; let mut triangle = HilbertPoly { vertices: vec![[300.0, 0.0], [0.0, 600.0], [600.0, 600.0]] };
println!("{}", triangle.dist([-2.0, 2.0], [2.0, 2.0]).unwrap()); let mut euclidean: Euclidean<2> = Euclidean();
let mut manhattan: Manhattan<2> = Manhattan();
let points = vec![(360, 340, Rgb([255, 0, 0])), (340, 340, Rgb([0, 255, 0])), (400, 400, Rgb([0, 0, 255]))];
let h = naive_voronoi_2d(&mut triangle, 600, 600, points.clone());
h.save("hilbert.png").unwrap();
let e = naive_voronoi_2d(&mut euclidean, 600, 600, points.clone());
e.save("euclidean.png").unwrap();
let m = naive_voronoi_2d(&mut manhattan, 600, 600, points);
m.save("manhattan.png").unwrap();
} }