From 26ea443a33943df11c9c3d0b6a0190871986043e Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Wed, 16 Oct 2019 16:44:34 +0200 Subject: [PATCH] Add support for unit scaling between spaces --- src/database/space/axis.rs | 77 +++++++++++++++++++++++++++++++++----- src/json/model.rs | 4 +- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/database/space/axis.rs b/src/database/space/axis.rs index 28d4a23..dc2d262 100644 --- a/src/database/space/axis.rs +++ b/src/database/space/axis.rs @@ -55,27 +55,79 @@ impl Graduation { } } +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[allow(non_camel_case_types)] +pub enum UnitSI { + // Partial list, which is tailored to the use case needs. Prevents possible + // confusions between Mm and mm, for example. + m, + dm, + cm, + mm, + um, + nm, + pm, +} + +impl UnitSI { + pub fn factor(&self) -> f64 { + match self { + UnitSI::m => 1.0_E0, + UnitSI::dm => 1.0_E-1, + UnitSI::cm => 1.0_E-2, + UnitSI::mm => 1.0_E-3, + UnitSI::um => 1.0_E-6, + UnitSI::nm => 1.0_E-9, + UnitSI::pm => 1.0_E-12, + } + } + + pub fn to_str(&self) -> &str { + match self { + UnitSI::m => "m", + UnitSI::dm => "dm", + UnitSI::cm => "cm", + UnitSI::mm => "mm", + UnitSI::um => "um", + UnitSI::nm => "nm", + UnitSI::pm => "pm", + } + } +} + +impl From<&str> for UnitSI { + fn from(name: &str) -> Self { + match name { + "m" => UnitSI::m, + "dm" => UnitSI::dm, + "cm" => UnitSI::cm, + "mm" => UnitSI::mm, + "um" => UnitSI::um, + "nm" => UnitSI::nm, + "pm" => UnitSI::pm, + _ => unimplemented!("Unknown unit '{}'", name), + } + } +} + // TODO: In the future this might become an Enum with AffineAxis, ArbitraryAxis, etc... #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct Axis { - measurement_unit: String, + measurement_unit: UnitSI, graduation: Graduation, // Coordinates in Universe, expressed in f64, and in the Universe number of dimensions. pub unit_vector: Position, } impl Axis { - pub fn new( - unit: S, + pub fn new( + unit: &str, unit_vector: Vec, set: NumberSet, minimum: f64, maximum: f64, steps: u64, - ) -> Result - where - S: Into, - { + ) -> Result { // Convert to Position, and ensure it is a unit vector. let unit_vector = Position::from(unit_vector).unit(); let graduation = Graduation::new(set, minimum, maximum, steps)?; @@ -87,8 +139,8 @@ impl Axis { }) } - pub fn measurement_unit(&self) -> &String { - &self.measurement_unit + pub fn measurement_unit(&self) -> String { + self.measurement_unit.to_str().into() } pub fn unit_vector(&self) -> &Position { @@ -106,6 +158,9 @@ impl Axis { let d = position.dot_product(&self.unit_vector); + // Apply Unit scaling + let d = d / self.measurement_unit.factor(); + // Ensure it is within allowed range: Upper bound. if d > max { return Err(format!("Encode: position out of bounds: {} >= {}", d, max)); @@ -122,6 +177,10 @@ impl Axis { // Convert a value on this axis to Universe coordinates, based from the origin of this axis. pub fn project_out(&self, coordinate: &Coordinate) -> Result { let d = self.decode(coordinate)?; + + // Apply Unit scaling + let d = d * self.measurement_unit.factor(); + Ok(self.unit_vector.clone() * d) } diff --git a/src/json/model.rs b/src/json/model.rs index 7484a1b..af6e54a 100644 --- a/src/json/model.rs +++ b/src/json/model.rs @@ -69,7 +69,7 @@ impl From for space::Axis { let g = axis.graduation; space::Axis::new( - axis.measurement_unit, + &axis.measurement_unit, axis.unit_vector, g.set.into(), g.minimum, @@ -83,7 +83,7 @@ impl From for space::Axis { impl From<&space::Axis> for Axis { fn from(axis: &space::Axis) -> Self { Axis { - measurement_unit: axis.measurement_unit().clone(), + measurement_unit: axis.measurement_unit(), graduation: axis.graduation().into(), unit_vector: axis.unit_vector().into(), }