commit ac732863d3cda11e01fd4e506a6c00f8bbe8114c Author: EvilMuffinHa Date: Thu Jun 16 17:10:32 2022 -0400 first commit - hilbert 2d poly diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f051aa0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,331 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "gif" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hilbert" +version = "0.1.0" +dependencies = [ + "image", +] + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-iter", + "num-rational", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.4", + "weezl", +] + +[[package]] +name = "weezl" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..beda60c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hilbert" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +image = "0.23.14" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b34ac53 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,141 @@ +use image::{ImageBuffer, Rgb, RgbImage}; + +trait Distance { + fn dist(&self, a: [f64; N], b: [f64; N]) -> Result; +} + +struct HilbertPoly { + vertices: Vec<[f64; 2]> +} + +#[allow(dead_code)] +struct Euclidean(); + +impl Distance for Euclidean { + fn dist(&self, a: [f64; N], b: [f64; N]) -> Result { + Ok(a.iter().zip(b.iter()).map(|x| (x.1 - x.0) * (x.1 - x.0)).sum::().sqrt()) + } +} + +#[allow(dead_code)] +struct Manhattan(); + +impl Distance for Manhattan { + fn dist(&self, a: [f64; N], b: [f64; N]) -> Result { + Ok(a.iter().zip(b.iter()).map(|x| f64::abs(x.1 - x.0)).sum::()) + } +} + +impl Distance for HilbertPoly { + fn dist(&self, a: [f64; N], b: [f64; N]) -> Result { + + // 2d Hilbert Convex Polygon, 3d is slightly different as it will be to a side (edge of + // convex set ) + if N != 2 { + return Err("Dim != 2"); + }; + + // Get edges. + let mut edges = self.vertices.windows(2).map(|x| [x[0], x[1]]).collect::>(); + edges.push([self.vertices[0], self.vertices[self.vertices.len() - 1]]); + + // Assert that the Hilbert convex set is convex. + let mut prev = 0.0; + let mut curr; + for i in 0..N { + let edge_one = edges[i]; + let edge_two = edges[(i + 1) % N]; + curr = (edge_one[1][0] - edge_one[0][0]) * (edge_two[1][1] - edge_one[0][1]) - + (edge_one[1][1] - edge_one[0][1]) * (edge_two[1][0] - edge_one[0][0]); + if curr != 0.0 { + if curr * prev < 0.0 { + return Err("Not convex."); + } else { + prev = curr; + } + } + } + + // Check if points are both inside the set + let (mut i, mut j, mut c) = (0, self.vertices.len() - 1, false); + loop { + if i >= self.vertices.len() { + break; + } + + + if ((self.vertices[i][1] > a[1]) != (self.vertices[j][1] > a[1])) && (a[0] < (self.vertices[j][0] - self.vertices[i][0]) * (a[1] - self.vertices[i][1]) / (self.vertices[j][1] - self.vertices[i][1]) + self.vertices[i][0]) { + c = !c; + } + j = i; + i += 1; + } + + if !c { + return Err("First point not in set."); + } + + + let (mut i, mut j, mut c) = (0, self.vertices.len() - 1, false); + loop { + if i >= self.vertices.len() { + break; + } + + + if ((self.vertices[i][1] > b[1]) != (self.vertices[j][1] > b[1])) && (b[0] < (self.vertices[j][0] - self.vertices[i][0]) * (b[1] - self.vertices[i][1]) / (self.vertices[j][1] - self.vertices[i][1]) + self.vertices[i][0]) { + c = !c; + } + j = i; + i += 1; + } + + if !c { + return Err("Second point not in set."); + } + + // Intersect the line with each polygon side + let slope = (b[1] - a[1]) / (b[0] - a[0]); + let p_intersect = edges.into_iter().map(|p| { + let edge_slope = (p[1][1] - p[0][1]) / (p[1][0] - p[0][0]); + let d = edge_slope - slope; + if d == 0.0 { + None + } else { + 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::>(); + + // 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 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 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 aq = f64::sqrt((b_closest.0[0] - a[0]) * (b_closest.0[0] - a[0]) + (b_closest.0[1] - a[1]) * (b_closest.0[1] - a[1])); + let bq = f64::sqrt(b_closest.1); + + Ok(f64::ln((pb * aq) / (pa * bq))) + } +} + +fn naive_voronoi_2d(metric: &mut dyn Distance<2>, w: u32, h: u32, points: Vec<(u32, u32)>) { + let mut image: RgbImage = ImageBuffer::new(w, h); + // All points must be in the width / height + for p in points { + assert!(p.0 <= w); + assert!(p.1 <= h); + } + + for i in 0..w { + for j in 0..h { + + } + } +} + +fn main() { + + let triangle = HilbertPoly { vertices: vec![[-8.0, 0.0], [8.0, 0.0], [0.0, 8.0]] }; + println!("{}", triangle.dist([-2.0, 2.0], [2.0, 2.0]).unwrap()); +}