abey79 / vsvg

Fast and portable tools for plotter users
http://whisk.rs
MIT License
107 stars 12 forks source link

Improve `Unit` and introduce `Length` #88

Closed abey79 closed 8 months ago

abey79 commented 8 months ago

BREAKING: this change the semantics of the float/Unit multiplication and remove the division.


From the docstrings:

Unit

Convert between units:

let f = 2.54f32;
assert_eq!(Unit::In.convert_from(&Unit::Cm, f), 1.0f32);
assert_eq!(Unit::Cm.convert_to(&Unit::In, f), 1.0f32);

Create a [Length] via multiplication:

assert_eq!(30.0f32 * Unit::Cm, Length { value: 30.0, unit: Unit::Cm });
assert_eq!(Unit::Mm * 25.0f64, Length { value: 25.0, unit: Unit::Mm });

Convert to/from strings:

assert_eq!(Unit::Cm.to_str(), "cm");
assert_eq!(Unit::Yd.to_str(), "yd");

assert_eq!(Unit::try_from("m"), Ok(Unit::M));
assert_eq!(Unit::try_from("kilometre"), Ok(Unit::Km));

Length

A [Length] can be created with [Length::new], by multiplying a float with a [Unit], or using the shorthand constructors:

assert_eq!(Length::new(0.0356, Unit::Cm), 0.0356 * Unit::Cm);
assert_eq!(Length::new(0.0356, Unit::Cm), Length::cm(0.0356));

All float conversion assume the default [Unit] of [Unit::Px]:

assert_eq!(Length::from(96.0), Length::new(96., Unit::Px));
assert_eq!(f64::from(1.0 * Unit::In), 96.0);

The usual arithmetic operations are supported.

Note: Floats are always considered as [Unit::Px]. When adding or subtracting two [Length]s, the result will have the [Unit] of the left-hand side.

// Negation is supported.
assert_eq!(-Length::new(1.0, Unit::In), -1.0 * Unit::In);

// The result has the unit of the left-hand side.
assert_eq!(1.0 * Unit::In + 2.54 * Unit::Cm, 2.0 * Unit::In);
assert_eq!(5.08 * Unit::Cm - 1.0 * Unit::In, 2.54 * Unit::Cm);

// Floats are considered pixels.
assert_eq!(1.0 * Unit::In + 96.0, 2.0 * Unit::In);
assert_eq!(96.0 + 1.0 * Unit::In , 2.0 * Unit::In);
assert_eq!(2.0 * Unit::In - 96.0, 1.0 * Unit::In);
assert_eq!(96.0 - 0.5 * Unit::In, 0.5 * Unit::In);

// Multiplication and division by floats is supported.
// Note: dividing by a `Length` is not supported.
assert_eq!((1.0 * Unit::In) * 2.0, 2.0 * Unit::In);
assert_eq!(2.0 * (1.0 * Unit::In), 2.0 * Unit::In);
assert_eq!((1.0 * Unit::In) / 2.0, 0.5 * Unit::In);

[Length] implements [From] for [Unit], so you can use [Unit] as a shorthand:

assert_eq!(Length::from(Unit::In), Length::new(1., Unit::In));

A [Length] with a different [Unit] can be converted using [Length::convert_to]:

let l = Length::new(2.54, Unit::Cm);
assert_eq!(l.convert_to(Unit::In), 1.0 * Unit::In);

[Length] delegates [Display] to [f64], so it supports the standard float formatting syntax:

let l = Length::new(0.0356, vsvg::Unit::Cm);
assert_eq!(format!("{l:.2}"), "0.04cm");