Extrude a 2D polygon along the Y axis by the given depth. - `polygon`: flat array of 2D points [x0, z0, x1, z1, ...] - `holes`: list of hole polygons, each as flat [x0, z0, x1, z1, ...] - `depth`: extrusion height (in Y direction) Returns vertices and indices. The geometry extends from Y=0 to Y=depth. Normals and UVs are computed automatically.
(
polygon: &[f64],
holes: &[Vec<f64>],
depth: f64,
)
| 21 | /// Returns vertices and indices. The geometry extends from Y=0 to Y=depth. |
| 22 | /// Normals and UVs are computed automatically. |
| 23 | pub fn extrude_polygon( |
| 24 | polygon: &[f64], |
| 25 | holes: &[Vec<f64>], |
| 26 | depth: f64, |
| 27 | ) -> GeometryData { |
| 28 | let depth = depth as f32; |
| 29 | |
| 30 | // Build earcutr input: flatten polygon + holes, track hole starts |
| 31 | let n_poly = polygon.len() / 2; |
| 32 | let mut flat_coords: Vec<f64> = polygon.to_vec(); |
| 33 | let mut hole_indices: Vec<usize> = Vec::new(); |
| 34 | |
| 35 | for hole in holes { |
| 36 | hole_indices.push(flat_coords.len() / 2); |
| 37 | flat_coords.extend_from_slice(hole); |
| 38 | } |
| 39 | |
| 40 | // Triangulate the 2D polygon |
| 41 | let triangles = earcutr::earcut(&flat_coords, &hole_indices, 2) |
| 42 | .unwrap_or_default(); |
| 43 | |
| 44 | let n_points = flat_coords.len() / 2; |
| 45 | let mut vertices = Vec::new(); |
| 46 | let mut indices = Vec::new(); |
| 47 | |
| 48 | // ---- Bottom face (Y = 0, normal pointing down) ---- |
| 49 | let base_bottom = 0u32; |
| 50 | for i in 0..n_points { |
| 51 | let x = flat_coords[i * 2] as f32; |
| 52 | let z = flat_coords[i * 2 + 1] as f32; |
| 53 | vertices.push(Vertex3D { |
| 54 | position: [x, 0.0, z], |
| 55 | normal: [0.0, -1.0, 0.0], |
| 56 | color: [1.0, 1.0, 1.0, 1.0], |
| 57 | uv: [x, z], // planar UV |
| 58 | joints: [0.0; 4], |
| 59 | weights: [0.0; 4], |
| 60 | tangent: [0.0; 4], |
| 61 | }); |
| 62 | } |
| 63 | // Bottom triangles (reversed winding for downward-facing) |
| 64 | for tri in triangles.chunks(3) { |
| 65 | indices.push(base_bottom + tri[0] as u32); |
| 66 | indices.push(base_bottom + tri[2] as u32); |
| 67 | indices.push(base_bottom + tri[1] as u32); |
| 68 | } |
| 69 | |
| 70 | // ---- Top face (Y = depth, normal pointing up) ---- |
| 71 | let base_top = vertices.len() as u32; |
| 72 | for i in 0..n_points { |
| 73 | let x = flat_coords[i * 2] as f32; |
| 74 | let z = flat_coords[i * 2 + 1] as f32; |
| 75 | vertices.push(Vertex3D { |
| 76 | position: [x, depth, z], |
| 77 | normal: [0.0, 1.0, 0.0], |
| 78 | color: [1.0, 1.0, 1.0, 1.0], |
| 79 | uv: [x, z], |
| 80 | joints: [0.0; 4], |
no test coverage detected