simplification
This commit is contained in:
parent
708ac7f409
commit
92d7a755d5
1 changed files with 51 additions and 77 deletions
128
src/main.rs
128
src/main.rs
|
|
@ -15,9 +15,9 @@ struct Edge(usize, usize);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TriangleData {
|
struct TriangleData {
|
||||||
index: usize,
|
index: usize,
|
||||||
|
vertices: Vec<usize>,
|
||||||
area: Option<f32>,
|
area: Option<f32>,
|
||||||
terminal_edge: Option<Edge>,
|
terminal_edge: Option<Edge>
|
||||||
third_vertex: Option<usize>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -43,6 +43,9 @@ impl GeometryData {
|
||||||
let point_b: Point<f32> = points[tri_idx[1]];
|
let point_b: Point<f32> = points[tri_idx[1]];
|
||||||
let point_c: Point<f32> = points[tri_idx[2]];
|
let point_c: Point<f32> = points[tri_idx[2]];
|
||||||
|
|
||||||
|
let mut vertices = vec![tri_idx[0], tri_idx[1], tri_idx[2]];
|
||||||
|
vertices.sort_unstable();
|
||||||
|
|
||||||
// Temporarily store edges_with_lengths for sorting and determining the terminal_edge.
|
// Temporarily store edges_with_lengths for sorting and determining the terminal_edge.
|
||||||
let mut edges_with_lengths_temp = [
|
let mut edges_with_lengths_temp = [
|
||||||
(Edge(min(tri_idx[0], tri_idx[1]), max(tri_idx[0], tri_idx[1])), point_a.euclidean_distance(&point_b)),
|
(Edge(min(tri_idx[0], tri_idx[1]), max(tri_idx[0], tri_idx[1])), point_a.euclidean_distance(&point_b)),
|
||||||
|
|
@ -53,11 +56,6 @@ impl GeometryData {
|
||||||
// Sort edges by length to ensure the longest edge is identified.
|
// Sort edges by length to ensure the longest edge is identified.
|
||||||
edges_with_lengths_temp.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
edges_with_lengths_temp.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
||||||
let terminal_edge: Option<Edge> = edges_with_lengths_temp.first().map(|(edge, _)| *edge);
|
let terminal_edge: Option<Edge> = edges_with_lengths_temp.first().map(|(edge, _)| *edge);
|
||||||
|
|
||||||
// Determine the third vertex
|
|
||||||
let third_vertex: Option<usize> = tri_idx.iter().find(|&&idx| {
|
|
||||||
idx != terminal_edge.unwrap().0 && idx != terminal_edge.unwrap().1
|
|
||||||
}).copied();
|
|
||||||
|
|
||||||
let area: Option<f32> = if types == 0 || types == 2 {
|
let area: Option<f32> = if types == 0 || types == 2 {
|
||||||
Some(Polygon::new(LineString::from(vec![
|
Some(Polygon::new(LineString::from(vec![
|
||||||
|
|
@ -88,9 +86,9 @@ impl GeometryData {
|
||||||
if types == 0 || types == 2 {
|
if types == 0 || types == 2 {
|
||||||
self.triangles.push(TriangleData {
|
self.triangles.push(TriangleData {
|
||||||
index,
|
index,
|
||||||
|
vertices,
|
||||||
area,
|
area,
|
||||||
terminal_edge,
|
terminal_edge
|
||||||
third_vertex
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +151,7 @@ fn delfin(
|
||||||
geometry_data: &GeometryData,
|
geometry_data: &GeometryData,
|
||||||
min_area: f32,
|
min_area: f32,
|
||||||
min_distance: f32,
|
min_distance: f32,
|
||||||
) -> Vec<Vec<HashSet<usize>>> {
|
) -> Vec<Vec<Vec<usize>>> {
|
||||||
|
|
||||||
// Sort all triangles by the longest terminal edge
|
// Sort all triangles by the longest terminal edge
|
||||||
let triangles_sorted: Vec<(usize, f32)> = geometry_data.triangles.iter()
|
let triangles_sorted: Vec<(usize, f32)> = geometry_data.triangles.iter()
|
||||||
|
|
@ -269,73 +267,32 @@ fn delfin(
|
||||||
area_z_score >= min_area && poly_set.len() >= 3
|
area_z_score >= min_area && poly_set.len() >= 3
|
||||||
});
|
});
|
||||||
|
|
||||||
void_polygons.iter().map(|triangle_set| {
|
let void_polygons_vertices: Vec<Vec<Vec<usize>>> = void_polygons.into_iter().map(|triangle_set: HashSet<usize>| {
|
||||||
triangle_set.iter().map(|&triangle_index| {
|
triangle_set.into_iter().map(|triangle_index| {
|
||||||
let triangle = &geometry_data.triangles[triangle_index];
|
// Directly retrieve the vertices of the triangle
|
||||||
let mut vertices = HashSet::new();
|
geometry_data.triangles[triangle_index].vertices.clone()
|
||||||
if let Some(terminal_edge) = triangle.terminal_edge {
|
|
||||||
vertices.insert(terminal_edge.0);
|
|
||||||
vertices.insert(terminal_edge.1);
|
|
||||||
}
|
|
||||||
if let Some(third_vertex) = triangle.third_vertex {
|
|
||||||
vertices.insert(third_vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
vertices
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<HashSet<usize>>>()
|
// Collecting into Vec<Vec<usize>>, each inner Vec<usize> represents a triangle's vertices
|
||||||
|
.collect::<Vec<Vec<usize>>>()
|
||||||
})
|
})
|
||||||
.collect()
|
// Collect each void area's vertex sets into the final Vec
|
||||||
|
.collect::<Vec<Vec<Vec<usize>>>>();
|
||||||
|
|
||||||
}
|
// Return the transformed structure
|
||||||
|
void_polygons_vertices
|
||||||
|
|
||||||
// Function to recursively expand clusters
|
|
||||||
fn expand_cluster(
|
|
||||||
vertex_idx: usize,
|
|
||||||
visited: &mut HashSet<usize>,
|
|
||||||
cluster: &mut HashSet<usize>,
|
|
||||||
geometry_data: &GeometryData,
|
|
||||||
mean_edge_length: f32,
|
|
||||||
std_edge_length: f32,
|
|
||||||
max_closeness: f32,
|
|
||||||
) {
|
|
||||||
visited.insert(vertex_idx);
|
|
||||||
|
|
||||||
if let Some(neighbors) = geometry_data.vertex_connections.get(&vertex_idx) {
|
|
||||||
for &neighbor_idx in neighbors {
|
|
||||||
if visited.contains(&neighbor_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let edge = Edge(min(vertex_idx, neighbor_idx), max(vertex_idx, neighbor_idx));
|
|
||||||
if let Some(&length) = geometry_data.edge_lengths.get(&edge) {
|
|
||||||
let z_score: f32 = (length - mean_edge_length) / std_edge_length;
|
|
||||||
if z_score <= max_closeness {
|
|
||||||
cluster.insert(neighbor_idx);
|
|
||||||
expand_cluster(
|
|
||||||
neighbor_idx,
|
|
||||||
visited,
|
|
||||||
cluster,
|
|
||||||
geometry_data,
|
|
||||||
mean_edge_length,
|
|
||||||
std_edge_length,
|
|
||||||
max_closeness,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dtscan(
|
fn dtscan(
|
||||||
geometry_data: &GeometryData,
|
geometry_data: &GeometryData,
|
||||||
min_pts: usize,
|
min_pts: usize,
|
||||||
max_closeness: f32,
|
max_closeness: f32,
|
||||||
) -> Vec<HashSet<usize>> {
|
) -> Vec<Vec<usize>> {
|
||||||
let mut clusters: Vec<HashSet<usize>> = Vec::new();
|
let mut clusters: Vec<Vec<usize>> = Vec::new();
|
||||||
let mut visited: HashSet<usize> = HashSet::new();
|
let mut visited: HashSet<usize> = HashSet::new();
|
||||||
let edge_lengths_values: Vec<f32> = geometry_data.edge_lengths.values().cloned().collect();
|
let edge_lengths_values: Vec<f32> = geometry_data.edge_lengths.values().cloned().collect();
|
||||||
let (mean_edge_length, std_edge_length) = mean_std(edge_lengths_values);
|
let (mean_edge_length, std_edge_length) = mean_std(edge_lengths_values);
|
||||||
|
|
||||||
for (&vertex_idx, neighbors) in &geometry_data.vertex_connections {
|
for (&vertex_idx, neighbors) in &geometry_data.vertex_connections {
|
||||||
if visited.contains(&vertex_idx) {
|
if visited.contains(&vertex_idx) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -349,23 +306,39 @@ fn dtscan(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
let mut cluster: HashSet<usize> = HashSet::new();
|
let mut cluster: Vec<usize> = Vec::new();
|
||||||
expand_cluster(
|
let mut to_expand: Vec<usize> = vec![vertex_idx];
|
||||||
vertex_idx,
|
|
||||||
&mut visited,
|
while let Some(current_vertex) = to_expand.pop() {
|
||||||
&mut cluster,
|
if !visited.insert(current_vertex) {
|
||||||
geometry_data,
|
continue;
|
||||||
mean_edge_length,
|
}
|
||||||
std_edge_length,
|
|
||||||
max_closeness,
|
cluster.push(current_vertex);
|
||||||
);
|
|
||||||
clusters.push(cluster);
|
// Add neighbors that are within max_closeness to to_expand
|
||||||
|
geometry_data.vertex_connections.get(¤t_vertex).map(|neighbors: &HashSet<usize>| {
|
||||||
|
for &neighbor in neighbors {
|
||||||
|
if let Some(&length) = geometry_data.edge_lengths.get(&Edge(min(current_vertex, neighbor), max(current_vertex, neighbor))) {
|
||||||
|
let z_score = (length - mean_edge_length) / std_edge_length;
|
||||||
|
if z_score <= max_closeness && !visited.contains(&neighbor) {
|
||||||
|
to_expand.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cluster.is_empty() {
|
||||||
|
clusters.push(cluster); // Add the constructed cluster to the list of clusters
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clusters
|
clusters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn improbability_z_score(total_area: f32, total_dots: u32, sub_area: f32, sub_dots: u32) -> f32 {
|
fn improbability_z_score(total_area: f32, total_dots: u32, sub_area: f32, sub_dots: u32) -> f32 {
|
||||||
// expected dots for the area under a Complete Spatial Randomness scenario
|
// expected dots for the area under a Complete Spatial Randomness scenario
|
||||||
let csr_lambda: f32 = total_dots as f32 - ( sub_area / total_area);
|
let csr_lambda: f32 = total_dots as f32 - ( sub_area / total_area);
|
||||||
|
|
@ -401,7 +374,7 @@ fn main() {
|
||||||
|
|
||||||
// Execute delfin function with the generated GeometryData
|
// Execute delfin function with the generated GeometryData
|
||||||
start = Instant::now();
|
start = Instant::now();
|
||||||
let void_polygons: Vec<Vec<HashSet<usize>>> = delfin(&geometry_data, min_area, min_distance);
|
let void_polygons: Vec<Vec<Vec<usize>>> = delfin(&geometry_data, min_area, min_distance);
|
||||||
duration = start.elapsed();
|
duration = start.elapsed();
|
||||||
println!("Found {:#?} Voids using {:#?} bytes of RAM in: {:#?}", void_polygons.len(), mem::size_of_val(&void_polygons), duration);
|
println!("Found {:#?} Voids using {:#?} bytes of RAM in: {:#?}", void_polygons.len(), mem::size_of_val(&void_polygons), duration);
|
||||||
|
|
||||||
|
|
@ -410,6 +383,7 @@ fn main() {
|
||||||
let clusters = dtscan(&geometry_data, min_pts, max_closeness);
|
let clusters = dtscan(&geometry_data, min_pts, max_closeness);
|
||||||
duration = start.elapsed();
|
duration = start.elapsed();
|
||||||
println!("Found {:#?} Attractors using {:#?} bytes of RAM in: {:#?}", clusters.len(), mem::size_of_val(&clusters), duration);
|
println!("Found {:#?} Attractors using {:#?} bytes of RAM in: {:#?}", clusters.len(), mem::size_of_val(&clusters), duration);
|
||||||
|
println!("{:?}", void_polygons);
|
||||||
|
println!("{:?}", clusters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue