use log::warn;
use crate::{Dose, Mode, Plane, Projection};
/// Controller for the X-ray planes in the system.
pub struct Controller<const IS_TWO_PLANE: bool> {
pub(crate) frontal: Plane,
pub(crate) lateral: Plane,
}
impl<const IS_TWO_PLANE: bool> Controller<IS_TWO_PLANE> {
/// Get a non-mutable reference to the frontal plane.
/// This might be useful if you want to check the state of the plane.
#[must_use]
pub fn frontal(&self) -> &Plane {
&self.frontal
}
/// Activate the frontal plane with the given [`Dose`] and [`Mode`].
///
/// # Examples
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<false>) {
/// controller.activate_frontal(Dose::High, Mode::Video);
///
/// let frontal = controller.frontal();
/// assert!(frontal.active());
/// assert_eq!(frontal.dose(), Dose::High);
/// assert_eq!(frontal.mode(), Mode::Video);
/// # }
/// ```
pub fn activate_frontal(&mut self, dose: Dose, mode: Mode) {
self.frontal.set_and_activate_xray(dose, mode);
}
}
impl Controller<false> {
/// Deactivate all active X-ray planes.
///
/// For a system with only one plane this
/// deactivates only the frontal plane.
///
/// # Examples
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<false>) {
/// assert!(!controller.frontal().active()); // starts inactive
/// controller.activate_frontal(Dose::Low, Mode::Image);
/// assert!(controller.frontal().active()); // now active
/// controller.deactivate_xray();
/// assert!(!controller.frontal().active()); // again inactive
/// # }
/// ```
pub fn deactivate_xray(&mut self) {
self.frontal.deactivate_xray();
}
}
impl Controller<true> {
/// Get a non-mutable reference to the lateral plane.
/// This might be useful if you want to check the state of the plane.
///
/// This function is only available for two-plane systems,
/// so it is only defined for [`Controller<true>`].
#[must_use]
pub fn lateral(&self) -> &Plane {
&self.lateral
}
/// Activate the lateral plane with the given [`Dose`] and [`Mode`].
///
/// This function is only available for two-plane systems,
/// so it is only defined for [`Controller<true>`].
///
/// # Examples
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<true>) {
/// controller.activate_lateral(Dose::High, Mode::Video);
///
/// let lateral = controller.lateral();
/// assert!(lateral.active());
/// assert_eq!(lateral.dose(), Dose::High);
/// assert_eq!(lateral.mode(), Mode::Video);
/// # }
/// ```
pub fn activate_lateral(&mut self, dose: Dose, mode: Mode) {
self.lateral.set_and_activate_xray(dose, mode);
}
/// Activate both planes with the given [`Dose`] and [`Mode`].
///
/// This function is only available for two-plane systems,
/// so it is only defined for [`Controller<true>`].
///
/// # Examples
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<true>) {
/// controller.activate_biplane(Dose::Low, Mode::Video);
///
/// let frontal = controller.frontal();
/// assert!(frontal.active());
/// assert_eq!(frontal.dose(), Dose::Low);
/// assert_eq!(frontal.mode(), Mode::Video);
///
/// let lateral = controller.lateral();
/// assert!(lateral.active());
/// assert_eq!(lateral.dose(), Dose::Low);
/// assert_eq!(lateral.mode(), Mode::Video);
/// # }
/// ```
pub fn activate_biplane(&mut self, dose: Dose, mode: Mode) {
self.frontal.set_and_activate_xray(dose, mode);
self.lateral.set_and_activate_xray(dose, mode);
}
/// Activate the X-ray planes based on the projection with
/// the given [`Dose`] and [`Mode`].
///
/// This function is only available for two-plane systems,
/// so it is only defined for [`Controller<true>`].
pub fn activate_xray(&mut self, projection: Projection, dose: Dose, mode: Mode) {
match projection {
Projection::Frontal => self.activate_frontal(dose, mode),
Projection::Lateral => self.activate_lateral(dose, mode),
Projection::Biplane => self.activate_biplane(dose, mode),
}
}
/// Deactivate all active X-ray planes.
///
/// Logs a warning if there are no active planes.
///
/// # Examples
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<true>) {
/// // activate both
/// controller.activate_biplane(Dose::High, Mode::Video);
/// assert!(controller.frontal().active());
/// assert!(controller.lateral().active());
///
/// // deactivate both
/// controller.deactivate_xray();
/// assert!(!controller.frontal().active());
/// assert!(!controller.lateral().active());
/// # }
/// ```
///
/// ```
/// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
/// # fn f(controller: &mut Controller<true>) {
/// // activate lateral
/// controller.activate_lateral(Dose::Low, Mode::Video);
/// assert!(!controller.frontal().active());
/// assert!(controller.lateral().active());
///
/// // deactivate lateral
/// controller.deactivate_xray();
/// assert!(!controller.frontal().active());
/// assert!(!controller.lateral().active());
///
/// // deactivate again - this logs a warning
/// controller.deactivate_xray();
/// # }
/// ```
pub fn deactivate_xray(&mut self) {
let mut deactivated = false;
if self.frontal.active() {
self.frontal.deactivate_xray();
deactivated = true;
}
if self.lateral.active() {
self.lateral.deactivate_xray();
deactivated = true;
}
if !deactivated {
warn!("Tried deactivating X-ray planes but they were all already inactive");
}
}
}