diff --git a/models/star/Cargo.toml b/models/star/Cargo.toml new file mode 100644 index 0000000000..b725b7e10a --- /dev/null +++ b/models/star/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "star" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies.fj] +path = "../../fj" diff --git a/models/star/README.md b/models/star/README.md new file mode 100644 index 0000000000..fe24e58306 --- /dev/null +++ b/models/star/README.md @@ -0,0 +1,10 @@ +# Fornjot - Star + +A model of a star that demonstrates sweeping a sketch to create a 3D shape, concave sketches, and how to generate sketches from code. + +To display this model, run the following from the repository root (model parameters are optional): +``` sh +cargo run -- --model start --parameters num_points=5 r1=1.0 r2=2.0 h=1.0 +``` + +![Screenshot of the star model](star.png) diff --git a/models/star/src/lib.rs b/models/star/src/lib.rs new file mode 100644 index 0000000000..977b3f85d3 --- /dev/null +++ b/models/star/src/lib.rs @@ -0,0 +1,58 @@ +use std::{collections::HashMap, f64::consts::PI}; + +#[no_mangle] +pub extern "C" fn model(args: &HashMap) -> fj::Shape { + // Number of points of the star + // + // "Points" in the sense of "pointy ends", not in the sense of geometrical + // points, or vertices. + let num_points: u64 = args + .get("num_points") + .map(|arg| arg.parse().unwrap()) + .unwrap_or(5); + + // Radius of the circle that all the vertices between the pointy ends are on + let r1: f64 = args + .get("r1") + .map(|arg| arg.parse().unwrap()) + .unwrap_or(1.0); + + // Radius of the circle that all the pointy ends are on + let r2: f64 = args + .get("r2") + .map(|arg| arg.parse().unwrap()) + .unwrap_or(2.0); + + // The height of the star + let h: f64 = args.get("h").map(|arg| arg.parse().unwrap()).unwrap_or(1.0); + + // We need to figure out where to generate vertices, depending on the number + // of points the star is supposed to have. Let's generate an iterator that + // gives us the angle and radius for each vertex. + let num_vertices = num_points * 2; + let vertex_iter = (0..num_vertices).map(|i| { + let angle = 2. * PI / num_vertices as f64 * i as f64; + let radius = if i % 2 == 0 { r1 } else { r2 }; + (angle, radius) + }); + + // Now that we got that iterator prepared, generating the vertices is just a + // bit of trigonometry. + let mut vertices = Vec::new(); + for (angle, radius) in vertex_iter { + let (sin, cos) = angle.sin_cos(); + + let x = cos * radius; + let y = sin * radius; + + vertices.push([x, y]); + } + + let sketch = fj::Sketch::from_points(vertices); + let star = fj::Sweep { + shape: sketch.into(), + length: h, + }; + + star.into() +}