From d84e78b29a5d5a6dc08b0b57b41d9a9bd2aa6eeb Mon Sep 17 00:00:00 2001 From: Don Garrett Date: Sat, 6 Sep 2025 12:57:33 -0500 Subject: [PATCH] Allocate memory for efficiently. This should generally improve rendering time. --- src/render.rs | 50 +++++++++++---------------------------------- src/server.rs | 4 +++- src/translate.rs | 53 ++++++++++++++++++++++++------------------------ 3 files changed, 41 insertions(+), 66 deletions(-) diff --git a/src/render.rs b/src/render.rs index 586e17d..0e3c088 100644 --- a/src/render.rs +++ b/src/render.rs @@ -23,14 +23,6 @@ fn new_triangle(p1: &Vertex, p2: &Vertex, p3: &Vertex) -> stl_io::Triangle { } } -/// N steps around a circle, measured in radians. -fn radian_steps(steps: u32) -> Vec { - let counter = 0..steps; - let stepsize = std::f64::consts::TAU / steps as f64; - - counter.map(|i| (i as f64 * stepsize) as f32).collect() -} - /// Find a point on the cirle at a given angle (in radians). fn vertex_on_circle(center: &Vertex, radius: f32, angle: f32) -> Vertex { let x = center[0] + (radius * angle.cos()); @@ -41,10 +33,14 @@ fn vertex_on_circle(center: &Vertex, radius: f32, angle: f32) -> Vertex { } fn vertexes_on_circle(layer: &Layer, steps: u32) -> Vec { - radian_steps(steps) - .iter() - .map(|angle| vertex_on_circle(&layer.center, layer.radius, *angle)) - .collect() + let mut result = Vec::with_capacity(steps as usize); + let stepsize = std::f64::consts::TAU / steps as f64; + + for i in 0..steps { + let angle = (i as f64 * stepsize) as f32; + result.push(vertex_on_circle(&layer.center, layer.radius, angle)); + } + result } fn tube_base(center: &Vertex, edge: &[Vertex]) -> Vec { @@ -88,13 +84,15 @@ pub fn render(layers: &Layers, resolution: f32) -> Vec { let circle_steps = ((layers.max_radius() * std::f32::consts::TAU) / resolution).max(64.0) as u32; - let mut layer_vertexes: Vec> = Vec::new(); + let mut layer_vertexes: Vec> = Vec::with_capacity(layers.layers.len()); for layer in &layers.layers { layer_vertexes.push(vertexes_on_circle(layer, circle_steps)); } - let mut result: Vec = Vec::new(); + // Estimate triangle count: base + sides + top + let estimated_triangles = layers.layers.len() * circle_steps as usize * 2; + let mut result: Vec = Vec::with_capacity(estimated_triangles as usize); result.append(&mut tube_base(&layers.base, &layer_vertexes[0])); for i in 0..layer_vertexes.len() - 1 { @@ -137,30 +135,6 @@ mod tests { assert_eq!(tri_big.normal, Normal::new([0.0, 0.0, 18.0])); } - #[test] - fn radian_steps_basic() { - assert_eq!(radian_steps(0), []); - assert_eq!(radian_steps(1), [0.0]); - assert_eq!(radian_steps(2), [0.0, std::f32::consts::PI]); - assert_eq!( - radian_steps(3), - [ - 0.0, - std::f32::consts::PI * 2.0 / 3.0, - std::f32::consts::PI * 4.0 / 3.0 - ] - ); - assert_eq!( - radian_steps(4), - [ - 0.0, - std::f32::consts::PI * 0.5, - std::f32::consts::PI, - std::f32::consts::PI * 1.5, - ] - ); - } - fn validate_vec_vertex_relative_eq(val: &Vec, expected: &Vec) { let mut pass = true; diff --git a/src/server.rs b/src/server.rs index 067fc63..19441fd 100644 --- a/src/server.rs +++ b/src/server.rs @@ -35,7 +35,9 @@ fn generate_binary_stl(mushroom: mushroom::Mushroom) -> Vec { let mesh = render::render(&layers, 0.1); // Generate / return the byte array. - let mut binary_stl = Vec::::new(); + // Estimate STL file size: ~80 bytes per triangle + 80 byte header + let estimated_size = mesh.len() * 80 + 80; + let mut binary_stl = Vec::::with_capacity(estimated_size); stl_io::write_stl(&mut binary_stl, mesh.iter()).unwrap(); binary_stl } diff --git a/src/translate.rs b/src/translate.rs index e2690bb..e1d2a34 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -6,33 +6,31 @@ use crate::mushroom::{CapStyle, Mushroom}; fn stalk_layers(mushroom: &Mushroom, base: &Vertex, _resolution: f32) -> Vec { let stalk_top = Vertex::new([base[0], base[1], base[2] + mushroom.stalk_h]); - [ - layers::Layer { - center: *base, - radius: mushroom.stalk_r, - }, - layers::Layer { - center: stalk_top, - radius: mushroom.stalk_r, - }, - ] - .to_vec() + let mut result = Vec::with_capacity(2); + result.push(layers::Layer { + center: *base, + radius: mushroom.stalk_r, + }); + result.push(layers::Layer { + center: stalk_top, + radius: mushroom.stalk_r, + }); + result } fn cap_layers_cylinder(mushroom: &Mushroom, base: &Vertex) -> Vec { let top = Vertex::new([base[0], base[1], base[2] + mushroom.cap_h]); - [ - layers::Layer { - center: *base, - radius: mushroom.cap_r, - }, - layers::Layer { - center: top, - radius: mushroom.cap_r, - }, - ] - .to_vec() + let mut result = Vec::with_capacity(2); + result.push(layers::Layer { + center: *base, + radius: mushroom.cap_r, + }); + result.push(layers::Layer { + center: top, + radius: mushroom.cap_r, + }); + result } fn cap_layers_dome(mushroom: &Mushroom, base: &Vertex, resolution: f32) -> Vec { @@ -129,11 +127,11 @@ pub fn mushroom(mushroom: &Mushroom, resolution: f32) -> layers::Layers { let base = Vertex::new([0.0, 0.0, 0.0]); // Get layers for the stalk. - let mut stalk_layers = stalk_layers(mushroom, &base, resolution); + let stalk_layers = stalk_layers(mushroom, &base, resolution); // Get layers for the cap. let cap_base = stalk_layers.last().unwrap().center; - let mut cap_layers = cap_layers(mushroom, &cap_base, resolution); + let cap_layers = cap_layers(mushroom, &cap_base, resolution); // The very top of the mushroom is directly above the top layer of the cap (or even with it) // at the exact height of the total mushroom. @@ -141,8 +139,9 @@ pub fn mushroom(mushroom: &Mushroom, resolution: f32) -> layers::Layers { let top = Vertex::new([cap_top[0], cap_top[1], base[2] + mushroom.height()]); // Assemble the final Layers object. - let mut layers: Vec = Vec::new(); - layers.append(&mut stalk_layers); - layers.append(&mut cap_layers); + let growth = stalk_layers.len() + cap_layers.len(); + let mut layers: Vec = Vec::with_capacity(growth); + layers.extend(stalk_layers); + layers.extend(cap_layers); layers::Layers { base, top, layers } }