generated from ElnuDev/rust-project
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
3.1 KiB
142 lines
3.1 KiB
use super::SVGUnit;
|
|
use derive_more::From;
|
|
use lazy_static::lazy_static;
|
|
use regex::Regex;
|
|
use std::cmp::Ordering;
|
|
use std::fmt;
|
|
use std::num::ParseFloatError;
|
|
use std::str::FromStr;
|
|
use std::{
|
|
fmt::Display,
|
|
ops::{Add, Div, Mul, Rem, Sub},
|
|
};
|
|
use strum::ParseError;
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct SVGMeasure {
|
|
pub measure: f64,
|
|
pub unit: SVGUnit,
|
|
}
|
|
|
|
impl SVGMeasure {
|
|
pub const fn new(measure: f64, unit: SVGUnit) -> Self {
|
|
Self { measure, unit }
|
|
}
|
|
|
|
pub fn to_user_units(self) -> f64 {
|
|
self.measure * self.unit.to_user_units()
|
|
}
|
|
|
|
pub fn to_unit(self, unit: SVGUnit) -> Self {
|
|
SVGMeasure {
|
|
measure: self.to_user_units() / unit.to_user_units(),
|
|
unit,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(From, Debug)]
|
|
pub enum SVGUnitParseError {
|
|
ParseMeasure(ParseFloatError),
|
|
ParseUnit(ParseError),
|
|
Invalid,
|
|
}
|
|
|
|
impl FromStr for SVGMeasure {
|
|
type Err = SVGUnitParseError;
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
if s == "0" {
|
|
return Ok(SVGMeasure::new(0.0, SVGUnit::Pixel));
|
|
}
|
|
lazy_static! {
|
|
static ref RE: Regex = Regex::new(r"^([\d.]+)([a-zA-Z]+)$").unwrap();
|
|
}
|
|
if let Some(captures) = RE.captures(s) {
|
|
let measure = captures[1].parse::<f64>()?;
|
|
let unit = captures[2].parse::<SVGUnit>()?;
|
|
Ok(SVGMeasure::new(measure, unit))
|
|
} else {
|
|
Err(SVGUnitParseError::Invalid)
|
|
}
|
|
}
|
|
}
|
|
|
|
const EQ_TOLERANCE: f64 = 0.00001;
|
|
|
|
impl PartialEq for SVGMeasure {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
(self.to_user_units() - other.to_user_units()).abs() < EQ_TOLERANCE
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for SVGMeasure {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(if self == other {
|
|
Ordering::Equal
|
|
} else if self.to_user_units() > other.to_user_units() {
|
|
Ordering::Greater
|
|
} else {
|
|
Ordering::Less
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Display for SVGMeasure {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}{}", self.measure, self.unit)
|
|
}
|
|
}
|
|
|
|
impl Add for SVGMeasure {
|
|
type Output = Self;
|
|
|
|
fn add(mut self, other: Self) -> Self {
|
|
self.measure += other.to_unit(self.unit).measure;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Sub for SVGMeasure {
|
|
type Output = Self;
|
|
|
|
fn sub(mut self, other: Self) -> Self {
|
|
self.measure -= other.to_unit(self.unit).measure;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Mul<f64> for SVGMeasure {
|
|
type Output = Self;
|
|
|
|
fn mul(mut self, scalar: f64) -> Self {
|
|
self.measure *= scalar;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Div for SVGMeasure {
|
|
type Output = f64;
|
|
|
|
fn div(self, other: Self) -> Self::Output {
|
|
self.measure / other.to_unit(self.unit).measure
|
|
}
|
|
}
|
|
|
|
impl Div<f64> for SVGMeasure {
|
|
type Output = Self;
|
|
|
|
fn div(mut self, scalar: f64) -> Self {
|
|
self.measure /= scalar;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Rem for SVGMeasure {
|
|
type Output = Self;
|
|
|
|
fn rem(mut self, other: Self) -> Self::Output {
|
|
self.measure %= other.to_unit(self.unit).measure;
|
|
self
|
|
}
|
|
}
|