mirror of https://github.com/rm-dr/daisy
Fixed compound unit conversion
parent
e816cea236
commit
91b2361f28
|
@ -22,7 +22,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daisy"
|
name = "daisy"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"rug",
|
"rug",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "daisy"
|
name = "daisy"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -99,7 +99,7 @@ impl Quantity {
|
||||||
let fa = self.unit.to_base_factor();
|
let fa = self.unit.to_base_factor();
|
||||||
let fb = other.unit.to_base_factor();
|
let fb = other.unit.to_base_factor();
|
||||||
|
|
||||||
return Some(self * fa / fb)
|
return Some(self.mul_no_convert(fa).div_no_convert(fb))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,10 +271,16 @@ impl Mul for Quantity {
|
||||||
|
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
fn mul(self, other: Self) -> Self::Output {
|
||||||
|
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if self.unit != o.unit {
|
if self.unit != o.unit {
|
||||||
if self.unit.compatible_with(&o.unit) {
|
if o.unit.compatible_with(&self.unit) {
|
||||||
o = o.convert_to(self.clone()).unwrap()
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
} else {
|
||||||
|
let cf = self.unit.common_factor(&o.unit);
|
||||||
|
if let Some(f) = cf {
|
||||||
|
o = o.convert_to(f).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,10 +294,16 @@ impl Mul for Quantity {
|
||||||
impl MulAssign for Quantity where {
|
impl MulAssign for Quantity where {
|
||||||
fn mul_assign(&mut self, other: Self) {
|
fn mul_assign(&mut self, other: Self) {
|
||||||
|
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if self.unit != o.unit {
|
if self.unit != o.unit {
|
||||||
if o.unit.compatible_with(&self.unit) {
|
if o.unit.compatible_with(&self.unit) {
|
||||||
o = o.convert_to(self.clone()).unwrap()
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
} else {
|
||||||
|
let cf = self.unit.common_factor(&o.unit);
|
||||||
|
if let Some(f) = cf {
|
||||||
|
o = o.convert_to(f).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,8 +319,13 @@ impl Div for Quantity {
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if self.unit != o.unit {
|
if self.unit != o.unit {
|
||||||
if self.unit.compatible_with(&o.unit) {
|
if o.unit.compatible_with(&self.unit) {
|
||||||
o = o.convert_to(self.clone()).unwrap()
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
} else {
|
||||||
|
let cf = self.unit.common_factor(&o.unit);
|
||||||
|
if let Some(f) = cf {
|
||||||
|
o = o.convert_to(f).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +341,13 @@ impl DivAssign for Quantity where {
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if self.unit != o.unit {
|
if self.unit != o.unit {
|
||||||
if self.unit.compatible_with(&o.unit) {
|
if o.unit.compatible_with(&self.unit) {
|
||||||
o = o.convert_to(self.clone()).unwrap()
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
} else {
|
||||||
|
let cf = self.unit.common_factor(&o.unit);
|
||||||
|
if let Some(f) = cf {
|
||||||
|
o = o.convert_to(f).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ use super::Unit;
|
||||||
use super::unit_db;
|
use super::unit_db;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Hash)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[derive(Hash)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct FreeUnit {
|
pub struct FreeUnit {
|
||||||
|
@ -18,6 +18,25 @@ pub struct FreeUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! unpack_string {
|
||||||
|
(
|
||||||
|
$u:expr, $s:expr,
|
||||||
|
$( $_:expr ),*
|
||||||
|
) => { $s };
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for FreeUnit {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
|
||||||
|
let s = unit_db!(self.base, unpack_string);
|
||||||
|
let p = self.prefix.to_string();
|
||||||
|
|
||||||
|
format!("{p}{s}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
macro_rules! unpack_base_factor {
|
macro_rules! unpack_base_factor {
|
||||||
(
|
(
|
||||||
$unit:expr,
|
$unit:expr,
|
||||||
|
@ -90,6 +109,8 @@ impl FreeUnit {
|
||||||
pub fn set_prefix(&mut self, prefix: Prefix) { self.prefix = prefix; }
|
pub fn set_prefix(&mut self, prefix: Prefix) { self.prefix = prefix; }
|
||||||
pub fn get_prefix(&self) -> Prefix { self.prefix }
|
pub fn get_prefix(&self) -> Prefix { self.prefix }
|
||||||
|
|
||||||
|
/// Returns a quantity q, so that self * q
|
||||||
|
/// gives a quantity in base units.
|
||||||
pub fn to_base_factor(&self) -> Quantity {
|
pub fn to_base_factor(&self) -> Quantity {
|
||||||
|
|
||||||
let q = unit_db!(self.base, unpack_base_factor);
|
let q = unit_db!(self.base, unpack_base_factor);
|
||||||
|
@ -102,23 +123,17 @@ impl FreeUnit {
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Get this unit in terms of base units
|
||||||
|
pub fn get_base(&self) -> Quantity {
|
||||||
|
let q = unit_db!(self.base, unpack_base_factor);
|
||||||
|
let mut q = q.unwrap_or(Quantity::new_rational_from_string("1").unwrap());
|
||||||
|
|
||||||
|
// Don't divide by self
|
||||||
|
q.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
|
||||||
|
|
||||||
macro_rules! unpack_string {
|
return q;
|
||||||
(
|
|
||||||
$u:expr, $s:expr,
|
|
||||||
$( $_:expr ),*
|
|
||||||
) => { $s };
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToString for FreeUnit {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
|
|
||||||
let s = unit_db!(self.base, unpack_string);
|
|
||||||
let p = self.prefix.to_string();
|
|
||||||
|
|
||||||
format!("{p}{s}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -97,12 +97,60 @@ impl Unit {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// True if base units are the same
|
||||||
pub fn compatible_with(&self, other: &Unit) -> bool {
|
pub fn compatible_with(&self, other: &Unit) -> bool {
|
||||||
let s = self.clone() * self.to_base_factor().unit;
|
let s = self.clone() * self.to_base_factor().unit;
|
||||||
let o = other.clone() * other.to_base_factor().unit;
|
let o = other.clone() * other.to_base_factor().unit;
|
||||||
|
|
||||||
return o == s;
|
return o == s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// True if these two units have a common factor
|
||||||
|
pub fn common_factor(&self, other: &Unit) -> Option<Quantity> {
|
||||||
|
|
||||||
|
if self.unitless() || other.unitless() { return None; }
|
||||||
|
|
||||||
|
|
||||||
|
let mut failed = false;
|
||||||
|
|
||||||
|
// What to convert `other` to before multiplying
|
||||||
|
let mut factor = Quantity::new_rational_from_string("1").unwrap();
|
||||||
|
let mut flag;
|
||||||
|
for (us, _) in self.get_val() {
|
||||||
|
flag = false;
|
||||||
|
for (uo, po) in other.get_val() {
|
||||||
|
if {
|
||||||
|
us.get_base().unit.compatible_with(&uo.get_base().unit)
|
||||||
|
} {
|
||||||
|
factor.insert_unit(us.clone(), po.clone());
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !flag { failed = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failed { return Some(factor);}
|
||||||
|
|
||||||
|
|
||||||
|
let mut factor = Quantity::new_rational_from_string("1").unwrap();
|
||||||
|
for (uo, po) in other.get_val() {
|
||||||
|
flag = false;
|
||||||
|
for (us, _) in self.get_val() {
|
||||||
|
if {
|
||||||
|
us.get_base().unit.compatible_with(&uo.get_base().unit)
|
||||||
|
} {
|
||||||
|
factor.insert_unit(us.clone(), po.clone());
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !flag { return None; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(factor);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, u: FreeUnit, p: Scalar) {
|
pub fn insert(&mut self, u: FreeUnit, p: Scalar) {
|
||||||
let v = self.get_val_mut();
|
let v = self.get_val_mut();
|
||||||
match v.get_mut(&u) {
|
match v.get_mut(&u) {
|
||||||
|
|
|
@ -208,4 +208,5 @@ fn complex_units() {
|
||||||
good_expr("3280.8 ft", "1km to ft");
|
good_expr("3280.8 ft", "1km to ft");
|
||||||
good_expr("62.137 mi/h", "100 km/h to mph");
|
good_expr("62.137 mi/h", "100 km/h to mph");
|
||||||
good_expr("20 mi", "10 mph * 2 hours");
|
good_expr("20 mi", "10 mph * 2 hours");
|
||||||
|
good_expr("120 m", "1 (m/s) * 2 min");
|
||||||
}
|
}
|
Loading…
Reference in New Issue