use geo::{Point, Polygon, LineString, EuclideanDistance, Area}; use std::collections::{HashMap, HashSet}; use std::cmp::{min, max}; use rand::Rng; use rayon::prelude::*; use delaunator::{triangulate, Point as DelaunatorPoint}; pub fn random_points(center: (f32, f32), radius: f32, num_points: usize) -> Vec> { let mut rng: rand::prelude::ThreadRng = rand::thread_rng(); let mut points: Vec> = Vec::with_capacity(num_points); for _ in 0..num_points { // Generate a random angle between 0 and 2*PI. let angle: f32 = rng.gen_range(0.0..(2.0 * std::f32::consts::PI)); // Generate a random radius to ensure uniform distribution within the circle. let r: f32 = (rng.gen_range(0.0..=1.0) as f32).sqrt() * radius; // Calculate x and y coordinates based on the random angle and radius. let x: f32 = center.0 + r * angle.cos(); let y: f32 = center.1 + r * angle.sin(); // Add the generated point to the points vector. points.push(Point::new(x, y)); } points } pub fn delaunay(points: &Vec>) -> Vec { // Convert geo::Point to delaunator::Point for triangulation 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); // Return the indices of points in the triangles result.triangles } fn preprocess(points: &[Point], triangles: &[usize]) -> ( HashMap>, HashMap, HashMap<(usize, usize), HashSet>, HashMap<(usize, usize), f32>, HashMap>, ) { // Process each set of triangle indices in parallel let triangle_calculation: Vec<_> = triangles.par_chunks(3).map(|tri_idx| { let point_a: Point = points[tri_idx[0]]; let point_b: Point = points[tri_idx[1]]; let point_c: Point = points[tri_idx[2]]; // Calculate the lengths of each edge and pair them with their vertex indices let edges_with_lengths: [((usize, usize), f32); 3] = [ ((min(tri_idx[0], tri_idx[1]), max(tri_idx[0], tri_idx[1])), point_a.euclidean_distance(&point_b)), ((min(tri_idx[1], tri_idx[2]), max(tri_idx[1], tri_idx[2])), point_b.euclidean_distance(&point_c)), ((min(tri_idx[2], tri_idx[0]), max(tri_idx[2], tri_idx[0])), point_c.euclidean_distance(&point_a)), ]; // Sort edges by length to ensure the longest edge is first let mut edges_sorted: Vec<((usize, usize), f32)> = edges_with_lengths.to_vec(); edges_sorted.sort_by(|a: &((usize, usize), f32), b: &((usize, usize), f32)| b.1.partial_cmp(&a.1).unwrap()); let terminal_edges: HashSet = [edges_sorted[0].0 .0, edges_sorted[0].0 .1].iter().cloned().collect::>(); // Collect 'area_map' with area for each triangle let poly: Polygon = Polygon::new(LineString::from(vec![ (point_a.x(), point_a.y()), (point_b.x(), point_b.y()), (point_c.x(), point_c.y()), (point_a.x(), point_a.y()), ]), vec![]); let area: f32 = poly.unsigned_area(); // Generate the node connections let mut node_connections: HashMap> = HashMap::new(); for &idx in tri_idx.iter() { let connected_nodes: HashSet = tri_idx.iter().filter(|&&x| x != idx).cloned().collect::>(); node_connections.insert(idx, connected_nodes); } // Return all calculated data for this triangle (tri_idx[0] / 3, terminal_edges, area, edges_sorted, node_connections) }).collect(); // Initialize shared data structures let mut terminal_map: HashMap> = HashMap::new(); // terminal edge for each triangle let mut area_map: HashMap = HashMap::new(); // area for each triangle let mut wing_map: HashMap<(usize, usize), HashSet> = HashMap::new(); // triangle index for each edge let mut edge_map: HashMap<(usize, usize), f32> = HashMap::new(); // length for each edge let mut node_map: HashMap> = HashMap::new(); // vertices connected to each vertex // Merge all triangle results for (triangle_index, terminal_edges, area, edges_sorted, node_connections) in triangle_calculation { terminal_map.insert(triangle_index, terminal_edges); area_map.insert(triangle_index, area); for &(edge, length) in &edges_sorted { wing_map.entry(edge).or_insert_with(HashSet::new).insert(triangle_index); edge_map.insert(edge, length); } for (idx, connections) in node_connections { node_map.entry(idx).or_insert_with(HashSet::new).extend(connections); } } (terminal_map, area_map, wing_map, edge_map, node_map) } fn main() { let points: Vec> = random_points((0.0, 0.0), 300.0, 2000); let triangles: Vec = delaunay(&points); let result: (HashMap>, HashMap, HashMap<(usize, usize), HashSet>, HashMap<(usize, usize), f32>, HashMap>) = preprocess(&points, &triangles); println!("{:?}", result); }