From bab4842b615f02c5360b8a2b5a669e23f019aaf1 Mon Sep 17 00:00:00 2001 From: randogoth Date: Tue, 2 Apr 2024 10:55:19 +0300 Subject: [PATCH 01/11] remove triangle --- src/lib.rs | 113 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d134e5f..fd76c73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,6 +83,7 @@ pub struct GeometryData { pub edge_to_triangles: HashMap>, // Maps an edge to triangle indices pub edge_lengths: HashMap, // Edge lengths pub vertex_connections: HashMap>, // Direct connections between vertices, for DTSCAN + pub triangle_blacklist: HashSet, // invalidated triangles } impl GeometryData { @@ -91,7 +92,8 @@ impl GeometryData { triangles: Vec::new(), edge_to_triangles: HashMap::new(), edge_lengths: HashMap::new(), - vertex_connections: HashMap::new(), // Adjusted for DTSCAN + vertex_connections: HashMap::new(), + triangle_blacklist: HashSet::new(), } } fn add_triangle(&mut self, index: usize, points: &[Point], tri_idx: &[usize], types: usize) { @@ -159,6 +161,10 @@ impl GeometryData { }; } } + + pub fn remove_triangle(&mut self, triangle_index: usize) { + self.triangle_blacklist.insert(triangle_index); + } } @@ -197,26 +203,53 @@ impl Xenobalanus { self.points = points } - pub fn triangle(&self, index: usize) -> TriangleData { - self.geometry_data.triangles[index].clone() + pub fn triangle(&self, index: usize) -> Option<&TriangleData> { + if !self.geometry_data.triangle_blacklist.contains(&index) { + Some(&self.geometry_data.triangles[index]) + } else { + None + } } - pub fn triangle_data(&self) -> &Vec { - &self.geometry_data.triangles + pub fn triangle_data(&self) -> Vec { + self.geometry_data.triangles.iter() + .enumerate() + .filter_map(|(index, triangle)| { + if self.geometry_data.triangle_blacklist.contains(&index) { + None // Skip blacklisted triangles + } else { + Some(triangle.clone()) // Include this triangle + } + }) + .collect() + } + + pub fn triangle_area(&self, index: usize) -> f32 { + self.triangle(index).map_or(0.0, |tri| tri.area.unwrap_or_default()) } pub fn triangles_flat(&self) -> Vec { - self.triangulation.clone() + let mut filtered_vertices = Vec::new(); + for (i, chunk) in self.triangulation.chunks(3).enumerate() { + // Skip this triangle if it's blacklisted + if self.geometry_data.triangle_blacklist.contains(&i) { + continue; + } + filtered_vertices.extend_from_slice(chunk); + } + filtered_vertices } pub fn triangle_vertices(&self) -> Vec> { - self.triangulation.chunks(3).map(|chunk| { + let triangulation = self.triangles_flat(); + triangulation.chunks(3).map(|chunk| { chunk.iter().map(|&index| index).collect() }).collect() } pub fn triangle_coordinates(&self) -> Vec> { - self.triangulation.chunks(3).map(|chunk| { + let triangulation = self.triangles_flat(); + triangulation.chunks(3).map(|chunk| { chunk.iter().map(|&index| { let point = &self.points[index]; (point.x, point.y) // Each point is represented by a Vec of its coordinates @@ -228,6 +261,45 @@ impl Xenobalanus { self.triangulation = vertices } + /// Helper function to calculate the sign of an area defined by three points. + fn sign(p1: &Point, p2: &Point, p3: &Point) -> f32 { + (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y) + } + + /// Determines if a point is inside a triangle. + fn point_in_triangle(pt: &Point, v1: &Point, v2: &Point, v3: &Point) -> bool { + let d1 = Self::sign(pt, v1, v2); + let d2 = Self::sign(pt, v2, v3); + let d3 = Self::sign(pt, v3, v1); + + let has_neg = d1 < 0.0 || d2 < 0.0 || d3 < 0.0; + let has_pos = d1 > 0.0 || d2 > 0.0 || d3 > 0.0; + + !(has_neg && has_pos) // True if the point is inside the triangle + } + + /// Finds the triangle that contains the given point. + pub fn find_containing_triangle(&self, new_point: &Point) -> Option { + for (index, triangle) in self.geometry_data.triangles.iter().enumerate() { + // Skip if the triangle is blacklisted + if self.geometry_data.triangle_blacklist.contains(&index) { + continue; + } + + // Retrieve the vertices of the triangle + let v1 = &self.points[triangle.vertices[0]]; + let v2 = &self.points[triangle.vertices[1]]; + let v3 = &self.points[triangle.vertices[2]]; + + // Check if the new_point is inside the current triangle + if Self::point_in_triangle(new_point, v1, v2, v3) { + return Some(index); // Return the index of the containing triangle + } + } + + None // Return None if no containing triangle is found + } + // Additional methods moved into GeometryProcessor, operating on self.geometry_data pub fn random_points(&mut self, center: (f32, f32), side_length: f32, num_points: u32) { // generate random points in a square @@ -247,15 +319,19 @@ impl Xenobalanus { &self.geometry_data.edge_lengths } - pub fn delaunay(&mut self) { - // Convert geo::Point to delaunator::Point for triangulation - let delaunator_points: Vec = self.points.iter() + fn triangulate(&self, points: &Vec) -> Vec { + + let delaunator_points: Vec = points.iter() .map(|point: &Point| DelaunatorPoint { x: point.x as f64, y: point.y as f64 }) .collect(); // Perform Delaunay triangulation let result: delaunator::Triangulation = triangulate(&delaunator_points); - self.triangulation = result.triangles + result.triangles + } + + pub fn delaunay(&mut self) { + self.triangulation = self.triangulate(&self.points); } pub fn preprocess(&mut self, types: usize) { @@ -281,7 +357,7 @@ impl Xenobalanus { let mut processed_triangles: HashSet = HashSet::new(); // Create a sorted list of triangles by their terminal edge length that meet the minimum distance criteria. - let mut triangles_sorted: Vec<(usize, f32)> = self.geometry_data.triangles.iter() + let mut triangles_sorted: Vec<(usize, f32)> = self.triangle_data().iter() .filter_map(|t| t.terminal_edge.and_then(|e| self.geometry_data.edge_lengths.get(&e).map(|&l| (t.index, l)))) .filter(|&(_, length)| length >= min_distance) .collect(); @@ -305,7 +381,7 @@ impl Xenobalanus { processed_triangles.insert(triangle_index); // Get all edges of the current triangle - if let Some(edges) = self.geometry_data.triangles.get(triangle_index).map(|t| t.get_edges()) { + if let Some(edges) = self.triangle(triangle_index).map(|t| t.get_edges()) { for edge in edges { // Add all edges to check for neighbors to expand @@ -328,8 +404,13 @@ impl Xenobalanus { continue; } + // Skip if triangle is blacklisted + if self.geometry_data.triangle_blacklist.contains(&neighbor_index) { + continue; + } + // Get neighbor triangle - if let Some(neighbor_triangle) = self.geometry_data.triangles.get(neighbor_index) { + if let Some(neighbor_triangle) = self.triangle(neighbor_index) { // Get neighbor triangle's terminal edge if let Some(neighbor_edge) = neighbor_triangle.terminal_edge { @@ -358,7 +439,7 @@ impl Xenobalanus { // Retain only those sets that meet the minimum area criteria void_polygons.retain(|set| { set.iter() - .filter_map(|&i| self.geometry_data.triangles[i].area) + .filter_map(|&i| Some(self.triangle_area(i))) .sum::() >= min_area }); From 6c83d0eb1707f6b6b4cc3890e1d6c35b12136b81 Mon Sep 17 00:00:00 2001 From: randogoth Date: Sat, 6 Apr 2024 17:16:15 +0300 Subject: [PATCH 02/11] do it serially --- src/lib.rs | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d134e5f..5199282 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,8 @@ use delaunator::{triangulate, Point as DelaunatorPoint}; use geo::{Point as GeoPoint, Coord}; use rand::Rng; -use rayon::prelude::*; use std::cmp::{min, max}; use std::collections::{HashMap, HashSet}; -use std::sync::{Arc, Mutex}; #[derive(Debug, Clone, Copy)] pub struct Point { @@ -215,6 +213,33 @@ impl Xenobalanus { }).collect() } + pub fn triangle_edges(&self) -> Vec<(usize, usize)> { + let triangles = self.triangle_vertices(); + let mut edges_set = HashSet::new(); + + for triangle in triangles { + // Generate edges from the triangle vertices + let edges = vec![ + (triangle[0], triangle[1]), + (triangle[1], triangle[2]), + (triangle[2], triangle[0]), + ]; + + for mut edge in edges { + // Normalize the edge to ensure consistency in representation + if edge.0 > edge.1 { + edge = (edge.1, edge.0); + } + + // Insert into the HashSet to ensure uniqueness + edges_set.insert(edge); + } + } + + // Convert the HashSet back into a Vec and return + edges_set.into_iter().collect() + } + pub fn triangle_coordinates(&self) -> Vec> { self.triangulation.chunks(3).map(|chunk| { chunk.iter().map(|&index| { @@ -259,17 +284,19 @@ impl Xenobalanus { } pub fn preprocess(&mut self, types: usize) { - let geometry_data = Arc::new(Mutex::new(GeometryData::new())); + // let geometry_data = Arc::new(Mutex::new(GeometryData::new())); + // self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { + // let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself - self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { - let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself + // // Perform locked update + // let mut gd_lock = gd.lock().unwrap(); + // gd_lock.add_triangle(index, &self.points, tri_idx, types); + // }); - // Perform locked update - let mut gd_lock = gd.lock().unwrap(); - gd_lock.add_triangle(index, &self.points, tri_idx, types); + // self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); + self.triangulation.chunks(3).enumerate().for_each(|(index, tri_idx)| { + self.geometry_data.add_triangle(index, &self.points, tri_idx, types); }); - - self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); } pub fn delfin( From e912c7b414b9b43fd60884c7c7da88016773b552 Mon Sep 17 00:00:00 2001 From: randogoth Date: Sun, 7 Apr 2024 16:21:55 +0300 Subject: [PATCH 03/11] Revert "do it serially" This reverts commit 6c83d0eb1707f6b6b4cc3890e1d6c35b12136b81. --- src/lib.rs | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5199282..d134e5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,10 @@ use delaunator::{triangulate, Point as DelaunatorPoint}; use geo::{Point as GeoPoint, Coord}; use rand::Rng; +use rayon::prelude::*; use std::cmp::{min, max}; use std::collections::{HashMap, HashSet}; +use std::sync::{Arc, Mutex}; #[derive(Debug, Clone, Copy)] pub struct Point { @@ -213,33 +215,6 @@ impl Xenobalanus { }).collect() } - pub fn triangle_edges(&self) -> Vec<(usize, usize)> { - let triangles = self.triangle_vertices(); - let mut edges_set = HashSet::new(); - - for triangle in triangles { - // Generate edges from the triangle vertices - let edges = vec![ - (triangle[0], triangle[1]), - (triangle[1], triangle[2]), - (triangle[2], triangle[0]), - ]; - - for mut edge in edges { - // Normalize the edge to ensure consistency in representation - if edge.0 > edge.1 { - edge = (edge.1, edge.0); - } - - // Insert into the HashSet to ensure uniqueness - edges_set.insert(edge); - } - } - - // Convert the HashSet back into a Vec and return - edges_set.into_iter().collect() - } - pub fn triangle_coordinates(&self) -> Vec> { self.triangulation.chunks(3).map(|chunk| { chunk.iter().map(|&index| { @@ -284,19 +259,17 @@ impl Xenobalanus { } pub fn preprocess(&mut self, types: usize) { - // let geometry_data = Arc::new(Mutex::new(GeometryData::new())); - // self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { - // let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself + let geometry_data = Arc::new(Mutex::new(GeometryData::new())); - // // Perform locked update - // let mut gd_lock = gd.lock().unwrap(); - // gd_lock.add_triangle(index, &self.points, tri_idx, types); - // }); + self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { + let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself - // self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); - self.triangulation.chunks(3).enumerate().for_each(|(index, tri_idx)| { - self.geometry_data.add_triangle(index, &self.points, tri_idx, types); + // Perform locked update + let mut gd_lock = gd.lock().unwrap(); + gd_lock.add_triangle(index, &self.points, tri_idx, types); }); + + self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); } pub fn delfin( From a56705383fa8687f672a051063fe920f77974a21 Mon Sep 17 00:00:00 2001 From: randogoth Date: Sun, 7 Apr 2024 16:25:48 +0300 Subject: [PATCH 04/11] optional parallel processing --- readme.md | 4 +++- src/lib.rs | 33 +++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index dae142b..2261de9 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,9 @@ fn main() { println!("Generated Delaunay triangulation"); // Pre-process triangles - xeno.preprocess(0); + // 1 - attractors, 2 - voids, 0 - both + // true/false - parallel processing + xeno.preprocess(0, false); // Execute delfin function with the generated GeometryData let min_area: f32 = 1000.0; // threshold for voidness diff --git a/src/lib.rs b/src/lib.rs index d134e5f..89854b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,18 +258,27 @@ impl Xenobalanus { self.triangulation = result.triangles } - pub fn preprocess(&mut self, types: usize) { - let geometry_data = Arc::new(Mutex::new(GeometryData::new())); - - self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { - let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself - - // Perform locked update - let mut gd_lock = gd.lock().unwrap(); - gd_lock.add_triangle(index, &self.points, tri_idx, types); - }); - - self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); + pub fn preprocess(&mut self, types: usize, parallel: bool) { + if parallel { + + let geometry_data = Arc::new(Mutex::new(GeometryData::new())); + + self.triangulation.par_chunks(3).enumerate().for_each(|(index, tri_idx)| { + let gd = geometry_data.clone(); // Clone Arc for use in each thread, not the data itself + + // Perform locked update + let mut gd_lock = gd.lock().unwrap(); + gd_lock.add_triangle(index, &self.points, tri_idx, types); + }); + + self.geometry_data = Arc::try_unwrap(geometry_data).unwrap().into_inner().unwrap(); + } else { + + self.triangulation.chunks(3).enumerate().for_each(|(index, tri_idx)| { + self.geometry_data.add_triangle(index, &self.points, tri_idx, types); + }); + + } } pub fn delfin( From c254dbf82cc2b28f687b8ac577fd9681b6193c3a Mon Sep 17 00:00:00 2001 From: Flux Date: Tue, 9 Apr 2024 12:30:04 +0300 Subject: [PATCH 05/11] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4763a89 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Tobias Raayoni Last + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 7241882ce5d824450fb7ce166ce82a4050fc227d Mon Sep 17 00:00:00 2001 From: randogoth Date: Tue, 9 Apr 2024 12:38:28 +0300 Subject: [PATCH 06/11] license, pck inf --- Cargo.toml | 7 +++++++ src/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 861b613..400d2ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,13 @@ name = "xenobalanus" version = "0.1.3" edition = "2021" +authors = ["Tobias Raayoni Last "] +repository = "https://github.com/randogoth/xenobalanus" +readme = "readme.md" +license = "MIT" +license-file = "LICENSE" +keywords = ["dtscan", "dbscan", "delfin", "cluster", "void", "delaunay", "astronomy", "attractor"] +categories = ["algorithms", "science", "mathematics"] [lib] name = "xenobalanus" diff --git a/src/lib.rs b/src/lib.rs index 89854b0..8fd25ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,27 @@ +/* +MIT License + +Copyright (c) 2024 Tobias Raayoni Last + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + use delaunator::{triangulate, Point as DelaunatorPoint}; use geo::{Point as GeoPoint, Coord}; use rand::Rng; From 898c13f70ead7cec99f2d633fad533fbb07fafce Mon Sep 17 00:00:00 2001 From: randogoth Date: Wed, 10 Apr 2024 06:04:34 +0300 Subject: [PATCH 07/11] rad --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/lib.rs | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f37377..35c288f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "xenobalanus" -version = "0.1.3" +version = "0.1.4" dependencies = [ "delaunator", "geo", diff --git a/Cargo.toml b/Cargo.toml index 861b613..d09551f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xenobalanus" -version = "0.1.3" +version = "0.1.4" edition = "2021" [lib] diff --git a/src/lib.rs b/src/lib.rs index 89854b0..8a58c5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,12 @@ impl Point { bearing } + pub fn bearing_rad(&self, point: Point) -> f32 { + let delta_x = point.x - self.x; + let delta_y = point.y - self.y; + delta_y.atan2(delta_x) + } + } impl From for Coord { From f2211bf5f574f9ca499d857e0f9d40cbfb533ab4 Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 11 Jun 2026 11:35:05 +0300 Subject: [PATCH 08/11] upgraded packages --- Cargo.lock | 592 +++++++++++++++++++++++++++++++---------------------- Cargo.toml | 9 +- src/lib.rs | 8 +- 3 files changed, 353 insertions(+), 256 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35c288f..080cd68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,18 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] +version = 4 [[package]] name = "allocator-api2" @@ -20,6 +8,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "approx" version = "0.5.1" @@ -36,10 +30,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] -name = "bytemuck" -version = "1.15.0" +name = "bitflags" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "byteorder" @@ -53,6 +47,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -93,7 +107,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" dependencies = [ - "itertools 0.11.0", + "itertools", "num-traits", ] @@ -103,6 +117,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "float_next_after" version = "1.0.0" @@ -110,15 +130,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" [[package]] -name = "geo" -version = "0.28.0" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f811f663912a69249fa620dcd2a005db7254529da2d8a0b23942e81f47084501" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "geo" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4416397671d8997e9a3e7ad99714f4f00a22e9eaa9b966a5985d2194fc9e02e1" dependencies = [ "earcutr", "float_next_after", "geo-types", "geographiclib-rs", + "i_overlay", "log", "num-traits", "robust 1.1.0", @@ -128,12 +155,13 @@ dependencies = [ [[package]] name = "geo-types" -version = "0.7.13" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" +checksum = "94776032c45f950d30a13af6113c2ad5625316c9abfbccee4dd5a6695f8fe0f5" dependencies = [ "approx", "num-traits", + "rayon", "rstar", "serde", ] @@ -149,13 +177,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "rand_core", + "wasip2", + "wasip3", ] [[package]] @@ -169,14 +200,21 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "heapless" version = "0.8.0" @@ -187,6 +225,74 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "i_float" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85df3a416829bb955fdc2416c7b73680c8dcea8d731f2c7aa23e1042fe1b8343" +dependencies = [ + "serde", +] + +[[package]] +name = "i_key_sort" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "347c253b4748a1a28baf94c9ce133b6b166f08573157e05afe718812bc599fcd" + +[[package]] +name = "i_overlay" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0542dfef184afdd42174a03dcc0625b6147fb73e1b974b1a08a2a42ac35cee49" +dependencies = [ + "i_float", + "i_key_sort", + "i_shape", + "i_tree", + "rayon", +] + +[[package]] +name = "i_shape" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a38f5a42678726718ff924f6d4a0e79b129776aeed298f71de4ceedbd091bce" +dependencies = [ + "i_float", + "serde", +] + +[[package]] +name = "i_tree" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155181bc97d770181cf9477da51218a19ee92a8e5be642e796661aee2b601139" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + [[package]] name = "itertools" version = "0.11.0" @@ -197,25 +303,22 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.12.1" +name = "itoa" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" @@ -230,72 +333,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] -name = "matrixmultiply" -version = "0.3.8" +name = "memchr" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "nalgebra" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d506eb7e08d6329505faa8a3a00a5dcc6de9f76e0c77e4b75763ae3c770831ff" -dependencies = [ - "approx", - "matrixmultiply", - "nalgebra-macros", - "num-complex", - "num-rational", - "num-traits", - "rand", - "rand_distr", - "simba", - "typenum", -] - -[[package]] -name = "nalgebra-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "num-complex" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "num-traits" @@ -308,28 +349,20 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -344,56 +377,33 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.8.5" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rand" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "ppv-lite86", + "chacha20", + "getrandom", "rand_core", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_distr" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" -dependencies = [ - "num-traits", - "rand", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rayon" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -401,9 +411,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -433,45 +443,52 @@ dependencies = [ ] [[package]] -name = "safe_arch" -version = "0.7.1" +name = "semver" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" -dependencies = [ - "bytemuck", -] +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] -name = "simba" -version = "0.6.0" +name = "serde_json" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b7840f121a46d63066ee7a99fc81dcabbc6105e437cae43528cea199b5a05f" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", - "wide", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", ] [[package]] @@ -482,11 +499,11 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "spade" -version = "2.6.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61addf9117b11d1f5b4bf6fe94242ba25f59d2d4b2080544b771bd647024fd00" +checksum = "a14e31a007e9f85c32784b04f89e6e194bb252a4d41b4a8ccd9e77245d901c8c" dependencies = [ - "hashbrown", + "hashbrown 0.15.5", "num-traits", "robust 1.1.0", "smallvec", @@ -498,47 +515,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "statrs" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d08e5e1748192713cc281da8b16924fb46be7b0c2431854eadc785823e5696e" -dependencies = [ - "approx", - "lazy_static", - "nalgebra", - "num-traits", - "rand", -] - [[package]] name = "syn" -version = "1.0.109" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn" -version = "2.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -546,25 +533,155 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "version_check" -version = "0.9.4" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wide" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "bytemuck", - "safe_arch", + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] [[package]] @@ -573,29 +690,12 @@ version = "0.1.4" dependencies = [ "delaunator", "geo", - "geo-types", - "itertools 0.12.1", "rand", "rayon", - "statrs", ] [[package]] -name = "zerocopy" -version = "0.7.32" +name = "zmij" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", -] +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index a049517..b3933f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,6 @@ name = "xenobalanus" [dependencies] delaunator = "1.0.2" -geo = "0.28.0" -geo-types = "0.7.13" -itertools = "0.12.1" -rand = "0.8.5" -rayon = "1.9.0" -statrs = "0.16.0" +geo = "0.30" +rand = "0.10" +rayon = "1.12" diff --git a/src/lib.rs b/src/lib.rs index 0805739..3af0075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ SOFTWARE. use delaunator::{triangulate, Point as DelaunatorPoint}; use geo::{Point as GeoPoint, Coord}; -use rand::Rng; +use rand::RngExt; use rayon::prelude::*; use std::cmp::{min, max}; use std::collections::{HashMap, HashSet}; @@ -265,10 +265,10 @@ impl Xenobalanus { let max_x = center.0 + side_length / 2.0; let min_y = center.1 - side_length / 2.0; let max_y = center.1 + side_length / 2.0; - let mut rng: rand::prelude::ThreadRng = rand::thread_rng(); + let mut rng = rand::rng(); for _ in 0..num_points { - let x = min_x + rng.gen_range(0.0..=1.0) as f32 * ( max_x - min_x); - let y: f32 = min_y + rng.gen_range(0.0..=1.0) as f32 * ( max_y - min_y); + let x = min_x + rng.random_range(0.0..=1.0) as f32 * ( max_x - min_x); + let y: f32 = min_y + rng.random_range(0.0..=1.0) as f32 * ( max_y - min_y); self.points.push(Point {x, y}); } } From f6d1241ecd8cbc91095f3ab120eee016f4e1d971 Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 11 Jun 2026 11:35:15 +0300 Subject: [PATCH 09/11] added devbox --- devbox.json | 14 +++++++++++++ devbox.lock | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 devbox.json create mode 100644 devbox.lock diff --git a/devbox.json b/devbox.json new file mode 100644 index 0000000..c8f865f --- /dev/null +++ b/devbox.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.16.0/.schema/devbox.schema.json", + "packages": ["rustup@latest"], + "shell": { + "init_hook": [ + "echo 'Welcome to devbox!' > /dev/null" + ], + "scripts": { + "test": [ + "echo \"Error: no test specified\" && exit 1" + ] + } + } +} diff --git a/devbox.lock b/devbox.lock new file mode 100644 index 0000000..818bec3 --- /dev/null +++ b/devbox.lock @@ -0,0 +1,58 @@ +{ + "lockfile_version": "1", + "packages": { + "github:NixOS/nixpkgs/nixpkgs-unstable": { + "last_modified": "2026-05-29T05:01:12Z", + "resolved": "github:NixOS/nixpkgs/e9a7635a57597d9754eccebdfc7045e6c8600e6b?lastModified=1780030872&narHash=sha256-u6WU%2Fyd%2Fo8iYQrHX3RAwO1hYa3LkoSL%2BWNQD0rJfJZQ%3D" + }, + "rustup@latest": { + "last_modified": "2026-05-21T08:15:18Z", + "plugin_version": "0.0.1", + "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#rustup", + "source": "devbox-search", + "version": "1.29.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nl70ay30nl2szm2g03xa0d7ai69dgbln-rustup-1.29.0", + "default": true + } + ], + "store_path": "/nix/store/nl70ay30nl2szm2g03xa0d7ai69dgbln-rustup-1.29.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/684175m8xqfisacqw9rdc97fn2vpp0fj-rustup-1.29.0", + "default": true + } + ], + "store_path": "/nix/store/684175m8xqfisacqw9rdc97fn2vpp0fj-rustup-1.29.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4hqncs7jnqc64z49r1w09b235074li9q-rustup-1.29.0", + "default": true + } + ], + "store_path": "/nix/store/4hqncs7jnqc64z49r1w09b235074li9q-rustup-1.29.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dpqx1vygrisrvnnwgym1226x317vqp4a-rustup-1.29.0", + "default": true + } + ], + "store_path": "/nix/store/dpqx1vygrisrvnnwgym1226x317vqp4a-rustup-1.29.0" + } + } + } + } +} From 5e3441584aa30a6438d964388d73de328e3dbe37 Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 11 Jun 2026 11:37:45 +0300 Subject: [PATCH 10/11] added tests --- src/lib.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3af0075..d9b71a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -454,4 +454,142 @@ impl Xenobalanus { clusters } +} + +#[cfg(test)] +mod tests { + use super::*; + + // --- Point --- + + #[test] + fn point_distance_3_4_5() { + let a = Point::new(0.0, 0.0); + let b = Point::new(3.0, 4.0); + assert!((a.distance(b) - 5.0).abs() < 1e-5); + } + + #[test] + fn point_bearing_east_is_zero() { + let origin = Point::new(0.0, 0.0); + let east = Point::new(1.0, 0.0); + // delta_y=0, delta_x=1 → atan2(0,1)=0° → bearing=0° + assert!((origin.bearing(east) - 0.0).abs() < 1e-4); + } + + // --- random_points --- + + #[test] + fn random_points_count_and_bounds() { + let mut xb = Xenobalanus::new(); + xb.random_points((0.0, 0.0), 10.0, 100); + let pts = xb.points(); + assert_eq!(pts.len(), 100); + for (x, y) in pts { + assert!(x >= -5.0 && x <= 5.0, "x={x} out of [-5, 5]"); + assert!(y >= -5.0 && y <= 5.0, "y={y} out of [-5, 5]"); + } + } + + // --- delaunay --- + + fn unit_square() -> Vec { + vec![ + Point::new(0.0, 0.0), + Point::new(1.0, 0.0), + Point::new(1.0, 1.0), + Point::new(0.0, 1.0), + ] + } + + #[test] + fn delaunay_four_points_two_triangles() { + let mut xb = Xenobalanus::new(); + xb.set_points(unit_square()); + xb.delaunay(); + // 4 convex points → 2 triangles → 6 indices + assert_eq!(xb.triangles_flat().len(), 6); + } + + // --- preprocess --- + + #[test] + fn preprocess_sequential_builds_edges() { + let mut xb = Xenobalanus::new(); + xb.set_points(unit_square()); + xb.delaunay(); + xb.preprocess(0, false); + // unit square Delaunay: 4 boundary edges + 1 diagonal = 5 + assert_eq!(xb.edge_lengths().len(), 5); + } + + #[test] + fn preprocess_parallel_matches_sequential() { + let mut xb_seq = Xenobalanus::new(); + xb_seq.set_points(unit_square()); + xb_seq.delaunay(); + xb_seq.preprocess(0, false); + + let mut xb_par = Xenobalanus::new(); + xb_par.set_points(unit_square()); + xb_par.delaunay(); + xb_par.preprocess(0, true); + + assert_eq!(xb_seq.edge_lengths().len(), xb_par.edge_lengths().len()); + } + + // --- dtscan --- + + #[test] + fn dtscan_finds_cluster_in_grid() { + let mut xb = Xenobalanus::new(); + // 3×3 grid with spacing 1.0; diagonal ≈ 1.414 + let pts: Vec = (0..3) + .flat_map(|i| (0..3).map(move |j| Point::new(i as f32, j as f32))) + .collect(); + xb.set_points(pts); + xb.delaunay(); + xb.preprocess(0, false); + // max_closeness=1.5 covers all edges (max diagonal ≈ 1.414) + let clusters = xb.dtscan(2, 1.5); + assert!(!clusters.is_empty()); + } + + // --- delfin --- + + #[test] + fn delfin_smoke_test() { + let mut xb = Xenobalanus::new(); + xb.random_points((0.0, 0.0), 100.0, 200); + xb.delaunay(); + xb.preprocess(2, false); + // just verify it runs without panic + let _voids = xb.delfin(0.0, 0.0); + } + + // --- readme example --- + + #[test] + fn readme_example_pipeline() { + // Mirrors the workflow shown in the README exactly. + let dots: u32 = 10000; + let side_length: f32 = 10000.0; + let mut xeno = Xenobalanus::new(); + xeno.random_points((0.0, 0.0), side_length, dots); + + xeno.delaunay(); + xeno.preprocess(0, false); + + let min_area: f32 = 1000.0; + let min_distance: f32 = 200.0; + let void_polygons: Vec> = xeno.delfin(min_area, min_distance); + + let min_pts: usize = 5; + let max_closeness: f32 = 100.5; + let clusters: Vec> = xeno.dtscan(min_pts, max_closeness); + + // With 10 000 uniform random points both algorithms should find results. + assert!(!void_polygons.is_empty(), "delfin found no voids"); + assert!(!clusters.is_empty(), "dtscan found no clusters"); + } } \ No newline at end of file From 545bcb1633776c3c4ab226db7b4ff2240892bb9d Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 11 Jun 2026 11:38:30 +0300 Subject: [PATCH 11/11] bumped version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b3933f2..f89cbbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xenobalanus" -version = "0.1.4" +version = "0.2.0" edition = "2021" authors = ["Tobias Raayoni Last "] repository = "https://github.com/randogoth/xenobalanus"