use serde::{Deserialize, Serialize};
use crate::model::Material;
use crate::scope::{Quat, Vec3};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SnapBinding {
pub label: String,
pub tolerance: Option<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Axis {
X,
Y,
Z,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SplitSize {
Absolute(f64),
Relative(f64),
Floating(f64),
}
impl SplitSize {
pub fn is_valid(&self) -> bool {
match self {
SplitSize::Absolute(v) | SplitSize::Relative(v) | SplitSize::Floating(v) => {
v.is_finite() && *v > 0.0
}
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SplitSlot {
pub size: SplitSize,
pub rule: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum FaceSelector {
Top,
Bottom,
Front,
Back,
Left,
Right,
Side,
All,
}
impl FaceSelector {
pub fn parse(s: &str) -> Option<Self> {
match s {
"top" | "Top" => Some(Self::Top),
"bottom" | "Bottom" => Some(Self::Bottom),
"front" | "Front" => Some(Self::Front),
"back" | "Back" => Some(Self::Back),
"left" | "Left" => Some(Self::Left),
"right" | "Right" => Some(Self::Right),
"side" | "Side" => Some(Self::Side),
"all" | "All" | "_" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CompFaceCase {
pub selector: FaceSelector,
pub rule: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CompTarget {
Faces(Vec<CompFaceCase>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum OffsetSelector {
Inside,
Border,
All,
}
impl OffsetSelector {
pub fn parse(s: &str) -> Option<Self> {
match s {
"inside" | "Inside" => Some(Self::Inside),
"border" | "Border" => Some(Self::Border),
"all" | "All" | "_" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OffsetCase {
pub selector: OffsetSelector,
pub rule: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RoofType {
Pyramid,
Shed,
Gable,
Hip,
Flat,
OpenGable,
BoxGable,
PyramidHip,
Butterfly,
MShaped,
Gambrel,
Mansard,
Saltbox,
Jerkinhead,
DutchGable,
}
impl RoofType {
pub fn parse(s: &str) -> Option<Self> {
match s {
"pyramid" | "Pyramid" => Some(Self::Pyramid),
"shed" | "Shed" => Some(Self::Shed),
"gable" | "Gable" => Some(Self::Gable),
"hip" | "Hip" => Some(Self::Hip),
"flat" | "Flat" => Some(Self::Flat),
"openGable" | "OpenGable" => Some(Self::OpenGable),
"boxGable" | "BoxGable" => Some(Self::BoxGable),
"pyramidHip" | "PyramidHip" => Some(Self::PyramidHip),
"butterfly" | "Butterfly" => Some(Self::Butterfly),
"mShaped" | "MShaped" => Some(Self::MShaped),
"gambrel" | "Gambrel" => Some(Self::Gambrel),
"mansard" | "Mansard" => Some(Self::Mansard),
"saltbox" | "Saltbox" => Some(Self::Saltbox),
"jerkinhead" | "Jerkinhead" => Some(Self::Jerkinhead),
"dutchGable" | "DutchGable" => Some(Self::DutchGable),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum RoofFaceSelector {
Slope,
GableEnd,
LowerSlope,
UpperSlope,
HipEnd,
ValleySlope,
OuterSlope,
InnerSlope,
Fascia,
All,
}
impl RoofFaceSelector {
pub fn parse(s: &str) -> Option<Self> {
match s {
"slope" | "Slope" => Some(Self::Slope),
"gable" | "GableEnd" | "gableEnd" => Some(Self::GableEnd),
"lowerSlope" | "LowerSlope" => Some(Self::LowerSlope),
"upperSlope" | "UpperSlope" => Some(Self::UpperSlope),
"hipEnd" | "HipEnd" => Some(Self::HipEnd),
"valleySlope" | "ValleySlope" => Some(Self::ValleySlope),
"outerSlope" | "OuterSlope" => Some(Self::OuterSlope),
"innerSlope" | "InnerSlope" => Some(Self::InnerSlope),
"fascia" | "Fascia" => Some(Self::Fascia),
"all" | "All" | "_" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RoofCase {
pub selector: RoofFaceSelector,
pub rule: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RoofConfig {
pub roof_type: RoofType,
pub pitch: f64,
pub secondary_pitch: Option<f64>,
pub overhang: f64,
pub ridge_offset: f64,
pub fascia_depth: f64,
pub tier_height: Option<f64>,
}
impl RoofConfig {
pub fn new(roof_type: RoofType, pitch: f64) -> Self {
Self {
roof_type,
pitch,
secondary_pitch: None,
overhang: 0.0,
ridge_offset: 0.5,
fascia_depth: 0.0,
tier_height: None,
}
}
pub fn secondary_pitch_or_default(&self) -> f64 {
self.secondary_pitch.unwrap_or(self.pitch / 2.0)
}
pub fn tier_height_or(&self, default: f64) -> f64 {
self.tier_height.unwrap_or(default)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AttachSelector {
Surface,
All,
}
impl AttachSelector {
pub fn parse(s: &str) -> Option<Self> {
match s {
"surface" | "Surface" => Some(Self::Surface),
"all" | "All" | "_" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttachCase {
pub selector: AttachSelector,
pub rule: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ShapeOp {
Extrude(f64),
Taper(f64),
Rotate(Quat),
Translate(Vec3),
Scale(Vec3),
Split {
axis: Axis,
slots: Vec<SplitSlot>,
snap: Option<SnapBinding>,
},
Repeat {
axis: Axis,
tile_sizes: Vec<f64>,
rule: String,
},
Comp(CompTarget),
I(String),
Mat(Material),
Rule(String),
Align { local_axis: Axis, target: Vec3 },
Offset {
distance: f64,
cases: Vec<OffsetCase>,
},
Roof {
config: RoofConfig,
cases: Vec<RoofCase>,
},
RegSnap(String),
IfClear { rule: String },
IfOccluded { rule: String },
Polygon(Vec<glam::DVec2>),
Attach {
world_axis: Vec3,
cases: Vec<AttachCase>,
},
}