//! World-space primitives. A sprite is a list of these; they are projected, //! culled and shaded only when the scene is rendered for a rotation. use serde::{Deserialize, Serialize}; pub type P2 = [f64; 2]; pub type P3 = [f64; 3]; /// Height of a prism's bottom or top: one value, or one per footprint vertex /// (sloped roofs, stair flights). #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum Zs { One(f64), Each(Vec), } impl Zs { #[inline] pub fn at(&self, i: usize) -> f64 { match self { Zs::One(z) => *z, Zs::Each(v) => v.get(i).copied().unwrap_or(f64::NAN), } } } impl From for Zs { fn from(z: f64) -> Self { Zs::One(z) } } /// Classes and switches of a solid. `mat` is the material class for every /// face; `side` / `top` override it for the side faces / the top. #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Style { pub mat: String, pub side: Option, pub top: Option, pub no_side: bool, pub no_top: bool, /// Pick id on the faces themselves (otherwise the sprite's id applies). pub id: Option, } impl Style { pub fn mat(mat: impl Into) -> Self { Style { mat: mat.into(), ..Default::default() } } pub fn id(mut self, id: impl Into) -> Self { self.id = Some(id.into()); self } pub fn top(mut self, top: impl Into) -> Self { self.top = Some(top.into()); self } pub fn side(mut self, side: impl Into) -> Self { self.side = Some(side.into()); self } pub fn no_top(mut self) -> Self { self.no_top = true; self } pub fn side_cls(&self) -> &str { self.side.as_deref().unwrap_or(&self.mat) } pub fn top_cls(&self) -> &str { self.top.as_deref().unwrap_or(&self.mat) } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Prim { /// Vertical prism over a convex counter-clockwise footprint. Prism { pts: Vec, z0: Zs, z1: Zs, st: Style, }, /// Upright cylinder (two side faces and an elliptic top). Cyl { c: P2, r: f64, z0: f64, z1: f64, st: Style, }, /// Frustum (cone) with n sides: radius r0 at z0, r1 at z1. Frust { c: P2, r0: f64, r1: f64, z0: f64, z1: f64, n: u32, st: Style, }, /// Openings (windows, doors) on the vertical face through a -> b; the /// outward normal is on the right of a -> b. Each entry is /// [u0, u1, z0, z1]: distance along the face and heights. Open { a: P2, b: P2, list: Vec<[f64; 4]>, cls: String, id: Option, }, /// Flat polygon(s) at height z; later polygons cut holes (even-odd). Flat { polys: Vec>, z: f64, cls: String, id: Option, }, /// Line segments [x0, y0, x1, y1] at height z. Lines { segs: Vec<[f64; 4]>, z: f64, cls: String, id: Option, }, /// Flat ellipse (a circle on the ground plane) at height z. Disc { c: P2, z: f64, r: f64, cls: String, id: Option, }, /// Planar polygon in 3D (roof slopes, gables, ramps), shaded by its /// normal: mostly upward = top, else left/centre/right by direction. /// One-sided faces (counter-clockwise seen from outside) are culled /// when turned away; two-sided faces always draw. Face { pts: Vec, mat: String, id: Option, two_sided: bool, }, /// 3D polygons merged into one path with a fixed class (PV modules, /// signs, markings on slopes): no shading, no culling. Poly { polys: Vec>, cls: String, id: Option, }, /// Screen-space circle of radius r (screen units) at a world point, /// shifted by off (screen units): heads, lamps, LEDs, tree crowns. Circle { at: P3, r: f64, off: P2, cls: String, id: Option, }, /// Screen-space vertical strip of half width w between two heights: /// trunks, thin poles. Stem { at: P2, z0: f64, z1: f64, w: f64, cls: String, id: Option, }, /// Rising steam or smoke puffs (CSS animation). Puffs { at: P3, kind: String, n: u32, dur: f64, }, /// Spinning fan lying in the plane at height at.z (CSS animation). Fan { at: P3, r: f64 }, /// Raw SVG translated to a world point (or untranslated without one). /// `{uid}` in the text is replaced by the view's unique id. Raw { at: Option, svg: String }, /// `` around nested primitives (animation, ghosting). Group { cls: String, style: String, items: Vec, }, /// Items drawn back to front by the depth of their plan anchor. Seq { items: Vec<(P2, Vec)> }, }