use dyn_clone::DynClone;
use planar_geo::prelude::*;
use std::borrow::Cow;
use std::{any::Any, sync::Arc};
use stem_material::prelude::*;
#[cfg(feature = "cairo")]
use planar_geo::draw::Style;
#[doc = ""]
#[cfg_attr(
feature = "doc-images",
doc = "![Magnet coordinate system in rotary motors][drawing_rotary_motor]"
)]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image("drawing_rotary_motor", "docs/img/drawing_rotary_motor.svg")
)]
#[cfg_attr(
feature = "doc-images",
doc = "![Magnet coordinate system in linear motors][drawing_linear_motor]"
)]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image("drawing_linear_motor", "docs/img/drawing_linear_motor.svg")
)]
#[cfg_attr(
not(feature = "doc-images"),
doc = "**Doc images not enabled**. Compile docs with
`cargo doc --features 'doc-images'` and Rust version >= 1.54."
)]
#[cfg_attr(feature = "serde", typetag::serde)]
pub trait Magnet: Sync + Send + DynClone + std::fmt::Debug + Any {
fn width(&self) -> Length;
fn length(&self) -> Length;
fn thickness(&self) -> Length;
fn material(&self) -> &Material;
fn shape(&self) -> Cow<'_, Shape>;
fn material_arc(&self) -> Arc<Material> {
Arc::new(self.material().clone())
}
fn area(&self) -> Area {
let shape = self.shape();
return Area::new::<square_meter>(shape.area());
}
fn volume(&self) -> Volume {
return self.area() * self.length();
}
fn mass(&self) -> Mass {
return self.volume() * self.material().mass_density().get(&[]);
}
fn magnetomotive_force(&self, conditions: &[DynQuantity<f64>]) -> ElectricCurrent {
let remanence = self.material().remanence().get(conditions);
if remanence > MagneticFluxDensity::new::<tesla>(0.0) {
let rel_permeability = self.material().relative_permeability().get(conditions);
return remanence * self.thickness() / (rel_permeability * *VACUUM_PERMEABILITY);
} else {
return ElectricCurrent::new::<ampere>(0.0);
}
}
fn north_south_shapes(&self) -> [Cow<'_, Shape>; 2] {
let shape: Cow<'_, Shape> = self.shape();
let mut bb = shape.bounding_box();
bb.scale(2.0); let y = shape.centroid()[1];
let cut_line = Polysegment::from_points(&[[bb.xmin(), y], [bb.xmax(), y]]);
let cutted: Vec<Polysegment> =
shape
.contour()
.intersection_cut(&cut_line, DEFAULT_EPSILON, DEFAULT_MAX_ULPS);
if cutted.len() == 2 {
let mut it = cutted.into_iter();
let north_chain = it.next().expect("has two elements");
let south_chain = it.next().expect("has two elements");
if let Ok(north) = Shape::new(vec![Contour::new(north_chain)]) {
if let Ok(south) = Shape::new(vec![Contour::new(south_chain)]) {
return [Cow::Owned(north), Cow::Owned(south)];
}
}
}
match shape {
Cow::Borrowed(shape) => {
return [Cow::Borrowed(shape), Cow::Borrowed(shape)];
}
Cow::Owned(shape) => {
return [Cow::Owned(shape.clone()), Cow::Owned(shape)];
}
}
}
#[doc = ""]
#[cfg_attr(
feature = "doc-images",
doc = "![Magnet with normal north-south orientation][block_magnet_north_south]"
)]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image(
"block_magnet_north_south",
"docs/img/block_magnet_north_south.svg"
)
)]
#[cfg_attr(
feature = "doc-images",
doc = "![Magnet with inverted north-south orientation][block_magnet_south_north]"
)]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image(
"block_magnet_south_north",
"docs/img/block_magnet_south_north.svg"
)
)]
#[cfg_attr(
not(feature = "doc-images"),
doc = "**Doc images not enabled**. Compile docs with
`cargo doc --features 'doc-images'` and Rust version >= 1.54."
)]
#[cfg(feature = "cairo")]
fn drawables(&self, split: bool, invert: bool) -> Vec<DrawableCow<'_>> {
if split {
let shapes = self.north_south_shapes();
let mut dark_green = Style::default();
dark_green.background_color = crate::DARK_GREEN;
let mut red = Style::default();
red.background_color = crate::RED;
let styles = if invert {
[red, dark_green]
} else {
[dark_green, red]
};
return shapes
.into_iter()
.zip(styles.into_iter())
.map(DrawableCow::from)
.collect();
} else {
let shape = self.shape();
let mut style = Style::default();
style.background_color = crate::RED;
return vec![DrawableCow::from((shape, style))];
}
}
}