From b1cbf5fadb5929ce4db7c613a36370f4cac7e0aa Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 17 Jun 2021 19:25:03 +0200 Subject: [PATCH 01/10] Add a new `nannou_core` crate. Switch core from `cgmath` to `glam`. See #752 for motivation behind adding a `nannou_core` crate. Note that this commit does not yet replace the color, geom, math and rand modules within the `nannou` crate. This will be performed in a following commit. --- Cargo.toml | 1 + nannou_core/Cargo.toml | 26 + nannou_core/src/color/conv.rs | 143 +++++ nannou_core/src/color/mod.rs | 167 ++++++ nannou_core/src/geom/cuboid.rs | 901 ++++++++++++++++++++++++++++++++ nannou_core/src/geom/ellipse.rs | 384 ++++++++++++++ nannou_core/src/geom/mod.rs | 91 ++++ nannou_core/src/geom/point.rs | 31 ++ nannou_core/src/geom/polygon.rs | 152 ++++++ nannou_core/src/geom/quad.rs | 364 +++++++++++++ nannou_core/src/geom/range.rs | 820 +++++++++++++++++++++++++++++ nannou_core/src/geom/rect.rs | 815 +++++++++++++++++++++++++++++ nannou_core/src/geom/scalar.rs | 38 ++ nannou_core/src/geom/tri.rs | 365 +++++++++++++ nannou_core/src/geom/vector.rs | 22 + nannou_core/src/geom/vertex.rs | 397 ++++++++++++++ nannou_core/src/lib.rs | 39 ++ nannou_core/src/math.rs | 193 +++++++ nannou_core/src/prelude.rs | 27 + nannou_core/src/rand.rs | 73 +++ 20 files changed, 5049 insertions(+) create mode 100644 nannou_core/Cargo.toml create mode 100644 nannou_core/src/color/conv.rs create mode 100644 nannou_core/src/color/mod.rs create mode 100644 nannou_core/src/geom/cuboid.rs create mode 100644 nannou_core/src/geom/ellipse.rs create mode 100644 nannou_core/src/geom/mod.rs create mode 100644 nannou_core/src/geom/point.rs create mode 100644 nannou_core/src/geom/polygon.rs create mode 100644 nannou_core/src/geom/quad.rs create mode 100644 nannou_core/src/geom/range.rs create mode 100644 nannou_core/src/geom/rect.rs create mode 100644 nannou_core/src/geom/scalar.rs create mode 100644 nannou_core/src/geom/tri.rs create mode 100644 nannou_core/src/geom/vector.rs create mode 100644 nannou_core/src/geom/vertex.rs create mode 100644 nannou_core/src/lib.rs create mode 100644 nannou_core/src/math.rs create mode 100644 nannou_core/src/prelude.rs create mode 100644 nannou_core/src/rand.rs diff --git a/Cargo.toml b/Cargo.toml index c82591100..7b833bbbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "guide/book_tests", "nannou", "nannou_audio", + "nannou_core", "nannou_isf", "nannou_laser", "nannou_new", diff --git a/nannou_core/Cargo.toml b/nannou_core/Cargo.toml new file mode 100644 index 000000000..4421a6979 --- /dev/null +++ b/nannou_core/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "nannou_core" +version = "0.1.0" +authors = ["mitchmindtree "] +edition = "2018" + +[dependencies] +glam = { version = "0.16", default-features = false, features = ["num-traits", "rand"] } +# TODO: Awaiting `no-std` to be published. +# noise = 0.6 +num-traits = { version = "0.2.14", default-features = false } +palette = { version = "0.5", default-features = false, features = ["named"] } +# TODO: Need to check support for no-std. +# pennereq = "0.3" +rand = { version = "0.7", default-features = false, features = ["small_rng"] } +# TODO: Needs no-std support before we can add text logic to this core. +# rusttype = "0.8" + +[features] +default = ["std"] +libm = ["glam/libm", "num-traits/libm", "palette/libm" ] +serde = ["glam/serde", "palette/serde"] +std = ["glam/std", "num-traits/std", "palette/std", "rand/std"] + +[package.metadata.docs.rs] +features = ["serde", "std"] diff --git a/nannou_core/src/color/conv.rs b/nannou_core/src/color/conv.rs new file mode 100644 index 000000000..f9413f468 --- /dev/null +++ b/nannou_core/src/color/conv.rs @@ -0,0 +1,143 @@ +//! This module provides some more flexible conversions and aims to fill the gaps within the `From` +//! and `Into` implementations provided by the `palette` library. +//! +//! If a desired conversion is missing, feel free to open an issue or pull request! + +use crate::color::white_point::D65; +use crate::color::{self, encoding, Alpha, Component, IntoColor, LinSrgba}; +use crate::math::num_traits::Float; + +/// Types that may be converted directly into a linear sRGBA color representation. +/// +/// This is more flexible than `Into>` as it also supports converting from different +/// sRGBA encodings that also have different component types. +/// +/// This trait is important for nannou as the `Draw` API works with the `LinSrgba` type as a target +/// for its generic colour type API. +pub trait IntoLinSrgba +where + S: Component, +{ + /// Convert self into RGBA. + fn into_lin_srgba(self) -> LinSrgba; +} + +impl IntoLinSrgba for color::Xyz +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::Yxy +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::Lab +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::Lch +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::LinSrgb +where + T: Component, + S: Component, +{ + fn into_lin_srgba(self) -> LinSrgba { + let color = self.into_format(); + let alpha = S::max_intensity(); + Alpha { color, alpha } + } +} + +impl IntoLinSrgba for color::Srgb +where + T: Component, + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + let color = self.into_format().into_linear(); + let alpha = S::max_intensity(); + Alpha { color, alpha } + } +} + +impl IntoLinSrgba for color::Hsl +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::Hsv +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::Hwb +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for color::SrgbLuma +where + S: Component + Float, +{ + fn into_lin_srgba(self) -> LinSrgba { + into_lin_srgb_with_alpha(self) + } +} + +impl IntoLinSrgba for Alpha +where + C: IntoLinSrgba, + S: Component, + T: Component, +{ + fn into_lin_srgba(self) -> LinSrgba { + let Alpha { color, alpha } = self; + let mut srgba = color.into_lin_srgba(); + srgba.alpha = alpha.convert(); + srgba + } +} + +fn into_lin_srgb_with_alpha(color: C) -> LinSrgba +where + C: IntoColor, + S: Component + Float, +{ + let color: color::LinSrgb = color.into_rgb::(); + let alpha = S::max_intensity(); + Alpha { color, alpha } +} diff --git a/nannou_core/src/color/mod.rs b/nannou_core/src/color/mod.rs new file mode 100644 index 000000000..c7f04a0ff --- /dev/null +++ b/nannou_core/src/color/mod.rs @@ -0,0 +1,167 @@ +//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the +//! [palette crate](https://docs.rs/palette). +//! +//! See the [**named**](./named/index.html) module for a set of provided color constants. + +//pub mod conv; + +//pub use self::conv::IntoLinSrgba; +pub use self::named::*; +#[doc(inline)] +pub use palette::*; + +/// The default scalar value for working with color components, hues, etc. +pub type DefaultScalar = f32; + +/// A color represented as red, green and blue intensities. +/// +/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space. +/// +/// If you are looking for more advanced control over the RGB space and component type, please see +/// the `palette` crate's generic `Rgb` type. +pub type Rgb = Srgb; + +/// The same as `Rgb`, but with `u8`'s. +pub type Rgb8 = Rgb; + +/// The same as `Rgb`, but with an alpha value representing opacity. +/// +/// This type is an alias for the `Srgba` type, a type that represents the sRGB color space +/// alongside an alpha value. +/// +/// If you are looking for more advanced control over the RGB space and component type, please see +/// the `palette` crate's generic `Rgb` type. +pub type Rgba = Srgba; + +/// The same as `Rgba`, but with `u8`'s. +pub type Rgba8 = Rgba; + +/// A color represented as gray intensity. +/// +/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space. +/// +/// If you are looking for more advanced control over the RGB space and component type, please see +/// the `palette` crate's generic `Rgb` type. +pub type Gray = Srgb; + +/// A short-hand constructor for `Rgb::new`. +pub fn rgb(r: T, g: T, b: T) -> Rgb +where + T: Component, +{ + srgb(r, g, b) +} + +/// A short-hand constructor for `Rgb::::new` . +pub fn rgb8(r: u8, g: u8, b: u8) -> Rgb8 { + srgb(r, g, b) +} + +/// A short-hand constructor for `Rgba::new`. +pub fn rgba(r: T, g: T, b: T, a: T) -> Rgba +where + T: Component, +{ + srgba(r, g, b, a) +} + +/// A short-hand constructor for `Rgba::new`. +pub fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Rgba8 { + srgba8(r, g, b, a) +} + +/// A short-hand constructor for `Srgb::new`. +pub fn srgb(r: T, g: T, b: T) -> Srgb +where + T: Component, +{ + Srgb::new(r, g, b) +} + +/// A short-hand constructor for `Srgb::new`. +pub fn srgb8(r: u8, g: u8, b: u8) -> Srgb { + Srgb::new(r, g, b) +} + +/// A short-hand constructor for `Srgba::new`. +pub fn srgba(r: T, g: T, b: T, a: T) -> Srgba +where + T: Component, +{ + Srgba::new(r, g, b, a) +} + +/// A short-hand constructor for `Srgba::new`. +pub fn srgba8(r: u8, g: u8, b: u8, a: u8) -> Srgba { + Srgba::new(r, g, b, a) +} + +/// A short-hand constructor for `LinSrgb::new`. +pub fn lin_srgb(r: T, g: T, b: T) -> LinSrgb +where + T: Component, +{ + LinSrgb::new(r, g, b) +} + +/// A short-hand constructor for `LinSrgba::new`. +pub fn lin_srgba(r: T, g: T, b: T, a: T) -> LinSrgba +where + T: Component, +{ + LinSrgba::new(r, g, b, a) +} + +/// Create a new color from a hexadecimal int literal +#[inline] +pub fn rgb_u32(c: u32) -> Rgb { + let blue: u8 = (c & 0xFF) as u8; + let green: u8 = ((c >> 8) & 0xFF) as u8; + let red: u8 = ((c >> 16) & 0xFF) as u8; + rgb8(red, green, blue) +} + +/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`. +/// +/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is +/// 360 degrees (or 2 PI radians). +pub fn hsl(h: f32, s: f32, l: f32) -> Hsl { + Hsl::new(RgbHue::from_degrees(h * 360.0), s, l) +} + +/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`. +/// +/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is +/// 360 degrees (or 2 PI radians). +pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla { + Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a) +} + +/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`. +/// +/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is +/// 360 degrees (or 2 PI radians). +pub fn hsv(h: f32, s: f32, v: f32) -> Hsv { + Hsv::new(RgbHue::from_degrees(h * 360.0), s, v) +} + +/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`. +/// +/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is +/// 360 degrees (or 2 PI radians). +pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva { + Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a) +} + +/// A short-hand constructor for `Gray::new`. +pub fn gray(g: T) -> Gray +where + T: Component, +{ + srgb(g, g, g) +} + +#[test] +fn test_rgb_u32() { + assert_eq!(rgb_u32(0xFF8000), rgb8(255, 128, 0)); +} diff --git a/nannou_core/src/geom/cuboid.rs b/nannou_core/src/geom/cuboid.rs new file mode 100644 index 000000000..e23bdb362 --- /dev/null +++ b/nannou_core/src/geom/cuboid.rs @@ -0,0 +1,901 @@ +//! Items related to cube geometry. +//! +//! The main type is the `Cuboid` type. + +use crate::geom::{quad, scalar, Quad, Range, Scalar, Tri}; +use crate::math::num_traits::Float; + +/// The number of faces on a Cuboid. +pub const NUM_FACES: u8 = 6; + +/// The number of corners on a Cuboid. +pub const NUM_CORNERS: u8 = 8; + +/// The number of subdivisions for a Cuboid. +pub const NUM_SUBDIVISIONS: u8 = 8; + +/// The number of triangles used to triangulate a cuboid. +pub const NUM_TRIANGLES: u8 = NUM_FACES * 2; + +/// A light-weight `Cuboid` type with many helper and utility methods. +/// +/// The cuboid is also known as a "rectangular prism". +/// +/// `Cuboid` is implemented similarly to `geom::Rect` but with 3 axes instead of 2. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Cuboid { + /// The start and end along the x axis. + pub x: Range, + /// The start and end along the y axis. + pub y: Range, + /// The start and end along the z axis. + pub z: Range, +} + +/// Each of the faces of a cuboid. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Face { + Back, + Right, + Top, + Front, + Bottom, + Left, +} + +/// An iterator yielding each corner of a cuboid in the following order. +#[derive(Clone, Debug)] +pub struct Corners<'a, S: 'a> { + cuboid: &'a Cuboid, + corner_index: u8, +} + +/// An iterator yielding the faces of a cuboid as per their ordering. +#[derive(Clone, Debug)] +pub struct Faces { + next_face_index: u8, +} + +/// A quad representing a single face of a cuboid. +pub type FaceQuad = Quad<[S; 3]>; + +/// An iterator yielding each face of a cuboid as a quad. +#[derive(Clone, Debug)] +pub struct FaceQuads<'a, S: 'a = scalar::Default> { + // The cuboid object from which each face will be yielded. + cuboid: &'a Cuboid, + // The next face to yield. + faces: Faces, +} + +/// An iterator yielding all triangles for all faces. +#[derive(Clone, Debug)] +pub struct Triangles<'a, S: 'a> { + face_quads: FaceQuads<'a, S>, + triangles: quad::Triangles<[S; 3]>, +} + +/// The three ranges that make up the 8 subdivisions of a cuboid. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct SubdivisionRanges { + /// The first half of the *x* axis range. + pub x_a: Range, + /// The second half of the *x* axis range. + pub x_b: Range, + /// The first half of the *y* axis range. + pub y_a: Range, + /// The second half of the *y* axis range. + pub y_b: Range, + /// The first half of the *z* axis range. + pub z_a: Range, + /// The second half of the *z* axis range. + pub z_b: Range, +} + +/// Yields even subdivisions of a `Cuboid`. +/// +/// The eight subdivisions will each be yielded as a `Cuboid` whose dimensions are exactly half of +/// the original `Cuboid`. +#[derive(Clone)] +pub struct Subdivisions { + ranges: SubdivisionRanges, + subdivision_index: u8, +} + +macro_rules! corner_from_index { + (0, $cuboid:expr) => { + [$cuboid.x.start, $cuboid.y.start, $cuboid.z.start] + }; + (1, $cuboid:expr) => { + [$cuboid.x.end, $cuboid.y.start, $cuboid.z.start] + }; + (2, $cuboid:expr) => { + [$cuboid.x.start, $cuboid.y.end, $cuboid.z.start] + }; + (3, $cuboid:expr) => { + [$cuboid.x.end, $cuboid.y.end, $cuboid.z.start] + }; + (4, $cuboid:expr) => { + [$cuboid.x.start, $cuboid.y.start, $cuboid.z.end] + }; + (5, $cuboid:expr) => { + [$cuboid.x.end, $cuboid.y.start, $cuboid.z.end] + }; + (6, $cuboid:expr) => { + [$cuboid.x.start, $cuboid.y.end, $cuboid.z.end] + }; + (7, $cuboid:expr) => { + [$cuboid.x.end, $cuboid.y.end, $cuboid.z.end] + }; +} + +macro_rules! face_from_index { + (0) => { + Face::Back + }; + (1) => { + Face::Right + }; + (2) => { + Face::Top + }; + (3) => { + Face::Front + }; + (4) => { + Face::Bottom + }; + (5) => { + Face::Left + }; +} + +macro_rules! quad_from_corner_indices { + ($cuboid:expr, $a:tt, $b:tt, $c:tt, $d:tt) => { + [ + corner_from_index!($a, $cuboid).into(), + corner_from_index!($b, $cuboid).into(), + corner_from_index!($c, $cuboid).into(), + corner_from_index!($d, $cuboid).into(), + ] + }; +} + +// Given some `SubdivisionRanges` and a subdivision index, produce the cuboid for that subdivision. +// +// 1. Front bottom left +// 2. Front bottom right +// 3. Front top left +// 4. Front top right +// 5. Back bottom left +// 6. Back bottom right +// 7. Back top left +// 8. Back top right +macro_rules! subdivision_from_index { + ($ranges:expr,0) => { + Cuboid { + x: $ranges.x_a, + y: $ranges.y_a, + z: $ranges.z_a, + } + }; + ($ranges:expr,1) => { + Cuboid { + x: $ranges.x_b, + y: $ranges.y_a, + z: $ranges.z_a, + } + }; + ($ranges:expr,2) => { + Cuboid { + x: $ranges.x_a, + y: $ranges.y_b, + z: $ranges.z_a, + } + }; + ($ranges:expr,3) => { + Cuboid { + x: $ranges.x_b, + y: $ranges.y_b, + z: $ranges.z_a, + } + }; + ($ranges:expr,4) => { + Cuboid { + x: $ranges.x_a, + y: $ranges.y_a, + z: $ranges.z_b, + } + }; + ($ranges:expr,5) => { + Cuboid { + x: $ranges.x_b, + y: $ranges.y_a, + z: $ranges.z_b, + } + }; + ($ranges:expr,6) => { + Cuboid { + x: $ranges.x_a, + y: $ranges.y_b, + z: $ranges.z_b, + } + }; + ($ranges:expr,7) => { + Cuboid { + x: $ranges.x_b, + y: $ranges.y_b, + z: $ranges.z_b, + } + }; +} + +impl Cuboid +where + S: Float + Scalar, +{ + /// Construct a Rect from a given centre point (x, y, z) and dimensions (width, height, depth). + pub fn from_xyz_whd([x, y, z]: [S; 3], [w, h, d]: [S; 3]) -> Self { + Cuboid { + x: Range::from_pos_and_len(x, w), + y: Range::from_pos_and_len(y, h), + z: Range::from_pos_and_len(z, d), + } + } + + /// The position in the middle of the x range. + pub fn x(&self) -> S { + self.x.middle() + } + + /// The position in the middle of the y range. + pub fn y(&self) -> S { + self.y.middle() + } + + /// The position in the middle of the z range. + pub fn z(&self) -> S { + self.z.middle() + } + + /// The xyz position in the middle of the bounds. + pub fn xyz(&self) -> [S; 3] { + [self.x(), self.y(), self.z()].into() + } + + /// The centered x, y and z coordinates as a tuple. + pub fn x_y_z(&self) -> (S, S, S) { + (self.x(), self.y(), self.z()) + } + + /// The six ranges used for the `Cuboid`'s eight subdivisions. + pub fn subdivision_ranges(&self) -> SubdivisionRanges { + let (x, y, z) = self.x_y_z(); + let x_a = Range::new(self.x.start, x); + let x_b = Range::new(x, self.x.end); + let y_a = Range::new(self.y.start, y); + let y_b = Range::new(y, self.y.end); + let z_a = Range::new(self.z.start, z); + let z_b = Range::new(z, self.z.end); + SubdivisionRanges { + x_a, + x_b, + y_a, + y_b, + z_a, + z_b, + } + } + + /// The position and dimensions of the cuboid. + pub fn xyz_whd(&self) -> ([S; 3], [S; 3]) { + (self.xyz(), self.whd()) + } + + /// The position and dimensions of the cuboid. + pub fn x_y_z_w_h_d(&self) -> (S, S, S, S, S, S) { + let (x, y, z) = self.x_y_z(); + let (w, h, d) = self.w_h_d(); + (x, y, z, w, h, d) + } +} + +impl Cuboid +where + S: Scalar, +{ + /// Construct a cuboid from its x, y and z ranges. + pub fn from_ranges(x: Range, y: Range, z: Range) -> Self { + Cuboid { x, y, z } + } + + /// Converts `self` to an absolute `Cuboid` so that the magnitude of each range is always + /// positive. + pub fn absolute(&self) -> Self { + let x = self.x.absolute(); + let y = self.y.absolute(); + let z = self.z.absolute(); + Cuboid { x, y, z } + } + + /// Shift the cuboid along the x axis. + pub fn shift_x(self, x: S) -> Self { + Cuboid { + x: self.x.shift(x), + ..self + } + } + + /// Shift the cuboid along the y axis. + pub fn shift_y(self, y: S) -> Self { + Cuboid { + y: self.y.shift(y), + ..self + } + } + + /// Shift the cuboid along the z axis. + pub fn shift_z(self, z: S) -> Self { + Cuboid { + z: self.z.shift(z), + ..self + } + } + + /// Shift the cuboid by the given vector. + pub fn shift(self, [x, y, z]: [S; 3]) -> Self { + Cuboid { + x: self.x.shift(x), + y: self.y.shift(y), + z: self.z.shift(z), + } + } + + /// Does the given cuboid contain the given point. + pub fn contains(&self, [x, y, z]: [S; 3]) -> bool { + self.x.contains(x) && self.y.contains(y) && self.z.contains(z) + } + + /// Stretches the closest side(s) to the given point if the point lies outside of the Cuboid + /// area. + pub fn stretch_to_point(self, [px, py, pz]: [S; 3]) -> Self { + let Cuboid { x, y, z } = self; + Cuboid { + x: x.stretch_to_value(px), + y: y.stretch_to_value(py), + z: z.stretch_to_value(pz), + } + } + + /// The cuboid representing the area in which two cuboids overlap. + pub fn overlap(self, other: Self) -> Option { + self.x.overlap(other.x).and_then(|x| { + self.y + .overlap(other.y) + .and_then(|y| self.z.overlap(other.z).map(|z| Cuboid { x, y, z })) + }) + } + + /// The cuboid that encompass the two given cuboids. + pub fn max(self, other: Self) -> Self + where + S: Float, + { + Cuboid { + x: self.x.max(other.x), + y: self.y.max(other.y), + z: self.z.max(other.y), + } + } + + /// The start of the range along the x axis. + pub fn left(&self) -> S { + self.x.start + } + + /// The end of the range along the x axis. + pub fn right(&self) -> S { + self.x.end + } + + /// The start of the range along the y axis. + pub fn bottom(&self) -> S { + self.y.start + } + + /// The end of the range along the y axis. + pub fn top(&self) -> S { + self.y.end + } + + /// The start of the range along the z axis. + pub fn front(&self) -> S { + self.z.start + } + + /// The end of the range along the z axis. + pub fn back(&self) -> S { + self.z.end + } + + /// The quad for the face at the start of the range along the x axis. + pub fn left_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 4, 6, 2, 0)) + } + + /// The quad for the face at the end of the range along the x axis. + pub fn right_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 1, 3, 7, 5)) + } + + /// The quad for the face at the start of the range along the y axis. + pub fn bottom_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 0, 1, 5, 4)) + } + + /// The quad for the face at the end of the range along the y axis. + pub fn top_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 2, 6, 7, 3)) + } + + /// The quad for the face at the start of the range along the z axis. + pub fn front_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 0, 2, 3, 1)) + } + + /// The quad for the face at the end of the range along the z axis. + pub fn back_quad(&self) -> FaceQuad { + Quad(quad_from_corner_indices!(self, 5, 7, 6, 4)) + } + + /// The quad for the given face. + pub fn face_quad(&self, face: Face) -> FaceQuad { + match face { + Face::Front => self.front_quad(), + Face::Right => self.right_quad(), + Face::Back => self.back_quad(), + Face::Left => self.left_quad(), + Face::Bottom => self.bottom_quad(), + Face::Top => self.top_quad(), + } + } + + /// The 8 corners of the cuboid in the following order: + /// + /// ```ignore + /// y + /// | z + /// |/ + /// 0---x + /// + /// 6---7 + /// /| /| + /// 2---3 | + /// | 4-|-5 + /// |/ |/ + /// 0---1 + /// ``` + pub fn corners(&self) -> [[S; 3]; NUM_CORNERS as usize] { + let a = [self.x.start, self.y.start, self.z.start].into(); + let b = [self.x.end, self.y.start, self.z.start].into(); + let c = [self.x.start, self.y.end, self.z.start].into(); + let d = [self.x.end, self.y.end, self.z.start].into(); + let e = [self.x.start, self.y.start, self.z.end].into(); + let f = [self.x.end, self.y.start, self.z.end].into(); + let g = [self.x.start, self.y.end, self.z.end].into(); + let h = [self.x.end, self.y.end, self.z.end].into(); + [a, b, c, d, e, f, g, h] + } + + /// The same as `corners` but produces an iterator rather than a fixed-size array. + pub fn corners_iter(&self) -> Corners { + Corners { + cuboid: self, + corner_index: 0, + } + } + + /// The 6 faces of the of the cuboid in the order yielded by the `Faces` iterator. + pub fn faces(&self) -> [FaceQuad; NUM_FACES as usize] { + let mut faces = self.faces_iter(); + [ + faces.next().unwrap(), + faces.next().unwrap(), + faces.next().unwrap(), + faces.next().unwrap(), + faces.next().unwrap(), + faces.next().unwrap(), + ] + } + + /// An iterator yielding a quad for each face on the cuboid. + pub fn faces_iter(&self) -> FaceQuads { + FaceQuads { + faces: Faces { next_face_index: 0 }, + cuboid: self, + } + } + + /// Produce an iterator yielding every triangle in the cuboid (two for each face). + /// + /// Uses the `faces_iter` method internally. + pub fn triangles_iter(&self) -> Triangles { + let mut face_quads = self.faces_iter(); + let first_quad = face_quads.next().unwrap(); + let triangles = first_quad.triangles_iter(); + Triangles { + face_quads, + triangles, + } + } + + /// The length of the cuboid along the *x* axis (aka `width` or `w` for short). + pub fn w(&self) -> S { + self.x.len() + } + + /// The length of the cuboid along the *y* axis (aka `height` or `h` for short). + pub fn h(&self) -> S { + self.y.len() + } + + /// The length of the cuboid along the *z* axis (aka `depth` or `d` for short). + pub fn d(&self) -> S { + self.z.len() + } + + /// The dimensions (width, height and depth) of the cuboid as a vector. + pub fn whd(&self) -> [S; 3] { + [self.w(), self.h(), self.d()].into() + } + + /// The dimensions (width, height and depth) of the cuboid as a tuple. + pub fn w_h_d(&self) -> (S, S, S) { + (self.w(), self.h(), self.d()) + } + + /// The total volume of the cuboid. + pub fn volume(&self) -> S { + let (w, h, d) = self.w_h_d(); + w * h * d + } + + /// The cuboid with some padding applied to the left side. + pub fn pad_left(self, pad: S) -> Self { + Cuboid { + x: self.x.pad_start(pad), + ..self + } + } + + /// The cuboid with some padding applied to the right side. + pub fn pad_right(self, pad: S) -> Self { + Cuboid { + x: self.x.pad_end(pad), + ..self + } + } + + /// The cuboid with some padding applied to the bottom side. + pub fn pad_bottom(self, pad: S) -> Self { + Cuboid { + y: self.y.pad_start(pad), + ..self + } + } + + /// The cuboid with some padding applied to the top side. + pub fn pad_top(self, pad: S) -> Self { + Cuboid { + y: self.y.pad_end(pad), + ..self + } + } + + /// The cuboid with some padding applied to the front side. + pub fn pad_front(self, pad: S) -> Self { + Cuboid { + z: self.z.pad_start(pad), + ..self + } + } + + /// The cuboid with some padding applied to the back side. + pub fn pad_back(self, pad: S) -> Self { + Cuboid { + z: self.z.pad_end(pad), + ..self + } + } + + /// The cuboid with some padding amount applied to each side. + pub fn pad(self, pad: S) -> Self { + let Cuboid { x, y, z } = self; + Cuboid { + x: x.pad(pad), + y: y.pad(pad), + z: z.pad(pad), + } + } +} + +impl SubdivisionRanges +where + S: Copy, +{ + /// The `Cuboid`s representing each of the eight subdivisions. + /// + /// Subdivisions are yielded in the following order: + /// + /// 1. Front bottom left + /// 2. Front bottom right + /// 3. Front top left + /// 4. Front top right + /// 5. Back bottom left + /// 6. Back bottom right + /// 7. Back top left + /// 8. Back top right + pub fn cuboids(&self) -> [Cuboid; NUM_SUBDIVISIONS as usize] { + let c1 = subdivision_from_index!(self, 0); + let c2 = subdivision_from_index!(self, 1); + let c3 = subdivision_from_index!(self, 2); + let c4 = subdivision_from_index!(self, 3); + let c5 = subdivision_from_index!(self, 4); + let c6 = subdivision_from_index!(self, 5); + let c7 = subdivision_from_index!(self, 6); + let c8 = subdivision_from_index!(self, 7); + [c1, c2, c3, c4, c5, c6, c7, c8] + } + + /// The same as `cuboids` but each subdivision is yielded via the returned `Iterator`. + pub fn cuboids_iter(self) -> Subdivisions { + Subdivisions { + ranges: self, + subdivision_index: 0, + } + } + + // The subdivision at the given index within the range 0..NUM_SUBDIVISIONS. + fn subdivision_at_index(&self, index: u8) -> Option> { + let cuboid = match index { + 0 => subdivision_from_index!(self, 0), + 1 => subdivision_from_index!(self, 1), + 2 => subdivision_from_index!(self, 2), + 3 => subdivision_from_index!(self, 3), + 4 => subdivision_from_index!(self, 4), + 5 => subdivision_from_index!(self, 5), + 6 => subdivision_from_index!(self, 6), + 7 => subdivision_from_index!(self, 7), + _ => return None, + }; + Some(cuboid) + } +} + +fn corner_from_index(c: &Cuboid, index: u8) -> Option<[S; 3]> +where + S: Copy, +{ + let p = match index { + 0 => corner_from_index!(0, c), + 1 => corner_from_index!(1, c), + 2 => corner_from_index!(2, c), + 3 => corner_from_index!(3, c), + 4 => corner_from_index!(4, c), + 5 => corner_from_index!(5, c), + 6 => corner_from_index!(6, c), + 7 => corner_from_index!(7, c), + _ => return None, + }; + Some(p.into()) +} + +impl<'a, S> Iterator for Corners<'a, S> +where + S: Copy, +{ + type Item = [S; 3]; + fn next(&mut self) -> Option { + if let Some(p) = corner_from_index(self.cuboid, self.corner_index) { + self.corner_index += 1; + return Some(p); + } + None + } +} + +impl<'a, S> DoubleEndedIterator for Corners<'a, S> +where + S: Copy, +{ + fn next_back(&mut self) -> Option { + let next_index = self.corner_index + 1; + if let Some(p) = corner_from_index(self.cuboid, NUM_CORNERS - self.corner_index) { + self.corner_index = next_index; + return Some(p); + } + None + } +} + +impl<'a, S> ExactSizeIterator for Corners<'a, S> +where + S: Copy, +{ + fn len(&self) -> usize { + NUM_CORNERS as usize - self.corner_index as usize + } +} + +impl Face { + /// Produce a face from an index into the order in which faces are yielded by the cuboid + /// `Faces` iterator. + fn from_index(i: u8) -> Option { + let face = match i { + 0 => face_from_index!(0), + 1 => face_from_index!(1), + 2 => face_from_index!(2), + 3 => face_from_index!(3), + 4 => face_from_index!(4), + 5 => face_from_index!(5), + _ => return None, + }; + Some(face) + } +} + +impl<'a, S> FaceQuads<'a, S> {} + +impl Iterator for Faces { + type Item = Face; + fn next(&mut self) -> Option { + if let Some(face) = Face::from_index(self.next_face_index) { + self.next_face_index += 1; + return Some(face); + } + None + } +} + +impl DoubleEndedIterator for Faces { + fn next_back(&mut self) -> Option { + let next_face_index = self.next_face_index + 1; + if let Some(face) = Face::from_index(NUM_FACES - next_face_index) { + self.next_face_index = next_face_index; + return Some(face); + } + None + } +} + +impl ExactSizeIterator for Faces { + fn len(&self) -> usize { + NUM_FACES as usize - self.next_face_index as usize + } +} + +impl<'a, S> Iterator for FaceQuads<'a, S> +where + S: Scalar, +{ + type Item = FaceQuad; + fn next(&mut self) -> Option { + self.faces.next().map(|f| self.cuboid.face_quad(f)) + } + fn size_hint(&self) -> (usize, Option) { + self.faces.size_hint() + } +} + +impl<'a, S> DoubleEndedIterator for FaceQuads<'a, S> +where + S: Scalar, +{ + fn next_back(&mut self) -> Option { + self.faces.next_back().map(|f| self.cuboid.face_quad(f)) + } +} + +impl<'a, S> ExactSizeIterator for FaceQuads<'a, S> +where + S: Scalar, +{ + fn len(&self) -> usize { + self.faces.len() + } +} + +impl<'a, S> Iterator for Triangles<'a, S> +where + S: Scalar, +{ + type Item = Tri<[S; 3]>; + fn next(&mut self) -> Option { + loop { + if let Some(tri) = self.triangles.next() { + return Some(tri); + } + self.triangles = match self.face_quads.next() { + Some(quad) => quad.triangles_iter(), + None => return None, + } + } + } + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl<'a, S> DoubleEndedIterator for Triangles<'a, S> +where + S: Scalar, +{ + fn next_back(&mut self) -> Option { + loop { + if let Some(tri) = self.triangles.next_back() { + return Some(tri); + } + self.triangles = match self.face_quads.next_back() { + Some(quad) => quad.triangles_iter(), + None => return None, + } + } + } +} + +impl<'a, S> ExactSizeIterator for Triangles<'a, S> +where + S: Scalar, +{ + fn len(&self) -> usize { + let remaining_triangles = self.triangles.len(); + let remaining_quads = self.face_quads.len(); + remaining_triangles + remaining_quads * 2 + } +} + +impl Iterator for Subdivisions +where + S: Copy, +{ + type Item = Cuboid; + fn next(&mut self) -> Option { + if let Some(sd) = self.ranges.subdivision_at_index(self.subdivision_index) { + self.subdivision_index += 1; + return Some(sd); + } + None + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl DoubleEndedIterator for Subdivisions +where + S: Copy, +{ + fn next_back(&mut self) -> Option { + let next_index = self.subdivision_index + 1; + if let Some(sd) = self + .ranges + .subdivision_at_index(NUM_SUBDIVISIONS - next_index) + { + self.subdivision_index = next_index; + return Some(sd); + } + None + } +} + +impl ExactSizeIterator for Subdivisions +where + S: Copy, +{ + fn len(&self) -> usize { + NUM_SUBDIVISIONS as usize - self.subdivision_index as usize + } +} diff --git a/nannou_core/src/geom/ellipse.rs b/nannou_core/src/geom/ellipse.rs new file mode 100644 index 000000000..d8676912a --- /dev/null +++ b/nannou_core/src/geom/ellipse.rs @@ -0,0 +1,384 @@ +use crate::geom::{ + self, + scalar::{self, Scalar}, + Rect, Tri, +}; +use crate::math::{ + self, + num_traits::{Float, NumCast}, +}; + +/// Scalar types compatible with ellipses. +pub trait EllipseScalar: Float + Scalar { + /// 2 * PI. + const TAU: Self; +} + +/// A simple ellipse type with helper methods around the `ellipse` module's functions. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Ellipse { + /// The width and height off the `Ellipse`. + pub rect: Rect, + /// The resolution (number of sides) of the `Ellipse`. + pub resolution: S, +} + +/// A subsection of an `Ellipse`. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Section { + /// The ellipse from which this section is produced. + pub ellipse: Ellipse, + /// The angle in radians of the start of the section. + pub offset_radians: S, + /// The section of the circumference in radians. + pub section_radians: S, +} + +/// An iterator yielding the edges of an ellipse (or some section of an `ellipse`) as a series of +/// points. +#[derive(Clone, Debug)] +#[allow(missing_copy_implementations)] +pub struct Circumference { + index: S, + num_points: S, + middle: [S; 2], + rad_step: S, + rad_offset: S, + half_w: S, + half_h: S, +} + +/// All vertices necessary for yielding the triangles that make up the centre. +#[derive(Clone, Debug)] +#[allow(missing_copy_implementations)] +pub struct TriangleVertices { + middle: Option<[S; 2]>, + circumference: Circumference, +} + +/// An iterator yielding an index for every vertex in every triangle in the ellipse. +#[derive(Clone, Debug)] +#[allow(missing_copy_implementations)] +pub struct TriangleIndices { + yield_middle: bool, + left: Option, + right: Option, + total: usize, +} + +/// An iterator yielding triangles that describe an oval or some section of an oval. +#[derive(Clone, Debug)] +pub struct Triangles { + // The last circumference point yielded by the `CircumferenceOffset` iterator. + last: [S; 2], + // The circumference points used to yield yielded by the `CircumferenceOffset` iterator. + points: Circumference, +} + +impl Ellipse +where + S: EllipseScalar, +{ + /// Construct a new ellipse from its bounding rect and resolution (number of sides). + pub fn new(rect: Rect, resolution: S) -> Self { + Ellipse { rect, resolution } + } + + /// A section of the `Ellipse`. + /// + /// `offset_radians` describes the angle at which the offset begins. + /// + /// `section_radians` describes how large the section is as an angle. + pub fn section(self, offset_radians: S, section_radians: S) -> Section { + Section { + ellipse: self, + offset_radians, + section_radians, + } + } + + /// Produces an iterator yielding the points of the ellipse circumference. + pub fn circumference(self) -> Circumference { + let Ellipse { rect, resolution } = self; + Circumference::new(rect, resolution) + } + + /// Produces an iterator yielding the triangles that describe the ellipse. + /// + /// TODO: Describe the order. + pub fn triangles(self) -> Triangles { + self.circumference().triangles() + } + + /// The same as **Triangles**, but produces the indices of each triangle into the returned + /// **TriangleVertices** iterator rather than the vertices for each corner. + pub fn triangle_indices(&self) -> (TriangleVertices, TriangleIndices) { + self.circumference().triangle_indices() + } +} + +impl Section +where + S: EllipseScalar, +{ + /// Produces an iterator yielding the points of the ellipse circumference. + pub fn circumference(self) -> Circumference { + let Section { + ellipse, + offset_radians, + section_radians, + } = self; + let circ = Circumference::new_section(ellipse.rect, ellipse.resolution, section_radians); + circ.offset_radians(offset_radians) + } + + /// Produces an iterator yielding the triangles that describe the ellipse section. + /// + /// TODO: Describe the order. + pub fn trangles(self) -> Triangles { + self.circumference().triangles() + } + + /// The same as **Triangles**, but produces the indices of each triangle into the returned + /// **TriangleVertices** iterator rather than the vertices for each corner. + pub fn triangle_indices(&self) -> (TriangleVertices, TriangleIndices) { + self.circumference().triangle_indices() + } +} + +impl Circumference +where + S: EllipseScalar, +{ + fn new_inner(rect: Rect, num_points: S, rad_step: S) -> Self { + let (x, y, w, h) = rect.x_y_w_h(); + let two = math::two(); + Circumference { + index: S::zero(), + num_points: num_points, + middle: [x, y].into(), + half_w: w / two, + half_h: h / two, + rad_step: rad_step, + rad_offset: S::zero(), + } + } + + /// An iterator yielding the ellipse's edges as a circumference represented as a series of + /// points. + /// + /// `resolution` is clamped to a minimum of `1` as to avoid creating a `Circumference` that + /// produces `NaN` values. + pub fn new(rect: Rect, mut resolution: S) -> Self { + resolution = crate::math::partial_max(resolution, S::one()); + Self::new_section(rect, resolution, S::TAU) + } + + /// Produces a new iterator that yields only a section of the ellipse's circumference, where + /// the section is described via its angle in radians. + /// + /// `resolution` is clamped to a minimum of `1` as to avoid creating a `Circumference` that + /// produces `NaN` values. + pub fn new_section(rect: Rect, resolution: S, radians: S) -> Self { + Self::new_inner(rect, resolution + S::one(), radians / resolution) + } + + /// Produces a new iterator that yields only a section of the ellipse's circumference, where + /// the section is described via its angle in radians. + pub fn section(mut self, radians: S) -> Self { + let resolution = self.num_points - S::one(); + self.rad_step = radians / resolution; + self + } + + /// Rotates the position at which the iterator starts yielding points by the given radians. + /// + /// This is particularly useful for yielding a different section of the circumference when + /// using `circumference_section` + pub fn offset_radians(mut self, radians: S) -> Self { + self.rad_offset = radians; + self + } + + /// Produces an `Iterator` yielding `Triangle`s. + /// + /// Triangles are created by joining each edge yielded by the inner `Circumference` to the + /// middle of the ellipse. + pub fn triangles(mut self) -> Triangles { + let last = self.next().unwrap_or(self.middle); + Triangles { last, points: self } + } + + /// The same as **Triangles**, but produces the indices of each triangle into the returned + /// **TriangleVertices** iterator rather than the vertices for each corner. + pub fn triangle_indices(self) -> (TriangleVertices, TriangleIndices) { + let middle = Some(self.middle); + let num_vertices = self.len(); + let circumference = self; + let vertices = TriangleVertices { + middle, + circumference, + }; + let indices = TriangleIndices { + yield_middle: true, + left: Some(1), + right: Some(2), + total: num_vertices, + }; + (vertices, indices) + } +} + +impl EllipseScalar for f32 { + const TAU: Self = core::f32::consts::TAU; +} + +impl EllipseScalar for f64 { + const TAU: Self = core::f64::consts::TAU; +} + +impl Iterator for Circumference +where + S: EllipseScalar, +{ + type Item = [S; 2]; + fn next(&mut self) -> Option { + let Circumference { + ref mut index, + num_points, + middle: [mx, my], + rad_step, + rad_offset, + half_w, + half_h, + } = *self; + if *index >= num_points { + return None; + } + let x = mx + half_w * (rad_offset + rad_step * *index).cos(); + let y = my + half_h * (rad_offset + rad_step * *index).sin(); + *index += S::one(); + Some([x, y].into()) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +// TODO: +// impl DoubleEndedIterator for Circumference +// where +// S: Scalar, +// { +// } + +impl ExactSizeIterator for Circumference +where + S: EllipseScalar + NumCast, +{ + fn len(&self) -> usize { + NumCast::from(self.num_points - self.index).unwrap() + } +} + +impl Iterator for TriangleVertices +where + S: EllipseScalar, +{ + type Item = [S; 2]; + fn next(&mut self) -> Option { + self.middle.take().or_else(|| self.circumference.next()) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for TriangleVertices +where + S: EllipseScalar, +{ + fn len(&self) -> usize { + (if self.middle.is_some() { 1 } else { 0 }) + self.circumference.len() + } +} + +impl Iterator for TriangleIndices { + type Item = usize; + fn next(&mut self) -> Option { + if self.yield_middle { + self.yield_middle = false; + Some(0) + } else if let Some(left) = self.left.take() { + Some(left) + } else if let Some(right) = self.right.take() { + // Check if we're done. If not, step the left and right indices. + if right < self.total { + self.yield_middle = true; + self.left = Some(right); + self.right = Some(right + 1); + } + Some(right) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for TriangleIndices { + fn len(&self) -> usize { + if let Some(right) = self.right { + let n_tris = self.total - right; + let remaining_middle = if self.yield_middle { 1 } else { 0 }; + let remaining_left = if self.left.is_some() { 1 } else { 0 }; + let remaining_right = 1; + n_tris * geom::tri::NUM_VERTICES as usize + + remaining_middle + + remaining_left + + remaining_right + } else { + 0 + } + } +} + +impl Iterator for Triangles +where + S: EllipseScalar, +{ + type Item = Tri<[S; 2]>; + fn next(&mut self) -> Option { + let Triangles { + ref mut points, + ref mut last, + } = *self; + points.next().map(|next| { + let triangle = Tri([points.middle, *last, next]); + *last = next; + triangle + }) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for Triangles +where + S: EllipseScalar, +{ + fn len(&self) -> usize { + self.points.len() + } +} diff --git a/nannou_core/src/geom/mod.rs b/nannou_core/src/geom/mod.rs new file mode 100644 index 000000000..a95c0f11f --- /dev/null +++ b/nannou_core/src/geom/mod.rs @@ -0,0 +1,91 @@ +//! Types, functions and other items related to geometry. This module is the source of all graphics +//! and lazer primitives and aids work in 2D and 3D space. +//! +//! Each module provides a set of general tools for working with the named geometry including: +//! +//! - A typed, object representation. +//! - Functions for producing vertices, triangles and triangulation indices. +//! - Functions for checking whether or not the geometry contains a point. +//! - Functions for determining the bounding rectangle or cuboid. +//! - A function for finding the centroid. + +pub mod cuboid; +pub mod ellipse; +pub mod point; +pub mod polygon; +pub mod quad; +pub mod range; +pub mod rect; +pub mod scalar; +pub mod tri; +pub mod vector; +pub mod vertex; + +pub use self::cuboid::Cuboid; +pub use self::ellipse::Ellipse; +pub use self::point::{pt2, pt3, pt4, Point2, Point3, Point4}; +pub use self::polygon::Polygon; +pub use self::quad::Quad; +pub use self::range::{Align, Edge, Range}; +pub use self::rect::{Corner, Padding, Rect}; +pub use self::scalar::Scalar; +pub use self::tri::Tri; +#[allow(deprecated)] +pub use self::vector::{Vector2, Vector3, Vector4}; +pub use self::vertex::{Vertex, Vertex2d, Vertex3d}; +pub use glam::{ + dvec2, dvec3, dvec4, ivec2, ivec3, ivec4, vec2, vec3, vec4, DVec2, DVec3, DVec4, IVec2, IVec3, + IVec4, Vec2, Vec3, Vec4, +}; + +// General geometry utility functions + +/// The `Rect` that bounds the given sequence of vertices. +/// +/// Returns `None` if the given iterator is empty. +pub fn bounding_rect(vertices: I) -> Option::Scalar>> +where + I: IntoIterator, + I::Item: Vertex2d, +{ + let mut vertices = vertices.into_iter(); + vertices.next().map(|first| { + let [x, y] = first.point2(); + let bounds = Rect { + x: Range::new(x, x), + y: Range::new(y, y), + }; + vertices.fold(bounds, |b, v| b.stretch_to_point(v.point2())) + }) +} + +/// The `Cuboid` that bounds the given sequence of vertices. +/// +/// Returns `None` if the given iterator is empty. +pub fn bounding_cuboid(vertices: I) -> Option::Scalar>> +where + I: IntoIterator, + I::Item: Vertex3d, +{ + let mut vertices = vertices.into_iter(); + vertices.next().map(|first| { + let [x, y, z] = first.point3(); + let bounds = Cuboid { + x: Range::new(x, x), + y: Range::new(y, y), + z: Range::new(z, z), + }; + vertices.fold(bounds, |b, v| b.stretch_to_point(v.point3())) + }) +} + +/// The `centroid` (average position) of all vertices in the given iterator. +/// +/// Returns `None` if the given iterator contains no vertices. +pub fn centroid(vertices: I) -> Option +where + I: IntoIterator, + I::Item: vertex::Average, +{ + ::average(vertices) +} diff --git a/nannou_core/src/geom/point.rs b/nannou_core/src/geom/point.rs new file mode 100644 index 000000000..44122a726 --- /dev/null +++ b/nannou_core/src/geom/point.rs @@ -0,0 +1,31 @@ +//! Implementation of the **Point** types. +//! +//! Currently, **Point** is simply a type alias for **Vector**. While this makes it easier for new +//! uses to understand and switch between the two, it also conflates the the two mathematical +//! concepts which are quite distinct. It is possible that in the future, we will switch to using +//! distinct types. For now, we are attempting to monitor usage and feedback to determine whether +//! or not this change is worth it. + +/// A 2-dimensional point type. +pub type Point2 = glam::Vec2; + +/// A 3-dimensional point type. +pub type Point3 = glam::Vec3; + +/// A 4-dimensional point type. +pub type Point4 = glam::Vec4; + +/// Construct a 2-dimensional point. +pub fn pt2(x: f32, y: f32) -> Point2 { + (x, y).into() +} + +/// Construct a 3-dimensional point. +pub fn pt3(x: f32, y: f32, z: f32) -> Point3 { + (x, y, z).into() +} + +/// Construct a 4-dimensional point. +pub fn pt4(x: f32, y: f32, z: f32, w: f32) -> Point4 { + (x, y, z, w).into() +} diff --git a/nannou_core/src/geom/polygon.rs b/nannou_core/src/geom/polygon.rs new file mode 100644 index 000000000..5f0b79527 --- /dev/null +++ b/nannou_core/src/geom/polygon.rs @@ -0,0 +1,152 @@ +use crate::geom::tri::{self, Tri}; +use crate::geom::{Cuboid, Rect, Vertex, Vertex2d, Vertex3d}; + +/// A simple type wrapper around a list of points that describe a polygon. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Polygon { + /// The iterator yielding all points in the polygon. + pub points: I, +} + +/// An iterator yielding indices into a polygon's vertices required to triangulate the polygon. +#[derive(Clone, Debug)] +pub struct TriangleIndices { + index: usize, + n_points: usize, +} + +impl Polygon +where + I: Iterator, +{ + /// Construct a new polygon from the given list of points describing its vertices. + pub fn new

(points: P) -> Self + where + P: IntoIterator, + { + let points = points.into_iter(); + Polygon { points } + } + + /// Triangulate the polygon given as a list of `Point`s describing its sides. + /// + /// Returns `None` if the polygon's iterator yields less than two points. + pub fn triangles(self) -> Option> { + triangles(self.points) + } + + /// Returns `Some` with the touched triangle if the given `Point` is over the polygon described + /// by the given series of points. + /// + /// This uses the `triangles` function internally. + pub fn contains(self, p: &I::Item) -> Option> + where + I::Item: Vertex2d, + { + contains(self.points, p) + } + + /// The `Rect` that bounds the polygon. + /// + /// Returns `None` if the polygon's point iterator is empty. + pub fn bounding_rect(self) -> Option::Scalar>> + where + I::Item: Vertex2d, + { + super::bounding_rect(self.points) + } + + /// The `Cuboid that bounds the polygon. + /// + /// Returns `None` if the polygon's point iterator is empty. + pub fn bounding_cuboid(self) -> Option::Scalar>> + where + I::Item: Vertex3d, + { + super::bounding_cuboid(self.points) + } +} + +/// An iterator that triangulates a polygon represented by a sequence of points describing its +/// edges. +#[derive(Clone, Debug)] +pub struct Triangles +where + I: Iterator, +{ + first: I::Item, + prev: I::Item, + points: I, +} + +/// Triangulate the polygon given as a list of `Point`s describing its sides. +/// +/// Returns `None` if the given iterator yields less than two points. +pub fn triangles(points: I) -> Option> +where + I: IntoIterator, +{ + let mut points = points.into_iter(); + let first = match points.next() { + Some(p) => p, + None => return None, + }; + let prev = match points.next() { + Some(p) => p, + None => return None, + }; + Some(Triangles { + first: first, + prev: prev, + points: points, + }) +} + +/// An iterator yielding indices into a polygon's vertices required to triangulate the polygon. +pub fn triangle_indices(n_points: usize) -> TriangleIndices { + let index = 0; + TriangleIndices { index, n_points } +} + +/// Returns `Some` with the touched triangle if the given `Point` is over the polygon described by +/// the given series of points. +/// +/// This uses the `triangles` function internally. +pub fn contains(points: I, point: &I::Item) -> Option> +where + I: IntoIterator, + I::Item: Vertex2d, +{ + triangles(points).and_then(|ts| tri::iter_contains(ts, &point)) +} + +impl Iterator for Triangles +where + I: Iterator, + I::Item: Vertex, +{ + type Item = Tri; + fn next(&mut self) -> Option { + self.points.next().map(|point| { + let t = Tri([self.first, self.prev, point]); + self.prev = point; + t + }) + } +} + +impl Iterator for TriangleIndices { + type Item = usize; + fn next(&mut self) -> Option { + let index = self.index; + let tri_index = index / 3; + if self.n_points < tri_index + 3 { + return None; + } + self.index += 1; + match index % 3 { + 0 => Some(0), + remainder => Some(tri_index + remainder), + } + } +} diff --git a/nannou_core/src/geom/quad.rs b/nannou_core/src/geom/quad.rs new file mode 100644 index 000000000..79221f1f2 --- /dev/null +++ b/nannou_core/src/geom/quad.rs @@ -0,0 +1,364 @@ +use crate::geom::{tri, vertex, Cuboid, Range, Rect, Tri, Vertex, Vertex2d, Vertex3d}; +use core::ops::{Deref, Index}; + +/// The number of vertices in a quad. +pub const NUM_VERTICES: u8 = 4; + +/// The number of triangles that make up a quad. +pub const NUM_TRIANGLES: u8 = 2; + +/// The same as `triangles`, but instead returns the vertex indices for each triangle. +pub const TRIANGLE_INDEX_TRIS: TrianglesIndexTris = [[0, 1, 2], [0, 2, 3]]; +pub type TrianglesIndexTris = [[usize; tri::NUM_VERTICES as usize]; NUM_TRIANGLES as usize]; + +/// The number of indices used to describe each triangle in the quad. +pub const NUM_TRIANGLE_INDICES: u8 = 6; + +/// The same as `triangles`, but instead returns the vertex indices for each triangle. +pub const TRIANGLE_INDICES: [usize; NUM_TRIANGLE_INDICES as usize] = [0, 1, 2, 0, 2, 3]; + +/// A quad represented by its four vertices. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub struct Quad(pub [V; NUM_VERTICES as usize]); + +/// An `Iterator` yielding the two triangles that make up a quad. +#[derive(Clone, Debug)] +pub struct Triangles { + a: Option>, + b: Option>, +} + +/// A simple iterator yielding each vertex in a `Quad`. +#[derive(Clone, Debug)] +pub struct Vertices { + quad: Quad, + index: u8, +} + +impl Quad +where + V: Vertex, +{ + /// Produce an iterator yielding each vertex in the `Quad`. + pub fn vertices(self) -> Vertices { + vertices(self) + } + + /// Produce the centroid of the quad, aka the "mean"/"average" vertex. + pub fn centroid(&self) -> V + where + V: vertex::Average, + { + centroid(self) + } + + /// Triangulates the given quad, represented by four points that describe its edges in either + /// clockwise or anti-clockwise order. + /// + /// # Example + /// + /// The following rectangle + /// + /// ```ignore + /// a b + /// -------- + /// | | + /// | | + /// | | + /// -------- + /// d c + /// + /// ``` + /// + /// given as + /// + /// ```ignore + /// triangles([a, b, c, d]) + /// ``` + /// + /// returns + /// + /// ```ignore + /// (Tri([a, b, c]), Tri([a, c, d])) + /// ``` + /// + /// Here's a basic code example: + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::{self, pt2, Quad, Tri}; + /// + /// fn main() { + /// let a = pt2(0.0, 1.0); + /// let b = pt2(1.0, 1.0); + /// let c = pt2(1.0, 0.0); + /// let d = pt2(0.0, 0.0); + /// let quad = Quad([a, b, c, d]); + /// let triangles = geom::quad::triangles(&quad); + /// assert_eq!(triangles, (Tri([a, b, c]), Tri([a, c, d]))); + /// } + /// ``` + #[inline] + pub fn triangles(&self) -> (Tri, Tri) { + triangles(self) + } + + /// The same as `triangles` but provided as an **Iterator**. + pub fn triangles_iter(&self) -> Triangles { + triangles_iter(self) + } + + /// The bounding `Rect` of the quad. + pub fn bounding_rect(self) -> Rect + where + V: Vertex2d, + { + let (a, b, c, d) = self.into(); + let ([ax, ay], b, c, d) = (a.point2(), b.point2(), c.point2(), d.point2()); + let rect = Rect { + x: Range::new(ax, ax), + y: Range::new(ay, ay), + }; + rect.stretch_to_point(b) + .stretch_to_point(c) + .stretch_to_point(d) + } + + /// The bounding `Rect` of the triangle. + pub fn bounding_cuboid(self) -> Cuboid + where + V: Vertex3d, + { + let (a, b, c, d) = self.into(); + let ([ax, ay, az], b, c, d) = (a.point3(), b.point3(), c.point3(), d.point3()); + let cuboid = Cuboid { + x: Range::new(ax, ax), + y: Range::new(ay, ay), + z: Range::new(az, az), + }; + cuboid + .stretch_to_point(b) + .stretch_to_point(c) + .stretch_to_point(d) + } + + /// Map the **Quad**'s vertices to a new type. + pub fn map_vertices(self, mut map: F) -> Quad + where + F: FnMut(V) -> V2, + { + let (a, b, c, d) = self.into(); + Quad([map(a), map(b), map(c), map(d)]) + } +} + +/// Produce an iterator yielding each vertex in the given **Quad**. +pub fn vertices(quad: Quad) -> Vertices { + let index = 0; + Vertices { quad, index } +} + +/// Produce the centroid of the quad, aka the "mean"/"average" vertex. +pub fn centroid(quad: &Quad) -> V +where + V: vertex::Average, +{ + crate::geom::centroid(quad.iter().cloned()).unwrap() +} + +/// Triangulates the given quad, represented by four points that describe its edges in either +/// clockwise or anti-clockwise order. +/// +/// # Example +/// +/// The following rectangle +/// +/// ```ignore +/// +/// a b +/// -------- +/// | | +/// | | +/// | | +/// -------- +/// d c +/// +/// ``` +/// +/// given as +/// +/// ```ignore +/// triangles([a, b, c, d]) +/// ``` +/// +/// returns +/// +/// ```ignore +/// (Tri([a, b, c]), Tri([a, c, d])) +/// ``` +/// +/// Here's a basic code example: +/// +/// ``` +/// # use nannou_core as nannou; +/// use nannou::geom::{self, pt2, Quad, Tri}; +/// +/// fn main() { +/// let a = pt2(0.0, 1.0); +/// let b = pt2(1.0, 1.0); +/// let c = pt2(1.0, 0.0); +/// let d = pt2(0.0, 0.0); +/// let quad = Quad([a, b, c, d]); +/// let triangles = geom::quad::triangles(&quad); +/// assert_eq!(triangles, (Tri([a, b, c]), Tri([a, c, d]))); +/// } +/// ``` +#[inline] +pub fn triangles(q: &Quad) -> (Tri, Tri) +where + V: Vertex, +{ + let a = Tri::from_index_tri(&q.0, &TRIANGLE_INDEX_TRIS[0]); + let b = Tri::from_index_tri(&q.0, &TRIANGLE_INDEX_TRIS[1]); + (a, b) +} + +/// The same as `triangles` but provided as an `Iterator`. +pub fn triangles_iter(points: &Quad) -> Triangles +where + V: Vertex, +{ + let (a, b) = triangles(points); + Triangles { + a: Some(a), + b: Some(b), + } +} + +impl Iterator for Triangles { + type Item = Tri; + fn next(&mut self) -> Option { + self.a.take().or_else(|| self.b.take()) + } + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl DoubleEndedIterator for Triangles { + fn next_back(&mut self) -> Option { + self.b.take().or_else(|| self.a.take()) + } +} + +impl ExactSizeIterator for Triangles { + fn len(&self) -> usize { + match (&self.a, &self.b) { + (&Some(_), &Some(_)) => 2, + (&None, &Some(_)) => 0, + _ => 1, + } + } +} + +impl Iterator for Vertices +where + V: Clone, +{ + type Item = V; + fn next(&mut self) -> Option { + if self.index < NUM_VERTICES { + let v = self.quad[self.index as usize].clone(); + self.index += 1; + Some(v) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for Vertices +where + V: Clone, +{ + fn len(&self) -> usize { + NUM_VERTICES as usize - self.index as usize + } +} + +impl Deref for Quad { + type Target = [V; NUM_VERTICES as usize]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<[V; NUM_VERTICES as usize]> for Quad +where + V: Vertex, +{ + fn from(points: [V; NUM_VERTICES as usize]) -> Self { + Quad(points) + } +} + +impl From<(V, V, V, V)> for Quad +where + V: Vertex, +{ + fn from((a, b, c, d): (V, V, V, V)) -> Self { + Quad([a, b, c, d]) + } +} + +impl Into<[V; NUM_VERTICES as usize]> for Quad +where + V: Vertex, +{ + fn into(self) -> [V; NUM_VERTICES as usize] { + self.0 + } +} + +impl Into<(V, V, V, V)> for Quad +where + V: Vertex, +{ + fn into(self) -> (V, V, V, V) { + (self[0], self[1], self[2], self[3]) + } +} + +impl AsRef> for Quad +where + V: Vertex, +{ + fn as_ref(&self) -> &Quad { + self + } +} + +impl AsRef<[V; NUM_VERTICES as usize]> for Quad +where + V: Vertex, +{ + fn as_ref(&self) -> &[V; NUM_VERTICES as usize] { + &self.0 + } +} + +impl Index for Quad +where + V: Vertex, +{ + type Output = V; + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} diff --git a/nannou_core/src/geom/range.rs b/nannou_core/src/geom/range.rs new file mode 100644 index 000000000..f33ad44b0 --- /dev/null +++ b/nannou_core/src/geom/range.rs @@ -0,0 +1,820 @@ +//! A type for working with one-dimensional ranges. + +use crate::geom::scalar; +use crate::math::num_traits::{Float, NumCast, One, Zero}; +use crate::math::{self, two}; +use core::ops::{Add, Neg, Sub}; + +/// Some start and end position along a single axis. +/// +/// As an example, a **Rect** is made up of two **Range**s; one along the *x* axis, and one along +/// the *y* axis. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Range { + /// The start of some `Range` along an axis. + pub start: S, + /// The end of some `Range` along an axis. + pub end: S, +} + +/// Represents either the **Start** or **End** **Edge** of a **Range**. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Edge { + /// The beginning of a **Range**. + Start, + /// The end of a **Range**. + End, +} + +/// Describes alignment along a range. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Align { + Start, + Middle, + End, +} + +impl Range +where + S: Copy, +{ + /// Construct a new `Range` from a given range, i.e. `Range::new(start, end)`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range { start: 0.0, end: 10.0 }, Range::new(0.0, 10.0)); + /// ``` + pub fn new(start: S, end: S) -> Self { + Range { + start: start, + end: end, + } + } + + /// Construct a new `Range` from a given length and its centered position. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 10.0), Range::from_pos_and_len(5.0, 10.0)); + /// assert_eq!(Range::new(-5.0, 1.0), Range::from_pos_and_len(-2.0, 6.0)); + /// assert_eq!(Range::new(-100.0, 200.0), Range::from_pos_and_len(50.0, 300.0)); + /// ``` + pub fn from_pos_and_len(pos: S, len: S) -> Self + where + S: Float, + { + let half_len = len / two(); + let start = pos - half_len; + let end = pos + half_len; + Range::new(start, end) + } + + /// The `start` value subtracted from the `end` value. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(-5.0, 5.0).magnitude(), 10.0); + /// assert_eq!(Range::new(5.0, -5.0).magnitude(), -10.0); + /// assert_eq!(Range::new(15.0, 10.0).magnitude(), -5.0); + /// ``` + pub fn magnitude(&self) -> S + where + S: Sub, + { + self.end - self.start + } + + /// The absolute length of the Range aka the absolute magnitude. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(-5.0, 5.0).len(), 10.0); + /// assert_eq!(Range::new(5.0, -5.0).len(), 10.0); + /// assert_eq!(Range::new(15.0, 10.0).len(), 5.0); + /// ``` + pub fn len(&self) -> S + where + S: Neg + PartialOrd + Sub + Zero, + { + let mag = self.magnitude(); + let zero = S::zero(); + if mag < zero { + -mag + } else { + mag + } + } + + /// Return the value directly between the start and end values. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(-5.0, 5.0).middle(), 0.0); + /// assert_eq!(Range::new(5.0, -5.0).middle(), 0.0); + /// assert_eq!(Range::new(10.0, 15.0).middle(), 12.5); + /// assert_eq!(Range::new(20.0, 40.0).middle(), 30.0); + /// assert_eq!(Range::new(20.0, -40.0).middle(), -10.0); + /// ``` + pub fn middle(&self) -> S + where + S: Float, + { + (self.end + self.start) / two() + } + + /// The current range with its start and end values swapped. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(-5.0, 5.0).invert(), Range::new(5.0, -5.0)); + /// assert_eq!(Range::new(-10.0, 10.0).invert(), Range::new(10.0, -10.0)); + /// assert_eq!(Range::new(0.0, 7.25).invert(), Range::new(7.25, 0.0)); + /// assert_eq!(Range::new(5.0, 1.0).invert(), Range::new(1.0, 5.0)); + /// ``` + pub fn invert(self) -> Self { + Range { + start: self.end, + end: self.start, + } + } + + /// Map the given scalar from `Self` to some other given `Range`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(0.0, 5.0); + /// + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.map_value(2.5, &b), 5.0); + /// assert_eq!(a.map_value(0.0, &b), 0.0); + /// assert_eq!(a.map_value(5.0, &b), 10.0); + /// assert_eq!(a.map_value(-5.0, &b), -10.0); + /// assert_eq!(a.map_value(10.0, &b), 20.0); + /// + /// let c = Range::new(10.0, -10.0); + /// assert_eq!(a.map_value(2.5, &c), 0.0); + /// assert_eq!(a.map_value(0.0, &c), 10.0); + /// assert_eq!(a.map_value(5.0, &c), -10.0); + /// assert_eq!(a.map_value(-5.0, &c), 30.0); + /// assert_eq!(a.map_value(10.0, &c), -30.0); + /// ``` + pub fn map_value(&self, value: S, other: &Self) -> S + where + S: NumCast, + { + math::map_range(value, self.start, self.end, other.start, other.end) + } + + /// Interpolates the **Range** using the given `weight`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let r = Range::new(-5.0, 5.0); + /// assert_eq!(r.lerp(0.0), -5.0); + /// assert_eq!(r.lerp(1.0), 5.0); + /// assert_eq!(r.lerp(0.5), 0.0); + /// ``` + pub fn lerp(&self, amount: S) -> S + where + S: Float, + { + self.start + ((self.end - self.start) * amount) + } + + /// Shift the `Range` start and end points by a given scalar. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 5.0).shift(5.0), Range::new(5.0, 10.0)); + /// assert_eq!(Range::new(0.0, 5.0).shift(-5.0), Range::new(-5.0, 0.0)); + /// assert_eq!(Range::new(5.0, -5.0).shift(-5.0), Range::new(0.0, -10.0)); + /// ``` + pub fn shift(self, amount: S) -> Self + where + S: Add, + { + Range { + start: self.start + amount, + end: self.end + amount, + } + } + + /// The direction of the Range represented as a normalised scalar. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 5.0).direction(), 1.0); + /// assert_eq!(Range::new(0.0, 0.0).direction(), 0.0); + /// assert_eq!(Range::new(0.0, -5.0).direction(), -1.0); + /// ``` + pub fn direction(&self) -> S + where + S: Neg + One + PartialOrd + Zero, + { + if self.start < self.end { + S::one() + } else if self.start > self.end { + -S::one() + } else { + S::zero() + } + } + + /// Converts the Range to an absolute Range by ensuring that `start` <= `end`. + /// + /// If `start` > `end`, then the start and end points will be swapped. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 5.0).absolute(), Range::new(0.0, 5.0)); + /// assert_eq!(Range::new(5.0, 1.0).absolute(), Range::new(1.0, 5.0)); + /// assert_eq!(Range::new(10.0, -10.0).absolute(), Range::new(-10.0, 10.0)); + /// ``` + pub fn absolute(self) -> Self + where + S: PartialOrd, + { + if self.start > self.end { + self.invert() + } else { + self + } + } + + /// The Range that encompasses both self and the given Range. + /// + /// The returned Range's `start` will always be <= its `end`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(0.0, 3.0); + /// let b = Range::new(7.0, 10.0); + /// assert_eq!(a.max(b), Range::new(0.0, 10.0)); + /// + /// let c = Range::new(-20.0, -30.0); + /// let d = Range::new(5.0, -7.5); + /// assert_eq!(c.max(d), Range::new(-30.0, 5.0)); + /// ``` + pub fn max(self, other: Self) -> Self + where + S: Float, + { + let start = self.start.min(self.end).min(other.start).min(other.end); + let end = self.start.max(self.end).max(other.start).max(other.end); + Range::new(start, end) + } + + /// The Range that represents the range of the overlap between two Ranges if there is some. + /// + /// Note that If one end of `self` aligns exactly with the opposite end of `other`, `Some` + /// `Range` will be returned with a magnitude of `0.0`. This is useful for algorithms that + /// involve calculating the visibility of widgets, as it allows for including widgets whose + /// bounding box may be a one dimensional straight line. + /// + /// The returned `Range`'s `start` will always be <= its `end`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(0.0, 6.0); + /// let b = Range::new(4.0, 10.0); + /// assert_eq!(a.overlap(b), Some(Range::new(4.0, 6.0))); + /// + /// let c = Range::new(10.0, -30.0); + /// let d = Range::new(-5.0, 20.0); + /// assert_eq!(c.overlap(d), Some(Range::new(-5.0, 10.0))); + /// + /// let e = Range::new(0.0, 2.5); + /// let f = Range::new(50.0, 100.0); + /// assert_eq!(e.overlap(f), None); + /// ``` + pub fn overlap(mut self, mut other: Self) -> Option + where + S: PartialOrd + Sub + Zero, + { + self = self.absolute(); + other = other.absolute(); + let start = math::partial_max(self.start, other.start); + let end = math::partial_min(self.end, other.end); + let magnitude = end - start; + if magnitude >= S::zero() { + Some(Range::new(start, end)) + } else { + None + } + } + + /// The Range that encompasses both self and the given Range. + /// + /// The same as [**Range::max**](./struct.Range.html#method.max) but retains `self`'s original + /// direction. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(0.0, 3.0); + /// let b = Range::new(7.0, 10.0); + /// assert_eq!(a.max_directed(b), Range::new(0.0, 10.0)); + /// + /// let c = Range::new(-20.0, -30.0); + /// let d = Range::new(5.0, -7.5); + /// assert_eq!(c.max_directed(d), Range::new(5.0, -30.0)); + /// ``` + pub fn max_directed(self, other: Self) -> Self + where + S: Float, + { + if self.start <= self.end { + self.max(other) + } else { + self.max(other).invert() + } + } + + /// Is the given scalar within our range. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let range = Range::new(0.0, 10.0); + /// assert!(range.contains(5.0)); + /// assert!(!range.contains(12.0)); + /// assert!(!range.contains(-1.0)); + /// assert!(range.contains(0.0)); + /// assert!(range.contains(10.0)); + /// ``` + pub fn contains(&self, pos: S) -> bool + where + S: PartialOrd, + { + let Range { start, end } = self.absolute(); + start <= pos && pos <= end + } + + /// Round the values at both ends of the Range and return the result. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.25, 9.5).round(), Range::new(0.0, 10.0)); + /// assert_eq!(Range::new(4.95, -5.3).round(), Range::new(5.0, -5.0)); + /// ``` + pub fn round(self) -> Self + where + S: Float, + { + Self::new(self.start.round(), self.end.round()) + } + + /// Floor the values at both ends of the Range and return the result. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.25, 9.5).floor(), Range::new(0.0, 9.0)); + /// assert_eq!(Range::new(4.95, -5.3).floor(), Range::new(4.0, -6.0)); + /// ``` + pub fn floor(self) -> Self + where + S: Float, + { + Self::new(self.start.floor(), self.end.floor()) + } + + /// The Range with some padding given to the `start` value. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 10.0).pad_start(2.0), Range::new(2.0, 10.0)); + /// assert_eq!(Range::new(10.0, 0.0).pad_start(2.0), Range::new(8.0, 0.0)); + /// ``` + pub fn pad_start(mut self, pad: S) -> Self + where + S: Add + Neg + PartialOrd, + { + let new_start = self.start + if self.start <= self.end { pad } else { -pad }; + self.start = new_start; + self + } + + /// The Range with some padding given to the `end` value. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 10.0).pad_end(2.0), Range::new(0.0, 8.0)); + /// assert_eq!(Range::new(10.0, 0.0).pad_end(2.0), Range::new(10.0, 2.0)); + /// ``` + pub fn pad_end(mut self, pad: S) -> Self + where + S: Add + Neg + PartialOrd, + { + let new_end = self.end + if self.start <= self.end { -pad } else { pad }; + self.end = new_end; + self + } + + /// The Range with some given padding to be applied to each end. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 10.0).pad(2.0), Range::new(2.0, 8.0)); + /// assert_eq!(Range::new(10.0, 0.0).pad(2.0), Range::new(8.0, 2.0)); + /// ``` + pub fn pad(self, pad: S) -> Self + where + S: Add + Neg + PartialOrd, + { + self.pad_start(pad).pad_end(pad) + } + + /// The Range with some padding given for each end. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 10.0).pad_ends(1.0, 2.0), Range::new(1.0, 8.0)); + /// assert_eq!(Range::new(10.0, 0.0).pad_ends(4.0, 3.0), Range::new(6.0, 3.0)); + /// ``` + pub fn pad_ends(self, start: S, end: S) -> Self + where + S: Add + Neg + PartialOrd, + { + self.pad_start(start).pad_end(end) + } + + /// Clamp the given value to the range. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert_eq!(Range::new(0.0, 5.0).clamp_value(7.0), 5.0); + /// assert_eq!(Range::new(5.0, -2.5).clamp_value(-3.0), -2.5); + /// assert_eq!(Range::new(5.0, 10.0).clamp_value(0.0), 5.0); + /// ``` + pub fn clamp_value(&self, value: S) -> S + where + S: PartialOrd, + { + math::clamp(value, self.start, self.end) + } + + /// Stretch the end that is closest to the given value only if it lies outside the Range. + /// + /// The resulting Range will retain the direction of the original range. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(2.5, 5.0); + /// assert_eq!(a.stretch_to_value(10.0), Range::new(2.5, 10.0)); + /// assert_eq!(a.stretch_to_value(0.0), Range::new(0.0, 5.0)); + /// + /// let b = Range::new(0.0, -5.0); + /// assert_eq!(b.stretch_to_value(10.0), Range::new(10.0, -5.0)); + /// assert_eq!(b.stretch_to_value(-10.0), Range::new(0.0, -10.0)); + /// ``` + pub fn stretch_to_value(self, value: S) -> Self + where + S: PartialOrd, + { + let Range { start, end } = self; + if start <= end { + if value < start { + Range { + start: value, + end: end, + } + } else if value > end { + Range { + start: start, + end: value, + } + } else { + self + } + } else { + if value < end { + Range { + start: start, + end: value, + } + } else if value > start { + Range { + start: value, + end: end, + } + } else { + self + } + } + } + + /// Does `self` have the same direction as `other`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// assert!(Range::new(0.0, 1.0).has_same_direction(Range::new(100.0, 200.0))); + /// assert!(Range::new(0.0, -5.0).has_same_direction(Range::new(-2.5, -6.0))); + /// assert!(!Range::new(0.0, 5.0).has_same_direction(Range::new(2.5, -2.5))); + /// ``` + pub fn has_same_direction(self, other: Self) -> bool + where + S: PartialOrd, + { + let self_direction = self.start <= self.end; + let other_direction = other.start <= other.end; + self_direction == other_direction + } + + /// Align the `start` of `self` to the `start` of the `other` **Range**. + /// + /// If the direction of `other` is different to `self`, `self`'s `end` will be aligned to the + /// `start` of `other` instead. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(2.5, 7.5); + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.align_start_of(b), Range::new(0.0, 5.0)); + /// assert_eq!(b.align_start_of(a), Range::new(2.5, 12.5)); + /// + /// let c = Range::new(2.5, -2.5); + /// let d = Range::new(-5.0, 5.0); + /// assert_eq!(c.align_start_of(d), Range::new(0.0, -5.0)); + /// assert_eq!(d.align_start_of(c), Range::new(-7.5, 2.5)); + /// ``` + pub fn align_start_of(self, other: Self) -> Self + where + S: PartialOrd + Add + Sub, + { + let diff = if self.has_same_direction(other) { + other.start - self.start + } else { + other.start - self.end + }; + self.shift(diff) + } + + /// Align the `end` of `self` to the `end` of the `other` **Range**. + /// + /// If the direction of `other` is different to `self`, `self`'s `start` will be aligned to the + /// `end` of `other` instead. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(2.5, 7.5); + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.align_end_of(b), Range::new(5.0, 10.0)); + /// assert_eq!(b.align_end_of(a), Range::new(-2.5, 7.5)); + /// + /// let c = Range::new(2.5, -2.5); + /// let d = Range::new(-5.0, 5.0); + /// assert_eq!(c.align_end_of(d), Range::new(5.0, 0.0)); + /// assert_eq!(d.align_end_of(c), Range::new(-2.5, 7.5)); + /// ``` + pub fn align_end_of(self, other: Self) -> Self + where + S: PartialOrd + Add + Sub, + { + let diff = if self.has_same_direction(other) { + other.end - self.end + } else { + other.end - self.start + }; + self.shift(diff) + } + + /// Align the middle of `self` to the middle of the `other` **Range**. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(0.0, 5.0); + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.align_middle_of(b), Range::new(2.5, 7.5)); + /// assert_eq!(b.align_middle_of(a), Range::new(-2.5, 7.5)); + /// + /// let c = Range::new(2.5, -2.5); + /// let d = Range::new(-10.0, 0.0); + /// assert_eq!(c.align_middle_of(d), Range::new(-2.5, -7.5)); + /// assert_eq!(d.align_middle_of(c), Range::new(-5.0, 5.0)); + /// ``` + pub fn align_middle_of(self, other: Self) -> Self + where + S: Float, + { + let diff = other.middle() - self.middle(); + self.shift(diff) + } + + /// Aligns the `start` of `self` with the `end` of `other`. + /// + /// If the directions are opposite, aligns the `end` of self with the `end` of `other`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(2.5, 7.5); + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.align_after(b), Range::new(10.0, 15.0)); + /// assert_eq!(b.align_after(a), Range::new(7.5, 17.5)); + /// + /// let c = Range::new(2.5, -2.5); + /// let d = Range::new(-5.0, 5.0); + /// assert_eq!(c.align_after(d), Range::new(10.0, 5.0)); + /// assert_eq!(d.align_after(c), Range::new(-12.5, -2.5)); + /// ``` + pub fn align_after(self, other: Self) -> Self + where + S: PartialOrd + Add + Sub, + { + let diff = if self.has_same_direction(other) { + other.end - self.start + } else { + other.end - self.end + }; + self.shift(diff) + } + + /// Aligns the `end` of `self` with the `start` of `other`. + /// + /// If the directions are opposite, aligns the `start` of self with the `start` of `other`. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::Range; + /// + /// let a = Range::new(2.5, 7.5); + /// let b = Range::new(0.0, 10.0); + /// assert_eq!(a.align_before(b), Range::new(-5.0, 0.0)); + /// assert_eq!(b.align_before(a), Range::new(-7.5, 2.5)); + /// + /// let c = Range::new(2.5, -2.5); + /// let d = Range::new(-5.0, 5.0); + /// assert_eq!(c.align_before(d), Range::new(-5.0, -10.0)); + /// assert_eq!(d.align_before(c), Range::new(2.5, 12.5)); + /// ``` + pub fn align_before(self, other: Self) -> Self + where + S: PartialOrd + Add + Sub, + { + let diff = if self.has_same_direction(other) { + other.start - self.end + } else { + other.start - self.start + }; + self.shift(diff) + } + + /// Align `self` to `other` along the *x* axis in accordance with the given `Align` variant. + pub fn align_to(self, align: Align, other: Self) -> Self + where + S: Float, + { + match align { + Align::Start => self.align_start_of(other), + Align::Middle => self.align_middle_of(other), + Align::End => self.align_end_of(other), + } + } + + /// The closest **Edge** of `self` to the given `scalar`. + /// + /// Returns **Start** if the distance between both **Edge**s is equal. + /// + /// # Examples + /// + /// ``` + /// # use nannou_core as nannou; + /// use nannou::geom::{Edge, Range}; + /// + /// assert_eq!(Range::new(0.0, 10.0).closest_edge(4.0), Edge::Start); + /// assert_eq!(Range::new(0.0, 10.0).closest_edge(7.0), Edge::End); + /// assert_eq!(Range::new(0.0, 10.0).closest_edge(5.0), Edge::Start); + /// ``` + pub fn closest_edge(&self, scalar: S) -> Edge + where + S: PartialOrd + Sub, + { + let Range { start, end } = *self; + let start_diff = if scalar < start { + start - scalar + } else { + scalar - start + }; + let end_diff = if scalar < end { + end - scalar + } else { + scalar - end + }; + if start_diff <= end_diff { + Edge::Start + } else { + Edge::End + } + } +} diff --git a/nannou_core/src/geom/rect.rs b/nannou_core/src/geom/rect.rs new file mode 100644 index 000000000..5c483ba4f --- /dev/null +++ b/nannou_core/src/geom/rect.rs @@ -0,0 +1,815 @@ +use crate::geom::{quad, scalar, Align, Edge, Quad, Range, Scalar, Tri}; +use crate::math::{self, num_traits::Float}; +use core::ops::Neg; + +/// Defines a Rectangle's bounds across the x and y axes. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Rect { + /// The start and end positions of the Rectangle on the x axis. + pub x: Range, + /// The start and end positions of the Rectangle on the y axis. + pub y: Range, +} + +/// The distance between the inner edge of a border and the outer edge of the inner content. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Padding { + /// Padding on the start and end of the *x* axis. + pub x: Range, + /// Padding on the start and end of the *y* axis. + pub y: Range, +} + +/// Either of the four corners of a **Rect**. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Corner { + /// The top left corner of a **Rect**. + TopLeft, + /// The top right corner of a **Rect**. + TopRight, + /// The bottom left corner of a **Rect**. + BottomLeft, + /// The bottom right corner of a **Rect**. + BottomRight, +} + +/// Yields even subdivisions of a `Rect`. +/// +/// The four subdivisions will each be yielded as a `Rect` whose dimensions are exactly half of the +/// original `Rect`. +#[derive(Clone)] +pub struct Subdivisions { + ranges: SubdivisionRanges, + subdivision_index: u8, +} + +/// The ranges that describe the subdivisions of a `Rect`. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct SubdivisionRanges { + /// The first half of the x range. + pub x_a: Range, + /// The second half of the x range. + pub x_b: Range, + /// The first half of the y range. + pub y_a: Range, + /// The second half of the y range. + pub y_b: Range, +} + +/// An iterator yielding the four corners of a `Rect`. +#[derive(Clone, Debug)] +pub struct Corners { + rect: Rect, + index: u8, +} + +/// The triangles iterator yielded by the `Rect`. +pub type Triangles = quad::Triangles<[S; 2]>; + +/// The number of subdivisions when dividing a `Rect` in half along the *x* and *y* axes. +pub const NUM_SUBDIVISIONS: u8 = 4; + +/// The number of subdivisions when dividing a `Rect` in half along the *x* and *y* axes. +pub const NUM_CORNERS: u8 = 4; + +/// The number of triangles used to represent a `Rect`. +pub const NUM_TRIANGLES: u8 = 2; + +impl Padding +where + S: Scalar, +{ + /// No padding. + pub fn none() -> Self { + Padding { + x: Range::new(S::zero(), S::zero()), + y: Range::new(S::zero(), S::zero()), + } + } +} + +// Given some `SubdivisionRanges` and a subdivision index, produce the rect for that subdivision. +macro_rules! subdivision_from_index { + ($ranges:expr,0) => { + Rect { + x: $ranges.x_a, + y: $ranges.y_a, + } + }; + ($ranges:expr,1) => { + Rect { + x: $ranges.x_b, + y: $ranges.y_a, + } + }; + ($ranges:expr,2) => { + Rect { + x: $ranges.x_a, + y: $ranges.y_b, + } + }; + ($ranges:expr,3) => { + Rect { + x: $ranges.x_b, + y: $ranges.y_b, + } + }; +} + +// Given some `Rect` and an index, produce the corner for that index. +macro_rules! corner_from_index { + ($rect:expr,0) => { + [$rect.x.start, $rect.y.end] + }; + ($rect:expr,1) => { + [$rect.x.end, $rect.y.end] + }; + ($rect:expr,2) => { + [$rect.x.end, $rect.y.start] + }; + ($rect:expr,3) => { + [$rect.x.start, $rect.y.start] + }; +} + +impl Rect +where + S: Scalar + Float, +{ + /// Construct a Rect from a given `Point` and `Dimensions`. + pub fn from_xy_wh([x, y]: [S; 2], [w, h]: [S; 2]) -> Self { + Rect { + x: Range::from_pos_and_len(x, w), + y: Range::from_pos_and_len(y, h), + } + } + + /// Construct a Rect from the given `x` `y` coordinates and `w` `h` dimensions. + pub fn from_x_y_w_h(x: S, y: S, w: S, h: S) -> Self { + Rect::from_xy_wh([x, y], [w, h]) + } + + /// Construct a Rect at origin with the given dimensions. + pub fn from_wh(wh: [S; 2]) -> Self { + let p = [S::zero(); 2]; + Self::from_xy_wh(p, wh) + } + + /// Construct a Rect at origin with the given width and height. + pub fn from_w_h(w: S, h: S) -> Self { + Self::from_wh([w, h]) + } + + /// The position in the middle of the x bounds. + pub fn x(&self) -> S { + self.x.middle() + } + + /// The position in the middle of the y bounds. + pub fn y(&self) -> S { + self.y.middle() + } + + /// The xy position in the middle of the bounds. + pub fn xy(&self) -> [S; 2] { + [self.x(), self.y()] + } + + /// The centered x and y coordinates as a tuple. + pub fn x_y(&self) -> (S, S) { + (self.x(), self.y()) + } + + /// Convert the Rect to a `Point` and `Dimensions`. + pub fn xy_wh(&self) -> ([S; 2], [S; 2]) { + (self.xy(), self.wh()) + } + + /// The Rect's centered coordinates and dimensions in a tuple. + pub fn x_y_w_h(&self) -> (S, S, S, S) { + let (xy, wh) = self.xy_wh(); + (xy[0], xy[1], wh[0], wh[1]) + } + + /// The middle of the left edge. + pub fn mid_left(&self) -> [S; 2] { + [self.left(), self.y()] + } + + /// The middle of the top edge. + pub fn mid_top(&self) -> [S; 2] { + [self.x(), self.top()] + } + + /// The middle of the right edge. + pub fn mid_right(&self) -> [S; 2] { + [self.right(), self.y()] + } + + /// The middle of the bottom edge. + pub fn mid_bottom(&self) -> [S; 2] { + [self.x(), self.bottom()] + } + + /// Align `self` to `other` along the *x* axis in accordance with the given `Align` variant. + pub fn align_x_of(self, align: Align, other: Self) -> Self { + Rect { + x: self.x.align_to(align, other.x), + y: self.y, + } + } + + /// Align `self` to `other` along the *y* axis in accordance with the given `Align` variant. + pub fn align_y_of(self, align: Align, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_to(align, other.y), + } + } + + /// Align the middle of `self` with the middle of the `other` **Rect** along the *x* axis. + pub fn align_middle_x_of(self, other: Self) -> Self { + Rect { + x: self.x.align_middle_of(other.x), + y: self.y, + } + } + + /// Align the middle of `self` with the middle of the `other` **Rect** along the *y* axis. + pub fn align_middle_y_of(self, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_middle_of(other.y), + } + } + + /// Place `self` in the middle of the top edge of the `other` **Rect**. + pub fn mid_top_of(self, other: Self) -> Self { + self.align_middle_x_of(other).align_top_of(other) + } + + /// Place `self` in the middle of the bottom edge of the `other` **Rect**. + pub fn mid_bottom_of(self, other: Self) -> Self { + self.align_middle_x_of(other).align_bottom_of(other) + } + + /// Place `self` in the middle of the left edge of the `other` **Rect**. + pub fn mid_left_of(self, other: Self) -> Self { + self.align_left_of(other).align_middle_y_of(other) + } + + /// Place `self` in the middle of the right edge of the `other` **Rect**. + pub fn mid_right_of(self, other: Self) -> Self { + self.align_right_of(other).align_middle_y_of(other) + } + + /// Place `self` directly in the middle of the `other` **Rect**. + pub fn middle_of(self, other: Self) -> Self { + self.align_middle_x_of(other).align_middle_y_of(other) + } + + /// The four ranges used for the `Rect`'s four subdivisions. + pub fn subdivision_ranges(&self) -> SubdivisionRanges { + let (x, y) = self.x_y(); + let x_a = Range::new(self.x.start, x); + let x_b = Range::new(x, self.x.end); + let y_a = Range::new(self.y.start, y); + let y_b = Range::new(y, self.y.end); + SubdivisionRanges { x_a, x_b, y_a, y_b } + } + + /// Divide the `Rect` in half along the *x* and *y* axes and return the four subdivisions. + /// + /// Subdivisions are yielded in the following order: + /// + /// 1. Bottom left + /// 2. Bottom right + /// 3. Top left + /// 4. Top right + pub fn subdivisions(&self) -> [Self; NUM_SUBDIVISIONS as usize] { + self.subdivision_ranges().rects() + } + + /// The same as `subdivisions` but each subdivision is yielded via the returned `Iterator`. + pub fn subdivisions_iter(&self) -> Subdivisions { + self.subdivision_ranges().rects_iter() + } +} + +impl Rect +where + S: Scalar, +{ + /// Construct a Rect from the coordinates of two points. + pub fn from_corners([ax, ay]: [S; 2], [bx, by]: [S; 2]) -> Self { + let (left, right) = if ax < bx { (ax, bx) } else { (bx, ax) }; + let (bottom, top) = if ay < by { (ay, by) } else { (by, ay) }; + Rect { + x: Range { + start: left, + end: right, + }, + y: Range { + start: bottom, + end: top, + }, + } + } + + /// Converts `self` to an absolute `Rect` so that the magnitude of each range is always + /// positive. + pub fn absolute(self) -> Self { + let x = self.x.absolute(); + let y = self.y.absolute(); + Rect { x, y } + } + + /// The Rect representing the area in which two Rects overlap. + pub fn overlap(self, other: Self) -> Option { + self.x + .overlap(other.x) + .and_then(|x| self.y.overlap(other.y).map(|y| Rect { x: x, y: y })) + } + + /// The Rect that encompass the two given sets of Rect. + pub fn max(self, other: Self) -> Self + where + S: Float, + { + Rect { + x: self.x.max(other.x), + y: self.y.max(other.y), + } + } + + /// The Rect's lowest y value. + pub fn bottom(&self) -> S { + self.y.absolute().start + } + + /// The Rect's highest y value. + pub fn top(&self) -> S { + self.y.absolute().end + } + + /// The Rect's lowest x value. + pub fn left(&self) -> S { + self.x.absolute().start + } + + /// The Rect's highest x value. + pub fn right(&self) -> S { + self.x.absolute().end + } + + /// The top left corner **Point**. + pub fn top_left(&self) -> [S; 2] { + [self.left(), self.top()] + } + + /// The bottom left corner **Point**. + pub fn bottom_left(&self) -> [S; 2] { + [self.left(), self.bottom()] + } + + /// The top right corner **Point**. + pub fn top_right(&self) -> [S; 2] { + [self.right(), self.top()] + } + + /// The bottom right corner **Point**. + pub fn bottom_right(&self) -> [S; 2] { + [self.right(), self.bottom()] + } + + /// The edges of the **Rect** in a tuple (left, right, bottom, top). + pub fn l_r_b_t(&self) -> (S, S, S, S) { + (self.left(), self.right(), self.bottom(), self.top()) + } + + /// Shift the Rect along the x axis. + pub fn shift_x(self, x: S) -> Self { + Rect { + x: self.x.shift(x), + ..self + } + } + + /// Shift the Rect along the y axis. + pub fn shift_y(self, y: S) -> Self { + Rect { + y: self.y.shift(y), + ..self + } + } + + /// Shift the Rect by the given vector. + pub fn shift(self, [x, y]: [S; 2]) -> Self { + self.shift_x(x).shift_y(y) + } + + /// Does the given point touch the Rectangle. + pub fn contains(&self, [x, y]: [S; 2]) -> bool { + self.x.contains(x) && self.y.contains(y) + } + + /// Stretches the closest edge(s) to the given point if the point lies outside of the Rect area. + pub fn stretch_to_point(self, [px, py]: [S; 2]) -> Self { + let Rect { x, y } = self; + Rect { + x: x.stretch_to_value(px), + y: y.stretch_to_value(py), + } + } + + /// Align `self`'s right edge with the left edge of the `other` **Rect**. + pub fn left_of(self, other: Self) -> Self { + Rect { + x: self.x.align_before(other.x), + y: self.y, + } + } + + /// Align `self`'s left edge with the right dge of the `other` **Rect**. + pub fn right_of(self, other: Self) -> Self { + Rect { + x: self.x.align_after(other.x), + y: self.y, + } + } + + /// Align `self`'s top edge with the bottom edge of the `other` **Rect**. + pub fn below(self, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_before(other.y), + } + } + + /// Align `self`'s bottom edge with the top edge of the `other` **Rect**. + pub fn above(self, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_after(other.y), + } + } + + /// Align `self`'s left edge with the left edge of the `other` **Rect**. + pub fn align_left_of(self, other: Self) -> Self { + Rect { + x: self.x.align_start_of(other.x), + y: self.y, + } + } + + /// Align `self`'s right edge with the right edge of the `other` **Rect**. + pub fn align_right_of(self, other: Self) -> Self { + Rect { + x: self.x.align_end_of(other.x), + y: self.y, + } + } + + /// Align `self`'s bottom edge with the bottom edge of the `other` **Rect**. + pub fn align_bottom_of(self, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_start_of(other.y), + } + } + + /// Align `self`'s top edge with the top edge of the `other` **Rect**. + pub fn align_top_of(self, other: Self) -> Self { + Rect { + x: self.x, + y: self.y.align_end_of(other.y), + } + } + + /// Place `self` along the top left edges of the `other` **Rect**. + pub fn top_left_of(self, other: Self) -> Self { + self.align_left_of(other).align_top_of(other) + } + + /// Place `self` along the top right edges of the `other` **Rect**. + pub fn top_right_of(self, other: Self) -> Self { + self.align_right_of(other).align_top_of(other) + } + + /// Place `self` along the bottom left edges of the `other` **Rect**. + pub fn bottom_left_of(self, other: Self) -> Self { + self.align_left_of(other).align_bottom_of(other) + } + + /// Place `self` along the bottom right edges of the `other` **Rect**. + pub fn bottom_right_of(self, other: Self) -> Self { + self.align_right_of(other).align_bottom_of(other) + } + + /// Return the **Corner** of `self` that is closest to the given **Point**. + pub fn closest_corner(&self, [x, y]: [S; 2]) -> Corner { + let x_edge = self.x.closest_edge(x); + let y_edge = self.y.closest_edge(y); + match (x_edge, y_edge) { + (Edge::Start, Edge::Start) => Corner::BottomLeft, + (Edge::Start, Edge::End) => Corner::TopLeft, + (Edge::End, Edge::Start) => Corner::BottomRight, + (Edge::End, Edge::End) => Corner::TopRight, + } + } + + /// The four corners of the `Rect`. + pub fn corners(&self) -> Quad<[S; 2]> { + Quad::from([ + corner_from_index!(self, 0), + corner_from_index!(self, 1), + corner_from_index!(self, 2), + corner_from_index!(self, 3), + ]) + } + + /// An iterator yielding the four corners of the `Rect`. + pub fn corners_iter(&self) -> Corners { + let rect = *self; + let index = 0; + Corners { rect, index } + } + + /// Return two `Tri`s that represent the `Rect`. + pub fn triangles(&self) -> (Tri<[S; 2]>, Tri<[S; 2]>) { + self.corners().triangles() + } + + /// An iterator yielding the `Rect`'s two `Tri`'s. + pub fn triangles_iter(self) -> Triangles { + self.corners().triangles_iter() + } + + /// Produce the corner at the given index. + pub fn corner_at_index(&self, index: u8) -> Option<[S; 2]> { + match index { + 0 => Some(corner_from_index!(self, 0)), + 1 => Some(corner_from_index!(self, 1)), + 2 => Some(corner_from_index!(self, 2)), + 3 => Some(corner_from_index!(self, 3)), + _ => None, + } + } +} + +impl SubdivisionRanges +where + S: Copy, +{ + /// The `Rect`s representing each of the four subdivisions. + /// + /// Subdivisions are yielded in the following order: + /// + /// 1. Bottom left + /// 2. Bottom right + /// 3. Top left + /// 4. Top right + pub fn rects(&self) -> [Rect; NUM_SUBDIVISIONS as usize] { + let r1 = subdivision_from_index!(self, 0); + let r2 = subdivision_from_index!(self, 1); + let r3 = subdivision_from_index!(self, 2); + let r4 = subdivision_from_index!(self, 3); + [r1, r2, r3, r4] + } + + /// The same as `rects` but each subdivision is yielded via the returned `Iterator`. + pub fn rects_iter(self) -> Subdivisions { + Subdivisions { + ranges: self, + subdivision_index: 0, + } + } + + // The subdivision at the given index within the range 0..NUM_SUBDIVISIONS. + fn subdivision_at_index(&self, index: u8) -> Option> { + let rect = match index { + 0 => subdivision_from_index!(self, 0), + 1 => subdivision_from_index!(self, 1), + 2 => subdivision_from_index!(self, 2), + 3 => subdivision_from_index!(self, 3), + _ => return None, + }; + Some(rect) + } +} + +impl Rect +where + S: Scalar + Neg, +{ + /// The width of the Rect. + pub fn w(&self) -> S { + self.x.len() + } + + /// The height of the Rect. + pub fn h(&self) -> S { + self.y.len() + } + + /// The total dimensions of the Rect. + pub fn wh(&self) -> [S; 2] { + [self.w(), self.h()].into() + } + + /// The width and height of the Rect as a tuple. + pub fn w_h(&self) -> (S, S) { + (self.w(), self.h()) + } + + /// The length of the longest side of the rectangle. + pub fn len(&self) -> S { + math::partial_max(self.w(), self.h()) + } + + /// The left and top edges of the **Rect** along with the width and height. + pub fn l_t_w_h(&self) -> (S, S, S, S) { + let (w, h) = self.w_h(); + (self.left(), self.top(), w, h) + } + + /// The left and bottom edges of the **Rect** along with the width and height. + pub fn l_b_w_h(&self) -> (S, S, S, S) { + let (w, h) = self.w_h(); + (self.left(), self.bottom(), w, h) + } + + /// The Rect with some padding applied to the left edge. + pub fn pad_left(self, pad: S) -> Self { + Rect { + x: self.x.pad_start(pad), + ..self + } + } + + /// The Rect with some padding applied to the right edge. + pub fn pad_right(self, pad: S) -> Self { + Rect { + x: self.x.pad_end(pad), + ..self + } + } + + /// The rect with some padding applied to the bottom edge. + pub fn pad_bottom(self, pad: S) -> Self { + Rect { + y: self.y.pad_start(pad), + ..self + } + } + + /// The Rect with some padding applied to the top edge. + pub fn pad_top(self, pad: S) -> Self { + Rect { + y: self.y.pad_end(pad), + ..self + } + } + + /// The Rect with some padding amount applied to each edge. + pub fn pad(self, pad: S) -> Self { + let Rect { x, y } = self; + Rect { + x: x.pad(pad), + y: y.pad(pad), + } + } + + /// The Rect with some padding applied. + pub fn padding(self, padding: Padding) -> Self { + Rect { + x: self.x.pad_ends(padding.x.start, padding.x.end), + y: self.y.pad_ends(padding.y.start, padding.y.end), + } + } + + /// Returns a `Rect` with a position relative to the given position on the *x* axis. + pub fn relative_to_x(self, x: S) -> Self { + Rect { + x: self.x.shift(-x), + ..self + } + } + + /// Returns a `Rect` with a position relative to the given position on the *y* axis. + pub fn relative_to_y(self, y: S) -> Self { + Rect { + y: self.y.shift(-y), + ..self + } + } + + /// Returns a `Rect` with a position relative to the given position. + pub fn relative_to(self, [x, y]: [S; 2]) -> Self { + self.relative_to_x(x).relative_to_y(y) + } + + /// Invert the x axis (aka flip *around* the y axis). + pub fn invert_x(self) -> Self { + Rect { + x: self.x.invert(), + ..self + } + } + + /// Invert the y axis (aka flip *around* the x axis). + pub fn invert_y(self) -> Self { + Rect { + y: self.y.invert(), + ..self + } + } +} + +impl Iterator for Subdivisions +where + S: Copy, +{ + type Item = Rect; + + fn next(&mut self) -> Option { + if let Some(sd) = self.ranges.subdivision_at_index(self.subdivision_index) { + self.subdivision_index += 1; + return Some(sd); + } + None + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl DoubleEndedIterator for Subdivisions +where + S: Copy, +{ + fn next_back(&mut self) -> Option { + let next_index = self.subdivision_index + 1; + if let Some(sd) = self + .ranges + .subdivision_at_index(NUM_SUBDIVISIONS - next_index) + { + self.subdivision_index = next_index; + return Some(sd); + } + None + } +} + +impl ExactSizeIterator for Subdivisions +where + S: Copy, +{ + fn len(&self) -> usize { + NUM_SUBDIVISIONS as usize - self.subdivision_index as usize + } +} + +impl Iterator for Corners +where + S: Scalar, +{ + type Item = [S; 2]; + fn next(&mut self) -> Option { + if let Some(corner) = self.rect.corner_at_index(self.index) { + self.index += 1; + return Some(corner); + } + None + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl DoubleEndedIterator for Corners +where + S: Scalar, +{ + fn next_back(&mut self) -> Option { + let next_index = self.index + 1; + if let Some(corner) = self.rect.corner_at_index(NUM_CORNERS - next_index) { + self.index = next_index; + return Some(corner); + } + None + } +} + +impl ExactSizeIterator for Corners +where + S: Scalar, +{ + fn len(&self) -> usize { + (NUM_CORNERS - self.index) as usize + } +} diff --git a/nannou_core/src/geom/scalar.rs b/nannou_core/src/geom/scalar.rs new file mode 100644 index 000000000..91bca186a --- /dev/null +++ b/nannou_core/src/geom/scalar.rs @@ -0,0 +1,38 @@ +use crate::math::num_traits::{Num, NumOps}; +use core::ops; + +/// Implemented for all numeric scalar types used within `geom`. +/// +/// A base set of traits that must be implemented by all types used to represent scalar values +/// within the `geom` module abstractions. +pub trait Scalar: + Clone + + Copy + + Num + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::MulAssign + + ops::DivAssign + + ops::RemAssign + + ops::Neg +{ +} + +impl Scalar for T where + T: Clone + + Copy + + Num + + NumOps + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::MulAssign + + ops::DivAssign + + ops::RemAssign + + ops::Neg +{ +} + +/// The default scalar type used for geometry throughout Nannou. +pub type Default = f32; diff --git a/nannou_core/src/geom/tri.rs b/nannou_core/src/geom/tri.rs new file mode 100644 index 000000000..04929bb88 --- /dev/null +++ b/nannou_core/src/geom/tri.rs @@ -0,0 +1,365 @@ +use crate::geom::{vertex, Cuboid, Range, Rect, Scalar, Vertex, Vertex2d, Vertex3d}; +use crate::math::num_traits::Zero; +use core::ops::Deref; + +/// The number of vertices in a triangle. +pub const NUM_VERTICES: u8 = 3; + +/// A triangle as three vertices. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub struct Tri(pub [V; NUM_VERTICES as usize]); + +/// An iterator yielding each of the vertices of the triangle. +#[derive(Clone, Debug)] +pub struct Vertices { + tri: Tri, + index: u8, +} + +/// An iterator yielding triangles whose vertices are produced by the given iterator yielding +/// vertices. +#[derive(Clone, Debug)] +pub struct IterFromVertices { + vertices: I, +} + +/// An iterator that flattens an iterator yielding triangles into its vertices. +#[derive(Clone, Debug)] +pub struct VerticesFromIter { + tris: I, + tri: Option>, +} + +/// Converts an iterator yielding `[usize; 3]` into an iterator yielding `usize`s. +#[derive(Clone, Debug)] +pub struct FlattenIndices { + indices: I, + b: Option, + c: Option, +} + +impl Tri { + /// Create a **Tri** by indexing into the given buffer. + /// + /// **Panics** if any of the given indices are out of range of the given `vertices` slice. + pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Self + where + V: Clone, + { + from_index_tri(vertices, indices) + } + + /// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator. + /// + /// Returns **None** if there were not at least 3 vertices in the given iterator. + pub fn from_vertices(vertices: I) -> Option + where + I: IntoIterator, + { + from_vertices(vertices) + } + + /// Produce an iterator yielding each of the vertices of the triangle. + pub fn vertices(self) -> Vertices { + let tri = self; + let index = 0; + Vertices { tri, index } + } + + /// Produce the centroid of the triangle aka the "mean"/"average" of all the points. + pub fn centroid(self) -> V + where + V: vertex::Average, + { + crate::geom::centroid(self[..].iter().cloned()).unwrap() + } + + /// Maps the underlying vertices to a new type and returns the resulting `Tri`. + pub fn map_vertices(self, mut map: F) -> Tri + where + F: FnMut(V) -> V2, + { + let Tri([a, b, c]) = self; + Tri([map(a), map(b), map(c)]) + } + + /// Returns `true` if the given 2D vertex is contained within the 2D `Tri`. + /// + /// # Example + /// + /// ``` + /// # use nannou_core as nannou; + /// # use nannou::prelude::*; + /// # use nannou::geom::Tri; + /// # fn main() { + /// let a = [-0.5, 0.0]; + /// let b = [0.0, 1.0]; + /// let c = [0.5, -0.75]; + /// let tri = Tri([a, b, c]); + /// assert!(tri.contains(&[0.0, 0.0])); + /// assert!(!tri.contains(&[3.0, 3.0])); + /// # } + /// ``` + pub fn contains(&self, v: &V) -> bool + where + V: Vertex2d, + { + let (a, b, c) = (*self).into(); + let (a, b, c) = (a.point2(), b.point2(), c.point2()); + let v = (*v).point2(); + + fn sign([ax, ay]: [S; 2], [bx, by]: [S; 2], [cx, cy]: [S; 2]) -> S + where + S: Scalar, + { + (ax - cx) * (by - cy) - (bx - cx) * (ay - cy) + } + + let b1 = sign(v, a, b) < V::Scalar::zero(); + let b2 = sign(v, b, c) < V::Scalar::zero(); + let b3 = sign(v, c, a) < V::Scalar::zero(); + + (b1 == b2) && (b2 == b3) + } + + /// The bounding `Rect` of the triangle. + pub fn bounding_rect(self) -> Rect + where + V: Vertex2d, + { + let (a, b, c) = self.into(); + let ([ax, ay], b, c) = (a.point2(), b.point2(), c.point2()); + let rect = Rect { + x: Range::new(ax, ax), + y: Range::new(ay, ay), + }; + rect.stretch_to_point(b).stretch_to_point(c) + } + + /// The bounding `Rect` of the triangle. + pub fn bounding_cuboid(self) -> Cuboid + where + V: Vertex3d, + { + let (a, b, c) = self.into(); + let ([ax, ay, az], b, c) = (a.point3(), b.point3(), c.point3()); + let cuboid = Cuboid { + x: Range::new(ax, ax), + y: Range::new(ay, ay), + z: Range::new(az, az), + }; + cuboid.stretch_to_point(b).stretch_to_point(c) + } +} + +/// Returns the first `Tri` that contains the given vertex. +/// +/// Returns `None` if no `Tri`'s contain the given vertex. +pub fn iter_contains(tris: I, v: &V) -> Option +where + I: IntoIterator, + I::Item: AsRef>, + V: Vertex2d, +{ + tris.into_iter().find(|tri| tri.as_ref().contains(v)) +} + +/// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator. +/// +/// Returns **None** if there were not at least 3 vertices in the given iterator. +pub fn from_vertices(vertices: I) -> Option> +where + I: IntoIterator, +{ + let mut vertices = vertices.into_iter(); + match (vertices.next(), vertices.next(), vertices.next()) { + (Some(a), Some(b), Some(c)) => Some(Tri([a, b, c])), + _ => None, + } +} + +/// Produce an iterator yielding a triangle for every three vertices yielded by the given +/// `vertices` iterator. +pub fn iter_from_vertices(vertices: I) -> IterFromVertices +where + I: IntoIterator, +{ + let vertices = vertices.into_iter(); + IterFromVertices { vertices } +} + +/// Create a **Tri** by indexing into the given buffer. +/// +/// **Panics** if any of the given indices are out of range of the given `vertices` slice. +pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Tri +where + V: Clone, +{ + let a = vertices[indices[0]].clone(); + let b = vertices[indices[1]].clone(); + let c = vertices[indices[2]].clone(); + Tri([a, b, c]) +} + +/// Produce an iterator that flattens the given iterator yielding triangles into its vertices. +pub fn vertices_from_iter(tris: I) -> VerticesFromIter +where + I: IntoIterator>, +{ + let tris = tris.into_iter(); + let tri = None; + VerticesFromIter { tris, tri } +} + +/// Given an iterator yielding trios of indices, produce an iterator that yields each index one at +/// a time. +pub fn flatten_index_tris(index_tris: I) -> FlattenIndices +where + I: IntoIterator, +{ + FlattenIndices { + indices: index_tris.into_iter(), + b: None, + c: None, + } +} + +impl Deref for Tri { + type Target = [V; 3]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<[V; 3]> for Tri { + fn from(points: [V; 3]) -> Self { + Tri(points) + } +} + +impl From<(V, V, V)> for Tri { + fn from((a, b, c): (V, V, V)) -> Self { + Tri([a, b, c]) + } +} + +impl Into<[V; 3]> for Tri { + fn into(self) -> [V; 3] { + self.0 + } +} + +impl Into<(V, V, V)> for Tri { + fn into(self) -> (V, V, V) { + let Tri([a, b, c]) = self; + (a, b, c) + } +} + +impl AsRef> for Tri { + fn as_ref(&self) -> &Tri { + self + } +} + +impl AsRef<[V; 3]> for Tri { + fn as_ref(&self) -> &[V; 3] { + &self.0 + } +} + +impl Iterator for Vertices +where + V: Clone, +{ + type Item = V; + fn next(&mut self) -> Option { + if self.index < NUM_VERTICES { + let v = self.tri.0[self.index as usize].clone(); + self.index += 1; + Some(v) + } else { + None + } + } +} + +impl ExactSizeIterator for Vertices +where + V: Clone, +{ + fn len(&self) -> usize { + NUM_VERTICES as usize - self.index as usize + } +} + +impl Iterator for IterFromVertices +where + I: Iterator, +{ + type Item = Tri; + fn next(&mut self) -> Option { + from_vertices(&mut self.vertices) + } +} + +impl Iterator for VerticesFromIter +where + I: Iterator>, + V: Vertex, +{ + type Item = V; + fn next(&mut self) -> Option { + loop { + if let Some(v) = self.tri.as_mut().and_then(|vs| vs.next()) { + return Some(v); + } + match self.tris.next() { + Some(t) => self.tri = Some(t.vertices()), + None => return None, + } + } + } +} + +impl ExactSizeIterator for VerticesFromIter +where + I: Iterator> + ExactSizeIterator, + V: Vertex, +{ + fn len(&self) -> usize { + let current_tri_vs = self.tri.as_ref().map(|vs| vs.len()).unwrap_or(0); + let remaining_tri_vs = self.tris.len() * NUM_VERTICES as usize; + current_tri_vs + remaining_tri_vs + } +} + +impl Iterator for FlattenIndices +where + I: Iterator, +{ + type Item = usize; + fn next(&mut self) -> Option { + if let Some(next) = self.b.take() { + return Some(next); + } + if let Some(next) = self.c.take() { + return Some(next); + } + if let Some([next, b, c]) = self.indices.next() { + self.b = Some(b); + self.c = Some(c); + return Some(next); + } + None + } +} + +impl ExactSizeIterator for FlattenIndices +where + I: Iterator + ExactSizeIterator, +{ + fn len(&self) -> usize { + self.indices.len() * 3 + self.b.map(|_| 1).unwrap_or(0) + self.c.map(|_| 1).unwrap_or(0) + } +} diff --git a/nannou_core/src/geom/vector.rs b/nannou_core/src/geom/vector.rs new file mode 100644 index 000000000..cf2848f1e --- /dev/null +++ b/nannou_core/src/geom/vector.rs @@ -0,0 +1,22 @@ +pub use glam::{vec2, vec3, vec4, Vec2, Vec3, Vec4}; + +/// A common alias for the `glam::Vec2` type. +#[deprecated( + since = "0.17.0", + note = "Use Vec2 now that we have switched to `glam`" +)] +pub type Vector2 = glam::Vec2; + +/// A common alias for the `glam::Vec3` type. +#[deprecated( + since = "0.17.0", + note = "Use Vec3 now that we have switched to `glam`" +)] +pub type Vector3 = glam::Vec3; + +/// A common alias for the `glam::Vec4` type. +#[deprecated( + since = "0.17.0", + note = "Use Vec4 now that we have switched to `glam`" +)] +pub type Vector4 = glam::Vec4; diff --git a/nannou_core/src/geom/vertex.rs b/nannou_core/src/geom/vertex.rs new file mode 100644 index 000000000..a433d7059 --- /dev/null +++ b/nannou_core/src/geom/vertex.rs @@ -0,0 +1,397 @@ +use crate::geom::{scalar::Scalar, Point3}; +use crate::math::num_traits::{cast, NumCast}; +use core::ops::{Add, Div}; + +/// Types used as vertices that can be used to describe geometric points in space. +pub trait Vertex: Clone + Copy + PartialEq { + /// The values used to describe the vertex position. + type Scalar: Scalar; +} + +/// Vertex types that have at least 2 dimensions. +pub trait Vertex2d: Vertex { + /// The x, y location of the vertex. + fn point2(self) -> [Self::Scalar; 2]; +} + +/// Vertex types that have at least 3 dimensions. +pub trait Vertex3d: Vertex2d { + /// The x, y, z location of the vertex. + fn point3(self) -> [Self::Scalar; 3]; +} + +/// Vertices whose average can be determined. +/// +/// Useful for determining the centroid of triangles, quads and arbitrary polygons. +pub trait Average: Vertex { + /// Produce the average of the given sequence of vertices. + /// + /// Returns `None` if the given iterator is empty. + fn average(vertices: I) -> Option + where + I: IntoIterator; +} + +/// If a type is not specified for a piece of geometry, this is the default type used. +pub type Default = Point3; + +/// An iterator yielding a vertex for each index yielded by the given indices iterator. +#[derive(Clone, Debug)] +pub struct IterFromIndices<'a, I, V: 'a = Default> { + indices: I, + vertices: &'a [V], +} + +/// Produce an iterator yielding a vertex for each index yielded by the given indices iterator. +pub fn iter_from_indices(indices: I, vertices: &[V]) -> IterFromIndices +where + I: IntoIterator, +{ + let indices = indices.into_iter(); + IterFromIndices { indices, vertices } +} + +// Iterators + +impl<'a, I, V> Iterator for IterFromIndices<'a, I, V> +where + I: Iterator, +{ + type Item = &'a V; + fn next(&mut self) -> Option { + let IterFromIndices { + ref mut indices, + ref vertices, + } = *self; + indices.next().map(|i| &vertices[i]) + } + + fn size_hint(&self) -> (usize, Option) { + self.indices.size_hint() + } +} + +impl<'a, I, V> DoubleEndedIterator for IterFromIndices<'a, I, V> +where + I: Iterator + DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + let IterFromIndices { + ref mut indices, + ref vertices, + } = *self; + indices.next_back().map(|i| &vertices[i]) + } +} + +impl<'a, I, V> ExactSizeIterator for IterFromIndices<'a, I, V> +where + I: Iterator + ExactSizeIterator, +{ + fn len(&self) -> usize { + self.indices.len() + } +} + +// // Srgba impls. +// +// impl Srgba { +// /// A reference to the inner vertex. +// pub fn vertex(&self) -> &V { +// &self.0 +// } +// /// A reference to the inner rgba. +// pub fn rgba(&self) -> &color::Srgba { +// &self.1 +// } +// } +// +// impl Deref for Srgba { +// type Target = V; +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } +// +// impl DerefMut for Srgba { +// fn deref_mut(&mut self) -> &mut Self::Target { +// &mut self.0 +// } +// } +// +// impl From<(V, color::Srgba)> for Srgba { +// fn from((v, rgba): (V, color::Srgba)) -> Self { +// Srgba(v, rgba) +// } +// } +// +// impl Into<(V, color::Srgba)> for Srgba { +// fn into(self) -> (V, color::Srgba) { +// let Srgba(v, rgba) = self; +// (v, rgba) +// } +// } + +// Vertex impls + +impl Vertex for glam::Vec2 { + type Scalar = f32; +} + +impl Vertex for glam::Vec3 { + type Scalar = f32; +} + +impl Vertex for glam::DVec2 { + type Scalar = f64; +} + +impl Vertex for glam::DVec3 { + type Scalar = f64; +} + +impl Vertex for glam::IVec2 { + type Scalar = i32; +} + +impl Vertex for glam::IVec3 { + type Scalar = i32; +} + +impl Vertex for [S; 2] +where + S: Scalar, +{ + type Scalar = S; +} + +impl Vertex for [S; 3] +where + S: Scalar, +{ + type Scalar = S; +} + +impl Vertex for (S, S) +where + S: Scalar, +{ + type Scalar = S; +} + +impl Vertex for (S, S, S) +where + S: Scalar, +{ + type Scalar = S; +} + +// Vertex2d impls + +impl Vertex2d for glam::Vec2 { + fn point2(self) -> [Self::Scalar; 2] { + self.to_array() + } +} + +impl Vertex2d for glam::Vec3 { + fn point2(self) -> [Self::Scalar; 2] { + self.truncate().to_array() + } +} + +impl Vertex2d for glam::DVec2 { + fn point2(self) -> [Self::Scalar; 2] { + self.to_array() + } +} + +impl Vertex2d for glam::DVec3 { + fn point2(self) -> [Self::Scalar; 2] { + self.truncate().to_array() + } +} + +impl Vertex2d for glam::IVec2 { + fn point2(self) -> [Self::Scalar; 2] { + self.to_array() + } +} + +impl Vertex2d for glam::IVec3 { + fn point2(self) -> [Self::Scalar; 2] { + self.truncate().to_array() + } +} + +impl Vertex2d for [S; 2] +where + S: Scalar, +{ + fn point2(self) -> [Self::Scalar; 2] { + self + } +} + +impl Vertex2d for [S; 3] +where + S: Scalar, +{ + fn point2(self) -> [Self::Scalar; 2] { + let [x, y, _] = self; + [x, y] + } +} + +impl Vertex2d for (S, S) +where + S: Scalar, +{ + fn point2(self) -> [Self::Scalar; 2] { + let (x, y) = self; + [x, y] + } +} + +impl Vertex2d for (S, S, S) +where + S: Scalar, +{ + fn point2(self) -> [Self::Scalar; 2] { + let (x, y, _) = self; + [x, y] + } +} + +// Vertex3d impls + +impl Vertex3d for glam::Vec3 { + fn point3(self) -> [Self::Scalar; 3] { + self.to_array() + } +} + +impl Vertex3d for glam::DVec3 { + fn point3(self) -> [Self::Scalar; 3] { + self.to_array() + } +} + +impl Vertex3d for glam::IVec3 { + fn point3(self) -> [Self::Scalar; 3] { + self.to_array() + } +} + +impl Vertex3d for [S; 3] +where + S: Scalar, +{ + fn point3(self) -> [Self::Scalar; 3] { + self + } +} + +impl Vertex3d for (S, S, S) +where + S: Scalar, +{ + fn point3(self) -> [Self::Scalar; 3] { + let (x, y, z) = self; + [x, y, z] + } +} + +// Average impls + +fn avg_glam_vecs(vertices: I) -> Option +where + I: IntoIterator, + I::Item: Add + + Div<::Scalar, Output = I::Item> + + Vertex, + ::Scalar: NumCast, +{ + let mut vertices = vertices.into_iter(); + vertices.next().map(|first| { + let init = (1, first); + let (len, total) = vertices.fold(init, |(i, acc), p| (i + 1, acc + p)); + let divisor: ::Scalar = cast(len).unwrap(); + total / divisor + }) +} + +impl Average for glam::Vec2 { + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + avg_glam_vecs(vertices) + } +} + +impl Average for glam::Vec3 { + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + avg_glam_vecs(vertices) + } +} + +impl Average for glam::DVec2 { + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + avg_glam_vecs(vertices) + } +} + +impl Average for glam::DVec3 { + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + avg_glam_vecs(vertices) + } +} + +impl Average for [S; 2] +where + S: Scalar + NumCast, +{ + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + let mut vertices = vertices.into_iter(); + vertices.next().map(|first| { + let init = (1, first); + let (len, [x, y]) = + vertices.fold(init, |(i, [ax, ay]), [bx, by]| (i + 1, [ax + bx, ay + by])); + let divisor: S = cast(len).unwrap(); + [x / divisor, y / divisor] + }) + } +} + +impl Average for [S; 3] +where + S: Scalar + NumCast, +{ + fn average(vertices: I) -> Option + where + I: IntoIterator, + { + let mut vertices = vertices.into_iter(); + vertices.next().map(|first| { + let init = (1, first); + let (len, [x, y, z]) = vertices.fold(init, |(i, [ax, ay, az]), [bx, by, bz]| { + (i + 1, [ax + bx, ay + by, az + bz]) + }); + let divisor: S = cast(len).unwrap(); + [x / divisor, y / divisor, z / divisor] + }) + } +} diff --git a/nannou_core/src/lib.rs b/nannou_core/src/lib.rs new file mode 100644 index 000000000..b70ecce48 --- /dev/null +++ b/nannou_core/src/lib.rs @@ -0,0 +1,39 @@ +//! nannou's core abstractions. +//! +//! This crate aims to be a stripped-down foundation for nannou projects that don't require +//! windowing or wgpu graphics. These might include: +//! +//! - Headless applications, e.g. for LASER or lighting control. +//! - Embedded applications, e.g. driving motors or LEDs in an art installation. +//! - `rust-gpu` shaders which have strict requirements beyond the limitations of `no_std`. +//! - Hot-loaded dynamic libraries that benefit from faster compilation times. +//! +//! The crate includes nannou's color, math, geometry and noise abstractions without the deep stack +//! of crates required to establish an event loop, interoperate with wgpu, etc. Another way of +//! describing this crate might be "nannou without the I/O". +//! +//! ## Crate `[features]` +//! +//! The primary feature of this crate is support for `#![no_std]`. This means we can use the crate +//! for embedded applications and in some cases rust-gpu shaders. +//! +//! By default, the `std` feature is enabled. For compatibility with a `#![no_std]` environment be +//! sure to disable default features (i.e. `default-features = false`) and enable the `libm` +//! feature. The `libm` feature provides some core functionality required by crates +//! +//! - `std`: Enabled by default, enables the Rust std library. One of the primary features of this +//! crate is support for `#![no_std]`. This means we can use the crate for embedded applications +//! and in some cases rust-gpu shaders. For compatibility with a `#![no_std]` environment be sure +//! to disable default features (i.e. `default-features = false`) and enable the `libm` feature. +//! - `libm`: provides some core math support in the case that `std` is not enabled. This feature +//! must be enabled if `std` is disabled. +//! - `serde`: enables the associated serde serialization/deserialization features in `glam`, +//! `palette` and `rand`. + +#![no_std] + +pub mod color; +pub mod geom; +pub mod math; +pub mod prelude; +pub mod rand; diff --git a/nannou_core/src/math.rs b/nannou_core/src/math.rs new file mode 100644 index 000000000..ba5df1ee8 --- /dev/null +++ b/nannou_core/src/math.rs @@ -0,0 +1,193 @@ +//! A mathematical foundation for nannou including point and vector types and a range of +//! helper/utility functions. + +pub use num_traits; + +use core::ops::Add; +use num_traits::{Float, NumCast, One}; + +const ONE_TURN_DEGREES_F32: f32 = 360.0; +const ONE_TURN_DEGREES_F64: f64 = 360.0; + +/// Functions for converting between angle representations. +/// +/// Only implemented for `f32` and `f64`. +pub trait ConvertAngle { + fn deg_to_rad(self) -> Self; + fn rad_to_deg(self) -> Self; + fn turns_to_rad(self) -> Self; + fn rad_to_turns(self) -> Self; +} + +impl ConvertAngle for f32 { + fn deg_to_rad(self) -> Self { + self * core::f32::consts::TAU / ONE_TURN_DEGREES_F32 + } + fn rad_to_deg(self) -> Self { + self * ONE_TURN_DEGREES_F32 / core::f32::consts::TAU + } + fn turns_to_rad(self) -> Self { + self * core::f32::consts::TAU + } + fn rad_to_turns(self) -> Self { + self / core::f32::consts::TAU + } +} + +impl ConvertAngle for f64 { + fn deg_to_rad(self) -> Self { + self * core::f64::consts::TAU / ONE_TURN_DEGREES_F64 + } + fn rad_to_deg(self) -> Self { + self * ONE_TURN_DEGREES_F64 / core::f64::consts::TAU + } + fn turns_to_rad(self) -> Self { + self * core::f64::consts::TAU + } + fn rad_to_turns(self) -> Self { + self / core::f64::consts::TAU + } +} + +/// Maps a value from an input range to an output range. +/// +/// Note that `map_range` doesn't clamp the output: if `val` is outside the input range, the mapped +/// value will be outside the output range. (Use `clamp` to restrict the output, if desired.) +/// +/// # Examples +/// ``` +/// # use nannou_core::prelude::*; +/// assert_eq!(map_range(128, 0, 255, 0.0, 1.0), 0.5019607843137255); +/// ``` +/// ``` +/// # use nannou_core::prelude::*; +/// assert_eq!(map_range(3, 0, 10, 0.0, 1.0), 0.3); +/// ``` +/// ``` +/// # use nannou_core::prelude::*; +/// // When the value is outside the input range, the result will be outside the output range. +/// let result = map_range(15, 0, 10, 0.0, 1.0); +/// assert_eq!(result, 1.5); +/// assert_eq!(clamp(result, 0.0, 1.0), 1.0); +/// ``` +// TODO: Should consider refactoring this to only allow for conversions between types that cannot +// fail. This would break some code but make users think about issues like converting to signed +// ranges with unsigned types, etc. Would also reduce size of code generated due to all the panic +// branches. +pub fn map_range(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y +where + X: NumCast, + Y: NumCast, +{ + macro_rules! unwrap_or_panic { + ($result:expr, $arg:expr) => { + $result.unwrap_or_else(|| panic!("[map_range] failed to cast {} arg to `f64`", $arg)) + }; + } + + let val_f: f64 = unwrap_or_panic!(NumCast::from(val), "first"); + let in_min_f: f64 = unwrap_or_panic!(NumCast::from(in_min), "second"); + let in_max_f: f64 = unwrap_or_panic!(NumCast::from(in_max), "third"); + let out_min_f: f64 = unwrap_or_panic!(NumCast::from(out_min), "fourth"); + let out_max_f: f64 = unwrap_or_panic!(NumCast::from(out_max), "fifth"); + + NumCast::from((val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f) + .unwrap_or_else(|| panic!("[map_range] failed to cast result to target type")) +} + +/// The max between two partially ordered values. +pub fn partial_max(a: T, b: T) -> T +where + T: PartialOrd, +{ + if a >= b { + a + } else { + b + } +} + +/// The min between two partially ordered values. +pub fn partial_min(a: T, b: T) -> T +where + T: PartialOrd, +{ + if a <= b { + a + } else { + b + } +} + +/// Clamp a value between some range. +pub fn clamp(n: T, start: T, end: T) -> T +where + T: PartialOrd, +{ + if start <= end { + if n < start { + start + } else if n > end { + end + } else { + n + } + } else { + if n < end { + end + } else if n > start { + start + } else { + n + } + } +} + +pub fn two() -> S +where + S: Add + One, +{ + S::one() + S::one() +} + +/// Models the C++ fmod function. +#[inline] +pub fn fmod(numer: F, denom: F) -> F +where + F: Float, +{ + let rquot: F = (numer / denom).floor(); + numer - rquot * denom +} + +/// Convert the given angle in degrees to the same angle in radians. +pub fn deg_to_rad(s: S) -> S +where + S: ConvertAngle, +{ + s.deg_to_rad() +} + +/// Convert the given angle in radians to the same angle in degrees. +pub fn rad_to_deg(s: S) -> S +where + S: ConvertAngle, +{ + s.rad_to_deg() +} + +/// Convert the given value as a number of "turns" into the equivalent angle in radians. +pub fn turns_to_rad(s: S) -> S +where + S: ConvertAngle, +{ + s.turns_to_rad() +} + +/// Convert the given value in radians to the equivalent value as a number of turns. +pub fn rad_to_turns(s: S) -> S +where + S: ConvertAngle, +{ + s.rad_to_turns() +} diff --git a/nannou_core/src/prelude.rs b/nannou_core/src/prelude.rs new file mode 100644 index 000000000..f997c1c55 --- /dev/null +++ b/nannou_core/src/prelude.rs @@ -0,0 +1,27 @@ +//! A collection of commonly used items that are generally useful to have in scope. + +pub use crate::color::named::*; +pub use crate::color::{ + gray, hsl, hsla, hsv, hsva, lin_srgb, lin_srgba, rgb, rgb8, rgba, rgba8, srgb, srgb8, srgba, + srgba8, +}; +pub use crate::color::{ + Gray, Hsl, Hsla, Hsv, Hsva, LinSrgb, LinSrgba, Rgb, Rgb8, Rgba, Rgba8, Srgb, Srgba, +}; +pub use crate::geom::{ + self, pt2, pt3, vec2, vec3, vec4, Cuboid, Point2, Point3, Rect, Vec2, Vec3, Vec4, +}; +#[allow(deprecated)] +pub use crate::geom::{Vector2, Vector3, Vector4}; +pub use crate::math::num_traits::*; +pub use crate::math::{ + clamp, deg_to_rad, fmod, map_range, partial_max, partial_min, rad_to_deg, rad_to_turns, + turns_to_rad, +}; + +// NOTE: These helper functions rely on a thread-local RNG and are currently only available via std. +#[cfg(feature = "std")] +pub use crate::rand::{random, random_ascii, random_f32, random_f64, random_range}; + +pub use core::f32::consts::{PI, TAU}; +pub use core::f64::consts::{PI as PI_F64, TAU as TAU_F64}; diff --git a/nannou_core/src/rand.rs b/nannou_core/src/rand.rs new file mode 100644 index 000000000..2c4f42d22 --- /dev/null +++ b/nannou_core/src/rand.rs @@ -0,0 +1,73 @@ +//! Items related to randomness and random number generators. Also provides some high-level helper +//! functions. +//! +//! Helper functions include [**random_f32()**](./fn.random_f32.html), +//! [**random_f64()**](./fn.random_f64.html) and [**random_range(min, +//! max)**](./fn.random_range.html). + +pub use self::rand::*; +pub use rand; + +/// A wrapper function around the `random` function that avoids the need for specifying a type in +/// the case that it cannot be inferred. The primary purpose for this is to simplify the random API +/// for new rust users. +/// +/// NOTE: This helper function relies on a thread-local RNG and is currently only available with +/// the "std" feature enabled. +#[cfg(feature = "std")] +pub fn random_f32() -> f32 { + random() +} + +/// A wrapper function around the `random` function that avoids the need for specifying a type in +/// the case that it cannot be inferred. The primary purpose for this is to simplify the random API +/// for new rust users. +/// +/// NOTE: This helper function relies on a thread-local RNG and is currently only available with +/// the "std" feature enabled. +#[cfg(feature = "std")] +pub fn random_f64() -> f64 { + random() +} + +/// A function for generating a random value within the given range. +/// +/// The generated value may be within the range [min, max). That is, the result is inclusive of +/// `min`, but will never be `max`. +/// +/// If the given `min` is greater than the given `max`, they will be swapped before calling +/// `gen_range` internally to avoid triggering a `panic!`. +/// +/// This calls `rand::thread_rng().gen_range(min, max)` internally, in turn using the thread-local +/// default random number generator. +/// +/// NOTE: This helper function relies on a thread-local RNG and is currently only available with +/// the "std" feature enabled. +#[cfg(feature = "std")] +pub fn random_range(min: T, max: T) -> T +where + T: PartialOrd + distributions::uniform::SampleUniform, +{ + let (min, max) = if min <= max { (min, max) } else { (max, min) }; + rand::thread_rng().gen_range(min, max) +} + +/// Generates and returns a random ascii character. +/// +/// The ascii characters that can be generated are: +/// +/// ABCDEFGHIJKLMNOPQRSTUVWXYZ\ +/// abcdefghijklmnopqrstuvwxyz\ +/// 0123456789)(*&^%$#@!~. +/// +/// NOTE: This helper function relies on a thread-local RNG and is currently only available with +/// the "std" feature enabled. +#[cfg(feature = "std")] +pub fn random_ascii() -> char { + const ASCIISET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789)(*&^%$#@!~. "; + + let idx = rand::thread_rng().gen_range(0, ASCIISET.len()); + ASCIISET[idx] as char +} From e8a5e50f3c750571dd8d4f9060e3d790332773bb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 18 Jun 2021 15:52:09 +0200 Subject: [PATCH 02/10] Integrate `nannou_core` into main `nannou` crate This removes the color, math, rand and geom modules in favour of depending on the `nannou_core` crate. The `nannou_core` modules are re-exported within `nannou` in order to provide a near identical API to the existing one. The majority of changes here revolve around the change from `cgmath` to `glam`. The most notable changes include: - `geom::Vector2` -> `glam::Vec2` - `cgmath::Matrix4` -> `glam::Mat4` - `magnitude` -> `length` This change also removes the generic `Scalar` type parameter from the `Draw` API and related items in the hope of improving downstream compile times. Also removes the seemingly unused `geom::graph` module. Use-cases for this module and its abstractions were mostly made reduntatnt upon allowing for transformations to be applied to the `Draw` instance itself. --- nannou/Cargo.toml | 4 +- nannou/src/app.rs | 12 +- nannou/src/color/conv.rs | 143 -- nannou/src/color/mod.rs | 167 -- nannou/src/draw/background.rs | 24 +- nannou/src/draw/drawing.rs | 213 +-- nannou/src/draw/mesh/builder.rs | 44 +- nannou/src/draw/mesh/mod.rs | 78 +- nannou/src/draw/mesh/vertex.rs | 97 +- nannou/src/draw/mod.rs | 235 ++- nannou/src/draw/primitive/arrow.rs | 86 +- nannou/src/draw/primitive/ellipse.rs | 86 +- nannou/src/draw/primitive/line.rs | 75 +- nannou/src/draw/primitive/mesh.rs | 182 +- nannou/src/draw/primitive/mod.rs | 34 +- nannou/src/draw/primitive/path.rs | 294 ++- nannou/src/draw/primitive/polygon.rs | 181 +- nannou/src/draw/primitive/quad.rs | 87 +- nannou/src/draw/primitive/rect.rs | 65 +- nannou/src/draw/primitive/text.rs | 64 +- nannou/src/draw/primitive/texture.rs | 55 +- nannou/src/draw/primitive/tri.rs | 91 +- .../src/draw/properties/spatial/dimension.rs | 54 +- nannou/src/draw/properties/spatial/mod.rs | 32 +- .../draw/properties/spatial/orientation.rs | 176 +- .../src/draw/properties/spatial/position.rs | 50 +- nannou/src/draw/renderer/mod.rs | 32 +- nannou/src/event.rs | 27 +- nannou/src/geom/cuboid.rs | 904 --------- nannou/src/geom/ellipse.rs | 386 ---- nannou/src/geom/graph/edge.rs | 251 --- nannou/src/geom/graph/mod.rs | 829 --------- nannou/src/geom/graph/node.rs | 465 ----- nannou/src/geom/mod.rs | 95 +- nannou/src/geom/path.rs | 26 +- nannou/src/geom/point.rs | 33 - nannou/src/geom/polygon.rs | 152 -- nannou/src/geom/quad.rs | 363 ---- nannou/src/geom/range.rs | 754 -------- nannou/src/geom/rect.rs | 814 --------- nannou/src/geom/scalar.rs | 2 - nannou/src/geom/tri.rs | 364 ---- nannou/src/geom/vector.rs | 1614 ----------------- nannou/src/geom/vertex.rs | 344 ---- nannou/src/lib.rs | 10 +- nannou/src/math.rs | 158 -- nannou/src/mesh/vertex.rs | 65 +- nannou/src/prelude.rs | 30 +- nannou/src/rand.rs | 58 - nannou/src/state.rs | 82 +- nannou/src/text/mod.rs | 21 +- nannou/src/window.rs | 7 +- nannou/tests/geom_tests.rs | 12 +- nannou_core/Cargo.toml | 4 +- nannou_core/src/color/mod.rs | 4 +- nannou_core/src/lib.rs | 3 + nannou_core/src/math.rs | 18 +- nannou_core/src/prelude.rs | 2 +- 58 files changed, 1057 insertions(+), 9501 deletions(-) delete mode 100644 nannou/src/color/conv.rs delete mode 100644 nannou/src/color/mod.rs delete mode 100644 nannou/src/geom/cuboid.rs delete mode 100644 nannou/src/geom/ellipse.rs delete mode 100644 nannou/src/geom/graph/edge.rs delete mode 100644 nannou/src/geom/graph/mod.rs delete mode 100644 nannou/src/geom/graph/node.rs delete mode 100644 nannou/src/geom/point.rs delete mode 100644 nannou/src/geom/polygon.rs delete mode 100644 nannou/src/geom/quad.rs delete mode 100644 nannou/src/geom/range.rs delete mode 100644 nannou/src/geom/rect.rs delete mode 100644 nannou/src/geom/scalar.rs delete mode 100644 nannou/src/geom/tri.rs delete mode 100644 nannou/src/geom/vector.rs delete mode 100644 nannou/src/geom/vertex.rs delete mode 100644 nannou/src/math.rs delete mode 100644 nannou/src/rand.rs diff --git a/nannou/Cargo.toml b/nannou/Cargo.toml index 005dd775c..68cad0d3d 100644 --- a/nannou/Cargo.toml +++ b/nannou/Cargo.toml @@ -14,7 +14,6 @@ edition = "2018" default = ["notosans"] [dependencies] -cgmath = { version = "0.17", features = ["serde"] } conrod_core = "0.73" conrod_wgpu = "0.73" conrod_winit = "0.72" @@ -24,12 +23,11 @@ futures = { version = "0.3", features = ["executor", "thread-pool"] } image = "0.23" instant = "0.1.9" lyon = "0.15" +nannou_core = { version = "0.16.0", path = "../nannou_core", features = ["std", "serde"] } noise = "0.6" notosans = { version = "0.1", optional = true } num_cpus = "1" -palette = { version = "0.5", features = ["serializing"] } pennereq = "0.3" -rand = { version = "0.7", features = ["small_rng"] } rusttype = "0.8" serde = "1" serde_derive = "1" diff --git a/nannou/src/app.rs b/nannou/src/app.rs index fa1e2be3c..2b71cbff8 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -154,7 +154,7 @@ pub struct App { /// running installations. This is because the "resolution" of floating point values reduces as /// the number becomes higher. Instead, we recommend using `app.duration.since_start` or /// `app.duration.since_prev_update` to access a more precise form of app time. - pub time: DrawScalar, + pub time: f32, } /// Miscellaneous app configuration parameters. @@ -168,16 +168,10 @@ struct Config { // Draw state managed by the **App**. #[derive(Debug)] struct DrawState { - draw: RefCell>, + draw: RefCell, renderers: RefCell>>, } -/// The app uses a set scalar type in order to provide a simplistic API to users. -/// -/// If you require changing the scalar type to something else, consider using a custom -/// **nannou::draw::Draw** instance. -pub type DrawScalar = geom::scalar::Default; - /// A handle to the **App** that can be shared across threads. This may be used to "wake up" the /// **App**'s inner event loop. #[derive(Clone)] @@ -776,7 +770,7 @@ impl App { /// The **Rect** coords are described in "points" (pixels divided by the hidpi factor). /// /// **Panics** if there are no windows or if no window is in focus. - pub fn window_rect(&self) -> geom::Rect { + pub fn window_rect(&self) -> geom::Rect { self.main_window().rect() } diff --git a/nannou/src/color/conv.rs b/nannou/src/color/conv.rs deleted file mode 100644 index f9413f468..000000000 --- a/nannou/src/color/conv.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! This module provides some more flexible conversions and aims to fill the gaps within the `From` -//! and `Into` implementations provided by the `palette` library. -//! -//! If a desired conversion is missing, feel free to open an issue or pull request! - -use crate::color::white_point::D65; -use crate::color::{self, encoding, Alpha, Component, IntoColor, LinSrgba}; -use crate::math::num_traits::Float; - -/// Types that may be converted directly into a linear sRGBA color representation. -/// -/// This is more flexible than `Into>` as it also supports converting from different -/// sRGBA encodings that also have different component types. -/// -/// This trait is important for nannou as the `Draw` API works with the `LinSrgba` type as a target -/// for its generic colour type API. -pub trait IntoLinSrgba -where - S: Component, -{ - /// Convert self into RGBA. - fn into_lin_srgba(self) -> LinSrgba; -} - -impl IntoLinSrgba for color::Xyz -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::Yxy -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::Lab -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::Lch -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::LinSrgb -where - T: Component, - S: Component, -{ - fn into_lin_srgba(self) -> LinSrgba { - let color = self.into_format(); - let alpha = S::max_intensity(); - Alpha { color, alpha } - } -} - -impl IntoLinSrgba for color::Srgb -where - T: Component, - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - let color = self.into_format().into_linear(); - let alpha = S::max_intensity(); - Alpha { color, alpha } - } -} - -impl IntoLinSrgba for color::Hsl -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::Hsv -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::Hwb -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for color::SrgbLuma -where - S: Component + Float, -{ - fn into_lin_srgba(self) -> LinSrgba { - into_lin_srgb_with_alpha(self) - } -} - -impl IntoLinSrgba for Alpha -where - C: IntoLinSrgba, - S: Component, - T: Component, -{ - fn into_lin_srgba(self) -> LinSrgba { - let Alpha { color, alpha } = self; - let mut srgba = color.into_lin_srgba(); - srgba.alpha = alpha.convert(); - srgba - } -} - -fn into_lin_srgb_with_alpha(color: C) -> LinSrgba -where - C: IntoColor, - S: Component + Float, -{ - let color: color::LinSrgb = color.into_rgb::(); - let alpha = S::max_intensity(); - Alpha { color, alpha } -} diff --git a/nannou/src/color/mod.rs b/nannou/src/color/mod.rs deleted file mode 100644 index 5aa67c50a..000000000 --- a/nannou/src/color/mod.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the -//! [palette crate](https://docs.rs/palette). -//! -//! See the [**named**](./named/index.html) module for a set of provided color constants. - -pub mod conv; - -pub use self::conv::IntoLinSrgba; -pub use self::named::*; -#[doc(inline)] -pub use palette::*; - -/// The default scalar value for working with color components, hues, etc. -pub type DefaultScalar = f32; - -/// A color represented as red, green and blue intensities. -/// -/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space. -/// -/// If you are looking for more advanced control over the RGB space and component type, please see -/// the `palette` crate's generic `Rgb` type. -pub type Rgb = Srgb; - -/// The same as `Rgb`, but with `u8`'s. -pub type Rgb8 = Rgb; - -/// The same as `Rgb`, but with an alpha value representing opacity. -/// -/// This type is an alias for the `Srgba` type, a type that represents the sRGB color space -/// alongside an alpha value. -/// -/// If you are looking for more advanced control over the RGB space and component type, please see -/// the `palette` crate's generic `Rgb` type. -pub type Rgba = Srgba; - -/// The same as `Rgba`, but with `u8`'s. -pub type Rgba8 = Rgba; - -/// A color represented as gray intensity. -/// -/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space. -/// -/// If you are looking for more advanced control over the RGB space and component type, please see -/// the `palette` crate's generic `Rgb` type. -pub type Gray = Srgb; - -/// A short-hand constructor for `Rgb::new`. -pub fn rgb(r: T, g: T, b: T) -> Rgb -where - T: Component, -{ - srgb(r, g, b) -} - -/// A short-hand constructor for `Rgb::::new` . -pub fn rgb8(r: u8, g: u8, b: u8) -> Rgb8 { - srgb(r, g, b) -} - -/// A short-hand constructor for `Rgba::new`. -pub fn rgba(r: T, g: T, b: T, a: T) -> Rgba -where - T: Component, -{ - srgba(r, g, b, a) -} - -/// A short-hand constructor for `Rgba::new`. -pub fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Rgba8 { - srgba8(r, g, b, a) -} - -/// A short-hand constructor for `Srgb::new`. -pub fn srgb(r: T, g: T, b: T) -> Srgb -where - T: Component, -{ - Srgb::new(r, g, b) -} - -/// A short-hand constructor for `Srgb::new`. -pub fn srgb8(r: u8, g: u8, b: u8) -> Srgb { - Srgb::new(r, g, b) -} - -/// A short-hand constructor for `Srgba::new`. -pub fn srgba(r: T, g: T, b: T, a: T) -> Srgba -where - T: Component, -{ - Srgba::new(r, g, b, a) -} - -/// A short-hand constructor for `Srgba::new`. -pub fn srgba8(r: u8, g: u8, b: u8, a: u8) -> Srgba { - Srgba::new(r, g, b, a) -} - -/// A short-hand constructor for `LinSrgb::new`. -pub fn lin_srgb(r: T, g: T, b: T) -> LinSrgb -where - T: Component, -{ - LinSrgb::new(r, g, b) -} - -/// A short-hand constructor for `LinSrgba::new`. -pub fn lin_srgba(r: T, g: T, b: T, a: T) -> LinSrgba -where - T: Component, -{ - LinSrgba::new(r, g, b, a) -} - -/// Create a new color from a hexadecimal int literal -#[inline] -pub fn rgb_u32(c: u32) -> Rgb { - let blue: u8 = (c & 0xFF) as u8; - let green: u8 = ((c >> 8) & 0xFF) as u8; - let red: u8 = ((c >> 16) & 0xFF) as u8; - rgb8(red, green, blue) -} - -/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`. -/// -/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is -/// 360 degrees (or 2 PI radians). -pub fn hsl(h: f32, s: f32, l: f32) -> Hsl { - Hsl::new(RgbHue::from_degrees(h * 360.0), s, l) -} - -/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`. -/// -/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is -/// 360 degrees (or 2 PI radians). -pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla { - Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a) -} - -/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`. -/// -/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is -/// 360 degrees (or 2 PI radians). -pub fn hsv(h: f32, s: f32, v: f32) -> Hsv { - Hsv::new(RgbHue::from_degrees(h * 360.0), s, v) -} - -/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`. -/// -/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is -/// 360 degrees (or 2 PI radians). -pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva { - Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a) -} - -/// A short-hand constructor for `Gray::new`. -pub fn gray(g: T) -> Gray -where - T: Component, -{ - srgb(g, g, g) -} - -#[test] -fn test_rgb_u32() { - assert_eq!(rgb_u32(0xFF8000), rgb8(255, 128, 0)); -} diff --git a/nannou/src/draw/background.rs b/nannou/src/draw/background.rs index e39439350..c09d69f7c 100644 --- a/nannou/src/draw/background.rs +++ b/nannou/src/draw/background.rs @@ -1,29 +1,18 @@ use crate::color::{self, IntoLinSrgba, Srgb, Srgba}; use crate::draw::properties::ColorScalar; use crate::draw::Draw; -use crate::geom; -use crate::math::BaseFloat; /// A type used to update the background colour. -pub struct Background<'a, S = geom::scalar::Default> -where - S: 'a + BaseFloat, -{ - draw: &'a Draw, +pub struct Background<'a> { + draw: &'a Draw, } /// Begin coloring the background. -pub fn new<'a, S>(draw: &'a Draw) -> Background<'a, S> -where - S: BaseFloat, -{ +pub fn new<'a>(draw: &'a Draw) -> Background<'a> { Background { draw } } -impl<'a, S> Background<'a, S> -where - S: BaseFloat, -{ +impl<'a> Background<'a> { /// Clear the background with the given color. /// /// This method supports any color type that can be converted into RGBA. @@ -100,10 +89,7 @@ where /// /// See the [wikipedia entry](https://en.wikipedia.org/wiki/HSL_and_HSV) for more details on /// this color space. - pub fn hsva(self, h: ColorScalar, s: ColorScalar, v: ColorScalar, a: ColorScalar) -> Self - where - S: Into>, - { + pub fn hsva(self, h: ColorScalar, s: ColorScalar, v: ColorScalar, a: ColorScalar) -> Self { let hue = h * 360.0; self.color(color::Hsva::new(hue, s, v, a)) } diff --git a/nannou/src/draw/drawing.rs b/nannou/src/draw/drawing.rs index 000470868..9b902039a 100644 --- a/nannou/src/draw/drawing.rs +++ b/nannou/src/draw/drawing.rs @@ -1,12 +1,12 @@ use crate::color::IntoLinSrgba; -use crate::draw::mesh::vertex::Color; +use crate::draw::mesh::vertex::{Color, TexCoords}; use crate::draw::primitive::Primitive; use crate::draw::properties::{ ColorScalar, SetColor, SetDimensions, SetFill, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Draw}; -use crate::geom::{self, Point2, Point3, Vector2, Vector3}; -use crate::math::{Angle, BaseFloat, Euler, Quaternion, Rad}; +use crate::geom::{Point2, Point3}; +use crate::glam::{Quat, Vec2, Vec3}; use lyon::path::PathEvent; use lyon::tessellation::{FillOptions, LineCap, LineJoin, StrokeOptions}; use std::marker::PhantomData; @@ -22,12 +22,9 @@ use std::marker::PhantomData; /// graph. As a result, each **Drawing** is associated with a single, unique node. Thus a /// **Drawing** can be thought of as a way of specifying properties for a node. #[derive(Debug)] -pub struct Drawing<'a, T, S = geom::scalar::Default> -where - S: 'a + BaseFloat, -{ +pub struct Drawing<'a, T> { // The `Draw` instance used to create this drawing. - draw: &'a Draw, + draw: &'a Draw, // The draw command index of the primitive being drawn. index: usize, // Whether or not the **Drawing** should attempt to finish the drawing on drop. @@ -39,24 +36,21 @@ where /// Some context that may be optionally provided to primitives in the drawing implementation. /// /// This is particularly useful for paths and meshes. -pub struct DrawingContext<'a, S> { +pub struct DrawingContext<'a> { /// The intermediary mesh for buffering yet-to-be-drawn paths and meshes. - pub mesh: &'a mut draw::Mesh, + pub mesh: &'a mut draw::Mesh, /// A re-usable buffer for collecting path events. pub path_event_buffer: &'a mut Vec, /// A re-usable buffer for collecting colored polyline points. - pub path_points_colored_buffer: &'a mut Vec<(Point2, Color)>, + pub path_points_colored_buffer: &'a mut Vec<(Point2, Color)>, /// A re-usable buffer for collecting textured polyline points. - pub path_points_textured_buffer: &'a mut Vec<(Point2, Point2)>, + pub path_points_textured_buffer: &'a mut Vec<(Point2, TexCoords)>, /// A re-usable buffer for collecting text. pub text_buffer: &'a mut String, } /// Construct a new **Drawing** instance. -pub fn new<'a, T, S>(draw: &'a Draw, index: usize) -> Drawing<'a, T, S> -where - S: BaseFloat, -{ +pub fn new<'a, T>(draw: &'a Draw, index: usize) -> Drawing<'a, T> { let _ty = PhantomData; let finish_on_drop = true; Drawing { @@ -67,10 +61,7 @@ where } } -impl<'a, T, S> Drop for Drawing<'a, T, S> -where - S: BaseFloat, -{ +impl<'a, T> Drop for Drawing<'a, T> { fn drop(&mut self) { if self.finish_on_drop { self.finish_inner(); @@ -78,9 +69,9 @@ where } } -impl<'a, S> DrawingContext<'a, S> { +impl<'a> DrawingContext<'a> { // Initialise the DrawingContext from the draw's IntermediaryState. - pub(crate) fn from_intermediary_state(state: &'a mut super::IntermediaryState) -> Self { + pub(crate) fn from_intermediary_state(state: &'a mut super::IntermediaryState) -> Self { let super::IntermediaryState { ref mut intermediary_mesh, ref mut path_event_buffer, @@ -98,10 +89,7 @@ impl<'a, S> DrawingContext<'a, S> { } } -impl<'a, T, S> Drawing<'a, T, S> -where - S: BaseFloat, -{ +impl<'a, T> Drawing<'a, T> { // Shared between the **finish** method and the **Drawing**'s **Drop** implementation. // // 1. Create vertices based on node-specific position, points, etc. @@ -123,10 +111,10 @@ where // Map the given function onto the primitive stored within **Draw** at `index`. // // The functionn is only applied if the node has not yet been **Drawn**. - fn map_primitive(mut self, map: F) -> Drawing<'a, T2, S> + fn map_primitive(mut self, map: F) -> Drawing<'a, T2> where - F: FnOnce(Primitive) -> Primitive, - T2: Into>, + F: FnOnce(Primitive) -> Primitive, + T2: Into, { if let Ok(mut state) = self.draw.state.try_borrow_mut() { if let Some(mut primitive) = state.drawing.remove(&self.index) { @@ -147,10 +135,10 @@ where // The same as `map_primitive` but also passes a mutable reference to the vertex data to the // map function. This is useful for types that may have an unknown number of arbitrary // vertices. - fn map_primitive_with_context(mut self, map: F) -> Drawing<'a, T2, S> + fn map_primitive_with_context(mut self, map: F) -> Drawing<'a, T2> where - F: FnOnce(Primitive, DrawingContext) -> Primitive, - T2: Into>, + F: FnOnce(Primitive, DrawingContext) -> Primitive, + T2: Into, { if let Ok(mut state) = self.draw.state.try_borrow_mut() { if let Some(mut primitive) = state.drawing.remove(&self.index) { @@ -177,11 +165,11 @@ where /// The function is only applied if the node has not yet been **Drawn**. /// /// **Panics** if the primitive does not contain type **T**. - pub fn map_ty(self, map: F) -> Drawing<'a, T2, S> + pub fn map_ty(self, map: F) -> Drawing<'a, T2> where F: FnOnce(T) -> T2, - T2: Into>, - Primitive: Into>, + T2: Into, + Primitive: Into>, { self.map_primitive(|prim| { let maybe_ty: Option = prim.into(); @@ -196,11 +184,11 @@ where /// The function is only applied if the node has not yet been **Drawn**. /// /// **Panics** if the primitive does not contain type **T**. - pub(crate) fn map_ty_with_context(self, map: F) -> Drawing<'a, T2, S> + pub(crate) fn map_ty_with_context(self, map: F) -> Drawing<'a, T2> where - F: FnOnce(T, DrawingContext) -> T2, - T2: Into>, - Primitive: Into>, + F: FnOnce(T, DrawingContext) -> T2, + T2: Into, + Primitive: Into>, { self.map_primitive_with_context(|prim, ctxt| { let maybe_ty: Option = prim.into(); @@ -213,11 +201,10 @@ where // SetColor implementations. -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetColor + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetColor + Into, + Primitive: Into>, { /// Specify a color. /// @@ -313,226 +300,192 @@ where // SetDimensions implementations. -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetDimensions + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetDimensions + Into, + Primitive: Into>, { /// Set the absolute width for the node. - pub fn width(self, w: S) -> Self { + pub fn width(self, w: f32) -> Self { self.map_ty(|ty| SetDimensions::width(ty, w)) } /// Set the absolute height for the node. - pub fn height(self, h: S) -> Self { + pub fn height(self, h: f32) -> Self { self.map_ty(|ty| SetDimensions::height(ty, h)) } /// Set the absolute depth for the node. - pub fn depth(self, d: S) -> Self { + pub fn depth(self, d: f32) -> Self { self.map_ty(|ty| SetDimensions::depth(ty, d)) } /// Short-hand for the **width** method. - pub fn w(self, w: S) -> Self { + pub fn w(self, w: f32) -> Self { self.map_ty(|ty| SetDimensions::w(ty, w)) } /// Short-hand for the **height** method. - pub fn h(self, h: S) -> Self { + pub fn h(self, h: f32) -> Self { self.map_ty(|ty| SetDimensions::h(ty, h)) } /// Short-hand for the **depth** method. - pub fn d(self, d: S) -> Self { + pub fn d(self, d: f32) -> Self { self.map_ty(|ty| SetDimensions::d(ty, d)) } /// Set the **x** and **y** dimensions for the node. - pub fn wh(self, v: Vector2) -> Self { + pub fn wh(self, v: Vec2) -> Self { self.map_ty(|ty| SetDimensions::wh(ty, v)) } /// Set the **x**, **y** and **z** dimensions for the node. - pub fn whd(self, v: Vector3) -> Self { + pub fn whd(self, v: Vec3) -> Self { self.map_ty(|ty| SetDimensions::whd(ty, v)) } /// Set the width and height for the node. - pub fn w_h(self, x: S, y: S) -> Self { + pub fn w_h(self, x: f32, y: f32) -> Self { self.map_ty(|ty| SetDimensions::w_h(ty, x, y)) } /// Set the width and height for the node. - pub fn w_h_d(self, x: S, y: S, z: S) -> Self { + pub fn w_h_d(self, x: f32, y: f32, z: f32) -> Self { self.map_ty(|ty| SetDimensions::w_h_d(ty, x, y, z)) } } // SetPosition methods. -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetPosition + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetPosition + Into, + Primitive: Into>, { /// Build with the given **Absolute** **Position** along the *x* axis. - pub fn x(self, x: S) -> Self { + pub fn x(self, x: f32) -> Self { self.map_ty(|ty| SetPosition::x(ty, x)) } /// Build with the given **Absolute** **Position** along the *y* axis. - pub fn y(self, y: S) -> Self { + pub fn y(self, y: f32) -> Self { self.map_ty(|ty| SetPosition::y(ty, y)) } /// Build with the given **Absolute** **Position** along the *z* axis. - pub fn z(self, z: S) -> Self { + pub fn z(self, z: f32) -> Self { self.map_ty(|ty| SetPosition::z(ty, z)) } /// Set the **Position** with some two-dimensional point. - pub fn xy(self, p: Point2) -> Self { + pub fn xy(self, p: Point2) -> Self { self.map_ty(|ty| SetPosition::xy(ty, p)) } /// Set the **Position** with some three-dimensional point. - pub fn xyz(self, p: Point3) -> Self { + pub fn xyz(self, p: Point3) -> Self { self.map_ty(|ty| SetPosition::xyz(ty, p)) } /// Set the **Position** with *x* *y* coordinates. - pub fn x_y(self, x: S, y: S) -> Self { + pub fn x_y(self, x: f32, y: f32) -> Self { self.map_ty(|ty| SetPosition::x_y(ty, x, y)) } /// Set the **Position** with *x* *y* *z* coordinates. - pub fn x_y_z(self, x: S, y: S, z: S) -> Self { + pub fn x_y_z(self, x: f32, y: f32, z: f32) -> Self { self.map_ty(|ty| SetPosition::x_y_z(ty, x, y, z)) } } // SetOrientation methods. -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetOrientation + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetOrientation + Into, + Primitive: Into>, { /// Describe orientation via the vector that points to the given target. - pub fn look_at(self, target: Point3) -> Self { + pub fn look_at(self, target: Point3) -> Self { self.map_ty(|ty| SetOrientation::look_at(ty, target)) } /// Specify the orientation around the *x* axis as an absolute value in radians. - pub fn x_radians(self, x: S) -> Self { + pub fn x_radians(self, x: f32) -> Self { self.map_ty(|ty| SetOrientation::x_radians(ty, x)) } /// Specify the orientation around the *y* axis as an absolute value in radians. - pub fn y_radians(self, y: S) -> Self { + pub fn y_radians(self, y: f32) -> Self { self.map_ty(|ty| SetOrientation::y_radians(ty, y)) } /// Specify the orientation around the *z* axis as an absolute value in radians. - pub fn z_radians(self, z: S) -> Self { + pub fn z_radians(self, z: f32) -> Self { self.map_ty(|ty| SetOrientation::z_radians(ty, z)) } /// Specify the orientation around the *x* axis as an absolute value in degrees. - pub fn x_degrees(self, x: S) -> Self - where - S: BaseFloat, - { + pub fn x_degrees(self, x: f32) -> Self { self.map_ty(|ty| SetOrientation::x_degrees(ty, x)) } /// Specify the orientation around the *y* axis as an absolute value in degrees. - pub fn y_degrees(self, y: S) -> Self - where - S: BaseFloat, - { + pub fn y_degrees(self, y: f32) -> Self { self.map_ty(|ty| SetOrientation::y_degrees(ty, y)) } /// Specify the orientation around the *z* axis as an absolute value in degrees. - pub fn z_degrees(self, z: S) -> Self - where - S: BaseFloat, - { + pub fn z_degrees(self, z: f32) -> Self { self.map_ty(|ty| SetOrientation::z_degrees(ty, z)) } /// Specify the orientation around the *x* axis as a number of turns around the axis. - pub fn x_turns(self, x: S) -> Self - where - S: BaseFloat, - { + pub fn x_turns(self, x: f32) -> Self { self.map_ty(|ty| SetOrientation::x_turns(ty, x)) } /// Specify the orientation around the *y* axis as a number of turns around the axis. - pub fn y_turns(self, y: S) -> Self - where - S: BaseFloat, - { + pub fn y_turns(self, y: f32) -> Self { self.map_ty(|ty| SetOrientation::y_turns(ty, y)) } /// Specify the orientation around the *z* axis as a number of turns around the axis. - pub fn z_turns(self, z: S) -> Self - where - S: BaseFloat, - { + pub fn z_turns(self, z: f32) -> Self { self.map_ty(|ty| SetOrientation::z_turns(ty, z)) } /// Specify the orientation along each axis with the given **Vector** of radians. /// /// This has the same affect as calling `self.x_radians(v.x).y_radians(v.y).z_radians(v.z)`. - pub fn radians(self, v: Vector3) -> Self { + pub fn radians(self, v: Vec3) -> Self { self.map_ty(|ty| SetOrientation::radians(ty, v)) } /// Specify the orientation along each axis with the given **Vector** of degrees. /// /// This has the same affect as calling `self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)`. - pub fn degrees(self, v: Vector3) -> Self - where - S: BaseFloat, - { + pub fn degrees(self, v: Vec3) -> Self { self.map_ty(|ty| SetOrientation::degrees(ty, v)) } /// Specify the orientation along each axis with the given **Vector** of "turns". /// /// This has the same affect as calling `self.x_turns(v.x).y_turns(v.y).z_turns(v.z)`. - pub fn turns(self, v: Vector3) -> Self - where - S: BaseFloat, - { + pub fn turns(self, v: Vec3) -> Self { self.map_ty(|ty| SetOrientation::turns(ty, v)) } /// Specify the orientation with the given **Euler**. /// - /// The euler can be specified in either radians (via **Rad**) or degrees (via **Deg**). - pub fn euler(self, e: Euler) -> Self - where - S: BaseFloat, - A: Angle + Into>, - { + /// The euler must be specified in radians. + pub fn euler(self, e: Vec3) -> Self { self.map_ty(|ty| SetOrientation::euler(ty, e)) } /// Specify the orientation with the given **Quaternion**. - pub fn quaternion(self, q: Quaternion) -> Self - where - S: BaseFloat, - { + pub fn quaternion(self, q: Quat) -> Self { self.map_ty(|ty| SetOrientation::quaternion(ty, q)) } @@ -541,21 +494,21 @@ where /// Specify the "pitch" of the orientation in radians. /// /// This has the same effect as calling `x_radians`. - pub fn pitch(self, pitch: S) -> Self { + pub fn pitch(self, pitch: f32) -> Self { self.map_ty(|ty| SetOrientation::pitch(ty, pitch)) } /// Specify the "yaw" of the orientation in radians. /// /// This has the same effect as calling `y_radians`. - pub fn yaw(self, yaw: S) -> Self { + pub fn yaw(self, yaw: f32) -> Self { self.map_ty(|ty| SetOrientation::yaw(ty, yaw)) } /// Specify the "roll" of the orientation in radians. /// /// This has the same effect as calling `z_radians`. - pub fn roll(self, roll: S) -> Self { + pub fn roll(self, roll: f32) -> Self { self.map_ty(|ty| SetOrientation::roll(ty, roll)) } @@ -563,18 +516,17 @@ where /// given value is specified in radians. /// /// This is equivalent to calling the `z_radians` or `roll` methods. - pub fn rotate(self, radians: S) -> Self { + pub fn rotate(self, radians: f32) -> Self { self.map_ty(|ty| SetOrientation::rotate(ty, radians)) } } // SetFill methods -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetFill + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetFill + Into, + Primitive: Into>, { /// Specify the whole set of fill tessellation options. pub fn fill_opts(self, opts: FillOptions) -> Self { @@ -614,11 +566,10 @@ where // SetStroke methods -impl<'a, T, S> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - T: SetStroke + Into>, - Primitive: Into>, - S: BaseFloat, + T: SetStroke + Into, + Primitive: Into>, { /// The start line cap as specified by the SVG spec. pub fn start_cap(self, cap: LineCap) -> Self { diff --git a/nannou/src/draw/mesh/builder.rs b/nannou/src/draw/mesh/builder.rs index dc7186739..232b0b901 100644 --- a/nannou/src/draw/mesh/builder.rs +++ b/nannou/src/draw/mesh/builder.rs @@ -6,8 +6,8 @@ //! Lyon tessellators assume `f32` data, so we do the same in the following implementations. use crate::draw; -use crate::geom; -use cgmath::Matrix4; +use crate::geom::Point2; +use crate::glam::Mat4; use lyon::tessellation::geometry_builder::{ self, FillGeometryBuilder, GeometryBuilder, StrokeGeometryBuilder, }; @@ -21,7 +21,7 @@ pub struct MeshBuilder<'a, A> { /// The number of indices in the mesh when begin was called. begin_index_count: u32, /// Transform matrix that also integrates position and orientation here. - transform: Matrix4, + transform: Mat4, /// The way in which vertex attributes should be sourced. attributes: A, } @@ -32,7 +32,7 @@ pub struct TexCoordsPerPoint; impl<'a, A> MeshBuilder<'a, A> { /// Begin extending the mesh. - fn new(mesh: &'a mut draw::Mesh, transform: Matrix4, attributes: A) -> Self { + fn new(mesh: &'a mut draw::Mesh, transform: Mat4, attributes: A) -> Self { MeshBuilder { mesh, begin_vertex_count: 0, @@ -47,7 +47,7 @@ impl<'a> MeshBuilder<'a, SingleColor> { /// Begin extending a mesh rendered with a single colour. pub fn single_color( mesh: &'a mut draw::Mesh, - transform: Matrix4, + transform: Mat4, color: draw::mesh::vertex::Color, ) -> Self { Self::new(mesh, transform, SingleColor(color)) @@ -56,14 +56,14 @@ impl<'a> MeshBuilder<'a, SingleColor> { impl<'a> MeshBuilder<'a, ColorPerPoint> { /// Begin extending a mesh where the path interpolates a unique color per point. - pub fn color_per_point(mesh: &'a mut draw::Mesh, transform: Matrix4) -> Self { + pub fn color_per_point(mesh: &'a mut draw::Mesh, transform: Mat4) -> Self { Self::new(mesh, transform, ColorPerPoint) } } impl<'a> MeshBuilder<'a, TexCoordsPerPoint> { /// Begin extending a mesh where the path interpolates a unique texture coordinates per point. - pub fn tex_coords_per_point(mesh: &'a mut draw::Mesh, transform: Matrix4) -> Self { + pub fn tex_coords_per_point(mesh: &'a mut draw::Mesh, transform: Mat4) -> Self { Self::new(mesh, transform, TexCoordsPerPoint) } } @@ -102,9 +102,8 @@ impl<'a> FillGeometryBuilder for MeshBuilder<'a, SingleColor> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let SingleColor(color) = self.attributes; let tex_coords = draw::mesh::vertex::default_tex_coords(); let vertex = draw::mesh::vertex::new(point, color, tex_coords); @@ -125,9 +124,8 @@ impl<'a> StrokeGeometryBuilder for MeshBuilder<'a, SingleColor> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let SingleColor(color) = self.attributes; let tex_coords = draw::mesh::vertex::default_tex_coords(); let vertex = draw::mesh::vertex::new(point, color, tex_coords); @@ -148,9 +146,8 @@ impl<'a> FillGeometryBuilder for MeshBuilder<'a, ColorPerPoint> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let col = &attrs.interpolated_attributes(); let color: draw::mesh::vertex::Color = (col[0], col[1], col[2], col[3]).into(); let tex_coords = draw::mesh::vertex::default_tex_coords(); @@ -172,9 +169,8 @@ impl<'a> StrokeGeometryBuilder for MeshBuilder<'a, ColorPerPoint> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let col = &attrs.interpolated_attributes(); let color: draw::mesh::vertex::Color = (col[0], col[1], col[2], col[3]).into(); let tex_coords = draw::mesh::vertex::default_tex_coords(); @@ -196,9 +192,8 @@ impl<'a> FillGeometryBuilder for MeshBuilder<'a, TexCoordsPerPoint> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let tc = &attrs.interpolated_attributes(); let tex_coords: draw::mesh::vertex::TexCoords = (tc[0], tc[1]).into(); let color = draw::mesh::vertex::DEFAULT_VERTEX_COLOR; @@ -220,9 +215,8 @@ impl<'a> StrokeGeometryBuilder for MeshBuilder<'a, TexCoordsPerPoint> { let id = VertexId::from_usize(self.mesh.points().len()); // Construct and insert the point - let p = geom::Point3::from(geom::Point2::from(position)); - let p = cgmath::Transform::transform_point(&self.transform, p.into()); - let point = geom::vec3(p.x, p.y, p.z); + let p = Point2::new(position.x, position.y).extend(0.0); + let point = self.transform.transform_point3(p); let tc = &attrs.interpolated_attributes(); let tex_coords: draw::mesh::vertex::TexCoords = (tc[0], tc[1]).into(); let color = draw::mesh::vertex::DEFAULT_VERTEX_COLOR; diff --git a/nannou/src/draw/mesh/mod.rs b/nannou/src/draw/mesh/mod.rs index 201089c2d..3bc07f73e 100644 --- a/nannou/src/draw/mesh/mod.rs +++ b/nannou/src/draw/mesh/mod.rs @@ -10,22 +10,22 @@ pub mod vertex; pub use self::builder::MeshBuilder; pub use self::vertex::Vertex; -pub type Points = Vec>; +pub type Points = Vec; pub type Indices = Vec; pub type Colors = Vec; -pub type TexCoords = Vec>; +pub type TexCoords = Vec; /// The inner mesh type used by the **draw::Mesh**. -pub type MeshType = - WithTexCoords>, Indices>, Colors>, TexCoords>; +pub type MeshType = + WithTexCoords, Indices>, Colors>, TexCoords>; /// The custom mesh type used internally by the **Draw** API. #[derive(Clone, Debug)] -pub struct Mesh { - mesh: MeshType, +pub struct Mesh { + mesh: MeshType, } -impl Mesh { +impl Mesh { /// The number of raw vertices contained within the mesh. pub fn raw_vertex_count(&self) -> usize { mesh::raw_vertex_count(self) @@ -42,7 +42,7 @@ impl Mesh { } /// The **Mesh**'s vertex position channel. - pub fn points(&self) -> &[vertex::Point] { + pub fn points(&self) -> &[vertex::Point] { mesh::Points::points(self) } @@ -57,12 +57,12 @@ impl Mesh { } /// The **Mesh**'s vertex texture coordinates channel. - pub fn tex_coords(&self) -> &[vertex::TexCoords] { + pub fn tex_coords(&self) -> &[vertex::TexCoords] { mesh::TexCoords::tex_coords(self) } /// Push the given vertex onto the inner channels. - pub fn push_vertex(&mut self, v: Vertex) { + pub fn push_vertex(&mut self, v: Vertex) { mesh::push_vertex(self, v); } @@ -74,7 +74,7 @@ impl Mesh { /// Extend the mesh channels with the given vertices. pub fn extend_vertices(&mut self, vs: I) where - I: IntoIterator>, + I: IntoIterator, { mesh::extend_vertices(self, vs); } @@ -90,7 +90,7 @@ impl Mesh { /// Extend the **Mesh** with the given vertices and indices. pub fn extend(&mut self, vs: V, is: I) where - V: IntoIterator>, + V: IntoIterator, I: IntoIterator, { self.extend_vertices(vs); @@ -121,12 +121,7 @@ impl Mesh { pub fn into_raw_vertices(self) -> mesh::RawVertices { mesh::raw_vertices(self) } -} -impl Mesh -where - S: Clone, -{ /// Extend the mesh from the given slices. /// /// This is faster than `extend` which uses iteration internally. @@ -134,10 +129,10 @@ where /// **Panic!**s if the length of the given points, colors and tex_coords slices do not match. pub fn extend_from_slices( &mut self, - points: &[vertex::Point], + points: &[vertex::Point], indices: &[u32], colors: &[vertex::Color], - tex_coords: &[vertex::TexCoords], + tex_coords: &[vertex::TexCoords], ) { assert_eq!(points.len(), colors.len()); assert_eq!(points.len(), tex_coords.len()); @@ -148,9 +143,9 @@ where /// Extend the mesh with the given slices of vertices. pub fn extend_vertices_from_slices( &mut self, - points: &[vertex::Point], + points: &[vertex::Point], colors: &[vertex::Color], - tex_coords: &[vertex::TexCoords], + tex_coords: &[vertex::TexCoords], ) { self.extend_from_slices(points, &[], colors, tex_coords); } @@ -181,45 +176,42 @@ where } } -impl Default for Mesh { +impl Default for Mesh { fn default() -> Self { let mesh = Default::default(); Mesh { mesh } } } -impl Deref for Mesh { - type Target = MeshType; +impl Deref for Mesh { + type Target = MeshType; fn deref(&self) -> &Self::Target { &self.mesh } } -impl DerefMut for Mesh { +impl DerefMut for Mesh { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.mesh } } -impl mesh::GetVertex for Mesh -where - S: Clone, -{ - type Vertex = Vertex; +impl mesh::GetVertex for Mesh { + type Vertex = Vertex; fn get_vertex(&self, index: u32) -> Option { mesh::WithTexCoords::get_vertex(&self.mesh, index) } } -impl mesh::Points for Mesh { - type Point = vertex::Point; - type Points = Points; +impl mesh::Points for Mesh { + type Point = vertex::Point; + type Points = Points; fn points(&self) -> &Self::Points { self.mesh.points() } } -impl mesh::Indices for Mesh { +impl mesh::Indices for Mesh { type Index = u32; type Indices = Indices; fn indices(&self) -> &Self::Indices { @@ -227,7 +219,7 @@ impl mesh::Indices for Mesh { } } -impl mesh::Colors for Mesh { +impl mesh::Colors for Mesh { type Color = vertex::Color; type Colors = Colors; fn colors(&self) -> &Self::Colors { @@ -235,21 +227,21 @@ impl mesh::Colors for Mesh { } } -impl mesh::TexCoords for Mesh { - type TexCoord = geom::Point2; - type TexCoords = TexCoords; +impl mesh::TexCoords for Mesh { + type TexCoord = geom::Point2; + type TexCoords = TexCoords; fn tex_coords(&self) -> &Self::TexCoords { self.mesh.tex_coords() } } -impl mesh::PushVertex> for Mesh { - fn push_vertex(&mut self, v: Vertex) { +impl mesh::PushVertex for Mesh { + fn push_vertex(&mut self, v: Vertex) { self.mesh.push_vertex(v); } } -impl mesh::PushIndex for Mesh { +impl mesh::PushIndex for Mesh { type Index = u32; fn push_index(&mut self, index: Self::Index) { @@ -264,13 +256,13 @@ impl mesh::PushIndex for Mesh { } } -impl mesh::ClearIndices for Mesh { +impl mesh::ClearIndices for Mesh { fn clear_indices(&mut self) { self.mesh.clear_indices(); } } -impl mesh::ClearVertices for Mesh { +impl mesh::ClearVertices for Mesh { fn clear_vertices(&mut self) { self.mesh.clear_vertices(); } diff --git a/nannou/src/draw/mesh/vertex.rs b/nannou/src/draw/mesh/vertex.rs index 558079d2e..df738cc92 100644 --- a/nannou/src/draw/mesh/vertex.rs +++ b/nannou/src/draw/mesh/vertex.rs @@ -1,19 +1,16 @@ use crate::color; -use crate::geom::{self, Point2, Point3, Vector3}; -use crate::math::BaseFloat; +use crate::geom::{Point2, Point3, Vec3}; use crate::mesh::vertex::{WithColor, WithTexCoords}; -use std::marker::PhantomData; -pub type Point = Point3; +pub type Point = Point3; pub type Color = color::LinSrgba; -pub type TexCoords = Point2; -pub type Normal = Vector3; -pub type ColoredPoint = WithColor, Color>; -pub type ColoredPoint2 = WithColor, Color>; +pub type TexCoords = Point2; +pub type Normal = Vec3; +pub type ColoredPoint = WithColor; +pub type ColoredPoint2 = WithColor; /// The vertex type produced by the **draw::Mesh**'s inner **MeshType**. -pub type Vertex = - WithTexCoords, Color>, TexCoords>; +pub type Vertex = WithTexCoords, TexCoords>; /// The number of channels in the color type. pub const COLOR_CHANNEL_COUNT: usize = 4; @@ -29,7 +26,7 @@ pub const DEFAULT_VERTEX_COLOR: Color = color::Alpha { }; /// Simplified constructor for a **draw::mesh::Vertex**. -pub fn new(point: Point, color: Color, tex_coords: TexCoords) -> Vertex { +pub fn new(point: Point, color: Color, tex_coords: TexCoords) -> Vertex { WithTexCoords { tex_coords, vertex: WithColor { @@ -40,24 +37,18 @@ pub fn new(point: Point, color: Color, tex_coords: TexCoords) -> Vertex } /// Default texture coordinates, for the case where a type is not textured. -pub fn default_tex_coords() -> TexCoords -where - S: BaseFloat, -{ - Point2 { - x: S::zero(), - y: S::zero(), - } +pub fn default_tex_coords() -> TexCoords { + [0.0; 2].into() } -impl Vertex { +impl Vertex { /// Borrow the inner **Point**. - pub fn point(&self) -> &Point { + pub fn point(&self) -> &Point { &self.vertex.vertex } /// Mutably borrow the inner **Point**. - pub fn point_mut(&mut self) -> &mut Point { + pub fn point_mut(&mut self) -> &mut Point { &mut self.vertex.vertex } } @@ -66,36 +57,30 @@ impl Vertex { /// /// Default values are used for tex_coords. #[derive(Clone, Debug)] -pub struct IterFromColoredPoints { +pub struct IterFromColoredPoints { colored_points: I, - _scalar: PhantomData, } -impl IterFromColoredPoints { +impl IterFromColoredPoints { /// Produce an iterator that converts an iterator yielding colored points to an iterator /// yielding **Vertex**s. /// /// The default value of `(0.0, 0.0)` is used for tex_coords. pub fn new

(colored_points: P) -> Self where - P: IntoIterator, Color>>, - I: Iterator, Color>>, + P: IntoIterator>, + I: Iterator>, { let colored_points = colored_points.into_iter(); - let _scalar = PhantomData; - IterFromColoredPoints { - colored_points, - _scalar, - } + IterFromColoredPoints { colored_points } } } -impl Iterator for IterFromColoredPoints +impl Iterator for IterFromColoredPoints where - I: Iterator, Color>>, - S: BaseFloat, + I: Iterator>, { - type Item = Vertex; + type Item = Vertex; fn next(&mut self) -> Option { self.colored_points.next().map(|vertex| { let tex_coords = default_tex_coords(); @@ -111,10 +96,9 @@ where /// /// The default value of `(0.0, 0.0)` is used for tex_coords. #[derive(Clone, Debug)] -pub struct IterFromPoints { +pub struct IterFromPoints { points: I, default_color: Color, - _scalar: PhantomData, } /// A type that converts an iterator yielding 2D points to an iterator yielding **Vertex**s. @@ -125,13 +109,12 @@ pub struct IterFromPoints { /// /// The default value of `(0.0, 0.0)` is used for tex_coords. #[derive(Clone, Debug)] -pub struct IterFromPoint2s { +pub struct IterFromPoint2s { points: I, default_color: Color, - _scalar: PhantomData, } -impl IterFromPoints { +impl IterFromPoints { /// Produce an iterator that converts an iterator yielding points to an iterator yielding /// **Vertex**s. /// @@ -140,20 +123,18 @@ impl IterFromPoints { /// The default value of `(0.0, 0.0)` is used for tex_coords. pub fn new

(points: P, default_color: Color) -> Self where - P: IntoIterator>, - I: Iterator>, + P: IntoIterator, + I: Iterator, { let points = points.into_iter(); - let _scalar = PhantomData; IterFromPoints { points, default_color, - _scalar, } } } -impl IterFromPoint2s { +impl IterFromPoint2s { /// A type that converts an iterator yielding 2D points to an iterator yielding **Vertex**s. /// /// The `z` position for each vertex will be `0.0`. @@ -163,25 +144,22 @@ impl IterFromPoint2s { /// The default value of `(0.0, 0.0)` is used for tex_coords. pub fn new

(points: P, default_color: Color) -> Self where - P: IntoIterator>, - I: Iterator>, + P: IntoIterator, + I: Iterator, { let points = points.into_iter(); - let _scalar = PhantomData; IterFromPoint2s { points, default_color, - _scalar, } } } -impl Iterator for IterFromPoints +impl Iterator for IterFromPoints where - I: Iterator>, - S: BaseFloat, + I: Iterator, { - type Item = Vertex; + type Item = Vertex; fn next(&mut self) -> Option { self.points.next().map(|vertex| { let color = self.default_color; @@ -193,15 +171,14 @@ where } } -impl Iterator for IterFromPoint2s +impl Iterator for IterFromPoint2s where - I: Iterator>, - S: BaseFloat, + I: Iterator, { - type Item = Vertex; + type Item = Vertex; fn next(&mut self) -> Option { - self.points.next().map(|Point2 { x, y }| { - let vertex = Point3 { x, y, z: S::zero() }; + self.points.next().map(|p| { + let vertex = p.extend(0.0); let color = self.default_color; let vertex = WithColor { vertex, color }; let tex_coords = default_tex_coords(); diff --git a/nannou/src/draw/mod.rs b/nannou/src/draw/mod.rs index ab821e148..aee06422c 100644 --- a/nannou/src/draw/mod.rs +++ b/nannou/src/draw/mod.rs @@ -3,7 +3,8 @@ //! See the [**Draw** type](./struct.Draw.html) for more details. use crate::geom::{self, Point2}; -use crate::math::{deg_to_rad, turns_to_rad, BaseFloat, Matrix4, SquareMatrix}; +use crate::glam::{vec3, EulerRot, Mat4, Quat, Vec2, Vec3}; +use crate::math::{deg_to_rad, turns_to_rad}; use crate::wgpu; use lyon::path::PathEvent; use std::cell::RefCell; @@ -13,7 +14,7 @@ use std::rc::Rc; pub use self::background::Background; pub use self::drawing::{Drawing, DrawingContext}; -use self::mesh::vertex::Color; +use self::mesh::vertex::{Color, TexCoords}; pub use self::mesh::Mesh; use self::primitive::Primitive; pub use self::renderer::{Builder as RendererBuilder, Renderer}; @@ -42,10 +43,7 @@ pub mod theme; /// See the [draw](https://github.com/nannou-org/nannou/blob/master/examples) examples for a /// variety of demonstrations of how the **Draw** type can be used! #[derive(Clone, Debug)] -pub struct Draw -where - S: BaseFloat, -{ +pub struct Draw { /// The state of the **Draw**. /// /// State is shared between this **Draw** instance and all other **Draw** instances that were @@ -55,17 +53,17 @@ where /// purpose of a **Draw** is to be an easy-as-possible, high-level API for drawing stuff. In /// order to be friendlier to new users, we want to avoid them having to think about mutability /// and focus on creativity. Rust-lang nuances can come later. - state: Rc>>, + state: Rc>, /// The current context of this **Draw** instance. - context: Context, + context: Context, } /// The current **Transform**, alpha **BlendState** and **Scissor** of a **Draw** instance. #[derive(Clone, Debug, PartialEq)] -pub struct Context { - pub transform: Matrix4, +pub struct Context { + pub transform: Mat4, pub blend: wgpu::BlendState, - pub scissor: Scissor, + pub scissor: Scissor, // TODO: Consider changing `PolygonMode` (added as of wgpu 0.7) rather than `PrimitiveTopology` // here. pub topology: wgpu::PrimitiveTopology, @@ -77,20 +75,20 @@ pub struct Context { /// During rendering, the list of **DrawCommand**s are converted into a list of **RenderCommands** /// that are directly associated with encodable render pass commands. #[derive(Clone, Debug)] -pub enum DrawCommand { +pub enum DrawCommand { /// Draw a primitive. - Primitive(Primitive), + Primitive(Primitive), /// A change in the rendering context occurred. - Context(Context), + Context(Context), } /// The scissor for a **Draw**'s render context. #[derive(Clone, Copy, Debug, PartialEq)] -pub enum Scissor { +pub enum Scissor { /// The extent of the scissor matches the bounds of the target texture. Full, /// Crop the view to the given rect. - Rect(geom::Rect), + Rect(geom::Rect), /// The scissor has no overlap with the previous window, resulting in nothing to draw. NoOverlap, } @@ -103,44 +101,41 @@ pub enum Scissor { /// drawing stuff. In order to be friendlier to new users, we want to avoid requiring them to think /// about mutability and instead focus on creativity. Rust-lang nuances can come later. #[derive(Clone, Debug)] -pub struct State -where - S: BaseFloat, -{ +pub struct State { /// The last context used to draw an image, used to detect changes and emit commands for them. - last_draw_context: Option>, + last_draw_context: Option, /// If `Some`, the **Draw** should first clear the frame's texture with the given color. background_color: Option, /// Primitives that are in the process of being drawn. /// /// Keys are indices into the `draw_commands` Vec. - drawing: HashMap>, + drawing: HashMap, /// The list of recorded draw commands. /// /// An element may be `None` if it is a primitive in the process of being drawn. - draw_commands: Vec>>, + draw_commands: Vec>, /// State made accessible via the `DrawingContext`. - intermediary_state: RefCell>, + intermediary_state: RefCell, /// The theme containing default values. theme: Theme, } /// State made accessible via the `DrawingContext`. #[derive(Clone, Debug)] -pub struct IntermediaryState { +pub struct IntermediaryState { /// Buffers of vertex data that may be re-used for paths, meshes, etc between view calls. - intermediary_mesh: Mesh, + intermediary_mesh: Mesh, /// A re-usable buffer for collecting path events. path_event_buffer: Vec, /// A re-usable buffer for collecting colored polyline points. - path_points_colored_buffer: Vec<(Point2, Color)>, + path_points_colored_buffer: Vec<(Point2, Color)>, /// A re-usable buffer for collecting textured polyline points. - path_points_textured_buffer: Vec<(Point2, Point2)>, + path_points_textured_buffer: Vec<(Point2, TexCoords)>, /// A buffer containing all text. text_buffer: String, } -impl IntermediaryState { +impl IntermediaryState { pub fn reset(&mut self) { self.intermediary_mesh.clear(); self.path_event_buffer.clear(); @@ -150,10 +145,7 @@ impl IntermediaryState { } } -impl State -where - S: BaseFloat, -{ +impl State { // Resets all state within the `Draw` instance. fn reset(&mut self) { self.background_color = None; @@ -180,17 +172,14 @@ where } // Insert the draw primitive command at the given index. - fn insert_draw_command(&mut self, index: usize, prim: Primitive) { + fn insert_draw_command(&mut self, index: usize, prim: Primitive) { if let Some(elem) = self.draw_commands.get_mut(index) { *elem = Some(DrawCommand::Primitive(prim)); } } } -impl Draw -where - S: BaseFloat, -{ +impl Draw { /// Create a new **Draw** instance. /// /// This is the same as calling **Draw::default**. @@ -209,148 +198,139 @@ where /// /// The resulting **Draw** instance will be have a transform equal to the new transform applied /// to the existing transform. - pub fn transform(&self, transform_matrix: Matrix4) -> Self { + pub fn transform(&self, transform_matrix: Mat4) -> Self { let mut context = self.context.clone(); context.transform = context.transform * transform_matrix; self.context(context) } /// Translate the position of the origin by the given translation vector. - pub fn translate(&self, v: geom::Vector3) -> Self { - self.transform(Matrix4::from_translation(v.into())) + pub fn translate(&self, v: Vec3) -> Self { + self.transform(Mat4::from_translation(v)) } /// Translate the position of the origin by the given translation vector. /// /// This method is short for `translate`. - pub fn xyz(&self, v: geom::Vector3) -> Self { + pub fn xyz(&self, v: Vec3) -> Self { self.translate(v) } /// Translate the position of the origin by the given translation vector. - pub fn xy(&self, v: geom::Vector2) -> Self { - self.xyz(v.into()) + pub fn xy(&self, v: Vec2) -> Self { + self.xyz(v.extend(0.0)) } /// Translate the position of the origin by the given amount across each axis. - pub fn x_y_z(&self, x: S, y: S, z: S) -> Self { + pub fn x_y_z(&self, x: f32, y: f32, z: f32) -> Self { self.xyz([x, y, z].into()) } /// Translate the position of the origin by the given amount across each axis. - pub fn x_y(&self, x: S, y: S) -> Self { + pub fn x_y(&self, x: f32, y: f32) -> Self { self.xy([x, y].into()) } /// Translate the position of the origin along the x axis. - pub fn x(&self, x: S) -> Self { - self.x_y(x, S::zero()) + pub fn x(&self, x: f32) -> Self { + self.x_y(x, 0.0) } /// Translate the position of the origin along the y axis. - pub fn y(&self, y: S) -> Self { - self.x_y(S::zero(), y) + pub fn y(&self, y: f32) -> Self { + self.x_y(0.0, y) } /// Translate the position of the origin along the z axis. - pub fn z(&self, z: S) -> Self { - self.x_y_z(S::zero(), S::zero(), z) + pub fn z(&self, z: f32) -> Self { + self.x_y_z(0.0, 0.0, z) } /// Produce a new **Draw** instance where the contents are scaled uniformly by the given value. - pub fn scale(&self, s: S) -> Self { - self.scale_axes(geom::vec3(s, s, s)) + pub fn scale(&self, s: f32) -> Self { + self.scale_axes(vec3(s, s, s)) } /// Produce a new **Draw** instance where the contents are scaled by the given amount across /// each axis. - pub fn scale_axes(&self, v: geom::Vector3) -> Self { - self.transform(Matrix4::from_nonuniform_scale(v.x, v.y, v.z)) + pub fn scale_axes(&self, v: Vec3) -> Self { + self.transform(Mat4::from_scale(v)) } /// Produce a new **Draw** instance where the contents are scaled by the given amount along the /// x axis - pub fn scale_x(&self, s: S) -> Self { - self.scale_axes(geom::vec3(s, S::one(), S::one())) + pub fn scale_x(&self, s: f32) -> Self { + self.scale_axes(vec3(s, 1.0, 1.0)) } /// Produce a new **Draw** instance where the contents are scaled by the given amount along the /// y axis - pub fn scale_y(&self, s: S) -> Self { - self.scale_axes(geom::vec3(S::one(), s, S::one())) + pub fn scale_y(&self, s: f32) -> Self { + self.scale_axes(vec3(1.0, s, 1.0)) } /// Produce a new **Draw** instance where the contents are scaled by the given amount along the /// z axis - pub fn scale_z(&self, s: S) -> Self { - self.scale_axes(geom::vec3(S::one(), S::one(), s)) + pub fn scale_z(&self, s: f32) -> Self { + self.scale_axes(vec3(1.0, 1.0, s)) } /// The given vector is interpreted as a Euler angle in radians and a transform is applied /// accordingly. - pub fn euler(&self, euler: cgmath::Euler>) -> Self { - self.transform(euler.into()) + pub fn euler(&self, euler: Vec3) -> Self { + self.transform(Mat4::from_euler(EulerRot::XYZ, euler.x, euler.y, euler.z)) } /// Specify the orientation with the given **Quaternion**. - pub fn quaternion(&self, q: cgmath::Quaternion) -> Self { - self.transform(q.into()) + pub fn quaternion(&self, q: Quat) -> Self { + self.transform(Mat4::from_quat(q)) } /// Specify the orientation along each axis with the given **Vector** of radians. /// /// This currently has the same affect as calling `euler`. - pub fn radians(&self, v: geom::Vector3) -> Self { - let euler = cgmath::Euler { - x: cgmath::Rad(v.x), - y: cgmath::Rad(v.y), - z: cgmath::Rad(v.z), - }; - self.euler(euler) + pub fn radians(&self, v: Vec3) -> Self { + self.euler(v) } /// Specify the orientation around the *x* axis in radians. - pub fn x_radians(&self, x: S) -> Self { - self.radians(geom::vec3(x, S::zero(), S::zero())) + pub fn x_radians(&self, x: f32) -> Self { + self.radians(vec3(x, 0.0, 0.0)) } /// Specify the orientation around the *y* axis in radians. - pub fn y_radians(&self, y: S) -> Self { - self.radians(geom::vec3(S::zero(), y, S::zero())) + pub fn y_radians(&self, y: f32) -> Self { + self.radians(vec3(0.0, y, 0.0)) } /// Specify the orientation around the *z* axis in radians. - pub fn z_radians(&self, z: S) -> Self { - self.radians(geom::vec3(S::zero(), S::zero(), z)) + pub fn z_radians(&self, z: f32) -> Self { + self.radians(vec3(0.0, 0.0, z)) } /// Specify the orientation along each axis with the given **Vector** of degrees. - pub fn degrees(&self, v: geom::Vector3) -> Self { - self.radians(geom::vec3( - deg_to_rad(v.x), - deg_to_rad(v.y), - deg_to_rad(v.z), - )) + pub fn degrees(&self, v: Vec3) -> Self { + self.radians(vec3(deg_to_rad(v.x), deg_to_rad(v.y), deg_to_rad(v.z))) } /// Specify the orientation around the *x* axis in degrees. - pub fn x_degrees(&self, x: S) -> Self { + pub fn x_degrees(&self, x: f32) -> Self { self.x_radians(deg_to_rad(x)) } /// Specify the orientation around the *y* axis in degrees. - pub fn y_degrees(&self, y: S) -> Self { + pub fn y_degrees(&self, y: f32) -> Self { self.y_radians(deg_to_rad(y)) } /// Specify the orientation around the *z* axis in degrees. - pub fn z_degrees(&self, z: S) -> Self { + pub fn z_degrees(&self, z: f32) -> Self { self.z_radians(deg_to_rad(z)) } /// Specify the orientation along each axis with the given **Vector** of degrees. - pub fn turns(&self, v: geom::Vector3) -> Self { - self.radians(geom::vec3( + pub fn turns(&self, v: Vec3) -> Self { + self.radians(vec3( turns_to_rad(v.x), turns_to_rad(v.y), turns_to_rad(v.z), @@ -358,38 +338,38 @@ where } /// Specify the orientation around the *x* axis as a number of turns around the axis. - pub fn x_turns(&self, x: S) -> Self { + pub fn x_turns(&self, x: f32) -> Self { self.x_radians(turns_to_rad(x)) } /// Specify the orientation around the *y* axis as a number of turns around the axis. - pub fn y_turns(&self, y: S) -> Self { + pub fn y_turns(&self, y: f32) -> Self { self.y_radians(turns_to_rad(y)) } /// Specify the orientation around the *z* axis as a number of turns around the axis. - pub fn z_turns(&self, z: S) -> Self { + pub fn z_turns(&self, z: f32) -> Self { self.z_radians(turns_to_rad(z)) } /// Specify the "pitch" of the orientation in radians. /// /// This has the same effect as calling `x_radians`. - pub fn pitch(&self, pitch: S) -> Self { + pub fn pitch(&self, pitch: f32) -> Self { self.x_radians(pitch) } /// Specify the "yaw" of the orientation in radians. /// /// This has the same effect as calling `y_radians`. - pub fn yaw(&self, yaw: S) -> Self { + pub fn yaw(&self, yaw: f32) -> Self { self.y_radians(yaw) } /// Specify the "roll" of the orientation in radians. /// /// This has the same effect as calling `z_radians`. - pub fn roll(&self, roll: S) -> Self { + pub fn roll(&self, roll: f32) -> Self { self.z_radians(roll) } @@ -397,7 +377,7 @@ where /// given value is specified in radians. /// /// This is equivalent to calling the `z_radians` or `roll` methods. - pub fn rotate(&self, radians: S) -> Self { + pub fn rotate(&self, radians: f32) -> Self { self.z_radians(radians) } @@ -424,7 +404,7 @@ where /// /// If the current **Draw** instance already contains a scissor, the result will be the overlap /// between the original scissor and the new one. - pub fn scissor(&self, scissor: geom::Rect) -> Self { + pub fn scissor(&self, scissor: geom::Rect) -> Self { let mut context = self.context.clone(); context.scissor = match context.scissor { Scissor::Full => Scissor::Rect(scissor), @@ -491,7 +471,7 @@ where } /// Produce a new **Draw** instance with the given context. - fn context(&self, context: Context) -> Self { + fn context(&self, context: Context) -> Self { let state = self.state.clone(); Draw { state, context } } @@ -499,15 +479,15 @@ where // Primitives. /// Specify a color with which the background should be cleared. - pub fn background(&self) -> Background { + pub fn background(&self) -> Background { background::new(self) } /// Add the given type to be drawn. - pub fn a(&self, primitive: T) -> Drawing + pub fn a(&self, primitive: T) -> Drawing where - T: Into>, - Primitive: Into>, + T: Into, + Primitive: Into>, { let index = { let mut state = self.state.borrow_mut(); @@ -520,7 +500,7 @@ where } // The primitive will be inserted in the next element. let index = state.draw_commands.len(); - let primitive: Primitive = primitive.into(); + let primitive: Primitive = primitive.into(); state.draw_commands.push(None); state.drawing.insert(index, primitive); index @@ -529,59 +509,59 @@ where } /// Begin drawing a **Path**. - pub fn path(&self) -> Drawing, S> { + pub fn path(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing an **Ellipse**. - pub fn ellipse(&self) -> Drawing, S> { + pub fn ellipse(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Line**. - pub fn line(&self) -> Drawing, S> { + pub fn line(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing an **Arrow**. - pub fn arrow(&self) -> Drawing, S> { + pub fn arrow(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Quad**. - pub fn quad(&self) -> Drawing, S> { + pub fn quad(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Rect**. - pub fn rect(&self) -> Drawing, S> { + pub fn rect(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Triangle**. - pub fn tri(&self) -> Drawing, S> { + pub fn tri(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Polygon**. - pub fn polygon(&self) -> Drawing, S> { + pub fn polygon(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Mesh**. - pub fn mesh(&self) -> Drawing { + pub fn mesh(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Polyline**. /// /// Note that this is simply short-hand for `draw.path().stroke()` - pub fn polyline(&self) -> Drawing, S> { + pub fn polyline(&self) -> Drawing { self.path().stroke() } /// Begin drawing a **Text**. - pub fn text(&self, s: &str) -> Drawing, S> { + pub fn text(&self, s: &str) -> Drawing { let text = { let state = self.state.borrow(); let mut intermediary_state = state.intermediary_state.borrow_mut(); @@ -592,13 +572,13 @@ where } /// Begin drawing a **Texture**. - pub fn texture(&self, view: &dyn wgpu::ToTextureView) -> Drawing, S> { + pub fn texture(&self, view: &dyn wgpu::ToTextureView) -> Drawing { self.a(primitive::Texture::new(view)) } /// Finish any drawings-in-progress and produce an iterator draining the inner draw commands /// and yielding them by value. - pub fn drain_commands(&self) -> impl Iterator> { + pub fn drain_commands(&self) -> impl Iterator { self.finish_remaining_drawings(); let cmds = { let mut state = self.state.borrow_mut(); @@ -614,7 +594,7 @@ where } } -impl Default for IntermediaryState { +impl Default for IntermediaryState { fn default() -> Self { let intermediary_mesh = Default::default(); let path_event_buffer = Default::default(); @@ -631,10 +611,7 @@ impl Default for IntermediaryState { } } -impl Default for State -where - S: BaseFloat, -{ +impl Default for State { fn default() -> Self { let last_draw_context = None; let background_color = Default::default(); @@ -653,24 +630,18 @@ where } } -impl Default for Draw -where - S: BaseFloat, -{ +impl Default for Draw { fn default() -> Self { - let state: Rc>> = Rc::new(RefCell::new(Default::default())); + let state: Rc> = Rc::new(RefCell::new(Default::default())); let context = Default::default(); Draw { state, context } } } -impl Default for Context -where - S: BaseFloat, -{ +impl Default for Context { fn default() -> Self { Self { - transform: Matrix4::identity(), + transform: Mat4::IDENTITY, blend: wgpu::BlendState { color: wgpu::RenderPipelineBuilder::DEFAULT_COLOR_BLEND, alpha: wgpu::RenderPipelineBuilder::DEFAULT_ALPHA_BLEND, diff --git a/nannou/src/draw/primitive/arrow.rs b/nannou/src/draw/primitive/arrow.rs index a943c2de3..1296c6409 100644 --- a/nannou/src/draw/primitive/arrow.rs +++ b/nannou/src/draw/primitive/arrow.rs @@ -5,24 +5,24 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{ColorScalar, SetColor, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; -use crate::geom::{self, pt2, vec2, Point2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom::{pt2, Point2}; +use crate::glam::vec2; use lyon::tessellation::StrokeOptions; /// A path containing only two points - a start and end. /// /// A triangle is drawn on the end to indicate direction. #[derive(Clone, Debug)] -pub struct Arrow { - line: Line, - head_length: Option, - head_width: Option, +pub struct Arrow { + line: Line, + head_length: Option, + head_width: Option, } /// The drawing context for a line. -pub type DrawingArrow<'a, S = geom::scalar::Default> = Drawing<'a, Arrow, S>; +pub type DrawingArrow<'a> = Drawing<'a, Arrow>; -impl Arrow { +impl Arrow { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.map_line(|l| l.weight(weight)) @@ -34,17 +34,17 @@ impl Arrow { } /// Specify the start point of the arrow. - pub fn start(self, start: Point2) -> Self { + pub fn start(self, start: Point2) -> Self { self.map_line(|l| l.start(start)) } /// Specify the end point of the arrow. - pub fn end(self, end: Point2) -> Self { + pub fn end(self, end: Point2) -> Self { self.map_line(|l| l.end(end)) } /// Specify the start and end points of the arrow. - pub fn points(self, start: Point2, end: Point2) -> Self { + pub fn points(self, start: Point2, end: Point2) -> Self { self.map_line(|l| l.points(start, end)) } @@ -53,7 +53,7 @@ impl Arrow { /// By default, this is equal to `weight * 4.0`. /// /// This value will be clamped to the length of the line itself. - pub fn head_length(mut self, length: S) -> Self { + pub fn head_length(mut self, length: f32) -> Self { self.head_length = Some(length); self } @@ -61,7 +61,7 @@ impl Arrow { /// The width of the arrow head. /// /// By default, this is equal to `weight * 2.0`. - pub fn head_width(mut self, width: S) -> Self { + pub fn head_width(mut self, width: f32) -> Self { self.head_width = Some(width); self } @@ -69,7 +69,7 @@ impl Arrow { // Map the inner `PathStroke` using the given function. fn map_line(self, map: F) -> Self where - F: FnOnce(Line) -> Line, + F: FnOnce(Line) -> Line, { let Arrow { line, @@ -85,10 +85,7 @@ impl Arrow { } } -impl<'a, S> DrawingArrow<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingArrow<'a> { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.map_ty(|ty| ty.weight(weight)) @@ -100,17 +97,17 @@ where } /// Specify the start point of the arrow. - pub fn start(self, start: Point2) -> Self { + pub fn start(self, start: Point2) -> Self { self.map_ty(|ty| ty.start(start)) } /// Specify the end point of the arrow. - pub fn end(self, end: Point2) -> Self { + pub fn end(self, end: Point2) -> Self { self.map_ty(|ty| ty.end(end)) } /// Specify the start and end points of the arrow. - pub fn points(self, start: Point2, end: Point2) -> Self { + pub fn points(self, start: Point2, end: Point2) -> Self { self.map_ty(|ty| ty.points(start, end)) } @@ -119,50 +116,50 @@ where /// By default, this is equal to `weight * 4.0`. /// /// This value will be clamped to the length of the line itself. - pub fn head_length(self, length: S) -> Self { + pub fn head_length(self, length: f32) -> Self { self.map_ty(|ty| ty.head_length(length)) } /// The width of the arrow head. /// /// By default, this is equal to `weight * 2.0`. - pub fn head_width(self, width: S) -> Self { + pub fn head_width(self, width: f32) -> Self { self.map_ty(|ty| ty.head_width(width)) } } -impl SetStroke for Arrow { +impl SetStroke for Arrow { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.line) } } -impl SetOrientation for Arrow { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Arrow { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.line) } } -impl SetPosition for Arrow { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Arrow { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.line) } } -impl SetColor for Arrow { +impl SetColor for Arrow { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.line) } } -impl From> for Primitive { - fn from(prim: Arrow) -> Self { +impl From for Primitive { + fn from(prim: Arrow) -> Self { Primitive::Arrow(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Arrow(prim) => Some(prim), _ => None, @@ -170,7 +167,7 @@ impl Into>> for Primitive { } } -impl draw::renderer::RenderPrimitive for Arrow { +impl draw::renderer::RenderPrimitive for Arrow { fn render_primitive( self, mut ctxt: draw::renderer::RenderContext, @@ -193,28 +190,28 @@ impl draw::renderer::RenderPrimitive for Arrow { let head_width = head_width.unwrap_or(line_w_2); let head_length = head_length.unwrap_or(line_w_4); let line_dir = end - start; - let line_dir_mag = line_dir.magnitude(); - let tri_len = head_length.min(line_dir_mag); - let tri_dir_norm = line_dir.with_magnitude(tri_len); + let line_dir_len = line_dir.length(); + let tri_len = head_length.min(line_dir_len); + let tri_dir_norm = line_dir.normalize() * tri_len; let tri_start = end - tri_dir_norm; let tri_end = end; let line_start = start; let line_end = tri_start; let tri_a = tri_end; - let tri_w_dir = vec2(-tri_dir_norm.y, tri_dir_norm.x).with_magnitude(head_width); + let tri_w_dir = vec2(-tri_dir_norm.y, tri_dir_norm.x).normalize() * head_width; let tri_b = tri_start + tri_w_dir; let tri_c = tri_start - tri_w_dir; // The line should only be drawn if there is space after drawing the triangle. - let draw_line = line_dir_mag > tri_len; + let draw_line = line_dir_len > tri_len; // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = line.path.position.transform() * line.path.orientation.transform(); let transform = global_transform * local_transform; // Draw the tri. let tri_points = [tri_a, tri_b, tri_c]; - let tri_points = tri_points.iter().cloned().map(Into::into); + let tri_points = tri_points.iter().cloned().map(|p| p.to_array().into()); let close_tri = true; let tri_events = lyon::path::iterator::FromPolyline::new(close_tri, tri_points); path::render_path_events( @@ -232,7 +229,7 @@ impl draw::renderer::RenderPrimitive for Arrow { // Draw the line. if draw_line { let line_points = [line_start, line_end]; - let line_points = line_points.iter().cloned().map(Into::into); + let line_points = line_points.iter().cloned().map(|p| p.to_array().into()); let close_line = false; let line_events = lyon::path::iterator::FromPolyline::new(close_line, line_points); path::render_path_events( @@ -252,10 +249,7 @@ impl draw::renderer::RenderPrimitive for Arrow { } } -impl Default for Arrow -where - S: Zero, -{ +impl Default for Arrow { fn default() -> Self { let line = Default::default(); let head_length = Default::default(); diff --git a/nannou/src/draw/primitive/ellipse.rs b/nannou/src/draw/primitive/ellipse.rs index 7a9ef998e..28a91fb43 100644 --- a/nannou/src/draw/primitive/ellipse.rs +++ b/nannou/src/draw/primitive/ellipse.rs @@ -7,27 +7,24 @@ use crate::draw::properties::{ spatial, ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::Drawing; -use crate::geom::{self, Vector2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom; +use crate::glam::Vec2; use lyon::tessellation::StrokeOptions; /// Properties related to drawing an **Ellipse**. -#[derive(Clone, Debug)] -pub struct Ellipse { - dimensions: spatial::dimension::Properties, - resolution: Option, - polygon: PolygonInit, +#[derive(Clone, Debug, Default)] +pub struct Ellipse { + dimensions: spatial::dimension::Properties, + resolution: Option, + polygon: PolygonInit, } /// The drawing context for an ellipse. -pub type DrawingEllipse<'a, S = geom::scalar::Default> = Drawing<'a, Ellipse, S>; +pub type DrawingEllipse<'a> = Drawing<'a, Ellipse>; // Ellipse-specific methods. -impl Ellipse -where - S: BaseFloat, -{ +impl Ellipse { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -37,8 +34,8 @@ where } /// Specify the width and height of the **Ellipse** via a given **radius**. - pub fn radius(self, radius: S) -> Self { - let side = radius * (S::one() + S::one()); + pub fn radius(self, radius: f32) -> Self { + let side = radius * 2.0; self.w_h(side, side) } @@ -46,7 +43,7 @@ where /// /// By default, ellipse does not use a resolution, but rather uses a stroke tolerance to /// determine how many vertices to use during tessellation. - pub fn resolution(mut self, resolution: usize) -> Self { + pub fn resolution(mut self, resolution: f32) -> Self { self.resolution = Some(resolution); self } @@ -54,7 +51,7 @@ where // Trait implementations. -impl draw::renderer::RenderPrimitive for Ellipse { +impl draw::renderer::RenderPrimitive for Ellipse { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -98,9 +95,9 @@ impl draw::renderer::RenderPrimitive for Ellipse { } } Some(resolution) => { - let rect = geom::Rect::from_wh(Vector2 { x: w, y: h }); + let rect = geom::Rect::from_w_h(w, h); let ellipse = geom::Ellipse::new(rect, resolution); - let points = ellipse.circumference(); + let points = ellipse.circumference().map(Vec2::from); polygon::render_points_themed( polygon.opts, points, @@ -115,68 +112,52 @@ impl draw::renderer::RenderPrimitive for Ellipse { } } -impl Default for Ellipse -where - S: Zero, -{ - fn default() -> Self { - let dimensions = Default::default(); - let polygon = Default::default(); - let resolution = Default::default(); - Ellipse { - dimensions, - polygon, - resolution, - } - } -} - -impl SetOrientation for Ellipse { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Ellipse { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.polygon) } } -impl SetPosition for Ellipse { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Ellipse { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.polygon) } } -impl SetDimensions for Ellipse { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Ellipse { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.dimensions) } } -impl SetColor for Ellipse { +impl SetColor for Ellipse { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.polygon) } } -impl SetStroke for Ellipse { +impl SetStroke for Ellipse { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.polygon) } } -impl SetPolygon for Ellipse { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for Ellipse { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { SetPolygon::polygon_options_mut(&mut self.polygon) } } // Primitive conversion. -impl From> for Primitive { - fn from(prim: Ellipse) -> Self { +impl From for Primitive { + fn from(prim: Ellipse) -> Self { Primitive::Ellipse(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Ellipse(prim) => Some(prim), _ => None, @@ -186,10 +167,7 @@ impl Into>> for Primitive { // Drawing methods. -impl<'a, S> DrawingEllipse<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingEllipse<'a> { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -199,12 +177,12 @@ where } /// Specify the width and height of the **Ellipse** via a given **radius**. - pub fn radius(self, radius: S) -> Self { + pub fn radius(self, radius: f32) -> Self { self.map_ty(|ty| ty.radius(radius)) } /// The number of sides used to draw the ellipse. - pub fn resolution(self, resolution: usize) -> Self { + pub fn resolution(self, resolution: f32) -> Self { self.map_ty(|ty| ty.resolution(resolution)) } } diff --git a/nannou/src/draw/primitive/line.rs b/nannou/src/draw/primitive/line.rs index c7c72a18f..b263c29e8 100644 --- a/nannou/src/draw/primitive/line.rs +++ b/nannou/src/draw/primitive/line.rs @@ -4,25 +4,24 @@ use crate::draw::primitive::{PathStroke, Primitive}; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{ColorScalar, SetColor, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; -use crate::geom::{self, pt2, Point2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom::{pt2, Point2}; use lyon::tessellation::StrokeOptions; /// A path containing only two points - a start and end. /// /// The usage of this type is almost identical to `PathStroke` but provides `start`, `end` and /// `points(a, b)` methods. -#[derive(Clone, Debug)] -pub struct Line { - pub path: PathStroke, - pub start: Option>, - pub end: Option>, +#[derive(Clone, Debug, Default)] +pub struct Line { + pub path: PathStroke, + pub start: Option, + pub end: Option, } /// The drawing context for a line. -pub type DrawingLine<'a, S = geom::scalar::Default> = Drawing<'a, Line, S>; +pub type DrawingLine<'a> = Drawing<'a, Line>; -impl Line { +impl Line { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.map_path(|p| p.stroke_weight(weight)) @@ -34,26 +33,26 @@ impl Line { } /// Specify the start point of the line. - pub fn start(mut self, start: Point2) -> Self { + pub fn start(mut self, start: Point2) -> Self { self.start = Some(start); self } /// Specify the end point of the line. - pub fn end(mut self, end: Point2) -> Self { + pub fn end(mut self, end: Point2) -> Self { self.end = Some(end); self } /// Specify the start and end points of the line. - pub fn points(self, start: Point2, end: Point2) -> Self { + pub fn points(self, start: Point2, end: Point2) -> Self { self.start(start).end(end) } // Map the inner `PathStroke` using the given function. fn map_path(self, map: F) -> Self where - F: FnOnce(PathStroke) -> PathStroke, + F: FnOnce(PathStroke) -> PathStroke, { let Line { path, start, end } = self; let path = map(path); @@ -61,10 +60,7 @@ impl Line { } } -impl<'a, S> DrawingLine<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingLine<'a> { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.map_ty(|ty| ty.weight(weight)) @@ -76,53 +72,53 @@ where } /// Specify the start point of the line. - pub fn start(self, start: Point2) -> Self { + pub fn start(self, start: Point2) -> Self { self.map_ty(|ty| ty.start(start)) } /// Specify the end point of the line. - pub fn end(self, end: Point2) -> Self { + pub fn end(self, end: Point2) -> Self { self.map_ty(|ty| ty.end(end)) } /// Specify the start and end points of the line. - pub fn points(self, start: Point2, end: Point2) -> Self { + pub fn points(self, start: Point2, end: Point2) -> Self { self.map_ty(|ty| ty.points(start, end)) } } -impl SetStroke for Line { +impl SetStroke for Line { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.path) } } -impl SetOrientation for Line { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Line { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.path) } } -impl SetPosition for Line { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Line { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.path) } } -impl SetColor for Line { +impl SetColor for Line { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.path) } } -impl From> for Primitive { - fn from(prim: Line) -> Self { +impl From for Primitive { + fn from(prim: Line) -> Self { Primitive::Line(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Line(prim) => Some(prim), _ => None, @@ -130,7 +126,7 @@ impl Into>> for Primitive { } } -impl draw::renderer::RenderPrimitive for Line { +impl draw::renderer::RenderPrimitive for Line { fn render_primitive( self, mut ctxt: draw::renderer::RenderContext, @@ -144,11 +140,11 @@ impl draw::renderer::RenderPrimitive for Line { } let close = false; let points = [start, end]; - let points = points.iter().cloned().map(Into::into); + let points = points.iter().cloned().map(|p| p.to_array().into()); let events = lyon::path::iterator::FromPolyline::new(close, points); // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = path.position.transform() * path.orientation.transform(); let transform = global_transform * local_transform; @@ -167,16 +163,3 @@ impl draw::renderer::RenderPrimitive for Line { draw::renderer::PrimitiveRender::default() } } - -impl Default for Line -where - S: Zero, -{ - fn default() -> Self { - Line { - path: Default::default(), - start: Default::default(), - end: Default::default(), - } - } -} diff --git a/nannou/src/draw/primitive/mesh.rs b/nannou/src/draw/primitive/mesh.rs index 2987c390b..bbf2c03fe 100644 --- a/nannou/src/draw/primitive/mesh.rs +++ b/nannou/src/draw/primitive/mesh.rs @@ -5,7 +5,6 @@ use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{ColorScalar, LinSrgba, SetColor, SetOrientation, SetPosition}; use crate::draw::{self, Drawing}; use crate::geom; -use crate::math::BaseFloat; use crate::wgpu; use std::ops; @@ -15,9 +14,9 @@ pub struct Vertexless; /// Properties related to drawing an arbitrary mesh of colours, geometry and texture. #[derive(Clone, Debug)] -pub struct Mesh { - position: position::Properties, - orientation: orientation::Properties, +pub struct Mesh { + position: position::Properties, + orientation: orientation::Properties, vertex_range: ops::Range, index_range: ops::Range, vertex_mode: draw::renderer::VertexMode, @@ -36,7 +35,7 @@ struct FlattenIndices { current: [usize; 3], } -pub type DrawingMesh<'a, S> = Drawing<'a, Mesh, S>; +pub type DrawingMesh<'a> = Drawing<'a, Mesh>; impl Vertexless { /// Describe the mesh with a sequence of textured points. @@ -45,17 +44,16 @@ impl Vertexless { /// coordinates in that order, e.g. `(point, tex_coords)`. `point` may be of any type that /// implements `Into` and `tex_coords` may be of any type that implements /// `Into`. - pub fn points_textured( + pub fn points_textured( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, texture_view: &dyn wgpu::ToTextureView, points: I, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { let points = points.into_iter().map(|(p, t)| { let point = p.into(); @@ -77,11 +75,10 @@ impl Vertexless { /// Each of the points must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoLinSrgba`. - pub fn points_colored(self, inner_mesh: &mut draw::Mesh, points: I) -> Mesh + pub fn points_colored(self, inner_mesh: &mut draw::Mesh, points: I) -> Mesh where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { let vertices = points.into_iter().map(|(p, c)| { @@ -101,11 +98,10 @@ impl Vertexless { /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn points(self, inner_mesh: &mut draw::Mesh, points: I) -> Mesh + pub fn points(self, inner_mesh: &mut draw::Mesh, points: I) -> Mesh where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { let vertices = points.into_iter().map(|p| { let point = p.into(); @@ -119,16 +115,15 @@ impl Vertexless { mesh } - fn points_inner( + fn points_inner( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, vertices: I, vertex_mode: draw::renderer::VertexMode, texture_view: Option, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, - I: Iterator>, + I: Iterator, { let v_start = inner_mesh.points().len(); let i_start = inner_mesh.indices().len(); @@ -147,17 +142,16 @@ impl Vertexless { /// coordinates in that order, e.g. `(point, tex_coords)`. `point` may be of any type that /// implements `Into` and `tex_coords` may be of any type that implements /// `Into`. - pub fn tris_textured( + pub fn tris_textured( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, texture_view: &dyn wgpu::ToTextureView, tris: I, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, I: IntoIterator>, - P: Into>, - T: Into>, + P: Into, + T: Into, { let points = tris .into_iter() @@ -171,11 +165,10 @@ impl Vertexless { /// Each of the vertices must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements `Into` /// and `color` may be of any type that implements `IntoLinSrgba`. - pub fn tris_colored(self, inner_mesh: &mut draw::Mesh, tris: I) -> Mesh + pub fn tris_colored(self, inner_mesh: &mut draw::Mesh, tris: I) -> Mesh where - S: BaseFloat, I: IntoIterator>, - P: Into>, + P: Into, C: IntoLinSrgba, { let points = tris @@ -193,11 +186,10 @@ impl Vertexless { /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn tris(self, inner_mesh: &mut draw::Mesh, tris: I) -> Mesh + pub fn tris(self, inner_mesh: &mut draw::Mesh, tris: I) -> Mesh where - S: BaseFloat, I: IntoIterator>, - V: Into>, + V: Into, { let points = tris .into_iter() @@ -214,19 +206,18 @@ impl Vertexless { /// coordinates in that order, e.g. `(point, tex_coords)`. `point` may be of any type that /// implements `Into` and `tex_coords` may be of any type that implements /// `Into`. - pub fn indexed_textured( + pub fn indexed_textured( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, texture_view: &dyn wgpu::ToTextureView, points: V, indices: I, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, V: IntoIterator, I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { let vertices = points.into_iter().map(|(p, t)| { let point = p.into(); @@ -251,17 +242,16 @@ impl Vertexless { /// Each of the `points` must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoLinSrgba`. - pub fn indexed_colored( + pub fn indexed_colored( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, points: V, indices: I, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, V: IntoIterator, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { let vertices = points.into_iter().map(|(p, c)| { @@ -279,11 +269,10 @@ impl Vertexless { /// Each trio of `indices` describes a single triangle made up of `points`. /// /// Each point may be any type that may be converted directly into the `Point3` type. - pub fn indexed(self, inner_mesh: &mut draw::Mesh, points: V, indices: I) -> Mesh + pub fn indexed(self, inner_mesh: &mut draw::Mesh, points: V, indices: I) -> Mesh where - S: BaseFloat, V: IntoIterator, - V::Item: Into>, + V::Item: Into, I: IntoIterator, { let vertices = points.into_iter().map(|p| { @@ -298,17 +287,16 @@ impl Vertexless { mesh } - fn indexed_inner( + fn indexed_inner( self, - inner_mesh: &mut draw::Mesh, + inner_mesh: &mut draw::Mesh, vertices: V, indices: I, vertex_mode: draw::renderer::VertexMode, texture_view: Option, - ) -> Mesh + ) -> Mesh where - S: BaseFloat, - V: IntoIterator>, + V: IntoIterator, I: IntoIterator, { let v_start = inner_mesh.points().len(); @@ -321,10 +309,7 @@ impl Vertexless { } } -impl Mesh -where - S: BaseFloat, -{ +impl Mesh { // Initialise a new `Mesh` with its ranges into the intermediary mesh, ready for drawing. fn new( vertex_range: ops::Range, @@ -347,10 +332,7 @@ where } } -impl<'a, S> Drawing<'a, Vertexless, S> -where - S: BaseFloat, -{ +impl<'a> Drawing<'a, Vertexless> { /// Describe the mesh with a sequence of points. /// /// The given iterator may yield any type that can be converted directly into `Point3`s. @@ -358,10 +340,10 @@ where /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn points(self, points: I) -> DrawingMesh<'a, S> + pub fn points(self, points: I) -> DrawingMesh<'a> where I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.map_ty_with_context(|ty, ctxt| ty.points(ctxt.mesh, points)) } @@ -371,10 +353,10 @@ where /// Each of the points must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoLinSrgba`. - pub fn points_colored(self, points: I) -> DrawingMesh<'a, S> + pub fn points_colored(self, points: I) -> DrawingMesh<'a> where I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.points_colored(ctxt.mesh, points)) @@ -390,11 +372,11 @@ where self, view: &dyn wgpu::ToTextureView, points: I, - ) -> DrawingMesh<'a, S> + ) -> DrawingMesh<'a> where I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { self.map_ty_with_context(|ty, ctxt| ty.points_textured(ctxt.mesh, view, points)) } @@ -407,10 +389,10 @@ where /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn tris(self, tris: I) -> DrawingMesh<'a, S> + pub fn tris(self, tris: I) -> DrawingMesh<'a> where I: IntoIterator>, - V: Into>, + V: Into, { self.map_ty_with_context(|ty, ctxt| ty.tris(ctxt.mesh, tris)) } @@ -420,10 +402,10 @@ where /// Each of the vertices must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements `Into` /// and `color` may be of any type that implements `IntoLinSrgba`. - pub fn tris_colored(self, tris: I) -> DrawingMesh<'a, S> + pub fn tris_colored(self, tris: I) -> DrawingMesh<'a> where I: IntoIterator>, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.tris_colored(ctxt.mesh, tris)) @@ -435,15 +417,11 @@ where /// coordinates in that order, e.g. `(point, tex_coords)`. `point` may be of any type that /// implements `Into` and `tex_coords` may be of any type that implements /// `Into`. - pub fn tris_textured( - self, - view: &dyn wgpu::ToTextureView, - tris: I, - ) -> DrawingMesh<'a, S> + pub fn tris_textured(self, view: &dyn wgpu::ToTextureView, tris: I) -> DrawingMesh<'a> where I: IntoIterator>, - P: Into>, - T: Into>, + P: Into, + T: Into, { self.map_ty_with_context(|ty, ctxt| ty.tris_textured(ctxt.mesh, view, tris)) } @@ -453,10 +431,10 @@ where /// Each trio of `indices` describes a single triangle made up of `points`. /// /// Each point may be any type that may be converted directly into the `Point3` type. - pub fn indexed(self, points: V, indices: I) -> DrawingMesh<'a, S> + pub fn indexed(self, points: V, indices: I) -> DrawingMesh<'a> where V: IntoIterator, - V::Item: Into>, + V::Item: Into, I: IntoIterator, { self.map_ty_with_context(|ty, ctxt| ty.indexed(ctxt.mesh, points, indices)) @@ -469,11 +447,11 @@ where /// Each of the `points` must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoLinSrgba`. - pub fn indexed_colored(self, points: V, indices: I) -> DrawingMesh<'a, S> + pub fn indexed_colored(self, points: V, indices: I) -> DrawingMesh<'a> where V: IntoIterator, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.indexed_colored(ctxt.mesh, points, indices)) @@ -492,18 +470,18 @@ where view: &dyn wgpu::ToTextureView, points: V, indices: I, - ) -> DrawingMesh<'a, S> + ) -> DrawingMesh<'a> where V: IntoIterator, I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { self.map_ty_with_context(|ty, ctxt| ty.indexed_textured(ctxt.mesh, view, points, indices)) } } -impl draw::renderer::RenderPrimitive for Mesh { +impl draw::renderer::RenderPrimitive for Mesh { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -520,7 +498,7 @@ impl draw::renderer::RenderPrimitive for Mesh { } = self; // Determine the transform to apply to vertices. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = position.transform() * orientation.transform(); let transform = global_transform * local_transform; @@ -532,11 +510,7 @@ impl draw::renderer::RenderPrimitive for Mesh { .map(|i| new_mesh_vertex_start + i - old_mesh_vertex_start); // A small function for transforming a point via the transform matrix. - let transform_point = |p: geom::Point3| -> geom::Point3 { - let p = cgmath::Point3::new(p.x, p.y, p.z); - let p = cgmath::Transform::transform_point(&transform, p); - p.into() - }; + let transform_point = |p: geom::Point3| -> geom::Point3 { transform.transform_point3(p) }; // Color the vertices based on whether or not we should fill, then extend the mesh! match fill_color { @@ -593,37 +567,37 @@ where } } -impl SetOrientation for Mesh { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Mesh { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.orientation) } } -impl SetPosition for Mesh { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Mesh { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.position) } } -impl SetColor for Mesh { +impl SetColor for Mesh { fn rgba_mut(&mut self) -> &mut Option { &mut self.fill_color.get_or_insert_with(Default::default).0 } } -impl From for Primitive { +impl From for Primitive { fn from(prim: Vertexless) -> Self { Primitive::MeshVertexless(prim) } } -impl From> for Primitive { - fn from(prim: Mesh) -> Self { +impl From for Primitive { + fn from(prim: Mesh) -> Self { Primitive::Mesh(prim) } } -impl Into> for Primitive { +impl Into> for Primitive { fn into(self) -> Option { match self { Primitive::MeshVertexless(prim) => Some(prim), @@ -632,8 +606,8 @@ impl Into> for Primitive { } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Mesh(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/mod.rs b/nannou/src/draw/primitive/mod.rs index a73748535..60272a10f 100644 --- a/nannou/src/draw/primitive/mod.rs +++ b/nannou/src/draw/primitive/mod.rs @@ -10,8 +10,6 @@ pub mod text; pub mod texture; pub mod tri; -use crate::geom; - pub use self::arrow::Arrow; pub use self::ellipse::Ellipse; pub use self::line::Line; @@ -30,21 +28,21 @@ pub use self::tri::Tri; /// This also allows us to flush all pending drawings to the mesh if `Draw::to_frame` is called /// before their respective **Drawing** types are dropped. #[derive(Clone, Debug)] -pub enum Primitive { - Arrow(Arrow), - Ellipse(Ellipse), - Line(Line), +pub enum Primitive { + Arrow(Arrow), + Ellipse(Ellipse), + Line(Line), MeshVertexless(mesh::Vertexless), - Mesh(Mesh), - PathInit(PathInit), - PathFill(PathFill), - PathStroke(PathStroke), - Path(Path), - PolygonInit(PolygonInit), - Polygon(Polygon), - Quad(Quad), - Rect(Rect), - Text(Text), - Texture(Texture), - Tri(Tri), + Mesh(Mesh), + PathInit(PathInit), + PathFill(PathFill), + PathStroke(PathStroke), + Path(Path), + PolygonInit(PolygonInit), + Polygon(Polygon), + Quad(Quad), + Rect(Rect), + Text(Text), + Texture(Texture), + Tri(Tri), } diff --git a/nannou/src/draw/primitive/path.rs b/nannou/src/draw/primitive/path.rs index 38d9d8aba..8ee422876 100644 --- a/nannou/src/draw/primitive/path.rs +++ b/nannou/src/draw/primitive/path.rs @@ -7,8 +7,8 @@ use crate::draw::properties::{ ColorScalar, SetColor, SetFill, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing, DrawingContext}; -use crate::geom::{self, Point2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom::Point2; +use crate::glam::Mat4; use crate::wgpu; use lyon::path::PathEvent; use lyon::tessellation::{FillOptions, FillTessellator, StrokeOptions, StrokeTessellator}; @@ -51,16 +51,16 @@ pub(crate) enum PathEventSourceIter<'a> { /// The beginning of the path building process, prior to choosing the tessellation mode (fill or /// stroke). -#[derive(Clone, Debug)] -pub struct PathInit(std::marker::PhantomData); +#[derive(Clone, Debug, Default)] +pub struct PathInit; /// A path drawing context ready to specify tessellation options. -#[derive(Clone, Debug)] -pub struct PathOptions { +#[derive(Clone, Debug, Default)] +pub struct PathOptions { pub(crate) opts: T, pub(crate) color: Option, - pub(crate) position: position::Properties, - pub(crate) orientation: orientation::Properties, + pub(crate) position: position::Properties, + pub(crate) orientation: orientation::Properties, } /// Mutable access to stroke and fill tessellators. @@ -70,17 +70,17 @@ pub struct Tessellators<'a> { } /// A filled path drawing context. -pub type PathFill = PathOptions; +pub type PathFill = PathOptions; /// A stroked path drawing context. -pub type PathStroke = PathOptions; +pub type PathStroke = PathOptions; /// Properties related to drawing a **Path**. #[derive(Clone, Debug)] -pub struct Path { +pub struct Path { color: Option, - position: position::Properties, - orientation: orientation::Properties, + position: position::Properties, + orientation: orientation::Properties, path_event_src: PathEventSource, options: Options, vertex_mode: draw::renderer::VertexMode, @@ -88,19 +88,19 @@ pub struct Path { } /// The initial drawing context for a path. -pub type DrawingPathInit<'a, S = geom::scalar::Default> = Drawing<'a, PathInit, S>; +pub type DrawingPathInit<'a> = Drawing<'a, PathInit>; /// The drawing context for a path in the tessellation options state. -pub type DrawingPathOptions<'a, T, S = geom::scalar::Default> = Drawing<'a, PathOptions, S>; +pub type DrawingPathOptions<'a, T> = Drawing<'a, PathOptions>; /// The drawing context for a stroked path, prior to path event submission. -pub type DrawingPathStroke<'a, S = geom::scalar::Default> = Drawing<'a, PathStroke, S>; +pub type DrawingPathStroke<'a> = Drawing<'a, PathStroke>; /// The drawing context for a filled path, prior to path event submission. -pub type DrawingPathFill<'a, S = geom::scalar::Default> = Drawing<'a, PathFill, S>; +pub type DrawingPathFill<'a> = Drawing<'a, PathFill>; /// The drawing context for a polyline whose vertices have been specified. -pub type DrawingPath<'a, S = geom::scalar::Default> = Drawing<'a, Path, S>; +pub type DrawingPath<'a> = Drawing<'a, Path>; /// Dynamically distinguish between fill and stroke tessellation options. #[derive(Clone, Debug)] @@ -109,14 +109,11 @@ pub enum Options { Stroke(StrokeOptions), } -impl PathInit { +impl PathInit { /// Specify that we want to use fill tessellation for the path. /// /// The returned building context allows for specifying the fill tessellation options. - pub fn fill(self) -> PathFill - where - S: Zero, - { + pub fn fill(self) -> PathFill { let opts = FillOptions::default(); PathFill::new(opts) } @@ -124,19 +121,13 @@ impl PathInit { /// Specify that we want to use stroke tessellation for the path. /// /// The returned building context allows for specifying the stroke tessellation options. - pub fn stroke(self) -> PathStroke - where - S: Zero, - { + pub fn stroke(self) -> PathStroke { let opts = Default::default(); PathStroke::new(opts) } } -impl PathOptions -where - S: Zero, -{ +impl PathOptions { /// Initialise the `PathOptions` builder. pub fn new(opts: T) -> Self { let orientation = Default::default(); @@ -151,7 +142,7 @@ where } } -impl PathFill { +impl PathFill { /// Maximum allowed distance to the path when building an approximation. /// /// This method is shorthand for the `fill_tolerance` method. @@ -169,7 +160,7 @@ impl PathFill { } } -impl PathStroke { +impl PathStroke { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.stroke_weight(weight) @@ -181,14 +172,13 @@ impl PathStroke { } } -impl PathOptions +impl PathOptions where T: TessellationOptions, { /// Submit the path events to be tessellated. - pub(crate) fn events(self, ctxt: DrawingContext, events: I) -> Path + pub(crate) fn events(self, ctxt: DrawingContext, events: I) -> Path where - S: BaseFloat, I: IntoIterator, { let DrawingContext { @@ -209,11 +199,10 @@ where } /// Consumes an iterator of points and converts them to an iterator yielding path events. - pub fn points(self, ctxt: DrawingContext, points: I) -> Path + pub fn points(self, ctxt: DrawingContext, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.points_inner(ctxt, false, points) } @@ -221,32 +210,29 @@ where /// Consumes an iterator of points and converts them to an iterator yielding path events. /// /// Closes the start and end points. - pub fn points_closed(self, ctxt: DrawingContext, points: I) -> Path + pub fn points_closed(self, ctxt: DrawingContext, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.points_inner(ctxt, true, points) } /// Submit path events as a polyline of colored points. - pub fn points_colored(self, ctxt: DrawingContext, points: I) -> Path + pub fn points_colored(self, ctxt: DrawingContext, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.points_colored_inner(ctxt, false, points) } /// Submit path events as a polyline of colored points. - pub fn points_colored_closed(self, ctxt: DrawingContext, points: I) -> Path + pub fn points_colored_closed(self, ctxt: DrawingContext, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.points_colored_inner(ctxt, true, points) @@ -255,15 +241,14 @@ where /// Submit path events as a polyline of textured points. pub fn points_textured( self, - ctxt: DrawingContext, + ctxt: DrawingContext, texture_view: &dyn wgpu::ToTextureView, points: I, - ) -> Path + ) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, - TC: Into>, + P: Into, + TC: Into, { self.points_textured_inner(ctxt, texture_view.to_texture_view(), false, points) } @@ -271,45 +256,37 @@ where /// Submit path events as a polyline of textured points. pub fn points_textured_closed( self, - ctxt: DrawingContext, + ctxt: DrawingContext, texture_view: &dyn wgpu::ToTextureView, points: I, - ) -> Path + ) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, - TC: Into>, + P: Into, + TC: Into, { self.points_textured_inner(ctxt, texture_view.to_texture_view(), true, points) } // Consumes an iterator of points and converts them to an iterator yielding events. - fn points_inner(self, ctxt: DrawingContext, close: bool, points: I) -> Path + fn points_inner(self, ctxt: DrawingContext, close: bool, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { - let iter = points.into_iter().map(Into::into).map(|p| { - let p: geom::Point2 = p.cast().expect("failed to cast point"); - lyon::math::point(p.x, p.y) - }); + let iter = points + .into_iter() + .map(Into::into) + .map(|p| lyon::math::point(p.x, p.y)); let events = lyon::path::iterator::FromPolyline::new(close, iter); self.events(ctxt, events) } // Consumes an iterator of points and converts them to an iterator yielding events. - fn points_colored_inner( - self, - ctxt: DrawingContext, - close: bool, - points: I, - ) -> Path + fn points_colored_inner(self, ctxt: DrawingContext, close: bool, points: I) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { let DrawingContext { @@ -340,16 +317,15 @@ where // Consumes an iterator of textured points and buffers them for rendering. fn points_textured_inner( self, - ctxt: DrawingContext, + ctxt: DrawingContext, texture_view: wgpu::TextureView, close: bool, points: I, - ) -> Path + ) -> Path where - S: BaseFloat, I: IntoIterator, - P: Into>, - TC: Into>, + P: Into, + TC: Into, { let DrawingContext { path_points_textured_buffer, @@ -378,7 +354,7 @@ where pub(crate) fn render_path_events( events: I, color: Option, - transform: cgmath::Matrix4, + transform: Mat4, options: Options, theme: &draw::Theme, theme_prim: &draw::theme::Primitive, @@ -408,7 +384,7 @@ pub(crate) fn render_path_events( pub(crate) fn render_path_points_colored( points_colored: I, close: bool, - transform: cgmath::Matrix4, + transform: Mat4, options: Options, fill_tessellator: &mut lyon::tessellation::FillTessellator, stroke_tessellator: &mut lyon::tessellation::StrokeTessellator, @@ -447,7 +423,7 @@ pub(crate) fn render_path_points_colored( pub(crate) fn render_path_points_textured( points_textured: I, close: bool, - transform: cgmath::Matrix4, + transform: Mat4, options: Options, fill_tessellator: &mut lyon::tessellation::FillTessellator, stroke_tessellator: &mut lyon::tessellation::StrokeTessellator, @@ -487,7 +463,7 @@ pub(crate) fn render_path_source( // TODO: path_src: PathEventSourceIter, color: Option, - transform: cgmath::Matrix4, + transform: Mat4, options: Options, theme: &draw::Theme, theme_prim: &draw::theme::Primitive, @@ -528,7 +504,7 @@ pub(crate) fn render_path_source( } } -impl draw::renderer::RenderPrimitive for Path { +impl draw::renderer::RenderPrimitive for Path { fn render_primitive( self, mut ctxt: draw::renderer::RenderContext, @@ -545,7 +521,7 @@ impl draw::renderer::RenderPrimitive for Path { } = self; // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = position.transform() * orientation.transform(); let transform = global_transform * local_transform; @@ -626,13 +602,13 @@ where // Begin the path. let mut iter = points_colored.into_iter(); let (first_point, first_color) = iter.next()?; - let p = first_point.into(); + let p = first_point.to_array().into(); let (r, g, b, a) = first_color.into(); path_builder.move_to(p, &[r, g, b, a]); // Add the lines, keeping track of the last for (point, color) in iter { - let p = point.into(); + let p = point.to_array().into(); let (r, g, b, a) = color.into(); path_builder.line_to(p, &[r, g, b, a]); } @@ -658,13 +634,13 @@ where // Begin the path. let mut iter = points_textured.into_iter(); let (first_point, first_tex_coords) = iter.next()?; - let p = first_point.into(); + let p = first_point.to_array().into(); let (tc_x, tc_y) = first_tex_coords.into(); path_builder.move_to(p, &[tc_x, tc_y]); // Add the lines, keeping track of the last for (point, tex_coords) in iter { - let p = point.into(); + let p = point.to_array().into(); let (tc_x, tc_y) = tex_coords.into(); path_builder.line_to(p, &[tc_x, tc_y]); } @@ -678,14 +654,11 @@ where Some(path_builder.build()) } -impl Path -where - S: BaseFloat, -{ +impl Path { // Initialise a new `Path` with its ranges into the intermediary mesh, ready for drawing. fn new( - position: position::Properties, - orientation: orientation::Properties, + position: position::Properties, + orientation: orientation::Properties, color: Option, path_event_src: PathEventSource, options: Options, @@ -704,29 +677,23 @@ where } } -impl<'a, S> DrawingPathInit<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingPathInit<'a> { /// Specify that we want to use fill tessellation for the path. /// /// The returned building context allows for specifying the fill tessellation options. - pub fn fill(self) -> DrawingPathFill<'a, S> { + pub fn fill(self) -> DrawingPathFill<'a> { self.map_ty(|ty| ty.fill()) } /// Specify that we want to use stroke tessellation for the path. /// /// The returned building context allows for specifying the stroke tessellation options. - pub fn stroke(self) -> DrawingPathStroke<'a, S> { + pub fn stroke(self) -> DrawingPathStroke<'a> { self.map_ty(|ty| ty.stroke()) } } -impl<'a, S> DrawingPathFill<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingPathFill<'a> { /// Maximum allowed distance to the path when building an approximation. pub fn tolerance(self, tolerance: f32) -> Self { self.map_ty(|ty| ty.tolerance(tolerance)) @@ -740,10 +707,7 @@ where } } -impl<'a, S> DrawingPathStroke<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingPathStroke<'a> { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { self.map_ty(|ty| ty.stroke_weight(weight)) @@ -755,15 +719,14 @@ where } } -impl<'a, T, S> DrawingPathOptions<'a, T, S> +impl<'a, T> DrawingPathOptions<'a, T> where - S: BaseFloat, T: TessellationOptions, - PathOptions: Into>, - Primitive: Into>>, + PathOptions: Into, + Primitive: Into>>, { /// Submit the path events to be tessellated. - pub fn events(self, events: I) -> DrawingPath<'a, S> + pub fn events(self, events: I) -> DrawingPath<'a> where I: IntoIterator, { @@ -771,10 +734,10 @@ where } /// Submit the path events as a polyline of points. - pub fn points(self, points: I) -> DrawingPath<'a, S> + pub fn points(self, points: I) -> DrawingPath<'a> where I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.map_ty_with_context(|ty, ctxt| ty.points(ctxt, points)) } @@ -782,20 +745,19 @@ where /// Submit the path events as a polyline of points. /// /// An event will be generated that closes the start and end points. - pub fn points_closed(self, points: I) -> DrawingPath<'a, S> + pub fn points_closed(self, points: I) -> DrawingPath<'a> where I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.map_ty_with_context(|ty, ctxt| ty.points_closed(ctxt, points)) } /// Submit path events as a polyline of colored points. - pub fn points_colored(self, points: I) -> DrawingPath<'a, S> + pub fn points_colored(self, points: I) -> DrawingPath<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.points_colored(ctxt, points)) @@ -804,11 +766,10 @@ where /// Submit path events as a polyline of colored points. /// /// The path with automatically close from the end point to the start point. - pub fn points_colored_closed(self, points: I) -> DrawingPath<'a, S> + pub fn points_colored_closed(self, points: I) -> DrawingPath<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.points_colored_closed(ctxt, points)) @@ -819,12 +780,11 @@ where self, view: &dyn wgpu::ToTextureView, points: I, - ) -> DrawingPath<'a, S> + ) -> DrawingPath<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, - TC: Into>, + P: Into, + TC: Into, { self.map_ty_with_context(|ty, ctxt| ty.points_textured(ctxt, view, points)) } @@ -836,24 +796,23 @@ where self, view: &dyn wgpu::ToTextureView, points: I, - ) -> DrawingPath<'a, S> + ) -> DrawingPath<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, - TC: Into>, + P: Into, + TC: Into, { self.map_ty_with_context(|ty, ctxt| ty.points_textured_closed(ctxt, view, points)) } } -impl SetFill for PathFill { +impl SetFill for PathFill { fn fill_options_mut(&mut self) -> &mut FillOptions { &mut self.opts } } -impl SetStroke for PathStroke { +impl SetStroke for PathStroke { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { &mut self.opts } @@ -873,85 +832,68 @@ impl TessellationOptions for StrokeOptions { } } -impl Default for PathInit { - fn default() -> Self { - PathInit(std::marker::PhantomData) - } -} - -impl Default for PathOptions -where - S: Zero, - T: Default, -{ - fn default() -> Self { - let opts = Default::default(); - PathOptions::new(opts) - } -} - -impl SetOrientation for PathOptions { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for PathOptions { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.orientation) } } -impl SetPosition for PathOptions { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for PathOptions { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.position) } } -impl SetColor for PathOptions { +impl SetColor for PathOptions { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.color) } } -impl SetOrientation for Path { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Path { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.orientation) } } -impl SetPosition for Path { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Path { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.position) } } -impl SetColor for Path { +impl SetColor for Path { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.color) } } -impl From> for Primitive { - fn from(prim: PathInit) -> Self { +impl From for Primitive { + fn from(prim: PathInit) -> Self { Primitive::PathInit(prim) } } -impl From> for Primitive { - fn from(prim: PathStroke) -> Self { +impl From for Primitive { + fn from(prim: PathStroke) -> Self { Primitive::PathStroke(prim) } } -impl From> for Primitive { - fn from(prim: PathFill) -> Self { +impl From for Primitive { + fn from(prim: PathFill) -> Self { Primitive::PathFill(prim) } } -impl From> for Primitive { - fn from(prim: Path) -> Self { +impl From for Primitive { + fn from(prim: Path) -> Self { Primitive::Path(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::PathInit(prim) => Some(prim), _ => None, @@ -959,8 +901,8 @@ impl Into>> for Primitive { } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::PathFill(prim) => Some(prim), _ => None, @@ -968,8 +910,8 @@ impl Into>> for Primitive { } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::PathStroke(prim) => Some(prim), _ => None, @@ -977,8 +919,8 @@ impl Into>> for Primitive { } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Path(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/polygon.rs b/nannou/src/draw/primitive/polygon.rs index ac2a018f2..754cf71e9 100644 --- a/nannou/src/draw/primitive/polygon.rs +++ b/nannou/src/draw/primitive/polygon.rs @@ -8,16 +8,15 @@ use crate::draw::properties::{ ColorScalar, LinSrgba, SetColor, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing}; -use crate::geom::{self, Point2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom::Point2; use crate::wgpu; use lyon::path::PathEvent; use lyon::tessellation::StrokeOptions; /// A trait implemented for all polygon draw primitives. -pub trait SetPolygon: Sized { +pub trait SetPolygon: Sized { /// Access to the polygon builder parameters. - fn polygon_options_mut(&mut self) -> &mut PolygonOptions; + fn polygon_options_mut(&mut self) -> &mut PolygonOptions; /// Specify no fill color and in turn no fill tessellation for the polygon. fn no_fill(mut self) -> Self { @@ -38,23 +37,23 @@ pub trait SetPolygon: Sized { } /// Specify the whole set of polygon options. - fn polygon_options(mut self, opts: PolygonOptions) -> Self { + fn polygon_options(mut self, opts: PolygonOptions) -> Self { *self.polygon_options_mut() = opts; self } } /// State related to drawing a **Polygon**. -#[derive(Clone, Debug)] -pub struct PolygonInit { - pub(crate) opts: PolygonOptions, +#[derive(Clone, Debug, Default)] +pub struct PolygonInit { + pub(crate) opts: PolygonOptions, } /// The set of options shared by all polygon types. -#[derive(Clone, Debug)] -pub struct PolygonOptions { - pub position: position::Properties, - pub orientation: orientation::Properties, +#[derive(Clone, Debug, Default)] +pub struct PolygonOptions { + pub position: position::Properties, + pub orientation: orientation::Properties, pub no_fill: bool, pub stroke_color: Option, pub color: Option, @@ -63,19 +62,19 @@ pub struct PolygonOptions { /// A polygon with vertices already submitted. #[derive(Clone, Debug)] -pub struct Polygon { - opts: PolygonOptions, +pub struct Polygon { + opts: PolygonOptions, path_event_src: PathEventSource, texture_view: Option, } /// Initialised drawing state for a polygon. -pub type DrawingPolygonInit<'a, S = geom::scalar::Default> = Drawing<'a, PolygonInit, S>; +pub type DrawingPolygonInit<'a> = Drawing<'a, PolygonInit>; /// Initialised drawing state for a polygon. -pub type DrawingPolygon<'a, S = geom::scalar::Default> = Drawing<'a, Polygon, S>; +pub type DrawingPolygon<'a> = Drawing<'a, Polygon>; -impl PolygonInit { +impl PolygonInit { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -85,9 +84,8 @@ impl PolygonInit { } /// Submit the path events to be tessellated. - pub(crate) fn events(self, ctxt: DrawingContext, events: I) -> Polygon + pub(crate) fn events(self, ctxt: DrawingContext, events: I) -> Polygon where - S: BaseFloat, I: IntoIterator, { let DrawingContext { @@ -104,15 +102,14 @@ impl PolygonInit { } /// Consumes an iterator of points and converts them to an iterator yielding path events. - pub fn points(self, ctxt: DrawingContext, points: I) -> Polygon + pub fn points(self, ctxt: DrawingContext, points: I) -> Polygon where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { let points = points.into_iter().map(|p| { - let p: Point2 = p.into().cast().expect("failed to cast point"); - p.into() + let p: Point2 = p.into(); + p.to_array().into() }); let close = true; let events = lyon::path::iterator::FromPolyline::new(close, points); @@ -120,11 +117,10 @@ impl PolygonInit { } /// Consumes an iterator of points and converts them to an iterator yielding path events. - pub fn points_colored(self, ctxt: DrawingContext, points: I) -> Polygon + pub fn points_colored(self, ctxt: DrawingContext, points: I) -> Polygon where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { let DrawingContext { @@ -150,15 +146,14 @@ impl PolygonInit { /// Consumes an iterator of points and converts them to an iterator yielding path events. pub fn points_textured( self, - ctxt: DrawingContext, + ctxt: DrawingContext, view: &dyn wgpu::ToTextureView, points: I, - ) -> Polygon + ) -> Polygon where - S: BaseFloat, I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { let DrawingContext { path_points_textured_buffer, @@ -199,7 +194,7 @@ pub fn render_events_themed( } = opts; // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = position.transform() * orientation.transform(); let transform = global_transform * local_transform; @@ -260,14 +255,14 @@ pub fn render_points_themed( { render_events_themed( opts, - || lyon::path::iterator::FromPolyline::closed(points.clone().map(|p| p.into())), + || lyon::path::iterator::FromPolyline::closed(points.clone().map(|p| p.to_array().into())), ctxt, theme_primitive, mesh, ); } -impl Polygon { +impl Polygon { pub(crate) fn render_themed( self, ctxt: draw::renderer::RenderContext, @@ -299,7 +294,7 @@ impl Polygon { } = ctxt; // Determine the transform to apply to all points. - let global_transform = transform; + let global_transform = *transform; let local_transform = position.transform() * orientation.transform(); let transform = global_transform * local_transform; @@ -439,7 +434,7 @@ impl Polygon { } } -impl draw::renderer::RenderPrimitive for Polygon { +impl draw::renderer::RenderPrimitive for Polygon { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -449,11 +444,10 @@ impl draw::renderer::RenderPrimitive for Polygon { } } -impl<'a, S, T> Drawing<'a, T, S> +impl<'a, T> Drawing<'a, T> where - S: BaseFloat, - T: SetPolygon + Into>, - Primitive: Into>, + T: SetPolygon + Into, + Primitive: Into>, { /// Specify no fill color and in turn no fill tessellation for the polygon. pub fn no_fill(self) -> Self { @@ -472,15 +466,12 @@ where } /// Specify the whole set of polygon options. - pub fn polygon_options(self, opts: PolygonOptions) -> Self { + pub fn polygon_options(self, opts: PolygonOptions) -> Self { self.map_ty(|ty| ty.polygon_options(opts)) } } -impl<'a, S> DrawingPolygonInit<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingPolygonInit<'a> { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -490,30 +481,27 @@ where } /// Describe the polygon with a sequence of path events. - pub fn events(self, events: I) -> DrawingPolygon<'a, S> + pub fn events(self, events: I) -> DrawingPolygon<'a> where - S: BaseFloat, I: IntoIterator, { self.map_ty_with_context(|ty, ctxt| ty.events(ctxt, events)) } /// Describe the polygon with a sequence of points. - pub fn points(self, points: I) -> DrawingPolygon<'a, S> + pub fn points(self, points: I) -> DrawingPolygon<'a> where - S: BaseFloat, I: IntoIterator, - I::Item: Into>, + I::Item: Into, { self.map_ty_with_context(|ty, ctxt| ty.points(ctxt, points)) } /// Consumes an iterator of points and converts them to an iterator yielding path events. - pub fn points_colored(self, points: I) -> DrawingPolygon<'a, S> + pub fn points_colored(self, points: I) -> DrawingPolygon<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, + P: Into, C: IntoLinSrgba, { self.map_ty_with_context(|ty, ctxt| ty.points_colored(ctxt, points)) @@ -524,117 +512,84 @@ where self, view: &dyn wgpu::ToTextureView, points: I, - ) -> DrawingPolygon<'a, S> + ) -> DrawingPolygon<'a> where - S: BaseFloat, I: IntoIterator, - P: Into>, - T: Into>, + P: Into, + T: Into, { self.map_ty_with_context(|ty, ctxt| ty.points_textured(ctxt, view, points)) } } -impl Default for PolygonInit -where - S: Zero, -{ - fn default() -> Self { - let opts = Default::default(); - PolygonInit { opts } - } -} - -impl Default for PolygonOptions -where - S: Zero, -{ - fn default() -> Self { - let position = Default::default(); - let orientation = Default::default(); - let no_fill = false; - let color = None; - let stroke_color = None; - let stroke = None; - PolygonOptions { - position, - orientation, - no_fill, - color, - stroke_color, - stroke, - } - } -} - -impl SetPolygon for PolygonOptions { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for PolygonOptions { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { self } } -impl SetOrientation for PolygonInit { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for PolygonInit { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.opts.orientation) } } -impl SetPosition for PolygonInit { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for PolygonInit { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.opts.position) } } -impl SetColor for PolygonInit { +impl SetColor for PolygonInit { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.opts.color) } } -impl SetPolygon for PolygonInit { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for PolygonInit { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { SetPolygon::polygon_options_mut(&mut self.opts) } } -impl SetStroke for PolygonInit { +impl SetStroke for PolygonInit { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.opts.stroke) } } -impl SetOrientation for Polygon { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Polygon { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.opts.orientation) } } -impl SetPosition for Polygon { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Polygon { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.opts.position) } } -impl SetColor for Polygon { +impl SetColor for Polygon { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.opts.color) } } -impl From> for Primitive { - fn from(prim: PolygonInit) -> Self { +impl From for Primitive { + fn from(prim: PolygonInit) -> Self { Primitive::PolygonInit(prim) } } -impl From> for Primitive { - fn from(prim: Polygon) -> Self { +impl From for Primitive { + fn from(prim: Polygon) -> Self { Primitive::Polygon(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::PolygonInit(prim) => Some(prim), _ => None, @@ -642,8 +597,8 @@ impl Into>> for Primitive { } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Polygon(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/quad.rs b/nannou/src/draw/primitive/quad.rs index e7819798d..04c47a41b 100644 --- a/nannou/src/draw/primitive/quad.rs +++ b/nannou/src/draw/primitive/quad.rs @@ -6,24 +6,24 @@ use crate::draw::properties::{ spatial, ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing}; -use crate::geom::{self, Point2, Vector2}; -use crate::math::{BaseFloat, ElementWise}; +use crate::geom::{self, pt2, Point2}; +use crate::glam::vec2; use lyon::tessellation::StrokeOptions; /// Properties related to drawing a **Quad**. #[derive(Clone, Debug)] -pub struct Quad { - quad: geom::Quad>, - polygon: PolygonInit, - dimensions: spatial::dimension::Properties, +pub struct Quad { + quad: geom::Quad, + polygon: PolygonInit, + dimensions: spatial::dimension::Properties, } /// The drawing context for a `Quad`. -pub type DrawingQuad<'a, S = geom::scalar::Default> = Drawing<'a, Quad, S>; +pub type DrawingQuad<'a> = Drawing<'a, Quad>; // Quad-specific methods. -impl Quad { +impl Quad { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -35,7 +35,7 @@ impl Quad { /// Use the given four points as the vertices (corners) of the quad. pub fn points

(mut self, a: P, b: P, c: P, d: P) -> Self where - P: Into>, + P: Into, { let a = a.into(); let b = b.into(); @@ -47,7 +47,7 @@ impl Quad { } // Trait implementations. -impl draw::renderer::RenderPrimitive for Quad { +impl draw::renderer::RenderPrimitive for Quad { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -66,12 +66,9 @@ impl draw::renderer::RenderPrimitive for Quad { let centroid = quad.centroid(); let x_scale = maybe_x.map(|x| x / cuboid.w()).unwrap_or(1.0); let y_scale = maybe_y.map(|y| y / cuboid.h()).unwrap_or(1.0); - let scale = Vector2 { - x: x_scale, - y: y_scale, - }; + let scale = vec2(x_scale, y_scale); let (a, b, c, d) = quad.into(); - let translate = |v: Point2| centroid + ((v - centroid).mul_element_wise(scale)); + let translate = |v: Point2| centroid + ((v - centroid) * scale); let new_a = translate(a); let new_b = translate(b); let new_c = translate(c); @@ -92,11 +89,8 @@ impl draw::renderer::RenderPrimitive for Quad { } } -impl From>> for Quad -where - S: BaseFloat, -{ - fn from(quad: geom::Quad>) -> Self { +impl From> for Quad { + fn from(quad: geom::Quad) -> Self { let polygon = Default::default(); let dimensions = Default::default(); Quad { @@ -107,74 +101,68 @@ where } } -impl Default for Quad -where - S: BaseFloat, -{ +impl Default for Quad { fn default() -> Self { // Create a quad pointing towards 0.0 radians. - let fifty = S::from(50.0).unwrap(); + let fifty = 50.0; let left = -fifty; let bottom = -fifty; let right = fifty; let top = fifty; - let a = Point2 { x: left, y: bottom }; - let b = Point2 { x: left, y: top }; - let c = Point2 { x: right, y: top }; - let d = Point2 { - x: right, - y: bottom, - }; + let a = pt2(left, bottom); + let b = pt2(left, top); + let c = pt2(right, top); + let d = pt2(right, bottom); Quad::from(geom::Quad([a, b, c, d])) } } -impl SetOrientation for Quad { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Quad { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.polygon) } } -impl SetPosition for Quad { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Quad { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.polygon) } } -impl SetDimensions for Quad { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Quad { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.dimensions) } } -impl SetColor for Quad { +impl SetColor for Quad { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.polygon) } } -impl SetStroke for Quad { +impl SetStroke for Quad { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.polygon) } } -impl SetPolygon for Quad { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for Quad { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { SetPolygon::polygon_options_mut(&mut self.polygon) } } // Primitive conversions. -impl From> for Primitive { - fn from(prim: Quad) -> Self { +impl From for Primitive { + fn from(prim: Quad) -> Self { Primitive::Quad(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Quad(prim) => Some(prim), _ => None, @@ -184,14 +172,11 @@ impl Into>> for Primitive { // Drawing methods. -impl<'a, S> DrawingQuad<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingQuad<'a> { /// Use the given points as the vertices (corners) of the quad. pub fn points

(self, a: P, b: P, c: P, d: P) -> Self where - P: Into>, + P: Into, { self.map_ty(|ty| ty.points(a, b, c, d)) } diff --git a/nannou/src/draw/primitive/rect.rs b/nannou/src/draw/primitive/rect.rs index 030c40174..b52c8cf18 100644 --- a/nannou/src/draw/primitive/rect.rs +++ b/nannou/src/draw/primitive/rect.rs @@ -6,23 +6,23 @@ use crate::draw::properties::{ ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing}; -use crate::geom::{self, Vector2}; -use crate::math::BaseFloat; +use crate::geom; +use crate::glam::Vec2; use lyon::tessellation::StrokeOptions; /// Properties related to drawing a **Rect**. #[derive(Clone, Debug)] -pub struct Rect { - dimensions: dimension::Properties, - polygon: PolygonInit, +pub struct Rect { + dimensions: dimension::Properties, + polygon: PolygonInit, } /// The drawing context for a Rect. -pub type DrawingRect<'a, S = geom::scalar::Default> = Drawing<'a, Rect, S>; +pub type DrawingRect<'a> = Drawing<'a, Rect>; // Trait implementations. -impl Rect { +impl Rect { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -32,10 +32,7 @@ impl Rect { } } -impl<'a, S> DrawingRect<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingRect<'a> { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -45,7 +42,7 @@ where } } -impl draw::renderer::RenderPrimitive for Rect { +impl draw::renderer::RenderPrimitive for Rect { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -64,8 +61,8 @@ impl draw::renderer::RenderPrimitive for Rect { ); let w = maybe_x.unwrap_or(100.0); let h = maybe_y.unwrap_or(100.0); - let rect = geom::Rect::from_wh(Vector2 { x: w, y: h }); - let points = rect.corners().vertices(); + let rect = geom::Rect::from_wh([w, h].into()); + let points = rect.corners().vertices().map(Vec2::from); polygon::render_points_themed( polygon.opts, points, @@ -78,20 +75,14 @@ impl draw::renderer::RenderPrimitive for Rect { } } -impl From> for Rect -where - S: BaseFloat, -{ - fn from(r: geom::Rect) -> Self { +impl From> for Rect { + fn from(r: geom::Rect) -> Self { let (x, y, w, h) = r.x_y_w_h(); Self::default().x_y(x, y).w_h(w, h) } } -impl Default for Rect -where - S: BaseFloat, -{ +impl Default for Rect { fn default() -> Self { let dimensions = <_>::default(); let polygon = <_>::default(); @@ -102,52 +93,52 @@ where } } -impl SetOrientation for Rect { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Rect { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.polygon) } } -impl SetPosition for Rect { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Rect { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.polygon) } } -impl SetDimensions for Rect { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Rect { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.dimensions) } } -impl SetColor for Rect { +impl SetColor for Rect { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.polygon) } } -impl SetStroke for Rect { +impl SetStroke for Rect { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.polygon) } } -impl SetPolygon for Rect { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for Rect { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { SetPolygon::polygon_options_mut(&mut self.polygon) } } // Primitive conversions. -impl From> for Primitive { - fn from(prim: Rect) -> Self { +impl From for Primitive { + fn from(prim: Rect) -> Self { Primitive::Rect(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Rect(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/text.rs b/nannou/src/draw/primitive/text.rs index 65c2e5ea7..0592b55bc 100644 --- a/nannou/src/draw/primitive/text.rs +++ b/nannou/src/draw/primitive/text.rs @@ -6,14 +6,13 @@ use crate::draw::properties::{ ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, }; use crate::draw::{self, theme, Drawing}; -use crate::geom::{self, Vector2}; -use crate::math::{BaseFloat, Zero}; +use crate::geom; use crate::text::{self, Align, Font, FontSize, Justify, Layout, Scalar, Wrap}; /// Properties related to drawing the **Text** primitive. #[derive(Clone, Debug)] -pub struct Text { - spatial: spatial::Properties, +pub struct Text { + spatial: spatial::Properties, style: Style, // The byte range into the `Draw` context's text buffer. text: std::ops::Range, @@ -28,14 +27,11 @@ pub struct Style { } /// The drawing context for the **Text** primitive. -pub type DrawingText<'a, S = geom::scalar::Default> = Drawing<'a, Text, S>; +pub type DrawingText<'a> = Drawing<'a, Text>; -impl Text { +impl Text { /// Begin drawing some text. - pub fn new(ctxt: DrawingContext, text: &str) -> Self - where - S: Zero, - { + pub fn new(ctxt: DrawingContext, text: &str) -> Self { let start = ctxt.text_buffer.len(); ctxt.text_buffer.push_str(text); let end = ctxt.text_buffer.len(); @@ -162,10 +158,7 @@ impl Text { } } -impl<'a, S> DrawingText<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingText<'a> { /// The font size to use for the text. pub fn font_size(self, size: text::FontSize) -> Self { self.map_ty(|ty| ty.font_size(size)) @@ -264,7 +257,7 @@ where } } -impl draw::renderer::RenderPrimitive for Text { +impl draw::renderer::RenderPrimitive for Text { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -290,13 +283,9 @@ impl draw::renderer::RenderPrimitive for Text { maybe_z.is_none(), "z dimension support for text is unimplemented" ); - let w = maybe_x - .map(|s| ::from(s).unwrap()) - .unwrap_or(200.0); - let h = maybe_y - .map(|s| ::from(s).unwrap()) - .unwrap_or(200.0); - let rect: geom::Rect = geom::Rect::from_wh(Vector2 { x: w, y: h }); + let w = maybe_x.unwrap_or(200.0); + let h = maybe_y.unwrap_or(200.0); + let rect: geom::Rect = geom::Rect::from_wh([w, h].into()); let color = color.unwrap_or_else(|| ctxt.theme.fill_lin_srgba(&theme::Primitive::Text)); let text_str = &ctxt.text_buffer[text.clone()]; @@ -350,7 +339,7 @@ impl draw::renderer::RenderPrimitive for Text { } // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = spatial.position.transform() * spatial.orientation.transform(); let transform = global_transform * local_transform; @@ -363,7 +352,7 @@ impl draw::renderer::RenderPrimitive for Text { let r = screen_rect.max.x as f32 / scale_factor - half_out_w; let t = -(screen_rect.min.y as f32 / scale_factor - half_out_h); let b = -(screen_rect.max.y as f32 / scale_factor - half_out_h); - geom::Rect::from_corners(geom::pt2(l, b), geom::pt2(r, t)) + geom::Rect::from_corners([l, b], [r, t]) }; // Skips non-rendered colors (e.g. due to line breaks), @@ -384,9 +373,8 @@ impl draw::renderer::RenderPrimitive for Text { let rect = to_nannou_rect(screen_rect); // Create a mesh-compatible vertex from the position and tex_coords. - let v = |position, tex_coords: [f32; 2]| -> draw::mesh::Vertex { - let p = geom::Point3::from(position); - let p = cgmath::Transform::transform_point(&transform, p.into()); + let v = |[x, y]: [f32; 2], tex_coords: [f32; 2]| -> draw::mesh::Vertex { + let p = transform.transform_point3([x, y, 0.0].into()); let point = draw::mesh::vertex::Point::from(p); draw::mesh::vertex::new(point, g_color.to_owned(), tex_coords.into()) }; @@ -426,25 +414,25 @@ impl draw::renderer::RenderPrimitive for Text { } } -impl SetOrientation for Text { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Text { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.spatial) } } -impl SetPosition for Text { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Text { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.spatial) } } -impl SetDimensions for Text { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Text { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.spatial) } } -impl SetColor for Text { +impl SetColor for Text { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.style.color) } @@ -452,14 +440,14 @@ impl SetColor for Text { // Primitive conversions. -impl From> for Primitive { - fn from(prim: Text) -> Self { +impl From for Primitive { + fn from(prim: Text) -> Self { Primitive::Text(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Text(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/texture.rs b/nannou/src/draw/primitive/texture.rs index 0f78953bb..5b86714a9 100644 --- a/nannou/src/draw/primitive/texture.rs +++ b/nannou/src/draw/primitive/texture.rs @@ -3,32 +3,29 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{self, dimension, orientation, position}; use crate::draw::properties::{SetDimensions, SetOrientation, SetPosition}; use crate::draw::{self, Drawing}; -use crate::geom::{self, Vector2}; -use crate::math::BaseFloat; +use crate::geom; +use crate::glam::Vec2; use crate::wgpu; /// Properties related to drawing a **Rect**. #[derive(Clone, Debug)] -pub struct Texture { +pub struct Texture { texture_view: wgpu::TextureView, - spatial: spatial::Properties, + spatial: spatial::Properties, area: geom::Rect, } /// The drawing context for a Rect. -pub type DrawingTexture<'a, S = geom::scalar::Default> = Drawing<'a, Texture, S>; +pub type DrawingTexture<'a> = Drawing<'a, Texture>; // Trait implementations. -impl Texture -where - S: BaseFloat, -{ +impl Texture { pub(crate) fn new(view: &dyn wgpu::ToTextureView) -> Self { let texture_view = view.to_texture_view(); let [w, h] = texture_view.size(); - let w = S::from(w).unwrap(); - let h = S::from(h).unwrap(); + let w = w as f32; + let h = h as f32; let spatial = spatial::Properties::default().w_h(w, h); let x = geom::Range { start: 0.0, @@ -47,7 +44,7 @@ where } } -impl Texture { +impl Texture { /// Specify the area of the texture to draw. /// /// The bounds of the rectangle should represent the desired area as texture coordinates of the @@ -63,10 +60,7 @@ impl Texture { } } -impl<'a, S> DrawingTexture<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingTexture<'a> { /// Specify the area of the texture to draw. /// /// The bounds of the rectangle should represent the desired area as texture coordinates of the @@ -81,7 +75,7 @@ where } } -impl draw::renderer::RenderPrimitive for Texture { +impl draw::renderer::RenderPrimitive for Texture { fn render_primitive( self, mut ctxt: draw::renderer::RenderContext, @@ -106,10 +100,10 @@ impl draw::renderer::RenderPrimitive for Texture { ); let w = maybe_x.unwrap_or(100.0); let h = maybe_y.unwrap_or(100.0); - let rect = geom::Rect::from_wh(Vector2 { x: w, y: h }); + let rect = geom::Rect::from_w_h(w, h); // Determine the transform to apply to all points. - let global_transform = ctxt.transform; + let global_transform = *ctxt.transform; let local_transform = position.transform() * orientation.transform(); let transform = global_transform * local_transform; @@ -117,7 +111,8 @@ impl draw::renderer::RenderPrimitive for Texture { let points_textured = rect .corners() .vertices() - .zip(area.invert_y().corners().vertices()); + .map(Vec2::from) + .zip(area.invert_y().corners().vertices().map(Vec2::from)); path::render_path_points_textured( points_textured, @@ -133,34 +128,34 @@ impl draw::renderer::RenderPrimitive for Texture { } } -impl SetOrientation for Texture { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Texture { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.spatial) } } -impl SetPosition for Texture { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Texture { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.spatial) } } -impl SetDimensions for Texture { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Texture { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.spatial) } } // Primitive conversions. -impl From> for Primitive { - fn from(prim: Texture) -> Self { +impl From for Primitive { + fn from(prim: Texture) -> Self { Primitive::Texture(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Texture(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/primitive/tri.rs b/nannou/src/draw/primitive/tri.rs index edb0f4093..8b0f96e70 100644 --- a/nannou/src/draw/primitive/tri.rs +++ b/nannou/src/draw/primitive/tri.rs @@ -6,24 +6,24 @@ use crate::draw::properties::{ ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing}; -use crate::geom::{self, Point2, Vector2}; -use crate::math::{BaseFloat, ElementWise}; +use crate::geom::{self, pt2, Point2}; +use crate::glam::vec2; use lyon::tessellation::StrokeOptions; /// Properties related to drawing a **Tri**. #[derive(Clone, Debug)] -pub struct Tri { - tri: geom::Tri>, - dimensions: dimension::Properties, - polygon: PolygonInit, +pub struct Tri { + tri: geom::Tri, + dimensions: dimension::Properties, + polygon: PolygonInit, } /// The drawing context for a `Tri`. -pub type DrawingTri<'a, S = geom::scalar::Default> = Drawing<'a, Tri, S>; +pub type DrawingTri<'a> = Drawing<'a, Tri>; // Tri-specific methods. -impl Tri { +impl Tri { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -35,7 +35,7 @@ impl Tri { /// Use the given three points as the vertices (corners) of the triangle. pub fn points

(mut self, a: P, b: P, c: P) -> Self where - P: Into>, + P: Into, { let a = a.into(); let b = b.into(); @@ -47,10 +47,7 @@ impl Tri { // Drawing methods. -impl<'a, S> DrawingTri<'a, S> -where - S: BaseFloat, -{ +impl<'a> DrawingTri<'a> { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self where @@ -62,7 +59,7 @@ where /// Use the given points as the vertices (corners) of the triangle. pub fn points

(self, a: P, b: P, c: P) -> Self where - P: Into>, + P: Into, { self.map_ty(|ty| ty.points(a, b, c)) } @@ -70,7 +67,7 @@ where // Trait implementations. -impl draw::renderer::RenderPrimitive for Tri { +impl draw::renderer::RenderPrimitive for Tri { fn render_primitive( self, ctxt: draw::renderer::RenderContext, @@ -88,12 +85,9 @@ impl draw::renderer::RenderPrimitive for Tri { let centroid = tri.centroid(); let x_scale = maybe_x.map(|x| x / cuboid.w()).unwrap_or(1.0); let y_scale = maybe_y.map(|y| y / cuboid.h()).unwrap_or(1.0); - let scale = Vector2 { - x: x_scale, - y: y_scale, - }; + let scale = vec2(x_scale, y_scale); let (a, b, c) = tri.into(); - let translate = |v: Point2| centroid + ((v - centroid).mul_element_wise(scale)); + let translate = |v: Point2| centroid + ((v - centroid) * scale); let new_a = translate(a); let new_b = translate(b); let new_c = translate(c); @@ -112,11 +106,8 @@ impl draw::renderer::RenderPrimitive for Tri { } } -impl From>> for Tri -where - S: BaseFloat, -{ - fn from(tri: geom::Tri>) -> Self { +impl From> for Tri { + fn from(tri: geom::Tri) -> Self { let dimensions = <_>::default(); let polygon = <_>::default(); Tri { @@ -127,74 +118,64 @@ where } } -impl Default for Tri -where - S: BaseFloat, -{ +impl Default for Tri { fn default() -> Self { // Create a triangle pointing towards 0.0 radians. - let zero = S::zero(); - let fifty = S::from(50.0).unwrap(); - let thirty_three = S::from(33.0).unwrap(); - let a = Point2 { - x: -fifty, - y: thirty_three, - }; - let b = Point2 { x: fifty, y: zero }; - let c = Point2 { - x: -fifty, - y: -thirty_three, - }; + let fifty = 50.0; + let thirty_three = 33.0; + let a = pt2(-fifty, thirty_three); + let b = pt2(fifty, 0.0); + let c = pt2(-fifty, -thirty_three); Tri::from(geom::Tri([a, b, c])) } } -impl SetOrientation for Tri { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Tri { + fn properties(&mut self) -> &mut orientation::Properties { SetOrientation::properties(&mut self.polygon) } } -impl SetPosition for Tri { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Tri { + fn properties(&mut self) -> &mut position::Properties { SetPosition::properties(&mut self.polygon) } } -impl SetDimensions for Tri { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Tri { + fn properties(&mut self) -> &mut dimension::Properties { SetDimensions::properties(&mut self.dimensions) } } -impl SetColor for Tri { +impl SetColor for Tri { fn rgba_mut(&mut self) -> &mut Option { SetColor::rgba_mut(&mut self.polygon) } } -impl SetStroke for Tri { +impl SetStroke for Tri { fn stroke_options_mut(&mut self) -> &mut StrokeOptions { SetStroke::stroke_options_mut(&mut self.polygon) } } -impl SetPolygon for Tri { - fn polygon_options_mut(&mut self) -> &mut PolygonOptions { +impl SetPolygon for Tri { + fn polygon_options_mut(&mut self) -> &mut PolygonOptions { SetPolygon::polygon_options_mut(&mut self.polygon) } } // Primitive conversions. -impl From> for Primitive { - fn from(prim: Tri) -> Self { +impl From for Primitive { + fn from(prim: Tri) -> Self { Primitive::Tri(prim) } } -impl Into>> for Primitive { - fn into(self) -> Option> { +impl Into> for Primitive { + fn into(self) -> Option { match self { Primitive::Tri(prim) => Some(prim), _ => None, diff --git a/nannou/src/draw/properties/spatial/dimension.rs b/nannou/src/draw/properties/spatial/dimension.rs index 26753f9c4..3ad341760 100644 --- a/nannou/src/draw/properties/spatial/dimension.rs +++ b/nannou/src/draw/properties/spatial/dimension.rs @@ -1,84 +1,74 @@ -use crate::geom::{self, Vector2, Vector3}; +use crate::glam::{Vec2, Vec3}; /// Dimension properties for **Drawing** a **Primitive**. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Properties { - pub x: Option, - pub y: Option, - pub z: Option, +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub struct Properties { + pub x: Option, + pub y: Option, + pub z: Option, } /// Primitives that support different dimensions. -pub trait SetDimensions: Sized { +pub trait SetDimensions: Sized { /// Provide a mutable reference to the **dimension::Properties** for updating. - fn properties(&mut self) -> &mut Properties; + fn properties(&mut self) -> &mut Properties; /// Set the absolute width for the primitive. - fn width(mut self, w: S) -> Self { + fn width(mut self, w: f32) -> Self { self.properties().x = Some(w); self } /// Set the absolute height for the primitive. - fn height(mut self, h: S) -> Self { + fn height(mut self, h: f32) -> Self { self.properties().y = Some(h); self } /// Set the absolute depth for the primitive. - fn depth(mut self, d: S) -> Self { + fn depth(mut self, d: f32) -> Self { self.properties().z = Some(d); self } /// Short-hand for the **width** method. - fn w(self, w: S) -> Self { + fn w(self, w: f32) -> Self { self.width(w) } /// Short-hand for the **height** method. - fn h(self, h: S) -> Self { + fn h(self, h: f32) -> Self { self.height(h) } /// Short-hand for the **depth** method. - fn d(self, d: S) -> Self { + fn d(self, d: f32) -> Self { self.depth(d) } /// Set the **x** and **y** dimensions for the primitive. - fn wh(self, v: Vector2) -> Self { + fn wh(self, v: Vec2) -> Self { self.w(v.x).h(v.y) } /// Set the **x**, **y** and **z** dimensions for the primitive. - fn whd(self, v: Vector3) -> Self { + fn whd(self, v: Vec3) -> Self { self.w(v.x).h(v.y).d(v.z) } /// Set the width and height for the primitive. - fn w_h(self, x: S, y: S) -> Self { - self.wh(Vector2 { x, y }) + fn w_h(self, x: f32, y: f32) -> Self { + self.wh([x, y].into()) } /// Set the width and height for the primitive. - fn w_h_d(self, x: S, y: S, z: S) -> Self { - self.whd(Vector3 { x, y, z }) + fn w_h_d(self, x: f32, y: f32, z: f32) -> Self { + self.whd([x, y, z].into()) } } -impl SetDimensions for Properties { - fn properties(&mut self) -> &mut Properties { +impl SetDimensions for Properties { + fn properties(&mut self) -> &mut Properties { self } } - -impl Default for Properties { - fn default() -> Self { - Self { - x: None, - y: None, - z: None, - } - } -} diff --git a/nannou/src/draw/properties/spatial/mod.rs b/nannou/src/draw/properties/spatial/mod.rs index a217686a3..d7aa8fa57 100644 --- a/nannou/src/draw/properties/spatial/mod.rs +++ b/nannou/src/draw/properties/spatial/mod.rs @@ -1,6 +1,3 @@ -use crate::geom; -use crate::math::Zero; - pub mod dimension; pub mod orientation; pub mod position; @@ -10,21 +7,18 @@ pub use self::orientation::SetOrientation; pub use self::position::SetPosition; /// Types that may be positioned, sized and oriented within 3D space. -pub trait SetSpatial: SetDimensions + SetPosition + SetOrientation {} +pub trait SetSpatial: SetDimensions + SetPosition + SetOrientation {} -impl SetSpatial for T where T: SetDimensions + SetPosition + SetOrientation {} +impl SetSpatial for T where T: SetDimensions + SetPosition + SetOrientation {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct Properties { - pub position: position::Properties, - pub dimensions: dimension::Properties, - pub orientation: orientation::Properties, +pub struct Properties { + pub position: position::Properties, + pub dimensions: dimension::Properties, + pub orientation: orientation::Properties, } -impl Default for Properties -where - S: Zero, -{ +impl Default for Properties { fn default() -> Self { let position = Default::default(); let dimensions = Default::default(); @@ -37,20 +31,20 @@ where } } -impl SetPosition for Properties { - fn properties(&mut self) -> &mut position::Properties { +impl SetPosition for Properties { + fn properties(&mut self) -> &mut position::Properties { self.position.properties() } } -impl SetDimensions for Properties { - fn properties(&mut self) -> &mut dimension::Properties { +impl SetDimensions for Properties { + fn properties(&mut self) -> &mut dimension::Properties { self.dimensions.properties() } } -impl SetOrientation for Properties { - fn properties(&mut self) -> &mut orientation::Properties { +impl SetOrientation for Properties { + fn properties(&mut self) -> &mut orientation::Properties { self.orientation.properties() } } diff --git a/nannou/src/draw/properties/spatial/orientation.rs b/nannou/src/draw/properties/spatial/orientation.rs index b15029d9f..c312189eb 100644 --- a/nannou/src/draw/properties/spatial/orientation.rs +++ b/nannou/src/draw/properties/spatial/orientation.rs @@ -1,36 +1,28 @@ -use crate::geom::{self, Point3, Vector3}; -use crate::math::{deg_to_rad, turns_to_rad, Angle, BaseFloat, Euler, Quaternion, Rad, Zero}; +use crate::geom::Point3; +use crate::glam::{EulerRot, Mat4, Quat, Vec3}; +use crate::math::{deg_to_rad, turns_to_rad}; /// Orientation properties for **Drawing** a **Primitive**. #[derive(Copy, Clone, Debug, PartialEq)] -pub enum Properties { +pub enum Properties { /// The orientation described by an angle along each axis. - Axes(Vector3), + Axes(Vec3), /// The orientation described by looking at some other point. - LookAt(Point3), + LookAt(Point3), + /// Angle described by quarternion. + Quat(Quat), } -impl Properties -where - S: Zero, -{ - pub fn transform(&self) -> cgmath::Matrix4 - where - S: BaseFloat, - { +impl Properties { + pub fn transform(&self) -> Mat4 { match *self { - Properties::Axes(v) => { - let euler = cgmath::Euler { - x: cgmath::Rad(v.x), - y: cgmath::Rad(v.y), - z: cgmath::Rad(v.z), - }; - cgmath::Matrix4::from(euler) - } + Properties::Axes(v) => Mat4::from_euler(EulerRot::XYZ, v.x, v.y, v.z), Properties::LookAt(p) => { - let eye = Vector3::new(S::zero(), S::zero(), S::zero()); - cgmath::Matrix4::look_at_dir(eye.into(), p.into(), up().into()) + let eye = Vec3::ZERO; + let up = Vec3::Y; + Mat4::look_at_rh(eye, p, up) } + Properties::Quat(q) => Mat4::from_quat(q), } } @@ -40,24 +32,20 @@ where /// If the `Properties` is already `Axes`, nothing changes. pub fn switch_to_axes(&mut self) { if let Properties::LookAt(_) = *self { - *self = Properties::Axes(Vector3::zero()); + *self = Properties::Axes(Vec3::ZERO); } } } -fn up() -> Vector3 { - Vector3::new(S::zero(), S::one(), S::zero()) -} - /// An API for setting the **orientation::Properties**. -pub trait SetOrientation: Sized { +pub trait SetOrientation: Sized { /// Provide a mutable reference to the **orientation::Properties** for updating. - fn properties(&mut self) -> &mut Properties; + fn properties(&mut self) -> &mut Properties; // Describing orientation via a target. /// Describe orientation via the vector that points to the given target. - fn look_at(mut self, target: Point3) -> Self { + fn look_at(mut self, target: Point3) -> Self { *self.properties() = Properties::LookAt(target); self } @@ -65,130 +53,86 @@ pub trait SetOrientation: Sized { // Absolute orientation. /// Specify the orientation around the *x* axis as an absolute value in radians. - fn x_radians(mut self, x: S) -> Self - where - S: BaseFloat, - { + fn x_radians(mut self, x: f32) -> Self { self.properties().switch_to_axes(); expect_axes(self.properties()).x = x; self } /// Specify the orientation around the *y* axis as an absolute value in radians. - fn y_radians(mut self, y: S) -> Self - where - S: BaseFloat, - { + fn y_radians(mut self, y: f32) -> Self { self.properties().switch_to_axes(); expect_axes(self.properties()).y = y; self } /// Specify the orientation around the *z* axis as an absolute value in radians. - fn z_radians(mut self, z: S) -> Self - where - S: BaseFloat, - { + fn z_radians(mut self, z: f32) -> Self { self.properties().switch_to_axes(); expect_axes(self.properties()).z = z; self } /// Specify the orientation around the *x* axis as an absolute value in degrees. - fn x_degrees(self, x: S) -> Self - where - S: BaseFloat, - { + fn x_degrees(self, x: f32) -> Self { self.x_radians(deg_to_rad(x)) } /// Specify the orientation around the *y* axis as an absolute value in degrees. - fn y_degrees(self, y: S) -> Self - where - S: BaseFloat, - { + fn y_degrees(self, y: f32) -> Self { self.y_radians(deg_to_rad(y)) } /// Specify the orientation around the *z* axis as an absolute value in degrees. - fn z_degrees(self, z: S) -> Self - where - S: BaseFloat, - { + fn z_degrees(self, z: f32) -> Self { self.z_radians(deg_to_rad(z)) } /// Specify the orientation around the *x* axis as a number of turns around the axis. - fn x_turns(self, x: S) -> Self - where - S: BaseFloat, - { + fn x_turns(self, x: f32) -> Self { self.x_radians(turns_to_rad(x)) } /// Specify the orientation around the *y* axis as a number of turns around the axis. - fn y_turns(self, y: S) -> Self - where - S: BaseFloat, - { + fn y_turns(self, y: f32) -> Self { self.y_radians(turns_to_rad(y)) } /// Specify the orientation around the *z* axis as a number of turns around the axis. - fn z_turns(self, z: S) -> Self - where - S: BaseFloat, - { + fn z_turns(self, z: f32) -> Self { self.z_radians(turns_to_rad(z)) } /// Specify the orientation along each axis with the given **Vector** of radians. /// /// This has the same affect as calling `self.x_radians(v.x).y_radians(v.y).z_radians(v.z)`. - fn radians(self, v: Vector3) -> Self - where - S: BaseFloat, - { + fn radians(self, v: Vec3) -> Self { self.x_radians(v.x).y_radians(v.y).z_radians(v.z) } /// Specify the orientation along each axis with the given **Vector** of degrees. /// /// This has the same affect as calling `self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)`. - fn degrees(self, v: Vector3) -> Self - where - S: BaseFloat, - { + fn degrees(self, v: Vec3) -> Self { self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z) } /// Specify the orientation along each axis with the given **Vector** of "turns". /// /// This has the same affect as calling `self.x_turns(v.x).y_turns(v.y).z_turns(v.z)`. - fn turns(self, v: Vector3) -> Self - where - S: BaseFloat, - { + fn turns(self, v: Vec3) -> Self { self.x_turns(v.x).y_turns(v.y).z_turns(v.z) } - /// Specify the orientation with the given **Euler**. - /// - /// The euler can be specified in either radians (via **Rad**) or degrees (via **Deg**). - fn euler(self, e: Euler) -> Self - where - S: BaseFloat, - A: Angle + Into>, - { - self.radians(euler_to_vec3(e)) + /// Specify the orientation with the given euler orientation in radians. + fn euler(self, e: Vec3) -> Self { + self.radians(e) } /// Specify the orientation with the given **Quaternion**. - fn quaternion(self, q: Quaternion) -> Self - where - S: BaseFloat, - { - self.euler(q.into()) + fn quaternion(mut self, q: Quat) -> Self { + *self.properties() = Properties::Quat(q); + self } // Higher level methods. @@ -196,30 +140,21 @@ pub trait SetOrientation: Sized { /// Specify the "pitch" of the orientation in radians. /// /// This has the same effect as calling `x_radians`. - fn pitch(self, pitch: S) -> Self - where - S: BaseFloat, - { + fn pitch(self, pitch: f32) -> Self { self.x_radians(pitch) } /// Specify the "yaw" of the orientation in radians. /// /// This has the same effect as calling `y_radians`. - fn yaw(self, yaw: S) -> Self - where - S: BaseFloat, - { + fn yaw(self, yaw: f32) -> Self { self.y_radians(yaw) } /// Specify the "roll" of the orientation in radians. /// /// This has the same effect as calling `z_radians`. - fn roll(self, roll: S) -> Self - where - S: BaseFloat, - { + fn roll(self, roll: f32) -> Self { self.z_radians(roll) } @@ -227,45 +162,28 @@ pub trait SetOrientation: Sized { /// given value is specified in radians. /// /// This is equivalent to calling the `z_radians` or `roll` methods. - fn rotate(self, radians: S) -> Self - where - S: BaseFloat, - { + fn rotate(self, radians: f32) -> Self { self.z_radians(radians) } } -impl SetOrientation for Properties { - fn properties(&mut self) -> &mut Properties { +impl SetOrientation for Properties { + fn properties(&mut self) -> &mut Properties { self } } -impl Default for Properties -where - S: Zero, -{ +impl Default for Properties { fn default() -> Self { - Properties::Axes(Vector3::zero()) + Properties::Axes(Vec3::ZERO) } } // Expects the `Axes` variant from the given properties. -fn expect_axes(p: &mut Properties) -> &mut Vector3 { +fn expect_axes(p: &mut Properties) -> &mut Vec3 { match *p { Properties::Axes(ref mut axes) => axes, Properties::LookAt(_) => panic!("expected `Axes`, found `LookAt`"), + Properties::Quat(_) => panic!("expected `Axes`, found `Quat`"), } } - -// Convert the given `Euler` into a `Vector3`. -fn euler_to_vec3(e: Euler) -> Vector3 -where - S: BaseFloat, - A: Angle + Into>, -{ - let x = e.x.into().0; - let y = e.y.into().0; - let z = e.z.into().0; - Vector3 { x, y, z } -} diff --git a/nannou/src/draw/properties/spatial/position.rs b/nannou/src/draw/properties/spatial/position.rs index 45814e92d..413c09907 100644 --- a/nannou/src/draw/properties/spatial/position.rs +++ b/nannou/src/draw/properties/spatial/position.rs @@ -1,79 +1,73 @@ //! Items related to describing positioning along each axis as -use crate::geom::{self, Point2, Point3}; -use crate::math::{BaseFloat, Zero}; +use crate::geom::{Point2, Point3}; +use crate::glam::Mat4; /// Position properties for **Drawing** a **Primitive**. #[derive(Copy, Clone, Debug, PartialEq)] -pub struct Properties { - pub point: Point3, +pub struct Properties { + pub point: Point3, } /// An API for setting the **position::Properties**. -pub trait SetPosition: Sized { +pub trait SetPosition: Sized { /// Provide a mutable reference to the **position::Properties** for updating. - fn properties(&mut self) -> &mut Properties; + fn properties(&mut self) -> &mut Properties; /// Build with the given **Absolute** **Position** along the *x* axis. - fn x(mut self, x: S) -> Self { + fn x(mut self, x: f32) -> Self { self.properties().point.x = x; self } /// Build with the given **Absolute** **Position** along the *y* axis. - fn y(mut self, y: S) -> Self { + fn y(mut self, y: f32) -> Self { self.properties().point.y = y; self } /// Build with the given **Absolute** **Position** along the *z* axis. - fn z(mut self, z: S) -> Self { + fn z(mut self, z: f32) -> Self { self.properties().point.z = z; self } /// Set the **Position** with some two-dimensional point. - fn xy(self, p: Point2) -> Self { + fn xy(self, p: Point2) -> Self { self.x(p.x).y(p.y) } /// Set the **Position** with some three-dimensional point. - fn xyz(self, p: Point3) -> Self { + fn xyz(self, p: Point3) -> Self { self.x(p.x).y(p.y).z(p.z) } /// Set the **Position** with *x* *y* coordinates. - fn x_y(self, x: S, y: S) -> Self { - self.xy(Point2 { x, y }) + fn x_y(self, x: f32, y: f32) -> Self { + self.xy([x, y].into()) } /// Set the **Position** with *x* *y* *z* coordinates. - fn x_y_z(self, x: S, y: S, z: S) -> Self { - self.xyz(Point3 { x, y, z }) + fn x_y_z(self, x: f32, y: f32, z: f32) -> Self { + self.xyz([x, y, z].into()) } } -impl Properties { - pub fn transform(&self) -> cgmath::Matrix4 - where - S: BaseFloat, - { - cgmath::Matrix4::from_translation(self.point.into()) +impl Properties { + pub fn transform(&self) -> Mat4 { + Mat4::from_translation(self.point.into()) } } -impl SetPosition for Properties { - fn properties(&mut self) -> &mut Properties { +impl SetPosition for Properties { + fn properties(&mut self) -> &mut Properties { self } } -impl Default for Properties -where - S: Zero, -{ +impl Default for Properties { fn default() -> Self { - let point = Point3::zero(); + let point = Point3::ZERO; Self { point } } } diff --git a/nannou/src/draw/renderer/mod.rs b/nannou/src/draw/renderer/mod.rs index 0c95f9c61..9f5dd00c8 100644 --- a/nannou/src/draw/renderer/mod.rs +++ b/nannou/src/draw/renderer/mod.rs @@ -1,8 +1,9 @@ use crate::draw; -use crate::draw::mesh::vertex::Color; +use crate::draw::mesh::vertex::{Color, TexCoords}; use crate::frame::Frame; -use crate::geom::{self, Point2, Rect, Vector2}; -use crate::math::{map_range, Matrix4}; +use crate::geom::{self, Point2, Rect}; +use crate::glam::{Mat4, Vec2, Vec3}; +use crate::math::map_range; use crate::text; use crate::wgpu; use lyon::path::PathEvent; @@ -33,17 +34,17 @@ pub struct PrimitiveRender { /// The context provided to primitives to assist with the rendering process. pub struct RenderContext<'a> { - pub transform: &'a crate::math::Matrix4, + pub transform: &'a Mat4, pub intermediary_mesh: &'a draw::Mesh, pub path_event_buffer: &'a [PathEvent], pub path_points_colored_buffer: &'a [(Point2, Color)], - pub path_points_textured_buffer: &'a [(Point2, Point2)], + pub path_points_textured_buffer: &'a [(Point2, TexCoords)], pub text_buffer: &'a str, pub theme: &'a draw::Theme, pub glyph_cache: &'a mut GlyphCache, pub fill_tessellator: &'a mut FillTessellator, pub stroke_tessellator: &'a mut StrokeTessellator, - pub output_attachment_size: Vector2, // logical coords + pub output_attachment_size: Vec2, // logical coords pub output_attachment_scale_factor: f32, } @@ -139,10 +140,6 @@ pub struct DrawError; #[repr(C)] #[derive(Copy, Clone, Debug)] struct Uniforms { - // /// The vector to multiply onto vertices in the vertex shader to map them from window space to - // /// shader space. - // window_to_shader: [f32; 3], - //view: Matrix4, /// Translates from "logical pixel coordinate space" (our "world space") to screen space. /// /// Specifically: @@ -150,7 +147,7 @@ struct Uniforms { /// - x is transformed from (-half_logical_win_w, half_logical_win_w) to (-1, 1). /// - y is transformed from (-half_logical_win_h, half_logical_win_h) to (1, -1). /// - z is transformed from (-max_logical_win_side, max_logical_win_side) to (0, 1). - proj: Matrix4, + proj: Mat4, } type SamplerId = u64; @@ -532,7 +529,7 @@ impl Renderer { let pt_to_px = |s: f32| (s * scale_factor).round() as u32; let full_rect = Rect::from_w_h(px_to_pt(w_px), px_to_pt(h_px)); - let window_to_scissor = |v: Vector2| -> [u32; 2] { + let window_to_scissor = |v: Vec2| -> [u32; 2] { let x = map_range(v.x, full_rect.left(), full_rect.right(), 0u32, w_px); let y = map_range(v.y, full_rect.bottom(), full_rect.top(), 0u32, h_px); [x, y] @@ -578,7 +575,7 @@ impl Renderer { fill_tessellator: &mut fill_tessellator, stroke_tessellator: &mut stroke_tessellator, glyph_cache: &mut self.glyph_cache, - output_attachment_size: Vector2::new(px_to_pt(w_px), px_to_pt(h_px)), + output_attachment_size: Vec2::new(px_to_pt(w_px), px_to_pt(h_px)), output_attachment_scale_factor: scale_factor, }; @@ -674,7 +671,7 @@ impl Renderer { .unwrap_or(geom::Rect::from_w_h(0.0, 0.0)), draw::Scissor::NoOverlap => geom::Rect::from_w_h(0.0, 0.0), }; - let [left, bottom] = window_to_scissor(rect.bottom_left()); + let [left, bottom] = window_to_scissor(rect.bottom_left().into()); let (width, height) = rect.w_h(); let (width, height) = (pt_to_px(width), pt_to_px(height)); let scissor = Scissor { @@ -1029,11 +1026,12 @@ fn create_uniforms([img_w, img_h]: [u32; 2], scale_factor: f32) -> Uniforms { let bottom = -top; let far = std::cmp::max(img_w, img_h) as f32 / scale_factor; let near = -far; - let proj = cgmath::ortho(left, right, bottom, top, near, far); + let proj = Mat4::orthographic_rh_gl(left, right, bottom, top, near, far); // By default, ortho scales z values to the range -1.0 to 1.0. We want to scale and translate // the z axis so that it is in the range of 0.0 to 1.0. - let trans = cgmath::Matrix4::from_translation(cgmath::Vector3::new(0.0, 0.0, 1.0)); - let scale = cgmath::Matrix4::from_nonuniform_scale(1.0, 1.0, 0.5); + // TODO: Can possibly solve this more easily by using `Mat4::orthographic_rh` above instead. + let trans = Mat4::from_translation(Vec3::Z); + let scale = Mat4::from_scale([1.0, 1.0, 0.5].into()); let proj = scale * trans * proj; let proj = proj.into(); Uniforms { proj } diff --git a/nannou/src/event.rs b/nannou/src/event.rs index e40b7fc76..3f4d73e54 100644 --- a/nannou/src/event.rs +++ b/nannou/src/event.rs @@ -6,7 +6,8 @@ //! - [**WindowEvent**](./enum.WindowEvent.html) - a stripped-back, simplified, newcomer-friendly //! version of the **raw**, low-level winit event. -use crate::geom::{self, Point2, Vector2}; +use crate::geom::{self, Point2}; +use crate::glam::Vec2; use crate::window; use crate::App; use std::path::PathBuf; @@ -74,7 +75,7 @@ pub struct TouchEvent { /// The state of the touch. pub phase: TouchPhase, /// The position of the touch. - pub position: Point2, + pub position: Point2, } /// Pressure on a touch pad. @@ -112,7 +113,7 @@ pub struct AxisMotion { #[derive(Clone, Debug, PartialEq)] pub enum WindowEvent { /// The window has been moved to a new position. - Moved(Point2), + Moved(Point2), /// The given keyboard key was pressed. KeyPressed(Key), @@ -121,7 +122,7 @@ pub enum WindowEvent { KeyReleased(Key), /// The mouse moved to the given x, y position. - MouseMoved(Point2), + MouseMoved(Point2), /// The given mouse button was pressed. MousePressed(MouseButton), @@ -139,7 +140,7 @@ pub enum WindowEvent { MouseWheel(MouseScrollDelta, TouchPhase), /// The window was resized to the given dimensions (in DPI-agnostic points, not pixels). - Resized(Vector2), + Resized(Vec2), /// A file at the given path was hovered over the window. HoveredFile(PathBuf), @@ -195,24 +196,24 @@ impl WindowEvent { // // winit produces input events in pixels, so these positions need to be divided by the // width and height of the window in order to be DPI agnostic. - let tw = |w: f64| w as geom::scalar::Default; - let th = |h: f64| h as geom::scalar::Default; - let tx = |x: f64| (x - win_w / 2.0) as geom::scalar::Default; - let ty = |y: f64| (-(y - win_h / 2.0)) as geom::scalar::Default; + let tw = |w: f64| w as f32; + let th = |h: f64| h as f32; + let tx = |x: f64| (x - win_w / 2.0) as f32; + let ty = |y: f64| (-(y - win_h / 2.0)) as f32; let event = match event { winit::event::WindowEvent::Resized(new_size) => { let (new_w, new_h) = new_size.to_logical::(scale_factor).into(); let x = tw(new_w); let y = th(new_h); - Resized(Vector2 { x, y }) + Resized([x, y].into()) } winit::event::WindowEvent::Moved(new_pos) => { let (new_x, new_y) = new_pos.to_logical::(scale_factor).into(); let x = tx(new_x); let y = ty(new_y); - Moved(Point2 { x, y }) + Moved([x, y].into()) } // TODO: Should separate the behaviour of close requested and destroyed. @@ -238,7 +239,7 @@ impl WindowEvent { let (x, y) = position.to_logical::(scale_factor).into(); let x = tx(x); let y = ty(y); - MouseMoved(Point2 { x, y }) + MouseMoved([x, y].into()) } winit::event::WindowEvent::CursorEntered { .. } => MouseEntered, @@ -263,7 +264,7 @@ impl WindowEvent { let (x, y) = location.to_logical::(scale_factor).into(); let x = tx(x); let y = ty(y); - let position = Point2 { x, y }; + let position = [x, y].into(); let touch = TouchEvent { phase: phase.clone(), position, diff --git a/nannou/src/geom/cuboid.rs b/nannou/src/geom/cuboid.rs deleted file mode 100644 index d27d448a2..000000000 --- a/nannou/src/geom/cuboid.rs +++ /dev/null @@ -1,904 +0,0 @@ -//! Items related to cube geometry. -//! -//! The main type is the `Cuboid` type. - -use crate::geom::{quad, scalar, Point3, Quad, Range, Tri, Vector3}; -use crate::math::num_traits::Float; -use crate::math::BaseNum; -use std::ops::Neg; - -/// The number of faces on a Cuboid. -pub const NUM_FACES: u8 = 6; - -/// The number of corners on a Cuboid. -pub const NUM_CORNERS: u8 = 8; - -/// The number of subdivisions for a Cuboid. -pub const NUM_SUBDIVISIONS: u8 = 8; - -/// The number of triangles used to triangulate a cuboid. -pub const NUM_TRIANGLES: u8 = NUM_FACES * 2; - -/// A light-weight `Cuboid` type with many helper and utility methods. -/// -/// The cuboid is also known as a "rectangular prism". -/// -/// `Cuboid` is implemented similarly to `geom::Rect` but with 3 axes instead of 2. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Cuboid { - /// The start and end along the x axis. - pub x: Range, - /// The start and end along the y axis. - pub y: Range, - /// The start and end along the z axis. - pub z: Range, -} - -/// Each of the faces of a cuboid. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Face { - Back, - Right, - Top, - Front, - Bottom, - Left, -} - -/// An iterator yielding each corner of a cuboid in the following order. -#[derive(Clone, Debug)] -pub struct Corners<'a, S: 'a> { - cuboid: &'a Cuboid, - corner_index: u8, -} - -/// An iterator yielding the faces of a cuboid as per their ordering. -#[derive(Clone, Debug)] -pub struct Faces { - next_face_index: u8, -} - -/// A quad representing a single face of a cuboid. -pub type FaceQuad = Quad>; - -/// An iterator yielding each face of a cuboid as a quad. -#[derive(Clone, Debug)] -pub struct FaceQuads<'a, S: 'a = scalar::Default> { - // The cuboid object from which each face will be yielded. - cuboid: &'a Cuboid, - // The next face to yield. - faces: Faces, -} - -/// An iterator yielding all triangles for all faces. -#[derive(Clone, Debug)] -pub struct Triangles<'a, S: 'a> { - face_quads: FaceQuads<'a, S>, - triangles: quad::Triangles>, -} - -/// The three ranges that make up the 8 subdivisions of a cuboid. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SubdivisionRanges { - /// The first half of the *x* axis range. - pub x_a: Range, - /// The second half of the *x* axis range. - pub x_b: Range, - /// The first half of the *y* axis range. - pub y_a: Range, - /// The second half of the *y* axis range. - pub y_b: Range, - /// The first half of the *z* axis range. - pub z_a: Range, - /// The second half of the *z* axis range. - pub z_b: Range, -} - -/// Yields even subdivisions of a `Cuboid`. -/// -/// The eight subdivisions will each be yielded as a `Cuboid` whose dimensions are exactly half of -/// the original `Cuboid`. -#[derive(Clone)] -pub struct Subdivisions { - ranges: SubdivisionRanges, - subdivision_index: u8, -} - -macro_rules! corner_from_index { - (0, $cuboid:expr) => { - [$cuboid.x.start, $cuboid.y.start, $cuboid.z.start] - }; - (1, $cuboid:expr) => { - [$cuboid.x.end, $cuboid.y.start, $cuboid.z.start] - }; - (2, $cuboid:expr) => { - [$cuboid.x.start, $cuboid.y.end, $cuboid.z.start] - }; - (3, $cuboid:expr) => { - [$cuboid.x.end, $cuboid.y.end, $cuboid.z.start] - }; - (4, $cuboid:expr) => { - [$cuboid.x.start, $cuboid.y.start, $cuboid.z.end] - }; - (5, $cuboid:expr) => { - [$cuboid.x.end, $cuboid.y.start, $cuboid.z.end] - }; - (6, $cuboid:expr) => { - [$cuboid.x.start, $cuboid.y.end, $cuboid.z.end] - }; - (7, $cuboid:expr) => { - [$cuboid.x.end, $cuboid.y.end, $cuboid.z.end] - }; -} - -macro_rules! face_from_index { - (0) => { - Face::Back - }; - (1) => { - Face::Right - }; - (2) => { - Face::Top - }; - (3) => { - Face::Front - }; - (4) => { - Face::Bottom - }; - (5) => { - Face::Left - }; -} - -macro_rules! quad_from_corner_indices { - ($cuboid:expr, $a:tt, $b:tt, $c:tt, $d:tt) => { - [ - corner_from_index!($a, $cuboid).into(), - corner_from_index!($b, $cuboid).into(), - corner_from_index!($c, $cuboid).into(), - corner_from_index!($d, $cuboid).into(), - ] - }; -} - -// Given some `SubdivisionRanges` and a subdivision index, produce the cuboid for that subdivision. -// -// 1. Front bottom left -// 2. Front bottom right -// 3. Front top left -// 4. Front top right -// 5. Back bottom left -// 6. Back bottom right -// 7. Back top left -// 8. Back top right -macro_rules! subdivision_from_index { - ($ranges:expr,0) => { - Cuboid { - x: $ranges.x_a, - y: $ranges.y_a, - z: $ranges.z_a, - } - }; - ($ranges:expr,1) => { - Cuboid { - x: $ranges.x_b, - y: $ranges.y_a, - z: $ranges.z_a, - } - }; - ($ranges:expr,2) => { - Cuboid { - x: $ranges.x_a, - y: $ranges.y_b, - z: $ranges.z_a, - } - }; - ($ranges:expr,3) => { - Cuboid { - x: $ranges.x_b, - y: $ranges.y_b, - z: $ranges.z_a, - } - }; - ($ranges:expr,4) => { - Cuboid { - x: $ranges.x_a, - y: $ranges.y_a, - z: $ranges.z_b, - } - }; - ($ranges:expr,5) => { - Cuboid { - x: $ranges.x_b, - y: $ranges.y_a, - z: $ranges.z_b, - } - }; - ($ranges:expr,6) => { - Cuboid { - x: $ranges.x_a, - y: $ranges.y_b, - z: $ranges.z_b, - } - }; - ($ranges:expr,7) => { - Cuboid { - x: $ranges.x_b, - y: $ranges.y_b, - z: $ranges.z_b, - } - }; -} - -impl Cuboid -where - S: BaseNum, -{ - /// Construct a Rect from a given centre point (x, y, z) and dimensions (width, height, depth). - pub fn from_xyz_whd(p: Point3, d: Vector3) -> Self { - Cuboid { - x: Range::from_pos_and_len(p.x, d.x), - y: Range::from_pos_and_len(p.y, d.y), - z: Range::from_pos_and_len(p.z, d.z), - } - } - - /// Construct a cuboid from its x, y and z ranges. - pub fn from_ranges(x: Range, y: Range, z: Range) -> Self { - Cuboid { x, y, z } - } - - /// Converts `self` to an absolute `Cuboid` so that the magnitude of each range is always - /// positive. - pub fn absolute(&self) -> Self { - let x = self.x.absolute(); - let y = self.y.absolute(); - let z = self.z.absolute(); - Cuboid { x, y, z } - } - - /// The position in the middle of the x range. - pub fn x(&self) -> S { - self.x.middle() - } - - /// The position in the middle of the y range. - pub fn y(&self) -> S { - self.y.middle() - } - - /// The position in the middle of the z range. - pub fn z(&self) -> S { - self.z.middle() - } - - /// The xyz position in the middle of the bounds. - pub fn xyz(&self) -> Point3 { - [self.x(), self.y(), self.z()].into() - } - - /// The centered x, y and z coordinates as a tuple. - pub fn x_y_z(&self) -> (S, S, S) { - (self.x(), self.y(), self.z()) - } - - /// Shift the cuboid along the x axis. - pub fn shift_x(self, x: S) -> Self { - Cuboid { - x: self.x.shift(x), - ..self - } - } - - /// Shift the cuboid along the y axis. - pub fn shift_y(self, y: S) -> Self { - Cuboid { - y: self.y.shift(y), - ..self - } - } - - /// Shift the cuboid along the z axis. - pub fn shift_z(self, z: S) -> Self { - Cuboid { - z: self.z.shift(z), - ..self - } - } - - /// Shift the cuboid by the given vector. - pub fn shift(self, v: Vector3) -> Self { - let Vector3 { x, y, z } = v; - Cuboid { - x: self.x.shift(x), - y: self.y.shift(y), - z: self.z.shift(z), - } - } - - /// Does the given cuboid contain the given point. - pub fn contains(&self, p: Point3) -> bool { - self.x.contains(p.x) && self.y.contains(p.y) && self.z.contains(p.z) - } - - /// Stretches the closest side(s) to the given point if the point lies outside of the Cuboid - /// area. - pub fn stretch_to_point(self, p: Point3) -> Self { - let Cuboid { x, y, z } = self; - Cuboid { - x: x.stretch_to_value(p.x), - y: y.stretch_to_value(p.y), - z: z.stretch_to_value(p.z), - } - } - - /// The cuboid representing the area in which two cuboids overlap. - pub fn overlap(self, other: Self) -> Option { - self.x.overlap(other.x).and_then(|x| { - self.y - .overlap(other.y) - .and_then(|y| self.z.overlap(other.z).map(|z| Cuboid { x, y, z })) - }) - } - - /// The cuboid that encompass the two given cuboids. - pub fn max(self, other: Self) -> Self - where - S: Float, - { - Cuboid { - x: self.x.max(other.x), - y: self.y.max(other.y), - z: self.z.max(other.y), - } - } - - /// The start of the range along the x axis. - pub fn left(&self) -> S { - self.x.start - } - - /// The end of the range along the x axis. - pub fn right(&self) -> S { - self.x.end - } - - /// The start of the range along the y axis. - pub fn bottom(&self) -> S { - self.y.start - } - - /// The end of the range along the y axis. - pub fn top(&self) -> S { - self.y.end - } - - /// The start of the range along the z axis. - pub fn front(&self) -> S { - self.z.start - } - - /// The end of the range along the z axis. - pub fn back(&self) -> S { - self.z.end - } - - /// The quad for the face at the start of the range along the x axis. - pub fn left_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 4, 6, 2, 0)) - } - - /// The quad for the face at the end of the range along the x axis. - pub fn right_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 1, 3, 7, 5)) - } - - /// The quad for the face at the start of the range along the y axis. - pub fn bottom_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 0, 1, 5, 4)) - } - - /// The quad for the face at the end of the range along the y axis. - pub fn top_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 2, 6, 7, 3)) - } - - /// The quad for the face at the start of the range along the z axis. - pub fn front_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 0, 2, 3, 1)) - } - - /// The quad for the face at the end of the range along the z axis. - pub fn back_quad(&self) -> FaceQuad { - Quad(quad_from_corner_indices!(self, 5, 7, 6, 4)) - } - - /// The quad for the given face. - pub fn face_quad(&self, face: Face) -> FaceQuad { - match face { - Face::Front => self.front_quad(), - Face::Right => self.right_quad(), - Face::Back => self.back_quad(), - Face::Left => self.left_quad(), - Face::Bottom => self.bottom_quad(), - Face::Top => self.top_quad(), - } - } - - /// The 8 corners of the cuboid in the following order: - /// - /// ```ignore - /// y - /// | z - /// |/ - /// 0---x - /// - /// 6---7 - /// /| /| - /// 2---3 | - /// | 4-|-5 - /// |/ |/ - /// 0---1 - /// ``` - pub fn corners(&self) -> [Point3; NUM_CORNERS as usize] { - let a = [self.x.start, self.y.start, self.z.start].into(); - let b = [self.x.end, self.y.start, self.z.start].into(); - let c = [self.x.start, self.y.end, self.z.start].into(); - let d = [self.x.end, self.y.end, self.z.start].into(); - let e = [self.x.start, self.y.start, self.z.end].into(); - let f = [self.x.end, self.y.start, self.z.end].into(); - let g = [self.x.start, self.y.end, self.z.end].into(); - let h = [self.x.end, self.y.end, self.z.end].into(); - [a, b, c, d, e, f, g, h] - } - - /// The same as `corners` but produces an iterator rather than a fixed-size array. - pub fn corners_iter(&self) -> Corners { - Corners { - cuboid: self, - corner_index: 0, - } - } - - /// The 6 faces of the of the cuboid in the order yielded by the `Faces` iterator. - pub fn faces(&self) -> [FaceQuad; NUM_FACES as usize] { - let mut faces = self.faces_iter(); - [ - faces.next().unwrap(), - faces.next().unwrap(), - faces.next().unwrap(), - faces.next().unwrap(), - faces.next().unwrap(), - faces.next().unwrap(), - ] - } - - /// An iterator yielding a quad for each face on the cuboid. - pub fn faces_iter(&self) -> FaceQuads { - FaceQuads { - faces: Faces { next_face_index: 0 }, - cuboid: self, - } - } - - /// Produce an iterator yielding every triangle in the cuboid (two for each face). - /// - /// Uses the `faces_iter` method internally. - pub fn triangles_iter(&self) -> Triangles { - let mut face_quads = self.faces_iter(); - let first_quad = face_quads.next().unwrap(); - let triangles = first_quad.triangles_iter(); - Triangles { - face_quads, - triangles, - } - } - - /// The six ranges used for the `Cuboid`'s eight subdivisions. - pub fn subdivision_ranges(&self) -> SubdivisionRanges { - let (x, y, z) = self.x_y_z(); - let x_a = Range::new(self.x.start, x); - let x_b = Range::new(x, self.x.end); - let y_a = Range::new(self.y.start, y); - let y_b = Range::new(y, self.y.end); - let z_a = Range::new(self.z.start, z); - let z_b = Range::new(z, self.z.end); - SubdivisionRanges { - x_a, - x_b, - y_a, - y_b, - z_a, - z_b, - } - } -} - -impl SubdivisionRanges -where - S: Copy, -{ - /// The `Cuboid`s representing each of the eight subdivisions. - /// - /// Subdivisions are yielded in the following order: - /// - /// 1. Front bottom left - /// 2. Front bottom right - /// 3. Front top left - /// 4. Front top right - /// 5. Back bottom left - /// 6. Back bottom right - /// 7. Back top left - /// 8. Back top right - pub fn cuboids(&self) -> [Cuboid; NUM_SUBDIVISIONS as usize] { - let c1 = subdivision_from_index!(self, 0); - let c2 = subdivision_from_index!(self, 1); - let c3 = subdivision_from_index!(self, 2); - let c4 = subdivision_from_index!(self, 3); - let c5 = subdivision_from_index!(self, 4); - let c6 = subdivision_from_index!(self, 5); - let c7 = subdivision_from_index!(self, 6); - let c8 = subdivision_from_index!(self, 7); - [c1, c2, c3, c4, c5, c6, c7, c8] - } - - /// The same as `cuboids` but each subdivision is yielded via the returned `Iterator`. - pub fn cuboids_iter(self) -> Subdivisions { - Subdivisions { - ranges: self, - subdivision_index: 0, - } - } - - // The subdivision at the given index within the range 0..NUM_SUBDIVISIONS. - fn subdivision_at_index(&self, index: u8) -> Option> { - let cuboid = match index { - 0 => subdivision_from_index!(self, 0), - 1 => subdivision_from_index!(self, 1), - 2 => subdivision_from_index!(self, 2), - 3 => subdivision_from_index!(self, 3), - 4 => subdivision_from_index!(self, 4), - 5 => subdivision_from_index!(self, 5), - 6 => subdivision_from_index!(self, 6), - 7 => subdivision_from_index!(self, 7), - _ => return None, - }; - Some(cuboid) - } -} - -impl Cuboid -where - S: BaseNum + Neg, -{ - /// The length of the cuboid along the *x* axis (aka `width` or `w` for short). - pub fn w(&self) -> S { - self.x.len() - } - - /// The length of the cuboid along the *y* axis (aka `height` or `h` for short). - pub fn h(&self) -> S { - self.y.len() - } - - /// The length of the cuboid along the *z* axis (aka `depth` or `d` for short). - pub fn d(&self) -> S { - self.z.len() - } - - /// The dimensions (width, height and depth) of the cuboid as a vector. - pub fn whd(&self) -> Vector3 { - [self.w(), self.h(), self.d()].into() - } - - /// The dimensions (width, height and depth) of the cuboid as a tuple. - pub fn w_h_d(&self) -> (S, S, S) { - (self.w(), self.h(), self.d()) - } - - /// The total volume of the cuboid. - pub fn volume(&self) -> S { - let (w, h, d) = self.w_h_d(); - w * h * d - } - - /// The position and dimensions of the cuboid. - pub fn xyz_whd(&self) -> (Point3, Vector3) { - (self.xyz(), self.whd()) - } - - /// The position and dimensions of the cuboid. - pub fn x_y_z_w_h_d(&self) -> (S, S, S, S, S, S) { - let (x, y, z) = self.x_y_z(); - let (w, h, d) = self.w_h_d(); - (x, y, z, w, h, d) - } - - /// The cuboid with some padding applied to the left side. - pub fn pad_left(self, pad: S) -> Self { - Cuboid { - x: self.x.pad_start(pad), - ..self - } - } - - /// The cuboid with some padding applied to the right side. - pub fn pad_right(self, pad: S) -> Self { - Cuboid { - x: self.x.pad_end(pad), - ..self - } - } - - /// The cuboid with some padding applied to the bottom side. - pub fn pad_bottom(self, pad: S) -> Self { - Cuboid { - y: self.y.pad_start(pad), - ..self - } - } - - /// The cuboid with some padding applied to the top side. - pub fn pad_top(self, pad: S) -> Self { - Cuboid { - y: self.y.pad_end(pad), - ..self - } - } - - /// The cuboid with some padding applied to the front side. - pub fn pad_front(self, pad: S) -> Self { - Cuboid { - z: self.z.pad_start(pad), - ..self - } - } - - /// The cuboid with some padding applied to the back side. - pub fn pad_back(self, pad: S) -> Self { - Cuboid { - z: self.z.pad_end(pad), - ..self - } - } - - /// The cuboid with some padding amount applied to each side. - pub fn pad(self, pad: S) -> Self { - let Cuboid { x, y, z } = self; - Cuboid { - x: x.pad(pad), - y: y.pad(pad), - z: z.pad(pad), - } - } -} - -fn corner_from_index(c: &Cuboid, index: u8) -> Option> -where - S: Copy, -{ - let p = match index { - 0 => corner_from_index!(0, c), - 1 => corner_from_index!(1, c), - 2 => corner_from_index!(2, c), - 3 => corner_from_index!(3, c), - 4 => corner_from_index!(4, c), - 5 => corner_from_index!(5, c), - 6 => corner_from_index!(6, c), - 7 => corner_from_index!(7, c), - _ => return None, - }; - Some(p.into()) -} - -impl<'a, S> Iterator for Corners<'a, S> -where - S: Copy, -{ - type Item = Point3; - fn next(&mut self) -> Option { - if let Some(p) = corner_from_index(self.cuboid, self.corner_index) { - self.corner_index += 1; - return Some(p); - } - None - } -} - -impl<'a, S> DoubleEndedIterator for Corners<'a, S> -where - S: Copy, -{ - fn next_back(&mut self) -> Option { - let next_index = self.corner_index + 1; - if let Some(p) = corner_from_index(self.cuboid, NUM_CORNERS - self.corner_index) { - self.corner_index = next_index; - return Some(p); - } - None - } -} - -impl<'a, S> ExactSizeIterator for Corners<'a, S> -where - S: Copy, -{ - fn len(&self) -> usize { - NUM_CORNERS as usize - self.corner_index as usize - } -} - -impl Face { - /// Produce a face from an index into the order in which faces are yielded by the cuboid - /// `Faces` iterator. - fn from_index(i: u8) -> Option { - let face = match i { - 0 => face_from_index!(0), - 1 => face_from_index!(1), - 2 => face_from_index!(2), - 3 => face_from_index!(3), - 4 => face_from_index!(4), - 5 => face_from_index!(5), - _ => return None, - }; - Some(face) - } -} - -impl<'a, S> FaceQuads<'a, S> {} - -impl Iterator for Faces { - type Item = Face; - fn next(&mut self) -> Option { - if let Some(face) = Face::from_index(self.next_face_index) { - self.next_face_index += 1; - return Some(face); - } - None - } -} - -impl DoubleEndedIterator for Faces { - fn next_back(&mut self) -> Option { - let next_face_index = self.next_face_index + 1; - if let Some(face) = Face::from_index(NUM_FACES - next_face_index) { - self.next_face_index = next_face_index; - return Some(face); - } - None - } -} - -impl ExactSizeIterator for Faces { - fn len(&self) -> usize { - NUM_FACES as usize - self.next_face_index as usize - } -} - -impl<'a, S> Iterator for FaceQuads<'a, S> -where - S: BaseNum, -{ - type Item = FaceQuad; - fn next(&mut self) -> Option { - self.faces.next().map(|f| self.cuboid.face_quad(f)) - } - fn size_hint(&self) -> (usize, Option) { - self.faces.size_hint() - } -} - -impl<'a, S> DoubleEndedIterator for FaceQuads<'a, S> -where - S: BaseNum, -{ - fn next_back(&mut self) -> Option { - self.faces.next_back().map(|f| self.cuboid.face_quad(f)) - } -} - -impl<'a, S> ExactSizeIterator for FaceQuads<'a, S> -where - S: BaseNum, -{ - fn len(&self) -> usize { - self.faces.len() - } -} - -impl<'a, S> Iterator for Triangles<'a, S> -where - S: BaseNum, -{ - type Item = Tri>; - fn next(&mut self) -> Option { - loop { - if let Some(tri) = self.triangles.next() { - return Some(tri); - } - self.triangles = match self.face_quads.next() { - Some(quad) => quad.triangles_iter(), - None => return None, - } - } - } - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl<'a, S> DoubleEndedIterator for Triangles<'a, S> -where - S: BaseNum, -{ - fn next_back(&mut self) -> Option { - loop { - if let Some(tri) = self.triangles.next_back() { - return Some(tri); - } - self.triangles = match self.face_quads.next_back() { - Some(quad) => quad.triangles_iter(), - None => return None, - } - } - } -} - -impl<'a, S> ExactSizeIterator for Triangles<'a, S> -where - S: BaseNum, -{ - fn len(&self) -> usize { - let remaining_triangles = self.triangles.len(); - let remaining_quads = self.face_quads.len(); - remaining_triangles + remaining_quads * 2 - } -} - -impl Iterator for Subdivisions -where - S: Copy, -{ - type Item = Cuboid; - fn next(&mut self) -> Option { - if let Some(sd) = self.ranges.subdivision_at_index(self.subdivision_index) { - self.subdivision_index += 1; - return Some(sd); - } - None - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl DoubleEndedIterator for Subdivisions -where - S: Copy, -{ - fn next_back(&mut self) -> Option { - let next_index = self.subdivision_index + 1; - if let Some(sd) = self - .ranges - .subdivision_at_index(NUM_SUBDIVISIONS - next_index) - { - self.subdivision_index = next_index; - return Some(sd); - } - None - } -} - -impl ExactSizeIterator for Subdivisions -where - S: Copy, -{ - fn len(&self) -> usize { - NUM_SUBDIVISIONS as usize - self.subdivision_index as usize - } -} diff --git a/nannou/src/geom/ellipse.rs b/nannou/src/geom/ellipse.rs deleted file mode 100644 index 50861ff0e..000000000 --- a/nannou/src/geom/ellipse.rs +++ /dev/null @@ -1,386 +0,0 @@ -use crate::geom::{self, scalar, Point2, Rect, Tri}; -use crate::math::num_traits::NumCast; -use crate::math::{self, BaseFloat, BaseNum}; -use std; -use std::ops::Neg; - -/// A simple ellipse type with helper methods around the `ellipse` module's functions. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Ellipse { - /// The width and height off the `Ellipse`. - pub rect: Rect, - /// The resolution (number of sides) of the `Ellipse`. - pub resolution: usize, -} - -/// A subsection of an `Ellipse`. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Section { - /// The ellipse from which this section is produced. - pub ellipse: Ellipse, - /// The angle in radians of the start of the section. - pub offset_radians: S, - /// The section of the circumference in radians. - pub section_radians: S, -} - -/// An iterator yielding the edges of an ellipse (or some section of an `ellipse`) as a series of -/// points. -#[derive(Clone, Debug)] -#[allow(missing_copy_implementations)] -pub struct Circumference { - index: usize, - num_points: usize, - middle: Point2, - rad_step: S, - rad_offset: S, - half_w: S, - half_h: S, -} - -/// All vertices necessary for yielding the triangles that make up the centre. -#[derive(Clone, Debug)] -#[allow(missing_copy_implementations)] -pub struct TriangleVertices { - middle: Option>, - circumference: Circumference, -} - -/// An iterator yielding an index for every vertex in every triangle in the ellipse. -#[derive(Clone, Debug)] -#[allow(missing_copy_implementations)] -pub struct TriangleIndices { - yield_middle: bool, - left: Option, - right: Option, - total: usize, -} - -/// An iterator yielding triangles that describe an oval or some section of an oval. -#[derive(Clone, Debug)] -pub struct Triangles { - // The last circumference point yielded by the `CircumferenceOffset` iterator. - last: Point2, - // The circumference points used to yield yielded by the `CircumferenceOffset` iterator. - points: Circumference, -} - -impl Ellipse -where - S: BaseNum + Neg, -{ - /// Construct a new ellipse from its bounding rect and resolution (number of sides). - pub fn new(rect: Rect, resolution: usize) -> Self { - Ellipse { rect, resolution } - } - - /// A section of the `Ellipse`. - /// - /// `offset_radians` describes the angle at which the offset begins. - /// - /// `section_radians` describes how large the section is as an angle. - pub fn section(self, offset_radians: S, section_radians: S) -> Section { - Section { - ellipse: self, - offset_radians, - section_radians, - } - } - - /// Produces an iterator yielding the points of the ellipse circumference. - pub fn circumference(self) -> Circumference { - let Ellipse { rect, resolution } = self; - Circumference::new(rect, resolution) - } -} - -impl Ellipse -where - S: BaseFloat, -{ - /// Produces an iterator yielding the triangles that describe the ellipse. - /// - /// TODO: Describe the order. - pub fn triangles(self) -> Triangles { - self.circumference().triangles() - } - - /// The same as **Triangles**, but produces the indices of each triangle into the returned - /// **TriangleVertices** iterator rather than the vertices for each corner. - pub fn triangle_indices(&self) -> (TriangleVertices, TriangleIndices) { - self.circumference().triangle_indices() - } -} - -impl Section -where - S: BaseNum + Neg, -{ - /// Produces an iterator yielding the points of the ellipse circumference. - pub fn circumference(self) -> Circumference { - let Section { - ellipse, - offset_radians, - section_radians, - } = self; - let circ = Circumference::new_section(ellipse.rect, ellipse.resolution, section_radians); - circ.offset_radians(offset_radians) - } -} - -impl Section -where - S: BaseFloat, -{ - /// Produces an iterator yielding the triangles that describe the ellipse section. - /// - /// TODO: Describe the order. - pub fn trangles(self) -> Triangles { - self.circumference().triangles() - } - - /// The same as **Triangles**, but produces the indices of each triangle into the returned - /// **TriangleVertices** iterator rather than the vertices for each corner. - pub fn triangle_indices(&self) -> (TriangleVertices, TriangleIndices) { - self.circumference().triangle_indices() - } -} - -impl Circumference -where - S: BaseNum + Neg, -{ - fn new_inner(rect: Rect, num_points: usize, rad_step: S) -> Self { - let (x, y, w, h) = rect.x_y_w_h(); - let two = math::two(); - Circumference { - index: 0, - num_points: num_points, - middle: [x, y].into(), - half_w: w / two, - half_h: h / two, - rad_step: rad_step, - rad_offset: S::zero(), - } - } - - /// An iterator yielding the ellipse's edges as a circumference represented as a series of - /// points. - /// - /// `resolution` is clamped to a minimum of `1` as to avoid creating a `Circumference` that - /// produces `NaN` values. - pub fn new(rect: Rect, mut resolution: usize) -> Self { - resolution = std::cmp::max(resolution, 1); - use std::f64::consts::PI; - let radians = S::from(2.0 * PI).unwrap(); - Self::new_section(rect, resolution, radians) - } - - /// Produces a new iterator that yields only a section of the ellipse's circumference, where - /// the section is described via its angle in radians. - /// - /// `resolution` is clamped to a minimum of `1` as to avoid creating a `Circumference` that - /// produces `NaN` values. - pub fn new_section(rect: Rect, resolution: usize, radians: S) -> Self { - let res = S::from(resolution).unwrap(); - Self::new_inner(rect, resolution + 1, radians / res) - } - - /// Produces a new iterator that yields only a section of the ellipse's circumference, where - /// the section is described via its angle in radians. - pub fn section(mut self, radians: S) -> Self { - let resolution = self.num_points - 1; - let res = S::from(resolution).unwrap(); - self.rad_step = radians / res; - self - } - - /// Rotates the position at which the iterator starts yielding points by the given radians. - /// - /// This is particularly useful for yielding a different section of the circumference when - /// using `circumference_section` - pub fn offset_radians(mut self, radians: S) -> Self { - self.rad_offset = radians; - self - } -} - -impl Circumference -where - S: BaseFloat, -{ - /// Produces an `Iterator` yielding `Triangle`s. - /// - /// Triangles are created by joining each edge yielded by the inner `Circumference` to the - /// middle of the ellipse. - pub fn triangles(mut self) -> Triangles { - let last = self.next().unwrap_or(self.middle); - Triangles { last, points: self } - } - - /// The same as **Triangles**, but produces the indices of each triangle into the returned - /// **TriangleVertices** iterator rather than the vertices for each corner. - pub fn triangle_indices(self) -> (TriangleVertices, TriangleIndices) { - let middle = Some(self.middle); - let num_vertices = self.len(); - let circumference = self; - let vertices = TriangleVertices { - middle, - circumference, - }; - let indices = TriangleIndices { - yield_middle: true, - left: Some(1), - right: Some(2), - total: num_vertices, - }; - (vertices, indices) - } -} - -impl Iterator for Circumference -where - S: BaseFloat, -{ - type Item = Point2; - fn next(&mut self) -> Option { - let Circumference { - ref mut index, - num_points, - middle, - rad_step, - rad_offset, - half_w, - half_h, - } = *self; - if *index >= num_points { - return None; - } - let index_s: S = NumCast::from(*index).unwrap(); - let x = middle.x + half_w * (rad_offset + rad_step * index_s).cos(); - let y = middle.y + half_h * (rad_offset + rad_step * index_s).sin(); - *index += 1; - Some([x, y].into()) - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -// TODO: -// impl DoubleEndedIterator for Circumference -// where -// S: BaseNum + Float, -// { -// } - -impl ExactSizeIterator for Circumference -where - S: BaseFloat, -{ - fn len(&self) -> usize { - self.num_points - self.index - } -} - -impl Iterator for TriangleVertices -where - S: BaseFloat, -{ - type Item = Point2; - fn next(&mut self) -> Option { - self.middle.take().or_else(|| self.circumference.next()) - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl ExactSizeIterator for TriangleVertices -where - S: BaseFloat, -{ - fn len(&self) -> usize { - (if self.middle.is_some() { 1 } else { 0 }) + self.circumference.len() - } -} - -impl Iterator for TriangleIndices { - type Item = usize; - fn next(&mut self) -> Option { - if self.yield_middle { - self.yield_middle = false; - Some(0) - } else if let Some(left) = self.left.take() { - Some(left) - } else if let Some(right) = self.right.take() { - // Check if we're done. If not, step the left and right indices. - if right < self.total { - self.yield_middle = true; - self.left = Some(right); - self.right = Some(right + 1); - } - Some(right) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl ExactSizeIterator for TriangleIndices { - fn len(&self) -> usize { - if let Some(right) = self.right { - let n_tris = self.total - right; - let remaining_middle = if self.yield_middle { 1 } else { 0 }; - let remaining_left = if self.left.is_some() { 1 } else { 0 }; - let remaining_right = 1; - n_tris * geom::tri::NUM_VERTICES as usize - + remaining_middle - + remaining_left - + remaining_right - } else { - 0 - } - } -} - -impl Iterator for Triangles -where - S: BaseFloat, -{ - type Item = Tri>; - fn next(&mut self) -> Option { - let Triangles { - ref mut points, - ref mut last, - } = *self; - points.next().map(|next| { - let triangle = Tri([points.middle, *last, next]); - *last = next; - triangle - }) - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl ExactSizeIterator for Triangles -where - S: BaseFloat, -{ - fn len(&self) -> usize { - self.points.len() - } -} diff --git a/nannou/src/geom/graph/edge.rs b/nannou/src/geom/graph/edge.rs deleted file mode 100644 index ae897a4d0..000000000 --- a/nannou/src/geom/graph/edge.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Items related to the edges of a geometry graph. -use crate::geom::{self, Vector3}; -use crate::math::{BaseFloat, Euler, Rad}; -use daggy; - -/// Unique index for an **Edge** within a **Graph**. -pub type Index = daggy::EdgeIndex; - -/// An iterator yielding multiple `Index`es. -pub type Indices = daggy::EdgeIndices; - -/// Describes an edge within the geometry graph. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Edge { - /// The unique kind of edge. - /// - /// Represents the combination of `Axis` and `Relative` association described by the edge. - pub kind: Kind, - /// A weight whose value's meaning depends on the edge's `Relative` association. - /// - /// For `Position` kind edges this represents a relative scalar value. - /// For `Orientation` kind edges this represents a relative angle in radians. - /// For `Scale` kind edges this represents the relative scale. - pub weight: S, -} - -/// The unique `Edge` kind - a combo of a `Relative` association and an `Axis`. -/// -/// Every incoming (parent) `Edge` for each `Node` in the graph *must* be a unique kind. E.g. -/// it does not make sense for a `Node` to be positioned relatively along the *x* axis to two -/// different parent `Node`s. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Kind { - /// The axis along which this edge describes some relationship. - pub axis: Axis, - /// The relative association described by the edge. - pub relative: Relative, -} - -/// Describes one of the three axes in three-dimensional space. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum Axis { - X, - Y, - Z, -} - -/// The various possible relative relationships that can be created between nodes. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Relative { - /// A relative position as a scalar value. - Position, - /// A relative orientation in radians. - Orientation, - /// A relative scale. - Scale, -} - -impl Kind { - /// Simple constructor for an edge `Kind`. - pub fn new(axis: Axis, relative: Relative) -> Self { - Kind { axis, relative } - } - - /// Simple constructor for and Edge describing a relative association over the **X** axis. - pub fn x(relative: Relative) -> Self { - Kind::new(Axis::X, relative) - } - - /// Simple constructor for and Edge describing a relative association over the **Y** axis. - pub fn y(relative: Relative) -> Self { - Kind::new(Axis::Y, relative) - } - - /// Simple constructor for and Edge describing a relative association over the **Z** axis. - pub fn z(relative: Relative) -> Self { - Kind::new(Axis::Z, relative) - } - - /// Simple constructor for an Edge describing a relative position along the given axis. - pub fn position(axis: Axis) -> Self { - let relative = Relative::Position; - Kind { axis, relative } - } - - /// Simple constructor for an Edge describing a relative orientation along the given axis. - pub fn orientation(axis: Axis) -> Self { - let relative = Relative::Orientation; - Kind { axis, relative } - } - - /// Simple constructor for an Edge describing a relative scale along the given axis. - pub fn scale(axis: Axis) -> Self { - let relative = Relative::Scale; - Kind { axis, relative } - } - - /// Simple constructor for and Edge describing a relative position over the **X** axis. - pub fn x_position() -> Self { - Kind::x(Relative::Position) - } - - /// Simple constructor for and Edge describing a relative orientation over the **X** axis. - pub fn x_orientation() -> Self { - Kind::x(Relative::Orientation) - } - - /// Simple constructor for and Edge describing a relative scale over the **X** axis. - pub fn x_scale() -> Self { - Kind::x(Relative::Scale) - } - - /// Simple constructor for and Edge describing a relative position over the **Y** axis. - pub fn y_position() -> Self { - Kind::y(Relative::Position) - } - - /// Simple constructor for and Edge describing a relative orientation over the **Y** axis. - pub fn y_orientation() -> Self { - Kind::y(Relative::Orientation) - } - - /// Simple constructor for and Edge describing a relative scale over the **Y** axis. - pub fn y_scale() -> Self { - Kind::y(Relative::Scale) - } - - /// Simple constructor for and Edge describing a relative position over the **Z** axis. - pub fn z_position() -> Self { - Kind::z(Relative::Position) - } - - /// Simple constructor for and Edge describing a relative orientation over the **Z** axis. - pub fn z_orientation() -> Self { - Kind::z(Relative::Orientation) - } - - /// Simple constructor for and Edge describing a relative scale over the **Z** axis. - pub fn z_scale() -> Self { - Kind::z(Relative::Scale) - } -} - -impl Edge { - /// Simple constructor for an `Edge`. - pub fn new(kind: Kind, weight: S) -> Self { - Edge { kind, weight } - } - - /// Simple constructor for an `Edge` describing a relative association over the **X** axis. - pub fn x(relative: Relative, weight: S) -> Self { - Edge::new(Kind::x(relative), weight) - } - - /// Simple constructor for an `Edge` describing a relative association over the **Y** axis. - pub fn y(relative: Relative, weight: S) -> Self { - Edge::new(Kind::y(relative), weight) - } - - /// Simple constructor for an `Edge` describing a relative association over the **Z** axis. - pub fn z(relative: Relative, weight: S) -> Self { - Edge::new(Kind::z(relative), weight) - } - - /// Simple constructor for an `Edge` describing a relative position over the given axis. - pub fn position(axis: Axis, weight: S) -> Self { - Edge::new(Kind::position(axis), weight) - } - - /// Simple constructor for an `Edge` describing a relative orientation over the given axis. - pub fn orientation(axis: Axis, weight: S) -> Self { - Edge::new(Kind::orientation(axis), weight) - } - - /// Simple constructor for an `Edge` describing a relative scale over the given axis. - pub fn scale(axis: Axis, weight: S) -> Self { - Edge::new(Kind::scale(axis), weight) - } - - /// Simple constructor for an `Edge` describing a relative position over the **X** axis. - pub fn x_position(weight: S) -> Self { - Edge::new(Kind::x_position(), weight) - } - - /// Simple constructor for an `Edge` describing a relative orientation over the **X** axis. - pub fn x_orientation(weight: S) -> Self { - Edge::new(Kind::x_orientation(), weight) - } - - /// Simple constructor for an `Edge` describing a relative scale over the **X** axis. - pub fn x_scale(weight: S) -> Self { - Edge::new(Kind::x_scale(), weight) - } - - /// Simple constructor for an `Edge` describing a relative position over the **Y** axis. - pub fn y_position(weight: S) -> Self { - Edge::new(Kind::y_position(), weight) - } - - /// Simple constructor for an `Edge` describing a relative orientation over the **Y** axis. - pub fn y_orientation(weight: S) -> Self { - Edge::new(Kind::y_orientation(), weight) - } - - /// Simple constructor for an `Edge` describing a relative scale over the **Y** axis. - pub fn y_scale(weight: S) -> Self { - Edge::new(Kind::y_scale(), weight) - } - - /// Simple constructor for an `Edge` describing a relative position over the **Z** axis. - pub fn z_position(weight: S) -> Self { - Edge::new(Kind::z_position(), weight) - } - - /// Simple constructor for an `Edge` describing a relative orientation over the **Z** axis. - pub fn z_orientation(weight: S) -> Self { - Edge::new(Kind::z_orientation(), weight) - } - - /// Simple constructor for an `Edge` describing a relative scale over the **Z** axis. - pub fn z_scale(weight: S) -> Self { - Edge::new(Kind::z_scale(), weight) - } -} - -/// The three edges describing the given position displacement. -pub fn displace(v: Vector3) -> [Edge; 3] { - [ - Edge::x_position(v.x), - Edge::y_position(v.y), - Edge::z_position(v.z), - ] -} - -/// The three edges describing the given orientation rotation. -pub fn rotate(e: Euler>) -> [Edge; 3] { - [ - Edge::x_orientation(e.x.0), - Edge::y_orientation(e.x.0), - Edge::z_orientation(e.z.0), - ] -} - -/// An edge for scaling each axis using the given single scalar scale value. -pub fn scale(scale: S) -> [Edge; 3] { - [ - Edge::x_scale(scale), - Edge::y_scale(scale), - Edge::z_scale(scale), - ] -} diff --git a/nannou/src/geom/graph/mod.rs b/nannou/src/geom/graph/mod.rs deleted file mode 100644 index f3c7192d1..000000000 --- a/nannou/src/geom/graph/mod.rs +++ /dev/null @@ -1,829 +0,0 @@ -use crate::geom::{self, Point3, Vector3}; -use crate::math::BaseFloat; -use daggy::petgraph::visit::{GraphBase, IntoNeighbors, Visitable}; -use daggy::{self, Walker}; -use std::iter; -use std::ops; -use std::option; - -pub use self::edge::Edge; -pub use self::node::Node; - -pub mod edge; -pub mod node; - -/// A composition of geometry described by an acyclic directed graph. -/// -/// The `Node`s within a graph may describe some primitive geometry (e.g. `Line`, `Cuboid`, etc) or -/// may contain other `Graph`s. This allows graphs to be composed of other graphs, which may then -/// be composed with other graphs, etc. -/// -/// The `Edge`s within a graph describe the relationships between the nodes. They allow for -/// describing the **position**, **orientation** and **scale** of nodes relative to others. -/// -/// All `Node`s other than the graph's "origin" node must have at least one parent, but may never -/// have more than one parent of each `edge::Kind`. -#[derive(Clone, Debug)] -pub struct Graph -where - S: BaseFloat, -{ - dag: Dag, - origin: node::Index, -} - -/// The `daggy` "directed acyclic graph" type used within the geometry graph. -pub type Dag = daggy::Dag, Edge, usize>; - -/// A **Walker** over some node's parent nodes. -pub struct Parents -where - S: BaseFloat, -{ - parents: daggy::Parents, Edge, usize>, -} - -/// A **Walker** over some node's children nodes. -pub struct Children -where - S: BaseFloat, -{ - children: daggy::Children, Edge, usize>, -} - -/// The slice of all nodes stored within the graph. -pub type RawNodes<'a, S = geom::scalar::Default> = daggy::RawNodes<'a, Node, usize>; - -/// The slice of all edges stored within the graph. -pub type RawEdges<'a, S = geom::scalar::Default> = daggy::RawEdges<'a, Edge, usize>; - -/// An alias for our Graph's **WouldCycle** error type. -pub type WouldCycle = daggy::WouldCycle>; - -/// An alias for our Graph's recursive walker. -pub type RecursiveWalk = daggy::walker::Recursive, F>; - -// An alias for the iterator yielding three parents that may or may not exist. -// -// Used for the `Position`, `Orientation` and `Scale` parents. -type ThreeNodes = iter::Chain< - iter::Chain, option::IntoIter>, - option::IntoIter, ->; - -/// An alias for the iterator yielding **X**, **Y** and **Z** **Position** parents. -pub type PositionParents = ThreeNodes; -/// An alias for the iterator yielding **X**, **Y** and **Z** **Orientation** parents. -pub type OrientationParents = ThreeNodes; -/// An alias for the iterator yielding **X**, **Y** and **Z** **Scale** parents. -pub type ScaleParents = ThreeNodes; -/// An alias for the iterator yielding **Position**, **Orientation** and **Scale** parents over the -/// **X** axis. -pub type XParents = ThreeNodes; -/// An alias for the iterator yielding **Position**, **Orientation** and **Scale** parents over the -/// **Y** axis. -pub type YParents = ThreeNodes; -/// An alias for the iterator yielding **Position**, **Orientation** and **Scale** parents over the -/// **Z** axis. -pub type ZParents = ThreeNodes; - -/// A **Walker** type yielding all transformed vertices of all nodes within the graph. -pub struct WalkVertices<'a, F, I, S: 'a = geom::scalar::Default> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - S: BaseFloat, -{ - dfs: &'a mut node::Dfs, - vertices_fn: F, - node: Option>, -} - -/// A **Walker** type yielding all transformed triangles of all nodes within the graph. -pub struct WalkTriangles<'a, F, I, V, S: 'a = geom::scalar::Default> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - S: BaseFloat, -{ - dfs: &'a mut node::Dfs, - triangles_fn: F, - node: Option>, -} - -/// An iterator yielding all vertices of all nodes within the graph. -/// -/// Uses the `WalkVertices` internally. -pub struct Vertices<'a, 'b, F, I, S: 'a + 'b = geom::scalar::Default> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - S: BaseFloat, -{ - graph: &'a Graph, - walker: WalkVertices<'b, F, I, S>, -} - -/// An iterator yielding all triangles of all nodes within the graph. -/// -/// Uses the `WalkTriangles` internally. -pub struct Triangles<'a, 'b, F, I, V, S: 'a + 'b = geom::scalar::Default> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - S: BaseFloat, -{ - graph: &'a Graph, - walker: WalkTriangles<'b, F, I, V, S>, -} - -impl<'a, F, I, S> WalkVertices<'a, F, I, S> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - I::Item: node::ApplyTransform, - S: BaseFloat, -{ - /// Return the next vertex in the graph. - pub fn next(&mut self, graph: &Graph) -> Option { - let WalkVertices { - ref mut dfs, - ref vertices_fn, - ref mut node, - } = *self; - loop { - if let Some(v) = node.as_mut().and_then(|n| n.next()) { - return Some(v); - } - match dfs.next_vertices(graph, vertices_fn) { - Some((_n, vs)) => *node = Some(vs), - None => return None, - } - } - } -} - -impl<'a, F, I, V, S> WalkTriangles<'a, F, I, V, S> -where - F: Fn(&node::Index) -> I, - I: IntoIterator>, - V: geom::Vertex + node::ApplyTransform, - S: BaseFloat, -{ - /// Return the next vertex in the graph. - pub fn next(&mut self, graph: &Graph) -> Option> { - let WalkTriangles { - ref mut dfs, - ref triangles_fn, - ref mut node, - } = *self; - loop { - if let Some(v) = node.as_mut().and_then(|n| n.next()) { - return Some(v); - } - match dfs.next_triangles(graph, triangles_fn) { - Some((_n, ts)) => *node = Some(ts), - None => return None, - } - } - } -} - -impl<'a, 'b, F, I, S> Iterator for Vertices<'a, 'b, F, I, S> -where - F: Fn(&node::Index) -> I, - I: IntoIterator, - I::Item: node::ApplyTransform, - S: BaseFloat, -{ - type Item = I::Item; - fn next(&mut self) -> Option { - self.walker.next(self.graph) - } -} - -impl<'a, 'b, F, I, V, S> Iterator for Triangles<'a, 'b, F, I, V, S> -where - F: Fn(&node::Index) -> I, - I: IntoIterator>, - V: geom::Vertex + node::ApplyTransform, - S: BaseFloat, -{ - type Item = geom::Tri; - fn next(&mut self) -> Option { - self.walker.next(self.graph) - } -} - -impl Graph -where - S: BaseFloat, -{ - /// Construct a new empty `Graph` with a single "origin" node. - /// - /// The "origin" is the "parent-most" of all nodes. Its transform is always equal to - /// `Transform::default()`. - /// - /// Calling this is the same as calling `Graph::default()`. - pub fn new() -> Self { - Graph::default() - } - - /// The **node::Index** of the origin node. - pub fn origin(&self) -> node::Index { - self.origin - } - - /// Construct the graph with pre-allocated buffers for the given `nodes`, `edges` and - /// `vertices` capacities. - pub fn with_capacity(nodes: usize, edges: usize) -> Self { - let mut dag = Dag::with_capacity(nodes, edges); - let origin = dag.add_node(Node::Point); - Graph { dag, origin } - } - - /// The total number of **Node**s in the **Graph**. - pub fn node_count(&self) -> usize { - self.dag.node_count() - } - - /// The total number of **Edge**s in the **Graph**. - pub fn edge_count(&self) -> usize { - self.dag.edge_count() - } - - /// Borrow the node at the given **node::Index** if there is one. - pub fn node(&self, idx: node::Index) -> Option<&Node> { - self.dag.node_weight(idx) - } - - /// Determine the full **Transform** for the **Node**. - /// - /// Returns **None** if the node does not exist. - pub fn node_transform(&self, idx: node::Index) -> Option> { - // If there is no node for the index, return **None**. - if self.node(idx).is_none() { - return None; - } - - // Calculate the transform. - let mut transform = node::Transform::default(); - for (e, parent) in self.parents(idx).iter(self) { - let parent_transform = self - .node_transform(parent) - .expect("no node for yielded parent"); - let edge = &self[e]; - transform.apply_edge(&parent_transform, edge); - } - - Some(transform) - } - - /// Transform the given vertices with the given node's **Transform**. - /// - /// This method uses the **node_transform** method internally. - /// - /// Returns **None** if the node does not exist. - pub fn node_vertices( - &self, - idx: node::Index, - vertices: I, - ) -> Option> - where - I: IntoIterator, - I::Item: node::ApplyTransform, - { - self.node_transform(idx) - .map(|transform| transform.vertices(vertices.into_iter())) - } - - /// Transform the given triangles with the given node's **Transform**. - /// - /// This method uses the **node_transform** method internally. - /// - /// Returns **None** if the node does not exist. - pub fn node_triangles( - &self, - idx: node::Index, - triangles: I, - ) -> Option> - where - I: IntoIterator>, - V: geom::Vertex + node::ApplyTransform, - { - self.node_transform(idx) - .map(|transform| transform.triangles(triangles.into_iter())) - } - - /// Borrow the edge at the given **edge::Index** if there is one. - pub fn edge(&self, idx: edge::Index) -> Option<&Edge> { - self.dag.edge_weight(idx) - } - - /// The slice containing all nodes. - pub fn raw_nodes(&self) -> RawNodes { - self.dag.raw_nodes() - } - - /// The slice containing all edges. - pub fn raw_edges(&self) -> RawEdges { - self.dag.raw_edges() - } - - /// Removes all **Node**s, **Edge**s and vertices from the **Graph** and resets the origin node. - /// - /// This does not de-allocate any buffers and should retain capacity. To drop all inner - /// buffers, use `mem::replace` with a new empty **Graph**. - pub fn clear(&mut self) { - self.dag.clear(); - let origin = self.dag.add_node(Node::Point); - self.origin = origin; - } - - /// Return the parent and child nodes on either end of the **Edge** at the given index. - pub fn edge_endpoints(&self, idx: edge::Index) -> Option<(node::Index, node::Index)> { - self.dag.edge_endpoints(idx) - } - - /// A **Walker** type that recursively walks the **Graph** using the given `recursive_fn`. - /// - /// **Panics** If the given start index does not exist within the **Graph**. - pub fn recursive_walk(&self, start: node::Index, recursive_fn: F) -> RecursiveWalk - where - F: FnMut(&Self, node::Index) -> Option<(edge::Index, node::Index)>, - { - RecursiveWalk::new(start, recursive_fn) - } - - /// Borrow the inner `daggy::Dag` (directed acyclic graph) upon which `Graph` is built. - /// - /// Can be useful/necessary for utilising some of the `daggy::Walker` types. - pub fn dag(&self) -> &Dag { - &self.dag - } - - /// Add the given **Node** to the graph. - /// - /// The created node will be a child of the graph's origin node. - /// - /// Returns the index of the new node. - pub fn add_node(&mut self, node: Node) -> node::Index { - let origin = self.origin(); - let zero = S::zero(); - let (x, y, z) = (zero, zero, zero); - let edges = edge::displace(Vector3 { x, y, z }); - let (_es, n) = self.add_child(origin, edges.iter().cloned(), node); - n - } - - // Remove and return the **Edge** at the given index. - // - // Return `None` if it didn't exist. - fn remove_edge(&mut self, idx: edge::Index) -> Option> { - self.dag.remove_edge(idx) - } - - /// Set the given **Edge** within the graph. - /// - /// The added edge will be in the direction `a` -> `b` - /// - /// There may only ever be one **Edge** of the given variant between `a` -> `b`. - /// - /// Checks if the edge would create a cycle in the **Graph**. - /// - /// If adding the edge **would not** cause the graph to cycle, the edge will be added and its - /// `edge::Index` returned. - /// - /// If adding the edge **would** cause the graph to cycle, the edge will not be added and - /// instead a `WouldCycle` error with the given weight will be returned. - /// - /// **Panics** if either `a` or `b` do not exist within the **Graph**. - /// - /// **Panics** if the **Graph** is at the maximum number of nodes for its index type. - pub fn set_edge( - &mut self, - a: node::Index, - b: node::Index, - edge: Edge, - ) -> Result> { - // Check to see if the node already has some matching incoming edge. - // Keep it if it's the one we want. Otherwise, remove any incoming edge that matches the given - // edge kind but isn't coming from the node that we desire. - let mut parents = self.parents(b); - let mut already_set = None; - - while let Some((in_edge_idx, in_node_idx)) = parents.walk_next(self) { - if edge.kind == self[in_edge_idx].kind { - if in_node_idx == a { - self.dag[in_edge_idx].weight = edge.weight; - already_set = Some(in_edge_idx); - } else { - self.remove_edge(in_edge_idx); - } - // Note that we only need to check for *one* edge as there can only ever be one - // parent edge of any kind for each node. We know this, as this method is the only - // function used by a public method that adds edges. - break; - } - } - - // If we don't already have an incoming edge from the requested parent, add one. - match already_set { - Some(edge_idx) => Ok(edge_idx), - None => self.dag.add_edge(a, b, edge), - } - } - - /// Add the given node as a child to the given `parent` connected via the given edges. - /// - /// There may only ever be one **Edge** of the given variant between `a` -> `b`. - /// - /// **Panics** if: - /// - /// - `parent` does not exist within the **Graph**. - /// - `edges` does not contain at least one **Edge**. - /// - the **Graph** is at the maximum number of nodes for its index type. - pub fn add_child( - &mut self, - parent: node::Index, - edges: E, - node: Node, - ) -> (edge::Indices, node::Index) - where - E: IntoIterator>, - { - let n = self.dag.add_node(node); - let mut edges = edges.into_iter().peekable(); - match edges.next() { - None => panic!("`edges` must contain at least one edge"), - Some(first) => { - let edges = Some(first).into_iter().chain(edges).map(|e| (parent, n, e)); - let edge_indices = self - .dag - .add_edges(edges) - .expect("cannot create a cycle when adding a new child"); - (edge_indices, n) - } - } - } - - /// Add the given children to the given `parent` connected via the given edges for each child. - /// - /// Returns an iterator yielding the node and edge indices for each child that was added. - /// - /// There may only ever be one **Edge** of the given variant between `a` -> `b`. - /// - /// **Panics** if: - /// - /// - `parent` does not exist within the **Graph**. - /// - any of the child `edges` iterators do not contain at least one **Edge**. - /// - the **Graph** is at the maximum number of nodes for its index type. - pub fn add_children( - &mut self, - parent: node::Index, - children: C, - ) -> Vec<(edge::Indices, node::Index)> - where - C: IntoIterator)>, - E: IntoIterator>, - { - let mut children_indices = vec![]; - for (edges, node) in children { - let child_indices = self.add_child(parent, edges, node); - children_indices.push(child_indices); - } - children_indices - } - - /// Produce a walker yielding all vertices from all nodes within the graph in order of - /// discovery within a depth-first-search. - pub fn walk_vertices<'a, F, I>( - &self, - dfs: &'a mut node::Dfs, - vertices_fn: F, - ) -> WalkVertices<'a, F, I, S> - where - F: Fn(&node::Index) -> I, - I: IntoIterator, - I::Item: node::ApplyTransform, - { - let node = None; - WalkVertices { - dfs, - vertices_fn, - node, - } - } - - /// Produce a walker yielding all vertices from all nodes within the graph in order of - /// discovery within a depth-first-search. - pub fn walk_triangles<'a, F, I, V>( - &self, - dfs: &'a mut node::Dfs, - triangles_fn: F, - ) -> WalkTriangles<'a, F, I, V, S> - where - F: Fn(&node::Index) -> I, - I: IntoIterator>, - V: geom::Vertex + node::ApplyTransform, - { - let node = None; - WalkTriangles { - dfs, - triangles_fn, - node, - } - } - - /// Produce an iterator yielding all vertices from all nodes within the graph in order of - /// discovery within a depth-first-search. - pub fn vertices<'a, 'b, F, I>( - &'a self, - dfs: &'b mut node::Dfs, - vertices_fn: F, - ) -> Vertices<'a, 'b, F, I, S> - where - F: Fn(&node::Index) -> I, - I: IntoIterator, - I::Item: node::ApplyTransform, - { - let walker = self.walk_vertices(dfs, vertices_fn); - let graph = self; - Vertices { graph, walker } - } - - /// Produce an iterator yielding all triangles from all nodes within the graph in order of - /// discovery within a depth-first-search. - pub fn triangles<'a, 'b, F, I, V>( - &'a self, - dfs: &'b mut node::Dfs, - triangles_fn: F, - ) -> Triangles<'a, 'b, F, I, V, S> - where - F: Fn(&node::Index) -> I, - I: IntoIterator>, - V: geom::Vertex + node::ApplyTransform, - { - let walker = self.walk_triangles(dfs, triangles_fn); - let graph = self; - Triangles { graph, walker } - } - - /// The `Cuboid` that bounds all nodes within the geometry graph. - /// - /// Returns `None` if the graph contains no vertices. - /// - /// 1. Iterates over all nodes. - /// 2. Expands a cuboid to the max bounds of each node. - /// 3. Returns the resulting cuboid. - pub fn bounding_cuboid( - &self, - dfs: &mut node::Dfs, - vertices_fn: F, - ) -> Option> - where - F: Fn(&node::Index) -> I, - I: IntoIterator>, - { - let vertices = self.vertices(dfs, vertices_fn); - geom::bounding_cuboid(vertices) - } - - //--------------- - // PARENT METHODS - //--------------- - - /// A **Walker** type that may be used to step through the parents of the given child node. - pub fn parents(&self, child: node::Index) -> Parents { - let parents = self.dag.parents(child); - Parents { parents } - } - - /// If the **Node** at the given index has some parent along an **Edge** of the given variant, - /// return an index to it. - pub fn edge_parent(&self, idx: node::Index, edge: edge::Kind) -> Option { - self.parents(idx) - .iter(self) - .find(|&(e, _)| self[e].kind == edge) - .map(|(_, n)| n) - } - - /// Return the index of the parent along the given node's **Position** **Edge**. - pub fn position_parent(&self, idx: node::Index, axis: edge::Axis) -> Option { - let kind = edge::Kind::new(axis, edge::Relative::Position); - self.edge_parent(idx, kind) - } - - /// Return the index of the parent along the given node's **Position** **Edge**. - pub fn x_position_parent(&self, idx: node::Index) -> Option { - self.position_parent(idx, edge::Axis::X) - } - - /// Return the index of the parent along the given node's **Position** **Edge**. - pub fn y_position_parent(&self, idx: node::Index) -> Option { - self.position_parent(idx, edge::Axis::Y) - } - - /// Return the index of the parent along the given node's **Position** **Edge**. - pub fn z_position_parent(&self, idx: node::Index) -> Option { - self.position_parent(idx, edge::Axis::Z) - } - - /// Produce an **Iterator** yielding the **Position** parents to the given node. - /// - /// Parents are always yielded in order of axis, e.g. **X**, **Y** then **Z**. - pub fn position_parents(&self, idx: node::Index) -> PositionParents { - self.x_position_parent(idx) - .into_iter() - .chain(self.y_position_parent(idx)) - .chain(self.z_position_parent(idx)) - } - - /// Return the index of the parent along the given node's **Orientation** **Edge**. - pub fn orientation_parent(&self, idx: node::Index, axis: edge::Axis) -> Option { - let kind = edge::Kind::new(axis, edge::Relative::Orientation); - self.edge_parent(idx, kind) - } - - /// Return the index of the parent along the given node's **Orientation** **Edge**. - pub fn x_orientation_parent(&self, idx: node::Index) -> Option { - self.orientation_parent(idx, edge::Axis::X) - } - - /// Return the index of the parent along the given node's **Orientation** **Edge**. - pub fn y_orientation_parent(&self, idx: node::Index) -> Option { - self.orientation_parent(idx, edge::Axis::Y) - } - - /// Return the index of the parent along the given node's **Orientation** **Edge**. - pub fn z_orientation_parent(&self, idx: node::Index) -> Option { - self.orientation_parent(idx, edge::Axis::Z) - } - - /// Produce an **Iterator** yielding the **Orientation** parents to the given node. - /// - /// Parents are always yielded in order of axis, e.g. **X**, **Y** then **Z**. - pub fn orientation_parents(&self, idx: node::Index) -> OrientationParents { - self.x_orientation_parent(idx) - .into_iter() - .chain(self.y_orientation_parent(idx)) - .chain(self.z_orientation_parent(idx)) - } - - /// Return the index of the parent along the given node's **Scale** **Edge**. - pub fn scale_parent(&self, idx: node::Index, axis: edge::Axis) -> Option { - let kind = edge::Kind::new(axis, edge::Relative::Scale); - self.edge_parent(idx, kind) - } - - /// Return the index of the parent along the given node's **Scale** **Edge**. - pub fn x_scale_parent(&self, idx: node::Index) -> Option { - self.scale_parent(idx, edge::Axis::X) - } - - /// Return the index of the parent along the given node's **Scale** **Edge**. - pub fn y_scale_parent(&self, idx: node::Index) -> Option { - self.scale_parent(idx, edge::Axis::Y) - } - - /// Return the index of the parent along the given node's **Scale** **Edge**. - pub fn z_scale_parent(&self, idx: node::Index) -> Option { - self.scale_parent(idx, edge::Axis::Z) - } - - /// Produce an **Iterator** yielding the **Scale** parents to the given node. - /// - /// Parents are always yielded in order of axis, e.g. **X**, **Y** then **Z**. - pub fn scale_parents(&self, idx: node::Index) -> ScaleParents { - self.x_scale_parent(idx) - .into_iter() - .chain(self.y_scale_parent(idx)) - .chain(self.z_scale_parent(idx)) - } - - /// Produce an **Iterator** yielding the **X** parents to the given node. - /// - /// Parents are always yielded in order of **Position**, **Orientation** and **Scale**. - pub fn x_parents(&self, idx: node::Index) -> XParents { - self.x_position_parent(idx) - .into_iter() - .chain(self.x_orientation_parent(idx)) - .chain(self.x_scale_parent(idx)) - } - - /// Produce an **Iterator** yielding the **Y** parents to the given node. - /// - /// Parents are always yielded in order of **Position**, **Orientation** and **Scale**. - pub fn y_parents(&self, idx: node::Index) -> YParents { - self.y_position_parent(idx) - .into_iter() - .chain(self.y_orientation_parent(idx)) - .chain(self.y_scale_parent(idx)) - } - - /// Produce an **Iterator** yielding the **Z** parents to the given node. - /// - /// Parents are always yielded in order of **Position**, **Orientation** and **Scale**. - pub fn z_parents(&self, idx: node::Index) -> ZParents { - self.z_position_parent(idx) - .into_iter() - .chain(self.z_orientation_parent(idx)) - .chain(self.z_scale_parent(idx)) - } - - //----------------- - // CHILDREN METHODS - //----------------- - - /// A **Walker** type that may be used to step through the children of the given parent node. - pub fn children(&self, parent: node::Index) -> Children { - let children = self.dag.children(parent); - Children { children } - } - - // TODO: Add `x_position_children`, `position_children`, etc methods. -} - -impl Default for Graph -where - S: BaseFloat, -{ - fn default() -> Self { - let mut dag = Dag::new(); - let origin = dag.add_node(Node::Point); - Graph { dag, origin } - } -} - -impl GraphBase for Graph -where - S: BaseFloat, -{ - type NodeId = node::Index; - type EdgeId = edge::Index; -} - -impl Visitable for Graph -where - S: BaseFloat, -{ - type Map = as Visitable>::Map; - fn visit_map(&self) -> Self::Map { - self.dag.visit_map() - } - fn reset_map(&self, map: &mut Self::Map) { - self.dag.reset_map(map) - } -} - -impl<'a, S> IntoNeighbors for &'a Graph -where - S: BaseFloat, -{ - type Neighbors = <&'a Dag as IntoNeighbors>::Neighbors; - fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { - self.dag.neighbors(n) - } -} - -impl ops::Index for Graph -where - S: BaseFloat, -{ - type Output = Node; - fn index<'a>(&'a self, id: node::Index) -> &'a Self::Output { - self.node(id).unwrap() - } -} - -impl ops::Index for Graph -where - S: BaseFloat, -{ - type Output = Edge; - fn index<'a>(&'a self, idx: edge::Index) -> &'a Self::Output { - self.edge(idx).unwrap() - } -} - -impl<'a, S> Walker<&'a Graph> for Children -where - S: BaseFloat, -{ - type Item = (edge::Index, node::Index); - #[inline] - fn walk_next(&mut self, graph: &'a Graph) -> Option { - self.children.walk_next(&graph.dag) - } -} - -impl<'a, S> Walker<&'a Graph> for Parents -where - S: BaseFloat, -{ - type Item = (edge::Index, node::Index); - #[inline] - fn walk_next(&mut self, graph: &'a Graph) -> Option { - self.parents.walk_next(&graph.dag) - } -} diff --git a/nannou/src/geom/graph/node.rs b/nannou/src/geom/graph/node.rs deleted file mode 100644 index ebbd6a8f8..000000000 --- a/nannou/src/geom/graph/node.rs +++ /dev/null @@ -1,465 +0,0 @@ -//! Items related to the nodes of a geometry graph. - -use crate::geom; -use crate::geom::graph::Edge; -use crate::geom::{scalar, Graph, Point3, Vector3}; -use crate::math::{self, BaseFloat, Basis3, Euler, Rad, Rotation}; -use daggy::petgraph::visit::{self, Visitable}; -use daggy::{self, Walker}; -use std::collections::HashMap; -use std::marker::PhantomData; -use std::ops; - -/// Unique index for a **Node** within a **Graph**. -pub type Index = daggy::NodeIndex; - -/// The **Node** type used within the **Graph**. -#[derive(Clone, Debug)] -pub enum Node -where - S: BaseFloat, -{ - /// A point has no vertices other than that yielded at the node's position. - /// - /// Useful for acting as an invisible "reference" node for controlling other children nodes. - /// - /// Also used to represent the graph's "origin" node. - Point, - /// A nested Graph. - Graph { graph: super::Graph, dfs: Dfs }, -} - -/// An iterator yielding all vertices for a node transformed by some given transform. -#[derive(Clone, Debug)] -pub struct TransformedVertices -where - S: BaseFloat, -{ - transform: PreparedTransform, - vertices: I, -} - -/// An iterator yielding all vertices for a node transformed by some given transform. -#[derive(Clone, Debug)] -pub struct TransformedTriangles -where - S: BaseFloat, -{ - transform: PreparedTransform, - triangles: I, - _vertex: PhantomData, -} - -/// A node's resulting rotation, displacement and scale relative to the graph's origin. -/// -/// A transform is calculated and applied to a node's vertices in the following order: -/// -/// 1. **scale**: `1.0 * parent_scale * edge_scale` -/// 2. **rotation**: `0.0 + parent_position + edge_displacement` -/// 3. **displacement**: 0.0 + parent_orientation + edge_orientation` -#[derive(Clone, Debug, PartialEq)] -pub struct Transform -where - S: BaseFloat, -{ - /// A scaling amount along each axis. - /// - /// The scaling amount is multiplied onto each vertex of the node. - pub scale: Vector3, - /// A rotation amount along each axis, describing a relative orientation. - /// - /// Rotates all vertices around the node origin when applied. - pub rot: Euler>, - /// A displacement amount along each axis. - /// - /// This vector is added onto the position of each vertex of the node. - pub disp: Vector3, -} - -/// A node's resulting rotation, displacement and scale relative to the graph's origin. -/// -/// The same as **Transfrom** but the euler has been converted to a matrix for more efficient -/// application. -#[derive(Clone, Debug, PartialEq)] -pub struct PreparedTransform { - /// A scaling amount along each axis. - /// - /// The scaling amount is multiplied onto each vertex of the node. - pub scale: Vector3, - /// A rotation amount along each axis, describing a relative orientation. - /// - /// Rotates all vertices around the node origin when applied. - pub rot: Basis3, - /// A displacement amount along each axis. - /// - /// This vector is added onto the position of each vertex of the node. - pub disp: Vector3, -} - -/// Mappings from node indices to their respective transform within the graph. -/// -/// This is calculated via the `Graph::update_transform_map` method. -#[derive(Clone, Debug, PartialEq)] -pub struct TransformMap -where - S: BaseFloat, -{ - map: HashMap>, -} - -/// A depth-first-search over nodes in the graph, yielding each node's unique index alongside its -/// absolute transform. -/// -/// The traversal may start at any given node. -/// -/// **Note:** The algorithm may not behave correctly if nodes are removed during iteration. It may -/// not necessarily visit added nodes or edges. -#[derive(Clone, Debug)] -pub struct Dfs -where - S: BaseFloat, -{ - dfs: visit::Dfs as Visitable>::Map>, - visited: TransformMap, -} - -impl Dfs -where - S: BaseFloat, -{ - /// Create a new **Dfs** starting from the graph's origin. - pub fn new(graph: &Graph) -> Self { - Self::start_from(graph, graph.origin()) - } - - /// Create a new **Dfs** starting from the node at the given node. - pub fn start_from(graph: &Graph, start: Index) -> Self { - let dfs = visit::Dfs::new(graph, start); - let visited = TransformMap::default(); - Dfs { dfs, visited } - } - - /// Clears the visit state. - pub fn reset(&mut self, graph: &Graph) { - self.dfs.reset(graph); - self.dfs.move_to(graph.origin()); - } - - /// Keep the discovered map but clear the visit stack and restart the dfs from the given node. - pub fn move_to(&mut self, start: Index) { - self.dfs.move_to(start); - } - - /// Return the tranform for the next node in the DFS. - /// - /// Returns `None` if the traversal is finished. - pub fn next_transform(&mut self, graph: &Graph) -> Option<(Index, Transform)> { - let n = match self.dfs.next(graph) { - None => return None, - Some(n) => n, - }; - let mut transform = Transform::default(); - for (e, parent) in graph.parents(n).iter(graph) { - let parent_transform = &self.visited[&parent]; - let edge = &graph[e]; - transform.apply_edge(parent_transform, edge); - } - self.visited.map.insert(n, transform.clone()); - Some((n, transform)) - } - - /// Return the vertices for the next node in the DFS. - /// - /// Uses `Dfs::next_transform` internally. - /// - /// Returns `None` if the traversal is finished. - pub fn next_vertices( - &mut self, - graph: &Graph, - vertices_fn: F, - ) -> Option<(Index, TransformedVertices)> - where - F: FnOnce(&Index) -> I, - I: IntoIterator, - I::Item: ApplyTransform, - { - self.next_transform(graph).map(|(n, transform)| { - let vertices = vertices_fn(&n); - let vertices = vertices.into_iter(); - (n, transform.vertices(vertices)) - }) - } - - /// Return the triangles for the next node in the DFS. - /// - /// Uses `Dfs::next_transform` and `Node::triangles` internally. - /// - /// Returns `None` if the traversal is finished. - pub fn next_triangles( - &mut self, - graph: &Graph, - triangles_fn: F, - ) -> Option<(Index, TransformedTriangles)> - where - F: FnOnce(&Index) -> I, - I: IntoIterator>, - V: geom::Vertex + ApplyTransform, - { - self.next_transform(graph).map(|(n, transform)| { - let triangles = triangles_fn(&n); - let triangles = triangles.into_iter(); - (n, transform.triangles(triangles)) - }) - } -} - -impl<'a, S> Walker<&'a Graph> for Dfs -where - S: BaseFloat, -{ - type Item = (Index, Transform); - fn walk_next(&mut self, graph: &'a Graph) -> Option { - self.next_transform(graph) - } -} - -impl Default for TransformMap -where - S: BaseFloat, -{ - fn default() -> Self { - TransformMap { - map: Default::default(), - } - } -} - -impl ops::Deref for TransformMap -where - S: BaseFloat, -{ - type Target = HashMap>; - fn deref(&self) -> &Self::Target { - &self.map - } -} - -impl Into>> for TransformMap -where - S: BaseFloat, -{ - fn into(self) -> HashMap> { - self.map - } -} - -impl Transform -where - S: BaseFloat, -{ - /// Apply the given parent `Edge` to this transform. - pub fn apply_edge(&mut self, parent: &Self, edge: &Edge) { - use crate::geom::graph::edge::{Axis, Relative}; - match (edge.kind.relative, edge.kind.axis) { - (Relative::Position, Axis::X) => self.disp.x += parent.disp.x + edge.weight, - (Relative::Position, Axis::Y) => self.disp.y += parent.disp.y + edge.weight, - (Relative::Position, Axis::Z) => self.disp.z += parent.disp.z + edge.weight, - (Relative::Orientation, Axis::X) => self.rot.x += parent.rot.x - Rad(edge.weight), - (Relative::Orientation, Axis::Y) => self.rot.y += parent.rot.y - Rad(edge.weight), - (Relative::Orientation, Axis::Z) => self.rot.z += parent.rot.z - Rad(edge.weight), - (Relative::Scale, Axis::X) => self.scale.x *= parent.scale.x * edge.weight, - (Relative::Scale, Axis::Y) => self.scale.y *= parent.scale.y * edge.weight, - (Relative::Scale, Axis::Z) => self.scale.z *= parent.scale.z * edge.weight, - } - } - - /// Prepare this transform for application. - pub fn prepare(self) -> PreparedTransform { - let Transform { disp, rot, scale } = self; - let rot = Basis3::from(rot); - PreparedTransform { disp, rot, scale } - } - - /// Transform the given vertices. - pub fn vertices(self, vertices: I) -> TransformedVertices - where - I: IntoIterator, - I::Item: ApplyTransform, - { - let transform = self.prepare(); - let vertices = vertices.into_iter(); - TransformedVertices { - transform, - vertices, - } - } - - /// Transform the given vertices. - pub fn triangles(self, triangles: I) -> TransformedTriangles - where - I: IntoIterator>, - V: geom::Vertex + ApplyTransform, - { - let transform = self.prepare(); - let triangles = triangles.into_iter(); - let _vertex = PhantomData; - TransformedTriangles { - transform, - triangles, - _vertex, - } - } -} - -impl Default for Transform -where - S: BaseFloat, -{ - fn default() -> Self { - let zero = S::zero(); - let one = S::one(); - let scale = Vector3 { - x: one, - y: one, - z: one, - }; - let rot = Euler { - x: Rad(zero), - y: Rad(zero), - z: Rad(zero), - }; - let disp = Vector3 { - x: zero, - y: zero, - z: zero, - }; - Transform { scale, rot, disp } - } -} - -impl math::Transform> for Transform -where - S: BaseFloat, -{ - fn one() -> Self { - let one = S::one(); - let (x, y, z) = (one, one, one); - Transform { - scale: Vector3 { x, y, z }, - rot: Euler { - x: Rad(x), - y: Rad(y), - z: Rad(z), - }, - disp: Vector3 { x, y, z }, - } - } - - fn look_at(_eye: Point3, _center: Point3, _up: Vector3) -> Self { - unimplemented!(); - } - - fn transform_vector(&self, _vec: Vector3) -> Vector3 { - unimplemented!(); - } - - fn inverse_transform_vector(&self, _vec: Vector3) -> Option> { - unimplemented!(); - } - - fn transform_point(&self, _point: Point3) -> Point3 { - unimplemented!(); - } - - fn concat(&self, _other: &Self) -> Self { - unimplemented!(); - } - - fn inverse_transform(&self) -> Option { - unimplemented!(); - } -} - -/// Apply the given transform to the given 3D point. -pub fn transform_point(transform: &PreparedTransform, mut point: Point3) -> Point3 -where - S: BaseFloat, -{ - // Scale the point relative to the node origin. - point.x *= transform.scale.x; - point.y *= transform.scale.y; - point.z *= transform.scale.z; - // Rotate the point around the node origin. - point = transform.rot.rotate_point(point.into()).into(); - // Displace the point from the node origin. - point += transform.disp; - point -} - -/// Vertex types which may apply a transform and produce a resulting transform. -pub trait ApplyTransform -where - S: BaseFloat, -{ - /// Apply the given transform and return the result. - fn apply_transform(self, transform: &PreparedTransform) -> Self; -} - -impl ApplyTransform for Point3 -where - S: BaseFloat, -{ - fn apply_transform(self, transform: &PreparedTransform) -> Self { - transform_point(transform, self) - } -} - -impl Iterator for TransformedVertices -where - I: Iterator, - I::Item: ApplyTransform, - S: BaseFloat, -{ - type Item = I::Item; - fn next(&mut self) -> Option { - self.vertices - .next() - .map(|vertex| vertex.apply_transform(&self.transform)) - } -} - -impl Iterator for TransformedTriangles -where - I: Iterator>, - V: geom::Vertex + ApplyTransform, - S: BaseFloat, -{ - type Item = geom::Tri; - fn next(&mut self) -> Option { - self.triangles - .next() - .map(|tri| tri.map_vertices(|vertex| vertex.apply_transform(&self.transform))) - } -} - -impl ExactSizeIterator for TransformedVertices -where - I: ExactSizeIterator, - I::Item: ApplyTransform, - S: BaseFloat, -{ - fn len(&self) -> usize { - self.vertices.len() - } -} - -impl ExactSizeIterator for TransformedTriangles -where - I: Iterator> + ExactSizeIterator, - V: geom::Vertex + ApplyTransform, - S: BaseFloat, -{ - fn len(&self) -> usize { - self.triangles.len() - } -} diff --git a/nannou/src/geom/mod.rs b/nannou/src/geom/mod.rs index aaa05fdf3..04632824c 100644 --- a/nannou/src/geom/mod.rs +++ b/nannou/src/geom/mod.rs @@ -9,100 +9,7 @@ //! - Functions for determining the bounding rectangle or cuboid. //! - A function for finding the centroid. -use crate::math::num_traits::cast; -use crate::math::{BaseFloat, EuclideanSpace}; -use std::ops; - -pub mod cuboid; -pub mod ellipse; -pub mod graph; pub mod path; -pub mod point; -pub mod polygon; -pub mod quad; -pub mod range; -pub mod rect; -pub mod scalar; -pub mod tri; -pub mod vector; -pub mod vertex; -pub use self::cuboid::Cuboid; -pub use self::ellipse::Ellipse; -pub use self::graph::Graph; pub use self::path::{path, Path}; -pub use self::point::{pt2, pt3, pt4, Point2, Point3, Point4}; -pub use self::polygon::Polygon; -pub use self::quad::Quad; -pub use self::range::{Align, Edge, Range}; -pub use self::rect::{Corner, Padding, Rect}; -pub use self::tri::Tri; -pub use self::vector::{vec2, vec3, vec4, Vector2, Vector3, Vector4}; -pub use self::vertex::{Vertex, Vertex2d, Vertex3d}; - -// General geometry utility functions - -/// The `Rect` that bounds the given sequence of vertices. -/// -/// Returns `None` if the given iterator is empty. -pub fn bounding_rect(vertices: I) -> Option::Scalar>> -where - I: IntoIterator, - I::Item: Vertex2d, -{ - let mut vertices = vertices.into_iter(); - vertices.next().map(|first| { - let Point2 { x, y } = first.point2(); - let bounds = Rect { - x: Range::new(x, x), - y: Range::new(y, y), - }; - vertices.fold(bounds, |b, v| { - let Point2 { x, y } = v.point2(); - let point = Point2 { x, y }; - b.stretch_to_point(point) - }) - }) -} - -/// The `Cuboid` that bounds the given sequence of vertices. -/// -/// Returns `None` if the given iterator is empty. -pub fn bounding_cuboid(vertices: I) -> Option::Scalar>> -where - I: IntoIterator, - I::Item: Vertex3d, -{ - let mut vertices = vertices.into_iter(); - vertices.next().map(|first| { - let Point3 { x, y, z } = first.point3(); - let bounds = Cuboid { - x: Range::new(x, x), - y: Range::new(y, y), - z: Range::new(z, z), - }; - vertices.fold(bounds, |b, v| { - let Point3 { x, y, z } = v.point3(); - let point = Point3 { x, y, z }; - b.stretch_to_point(point) - }) - }) -} - -/// The `centroid` (average position) of all vertices in the given iterator. -/// -/// Returns `None` if the given iterator contains no vertices. -pub fn centroid(vertices: I) -> Option -where - I: IntoIterator, - I::Item: Vertex + EuclideanSpace, - ::Diff: ops::Div::Diff>, - S: BaseFloat, -{ - let mut vertices = vertices.into_iter(); - vertices.next().map(|first| { - let init = (1, first.to_vec()); - let (len, total) = vertices.fold(init, |(i, acc), p| (i + 1, acc + p.to_vec())); - EuclideanSpace::from_vec(total / cast(len).unwrap()) - }) -} +pub use nannou_core::geom::*; diff --git a/nannou/src/geom/path.rs b/nannou/src/geom/path.rs index 80661c6a6..c4ced61b3 100644 --- a/nannou/src/geom/path.rs +++ b/nannou/src/geom/path.rs @@ -4,7 +4,8 @@ //! offerred by `lyon` in a way that interoperates a little more fluidly and consistently with the //! rest of nannou's API. -use crate::geom::{Point2, Vector2}; +use crate::geom::Point2; +use crate::glam::Vec2; /// A wrapper around a 2D lyon path exposing a nannou-friendly API. pub struct Path { @@ -97,13 +98,13 @@ impl Builder { /// /// If the current sub-path contains edges, this ends the sub-path without closing it. pub fn move_to(mut self, to: Point2) -> Self { - self.builder.move_to(to.into()); + self.builder.move_to(to.to_array().into()); self } /// Adds a line segment to the current sub-path and sets the current position. pub fn line_to(mut self, to: Point2) -> Self { - self.builder.line_to(to.into()); + self.builder.line_to(to.to_array().into()); self } @@ -116,14 +117,18 @@ impl Builder { /// Add a quadratic bezier curve to the path. pub fn quadratic_bezier_to(mut self, ctrl: Point2, to: Point2) -> Self { - self.builder.quadratic_bezier_to(ctrl.into(), to.into()); + self.builder + .quadratic_bezier_to(ctrl.to_array().into(), to.to_array().into()); self } /// Add a cubic bezier curve to the path. pub fn cubic_bezier_to(mut self, ctrl1: Point2, ctrl2: Point2, to: Point2) -> Self { - self.builder - .cubic_bezier_to(ctrl1.into(), ctrl2.into(), to.into()); + self.builder.cubic_bezier_to( + ctrl1.to_array().into(), + ctrl2.to_array().into(), + to.to_array().into(), + ); self } @@ -131,13 +136,13 @@ impl Builder { pub fn arc( mut self, center: Point2, - radii: Vector2, + radii: Vec2, sweep_angle_radians: f32, x_rotation_radians: f32, ) -> Self { self.builder.arc( - center.into(), - radii.into(), + center.to_array().into(), + radii.to_array().into(), lyon::math::Angle::radians(sweep_angle_radians), lyon::math::Angle::radians(x_rotation_radians), ); @@ -152,7 +157,8 @@ impl Builder { /// Returns the current position of the head of the path. pub fn position(&self) -> Point2 { - self.builder.current_position().into() + let p = self.builder.current_position(); + [p.x, p.y].into() } /// Build the path and return it. diff --git a/nannou/src/geom/point.rs b/nannou/src/geom/point.rs deleted file mode 100644 index 5df4c0c77..000000000 --- a/nannou/src/geom/point.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Implementation of the **Point** types. -//! -//! Currently, **Point** is simply a type alias for **Vector**. While this makes it easier for new -//! uses to understand and switch between the two, it also conflates the the two mathematical -//! concepts which are quite distinct. It is possible that in the future, we will switch to using -//! distinct types. For now, we are attempting to monitor usage and feedback to determine whether -//! or not this change is worth it. - -use crate::geom::{scalar, Vector2, Vector3, Vector4}; - -/// A 2-dimensional point type. -pub type Point2 = Vector2; - -/// A 3-dimensional point type. -pub type Point3 = Vector3; - -/// A 4-dimensional point type. -pub type Point4 = Vector4; - -/// Construct a 2-dimensional point. -pub fn pt2(x: S, y: S) -> Point2 { - Point2 { x, y } -} - -/// Construct a 3-dimensional point. -pub fn pt3(x: S, y: S, z: S) -> Point3 { - Point3 { x, y, z } -} - -/// Construct a 4-dimensional point. -pub fn pt4(x: S, y: S, z: S, w: S) -> Point4 { - Point4 { x, y, z, w } -} diff --git a/nannou/src/geom/polygon.rs b/nannou/src/geom/polygon.rs deleted file mode 100644 index 5f0b79527..000000000 --- a/nannou/src/geom/polygon.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::geom::tri::{self, Tri}; -use crate::geom::{Cuboid, Rect, Vertex, Vertex2d, Vertex3d}; - -/// A simple type wrapper around a list of points that describe a polygon. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Polygon { - /// The iterator yielding all points in the polygon. - pub points: I, -} - -/// An iterator yielding indices into a polygon's vertices required to triangulate the polygon. -#[derive(Clone, Debug)] -pub struct TriangleIndices { - index: usize, - n_points: usize, -} - -impl Polygon -where - I: Iterator, -{ - /// Construct a new polygon from the given list of points describing its vertices. - pub fn new

(points: P) -> Self - where - P: IntoIterator, - { - let points = points.into_iter(); - Polygon { points } - } - - /// Triangulate the polygon given as a list of `Point`s describing its sides. - /// - /// Returns `None` if the polygon's iterator yields less than two points. - pub fn triangles(self) -> Option> { - triangles(self.points) - } - - /// Returns `Some` with the touched triangle if the given `Point` is over the polygon described - /// by the given series of points. - /// - /// This uses the `triangles` function internally. - pub fn contains(self, p: &I::Item) -> Option> - where - I::Item: Vertex2d, - { - contains(self.points, p) - } - - /// The `Rect` that bounds the polygon. - /// - /// Returns `None` if the polygon's point iterator is empty. - pub fn bounding_rect(self) -> Option::Scalar>> - where - I::Item: Vertex2d, - { - super::bounding_rect(self.points) - } - - /// The `Cuboid that bounds the polygon. - /// - /// Returns `None` if the polygon's point iterator is empty. - pub fn bounding_cuboid(self) -> Option::Scalar>> - where - I::Item: Vertex3d, - { - super::bounding_cuboid(self.points) - } -} - -/// An iterator that triangulates a polygon represented by a sequence of points describing its -/// edges. -#[derive(Clone, Debug)] -pub struct Triangles -where - I: Iterator, -{ - first: I::Item, - prev: I::Item, - points: I, -} - -/// Triangulate the polygon given as a list of `Point`s describing its sides. -/// -/// Returns `None` if the given iterator yields less than two points. -pub fn triangles(points: I) -> Option> -where - I: IntoIterator, -{ - let mut points = points.into_iter(); - let first = match points.next() { - Some(p) => p, - None => return None, - }; - let prev = match points.next() { - Some(p) => p, - None => return None, - }; - Some(Triangles { - first: first, - prev: prev, - points: points, - }) -} - -/// An iterator yielding indices into a polygon's vertices required to triangulate the polygon. -pub fn triangle_indices(n_points: usize) -> TriangleIndices { - let index = 0; - TriangleIndices { index, n_points } -} - -/// Returns `Some` with the touched triangle if the given `Point` is over the polygon described by -/// the given series of points. -/// -/// This uses the `triangles` function internally. -pub fn contains(points: I, point: &I::Item) -> Option> -where - I: IntoIterator, - I::Item: Vertex2d, -{ - triangles(points).and_then(|ts| tri::iter_contains(ts, &point)) -} - -impl Iterator for Triangles -where - I: Iterator, - I::Item: Vertex, -{ - type Item = Tri; - fn next(&mut self) -> Option { - self.points.next().map(|point| { - let t = Tri([self.first, self.prev, point]); - self.prev = point; - t - }) - } -} - -impl Iterator for TriangleIndices { - type Item = usize; - fn next(&mut self) -> Option { - let index = self.index; - let tri_index = index / 3; - if self.n_points < tri_index + 3 { - return None; - } - self.index += 1; - match index % 3 { - 0 => Some(0), - remainder => Some(tri_index + remainder), - } - } -} diff --git a/nannou/src/geom/quad.rs b/nannou/src/geom/quad.rs deleted file mode 100644 index 6fbd898b0..000000000 --- a/nannou/src/geom/quad.rs +++ /dev/null @@ -1,363 +0,0 @@ -use crate::geom::{tri, vertex, Cuboid, Range, Rect, Tri, Vertex, Vertex2d, Vertex3d}; -use crate::math::EuclideanSpace; -use std::ops::{Deref, Index}; - -/// The number of vertices in a quad. -pub const NUM_VERTICES: u8 = 4; - -/// The number of triangles that make up a quad. -pub const NUM_TRIANGLES: u8 = 2; - -/// The same as `triangles`, but instead returns the vertex indices for each triangle. -pub const TRIANGLE_INDEX_TRIS: TrianglesIndexTris = [[0, 1, 2], [0, 2, 3]]; -pub type TrianglesIndexTris = [[usize; tri::NUM_VERTICES as usize]; NUM_TRIANGLES as usize]; - -/// The number of indices used to describe each triangle in the quad. -pub const NUM_TRIANGLE_INDICES: u8 = 6; - -/// The same as `triangles`, but instead returns the vertex indices for each triangle. -pub const TRIANGLE_INDICES: [usize; NUM_TRIANGLE_INDICES as usize] = [0, 1, 2, 0, 2, 3]; - -/// A quad represented by its four vertices. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -pub struct Quad(pub [V; NUM_VERTICES as usize]); - -/// An `Iterator` yielding the two triangles that make up a quad. -#[derive(Clone, Debug)] -pub struct Triangles { - a: Option>, - b: Option>, -} - -/// A simple iterator yielding each vertex in a `Quad`. -#[derive(Clone, Debug)] -pub struct Vertices { - quad: Quad, - index: u8, -} - -impl Quad -where - V: Vertex, -{ - /// Produce an iterator yielding each vertex in the `Quad`. - pub fn vertices(self) -> Vertices { - vertices(self) - } - - /// Produce the centroid of the quad, aka the "mean"/"average" vertex. - pub fn centroid(&self) -> V - where - V: EuclideanSpace, - { - centroid(self) - } - - /// Triangulates the given quad, represented by four points that describe its edges in either - /// clockwise or anti-clockwise order. - /// - /// # Example - /// - /// The following rectangle - /// - /// ```ignore - /// a b - /// -------- - /// | | - /// | | - /// | | - /// -------- - /// d c - /// - /// ``` - /// - /// given as - /// - /// ```ignore - /// triangles([a, b, c, d]) - /// ``` - /// - /// returns - /// - /// ```ignore - /// (Tri([a, b, c]), Tri([a, c, d])) - /// ``` - /// - /// Here's a basic code example: - /// - /// ``` - /// use nannou::geom::{self, pt2, Quad, Tri}; - /// - /// fn main() { - /// let a = pt2(0.0, 1.0); - /// let b = pt2(1.0, 1.0); - /// let c = pt2(1.0, 0.0); - /// let d = pt2(0.0, 0.0); - /// let quad = Quad([a, b, c, d]); - /// let triangles = geom::quad::triangles(&quad); - /// assert_eq!(triangles, (Tri([a, b, c]), Tri([a, c, d]))); - /// } - /// ``` - #[inline] - pub fn triangles(&self) -> (Tri, Tri) { - triangles(self) - } - - /// The same as `triangles` but provided as an **Iterator**. - pub fn triangles_iter(&self) -> Triangles { - triangles_iter(self) - } - - /// The bounding `Rect` of the quad. - pub fn bounding_rect(self) -> Rect - where - V: Vertex2d, - { - let (a, b, c, d) = self.into(); - let (a, b, c, d) = (a.point2(), b.point2(), c.point2(), d.point2()); - let rect = Rect { - x: Range::new(a.x, a.x), - y: Range::new(a.y, a.y), - }; - rect.stretch_to_point(b) - .stretch_to_point(c) - .stretch_to_point(d) - } - - /// The bounding `Rect` of the triangle. - pub fn bounding_cuboid(self) -> Cuboid - where - V: Vertex3d, - { - let (a, b, c, d) = self.into(); - let (a, b, c, d) = (a.point3(), b.point3(), c.point3(), d.point3()); - let cuboid = Cuboid { - x: Range::new(a.x, a.x), - y: Range::new(a.y, a.y), - z: Range::new(a.z, a.z), - }; - cuboid - .stretch_to_point(b) - .stretch_to_point(c) - .stretch_to_point(d) - } - - /// Map the **Quad**'s vertices to a new type. - pub fn map_vertices(self, mut map: F) -> Quad - where - F: FnMut(V) -> V2, - { - let (a, b, c, d) = self.into(); - Quad([map(a), map(b), map(c), map(d)]) - } -} - -/// Produce an iterator yielding each vertex in the given **Quad**. -pub fn vertices(quad: Quad) -> Vertices { - let index = 0; - Vertices { quad, index } -} - -/// Produce the centroid of the quad, aka the "mean"/"average" vertex. -pub fn centroid(quad: &Quad) -> V -where - V: EuclideanSpace, -{ - EuclideanSpace::centroid(&quad[..]) -} - -/// Triangulates the given quad, represented by four points that describe its edges in either -/// clockwise or anti-clockwise order. -/// -/// # Example -/// -/// The following rectangle -/// -/// ```ignore -/// -/// a b -/// -------- -/// | | -/// | | -/// | | -/// -------- -/// d c -/// -/// ``` -/// -/// given as -/// -/// ```ignore -/// triangles([a, b, c, d]) -/// ``` -/// -/// returns -/// -/// ```ignore -/// (Tri([a, b, c]), Tri([a, c, d])) -/// ``` -/// -/// Here's a basic code example: -/// -/// ``` -/// use nannou::geom::{self, pt2, Quad, Tri}; -/// -/// fn main() { -/// let a = pt2(0.0, 1.0); -/// let b = pt2(1.0, 1.0); -/// let c = pt2(1.0, 0.0); -/// let d = pt2(0.0, 0.0); -/// let quad = Quad([a, b, c, d]); -/// let triangles = geom::quad::triangles(&quad); -/// assert_eq!(triangles, (Tri([a, b, c]), Tri([a, c, d]))); -/// } -/// ``` -#[inline] -pub fn triangles(q: &Quad) -> (Tri, Tri) -where - V: Vertex, -{ - let a = Tri::from_index_tri(&q.0, &TRIANGLE_INDEX_TRIS[0]); - let b = Tri::from_index_tri(&q.0, &TRIANGLE_INDEX_TRIS[1]); - (a, b) -} - -/// The same as `triangles` but provided as an `Iterator`. -pub fn triangles_iter(points: &Quad) -> Triangles -where - V: Vertex, -{ - let (a, b) = triangles(points); - Triangles { - a: Some(a), - b: Some(b), - } -} - -impl Iterator for Triangles { - type Item = Tri; - fn next(&mut self) -> Option { - self.a.take().or_else(|| self.b.take()) - } - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl DoubleEndedIterator for Triangles { - fn next_back(&mut self) -> Option { - self.b.take().or_else(|| self.a.take()) - } -} - -impl ExactSizeIterator for Triangles { - fn len(&self) -> usize { - match (&self.a, &self.b) { - (&Some(_), &Some(_)) => 2, - (&None, &Some(_)) => 0, - _ => 1, - } - } -} - -impl Iterator for Vertices -where - V: Clone, -{ - type Item = V; - fn next(&mut self) -> Option { - if self.index < NUM_VERTICES { - let v = self.quad[self.index as usize].clone(); - self.index += 1; - Some(v) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl ExactSizeIterator for Vertices -where - V: Clone, -{ - fn len(&self) -> usize { - NUM_VERTICES as usize - self.index as usize - } -} - -impl Deref for Quad { - type Target = [V; NUM_VERTICES as usize]; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From<[V; NUM_VERTICES as usize]> for Quad -where - V: Vertex, -{ - fn from(points: [V; NUM_VERTICES as usize]) -> Self { - Quad(points) - } -} - -impl From<(V, V, V, V)> for Quad -where - V: Vertex, -{ - fn from((a, b, c, d): (V, V, V, V)) -> Self { - Quad([a, b, c, d]) - } -} - -impl Into<[V; NUM_VERTICES as usize]> for Quad -where - V: Vertex, -{ - fn into(self) -> [V; NUM_VERTICES as usize] { - self.0 - } -} - -impl Into<(V, V, V, V)> for Quad -where - V: Vertex, -{ - fn into(self) -> (V, V, V, V) { - (self[0], self[1], self[2], self[3]) - } -} - -impl AsRef> for Quad -where - V: Vertex, -{ - fn as_ref(&self) -> &Quad { - self - } -} - -impl AsRef<[V; NUM_VERTICES as usize]> for Quad -where - V: Vertex, -{ - fn as_ref(&self) -> &[V; NUM_VERTICES as usize] { - &self.0 - } -} - -impl Index for Quad -where - V: Vertex, -{ - type Output = V; - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} diff --git a/nannou/src/geom/range.rs b/nannou/src/geom/range.rs deleted file mode 100644 index 4d7c69021..000000000 --- a/nannou/src/geom/range.rs +++ /dev/null @@ -1,754 +0,0 @@ -//! A type for working with one-dimensional ranges. - -use crate::geom::scalar; -use crate::math::num_traits::{Float, One, Zero}; -use crate::math::{self, two, BaseNum}; -use std::ops::Neg; - -/// Some start and end position along a single axis. -/// -/// As an example, a **Rect** is made up of two **Range**s; one along the *x* axis, and one along -/// the *y* axis. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Range { - /// The start of some `Range` along an axis. - pub start: S, - /// The end of some `Range` along an axis. - pub end: S, -} - -/// Represents either the **Start** or **End** **Edge** of a **Range**. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub enum Edge { - /// The beginning of a **Range**. - Start, - /// The end of a **Range**. - End, -} - -/// Describes alignment along a range. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub enum Align { - Start, - Middle, - End, -} - -impl Range -where - S: BaseNum, -{ - /// Construct a new `Range` from a given range, i.e. `Range::new(start, end)`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range { start: 0.0, end: 10.0 }, Range::new(0.0, 10.0)); - /// ``` - pub fn new(start: S, end: S) -> Self { - Range { - start: start, - end: end, - } - } - - /// Construct a new `Range` from a given length and its centered position. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 10.0), Range::from_pos_and_len(5.0, 10.0)); - /// assert_eq!(Range::new(-5.0, 1.0), Range::from_pos_and_len(-2.0, 6.0)); - /// assert_eq!(Range::new(-100.0, 200.0), Range::from_pos_and_len(50.0, 300.0)); - /// ``` - pub fn from_pos_and_len(pos: S, len: S) -> Self { - let half_len = len / two(); - let start = pos - half_len; - let end = pos + half_len; - Range::new(start, end) - } - - /// The `start` value subtracted from the `end` value. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(-5.0, 5.0).magnitude(), 10.0); - /// assert_eq!(Range::new(5.0, -5.0).magnitude(), -10.0); - /// assert_eq!(Range::new(15.0, 10.0).magnitude(), -5.0); - /// ``` - pub fn magnitude(&self) -> S { - self.end - self.start - } - - /// The absolute length of the Range aka the absolute magnitude. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(-5.0, 5.0).len(), 10.0); - /// assert_eq!(Range::new(5.0, -5.0).len(), 10.0); - /// assert_eq!(Range::new(15.0, 10.0).len(), 5.0); - /// ``` - pub fn len(&self) -> S - where - S: Neg, - { - let mag = self.magnitude(); - let zero = S::zero(); - if mag < zero { - -mag - } else { - mag - } - } - - /// Return the value directly between the start and end values. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(-5.0, 5.0).middle(), 0.0); - /// assert_eq!(Range::new(5.0, -5.0).middle(), 0.0); - /// assert_eq!(Range::new(10.0, 15.0).middle(), 12.5); - /// assert_eq!(Range::new(20.0, 40.0).middle(), 30.0); - /// assert_eq!(Range::new(20.0, -40.0).middle(), -10.0); - /// ``` - pub fn middle(&self) -> S { - (self.end + self.start) / two() - } - - /// The current range with its start and end values swapped. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(-5.0, 5.0).invert(), Range::new(5.0, -5.0)); - /// assert_eq!(Range::new(-10.0, 10.0).invert(), Range::new(10.0, -10.0)); - /// assert_eq!(Range::new(0.0, 7.25).invert(), Range::new(7.25, 0.0)); - /// assert_eq!(Range::new(5.0, 1.0).invert(), Range::new(1.0, 5.0)); - /// ``` - pub fn invert(self) -> Self { - Range { - start: self.end, - end: self.start, - } - } - - /// Map the given scalar from `Self` to some other given `Range`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(0.0, 5.0); - /// - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.map_value(2.5, &b), 5.0); - /// assert_eq!(a.map_value(0.0, &b), 0.0); - /// assert_eq!(a.map_value(5.0, &b), 10.0); - /// assert_eq!(a.map_value(-5.0, &b), -10.0); - /// assert_eq!(a.map_value(10.0, &b), 20.0); - /// - /// let c = Range::new(10.0, -10.0); - /// assert_eq!(a.map_value(2.5, &c), 0.0); - /// assert_eq!(a.map_value(0.0, &c), 10.0); - /// assert_eq!(a.map_value(5.0, &c), -10.0); - /// assert_eq!(a.map_value(-5.0, &c), 30.0); - /// assert_eq!(a.map_value(10.0, &c), -30.0); - /// ``` - pub fn map_value(&self, value: S, other: &Self) -> S { - math::map_range(value, self.start, self.end, other.start, other.end) - } - - /// Interpolates the **Range** using the given `weight`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let r = Range::new(-5.0, 5.0); - /// assert_eq!(r.lerp(0.0), -5.0); - /// assert_eq!(r.lerp(1.0), 5.0); - /// assert_eq!(r.lerp(0.5), 0.0); - /// ``` - pub fn lerp(&self, amount: S) -> S { - self.start + ((self.end - self.start) * amount) - } - - /// Shift the `Range` start and end points by a given scalar. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 5.0).shift(5.0), Range::new(5.0, 10.0)); - /// assert_eq!(Range::new(0.0, 5.0).shift(-5.0), Range::new(-5.0, 0.0)); - /// assert_eq!(Range::new(5.0, -5.0).shift(-5.0), Range::new(0.0, -10.0)); - /// ``` - pub fn shift(self, amount: S) -> Self { - Range { - start: self.start + amount, - end: self.end + amount, - } - } - - /// The direction of the Range represented as a normalised scalar. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 5.0).direction(), 1.0); - /// assert_eq!(Range::new(0.0, 0.0).direction(), 0.0); - /// assert_eq!(Range::new(0.0, -5.0).direction(), -1.0); - /// ``` - pub fn direction(&self) -> S - where - S: Neg + One + Zero, - { - if self.start < self.end { - S::one() - } else if self.start > self.end { - -S::one() - } else { - S::zero() - } - } - - /// Converts the Range to an undirected Range. By ensuring that `start` <= `end`. - /// - /// If `start` > `end`, then the start and end points will be swapped. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 5.0).undirected(), Range::new(0.0, 5.0)); - /// assert_eq!(Range::new(5.0, 1.0).undirected(), Range::new(1.0, 5.0)); - /// assert_eq!(Range::new(10.0, -10.0).undirected(), Range::new(-10.0, 10.0)); - /// ``` - #[deprecated = "use `absolute` instead"] - pub fn undirected(self) -> Self { - if self.start > self.end { - self.invert() - } else { - self - } - } - - /// Converts the Range to an absolute Range by ensuring that `start` <= `end`. - /// - /// If `start` > `end`, then the start and end points will be swapped. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 5.0).absolute(), Range::new(0.0, 5.0)); - /// assert_eq!(Range::new(5.0, 1.0).absolute(), Range::new(1.0, 5.0)); - /// assert_eq!(Range::new(10.0, -10.0).absolute(), Range::new(-10.0, 10.0)); - /// ``` - pub fn absolute(self) -> Self { - if self.start > self.end { - self.invert() - } else { - self - } - } - - /// The Range that encompasses both self and the given Range. - /// - /// The returned Range's `start` will always be <= its `end`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(0.0, 3.0); - /// let b = Range::new(7.0, 10.0); - /// assert_eq!(a.max(b), Range::new(0.0, 10.0)); - /// - /// let c = Range::new(-20.0, -30.0); - /// let d = Range::new(5.0, -7.5); - /// assert_eq!(c.max(d), Range::new(-30.0, 5.0)); - /// ``` - pub fn max(self, other: Self) -> Self - where - S: Float, - { - let start = self.start.min(self.end).min(other.start).min(other.end); - let end = self.start.max(self.end).max(other.start).max(other.end); - Range::new(start, end) - } - - /// The Range that represents the range of the overlap between two Ranges if there is some. - /// - /// Note that If one end of `self` aligns exactly with the opposite end of `other`, `Some` - /// `Range` will be returned with a magnitude of `0.0`. This is useful for algorithms that - /// involve calculating the visibility of widgets, as it allows for including widgets whose - /// bounding box may be a one dimensional straight line. - /// - /// The returned `Range`'s `start` will always be <= its `end`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(0.0, 6.0); - /// let b = Range::new(4.0, 10.0); - /// assert_eq!(a.overlap(b), Some(Range::new(4.0, 6.0))); - /// - /// let c = Range::new(10.0, -30.0); - /// let d = Range::new(-5.0, 20.0); - /// assert_eq!(c.overlap(d), Some(Range::new(-5.0, 10.0))); - /// - /// let e = Range::new(0.0, 2.5); - /// let f = Range::new(50.0, 100.0); - /// assert_eq!(e.overlap(f), None); - /// ``` - pub fn overlap(mut self, mut other: Self) -> Option { - self = self.absolute(); - other = other.absolute(); - let start = math::partial_max(self.start, other.start); - let end = math::partial_min(self.end, other.end); - let magnitude = end - start; - if magnitude >= S::zero() { - Some(Range::new(start, end)) - } else { - None - } - } - - /// The Range that encompasses both self and the given Range. - /// - /// The same as [**Range::max**](./struct.Range.html#method.max) but retains `self`'s original - /// direction. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(0.0, 3.0); - /// let b = Range::new(7.0, 10.0); - /// assert_eq!(a.max_directed(b), Range::new(0.0, 10.0)); - /// - /// let c = Range::new(-20.0, -30.0); - /// let d = Range::new(5.0, -7.5); - /// assert_eq!(c.max_directed(d), Range::new(5.0, -30.0)); - /// ``` - pub fn max_directed(self, other: Self) -> Self - where - S: Float, - { - if self.start <= self.end { - self.max(other) - } else { - self.max(other).invert() - } - } - - /// Is the given scalar within our range. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let range = Range::new(0.0, 10.0); - /// assert!(range.contains(5.0)); - /// assert!(!range.contains(12.0)); - /// assert!(!range.contains(-1.0)); - /// assert!(range.contains(0.0)); - /// assert!(range.contains(10.0)); - /// ``` - pub fn contains(&self, pos: S) -> bool { - let Range { start, end } = self.absolute(); - start <= pos && pos <= end - } - - /// Round the values at both ends of the Range and return the result. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.25, 9.5).round(), Range::new(0.0, 10.0)); - /// assert_eq!(Range::new(4.95, -5.3).round(), Range::new(5.0, -5.0)); - /// ``` - pub fn round(self) -> Self - where - S: Float, - { - Self::new(self.start.round(), self.end.round()) - } - - /// Floor the values at both ends of the Range and return the result. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.25, 9.5).floor(), Range::new(0.0, 9.0)); - /// assert_eq!(Range::new(4.95, -5.3).floor(), Range::new(4.0, -6.0)); - /// ``` - pub fn floor(self) -> Self - where - S: Float, - { - Self::new(self.start.floor(), self.end.floor()) - } - - /// The Range with some padding given to the `start` value. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 10.0).pad_start(2.0), Range::new(2.0, 10.0)); - /// assert_eq!(Range::new(10.0, 0.0).pad_start(2.0), Range::new(8.0, 0.0)); - /// ``` - pub fn pad_start(mut self, pad: S) -> Self - where - S: Neg, - { - self.start += if self.start <= self.end { pad } else { -pad }; - self - } - - /// The Range with some padding given to the `end` value. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 10.0).pad_end(2.0), Range::new(0.0, 8.0)); - /// assert_eq!(Range::new(10.0, 0.0).pad_end(2.0), Range::new(10.0, 2.0)); - /// ``` - pub fn pad_end(mut self, pad: S) -> Self - where - S: Neg, - { - self.end += if self.start <= self.end { -pad } else { pad }; - self - } - - /// The Range with some given padding to be applied to each end. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 10.0).pad(2.0), Range::new(2.0, 8.0)); - /// assert_eq!(Range::new(10.0, 0.0).pad(2.0), Range::new(8.0, 2.0)); - /// ``` - pub fn pad(self, pad: S) -> Self - where - S: Neg, - { - self.pad_start(pad).pad_end(pad) - } - - /// The Range with some padding given for each end. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 10.0).pad_ends(1.0, 2.0), Range::new(1.0, 8.0)); - /// assert_eq!(Range::new(10.0, 0.0).pad_ends(4.0, 3.0), Range::new(6.0, 3.0)); - /// ``` - pub fn pad_ends(self, start: S, end: S) -> Self - where - S: Neg, - { - self.pad_start(start).pad_end(end) - } - - /// Clamp the given value to the range. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert_eq!(Range::new(0.0, 5.0).clamp_value(7.0), 5.0); - /// assert_eq!(Range::new(5.0, -2.5).clamp_value(-3.0), -2.5); - /// assert_eq!(Range::new(5.0, 10.0).clamp_value(0.0), 5.0); - /// ``` - pub fn clamp_value(&self, value: S) -> S { - math::clamp(value, self.start, self.end) - } - - /// Stretch the end that is closest to the given value only if it lies outside the Range. - /// - /// The resulting Range will retain the direction of the original range. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(2.5, 5.0); - /// assert_eq!(a.stretch_to_value(10.0), Range::new(2.5, 10.0)); - /// assert_eq!(a.stretch_to_value(0.0), Range::new(0.0, 5.0)); - /// - /// let b = Range::new(0.0, -5.0); - /// assert_eq!(b.stretch_to_value(10.0), Range::new(10.0, -5.0)); - /// assert_eq!(b.stretch_to_value(-10.0), Range::new(0.0, -10.0)); - /// ``` - pub fn stretch_to_value(self, value: S) -> Self { - let Range { start, end } = self; - if start <= end { - if value < start { - Range { - start: value, - end: end, - } - } else if value > end { - Range { - start: start, - end: value, - } - } else { - self - } - } else { - if value < end { - Range { - start: start, - end: value, - } - } else if value > start { - Range { - start: value, - end: end, - } - } else { - self - } - } - } - - /// Does `self` have the same direction as `other`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// assert!(Range::new(0.0, 1.0).has_same_direction(Range::new(100.0, 200.0))); - /// assert!(Range::new(0.0, -5.0).has_same_direction(Range::new(-2.5, -6.0))); - /// assert!(!Range::new(0.0, 5.0).has_same_direction(Range::new(2.5, -2.5))); - /// ``` - pub fn has_same_direction(self, other: Self) -> bool { - let self_direction = self.start <= self.end; - let other_direction = other.start <= other.end; - self_direction == other_direction - } - - /// Align the `start` of `self` to the `start` of the `other` **Range**. - /// - /// If the direction of `other` is different to `self`, `self`'s `end` will be aligned to the - /// `start` of `other` instead. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(2.5, 7.5); - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.align_start_of(b), Range::new(0.0, 5.0)); - /// assert_eq!(b.align_start_of(a), Range::new(2.5, 12.5)); - /// - /// let c = Range::new(2.5, -2.5); - /// let d = Range::new(-5.0, 5.0); - /// assert_eq!(c.align_start_of(d), Range::new(0.0, -5.0)); - /// assert_eq!(d.align_start_of(c), Range::new(-7.5, 2.5)); - /// ``` - pub fn align_start_of(self, other: Self) -> Self { - let diff = if self.has_same_direction(other) { - other.start - self.start - } else { - other.start - self.end - }; - self.shift(diff) - } - - /// Align the `end` of `self` to the `end` of the `other` **Range**. - /// - /// If the direction of `other` is different to `self`, `self`'s `start` will be aligned to the - /// `end` of `other` instead. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(2.5, 7.5); - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.align_end_of(b), Range::new(5.0, 10.0)); - /// assert_eq!(b.align_end_of(a), Range::new(-2.5, 7.5)); - /// - /// let c = Range::new(2.5, -2.5); - /// let d = Range::new(-5.0, 5.0); - /// assert_eq!(c.align_end_of(d), Range::new(5.0, 0.0)); - /// assert_eq!(d.align_end_of(c), Range::new(-2.5, 7.5)); - /// ``` - pub fn align_end_of(self, other: Self) -> Self { - let diff = if self.has_same_direction(other) { - other.end - self.end - } else { - other.end - self.start - }; - self.shift(diff) - } - - /// Align the middle of `self` to the middle of the `other` **Range**. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(0.0, 5.0); - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.align_middle_of(b), Range::new(2.5, 7.5)); - /// assert_eq!(b.align_middle_of(a), Range::new(-2.5, 7.5)); - /// - /// let c = Range::new(2.5, -2.5); - /// let d = Range::new(-10.0, 0.0); - /// assert_eq!(c.align_middle_of(d), Range::new(-2.5, -7.5)); - /// assert_eq!(d.align_middle_of(c), Range::new(-5.0, 5.0)); - /// ``` - pub fn align_middle_of(self, other: Self) -> Self { - let diff = other.middle() - self.middle(); - self.shift(diff) - } - - /// Aligns the `start` of `self` with the `end` of `other`. - /// - /// If the directions are opposite, aligns the `end` of self with the `end` of `other`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(2.5, 7.5); - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.align_after(b), Range::new(10.0, 15.0)); - /// assert_eq!(b.align_after(a), Range::new(7.5, 17.5)); - /// - /// let c = Range::new(2.5, -2.5); - /// let d = Range::new(-5.0, 5.0); - /// assert_eq!(c.align_after(d), Range::new(10.0, 5.0)); - /// assert_eq!(d.align_after(c), Range::new(-12.5, -2.5)); - /// ``` - pub fn align_after(self, other: Self) -> Self { - let diff = if self.has_same_direction(other) { - other.end - self.start - } else { - other.end - self.end - }; - self.shift(diff) - } - - /// Aligns the `end` of `self` with the `start` of `other`. - /// - /// If the directions are opposite, aligns the `start` of self with the `start` of `other`. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::Range; - /// - /// let a = Range::new(2.5, 7.5); - /// let b = Range::new(0.0, 10.0); - /// assert_eq!(a.align_before(b), Range::new(-5.0, 0.0)); - /// assert_eq!(b.align_before(a), Range::new(-7.5, 2.5)); - /// - /// let c = Range::new(2.5, -2.5); - /// let d = Range::new(-5.0, 5.0); - /// assert_eq!(c.align_before(d), Range::new(-5.0, -10.0)); - /// assert_eq!(d.align_before(c), Range::new(2.5, 12.5)); - /// ``` - pub fn align_before(self, other: Self) -> Self { - let diff = if self.has_same_direction(other) { - other.start - self.end - } else { - other.start - self.start - }; - self.shift(diff) - } - - /// Align `self` to `other` along the *x* axis in accordance with the given `Align` variant. - pub fn align_to(self, align: Align, other: Self) -> Self { - match align { - Align::Start => self.align_start_of(other), - Align::Middle => self.align_middle_of(other), - Align::End => self.align_end_of(other), - } - } - - /// The closest **Edge** of `self` to the given `scalar`. - /// - /// Returns **Start** if the distance between both **Edge**s is equal. - /// - /// # Examples - /// - /// ``` - /// use nannou::geom::{Edge, Range}; - /// - /// assert_eq!(Range::new(0.0, 10.0).closest_edge(4.0), Edge::Start); - /// assert_eq!(Range::new(0.0, 10.0).closest_edge(7.0), Edge::End); - /// assert_eq!(Range::new(0.0, 10.0).closest_edge(5.0), Edge::Start); - /// ``` - pub fn closest_edge(&self, scalar: S) -> Edge { - let Range { start, end } = *self; - let start_diff = if scalar < start { - start - scalar - } else { - scalar - start - }; - let end_diff = if scalar < end { - end - scalar - } else { - scalar - end - }; - if start_diff <= end_diff { - Edge::Start - } else { - Edge::End - } - } -} diff --git a/nannou/src/geom/rect.rs b/nannou/src/geom/rect.rs deleted file mode 100644 index 295f13fdb..000000000 --- a/nannou/src/geom/rect.rs +++ /dev/null @@ -1,814 +0,0 @@ -use crate::geom::{quad, scalar, Align, Edge, Point2, Quad, Range, Tri, Vector2}; -use crate::math::num_traits::Float; -use crate::math::{self, BaseNum}; -use std::ops::Neg; - -/// Defines a Rectangle's bounds across the x and y axes. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Rect { - /// The start and end positions of the Rectangle on the x axis. - pub x: Range, - /// The start and end positions of the Rectangle on the y axis. - pub y: Range, -} - -/// The distance between the inner edge of a border and the outer edge of the inner content. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Padding { - /// Padding on the start and end of the *x* axis. - pub x: Range, - /// Padding on the start and end of the *y* axis. - pub y: Range, -} - -/// Either of the four corners of a **Rect**. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Corner { - /// The top left corner of a **Rect**. - TopLeft, - /// The top right corner of a **Rect**. - TopRight, - /// The bottom left corner of a **Rect**. - BottomLeft, - /// The bottom right corner of a **Rect**. - BottomRight, -} - -/// Yields even subdivisions of a `Rect`. -/// -/// The four subdivisions will each be yielded as a `Rect` whose dimensions are exactly half of the -/// original `Rect`. -#[derive(Clone)] -pub struct Subdivisions { - ranges: SubdivisionRanges, - subdivision_index: u8, -} - -/// The ranges that describe the subdivisions of a `Rect`. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct SubdivisionRanges { - /// The first half of the x range. - pub x_a: Range, - /// The second half of the x range. - pub x_b: Range, - /// The first half of the y range. - pub y_a: Range, - /// The second half of the y range. - pub y_b: Range, -} - -/// An iterator yielding the four corners of a `Rect`. -#[derive(Clone, Debug)] -pub struct Corners { - rect: Rect, - index: u8, -} - -/// The triangles iterator yielded by the `Rect`. -pub type Triangles = quad::Triangles>; - -/// The number of subdivisions when dividing a `Rect` in half along the *x* and *y* axes. -pub const NUM_SUBDIVISIONS: u8 = 4; - -/// The number of subdivisions when dividing a `Rect` in half along the *x* and *y* axes. -pub const NUM_CORNERS: u8 = 4; - -/// The number of triangles used to represent a `Rect`. -pub const NUM_TRIANGLES: u8 = 2; - -impl Padding -where - S: BaseNum, -{ - /// No padding. - pub fn none() -> Self { - Padding { - x: Range::new(S::zero(), S::zero()), - y: Range::new(S::zero(), S::zero()), - } - } -} - -// Given some `SubdivisionRanges` and a subdivision index, produce the rect for that subdivision. -macro_rules! subdivision_from_index { - ($ranges:expr,0) => { - Rect { - x: $ranges.x_a, - y: $ranges.y_a, - } - }; - ($ranges:expr,1) => { - Rect { - x: $ranges.x_b, - y: $ranges.y_a, - } - }; - ($ranges:expr,2) => { - Rect { - x: $ranges.x_a, - y: $ranges.y_b, - } - }; - ($ranges:expr,3) => { - Rect { - x: $ranges.x_b, - y: $ranges.y_b, - } - }; -} - -// Given some `Rect` and an index, produce the corner for that index. -macro_rules! corner_from_index { - ($rect:expr,0) => { - crate::geom::pt2($rect.x.start, $rect.y.end) - }; - ($rect:expr,1) => { - crate::geom::pt2($rect.x.end, $rect.y.end) - }; - ($rect:expr,2) => { - crate::geom::pt2($rect.x.end, $rect.y.start) - }; - ($rect:expr,3) => { - crate::geom::pt2($rect.x.start, $rect.y.start) - }; -} - -impl Rect -where - S: BaseNum, -{ - /// Construct a Rect from a given `Point` and `Dimensions`. - pub fn from_xy_wh(p: Point2, wh: Vector2) -> Self { - Rect { - x: Range::from_pos_and_len(p.x, wh.x), - y: Range::from_pos_and_len(p.y, wh.y), - } - } - - /// Construct a Rect from the given `x` `y` coordinates and `w` `h` dimensions. - pub fn from_x_y_w_h(x: S, y: S, w: S, h: S) -> Self { - Rect::from_xy_wh(Point2 { x, y }, Vector2 { x: w, y: h }) - } - - /// Construct a Rect at origin with the given dimensions. - pub fn from_wh(wh: Vector2) -> Self { - let p = Point2 { - x: S::zero(), - y: S::zero(), - }; - Self::from_xy_wh(p, wh) - } - - /// Construct a Rect at origin with the given width and height. - pub fn from_w_h(w: S, h: S) -> Self { - Self::from_wh(Vector2 { x: w, y: h }) - } - - /// Construct a Rect from the coordinates of two points. - pub fn from_corners(a: Point2, b: Point2) -> Self { - let (left, right) = if a.x < b.x { (a.x, b.x) } else { (b.x, a.x) }; - let (bottom, top) = if a.y < b.y { (a.y, b.y) } else { (b.y, a.y) }; - Rect { - x: Range { - start: left, - end: right, - }, - y: Range { - start: bottom, - end: top, - }, - } - } - - /// Converts `self` to an absolute `Rect` so that the magnitude of each range is always - /// positive. - pub fn absolute(self) -> Self { - let x = self.x.absolute(); - let y = self.y.absolute(); - Rect { x, y } - } - - /// The Rect representing the area in which two Rects overlap. - pub fn overlap(self, other: Self) -> Option { - self.x - .overlap(other.x) - .and_then(|x| self.y.overlap(other.y).map(|y| Rect { x: x, y: y })) - } - - /// The Rect that encompass the two given sets of Rect. - pub fn max(self, other: Self) -> Self - where - S: Float, - { - Rect { - x: self.x.max(other.x), - y: self.y.max(other.y), - } - } - - /// The position in the middle of the x bounds. - pub fn x(&self) -> S { - self.x.middle() - } - - /// The position in the middle of the y bounds. - pub fn y(&self) -> S { - self.y.middle() - } - - /// The xy position in the middle of the bounds. - pub fn xy(&self) -> Point2 { - [self.x(), self.y()].into() - } - - /// The centered x and y coordinates as a tuple. - pub fn x_y(&self) -> (S, S) { - (self.x(), self.y()) - } - - /// The Rect's lowest y value. - pub fn bottom(&self) -> S { - self.y.absolute().start - } - - /// The Rect's highest y value. - pub fn top(&self) -> S { - self.y.absolute().end - } - - /// The Rect's lowest x value. - pub fn left(&self) -> S { - self.x.absolute().start - } - - /// The Rect's highest x value. - pub fn right(&self) -> S { - self.x.absolute().end - } - - /// The top left corner **Point**. - pub fn top_left(&self) -> Point2 { - [self.left(), self.top()].into() - } - - /// The bottom left corner **Point**. - pub fn bottom_left(&self) -> Point2 { - [self.left(), self.bottom()].into() - } - - /// The top right corner **Point**. - pub fn top_right(&self) -> Point2 { - [self.right(), self.top()].into() - } - - /// The bottom right corner **Point**. - pub fn bottom_right(&self) -> Point2 { - [self.right(), self.bottom()].into() - } - - /// The middle of the left edge. - pub fn mid_left(&self) -> Point2 { - [self.left(), self.y()].into() - } - - /// The middle of the top edge. - pub fn mid_top(&self) -> Point2 { - [self.x(), self.top()].into() - } - - /// The middle of the right edge. - pub fn mid_right(&self) -> Point2 { - [self.right(), self.y()].into() - } - - /// The middle of the bottom edge. - pub fn mid_bottom(&self) -> Point2 { - [self.x(), self.bottom()].into() - } - - /// The edges of the **Rect** in a tuple (left, right, bottom, top). - pub fn l_r_b_t(&self) -> (S, S, S, S) { - (self.left(), self.right(), self.bottom(), self.top()) - } - - /// Shift the Rect along the x axis. - pub fn shift_x(self, x: S) -> Self { - Rect { - x: self.x.shift(x), - ..self - } - } - - /// Shift the Rect along the y axis. - pub fn shift_y(self, y: S) -> Self { - Rect { - y: self.y.shift(y), - ..self - } - } - - /// Shift the Rect by the given vector. - pub fn shift(self, v: Vector2) -> Self { - self.shift_x(v.x).shift_y(v.y) - } - - /// Does the given point touch the Rectangle. - pub fn contains(&self, p: Point2) -> bool { - self.x.contains(p.x) && self.y.contains(p.y) - } - - /// Stretches the closest edge(s) to the given point if the point lies outside of the Rect area. - pub fn stretch_to_point(self, p: Point2) -> Self { - let Rect { x, y } = self; - Rect { - x: x.stretch_to_value(p.x), - y: y.stretch_to_value(p.y), - } - } - - /// Align `self`'s right edge with the left edge of the `other` **Rect**. - pub fn left_of(self, other: Self) -> Self { - Rect { - x: self.x.align_before(other.x), - y: self.y, - } - } - - /// Align `self`'s left edge with the right dge of the `other` **Rect**. - pub fn right_of(self, other: Self) -> Self { - Rect { - x: self.x.align_after(other.x), - y: self.y, - } - } - - /// Align `self`'s top edge with the bottom edge of the `other` **Rect**. - pub fn below(self, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_before(other.y), - } - } - - /// Align `self`'s bottom edge with the top edge of the `other` **Rect**. - pub fn above(self, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_after(other.y), - } - } - - /// Align `self` to `other` along the *x* axis in accordance with the given `Align` variant. - pub fn align_x_of(self, align: Align, other: Self) -> Self { - Rect { - x: self.x.align_to(align, other.x), - y: self.y, - } - } - - /// Align `self` to `other` along the *y* axis in accordance with the given `Align` variant. - pub fn align_y_of(self, align: Align, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_to(align, other.y), - } - } - - /// Align `self`'s left edge with the left edge of the `other` **Rect**. - pub fn align_left_of(self, other: Self) -> Self { - Rect { - x: self.x.align_start_of(other.x), - y: self.y, - } - } - - /// Align the middle of `self` with the middle of the `other` **Rect** along the *x* axis. - pub fn align_middle_x_of(self, other: Self) -> Self { - Rect { - x: self.x.align_middle_of(other.x), - y: self.y, - } - } - - /// Align `self`'s right edge with the right edge of the `other` **Rect**. - pub fn align_right_of(self, other: Self) -> Self { - Rect { - x: self.x.align_end_of(other.x), - y: self.y, - } - } - - /// Align `self`'s bottom edge with the bottom edge of the `other` **Rect**. - pub fn align_bottom_of(self, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_start_of(other.y), - } - } - - /// Align the middle of `self` with the middle of the `other` **Rect** along the *y* axis. - pub fn align_middle_y_of(self, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_middle_of(other.y), - } - } - - /// Align `self`'s top edge with the top edge of the `other` **Rect**. - pub fn align_top_of(self, other: Self) -> Self { - Rect { - x: self.x, - y: self.y.align_end_of(other.y), - } - } - - /// Place `self` along the top left edges of the `other` **Rect**. - pub fn top_left_of(self, other: Self) -> Self { - self.align_left_of(other).align_top_of(other) - } - - /// Place `self` along the top right edges of the `other` **Rect**. - pub fn top_right_of(self, other: Self) -> Self { - self.align_right_of(other).align_top_of(other) - } - - /// Place `self` along the bottom left edges of the `other` **Rect**. - pub fn bottom_left_of(self, other: Self) -> Self { - self.align_left_of(other).align_bottom_of(other) - } - - /// Place `self` along the bottom right edges of the `other` **Rect**. - pub fn bottom_right_of(self, other: Self) -> Self { - self.align_right_of(other).align_bottom_of(other) - } - - /// Place `self` in the middle of the top edge of the `other` **Rect**. - pub fn mid_top_of(self, other: Self) -> Self { - self.align_middle_x_of(other).align_top_of(other) - } - - /// Place `self` in the middle of the bottom edge of the `other` **Rect**. - pub fn mid_bottom_of(self, other: Self) -> Self { - self.align_middle_x_of(other).align_bottom_of(other) - } - - /// Place `self` in the middle of the left edge of the `other` **Rect**. - pub fn mid_left_of(self, other: Self) -> Self { - self.align_left_of(other).align_middle_y_of(other) - } - - /// Place `self` in the middle of the right edge of the `other` **Rect**. - pub fn mid_right_of(self, other: Self) -> Self { - self.align_right_of(other).align_middle_y_of(other) - } - - /// Place `self` directly in the middle of the `other` **Rect**. - pub fn middle_of(self, other: Self) -> Self { - self.align_middle_x_of(other).align_middle_y_of(other) - } - - /// Return the **Corner** of `self` that is closest to the given **Point**. - pub fn closest_corner(&self, p: Point2) -> Corner { - let x_edge = self.x.closest_edge(p.x); - let y_edge = self.y.closest_edge(p.y); - match (x_edge, y_edge) { - (Edge::Start, Edge::Start) => Corner::BottomLeft, - (Edge::Start, Edge::End) => Corner::TopLeft, - (Edge::End, Edge::Start) => Corner::BottomRight, - (Edge::End, Edge::End) => Corner::TopRight, - } - } - - /// The four corners of the `Rect`. - pub fn corners(&self) -> Quad> { - Quad::from([ - corner_from_index!(self, 0), - corner_from_index!(self, 1), - corner_from_index!(self, 2), - corner_from_index!(self, 3), - ]) - } - - /// An iterator yielding the four corners of the `Rect`. - pub fn corners_iter(&self) -> Corners { - let rect = *self; - let index = 0; - Corners { rect, index } - } - - /// Return two `Tri`s that represent the `Rect`. - pub fn triangles(&self) -> (Tri>, Tri>) { - self.corners().triangles() - } - - /// An iterator yielding the `Rect`'s two `Tri`'s. - pub fn triangles_iter(self) -> Triangles { - self.corners().triangles_iter() - } - - /// The four ranges used for the `Rect`'s four subdivisions. - pub fn subdivision_ranges(&self) -> SubdivisionRanges { - let (x, y) = self.x_y(); - let x_a = Range::new(self.x.start, x); - let x_b = Range::new(x, self.x.end); - let y_a = Range::new(self.y.start, y); - let y_b = Range::new(y, self.y.end); - SubdivisionRanges { x_a, x_b, y_a, y_b } - } - - /// Divide the `Rect` in half along the *x* and *y* axes and return the four subdivisions. - /// - /// Subdivisions are yielded in the following order: - /// - /// 1. Bottom left - /// 2. Bottom right - /// 3. Top left - /// 4. Top right - pub fn subdivisions(&self) -> [Self; NUM_SUBDIVISIONS as usize] { - self.subdivision_ranges().rects() - } - - /// The same as `subdivisions` but each subdivision is yielded via the returned `Iterator`. - pub fn subdivisions_iter(&self) -> Subdivisions { - self.subdivision_ranges().rects_iter() - } - - /// Produce the corner at the given index. - pub fn corner_at_index(&self, index: u8) -> Option> { - match index { - 0 => Some(corner_from_index!(self, 0)), - 1 => Some(corner_from_index!(self, 1)), - 2 => Some(corner_from_index!(self, 2)), - 3 => Some(corner_from_index!(self, 3)), - _ => None, - } - } -} - -impl SubdivisionRanges -where - S: Copy, -{ - /// The `Rect`s representing each of the four subdivisions. - /// - /// Subdivisions are yielded in the following order: - /// - /// 1. Bottom left - /// 2. Bottom right - /// 3. Top left - /// 4. Top right - pub fn rects(&self) -> [Rect; NUM_SUBDIVISIONS as usize] { - let r1 = subdivision_from_index!(self, 0); - let r2 = subdivision_from_index!(self, 1); - let r3 = subdivision_from_index!(self, 2); - let r4 = subdivision_from_index!(self, 3); - [r1, r2, r3, r4] - } - - /// The same as `rects` but each subdivision is yielded via the returned `Iterator`. - pub fn rects_iter(self) -> Subdivisions { - Subdivisions { - ranges: self, - subdivision_index: 0, - } - } - - // The subdivision at the given index within the range 0..NUM_SUBDIVISIONS. - fn subdivision_at_index(&self, index: u8) -> Option> { - let rect = match index { - 0 => subdivision_from_index!(self, 0), - 1 => subdivision_from_index!(self, 1), - 2 => subdivision_from_index!(self, 2), - 3 => subdivision_from_index!(self, 3), - _ => return None, - }; - Some(rect) - } -} - -impl Rect -where - S: BaseNum + Neg, -{ - /// The width of the Rect. - pub fn w(&self) -> S { - self.x.len() - } - - /// The height of the Rect. - pub fn h(&self) -> S { - self.y.len() - } - - /// The total dimensions of the Rect. - pub fn wh(&self) -> Vector2 { - [self.w(), self.h()].into() - } - - /// The width and height of the Rect as a tuple. - pub fn w_h(&self) -> (S, S) { - (self.w(), self.h()) - } - - /// Convert the Rect to a `Point` and `Dimensions`. - pub fn xy_wh(&self) -> (Point2, Vector2) { - (self.xy(), self.wh()) - } - - /// The Rect's centered coordinates and dimensions in a tuple. - pub fn x_y_w_h(&self) -> (S, S, S, S) { - let (xy, wh) = self.xy_wh(); - (xy[0], xy[1], wh[0], wh[1]) - } - - /// The length of the longest side of the rectangle. - pub fn len(&self) -> S { - math::partial_max(self.w(), self.h()) - } - - /// The left and top edges of the **Rect** along with the width and height. - pub fn l_t_w_h(&self) -> (S, S, S, S) { - let (w, h) = self.w_h(); - (self.left(), self.top(), w, h) - } - - /// The left and bottom edges of the **Rect** along with the width and height. - pub fn l_b_w_h(&self) -> (S, S, S, S) { - let (w, h) = self.w_h(); - (self.left(), self.bottom(), w, h) - } - - /// The Rect with some padding applied to the left edge. - pub fn pad_left(self, pad: S) -> Self { - Rect { - x: self.x.pad_start(pad), - ..self - } - } - - /// The Rect with some padding applied to the right edge. - pub fn pad_right(self, pad: S) -> Self { - Rect { - x: self.x.pad_end(pad), - ..self - } - } - - /// The rect with some padding applied to the bottom edge. - pub fn pad_bottom(self, pad: S) -> Self { - Rect { - y: self.y.pad_start(pad), - ..self - } - } - - /// The Rect with some padding applied to the top edge. - pub fn pad_top(self, pad: S) -> Self { - Rect { - y: self.y.pad_end(pad), - ..self - } - } - - /// The Rect with some padding amount applied to each edge. - pub fn pad(self, pad: S) -> Self { - let Rect { x, y } = self; - Rect { - x: x.pad(pad), - y: y.pad(pad), - } - } - - /// The Rect with some padding applied. - pub fn padding(self, padding: Padding) -> Self { - Rect { - x: self.x.pad_ends(padding.x.start, padding.x.end), - y: self.y.pad_ends(padding.y.start, padding.y.end), - } - } - - /// Returns a `Rect` with a position relative to the given position on the *x* axis. - pub fn relative_to_x(self, x: S) -> Self { - Rect { - x: self.x.shift(-x), - ..self - } - } - - /// Returns a `Rect` with a position relative to the given position on the *y* axis. - pub fn relative_to_y(self, y: S) -> Self { - Rect { - y: self.y.shift(-y), - ..self - } - } - - /// Returns a `Rect` with a position relative to the given position. - pub fn relative_to(self, p: Point2) -> Self { - self.relative_to_x(p.x).relative_to_y(p.y) - } - - /// Invert the x axis (aka flip *around* the y axis). - pub fn invert_x(self) -> Self { - Rect { - x: self.x.invert(), - ..self - } - } - - /// Invert the y axis (aka flip *around* the x axis). - pub fn invert_y(self) -> Self { - Rect { - y: self.y.invert(), - ..self - } - } -} - -impl Iterator for Subdivisions -where - S: Copy, -{ - type Item = Rect; - - fn next(&mut self) -> Option { - if let Some(sd) = self.ranges.subdivision_at_index(self.subdivision_index) { - self.subdivision_index += 1; - return Some(sd); - } - None - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl DoubleEndedIterator for Subdivisions -where - S: Copy, -{ - fn next_back(&mut self) -> Option { - let next_index = self.subdivision_index + 1; - if let Some(sd) = self - .ranges - .subdivision_at_index(NUM_SUBDIVISIONS - next_index) - { - self.subdivision_index = next_index; - return Some(sd); - } - None - } -} - -impl ExactSizeIterator for Subdivisions -where - S: Copy, -{ - fn len(&self) -> usize { - NUM_SUBDIVISIONS as usize - self.subdivision_index as usize - } -} - -impl Iterator for Corners -where - S: BaseNum, -{ - type Item = Point2; - fn next(&mut self) -> Option { - if let Some(corner) = self.rect.corner_at_index(self.index) { - self.index += 1; - return Some(corner); - } - None - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl DoubleEndedIterator for Corners -where - S: BaseNum, -{ - fn next_back(&mut self) -> Option { - let next_index = self.index + 1; - if let Some(corner) = self.rect.corner_at_index(NUM_CORNERS - next_index) { - self.index = next_index; - return Some(corner); - } - None - } -} - -impl ExactSizeIterator for Corners -where - S: BaseNum, -{ - fn len(&self) -> usize { - (NUM_CORNERS - self.index) as usize - } -} diff --git a/nannou/src/geom/scalar.rs b/nannou/src/geom/scalar.rs deleted file mode 100644 index 044e82e8f..000000000 --- a/nannou/src/geom/scalar.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// The default scalar type used for geometry throughout Nannou. -pub type Default = f32; diff --git a/nannou/src/geom/tri.rs b/nannou/src/geom/tri.rs deleted file mode 100644 index f122e7a68..000000000 --- a/nannou/src/geom/tri.rs +++ /dev/null @@ -1,364 +0,0 @@ -use crate::geom::{vertex, Cuboid, Point2, Range, Rect, Vertex, Vertex2d, Vertex3d}; -use crate::math::{BaseNum, EuclideanSpace, Zero}; -use std::ops::Deref; - -/// The number of vertices in a triangle. -pub const NUM_VERTICES: u8 = 3; - -/// A triangle as three vertices. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -pub struct Tri(pub [V; NUM_VERTICES as usize]); - -/// An iterator yielding each of the vertices of the triangle. -#[derive(Clone, Debug)] -pub struct Vertices { - tri: Tri, - index: u8, -} - -/// An iterator yielding triangles whose vertices are produced by the given iterator yielding -/// vertices. -#[derive(Clone, Debug)] -pub struct IterFromVertices { - vertices: I, -} - -/// An iterator that flattens an iterator yielding triangles into its vertices. -#[derive(Clone, Debug)] -pub struct VerticesFromIter { - tris: I, - tri: Option>, -} - -/// Converts an iterator yielding `[usize; 3]` into an iterator yielding `usize`s. -#[derive(Clone, Debug)] -pub struct FlattenIndices { - indices: I, - b: Option, - c: Option, -} - -impl Tri { - /// Create a **Tri** by indexing into the given buffer. - /// - /// **Panics** if any of the given indices are out of range of the given `vertices` slice. - pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Self - where - V: Clone, - { - from_index_tri(vertices, indices) - } - - /// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator. - /// - /// Returns **None** if there were not at least 3 vertices in the given iterator. - pub fn from_vertices(vertices: I) -> Option - where - I: IntoIterator, - { - from_vertices(vertices) - } - - /// Produce an iterator yielding each of the vertices of the triangle. - pub fn vertices(self) -> Vertices { - let tri = self; - let index = 0; - Vertices { tri, index } - } - - /// Produce the centroid of the triangle aka the "mean"/"average" of all the points. - pub fn centroid(self) -> V - where - V: EuclideanSpace, - { - EuclideanSpace::centroid(&self[..]) - } - - /// Maps the underlying vertices to a new type and returns the resulting `Tri`. - pub fn map_vertices(self, mut map: F) -> Tri - where - F: FnMut(V) -> V2, - { - let Tri([a, b, c]) = self; - Tri([map(a), map(b), map(c)]) - } - - /// Returns `true` if the given 2D vertex is contained within the 2D `Tri`. - /// - /// # Example - /// - /// ``` - /// # use nannou::prelude::*; - /// # use nannou::geom::Tri; - /// # fn main() { - /// let a = Point2 { x: -0.5, y: 0.0 }; - /// let b = Point2 { x: 0.0, y: 1.0 }; - /// let c = Point2 { x: 0.5, y: -0.75 }; - /// let tri = Tri([a, b, c]); - /// assert!(tri.contains(&Point2 { x: 0.0, y: 0.0 })); - /// assert!(!tri.contains(&Point2 { x: 3.0, y: 3.0 })); - /// # } - /// ``` - pub fn contains(&self, v: &V) -> bool - where - V: Vertex2d, - { - let (a, b, c) = (*self).into(); - let (a, b, c) = (a.point2(), b.point2(), c.point2()); - let v = (*v).point2(); - - fn sign(a: Point2, b: Point2, c: Point2) -> S - where - S: BaseNum, - { - (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1]) - } - - let b1 = sign(v, a, b) < V::Scalar::zero(); - let b2 = sign(v, b, c) < V::Scalar::zero(); - let b3 = sign(v, c, a) < V::Scalar::zero(); - - (b1 == b2) && (b2 == b3) - } - - /// The bounding `Rect` of the triangle. - pub fn bounding_rect(self) -> Rect - where - V: Vertex2d, - { - let (a, b, c) = self.into(); - let (a, b, c) = (a.point2(), b.point2(), c.point2()); - let rect = Rect { - x: Range::new(a.x, a.x), - y: Range::new(a.y, a.y), - }; - rect.stretch_to_point(b).stretch_to_point(c) - } - - /// The bounding `Rect` of the triangle. - pub fn bounding_cuboid(self) -> Cuboid - where - V: Vertex3d, - { - let (a, b, c) = self.into(); - let (a, b, c) = (a.point3(), b.point3(), c.point3()); - let cuboid = Cuboid { - x: Range::new(a.x, a.x), - y: Range::new(a.y, a.y), - z: Range::new(a.z, a.z), - }; - cuboid.stretch_to_point(b).stretch_to_point(c) - } -} - -/// Returns the first `Tri` that contains the given vertex. -/// -/// Returns `None` if no `Tri`'s contain the given vertex. -pub fn iter_contains(tris: I, v: &V) -> Option -where - I: IntoIterator, - I::Item: AsRef>, - V: Vertex2d, -{ - tris.into_iter().find(|tri| tri.as_ref().contains(v)) -} - -/// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator. -/// -/// Returns **None** if there were not at least 3 vertices in the given iterator. -pub fn from_vertices(vertices: I) -> Option> -where - I: IntoIterator, -{ - let mut vertices = vertices.into_iter(); - match (vertices.next(), vertices.next(), vertices.next()) { - (Some(a), Some(b), Some(c)) => Some(Tri([a, b, c])), - _ => None, - } -} - -/// Produce an iterator yielding a triangle for every three vertices yielded by the given -/// `vertices` iterator. -pub fn iter_from_vertices(vertices: I) -> IterFromVertices -where - I: IntoIterator, -{ - let vertices = vertices.into_iter(); - IterFromVertices { vertices } -} - -/// Create a **Tri** by indexing into the given buffer. -/// -/// **Panics** if any of the given indices are out of range of the given `vertices` slice. -pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Tri -where - V: Clone, -{ - let a = vertices[indices[0]].clone(); - let b = vertices[indices[1]].clone(); - let c = vertices[indices[2]].clone(); - Tri([a, b, c]) -} - -/// Produce an iterator that flattens the given iterator yielding triangles into its vertices. -pub fn vertices_from_iter(tris: I) -> VerticesFromIter -where - I: IntoIterator>, -{ - let tris = tris.into_iter(); - let tri = None; - VerticesFromIter { tris, tri } -} - -/// Given an iterator yielding trios of indices, produce an iterator that yields each index one at -/// a time. -pub fn flatten_index_tris(index_tris: I) -> FlattenIndices -where - I: IntoIterator, -{ - FlattenIndices { - indices: index_tris.into_iter(), - b: None, - c: None, - } -} - -impl Deref for Tri { - type Target = [V; 3]; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From<[V; 3]> for Tri { - fn from(points: [V; 3]) -> Self { - Tri(points) - } -} - -impl From<(V, V, V)> for Tri { - fn from((a, b, c): (V, V, V)) -> Self { - Tri([a, b, c]) - } -} - -impl Into<[V; 3]> for Tri { - fn into(self) -> [V; 3] { - self.0 - } -} - -impl Into<(V, V, V)> for Tri { - fn into(self) -> (V, V, V) { - let Tri([a, b, c]) = self; - (a, b, c) - } -} - -impl AsRef> for Tri { - fn as_ref(&self) -> &Tri { - self - } -} - -impl AsRef<[V; 3]> for Tri { - fn as_ref(&self) -> &[V; 3] { - &self.0 - } -} - -impl Iterator for Vertices -where - V: Clone, -{ - type Item = V; - fn next(&mut self) -> Option { - if self.index < NUM_VERTICES { - let v = self.tri.0[self.index as usize].clone(); - self.index += 1; - Some(v) - } else { - None - } - } -} - -impl ExactSizeIterator for Vertices -where - V: Clone, -{ - fn len(&self) -> usize { - NUM_VERTICES as usize - self.index as usize - } -} - -impl Iterator for IterFromVertices -where - I: Iterator, -{ - type Item = Tri; - fn next(&mut self) -> Option { - from_vertices(&mut self.vertices) - } -} - -impl Iterator for VerticesFromIter -where - I: Iterator>, - V: Vertex, -{ - type Item = V; - fn next(&mut self) -> Option { - loop { - if let Some(v) = self.tri.as_mut().and_then(|vs| vs.next()) { - return Some(v); - } - match self.tris.next() { - Some(t) => self.tri = Some(t.vertices()), - None => return None, - } - } - } -} - -impl ExactSizeIterator for VerticesFromIter -where - I: Iterator> + ExactSizeIterator, - V: Vertex, -{ - fn len(&self) -> usize { - let current_tri_vs = self.tri.as_ref().map(|vs| vs.len()).unwrap_or(0); - let remaining_tri_vs = self.tris.len() * NUM_VERTICES as usize; - current_tri_vs + remaining_tri_vs - } -} - -impl Iterator for FlattenIndices -where - I: Iterator, -{ - type Item = usize; - fn next(&mut self) -> Option { - if let Some(next) = self.b.take() { - return Some(next); - } - if let Some(next) = self.c.take() { - return Some(next); - } - if let Some([next, b, c]) = self.indices.next() { - self.b = Some(b); - self.c = Some(c); - return Some(next); - } - None - } -} - -impl ExactSizeIterator for FlattenIndices -where - I: Iterator + ExactSizeIterator, -{ - fn len(&self) -> usize { - self.indices.len() * 3 + self.b.map(|_| 1).unwrap_or(0) + self.c.map(|_| 1).unwrap_or(0) - } -} diff --git a/nannou/src/geom/vector.rs b/nannou/src/geom/vector.rs deleted file mode 100644 index 9eda85d43..000000000 --- a/nannou/src/geom/vector.rs +++ /dev/null @@ -1,1614 +0,0 @@ -//! Implementation of the **Vector** types. -//! -//! **Note:** Much of the code in this module is inspired by or copied directly from the `cgmath` -//! crate. Originally we used the `cgmath` types directly, however we decided to switch to our own -//! implementations in order to gain some flexibility. - -use crate::geom::scalar; -use crate::math::{self, BaseFloat, Bounded, InnerSpace, NumCast, One, Zero}; -use crate::rand::distributions::{Distribution, Standard}; -use crate::rand::Rng; -use crate::serde_derive::{Deserialize, Serialize}; -use std::{iter, ops}; - -/// A 2-dimensional vector. -#[repr(C)] -#[derive(Default, Debug, PartialEq, Eq, Copy, Clone, Hash, Serialize, Deserialize)] -pub struct Vector2 { - pub x: S, - pub y: S, -} - -/// A 3-dimensional vector. -#[repr(C)] -#[derive(Default, Debug, PartialEq, Eq, Copy, Clone, Hash, Serialize, Deserialize)] -pub struct Vector3 { - pub x: S, - pub y: S, - pub z: S, -} - -/// A 4-dimensional vector. -#[repr(C)] -#[derive(Default, Debug, PartialEq, Eq, Copy, Clone, Hash, Serialize, Deserialize)] -pub struct Vector4 { - pub x: S, - pub y: S, - pub z: S, - pub w: S, -} - -// Generates index operators for a compound type -// -// Code originally from `cgmath` macros module. -macro_rules! impl_index_operators { - ($VectorN:ident < $S:ident > , $n:expr, $Output:ty, $I:ty) => { - impl<$S> ::std::ops::Index<$I> for $VectorN<$S> { - type Output = $Output; - - #[inline] - fn index<'a>(&'a self, i: $I) -> &'a $Output { - let v: &[$S; $n] = self.as_ref(); - &v[i] - } - } - - impl<$S> ::std::ops::IndexMut<$I> for $VectorN<$S> { - #[inline] - fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { - let v: &mut [$S; $n] = self.as_mut(); - &mut v[i] - } - } - }; -} - -// Utility macro for generating associated functions for the vectors -macro_rules! impl_vector { - ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl $VectorN { - /// Construct a new vector, using the provided values. - #[inline] - pub fn new($($field: S),+) -> $VectorN { - $VectorN { $($field: $field),+ } - } - - /// Construct a vector using the given value for each field. - #[inline] - pub fn from_value(scalar: S) -> $VectorN - where - S: Clone, - { - $VectorN { $($field: scalar.clone()),+ } - } - - /// The number of dimensions in the vector. - #[inline] - pub fn len(&self) -> usize { - $n - } - - /// Perform the given operation on each field in the vector, returning a new vector - /// constructed from the operations. - #[inline] - pub fn map(self, mut f: F) -> $VectorN - where - F: FnMut(S) -> U, - { - $VectorN { $($field: f(self.$field)),+ } - } - - /// Perform the given operation on each each field on both vectors, returning a new - /// vector constructed from the operations. - #[inline] - pub fn zip_map(self, other: $VectorN, mut f: F) -> $VectorN - where - F: FnMut(S, T) -> U, - { - $VectorN { $($field: f(self.$field, other.$field)),+ } - } - - /// Test whether or not the vector is infinite. - pub fn is_finite(&self) -> bool - where - S: BaseFloat, - { - $(self.$field.is_finite())&&+ - } - - /// Component-wise casting to another type. - #[inline] - pub fn cast(&self) -> Option<$VectorN> - where - S: NumCast + Clone, - T: NumCast, - { - $( - let $field = match NumCast::from(self.$field.clone()) { - Some(field) => field, - None => return None - }; - )+ - Some($VectorN { $($field),+ }) - } - - /// A zeroed vector. - #[inline] - pub fn zero() -> $VectorN - where - S: Zero, - { - $VectorN { $($field: S::zero()),+ } - } - - /// Whether or not the vector is zeroed. - #[inline] - pub fn is_zero(&self) -> bool - where - S: PartialEq + Zero, - { - *self == $VectorN::zero() - } - - /// A vector with `1` for each element. - #[inline] - pub fn one() -> $VectorN - where - S: One, - { - $VectorN { $($field: S::one()),+ } - } - - /// Whether or not each element in the vector is equal to `1`. - #[inline] - pub fn is_one(&self) -> bool - where - S: PartialEq + One, - { - *self == $VectorN::one() - } - - /// Tests whether or not any of the vector's elements is `NaN`. - #[inline] - pub fn is_nan(&self) -> bool - where - S: BaseFloat, - { - $(self.$field.is_nan())||+ - } - - /// Sum the fields of the vector. - #[inline] - pub fn sum(self) -> S - where - S: ops::Add + Copy, - { - math::Array::sum(self) - } - - /// The product of the fields of the vector. - #[inline] - pub fn product(self) -> S - where - S: ops::Mul + Copy, - { - math::Array::product(self) - } - - /// Return a vector whose magnitude is limited to the given value. - #[inline] - pub fn limit_magnitude(self, limit: S) -> Self - where - S: BaseFloat, - { - limit_magnitude(self, limit) - } - - /// Return a vector with the given magnitude. - #[inline] - pub fn with_magnitude(self, magnitude: S) -> Self - where - S: BaseFloat, - { - self.normalize() * magnitude - } - - /// Return a normalized vector. - /// - /// If `self` `is_zero`, this returns `self`. - pub fn normalize(self) -> Self - where - S: BaseFloat, - { - if self.is_zero() { - self - } else { - InnerSpace::normalize(self) - } - } - - /// The magnitude of the vector. - /// - /// The magnitude represents the distance from the origin to the point described by the - /// vector. - /// - /// Note: This is equivalent to `.magnitude2().sqrt()`. As a result, it can be quite a - /// bit more computationally efficient to use `.magnitude2()` directly when feasible. - /// - /// ## Example - /// - /// ``` - /// # use nannou::prelude::*; - /// # fn main() { - /// let a = vec2(5.0, 0.0); - /// let b = vec2(0.0, 5.0); - /// assert_eq!(a.magnitude(), 5.0); - /// assert_eq!(b.magnitude(), 5.0); - /// # } - /// - /// ``` - pub fn magnitude(self) -> S - where - S: BaseFloat, - { - InnerSpace::magnitude(self) - } - - /// The square of the magnitude. - /// - /// See the `magnitude` docs for details. - pub fn magnitude2(self) -> S - where - S: BaseFloat, - { - InnerSpace::magnitude2(self) - } - - /// The dot product of self and the given vector. - #[inline] - pub fn dot(self, other: $VectorN) -> S - where - S: BaseFloat, - { - InnerSpace::dot(self, other) - } - } - - impl iter::Sum<$VectorN> for $VectorN - where - S: Zero + ops::Add, - { - #[inline] - fn sum(iter: I) -> $VectorN - where - I: Iterator>, - { - iter.fold($VectorN::zero(), ops::Add::add) - } - } - - impl<'a, S: 'a> iter::Sum<&'a $VectorN> for $VectorN - where - S: 'a + Clone + Zero + ops::Add, - { - #[inline] - fn sum(iter: I) -> $VectorN - where - I: Iterator>, - { - iter.fold($VectorN::zero(), |acc, s| acc + s.clone())// ops::Add::add) - } - } - - // std::ops - vector vector - - impl ops::Neg for $VectorN - where - S: ops::Neg, - { - type Output = $VectorN; - - #[inline] - fn neg(self) -> $VectorN { - self.map(|s| -s) - } - } - - impl ops::Add for $VectorN - where - S: ops::Add, - { - type Output = $VectorN; - - #[inline] - fn add(self, other: Self) -> Self { - self.zip_map(other, |a, b| a + b) - } - } - - impl ops::Sub for $VectorN - where - S: ops::Sub, - { - type Output = $VectorN; - - #[inline] - fn sub(self, other: Self) -> Self { - self.zip_map(other, |a, b| a - b) - } - } - - impl ops::Mul for $VectorN - where - S: ops::Mul, - { - type Output = $VectorN; - - #[inline] - fn mul(self, other: Self) -> Self { - self.zip_map(other, |a, b| a * b) - } - } - - impl ops::Div for $VectorN - where - S: ops::Div, - { - type Output = $VectorN; - - #[inline] - fn div(self, other: Self) -> Self { - self.zip_map(other, |a, b| a / b) - } - } - - impl ops::Rem for $VectorN - where - S: ops::Rem, - { - type Output = $VectorN; - - #[inline] - fn rem(self, other: Self) -> Self { - self.zip_map(other, |a, b| a % b) - } - } - - impl ops::AddAssign for $VectorN - where - S: ops::AddAssign, - { - fn add_assign(&mut self, other: Self) { - $(self.$field += other.$field;)+ - } - } - - impl ops::SubAssign for $VectorN - where - S: ops::SubAssign, - { - fn sub_assign(&mut self, other: Self) { - $(self.$field -= other.$field;)+ - } - } - - impl ops::DivAssign for $VectorN - where - S: Copy + ops::DivAssign, - { - #[inline] - fn div_assign(&mut self, other: Self) { - $(self.$field /= other.$field;)+ - } - } - - impl ops::MulAssign for $VectorN - where - S: Copy + ops::MulAssign, - { - #[inline] - fn mul_assign(&mut self, other: Self) { - $(self.$field *= other.$field;)+ - } - } - - impl ops::RemAssign for $VectorN - where - S: Copy + ops::RemAssign, - { - #[inline] - fn rem_assign(&mut self, other: Self) { - $(self.$field %= other.$field;)+ - } - } - - // std::ops - vector scalar - - impl ops::Rem for $VectorN - where - S: Copy + ops::Rem, - { - type Output = $VectorN; - - #[inline] - fn rem(self, scalar: S) -> Self { - self.map(|s| s % scalar) - } - } - - impl ops::Div for $VectorN - where - S: Copy + ops::Div, - { - type Output = $VectorN; - - #[inline] - fn div(self, scalar: S) -> Self { - self.map(|s| s / scalar) - } - } - - impl ops::Mul for $VectorN - where - S: Copy + ops::Mul, - { - type Output = $VectorN; - - #[inline] - fn mul(self, scalar: S) -> Self { - self.map(|s| s * scalar) - } - } - - impl ops::RemAssign for $VectorN - where - S: Copy + ops::RemAssign, - { - #[inline] - fn rem_assign(&mut self, scalar: S) { - $(self.$field %= scalar;)+ - } - } - - impl ops::DivAssign for $VectorN - where - S: Copy + ops::DivAssign, - { - #[inline] - fn div_assign(&mut self, scalar: S) { - $(self.$field /= scalar;)+ - } - } - - impl ops::MulAssign for $VectorN - where - S: Copy + ops::MulAssign, - { - #[inline] - fn mul_assign(&mut self, scalar: S) { - $(self.$field *= scalar;)+ - } - } - - // indexing - - impl_index_operators!($VectorN, $n, S, usize); - impl_index_operators!($VectorN, $n, [S], ops::Range); - impl_index_operators!($VectorN, $n, [S], ops::RangeTo); - impl_index_operators!($VectorN, $n, [S], ops::RangeFrom); - impl_index_operators!($VectorN, $n, [S], ops::RangeFull); - - // conversions - - impl From<[S; $n]> for $VectorN - where - S: Copy, - { - #[inline] - fn from(v: [S; $n]) -> Self { - let [$($field),+] = v; - $VectorN { $($field),+ } - } - } - - impl Into<[S; $n]> for $VectorN { - #[inline] - fn into(self) -> [S; $n] { - let $VectorN { $($field),+ } = self; - [$($field),+] - } - } - - impl AsRef<[S; $n]> for $VectorN { - #[inline] - fn as_ref(&self) -> &[S; $n] { - unsafe { - let ptr = self as *const _ as *const [S; $n]; - &*ptr - } - } - } - - impl AsMut<[S; $n]> for $VectorN { - #[inline] - fn as_mut(&mut self) -> &mut [S; $n] { - unsafe { - let ptr = self as *mut _ as *mut [S; $n]; - &mut*ptr - } - } - } - - impl ops::Deref for $VectorN { - type Target = [S; $n]; - #[inline] - fn deref(&self) -> &Self::Target { - self.as_ref() - } - } - - impl ops::DerefMut for $VectorN { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut() - } - } - - // num-traits - - impl Bounded for $VectorN - where - S: Bounded, - { - #[inline] - fn min_value() -> $VectorN { - $VectorN { $($field: S::min_value()),+ } - } - - #[inline] - fn max_value() -> $VectorN { - $VectorN { $($field: S::max_value()),+ } - } - } - - impl Zero for $VectorN - where - S: PartialEq + Zero, - { - #[inline] - fn zero() -> $VectorN { - $VectorN { $($field: S::zero()),* } - } - - #[inline] - fn is_zero(&self) -> bool { - *self == $VectorN::zero() - } - } - - // `rand` crate implementations - - impl Distribution<$VectorN> for Standard - where - Standard: Distribution, - { - fn sample(&self, rng: &mut R) -> $VectorN { - $VectorN { $($field: rng.gen()),+ } - } - } - - /// The short constructor. - #[inline] - pub fn $constructor($($field: S),+) -> $VectorN { - $VectorN::new($($field),+) - } - }; -} - -mod cgmath_impl { - // From `cgmath` - macro_rules! fold_array { - (& $method:ident, { $x:expr }) => { - *$x - }; - (& $method:ident, { $x:expr, $y:expr }) => { - $x.$method(&$y) - }; - (& $method:ident, { $x:expr, $y:expr, $z:expr }) => { - $x.$method(&$y).$method(&$z) - }; - (& $method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { - $x.$method(&$y).$method(&$z).$method(&$w) - }; - ($method:ident, { $x:expr }) => { - $x - }; - ($method:ident, { $x:expr, $y:expr }) => { - $x.$method($y) - }; - ($method:ident, { $x:expr, $y:expr, $z:expr }) => { - $x.$method($y).$method($z) - }; - ($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { - $x.$method($y).$method($z).$method($w) - }; - } - - use super::{Vector2, Vector3, Vector4}; - use crate::math::cgmath::{ - self, Angle, Array, BaseFloat, BaseNum, ElementWise, EuclideanSpace, InnerSpace, - MetricSpace, Rad, VectorSpace, - }; - use crate::math::cgmath::{AbsDiffEq, RelativeEq, UlpsEq}; - use std::ops; - - macro_rules! impl_vector_cgmath { - ($VectorN:ident { $($field:ident),+ }, $n:expr) => { - impl From> for $VectorN { - #[inline] - fn from(v: cgmath::$VectorN) -> Self { - let cgmath::$VectorN { $($field),+ } = v; - $VectorN { $($field),+ } - } - } - - impl Into> for $VectorN { - #[inline] - fn into(self) -> cgmath::$VectorN { - let $VectorN { $($field),+ } = self; - cgmath::$VectorN { $($field),+ } - } - } - - impl VectorSpace for $VectorN - where - S: BaseNum, - { - type Scalar = S; - } - - impl MetricSpace for $VectorN - where - S: BaseFloat, - { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl AbsDiffEq for $VectorN - where - S: AbsDiffEq, - S::Epsilon: Copy, - { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq( - &self, - other: &Self, - epsilon: Self::Epsilon, - ) -> bool { - $(self.$field.abs_diff_eq(&other.$field, epsilon))&&+ - } - } - - impl RelativeEq for $VectorN - where - S: RelativeEq, - S::Epsilon: Copy, - { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq( - &self, - other: &Self, - epsilon: Self::Epsilon, - max_relative: Self::Epsilon, - ) -> bool { - $(self.$field.relative_eq(&other.$field, epsilon, max_relative))&&+ - } - } - - impl UlpsEq for $VectorN - where - S: UlpsEq, - S::Epsilon: Copy, - { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - $(self.$field.ulps_eq(&other.$field, epsilon, max_ulps))&&+ - } - } - - impl ElementWise for $VectorN - where - S: BaseNum, - { - #[inline] - fn add_element_wise(self, rhs: S) -> $VectorN { - $VectorN::new($(self.$field + rhs),+) - } - #[inline] - fn sub_element_wise(self, rhs: S) -> $VectorN { - $VectorN::new($(self.$field - rhs),+) - } - #[inline] - fn mul_element_wise(self, rhs: S) -> $VectorN { - $VectorN::new($(self.$field * rhs),+) - } - #[inline] - fn div_element_wise(self, rhs: S) -> $VectorN { - $VectorN::new($(self.$field / rhs),+) - } - #[inline] - fn rem_element_wise(self, rhs: S) -> $VectorN { - $VectorN::new($(self.$field % rhs),+) - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: S) { - $(self.$field += rhs);+ - } - #[inline] - fn sub_assign_element_wise(&mut self, rhs: S) { - $(self.$field -= rhs);+ - } - #[inline] - fn mul_assign_element_wise(&mut self, rhs: S) { - $(self.$field *= rhs);+ - } - #[inline] - fn div_assign_element_wise(&mut self, rhs: S) { - $(self.$field /= rhs);+ - } - #[inline] - fn rem_assign_element_wise(&mut self, rhs: S) { - $(self.$field %= rhs);+ - } - } - - impl ElementWise for $VectorN - where - S: BaseFloat, - { - #[inline] - fn add_element_wise(self, rhs: $VectorN) -> $VectorN { - $VectorN::new($(self.$field + rhs.$field),+) - } - #[inline] - fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { - $VectorN::new($(self.$field - rhs.$field),+) - } - #[inline] - fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { - $VectorN::new($(self.$field * rhs.$field),+) - } - #[inline] - fn div_element_wise(self, rhs: $VectorN) -> $VectorN { - $VectorN::new($(self.$field / rhs.$field),+) - } - #[inline] - fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { - $VectorN::new($(self.$field % rhs.$field),+) - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: $VectorN) { - $(self.$field += rhs.$field);+ - } - #[inline] - fn sub_assign_element_wise(&mut self, rhs: $VectorN) { - $(self.$field -= rhs.$field);+ - } - #[inline] - fn mul_assign_element_wise(&mut self, rhs: $VectorN) { - $(self.$field *= rhs.$field);+ - } - #[inline] - fn div_assign_element_wise(&mut self, rhs: $VectorN) { - $(self.$field /= rhs.$field);+ - } - #[inline] - fn rem_assign_element_wise(&mut self, rhs: $VectorN) { - $(self.$field %= rhs.$field);+ - } - } - - impl Array for $VectorN - where - S: Copy, - { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $VectorN { - $VectorN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S - where - S: ops::Add, - { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S - where - S: ops::Mul, - { - fold_array!(mul, { $(self.$field),+ }) - } - - #[inline] - fn is_finite(&self) -> bool - where - S: BaseFloat, - { - $(self.$field.is_finite())&&+ - } - } - - impl EuclideanSpace for $VectorN - where - S: BaseNum, - { - type Scalar = S; - type Diff = $VectorN; - - #[inline] - fn origin() -> Self { - $VectorN { $($field: S::zero()),+ } - } - - #[inline] - fn from_vec(v: $VectorN) -> Self { - $VectorN::new($(v.$field),+) - } - - #[inline] - fn to_vec(self) -> $VectorN { - $VectorN::new($(self.$field),+) - } - - #[inline] - fn dot(self, other: $VectorN) -> S { - $VectorN::new($(self.$field * other.$field),+).sum() - } - } - } - } - - // A macro to simplify the implementation of the point conversion traits. - macro_rules! impl_point_conversions { - ($VectorN:ident { $($field:ident),+ }, $PointN:ident) => { - impl From> for $VectorN { - #[inline] - fn from(v: cgmath::$PointN) -> Self { - let cgmath::$PointN { $($field),+ } = v; - $VectorN { $($field),+ } - } - } - - impl Into> for $VectorN { - #[inline] - fn into(self) -> cgmath::$PointN { - let $VectorN { $($field),+ } = self; - cgmath::$PointN { $($field),+ } - } - } - }; - } - - impl_vector_cgmath!(Vector2 { x, y }, 2); - impl_vector_cgmath!(Vector3 { x, y, z }, 3); - impl_vector_cgmath!(Vector4 { x, y, z, w }, 4); - - impl_point_conversions!(Vector2 { x, y }, Point2); - impl_point_conversions!(Vector3 { x, y, z }, Point3); - - impl InnerSpace for Vector2 - where - S: BaseFloat, - { - #[inline] - fn dot(self, other: Vector2) -> S { - Vector2::mul_element_wise(self, other).sum() - } - - #[inline] - fn angle(self, other: Vector2) -> Rad { - Rad::atan2(Self::perp_dot(self, other), Self::dot(self, other)) - } - } - - impl InnerSpace for Vector3 - where - S: BaseFloat, - { - #[inline] - fn dot(self, other: Vector3) -> S { - Vector3::mul_element_wise(self, other).sum() - } - - #[inline] - fn angle(self, other: Vector3) -> Rad { - Rad::atan2(self.cross(other).magnitude(), Self::dot(self, other)) - } - } - - impl InnerSpace for Vector4 - where - S: BaseFloat, - { - #[inline] - fn dot(self, other: Vector4) -> S { - Vector4::mul_element_wise(self, other).sum() - } - } -} - -mod lyon_impl { - use super::{Vector2, Vector3, Vector4}; - use crate::math::Zero; - - impl From for Vector2 - where - S: From, - { - fn from(p: lyon::math::Point) -> Self { - (S::from(p.x), S::from(p.y)).into() - } - } - - impl From for Vector3 - where - S: From + Zero, - { - fn from(p: lyon::math::Point) -> Self { - Vector2::from(p).into() - } - } - - impl From for Vector4 - where - S: From + Zero, - { - fn from(p: lyon::math::Point) -> Self { - Vector2::from(p).into() - } - } - - impl From for Vector2 - where - S: From, - { - fn from(p: lyon::math::F64Point) -> Self { - (S::from(p.x), S::from(p.y)).into() - } - } - - impl From for Vector3 - where - S: From + Zero, - { - fn from(p: lyon::math::F64Point) -> Self { - Vector2::from(p).into() - } - } - - impl From for Vector4 - where - S: From + Zero, - { - fn from(p: lyon::math::F64Point) -> Self { - Vector2::from(p).into() - } - } - - impl From for Vector2 - where - S: From, - { - fn from(v: lyon::math::Vector) -> Self { - (S::from(v.x), S::from(v.y)).into() - } - } - - impl From for Vector3 - where - S: From + Zero, - { - fn from(v: lyon::math::Vector) -> Self { - Vector2::from(v).into() - } - } - - impl From for Vector4 - where - S: From + Zero, - { - fn from(v: lyon::math::Vector) -> Self { - Vector2::from(v).into() - } - } - - impl From for Vector2 - where - S: From, - { - fn from(p: lyon::math::Size) -> Self { - (S::from(p.width), S::from(p.height)).into() - } - } - - impl From for Vector3 - where - S: From + Zero, - { - fn from(p: lyon::math::Size) -> Self { - Vector2::from(p).into() - } - } - - impl From for Vector4 - where - S: From + Zero, - { - fn from(p: lyon::math::Size) -> Self { - Vector2::from(p).into() - } - } - - impl Into for Vector2 { - fn into(self) -> lyon::math::Point { - (self.x, self.y).into() - } - } - - impl Into for Vector3 { - fn into(self) -> lyon::math::Point { - (self.x, self.y).into() - } - } - - impl Into for Vector4 { - fn into(self) -> lyon::math::Point { - (self.x, self.y).into() - } - } - - impl Into for Vector2 - where - S: Into, - { - fn into(self) -> lyon::math::F64Point { - (self.x.into(), self.y.into()).into() - } - } - - impl Into for Vector3 - where - S: Into, - { - fn into(self) -> lyon::math::F64Point { - (self.x.into(), self.y.into()).into() - } - } - - impl Into for Vector4 - where - S: Into, - { - fn into(self) -> lyon::math::F64Point { - (self.x.into(), self.y.into()).into() - } - } - - impl Into for Vector2 { - fn into(self) -> lyon::math::Vector { - (self.x, self.y).into() - } - } - - impl Into for Vector3 { - fn into(self) -> lyon::math::Vector { - (self.x, self.y).into() - } - } - - impl Into for Vector4 { - fn into(self) -> lyon::math::Vector { - (self.x, self.y).into() - } - } - - impl Into for Vector2 { - fn into(self) -> lyon::math::Size { - (self.x, self.y).into() - } - } - - impl Into for Vector3 { - fn into(self) -> lyon::math::Size { - (self.x, self.y).into() - } - } - - impl Into for Vector4 { - fn into(self) -> lyon::math::Size { - (self.x, self.y).into() - } - } -} - -impl_vector!(Vector2 { x, y }, 2, vec2); -impl_vector!(Vector3 { x, y, z }, 3, vec3); -impl_vector!(Vector4 { x, y, z, w }, 4, vec4); - -// tuple conversions - -impl From<(S, S)> for Vector2 { - fn from((x, y): (S, S)) -> Self { - Vector2 { x, y } - } -} - -impl From<(S, S, S)> for Vector3 { - fn from((x, y, z): (S, S, S)) -> Self { - Vector3 { x, y, z } - } -} - -impl From<(S, S, S, S)> for Vector4 { - fn from((x, y, z, w): (S, S, S, S)) -> Self { - Vector4 { x, y, z, w } - } -} - -impl Into<(S, S)> for Vector2 { - fn into(self) -> (S, S) { - let Vector2 { x, y } = self; - (x, y) - } -} - -impl Into<(S, S, S)> for Vector3 { - fn into(self) -> (S, S, S) { - let Vector3 { x, y, z } = self; - (x, y, z) - } -} - -impl Into<(S, S, S, S)> for Vector4 { - fn into(self) -> (S, S, S, S) { - let Vector4 { x, y, z, w } = self; - (x, y, z, w) - } -} - -// expanding tuple conversions - -impl From<(S, S)> for Vector3 -where - S: Zero, -{ - fn from((x, y): (S, S)) -> Self { - let z = S::zero(); - Vector3 { x, y, z } - } -} - -impl From<(S, S)> for Vector4 -where - S: Zero, -{ - fn from((x, y): (S, S)) -> Self { - let z = S::zero(); - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -impl From<(S, S, S)> for Vector4 -where - S: Zero, -{ - fn from((x, y, z): (S, S, S)) -> Self { - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -// expanding fixed-size array conversions - -impl From<[S; 2]> for Vector3 -where - S: Zero, -{ - fn from([x, y]: [S; 2]) -> Self { - let z = S::zero(); - Vector3 { x, y, z } - } -} - -impl From<[S; 2]> for Vector4 -where - S: Zero, -{ - fn from([x, y]: [S; 2]) -> Self { - let z = S::zero(); - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -impl From<[S; 3]> for Vector4 -where - S: Zero, -{ - fn from([x, y, z]: [S; 3]) -> Self { - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -// expanding vector conversions - -impl From> for Vector3 -where - S: Zero, -{ - fn from(Vector2 { x, y }: Vector2) -> Self { - let z = S::zero(); - Vector3 { x, y, z } - } -} - -impl From> for Vector4 -where - S: Zero, -{ - fn from(Vector2 { x, y }: Vector2) -> Self { - let z = S::zero(); - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -impl From> for Vector4 -where - S: Zero, -{ - fn from(Vector3 { x, y, z }: Vector3) -> Self { - let w = S::zero(); - Vector4 { x, y, z, w } - } -} - -// Vector 2 - -impl Vector2 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector2 - where - S: Zero + One, - { - Vector2::new(S::one(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector2 - where - S: Zero + One, - { - Vector2::new(S::zero(), S::one()) - } - - /// The perpendicular dot product of the vector and `other`. - #[inline] - pub fn perp_dot(self, other: Vector2) -> S - where - S: ops::Sub + ops::Mul, - { - (self.x * other.y) - (self.y * other.x) - } - - /// Create a `Vector3`, using the `x` and `y` values from this vector, and the - /// provided `z`. - #[inline] - pub fn extend(self, z: S) -> Vector3 { - Vector3::new(self.x, self.y, z) - } - - /// Construct a normalised (aka "unit") vector from the given angle in radians. - /// - /// # Examples - /// - /// ``` - /// # use nannou::prelude::*; - /// # fn main() { - /// assert_eq!(Vector2::from_angle(0.0), vec2(1.0, 0.0)); - /// // Keep an eye out for accumulating floating point error. - /// assert_eq!(Vector2::from_angle(PI * 0.5), vec2(-0.00000004371139, 1.0)); - /// assert_eq!(Vector2::from_angle(PI), vec2(-1.0, -0.00000008742278)); - /// assert_eq!(Vector2::from_angle(PI * 1.5), vec2(0.000000011924881, -1.0)); - /// assert_eq!(Vector2::from_angle(TAU), vec2(1.0, 0.00000017484555)); - /// # } - /// ``` - pub fn from_angle(radians: S) -> Self - where - S: BaseFloat, - { - vec2(radians.cos(), radians.sin()) - } - - /// Returns the angle of the vector in radians. - /// - /// # Examples - /// - /// ``` - /// # use nannou::prelude::*; - /// # use nannou::Draw; - /// # fn main() { - /// let v = vec2(-0.5, 0.5); - /// let radians = v.angle(); - /// # let draw = Draw::new(); - /// draw.quad() - /// .rotate(radians); - /// assert_eq!(radians, 2.356194490192345); - /// # } - /// ``` - /// - pub fn angle(self) -> S - where - S: BaseFloat, - { - self.y.atan2(self.x) - } - - /// Returns the angle of the vector between `self` and `other` in radians. - /// - /// The result is between 0 and PI. Note: Nannou's implementation is commutative - /// (`v1.angle_between(v2)` == `v2.angle_between(v1)`). - /// - /// # Example - /// - /// ``` - /// # use nannou::prelude::*; - /// # fn main() { - /// let right = vec2(2.0, 0.0); - /// let up = vec2(0.0, 3.0); - /// let down = vec2(0.0, -100.0); - /// assert_eq!(right.angle_between(up), PI/2.0); - /// assert_eq!(right.angle_between(down), PI/2.0); - /// # } - /// ``` - pub fn angle_between(self, other: Self) -> S - where - S: BaseFloat, - { - let cos_theta = self.dot(other) / (self.magnitude() * other.magnitude()); - // Handle float rounding issues by clamping to [-1, 1]. - let cos_theta = cos_theta.min(S::one()).max(-S::one()); - cos_theta.acos() - } - - /// Rotate the vector around the origin (0.0, 0.0) by the given radians. - /// - /// # Examples - /// - /// ``` - /// # use nannou::prelude::*; - /// # fn main() { - /// let v = vec2(100.0, 0.0); - /// assert_eq!(v.rotate(PI).x, -v.x); - /// assert_eq!(v.rotate(TAU).x, v.x); - /// # } - /// ``` - pub fn rotate(self, radians: S) -> Self - where - S: BaseFloat, - { - let rad_cos = radians.cos(); - let rad_sin = radians.sin(); - let x = self.x * rad_cos - self.y * rad_sin; - let y = self.x * rad_sin + self.y * rad_cos; - vec2(x, y) - } - - //impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xy); -} - -// Vector 3 - -impl Vector3 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector3 - where - S: Zero + One, - { - Vector3::new(S::one(), S::zero(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector3 - where - S: Zero + One, - { - Vector3::new(S::zero(), S::one(), S::zero()) - } - - /// A unit vector in the `z` direction. - #[inline] - pub fn unit_z() -> Vector3 - where - S: Zero + One, - { - Vector3::new(S::zero(), S::zero(), S::one()) - } - - /// Returns the cross product of the vector and `other`. - #[inline] - pub fn cross(self, other: Vector3) -> Vector3 - where - S: Copy + ops::Sub + ops::Mul, - { - Vector3::new( - (self.y * other.z) - (self.z * other.y), - (self.z * other.x) - (self.x * other.z), - (self.x * other.y) - (self.y * other.x), - ) - } - - /// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the - /// provided `w`. - #[inline] - pub fn extend(self, w: S) -> Vector4 { - Vector4::new(self.x, self.y, self.z, w) - } - - /// Create a `Vector2`, dropping the `z` value. - #[inline] - pub fn truncate(self) -> Vector2 { - Vector2::new(self.x, self.y) - } - - // impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyz); -} - -// Vector 4 - -impl Vector4 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector4 - where - S: Zero + One, - { - Vector4::new(S::one(), S::zero(), S::zero(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector4 - where - S: Zero + One, - { - Vector4::new(S::zero(), S::one(), S::zero(), S::zero()) - } - - /// A unit vector in the `z` direction. - #[inline] - pub fn unit_z() -> Vector4 - where - S: Zero + One, - { - Vector4::new(S::zero(), S::zero(), S::one(), S::zero()) - } - - /// A unit vector in the `w` direction. - #[inline] - pub fn unit_w() -> Vector4 - where - S: Zero + One, - { - Vector4::new(S::zero(), S::zero(), S::zero(), S::one()) - } - - /// Create a `Vector3`, dropping the `w` value. - #[inline] - pub fn truncate(self) -> Vector3 { - Vector3::new(self.x, self.y, self.z) - } - - /// Create a `Vector3`, dropping the nth element. - #[inline] - pub fn truncate_n(&self, n: isize) -> Vector3 - where - S: Copy, - { - match n { - 0 => Vector3::new(self.y, self.z, self.w), - 1 => Vector3::new(self.x, self.z, self.w), - 2 => Vector3::new(self.x, self.y, self.w), - 3 => Vector3::new(self.x, self.y, self.z), - _ => panic!("{:?} is out of range", n), - } - } - - //impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyzw); -} - -// utility functions - -fn limit_magnitude(v: V, limit: V::Scalar) -> V -where - V: InnerSpace, - V::Scalar: BaseFloat, -{ - let magnitude2 = v.magnitude2(); - if magnitude2 <= limit * limit { - v - } else { - v.normalize() * limit - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::prelude::*; - use cgmath::assert_ulps_eq; - - #[test] - fn test_angle_between() { - let right = vec2(1.0, 0.0); - let upright = vec2(1.0, 1.0); - assert_eq!(right.angle_between(upright), PI / 4.0); - // angle_between is symmetric. - assert_eq!(upright.angle_between(right), PI / 4.0); - - let left = vec2(-1.0, 0.0); - let left2 = vec2(-1.0123456789, 0.0); - assert_ulps_eq!(right.angle_between(left), PI); - assert_ulps_eq!(right.angle_between(left2), PI); - - // angle between same vector is 0. - assert_eq!(upright.angle_between(upright), 0.0); - assert_eq!(left.angle_between(left), 0.0); - assert_eq!(left2.angle_between(left2), 0.0); - - // handles zero vector. - assert_eq!(right.angle_between(vec2(0.0, 0.0)), 0.0); - assert_eq!(left2.angle_between(vec2(0.0, 0.0)), 0.0); - } -} diff --git a/nannou/src/geom/vertex.rs b/nannou/src/geom/vertex.rs deleted file mode 100644 index a05c8ef32..000000000 --- a/nannou/src/geom/vertex.rs +++ /dev/null @@ -1,344 +0,0 @@ -use crate::color; -use crate::geom::{scalar, Point2, Point3}; -use crate::math::BaseNum; -use std::ops::{Deref, DerefMut}; - -/// Types used as vertices that can be used to describe geometric points in space. -pub trait Vertex: Clone + Copy + PartialEq { - /// The values used to describe the vertex position. - type Scalar: BaseNum; -} - -/// Vertex types that have at least 2 dimensions. -pub trait Vertex2d: Vertex { - /// The x, y location of the vertex. - fn point2(self) -> Point2; -} - -/// Vertex types that have at least 3 dimensions. -pub trait Vertex3d: Vertex2d { - /// The x, y, z location of the vertex. - fn point3(self) -> Point3; -} - -/// If a type is not specified for a piece of geometry, this is the default type used. -pub type Default = Point3; - -/// An iterator yielding a vertex for each index yielded by the given indices iterator. -#[derive(Clone, Debug)] -pub struct IterFromIndices<'a, I, V: 'a = Default> { - indices: I, - vertices: &'a [V], -} - -/// A vertex that is colored with the given `sRGBA` color. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Srgba(pub V, pub color::Srgba); - -/// Produce an iterator yielding a vertex for each index yielded by the given indices iterator. -pub fn iter_from_indices(indices: I, vertices: &[V]) -> IterFromIndices -where - I: IntoIterator, -{ - let indices = indices.into_iter(); - IterFromIndices { indices, vertices } -} - -// Iterators - -impl<'a, I, V> Iterator for IterFromIndices<'a, I, V> -where - I: Iterator, -{ - type Item = &'a V; - fn next(&mut self) -> Option { - let IterFromIndices { - ref mut indices, - ref vertices, - } = *self; - indices.next().map(|i| &vertices[i]) - } - - fn size_hint(&self) -> (usize, Option) { - self.indices.size_hint() - } -} - -impl<'a, I, V> DoubleEndedIterator for IterFromIndices<'a, I, V> -where - I: Iterator + DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option { - let IterFromIndices { - ref mut indices, - ref vertices, - } = *self; - indices.next_back().map(|i| &vertices[i]) - } -} - -impl<'a, I, V> ExactSizeIterator for IterFromIndices<'a, I, V> -where - I: Iterator + ExactSizeIterator, -{ - fn len(&self) -> usize { - self.indices.len() - } -} - -// Srgba impls. - -impl Srgba { - /// A reference to the inner vertex. - pub fn vertex(&self) -> &V { - &self.0 - } - /// A reference to the inner rgba. - pub fn rgba(&self) -> &color::Srgba { - &self.1 - } -} - -impl Deref for Srgba { - type Target = V; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Srgba { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl From<(V, color::Srgba)> for Srgba { - fn from((v, rgba): (V, color::Srgba)) -> Self { - Srgba(v, rgba) - } -} - -impl Into<(V, color::Srgba)> for Srgba { - fn into(self) -> (V, color::Srgba) { - let Srgba(v, rgba) = self; - (v, rgba) - } -} - -// Vertex impls - -impl Vertex for Point2 -where - S: BaseNum, -{ - type Scalar = S; -} - -impl Vertex for Point3 -where - S: BaseNum, -{ - type Scalar = S; -} - -impl Vertex for [S; 2] -where - S: BaseNum, -{ - type Scalar = S; -} - -impl Vertex for [S; 3] -where - S: BaseNum, -{ - type Scalar = S; -} - -impl Vertex for (S, S) -where - S: BaseNum, -{ - type Scalar = S; -} - -impl Vertex for (S, S, S) -where - S: BaseNum, -{ - type Scalar = S; -} - -// impl Vertex for Vector2 -// where -// S: BaseNum, -// { -// type Scalar = S; -// } -// -// impl Vertex for Vector3 -// where -// S: BaseNum, -// { -// type Scalar = S; -// } - -impl Vertex for Srgba -where - V: Vertex, -{ - type Scalar = V::Scalar; -} - -// Vertex2d impls - -impl Vertex2d for Point2 -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - Point2 { - x: self.x, - y: self.y, - } - } -} - -impl Vertex2d for Point3 -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - Point2 { - x: self.x, - y: self.y, - } - } -} - -impl Vertex2d for [S; 2] -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - Point2 { - x: self[0], - y: self[1], - } - } -} - -impl Vertex2d for [S; 3] -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - Point2 { - x: self[0], - y: self[1], - } - } -} - -impl Vertex2d for (S, S) -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - let (x, y) = self; - Point2 { x, y } - } -} - -impl Vertex2d for (S, S, S) -where - S: BaseNum, -{ - fn point2(self) -> Point2 { - let (x, y, _) = self; - Point2 { x, y } - } -} - -// impl Vertex2d for Vector2 -// where -// S: BaseNum, -// { -// fn point2(self) -> Point2 { -// self -// } -// } -// -// impl Vertex2d for Vector3 -// where -// S: BaseNum, -// { -// fn point2(self) -> Point2 { -// Point2 { x: self.x, y: self.y } -// } -// } - -impl Vertex2d for Srgba -where - V: Vertex2d, -{ - fn point2(self) -> Point2 { - self.0.point2() - } -} - -// Vertex3d impls - -impl Vertex3d for Point3 -where - S: BaseNum, -{ - fn point3(self) -> Point3 { - Point3 { - x: self.x, - y: self.y, - z: self.z, - } - } -} - -impl Vertex3d for [S; 3] -where - S: BaseNum, -{ - fn point3(self) -> Point3 { - Point3 { - x: self[0], - y: self[1], - z: self[2], - } - } -} - -impl Vertex3d for (S, S, S) -where - S: BaseNum, -{ - fn point3(self) -> Point3 { - let (x, y, z) = self; - Point3 { x, y, z } - } -} - -// impl Vertex3d for Vector3 -// where -// S: BaseNum, -// { -// fn point3(self) -> Point3 { -// self -// } -// } - -impl Vertex3d for Srgba -where - V: Vertex3d, -{ - fn point3(self) -> Point3 { - self.0.point3() - } -} diff --git a/nannou/src/lib.rs b/nannou/src/lib.rs index 5806d3759..2f12f0888 100644 --- a/nannou/src/lib.rs +++ b/nannou/src/lib.rs @@ -19,17 +19,17 @@ pub use conrod_winit; pub use daggy; pub use find_folder; pub use lyon; -use serde_derive; pub use winit; +pub use self::app::{App, LoopMode}; +pub use self::draw::Draw; pub use self::event::Event; pub use self::frame::Frame; pub use self::ui::Ui; -pub use crate::app::{App, LoopMode}; -pub use crate::draw::Draw; +#[doc(inline)] +pub use nannou_core::{color, glam, math, rand}; pub mod app; -pub mod color; pub mod draw; pub mod ease; pub mod event; @@ -37,11 +37,9 @@ pub mod frame; pub mod geom; pub mod image; pub mod io; -pub mod math; pub mod mesh; pub mod noise; pub mod prelude; -pub mod rand; pub mod state; pub mod text; pub mod time; diff --git a/nannou/src/math.rs b/nannou/src/math.rs deleted file mode 100644 index ce30772fc..000000000 --- a/nannou/src/math.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! A mathematical foundation for nannou including point and vector types and a range of -//! helper/utility functions. - -pub use cgmath; - -pub use self::cgmath::num_traits::{self, Bounded, Float, NumCast, One, Zero}; -// cgmath modules -pub use self::cgmath::prelude; -// cgmath types -pub use self::cgmath::{ - Basis2, Basis3, Decomposed, Deg, Euler, Matrix2, Matrix3, Matrix4, Ortho, Perspective, - PerspectiveFov, Quaternion, Rad, -}; -// cgmath traits -pub use self::cgmath::{ - Angle, Array, BaseFloat, BaseNum, ElementWise, EuclideanSpace, InnerSpace, Matrix, MetricSpace, - Rotation, Rotation2, Rotation3, SquareMatrix, Transform, Transform2, Transform3, VectorSpace, -}; -use std::ops::Add; - -/// Maps a value from an input range to an output range. -/// -/// Note that `map_range` doesn't clamp the output: if `val` is outside the input range, the mapped -/// value will be outside the output range. (Use `clamp` to restrict the output, if desired.) -/// -/// # Examples -/// ``` -/// # use nannou::prelude::*; -/// assert_eq!(map_range(128, 0, 255, 0.0, 1.0), 0.5019607843137255); -/// ``` -/// ``` -/// # use nannou::prelude::*; -/// assert_eq!(map_range(3, 0, 10, 0.0, 1.0), 0.3); -/// ``` -/// ``` -/// # use nannou::prelude::*; -/// // When the value is outside the input range, the result will be outside the output range. -/// let result = map_range(15, 0, 10, 0.0, 1.0); -/// assert_eq!(result, 1.5); -/// assert_eq!(clamp(result, 0.0, 1.0), 1.0); -/// ``` -pub fn map_range(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y -where - X: NumCast, - Y: NumCast, -{ - macro_rules! unwrap_or_panic { - ($result:expr, $arg:expr) => { - $result.unwrap_or_else(|| panic!("[map_range] failed to cast {} arg to `f64`", $arg)) - }; - } - - let val_f: f64 = unwrap_or_panic!(NumCast::from(val), "first"); - let in_min_f: f64 = unwrap_or_panic!(NumCast::from(in_min), "second"); - let in_max_f: f64 = unwrap_or_panic!(NumCast::from(in_max), "third"); - let out_min_f: f64 = unwrap_or_panic!(NumCast::from(out_min), "fourth"); - let out_max_f: f64 = unwrap_or_panic!(NumCast::from(out_max), "fifth"); - - NumCast::from((val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f) - .unwrap_or_else(|| panic!("[map_range] failed to cast result to target type")) -} - -/// The max between two partially ordered values. -pub fn partial_max(a: T, b: T) -> T -where - T: PartialOrd, -{ - if a >= b { - a - } else { - b - } -} - -/// The min between two partially ordered values. -pub fn partial_min(a: T, b: T) -> T -where - T: PartialOrd, -{ - if a <= b { - a - } else { - b - } -} - -/// Clamp a value between some range. -pub fn clamp(n: T, start: T, end: T) -> T -where - T: PartialOrd, -{ - if start <= end { - if n < start { - start - } else if n > end { - end - } else { - n - } - } else { - if n < end { - end - } else if n > start { - start - } else { - n - } - } -} - -pub fn two() -> S -where - S: Add + One, -{ - S::one() + S::one() -} - -/// Models the C++ fmod function. -#[inline] -pub fn fmod(numer: F, denom: F) -> F -where - F: Float, -{ - let rquot: F = (numer / denom).floor(); - numer - rquot * denom -} - -/// Convert the given angle in degrees to the same angle in radians. -pub fn deg_to_rad(deg: S) -> S -where - S: BaseFloat, -{ - Rad::from(Deg(deg)).0 -} - -/// Convert the given angle in radians to the same angle in degrees. -pub fn rad_to_deg(rad: S) -> S -where - S: BaseFloat, -{ - Deg::from(Rad(rad)).0 -} - -/// Convert the given value as a number of "turns" into the equivalent angle in radians. -pub fn turns_to_rad(turns: S) -> S -where - S: BaseFloat, -{ - turns * NumCast::from(2.0 * ::std::f64::consts::PI).unwrap() -} - -/// Convert the given value in radians to the equivalent value as a number of turns. -pub fn rad_to_turns(rad: S) -> S -where - S: BaseFloat, -{ - rad / NumCast::from(2.0 * ::std::f64::consts::PI).unwrap() -} diff --git a/nannou/src/mesh/vertex.rs b/nannou/src/mesh/vertex.rs index c93f87667..2294a9d4d 100644 --- a/nannou/src/mesh/vertex.rs +++ b/nannou/src/mesh/vertex.rs @@ -1,9 +1,7 @@ //! Vertex types yielded by the mesh adaptors and their implementations. use crate::color::{self, IntoLinSrgba}; -use crate::geom::graph::node::{self, ApplyTransform}; -use crate::geom::{self, Point2, Point3}; -use crate::math::BaseFloat; +use crate::geom::{self, Point2}; use std::ops::{Deref, DerefMut}; /// A vertex with a specified color. @@ -15,7 +13,7 @@ pub struct WithColor> { /// A vertex with some specified texture coordinates. #[derive(Copy, Clone, Debug, Default, PartialEq)] -pub struct WithTexCoords> { +pub struct WithTexCoords { pub vertex: V, pub tex_coords: T, } @@ -27,49 +25,6 @@ pub struct WithNormal { pub normal: N, } -// Node Transform application implementations. - -impl ApplyTransform for WithColor -where - V: ApplyTransform, - S: BaseFloat, -{ - fn apply_transform(self, transform: &node::PreparedTransform) -> Self { - let WithColor { mut vertex, color } = self; - vertex = vertex.apply_transform(transform); - WithColor { vertex, color } - } -} - -impl ApplyTransform for WithTexCoords -where - V: ApplyTransform, - S: BaseFloat, -{ - fn apply_transform(self, transform: &node::PreparedTransform) -> Self { - let WithTexCoords { - mut vertex, - tex_coords, - } = self; - vertex = vertex.apply_transform(transform); - WithTexCoords { vertex, tex_coords } - } -} - -impl ApplyTransform for WithNormal -where - V: ApplyTransform, - S: BaseFloat, -{ - fn apply_transform(self, _transform: &node::PreparedTransform) -> Self { - //let WithNormal { mut vertex, mut normal } = self; - //vertex = vertex.apply_transform(transform); - // TODO: Apply transform to the `normal`. - unimplemented!(); - //WithNormal { vertex, normal } - } -} - // Deref implementations for each vertex adaptor to their inner vertex type. impl Deref for WithColor { @@ -142,7 +97,7 @@ where V: geom::Vertex2d, Self: geom::Vertex, { - fn point2(self) -> Point2 { + fn point2(self) -> [Self::Scalar; 2] { self.vertex.point2() } } @@ -152,7 +107,7 @@ where V: geom::Vertex2d, Self: geom::Vertex, { - fn point2(self) -> Point2 { + fn point2(self) -> [Self::Scalar; 2] { self.vertex.point2() } } @@ -162,7 +117,7 @@ where V: geom::Vertex2d, Self: geom::Vertex, { - fn point2(self) -> Point2 { + fn point2(self) -> [Self::Scalar; 2] { self.vertex.point2() } } @@ -172,7 +127,7 @@ where V: geom::Vertex3d, Self: geom::Vertex, { - fn point3(self) -> Point3 { + fn point3(self) -> [Self::Scalar; 3] { self.vertex.point3() } } @@ -182,7 +137,7 @@ where V: geom::Vertex3d, Self: geom::Vertex, { - fn point3(self) -> Point3 { + fn point3(self) -> [Self::Scalar; 3] { self.vertex.point3() } } @@ -192,7 +147,7 @@ where V: geom::Vertex3d, Self: geom::Vertex, { - fn point3(self) -> Point3 { + fn point3(self) -> [Self::Scalar; 3] { self.vertex.point3() } } @@ -240,6 +195,6 @@ where #[test] fn test_tuple_conv() { use crate::color::named::GREEN; - let _: Point2<_> = [0.0, 0.0].into(); - let _: WithColor> = ([0.0, 0.0], GREEN).into(); + let _: Point2 = [0.0, 0.0].into(); + let _: WithColor = ([0.0, 0.0], GREEN).into(); } diff --git a/nannou/src/prelude.rs b/nannou/src/prelude.rs index ee3acca06..91bd8fa3a 100644 --- a/nannou/src/prelude.rs +++ b/nannou/src/prelude.rs @@ -1,14 +1,6 @@ //! A collection of commonly used items that we recommend importing for ease of use. pub use crate::app::{self, App, LoopMode}; -pub use crate::color::named::*; -pub use crate::color::{ - gray, hsl, hsla, hsv, hsva, lin_srgb, lin_srgba, rgb, rgb8, rgba, rgba8, srgb, srgb8, srgba, - srgba8, -}; -pub use crate::color::{ - Gray, Hsl, Hsla, Hsv, Hsva, LinSrgb, LinSrgba, Rgb, Rgb8, Rgba, Rgba8, Srgb, Srgba, -}; pub use crate::draw::Draw; pub use crate::event::WindowEvent::*; pub use crate::event::{ @@ -16,17 +8,7 @@ pub use crate::event::{ TouchpadPressure, Update, WindowEvent, }; pub use crate::frame::{Frame, RawFrame}; -pub use crate::geom::{ - self, pt2, pt3, vec2, vec3, vec4, Cuboid, Point2, Point3, Rect, Vector2, Vector3, Vector4, -}; pub use crate::io::{load_from_json, load_from_toml, safe_file_save, save_to_json, save_to_toml}; -pub use crate::math::num_traits::*; -pub use crate::math::prelude::*; -pub use crate::math::{ - clamp, deg_to_rad, fmod, map_range, partial_max, partial_min, rad_to_deg, rad_to_turns, - turns_to_rad, -}; -pub use crate::rand::{random, random_ascii, random_f32, random_f64, random_range}; pub use crate::text::{self, text}; pub use crate::time::DurationF64; pub use crate::ui; @@ -38,14 +20,4 @@ pub use crate::wgpu::blend::{ pub use crate::wgpu::util::{BufferInitDescriptor, DeviceExt}; pub use crate::window::{self, Id as WindowId}; pub use crate::window::{Fullscreen, Window}; - -// The following constants have "regular" names for the `DefaultScalar` type and type suffixes for -// other types. If the `DefaultScalar` changes, these should probably change too. - -pub use std::f32::consts::PI; -pub use std::f64::consts::PI as PI_F64; - -/// Two times PI. -pub const TAU: f32 = PI * 2.0; -/// Two times PI. -pub const TAU_F64: f64 = PI_F64 * 2.0; +pub use nannou_core::prelude::*; diff --git a/nannou/src/rand.rs b/nannou/src/rand.rs deleted file mode 100644 index 824c82424..000000000 --- a/nannou/src/rand.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Items related to randomness and random number generators. Also provides some high-level helper -//! functions. -//! -//! Helper functions include [**random_f32()**](./fn.random_f32.html), -//! [**random_f64()**](./fn.random_f64.html) and [**random_range(min, -//! max)**](./fn.random_range.html). - -pub use rand; - -pub use self::rand::*; - -/// A wrapper function around the `random` function that avoids the need for specifying a type in -/// the case that it cannot be inferred. The primary purpose for this is to simplify the random API -/// for new rust users. -pub fn random_f32() -> f32 { - random() -} - -/// A wrapper function around the `random` function that avoids the need for specifying a type in -/// the case that it cannot be inferred. The primary purpose for this is to simplify the random API -/// for new rust users. -pub fn random_f64() -> f64 { - random() -} - -/// A function for generating a random value within the given range. -/// -/// The generated value may be within the range [min, max). That is, the result is inclusive of -/// `min`, but will never be `max`. -/// -/// If the given `min` is greater than the given `max`, they will be swapped before calling -/// `gen_range` internally to avoid triggering a `panic!`. -/// -/// This calls `rand::thread_rng().gen_range(min, max)` internally, in turn using the thread-local -/// default random number generator. -pub fn random_range(min: T, max: T) -> T -where - T: PartialOrd + distributions::uniform::SampleUniform, -{ - let (min, max) = if min <= max { (min, max) } else { (max, min) }; - rand::thread_rng().gen_range(min, max) -} - -/// Generates and returns a random ascii character. -/// -/// The ascii characters that can be generated are: -/// -/// ABCDEFGHIJKLMNOPQRSTUVWXYZ\ -/// abcdefghijklmnopqrstuvwxyz\ -/// 0123456789)(*&^%$#@!~. -pub fn random_ascii() -> char { - const ASCIISET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789)(*&^%$#@!~. "; - - let idx = rand::thread_rng().gen_range(0, ASCIISET.len()); - ASCIISET[idx] as char -} diff --git a/nannou/src/state.rs b/nannou/src/state.rs index bcf8ba652..545f7fcd7 100644 --- a/nannou/src/state.rs +++ b/nannou/src/state.rs @@ -65,14 +65,10 @@ pub mod keys { /// Tracked state related to the mouse. pub mod mouse { - use crate::geom::{self, Point2}; - use crate::math::BaseFloat; + use crate::geom::Point2; use crate::window; use std; - /// The default scalar value used for positions. - pub type DefaultScalar = geom::scalar::Default; - #[doc(inline)] pub use crate::event::MouseButton as Button; @@ -81,76 +77,64 @@ pub mod mouse { /// The state of the `Mouse` at a single moment in time. #[derive(Copy, Clone, Debug, PartialEq)] - pub struct Mouse { + pub struct Mouse { /// The ID of the last window currently in focus. pub window: Option, /// *x* position relative to the middle of `window`. - pub x: S, + pub x: f32, /// *y* position relative to the middle of `window`. - pub y: S, + pub y: f32, /// A map describing the state of each mouse button. pub buttons: ButtonMap, } /// Whether the button is up or down. #[derive(Copy, Clone, Debug, PartialEq)] - pub enum ButtonPosition { + pub enum ButtonPosition { /// The button is up (i.e. pressed). Up, /// The button is down and was originally pressed down at the given `Point2`. - Down(Point2), + Down(Point2), } /// Stores the state of all mouse buttons. /// /// If the mouse button is down, it stores the position of the mouse when the button was pressed #[derive(Copy, Clone, Debug, PartialEq)] - pub struct ButtonMap { - buttons: [ButtonPosition; NUM_BUTTONS], + pub struct ButtonMap { + buttons: [ButtonPosition; NUM_BUTTONS], } /// An iterator yielding all pressed buttons. #[derive(Clone)] - pub struct PressedButtons<'a, S: 'a = DefaultScalar> { - buttons: std::iter::Enumerate>>, + pub struct PressedButtons<'a> { + buttons: std::iter::Enumerate>, } - impl Mouse - where - S: BaseFloat, - { + impl Mouse { /// Construct a new default `Mouse`. pub fn new() -> Self { Mouse { window: None, buttons: ButtonMap::new(), - x: S::zero(), - y: S::zero(), + x: 0.0, + y: 0.0, } } /// The position of the mouse relative to the middle of the window in focus.. - pub fn position(&self) -> Point2 { - Point2 { - x: self.x, - y: self.y, - } + pub fn position(&self) -> Point2 { + [self.x, self.y].into() } } - impl ButtonPosition - where - S: BaseFloat, - { + impl ButtonPosition { /// If the mouse button is down, return a new one with position relative to the given `xy`. - pub fn relative_to(self, xy: Point2) -> Self { + pub fn relative_to(self, xy: Point2) -> Self { match self { ButtonPosition::Down(pos) => { let rel_p = pos - xy; - ButtonPosition::Down(Point2 { - x: rel_p.x, - y: rel_p.y, - }) + ButtonPosition::Down([rel_p.x, rel_p.y].into()) } button_pos => button_pos, } @@ -173,7 +157,7 @@ pub mod mouse { } /// Returns the position at which the button was pressed. - pub fn if_down(&self) -> Option> { + pub fn if_down(&self) -> Option { match *self { ButtonPosition::Down(xy) => Some(xy), _ => None, @@ -181,10 +165,7 @@ pub mod mouse { } } - impl ButtonMap - where - S: BaseFloat, - { + impl ButtonMap { /// Returns a new button map with all states set to `None` pub fn new() -> Self { ButtonMap { @@ -193,7 +174,7 @@ pub mod mouse { } /// Returns a copy of the ButtonMap relative to the given `Point` - pub fn relative_to(self, xy: Point2) -> Self { + pub fn relative_to(self, xy: Point2) -> Self { self.buttons .iter() .enumerate() @@ -204,22 +185,22 @@ pub mod mouse { } /// The state of the left mouse button. - pub fn left(&self) -> &ButtonPosition { + pub fn left(&self) -> &ButtonPosition { &self[Button::Left] } /// The state of the middle mouse button. - pub fn middle(&self) -> &ButtonPosition { + pub fn middle(&self) -> &ButtonPosition { &self[Button::Middle] } /// The state of the right mouse button. - pub fn right(&self) -> &ButtonPosition { + pub fn right(&self) -> &ButtonPosition { &self[Button::Right] } /// Sets the `Button` in the `Down` position. - pub fn press(&mut self, button: Button, xy: Point2) { + pub fn press(&mut self, button: Button, xy: Point2) { self.buttons[button_to_idx(button)] = ButtonPosition::Down(xy); } @@ -230,25 +211,22 @@ pub mod mouse { /// An iterator yielding all pressed mouse buttons along with the location at which they /// were originally pressed. - pub fn pressed(&self) -> PressedButtons { + pub fn pressed(&self) -> PressedButtons { PressedButtons { buttons: self.buttons.iter().enumerate(), } } } - impl std::ops::Index