Compare commits
1 commit
main
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab4842b61 |
1 changed files with 97 additions and 16 deletions
113
src/lib.rs
113
src/lib.rs
|
|
@ -83,6 +83,7 @@ pub struct GeometryData {
|
||||||
pub edge_to_triangles: HashMap<Edge, Vec<usize>>, // Maps an edge to triangle indices
|
pub edge_to_triangles: HashMap<Edge, Vec<usize>>, // Maps an edge to triangle indices
|
||||||
pub edge_lengths: HashMap<Edge, f32>, // Edge lengths
|
pub edge_lengths: HashMap<Edge, f32>, // Edge lengths
|
||||||
pub vertex_connections: HashMap<usize, HashSet<usize>>, // Direct connections between vertices, for DTSCAN
|
pub vertex_connections: HashMap<usize, HashSet<usize>>, // Direct connections between vertices, for DTSCAN
|
||||||
|
pub triangle_blacklist: HashSet<usize>, // invalidated triangles
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeometryData {
|
impl GeometryData {
|
||||||
|
|
@ -91,7 +92,8 @@ impl GeometryData {
|
||||||
triangles: Vec::new(),
|
triangles: Vec::new(),
|
||||||
edge_to_triangles: HashMap::new(),
|
edge_to_triangles: HashMap::new(),
|
||||||
edge_lengths: 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) {
|
fn add_triangle(&mut self, index: usize, points: &[Point], tri_idx: &[usize], types: usize) {
|
||||||
|
|
@ -160,6 +162,10 @@ impl GeometryData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_triangle(&mut self, triangle_index: usize) {
|
||||||
|
self.triangle_blacklist.insert(triangle_index);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Xenobalanus {
|
pub struct Xenobalanus {
|
||||||
|
|
@ -197,26 +203,53 @@ impl Xenobalanus {
|
||||||
self.points = points
|
self.points = points
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn triangle(&self, index: usize) -> TriangleData {
|
pub fn triangle(&self, index: usize) -> Option<&TriangleData> {
|
||||||
self.geometry_data.triangles[index].clone()
|
if !self.geometry_data.triangle_blacklist.contains(&index) {
|
||||||
|
Some(&self.geometry_data.triangles[index])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn triangle_data(&self) -> &Vec<TriangleData> {
|
pub fn triangle_data(&self) -> Vec<TriangleData> {
|
||||||
&self.geometry_data.triangles
|
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<usize> {
|
pub fn triangles_flat(&self) -> Vec<usize> {
|
||||||
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<Vec<usize>> {
|
pub fn triangle_vertices(&self) -> Vec<Vec<usize>> {
|
||||||
self.triangulation.chunks(3).map(|chunk| {
|
let triangulation = self.triangles_flat();
|
||||||
|
triangulation.chunks(3).map(|chunk| {
|
||||||
chunk.iter().map(|&index| index).collect()
|
chunk.iter().map(|&index| index).collect()
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn triangle_coordinates(&self) -> Vec<Vec<(f32, f32)>> {
|
pub fn triangle_coordinates(&self) -> Vec<Vec<(f32, f32)>> {
|
||||||
self.triangulation.chunks(3).map(|chunk| {
|
let triangulation = self.triangles_flat();
|
||||||
|
triangulation.chunks(3).map(|chunk| {
|
||||||
chunk.iter().map(|&index| {
|
chunk.iter().map(|&index| {
|
||||||
let point = &self.points[index];
|
let point = &self.points[index];
|
||||||
(point.x, point.y) // Each point is represented by a Vec<f32> of its coordinates
|
(point.x, point.y) // Each point is represented by a Vec<f32> of its coordinates
|
||||||
|
|
@ -228,6 +261,45 @@ impl Xenobalanus {
|
||||||
self.triangulation = vertices
|
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<usize> {
|
||||||
|
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
|
// 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) {
|
pub fn random_points(&mut self, center: (f32, f32), side_length: f32, num_points: u32) {
|
||||||
// generate random points in a square
|
// generate random points in a square
|
||||||
|
|
@ -247,15 +319,19 @@ impl Xenobalanus {
|
||||||
&self.geometry_data.edge_lengths
|
&self.geometry_data.edge_lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delaunay(&mut self) {
|
fn triangulate(&self, points: &Vec<Point>) -> Vec<usize> {
|
||||||
// Convert geo::Point to delaunator::Point for triangulation
|
|
||||||
let delaunator_points: Vec<DelaunatorPoint> = self.points.iter()
|
let delaunator_points: Vec<DelaunatorPoint> = points.iter()
|
||||||
.map(|point: &Point| DelaunatorPoint { x: point.x as f64, y: point.y as f64 })
|
.map(|point: &Point| DelaunatorPoint { x: point.x as f64, y: point.y as f64 })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Perform Delaunay triangulation
|
// Perform Delaunay triangulation
|
||||||
let result: delaunator::Triangulation = triangulate(&delaunator_points);
|
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) {
|
pub fn preprocess(&mut self, types: usize) {
|
||||||
|
|
@ -281,7 +357,7 @@ impl Xenobalanus {
|
||||||
let mut processed_triangles: HashSet<usize> = HashSet::new();
|
let mut processed_triangles: HashSet<usize> = HashSet::new();
|
||||||
|
|
||||||
// Create a sorted list of triangles by their terminal edge length that meet the minimum distance criteria.
|
// 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_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)
|
.filter(|&(_, length)| length >= min_distance)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -305,7 +381,7 @@ impl Xenobalanus {
|
||||||
processed_triangles.insert(triangle_index);
|
processed_triangles.insert(triangle_index);
|
||||||
|
|
||||||
// Get all edges of the current triangle
|
// 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 {
|
for edge in edges {
|
||||||
|
|
||||||
// Add all edges to check for neighbors to expand
|
// Add all edges to check for neighbors to expand
|
||||||
|
|
@ -328,8 +404,13 @@ impl Xenobalanus {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip if triangle is blacklisted
|
||||||
|
if self.geometry_data.triangle_blacklist.contains(&neighbor_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Get neighbor triangle
|
// 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
|
// Get neighbor triangle's terminal edge
|
||||||
if let Some(neighbor_edge) = neighbor_triangle.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
|
// Retain only those sets that meet the minimum area criteria
|
||||||
void_polygons.retain(|set| {
|
void_polygons.retain(|set| {
|
||||||
set.iter()
|
set.iter()
|
||||||
.filter_map(|&i| self.geometry_data.triangles[i].area)
|
.filter_map(|&i| Some(self.triangle_area(i)))
|
||||||
.sum::<f32>() >= min_area
|
.sum::<f32>() >= min_area
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue