pub use super::rectangle_field::*;
use anyhow::Result;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use crate::magnets::{GetCenter, GetField, MagnetTrait};
use crate::points::{Point2, PolarPoint};
use crate::utils::conversions::Angle;
use crate::MagnetError;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Rectangle {
pub width: f64,
pub height: f64,
pub center: Point2,
pub alpha: Angle,
pub jr: f64,
pub phi: Angle,
pub a: f64,
pub b: f64,
pub jx: f64,
pub jy: f64,
}
impl GetCenter<Point2> for Point2 {
fn center(&self) -> Point2 {
*self
}
}
impl<T: Into<f64> + Copy, U: Into<f64> + Copy> GetCenter<Point2> for (T, U) {
fn center(&self) -> Point2 {
Point2 {
x: self.0.into(),
y: self.1.into(),
}
}
}
impl Default for Rectangle {
fn default() -> Self {
Rectangle {
width: 1.0,
height: 1.0,
center: Point2::new(0.0, 0.0),
alpha: Angle::Degrees(0.0),
jr: 1.0,
phi: Angle::Degrees(90.0),
jx: 0.0,
jy: 1.0,
a: 0.5,
b: 0.5,
}
}
}
impl Rectangle {
pub fn new<C>(
width: f64,
height: f64,
center: C,
alpha: Angle,
jr: f64,
phi: Angle,
) -> Rectangle
where
C: GetCenter<Point2>,
{
let phi_rad = phi.to_radians();
Rectangle {
width,
height,
center: center.center(),
alpha,
jr,
phi,
jx: jr * phi_rad.cos(),
jy: jr * phi_rad.sin(),
a: width / 2.0,
b: height / 2.0,
}
}
}
impl fmt::Display for Rectangle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[w: {},\th: {},\tc: {},\talpha:{}\tJ ({:.3}, {:.3})]",
self.width,
self.height,
self.center,
self.alpha.to_degrees(),
self.jr,
self.phi.to_degrees()
)
}
}
impl MagnetTrait<[f64; 2], Point2, [f64; 2], PolarPoint> for Rectangle {
fn center(&self) -> Point2 {
self.center
}
fn size(&self) -> [f64; 2] {
[self.width, self.height]
}
fn magnetisation(self) -> PolarPoint {
PolarPoint::new(self.jr, self.phi.to_radians())
}
fn set_center(&mut self, point: Point2) {
self.center = point;
}
fn set_size(&mut self, point: [f64; 2]) {
self.width = point[0];
self.height = point[1];
self.a = self.width / 2.0;
self.b = self.height / 2.0;
}
fn set_magnetisation(&mut self, magnetisation: PolarPoint) {
self.jr = magnetisation.rho;
self.phi = Angle::Radians(magnetisation.phi);
self.jx = self.jr * (magnetisation.phi.cos());
self.jy = self.jr * (magnetisation.phi.sin());
}
}
impl GetField<&Point2, Result<Point2, MagnetError>> for Rectangle {
fn field(&self, point: &Point2) -> Result<Point2, MagnetError> {
get_field_rectangle(self, point)
}
}
impl GetField<&(f64, f64), Result<(f64, f64), MagnetError>> for Rectangle {
fn field(&self, point: &(f64, f64)) -> Result<(f64, f64), MagnetError> {
let field_vec = get_field_rectangle(
self,
&Point2 {
x: point.0,
y: point.1,
},
)?;
Ok((field_vec.x, field_vec.y))
}
}
#[cfg(test)]
mod tests {
use crate::utils::comparison::nearly_equal;
use super::{Angle, GetField, Point2, Rectangle};
#[test]
fn test_tuple_rectangle_field() {
let magnet = Rectangle::new(
1.0,
1.0,
Point2::new(0., 0.0),
Angle::Degrees(0.0),
1.0,
Angle::Degrees(90.0),
);
let point = (0.0, 0.0);
let field = magnet.field(&point).unwrap();
assert!(nearly_equal(field.0, 0.0_f64));
assert!(nearly_equal(field.1, 0.5));
}
#[test]
fn test_point2_rectangle_field() {
let magnet = Rectangle::new(
1.0,
1.0,
Point2::new(0., 0.0),
Angle::Degrees(0.0),
1.0,
Angle::Degrees(90.0),
);
let point = Point2::new(0.0, 0.0);
let field = magnet.field(&point).unwrap();
assert!(nearly_equal(field.x, 0.0_f64));
assert!(nearly_equal(field.y, 0.5_f64));
}
#[test]
fn test_point2_rectangle_field_45() {
let magnet = Rectangle::new(
1.0,
1.0,
Point2::new(0., 0.0),
Angle::Degrees(0.0),
1.0,
Angle::Degrees(45.0),
);
let point = Point2::new(0.0, 0.0);
let field = magnet.field(&point).unwrap();
assert!(nearly_equal(field.x, 0.5 / 2.0_f64.sqrt()));
assert!(nearly_equal(field.y, 0.5 / 2.0_f64.sqrt()));
}
}