use std::fmt;
use std::iter::Sum;
use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
#[derive(Clone, Copy, Default, PartialEq, PartialOrd)]
pub struct Pt(f32);
impl Pt {
pub const ZERO: Self = Self(0.0);
pub const INFINITY: Self = Self(f32::INFINITY);
pub const fn new(v: f32) -> Self {
Self(v)
}
pub fn abs(self) -> Self {
Self(self.0.abs())
}
pub fn max(self, other: Self) -> Self {
Self(self.0.max(other.0))
}
pub fn min(self, other: Self) -> Self {
Self(self.0.min(other.0))
}
pub fn raw(self) -> f32 {
self.0
}
}
impl fmt::Debug for Pt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.2}pt", self.0)
}
}
impl fmt::Display for Pt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.2}pt", self.0)
}
}
impl From<Pt> for f32 {
fn from(pt: Pt) -> f32 {
pt.0
}
}
impl Add for Pt {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}
impl AddAssign for Pt {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for Pt {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
impl SubAssign for Pt {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Neg for Pt {
type Output = Self;
fn neg(self) -> Self {
Self(-self.0)
}
}
impl Mul<f32> for Pt {
type Output = Self;
fn mul(self, rhs: f32) -> Self {
Self(self.0 * rhs)
}
}
impl Div<f32> for Pt {
type Output = Self;
fn div(self, rhs: f32) -> Self {
Self(self.0 / rhs)
}
}
impl Div<Pt> for Pt {
type Output = f32;
fn div(self, rhs: Pt) -> f32 {
self.0 / rhs.0
}
}
impl Sum for Pt {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
Self(iter.map(|p| p.0).sum())
}
}
use crate::model::dimension::{Dimension, EighthPoints, Emu, HalfPoints, Points, Twips};
impl From<Dimension<Twips>> for Pt {
fn from(d: Dimension<Twips>) -> Self {
Self(d.raw() as f32 / 20.0)
}
}
impl From<Dimension<HalfPoints>> for Pt {
fn from(d: Dimension<HalfPoints>) -> Self {
Self(d.raw() as f32 / 2.0)
}
}
impl From<Dimension<Emu>> for Pt {
fn from(d: Dimension<Emu>) -> Self {
Self(d.raw() as f32 / 12700.0)
}
}
impl From<Dimension<EighthPoints>> for Pt {
fn from(d: Dimension<EighthPoints>) -> Self {
Self(d.raw() as f32 / 8.0)
}
}
impl From<Dimension<Points>> for Pt {
fn from(d: Dimension<Points>) -> Self {
Self(d.raw() as f32)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pt_zero() {
assert_eq!(Pt::ZERO.raw(), 0.0);
}
#[test]
fn pt_arithmetic() {
let a = Pt::new(10.0);
let b = Pt::new(3.0);
assert_eq!((a + b).raw(), 13.0);
assert_eq!((a - b).raw(), 7.0);
assert_eq!((a * 2.0).raw(), 20.0);
assert_eq!((a / 2.0).raw(), 5.0);
assert_eq!(a / b, 10.0 / 3.0);
}
#[test]
fn pt_add_assign() {
let mut a = Pt::new(5.0);
a += Pt::new(3.0);
assert_eq!(a.raw(), 8.0);
}
#[test]
fn pt_sub_assign() {
let mut a = Pt::new(5.0);
a -= Pt::new(2.0);
assert_eq!(a.raw(), 3.0);
}
#[test]
fn pt_neg() {
assert_eq!((-Pt::new(5.0)).raw(), -5.0);
}
#[test]
fn pt_abs() {
assert_eq!(Pt::new(-3.0).abs().raw(), 3.0);
assert_eq!(Pt::new(3.0).abs().raw(), 3.0);
}
#[test]
fn pt_max_min() {
let a = Pt::new(5.0);
let b = Pt::new(10.0);
assert_eq!(a.max(b).raw(), 10.0);
assert_eq!(a.min(b).raw(), 5.0);
}
#[test]
fn pt_sum() {
let pts = vec![Pt::new(1.0), Pt::new(2.0), Pt::new(3.0)];
let total: Pt = pts.into_iter().sum();
assert_eq!(total.raw(), 6.0);
}
#[test]
fn twips_to_pt() {
assert_eq!(Pt::from(Dimension::<Twips>::new(720)).raw(), 36.0);
}
#[test]
fn half_points_to_pt() {
assert_eq!(Pt::from(Dimension::<HalfPoints>::new(24)).raw(), 12.0);
}
#[test]
fn emu_to_pt() {
let pt = Pt::from(Dimension::<Emu>::new(914400));
assert!((pt.raw() - 72.0).abs() < 0.01);
}
#[test]
fn eighth_points_to_pt() {
assert_eq!(Pt::from(Dimension::<EighthPoints>::new(8)).raw(), 1.0);
}
#[test]
fn pt_display() {
assert_eq!(format!("{}", Pt::new(12.5)), "12.50pt");
}
#[test]
fn pt_infinity() {
assert!(Pt::INFINITY.raw().is_infinite());
}
}