use crate::geom::{quad, scalar, Point3, Quad, Range, Tri, Vector3};
use crate::math::num_traits::Float;
use crate::math::BaseNum;
use std::ops::Neg;
pub const NUM_FACES: u8 = 6;
pub const NUM_CORNERS: u8 = 8;
pub const NUM_SUBDIVISIONS: u8 = 8;
pub const NUM_TRIANGLES: u8 = NUM_FACES * 2;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Cuboid<S = scalar::Default> {
pub x: Range<S>,
pub y: Range<S>,
pub z: Range<S>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Face {
Back,
Right,
Top,
Front,
Bottom,
Left,
}
#[derive(Clone, Debug)]
pub struct Corners<'a, S: 'a> {
cuboid: &'a Cuboid<S>,
corner_index: u8,
}
#[derive(Clone, Debug)]
pub struct Faces {
next_face_index: u8,
}
pub type FaceQuad<S> = Quad<Point3<S>>;
#[derive(Clone, Debug)]
pub struct FaceQuads<'a, S: 'a = scalar::Default> {
cuboid: &'a Cuboid<S>,
faces: Faces,
}
#[derive(Clone, Debug)]
pub struct Triangles<'a, S: 'a> {
face_quads: FaceQuads<'a, S>,
triangles: quad::Triangles<Point3<S>>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct SubdivisionRanges<S> {
pub x_a: Range<S>,
pub x_b: Range<S>,
pub y_a: Range<S>,
pub y_b: Range<S>,
pub z_a: Range<S>,
pub z_b: Range<S>,
}
#[derive(Clone)]
pub struct Subdivisions<S = scalar::Default> {
ranges: SubdivisionRanges<S>,
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(),
]
};
}
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<S> Cuboid<S>
where
S: BaseNum,
{
pub fn from_xyz_whd(p: Point3<S>, d: Vector3<S>) -> 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),
}
}
pub fn from_ranges(x: Range<S>, y: Range<S>, z: Range<S>) -> Self {
Cuboid { x, y, z }
}
pub fn absolute(&self) -> Self {
let x = self.x.absolute();
let y = self.y.absolute();
let z = self.z.absolute();
Cuboid { x, y, z }
}
pub fn x(&self) -> S {
self.x.middle()
}
pub fn y(&self) -> S {
self.y.middle()
}
pub fn z(&self) -> S {
self.z.middle()
}
pub fn xyz(&self) -> Point3<S> {
[self.x(), self.y(), self.z()].into()
}
pub fn x_y_z(&self) -> (S, S, S) {
(self.x(), self.y(), self.z())
}
pub fn shift_x(self, x: S) -> Self {
Cuboid {
x: self.x.shift(x),
..self
}
}
pub fn shift_y(self, y: S) -> Self {
Cuboid {
y: self.y.shift(y),
..self
}
}
pub fn shift_z(self, z: S) -> Self {
Cuboid {
z: self.z.shift(z),
..self
}
}
pub fn shift(self, v: Vector3<S>) -> Self {
let Vector3 { x, y, z } = v;
Cuboid {
x: self.x.shift(x),
y: self.y.shift(y),
z: self.z.shift(z),
}
}
pub fn contains(&self, p: Point3<S>) -> bool {
self.x.contains(p.x) && self.y.contains(p.y) && self.z.contains(p.z)
}
pub fn stretch_to_point(self, p: Point3<S>) -> 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),
}
}
pub fn overlap(self, other: Self) -> Option<Self> {
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 }))
})
}
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),
}
}
pub fn left(&self) -> S {
self.x.start
}
pub fn right(&self) -> S {
self.x.end
}
pub fn bottom(&self) -> S {
self.y.start
}
pub fn top(&self) -> S {
self.y.end
}
pub fn front(&self) -> S {
self.z.start
}
pub fn back(&self) -> S {
self.z.end
}
pub fn left_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 4, 6, 2, 0))
}
pub fn right_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 1, 3, 7, 5))
}
pub fn bottom_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 0, 1, 5, 4))
}
pub fn top_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 2, 6, 7, 3))
}
pub fn front_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 0, 2, 3, 1))
}
pub fn back_quad(&self) -> FaceQuad<S> {
Quad(quad_from_corner_indices!(self, 5, 7, 6, 4))
}
pub fn face_quad(&self, face: Face) -> FaceQuad<S> {
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(),
}
}
pub fn corners(&self) -> [Point3<S>; 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]
}
pub fn corners_iter(&self) -> Corners<S> {
Corners {
cuboid: self,
corner_index: 0,
}
}
pub fn faces(&self) -> [FaceQuad<S>; 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(),
]
}
pub fn faces_iter(&self) -> FaceQuads<S> {
FaceQuads {
faces: Faces { next_face_index: 0 },
cuboid: self,
}
}
pub fn triangles_iter(&self) -> Triangles<S> {
let mut face_quads = self.faces_iter();
let first_quad = face_quads.next().unwrap();
let triangles = first_quad.triangles_iter();
Triangles {
face_quads,
triangles,
}
}
pub fn subdivision_ranges(&self) -> SubdivisionRanges<S> {
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<S> SubdivisionRanges<S>
where
S: Copy,
{
pub fn cuboids(&self) -> [Cuboid<S>; 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]
}
pub fn cuboids_iter(self) -> Subdivisions<S> {
Subdivisions {
ranges: self,
subdivision_index: 0,
}
}
fn subdivision_at_index(&self, index: u8) -> Option<Cuboid<S>> {
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<S> Cuboid<S>
where
S: BaseNum + Neg<Output = S>,
{
pub fn w(&self) -> S {
self.x.len()
}
pub fn h(&self) -> S {
self.y.len()
}
pub fn d(&self) -> S {
self.z.len()
}
pub fn whd(&self) -> Vector3<S> {
[self.w(), self.h(), self.d()].into()
}
pub fn w_h_d(&self) -> (S, S, S) {
(self.w(), self.h(), self.d())
}
pub fn volume(&self) -> S {
let (w, h, d) = self.w_h_d();
w * h * d
}
pub fn xyz_whd(&self) -> (Point3<S>, Vector3<S>) {
(self.xyz(), self.whd())
}
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)
}
pub fn pad_left(self, pad: S) -> Self {
Cuboid {
x: self.x.pad_start(pad),
..self
}
}
pub fn pad_right(self, pad: S) -> Self {
Cuboid {
x: self.x.pad_end(pad),
..self
}
}
pub fn pad_bottom(self, pad: S) -> Self {
Cuboid {
y: self.y.pad_start(pad),
..self
}
}
pub fn pad_top(self, pad: S) -> Self {
Cuboid {
y: self.y.pad_end(pad),
..self
}
}
pub fn pad_front(self, pad: S) -> Self {
Cuboid {
z: self.z.pad_start(pad),
..self
}
}
pub fn pad_back(self, pad: S) -> Self {
Cuboid {
z: self.z.pad_end(pad),
..self
}
}
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<S>(c: &Cuboid<S>, index: u8) -> Option<Point3<S>>
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<S>;
fn next(&mut self) -> Option<Self::Item> {
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<Self::Item> {
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 {
fn from_index(i: u8) -> Option<Self> {
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<Self::Item> {
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<Self::Item> {
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<S>;
fn next(&mut self) -> Option<Self::Item> {
self.faces.next().map(|f| self.cuboid.face_quad(f))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.faces.size_hint()
}
}
impl<'a, S> DoubleEndedIterator for FaceQuads<'a, S>
where
S: BaseNum,
{
fn next_back(&mut self) -> Option<Self::Item> {
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<Point3<S>>;
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'a, S> DoubleEndedIterator for Triangles<'a, S>
where
S: BaseNum,
{
fn next_back(&mut self) -> Option<Self::Item> {
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<S> Iterator for Subdivisions<S>
where
S: Copy,
{
type Item = Cuboid<S>;
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<S> DoubleEndedIterator for Subdivisions<S>
where
S: Copy,
{
fn next_back(&mut self) -> Option<Self::Item> {
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<S> ExactSizeIterator for Subdivisions<S>
where
S: Copy,
{
fn len(&self) -> usize {
NUM_SUBDIVISIONS as usize - self.subdivision_index as usize
}
}