preprocess multithreaded
This commit is contained in:
parent
0e1453316a
commit
486f3246fc
3 changed files with 107 additions and 34 deletions
46
Cargo.lock
generated
46
Cargo.lock
generated
|
|
@ -47,6 +47,31 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "delaunator"
|
name = "delaunator"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -253,6 +278,26 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "robust"
|
name = "robust"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|
@ -338,6 +383,7 @@ dependencies = [
|
||||||
"delaunator",
|
"delaunator",
|
||||||
"geo",
|
"geo",
|
||||||
"rand",
|
"rand",
|
||||||
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,4 @@ edition = "2021"
|
||||||
delaunator = "1.0.2"
|
delaunator = "1.0.2"
|
||||||
geo = "0.28.0"
|
geo = "0.28.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
rayon = "1.9.0"
|
||||||
|
|
|
||||||
94
src/main.rs
94
src/main.rs
|
|
@ -2,6 +2,7 @@ use geo::{Point, Polygon, LineString, EuclideanDistance, Area};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use rayon::prelude::*;
|
||||||
use delaunator::{triangulate, Point as DelaunatorPoint};
|
use delaunator::{triangulate, Point as DelaunatorPoint};
|
||||||
|
|
||||||
pub fn random_points(center: (f32, f32), radius: f32, num_points: usize) -> Vec<Point<f32>> {
|
pub fn random_points(center: (f32, f32), radius: f32, num_points: usize) -> Vec<Point<f32>> {
|
||||||
|
|
@ -23,7 +24,7 @@ pub fn random_points(center: (f32, f32), radius: f32, num_points: usize) -> Vec<
|
||||||
points
|
points
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delaunay(points: Vec<Point<f32>>) -> Vec<usize> {
|
pub fn delaunay(points: &Vec<Point<f32>>) -> Vec<usize> {
|
||||||
// Convert geo::Point<f32> to delaunator::Point for triangulation
|
// Convert geo::Point<f32> to delaunator::Point for triangulation
|
||||||
let delaunator_points: Vec<DelaunatorPoint> = points.iter()
|
let delaunator_points: Vec<DelaunatorPoint> = points.iter()
|
||||||
.map(|point: &Point<f32>| DelaunatorPoint { x: point.x() as f64, y: point.y() as f64 })
|
.map(|point: &Point<f32>| DelaunatorPoint { x: point.x() as f64, y: point.y() as f64 })
|
||||||
|
|
@ -36,55 +37,80 @@ pub fn delaunay(points: Vec<Point<f32>>) -> Vec<usize> {
|
||||||
result.triangles
|
result.triangles
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preprocess(dots: Vec<(f32, f32)>, triangles: Vec<usize>) -> (Vec<Point<f32>>, HashMap<usize, HashSet<usize>>, HashMap<usize, f32>, HashMap<(usize, usize), HashSet<usize>>, HashMap<(usize, usize), f32>, HashMap<usize, HashSet<usize>>) {
|
fn preprocess(points: &[Point<f32>], triangles: &[usize]) -> (
|
||||||
let points: Vec<Point<f32>> = dots.into_iter().map(|(x, y)| Point::new(x, y)).collect();
|
HashMap<usize, HashSet<usize>>,
|
||||||
|
HashMap<usize, f32>,
|
||||||
|
HashMap<(usize, usize), HashSet<usize>>,
|
||||||
|
HashMap<(usize, usize), f32>,
|
||||||
|
HashMap<usize, HashSet<usize>>,
|
||||||
|
) {
|
||||||
|
// Process each set of triangle indices in parallel
|
||||||
|
let triangle_calculation: Vec<_> = triangles.par_chunks(3).map(|tri_idx| {
|
||||||
|
let point_a: Point<f32> = points[tri_idx[0]];
|
||||||
|
let point_b: Point<f32> = points[tri_idx[1]];
|
||||||
|
let point_c: Point<f32> = points[tri_idx[2]];
|
||||||
|
|
||||||
let mut wing_map: HashMap<(usize, usize), HashSet<usize>> = HashMap::new();
|
// Calculate the lengths of each edge and pair them with their vertex indices
|
||||||
let mut node_map: HashMap<usize, HashSet<usize>> = HashMap::new();
|
let edges_with_lengths: [((usize, usize), f32); 3] = [
|
||||||
let mut edge_map: HashMap<(usize, usize), f32> = HashMap::new();
|
|
||||||
let mut terminal_map: HashMap<usize, HashSet<usize>> = HashMap::new();
|
|
||||||
let mut area_map: HashMap<usize, f32> = HashMap::new();
|
|
||||||
|
|
||||||
for i in (0..triangles.len()).step_by(3) {
|
|
||||||
let tri_idx = &triangles[i..i + 3];
|
|
||||||
let point_a = points[tri_idx[0]];
|
|
||||||
let point_b = points[tri_idx[1]];
|
|
||||||
let point_c = points[tri_idx[2]];
|
|
||||||
|
|
||||||
let edges_with_lengths = [
|
|
||||||
((min(tri_idx[0], tri_idx[1]), max(tri_idx[0], tri_idx[1])), point_a.euclidean_distance(&point_b)),
|
((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[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)),
|
((min(tri_idx[2], tri_idx[0]), max(tri_idx[2], tri_idx[0])), point_c.euclidean_distance(&point_a)),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut edges_sorted = edges_with_lengths.to_vec();
|
// Sort edges by length to ensure the longest edge is first
|
||||||
edges_sorted.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
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<usize> = [edges_sorted[0].0 .0, edges_sorted[0].0 .1].iter().cloned().collect::<HashSet<_>>();
|
||||||
|
|
||||||
terminal_map.insert(i / 3, [edges_sorted[0].0 .0, edges_sorted[0].0 .1].iter().cloned().collect());
|
// Collect 'area_map' with area for each triangle
|
||||||
|
let poly: Polygon<f32> = Polygon::new(LineString::from(vec![
|
||||||
for &(edge, length) in &edges_sorted {
|
|
||||||
wing_map.entry(edge).or_insert_with(HashSet::new).insert(i / 3);
|
|
||||||
edge_map.insert(edge, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
for &idx in tri_idx.iter() {
|
|
||||||
node_map.entry(idx).or_insert_with(HashSet::new).extend(tri_idx.iter().filter(|&&x| x != idx).cloned());
|
|
||||||
}
|
|
||||||
|
|
||||||
let poly = Polygon::new(LineString::from(vec![
|
|
||||||
(point_a.x(), point_a.y()),
|
(point_a.x(), point_a.y()),
|
||||||
(point_b.x(), point_b.y()),
|
(point_b.x(), point_b.y()),
|
||||||
(point_c.x(), point_c.y()),
|
(point_c.x(), point_c.y()),
|
||||||
(point_a.x(), point_a.y()), // Close the loop
|
(point_a.x(), point_a.y()),
|
||||||
]), vec![]);
|
]), vec![]);
|
||||||
|
let area: f32 = poly.unsigned_area();
|
||||||
|
|
||||||
area_map.insert(i / 3, poly.unsigned_area()); // Correctly calculate the area
|
// Generate the node connections
|
||||||
|
let mut node_connections: HashMap<usize, HashSet<usize>> = HashMap::new();
|
||||||
|
for &idx in tri_idx.iter() {
|
||||||
|
let connected_nodes: HashSet<usize> = tri_idx.iter().filter(|&&x| x != idx).cloned().collect::<HashSet<_>>();
|
||||||
|
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<usize, HashSet<usize>> = HashMap::new(); // terminal edge for each triangle
|
||||||
|
let mut area_map: HashMap<usize, f32> = HashMap::new(); // area for each triangle
|
||||||
|
let mut wing_map: HashMap<(usize, usize), HashSet<usize>> = 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<usize, HashSet<usize>> = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(points, terminal_map, area_map, wing_map, edge_map, node_map)
|
(terminal_map, area_map, wing_map, edge_map, node_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
let points: Vec<Point<f32>> = random_points((0.0, 0.0), 300.0, 2000);
|
||||||
|
let triangles: Vec<usize> = delaunay(&points);
|
||||||
|
let result: (HashMap<usize, HashSet<usize>>, HashMap<usize, f32>, HashMap<(usize, usize), HashSet<usize>>, HashMap<(usize, usize), f32>, HashMap<usize, HashSet<usize>>) = preprocess(&points, &triangles);
|
||||||
|
println!("{:?}", result);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue