From eea05b79f9fb163800d64f21c911547b8954b0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 26 Jul 2024 21:05:46 +0200 Subject: [PATCH] fix ccw order after stitching, and don't trust is_corner --- Cargo.toml | 1 + src/instance.rs | 10 ++++- src/stitching.rs | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b372341..1765272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ spade = "2.9" geo = "0.28.0" log = "0.4" thiserror = "1" +itertools = "0.13.0" [dev-dependencies] criterion = "0.5" diff --git a/src/instance.rs b/src/instance.rs index 9d774fb..b73d27f 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -693,7 +693,10 @@ impl<'m> SearchInstance<'m> { .vertices .get(node.edge.0 as usize) .unwrap(); - if vertex.is_corner + if vertex + .polygons + .iter() + .any(|p| *p == u32::MAX || self.blocked_layers.contains(&p.layer())) && vertex.coords.distance_squared(node.interval.0) < EPSILON { node.interval.0 @@ -718,7 +721,10 @@ impl<'m> SearchInstance<'m> { .vertices .get(node.edge.1 as usize) .unwrap(); - if vertex.is_corner + if vertex + .polygons + .iter() + .any(|p| *p == u32::MAX || self.blocked_layers.contains(&p.layer())) && vertex.coords.distance_squared(node.interval.1) < EPSILON { node.interval.1 diff --git a/src/stitching.rs b/src/stitching.rs index e0b2570..df27a73 100644 --- a/src/stitching.rs +++ b/src/stitching.rs @@ -5,6 +5,111 @@ use glam::Vec2; use crate::{instance::U32Layer, Mesh}; impl Mesh { + fn reorder_neighbors_ccw_and_fix_empties(&mut self) { + let mut reordered_neighbors = vec![]; + for layer in self.layers.iter() { + let mut reordered_neighbors_in_layer = vec![]; + for vertex in &layer.vertices { + // For each polygon using a vertex, sort them in CCW order + let mut polygons = vertex + .polygons + .iter() + .filter(|p| **p != u32::MAX) + .cloned() + .collect::>(); + // Sort by the angle between the Y axis and the direction from the vertex to the center of the polygon + polygons.sort_by_key(|p| { + let vertices = + &self.layers[p.layer() as usize].polygons[p.polygon() as usize].vertices; + let center = vertices + .iter() + .map(|v| self.layers[p.layer() as usize].vertices[*v as usize].coords) + .sum::() + / vertices.len() as f32; + let direction = center - vertex.coords; + let angle = Vec2::Y.angle_between(direction); + (angle * 100000.0) as i32 + }); + + // Reintroduce empty markers + // For two following polygons on a vertex, check their previous / next vertices + // If they are different, there is a hole between them + let first = polygons[0]; + let last = *polygons.last().unwrap(); + if first == last { + polygons.push(u32::MAX); + } else { + polygons = polygons + .windows(2) + .map(|pair| [pair[0], pair[1]]) + .chain(std::iter::once([last, first])) + .flat_map(|pair| { + let mut polygon_a = self.layers[pair[0].layer() as usize].polygons + [pair[0].polygon() as usize] + .vertices + .clone(); + polygon_a.reverse(); + let mut found = false; + let previous_a = polygon_a + .iter() + .cycle() + .find(|v| { + if found { + return true; + } + if self.layers[pair[0].layer() as usize].vertices[**v as usize] + .coords + == vertex.coords + { + found = true; + } + false + }) + .unwrap(); + let polygon_b = &self.layers[pair[1].layer() as usize].polygons + [pair[1].polygon() as usize] + .vertices; + let mut found = false; + let next_b = polygon_b + .iter() + .cycle() + .find(|v| { + if found { + return true; + } + if self.layers[pair[1].layer() as usize].vertices[**v as usize] + .coords + == vertex.coords + { + found = true; + } + false + }) + .unwrap(); + if self.layers[pair[0].layer() as usize].vertices[*previous_a as usize] + .coords + != self.layers[pair[1].layer() as usize].vertices[*next_b as usize] + .coords + { + vec![pair[0], u32::MAX] + } else { + vec![pair[0]] + } + }) + .collect(); + } + reordered_neighbors_in_layer.push(polygons); + } + + reordered_neighbors.push(reordered_neighbors_in_layer); + } + for (layer, new) in self.layers.iter_mut().zip(reordered_neighbors.into_iter()) { + for (vertex, new) in layer.vertices.iter_mut().zip(new.into_iter()) { + vertex.polygons = new; + } + } + } + fn stitch_internals( &mut self, target_layer: Option, @@ -74,6 +179,7 @@ impl Mesh { vertex_from.polygons.append(&mut neighbors_to); } } + self.reorder_neighbors_ccw_and_fix_empties(); } /// Stitch points between layers. After, the polygons neighboring the stitch points will be