Rework to split layer generation and triangle rendering.

This commit is contained in:
dongar committed 2024-06-12 22:25:44 -05:00
1 parent fa7b9345fe
commit 860ac88b61
6 files changed
+304 -86

No files matched your search

+84 -37
View File
@@ -1,6 +1,6 @@
use stl_io::{self, Normal, Triangle, Vertex};
use crate::mushroom::Mushroom;
use crate::layers::{Layer, Layers};
fn new_triangle(p1: &Vertex, p2: &Vertex, p3: &Vertex) -> stl_io::Triangle {
// Set Vector U to (Triangle.p2 minus Triangle.p1)
@@ -40,10 +40,10 @@ fn vertex_on_circle(center: &Vertex, radius: f32, angle: f32) -> Vertex {
return Vertex::new([x, y, z]);
}
fn vertexes_on_circle(center: &Vertex, radius: f32, steps: u32) -> Vec<Vertex> {
fn vertexes_on_circle(layer: &Layer, steps: u32) -> Vec<Vertex> {
return radian_steps(steps)
.iter()
.map(|angle| vertex_on_circle(center, radius, *angle))
.map(|angle| vertex_on_circle(&layer.center, layer.radius, *angle))
.collect();
}
@@ -80,46 +80,35 @@ fn tube_top(center: &Vertex, edge: &Vec<Vertex>) -> Vec<Triangle> {
return tube_base(&center, &edge);
}
pub fn mushroom(mushroom: &Mushroom) -> Vec<Triangle> {
// Max size of any flat surface in mm.
let resolution: f32 = 1.0;
pub fn render(layers: &Layers, resolution: f32) -> Vec<Triangle> {
// Top and Bottom must be a single point, and must be at least one middle layer.
assert!(!layers.layers.is_empty());
// We always use the same number of diameter steps to ensure the number of circular vertices doesn't change,
// which might create small breaks in our model.
let diameter_steps = std::cmp::max(
(mushroom.cap_d * std::f32::consts::TAU * resolution) as u32,
64,
);
// How many vertexes per circle. IE: the resolution of the circle.
let circle_steps =
((layers.max_radius() * std::f32::consts::TAU) / resolution).max(64.0) as u32;
let stalk_base_center = Vertex::new([0.0, 0.0, 0.0]);
let stalk_base_edge = vertexes_on_circle(&stalk_base_center, mushroom.stalk_d, diameter_steps);
let stalk_top_center = Vertex::new([
stalk_base_center[0],
stalk_base_center[1],
stalk_base_center[2] + mushroom.stalk_h,
]);
let stalk_top_edge = vertexes_on_circle(&stalk_top_center, mushroom.stalk_d, diameter_steps);
let cap_base_edge = vertexes_on_circle(&stalk_top_center, mushroom.cap_d, diameter_steps);
let cap_top_center = Vertex::new([
stalk_top_center[0],
stalk_top_center[1],
stalk_top_center[2] + mushroom.cap_h,
]);
let cap_top_edge = vertexes_on_circle(&cap_top_center, mushroom.cap_d, diameter_steps);
let mut layer_vertexes: Vec<Vec<Vertex>> = Vec::new();
let mut result = Vec::new();
for layer in &layers.layers {
layer_vertexes.push(vertexes_on_circle(&layer, circle_steps));
}
result.append(&mut tube_base(&stalk_base_center, &stalk_base_edge));
result.append(&mut tube_sides(&stalk_base_edge, &stalk_top_edge));
result.append(&mut tube_sides(&stalk_top_edge, &cap_base_edge));
result.append(&mut tube_sides(&cap_base_edge, &cap_top_edge));
result.append(&mut tube_top(&cap_top_center, &cap_top_edge));
let mut result: Vec<Triangle> = Vec::new();
result.append(&mut tube_base(&layers.base, &layer_vertexes[0]));
for i in 0..layer_vertexes.len() - 1 {
result.append(&mut tube_sides(&layer_vertexes[i], &layer_vertexes[i + 1]));
}
result.append(&mut tube_top(&layers.top, &layer_vertexes.last().unwrap()));
return result;
}
#[cfg(test)]
mod tests {
use approx::relative_eq;
use super::*;
#[test]
@@ -196,7 +185,13 @@ mod tests {
#[test]
fn vertexes_on_circle_basic() {
let val = vertexes_on_circle(&Vertex::new([0.0, 0.0, 0.0]), 1.0, 4);
let val = vertexes_on_circle(
&Layer {
center: Vertex::new([0.0, 0.0, 0.0]),
radius: 1.0,
},
4,
);
let expected = [
Vertex::new([1.0, 0.0, 0.0]),
@@ -211,7 +206,13 @@ mod tests {
#[test]
fn vertexes_on_circle_complex() {
let val = vertexes_on_circle(&Vertex::new([4.0, 5.0, 6.0]), 3.0, 4);
let val = vertexes_on_circle(
&Layer {
center: Vertex::new([4.0, 5.0, 6.0]),
radius: 3.0,
},
4,
);
let expected = [
Vertex::new([7.0, 5.0, 6.0]),
@@ -229,7 +230,13 @@ mod tests {
// fn tube_base(center: &Vertex, edge: &Vec<Vertex>) -> Vec<Triangle> {
let center = Vertex::new([0.0, 0.0, 0.0]);
let edge = vertexes_on_circle(&center, 1.0, 4);
let edge = vertexes_on_circle(
&Layer {
center: center.clone(),
radius: 1.0,
},
4,
);
let triangles = tube_base(&center, &edge);
@@ -244,7 +251,13 @@ mod tests {
#[test]
fn tube_top_test() {
let center = Vertex::new([0.0, 0.0, 0.0]);
let edge = vertexes_on_circle(&center, 1.0, 4);
let edge = vertexes_on_circle(
&Layer {
center: center.clone(),
radius: 1.0,
},
4,
);
let triangles = tube_top(&center, &edge);
@@ -255,4 +268,38 @@ mod tests {
assert_eq!(t.normal, Vertex::new([0.0, 0.0, 1.0]));
}
}
#[test]
fn render_test() {
let layers = Layers {
base: Vertex::new([0.0, 0.0, 0.0]),
layers: [
Layer {
center: Vertex::new([0.0, 0.0, 1.0]),
radius: 1.0,
},
Layer {
center: Vertex::new([0.0, 0.0, 2.0]),
radius: 1.0,
},
]
.to_vec(),
top: Vertex::new([0.0, 0.0, 3.0]),
};
let mesh = render(&layers, 10.0); // Large resolution ensures minimum steps of 64.
// 64 triangles for top, 128 for sides, 64 for bottom.
assert_eq!(mesh.len(), 64 + 128 + 64);
for i in 0..mesh.len() {
if i < 64 {
assert!(mesh[i].normal[2] < 0.0) // Bottom triangles point down.
} else if i < (64 + 128) {
assert!(mesh[i].normal[2] == 0.0) // side triangles point out.
} else {
assert!(mesh[i].normal[2] > 0.0) // top triangles point up.
}
}
}
}