region: add an ElongatedTorus type

this is needed for when we want to couple some cores,
but require a narrower space to do so in.
This commit is contained in:
colin 2022-09-01 18:39:32 -07:00
parent 19ff08ada8
commit f737a4c916
2 changed files with 139 additions and 0 deletions

View File

@ -0,0 +1,97 @@
use crate::geom::Meters;
use super::{
and_not,
Cube,
HasCrossSection,
Intersection,
InvertedRegion,
Region,
Torus,
Union,
Union4,
};
use coremem_cross::vec::Vec3;
/// it's a torus, but elongated around its axis to resemble a pill shape.
///
/// ```
/// _______
/// / \
/// | |
/// \_______/
/// ```
pub struct ElongatedTorus(Union4<
Intersection<Torus, InvertedRegion<Cube>>, // rounded top
Intersection<Torus, InvertedRegion<Cube>>, // rounded bottom
Cube, // left connection between top/bot
Cube, // right connection between top/bot
>);
impl ElongatedTorus {
pub fn new_xz(center: Meters, length: f32, major_rad: f32, minor_rad: f32) -> Self {
let body = Cube::new_centered(
center,
Meters::new(2.0 * (major_rad + minor_rad), 2.0 * minor_rad, length),
);
let top = and_not(
Torus::new_xz(
center + Meters::new(0.0, 0.0, length),
major_rad,
minor_rad,
),
body,
);
let bot = and_not(
Torus::new_xz(
center - Meters::new(0.0, 0.0, length),
major_rad,
minor_rad,
),
body,
);
// TODO: these should be cylinders
let left = Cube::new_centered(
center - Meters::new(major_rad, 0.0, 0.0),
Meters::new(2.0 * minor_rad, 2.0 * minor_rad, length),
);
let right = Cube::new_centered(
center + Meters::new(major_rad, 0.0, 0.0),
Meters::new(2.0 * minor_rad, 2.0 * minor_rad, length),
);
Self(Union::new4(
top,
bot,
left,
right,
))
}
}
impl Region for ElongatedTorus {
fn contains(&self, p: Meters) -> bool {
self.0.contains(p)
}
}
impl HasCrossSection for ElongatedTorus {
fn cross_section_normal(&self, p: Meters) -> Vec3<f32> {
let top = self.0.region0_of_4();
let bot = self.0.region1_of_4();
let right = self.0.region3_of_4();
let left = self.0.region2_of_4();
let bridge_area =
(right.x_range().end - right.x_range().start)
* (right.y_range().start - right.y_range().end);
if top.contains(p) {
top.region0_of_2().cross_section_normal(p)
} else if bot.contains(p) {
bot.region0_of_2().cross_section_normal(p)
} else if right.contains(p) {
Vec3::new(0.0, 0.0, bridge_area)
} else if left.contains(p) {
Vec3::new(0.0, 0.0, -bridge_area)
} else {
Vec3::default()
}
}
}

View File

@ -7,6 +7,8 @@ use serde::{Serialize, Deserialize};
use std::collections::BTreeSet;
use std::sync::Arc;
mod constructed;
pub use constructed::*;
mod primitives;
pub use primitives::*;
@ -118,6 +120,40 @@ impl<R1, R2> Union<R1, R2> {
}
}
impl<R0, R1> Union<R0, R1> {
pub fn region0_of_2(&self) -> &R0 {
&self.0
}
pub fn region1_of_2(&self) -> &R1 {
&self.1
}
}
impl<R0, R1, R2> Union3<R0, R1, R2> {
pub fn region0_of_3(&self) -> &R0 {
self.0.region0_of_2()
}
pub fn region1_of_3(&self) -> &R1 {
self.0.region1_of_2()
}
pub fn region2_of_3(&self) -> &R2 {
&self.1
}
}
impl<R0, R1, R2, R3> Union4<R0, R1, R2, R3> {
pub fn region0_of_4(&self) -> &R0 {
self.0.region0_of_3()
}
pub fn region1_of_4(&self) -> &R1 {
self.0.region1_of_3()
}
pub fn region2_of_4(&self) -> &R2 {
self.0.region2_of_3()
}
pub fn region3_of_4(&self) -> &R3 {
&self.1
}
}
impl<R1: Region, R2: Region> Region for Union<R1, R2> {
fn contains(&self, p: Meters) -> bool {
self.0.contains(p) || self.1.contains(p)
@ -135,6 +171,12 @@ impl<R1, R2> Intersection<R1, R2> {
pub fn new2(r1: R1, r2: R2) -> Self {
Self(r1, r2)
}
pub fn region0_of_2(&self) -> &R1 {
&self.0
}
pub fn region1_of_2(&self) -> &R2 {
&self.1
}
}
impl<R1: Region, R2: Region> Region for Intersection<R1, R2> {