use crate::*;
#[cfg(feature = "bevy")]
use bevy::prelude::{Bundle, Component, Entity};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub const DEFAULT_DOOR_THICKNESS: f32 = 0.05;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "bevy", derive(Bundle))]
pub struct Door<T: RefTrait> {
pub anchors: Edge<T>,
pub name: NameInSite,
pub kind: DoorType,
#[serde(skip)]
pub marker: DoorMarker,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "bevy", derive(Component))]
pub enum DoorType {
SingleSliding(SingleSlidingDoor),
DoubleSliding(DoubleSlidingDoor),
SingleSwing(SingleSwingDoor),
DoubleSwing(DoubleSwingDoor),
Model(Model),
}
impl DoorType {
pub fn single_sliding(&self) -> Option<&SingleSlidingDoor> {
match self {
Self::SingleSliding(v) => Some(v),
_ => None,
}
}
pub fn double_sliding(&self) -> Option<&DoubleSlidingDoor> {
match self {
Self::DoubleSliding(v) => Some(v),
_ => None,
}
}
pub fn single_swing(&self) -> Option<&SingleSwingDoor> {
match self {
Self::SingleSwing(v) => Some(v),
_ => None,
}
}
pub fn double_swing(&self) -> Option<&DoubleSwingDoor> {
match self {
Self::DoubleSwing(v) => Some(v),
_ => None,
}
}
pub fn model(&self) -> Option<&Model> {
match self {
Self::Model(v) => Some(v),
_ => None,
}
}
pub fn label(&self) -> &str {
match self {
Self::SingleSliding(_) => "Single Sliding",
Self::DoubleSliding(_) => "Double Sliding",
Self::SingleSwing(_) => "Single Swing",
Self::DoubleSwing(_) => "Double Swing",
Self::Model(_) => "Model",
}
}
pub fn set_open(&mut self) {
self.set_positions(1.0);
}
pub fn set_closed(&mut self) {
self.set_positions(0.0);
}
pub fn set_positions(&mut self, position: f32) {
match self {
Self::SingleSliding(door) => {
door.position = position;
}
Self::SingleSwing(door) => {
door.position = position;
}
Self::DoubleSliding(door) => {
door.left_position = position;
door.right_position = position;
}
Self::DoubleSwing(door) => {
door.left_position = position;
door.right_position = position;
}
Self::Model(_) => {
}
}
}
}
impl Default for DoorType {
fn default() -> Self {
SingleSlidingDoor::default().into()
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct SingleSlidingDoor {
pub towards: Side,
#[serde(default, skip_serializing_if = "is_default")]
pub position: f32,
}
impl Default for SingleSlidingDoor {
fn default() -> Self {
Self {
towards: Side::Left,
position: 1.0,
}
}
}
impl From<SingleSlidingDoor> for DoorType {
fn from(v: SingleSlidingDoor) -> Self {
Self::SingleSliding(v)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct DoubleSlidingDoor {
pub left_right_ratio: f32,
#[serde(default, skip_serializing_if = "is_default")]
pub left_position: f32,
#[serde(default, skip_serializing_if = "is_default")]
pub right_position: f32,
}
impl DoubleSlidingDoor {
pub fn compute_offset(&self, door_width: f32) -> f32 {
let l = self.left_right_ratio * door_width / (self.left_right_ratio + 1.0);
return door_width / 2.0 - l;
}
}
impl Default for DoubleSlidingDoor {
fn default() -> Self {
Self {
left_right_ratio: 1.0,
left_position: 1.0,
right_position: 1.0,
}
}
}
impl From<DoubleSlidingDoor> for DoorType {
fn from(v: DoubleSlidingDoor) -> Self {
Self::DoubleSliding(v)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct SingleSwingDoor {
pub pivot_on: Side,
pub swing: Swing,
#[serde(default, skip_serializing_if = "is_default")]
pub position: f32,
}
impl Default for SingleSwingDoor {
fn default() -> Self {
Self {
pivot_on: Side::Left,
swing: Swing::Forward(Angle::Deg(90.0)),
position: 1.0,
}
}
}
impl From<SingleSwingDoor> for DoorType {
fn from(v: SingleSwingDoor) -> Self {
Self::SingleSwing(v)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct DoubleSwingDoor {
pub swing: Swing,
pub left_right_ratio: f32,
#[serde(default, skip_serializing_if = "is_default")]
pub left_position: f32,
#[serde(default, skip_serializing_if = "is_default")]
pub right_position: f32,
}
impl DoubleSwingDoor {
pub fn compute_offset(&self, door_width: f32) -> f32 {
let l = self.left_right_ratio * door_width / (self.left_right_ratio + 1.0);
return door_width / 2.0 - l;
}
}
impl Default for DoubleSwingDoor {
fn default() -> Self {
Self {
swing: Swing::Forward(Angle::Deg(90.0)),
left_right_ratio: 1.0,
left_position: 1.0,
right_position: 1.0,
}
}
}
impl From<DoubleSwingDoor> for DoorType {
fn from(v: DoubleSwingDoor) -> Self {
Self::DoubleSwing(v)
}
}
impl From<Model> for DoorType {
fn from(v: Model) -> Self {
Self::Model(v)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
pub enum Swing {
Forward(Angle),
Backward(Angle),
Both { forward: Angle, backward: Angle },
}
impl Swing {
pub fn label(&self) -> &'static str {
match self {
Self::Forward(_) => "Forward",
Self::Backward(_) => "Backward",
Self::Both { .. } => "Both",
}
}
pub fn swing_on_pivot(&self, pivot_on: Side) -> (Angle, Angle) {
let pivot_sign = pivot_on.sign();
let closed_angle = pivot_on.pivot_closed_angle();
match self {
Self::Forward(sweep) => (closed_angle, pivot_sign * *sweep),
Self::Backward(sweep) => (closed_angle, -pivot_sign * *sweep),
Self::Both { forward, backward } => (
closed_angle - pivot_sign * *backward,
pivot_sign * (*forward + *backward),
),
}
}
pub fn assume_forward(&self) -> Self {
match self {
Self::Forward(angle) => Self::Forward(*angle),
Self::Backward(angle) => Self::Forward(*angle),
Self::Both { forward, .. } => Self::Forward(*forward),
}
}
pub fn assume_backward(&self) -> Self {
match self {
Self::Forward(angle) => Self::Backward(*angle),
Self::Backward(angle) => Self::Backward(*angle),
Self::Both { backward, .. } => Self::Backward(*backward),
}
}
pub fn assume_both(&self) -> Self {
match self {
Self::Forward(angle) => Self::Both {
forward: *angle,
backward: *angle,
},
Self::Backward(angle) => Self::Both {
forward: *angle,
backward: *angle,
},
Self::Both { forward, backward } => Self::Both {
forward: *forward,
backward: *backward,
},
}
}
}
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "bevy", derive(Component))]
pub struct DoorMarker;
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "bevy", derive(Component))]
pub struct RecallDoorType {
pub single_sliding: Option<DoorType>,
pub double_sliding: Option<DoorType>,
pub single_swing: Option<DoorType>,
pub double_swing: Option<DoorType>,
pub model: Option<DoorType>,
}
impl RecallDoorType {
pub fn assume_single_sliding(&self, current: &DoorType) -> DoorType {
current
.single_sliding()
.map(|x| x.clone().into())
.unwrap_or(
self.single_sliding
.as_ref()
.map(|x| x.clone())
.unwrap_or(SingleSlidingDoor::default().into()),
)
}
pub fn assume_double_sliding(&self, current: &DoorType) -> DoorType {
current
.double_sliding()
.map(|x| x.clone().into())
.unwrap_or(
self.double_sliding
.as_ref()
.map(|x| x.clone())
.unwrap_or(DoubleSlidingDoor::default().into()),
)
}
pub fn assume_single_swing(&self, current: &DoorType) -> DoorType {
current.single_swing().map(|x| x.clone().into()).unwrap_or(
self.single_swing
.as_ref()
.map(|x| x.clone())
.unwrap_or(SingleSwingDoor::default().into()),
)
}
pub fn assume_double_swing(&self, current: &DoorType) -> DoorType {
current.double_swing().map(|x| x.clone().into()).unwrap_or(
self.double_swing
.as_ref()
.map(|x| x.clone())
.unwrap_or(DoubleSwingDoor::default().into()),
)
}
pub fn assume_model(&self, current: &DoorType) -> DoorType {
current.model().map(|x| x.clone().into()).unwrap_or(
self.model
.as_ref()
.map(|x| x.clone())
.unwrap_or(DoorType::Model(Model::default())),
)
}
}
impl Recall for RecallDoorType {
type Source = DoorType;
fn remember(&mut self, source: &Self::Source) {
match source {
DoorType::SingleSliding(_) => {
self.single_sliding = Some(source.clone());
}
DoorType::DoubleSliding { .. } => {
self.double_sliding = Some(source.clone());
}
DoorType::SingleSwing { .. } => {
self.single_swing = Some(source.clone());
}
DoorType::DoubleSwing(_) => {
self.double_swing = Some(source.clone());
}
DoorType::Model(_) => {
self.model = Some(source.clone());
}
}
}
}
#[cfg(feature = "bevy")]
impl Door<Entity> {
pub fn to_u32(&self, anchors: Edge<u32>) -> Door<u32> {
Door {
anchors,
name: self.name.clone(),
kind: self.kind.clone(),
marker: Default::default(),
}
}
}
impl<T: RefTrait> Door<T> {
pub fn convert<U: RefTrait>(&self, id_map: &HashMap<T, U>) -> Result<Door<U>, T> {
Ok(Door {
anchors: self.anchors.convert(id_map)?,
name: self.name.clone(),
kind: self.kind.clone(),
marker: Default::default(),
})
}
}
impl<T: RefTrait> From<Edge<T>> for Door<T> {
fn from(edge: Edge<T>) -> Self {
let kind = SingleSlidingDoor {
position: 0.0,
..Default::default()
};
Door {
anchors: edge,
name: NameInSite("<Unnamed>".to_string()),
kind: kind.into(),
marker: Default::default(),
}
}
}