mirror of https://github.com/rm-dr/daisy
Fixed unit conversion
parent
7560b7a931
commit
5de314e11c
|
@ -94,14 +94,12 @@ impl Quantity {
|
||||||
|
|
||||||
|
|
||||||
pub fn convert_to(self, other: Quantity) -> Option<Quantity> {
|
pub fn convert_to(self, other: Quantity) -> Option<Quantity> {
|
||||||
|
if !self.unit.compatible_with(&other.unit) { return None; }
|
||||||
|
|
||||||
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();
|
||||||
let r = self * fa / fb;
|
|
||||||
|
|
||||||
// If this didn't work, units are incompatible
|
return Some(self * fa / fb)
|
||||||
if r.unit != other.unit { return None; };
|
|
||||||
|
|
||||||
return Some(r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +165,33 @@ impl Quantity {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Quantity {
|
||||||
|
pub fn mul_no_convert(self, other: Self) -> Self {
|
||||||
|
Quantity {
|
||||||
|
scalar: self.scalar * other.scalar,
|
||||||
|
unit: self.unit * other.unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_assign_no_convert(&mut self, other: Self) {
|
||||||
|
self.scalar *= other.scalar;
|
||||||
|
self.unit *= other.unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div_no_convert(self, other: Self) -> Self {
|
||||||
|
Quantity {
|
||||||
|
scalar: self.scalar / other.scalar,
|
||||||
|
unit: self.unit / other.unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div_assign_no_convert(&mut self, other: Self) {
|
||||||
|
self.scalar *= other.scalar;
|
||||||
|
self.unit *= other.unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Neg for Quantity where {
|
impl Neg for Quantity where {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
@ -182,10 +207,10 @@ impl Add for Quantity {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self::Output {
|
fn add(self, other: Self) -> Self::Output {
|
||||||
if self.unit != other.unit { panic!() }
|
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if !o.unit.prefixes_match(&self.unit) {
|
if self.unit != o.unit {
|
||||||
o = o.convert_to(self.clone()).unwrap();
|
o = o.convert_to(self.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,10 +223,10 @@ impl Add for Quantity {
|
||||||
|
|
||||||
impl AddAssign for Quantity where {
|
impl AddAssign for Quantity where {
|
||||||
fn add_assign(&mut self, other: Self) {
|
fn add_assign(&mut self, other: Self) {
|
||||||
if self.unit != other.unit { panic!() }
|
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if !o.unit.prefixes_match(&self.unit) {
|
if self.unit != o.unit {
|
||||||
o = o.convert_to(self.clone()).unwrap();
|
o = o.convert_to(self.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,10 +238,10 @@ impl Sub for Quantity {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
if self.unit != other.unit { panic!() }
|
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if !o.unit.prefixes_match(&self.unit) {
|
if self.unit != o.unit {
|
||||||
o = o.convert_to(self.clone()).unwrap();
|
o = o.convert_to(self.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,10 +254,10 @@ impl Sub for Quantity {
|
||||||
|
|
||||||
impl SubAssign for Quantity where {
|
impl SubAssign for Quantity where {
|
||||||
fn sub_assign(&mut self, other: Self) {
|
fn sub_assign(&mut self, other: Self) {
|
||||||
if self.unit != other.unit { panic!() }
|
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||||
|
|
||||||
let mut o = other;
|
let mut o = other;
|
||||||
if !o.unit.prefixes_match(&self.unit) {
|
if self.unit != o.unit {
|
||||||
o = o.convert_to(self.clone()).unwrap();
|
o = o.convert_to(self.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,26 +265,38 @@ impl SubAssign for Quantity where {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Mul for Quantity {
|
impl Mul for Quantity {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
fn mul(self, other: Self) -> Self::Output {
|
||||||
|
|
||||||
let f = self.unit.match_prefix_factor(&other.unit);
|
let mut o = other;
|
||||||
|
if self.unit != o.unit {
|
||||||
|
if self.unit.compatible_with(&o.unit) {
|
||||||
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Quantity {
|
Quantity {
|
||||||
scalar: self.scalar * other.scalar * f.scalar,
|
scalar: self.scalar * o.scalar,
|
||||||
unit: self.unit * other.unit * f.unit,
|
unit: self.unit * o.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 f = self.unit.match_prefix_factor(&other.unit);
|
|
||||||
|
|
||||||
self.scalar *= other.scalar * f.scalar;
|
let mut o = other;
|
||||||
self.unit *= other.unit * f.unit;
|
if self.unit != o.unit {
|
||||||
|
if o.unit.compatible_with(&self.unit) {
|
||||||
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scalar *= o.scalar;
|
||||||
|
self.unit *= o.unit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,17 +304,33 @@ impl Div for Quantity {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn div(self, other: Self) -> Self::Output {
|
fn div(self, other: Self) -> Self::Output {
|
||||||
|
|
||||||
|
let mut o = other;
|
||||||
|
if self.unit != o.unit {
|
||||||
|
if self.unit.compatible_with(&o.unit) {
|
||||||
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Quantity {
|
Quantity {
|
||||||
scalar: self.scalar / other.scalar,
|
scalar: self.scalar / o.scalar,
|
||||||
unit: self.unit / other.unit
|
unit: self.unit / o.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DivAssign for Quantity where {
|
impl DivAssign for Quantity where {
|
||||||
fn div_assign(&mut self, other: Self) {
|
fn div_assign(&mut self, other: Self) {
|
||||||
self.scalar /= other.scalar;
|
|
||||||
self.unit /= other.unit;
|
let mut o = other;
|
||||||
|
if self.unit != o.unit {
|
||||||
|
if self.unit.compatible_with(&o.unit) {
|
||||||
|
o = o.convert_to(self.clone()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scalar /= o.scalar;
|
||||||
|
self.unit /= o.unit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::quantity::Scalar;
|
use crate::quantity::Scalar;
|
||||||
use crate::quantity::Quantity;
|
use crate::quantity::Quantity;
|
||||||
|
@ -8,26 +8,15 @@ use super::Unit;
|
||||||
use super::unit_db;
|
use super::unit_db;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct FreeUnit {
|
pub struct FreeUnit {
|
||||||
pub (in super) base: UnitBase,
|
pub (in super) base: UnitBase,
|
||||||
pub (in super) prefix: Prefix
|
pub (in super) prefix: Prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for FreeUnit {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.base.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for FreeUnit {}
|
|
||||||
impl PartialEq for FreeUnit {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.base.eq(&other.base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
macro_rules! unpack_base_factor {
|
macro_rules! unpack_base_factor {
|
||||||
(
|
(
|
||||||
|
@ -83,11 +72,6 @@ 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 }
|
||||||
|
|
||||||
pub fn same_with_prefix(&self, other: &FreeUnit) -> bool {
|
|
||||||
self.base.eq(&other.base) && self.prefix.eq(&other.prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -96,7 +80,7 @@ impl FreeUnit {
|
||||||
let mut p = self.prefix.to_ratio();
|
let mut p = self.prefix.to_ratio();
|
||||||
p.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
|
p.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
|
||||||
p.insert_unit(FreeUnit::from_base_prefix(self.base, self.prefix), Scalar::new_rational(-1f64).unwrap());
|
p.insert_unit(FreeUnit::from_base_prefix(self.base, self.prefix), Scalar::new_rational(-1f64).unwrap());
|
||||||
q *= p;
|
q.mul_assign_no_convert(p);
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,46 +97,11 @@ impl Unit {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prefixes_match(&self, other: &Unit) -> bool {
|
pub fn compatible_with(&self, other: &Unit) -> bool {
|
||||||
let v = self.get_val();
|
let s = self.clone() * self.to_base_factor().unit;
|
||||||
for (u, _) in other.get_val() {
|
let o = other.clone() * other.to_base_factor().unit;
|
||||||
let k = v.get_key_value(u);
|
return o == s;
|
||||||
|
|
||||||
if k.is_some() {
|
|
||||||
let k = k.unwrap().0;
|
|
||||||
if !u.same_with_prefix(k) { return false; }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_prefix_factor(&self, other: &Unit) -> Quantity {
|
|
||||||
let mut f = Quantity::new_rational(1f64).unwrap();
|
|
||||||
|
|
||||||
let v = self.get_val();
|
|
||||||
for (ou, op) in other.get_val() {
|
|
||||||
let k = v.get_key_value(ou);
|
|
||||||
|
|
||||||
if k.is_some() {
|
|
||||||
let (su, _) = k.unwrap();
|
|
||||||
|
|
||||||
// Conversion factor ou -> basic
|
|
||||||
let mut p = ou.prefix.to_ratio();
|
|
||||||
p.insert_unit(FreeUnit::from_base(ou.base), Scalar::new_rational(1f64).unwrap());
|
|
||||||
p.insert_unit(FreeUnit::from_base_prefix(ou.base, ou.prefix), Scalar::new_rational(-1f64).unwrap());
|
|
||||||
|
|
||||||
// Conversion factor su -> basic
|
|
||||||
let mut q = su.prefix.to_ratio();
|
|
||||||
q.insert_unit(FreeUnit::from_base(su.base), Scalar::new_rational(1f64).unwrap());
|
|
||||||
q.insert_unit(FreeUnit::from_base_prefix(su.base, su.prefix), Scalar::new_rational(-1f64).unwrap());
|
|
||||||
|
|
||||||
f = f * (p / q).pow(Quantity::from_scalar(op.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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();
|
||||||
|
@ -165,15 +130,13 @@ impl Unit {
|
||||||
|
|
||||||
for (u, p) in self.get_val().iter() {
|
for (u, p) in self.get_val().iter() {
|
||||||
let b = u.to_base_factor();
|
let b = u.to_base_factor();
|
||||||
q *= b.pow(Quantity::from_scalar(p.clone()));
|
q.mul_assign_no_convert(b.pow(Quantity::from_scalar(p.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Unit {
|
impl Unit {
|
||||||
pub fn from_string(s: &str) -> Option<Quantity> {
|
pub fn from_string(s: &str) -> Option<Quantity> {
|
||||||
macro_rules! unpack_fromstring {
|
macro_rules! unpack_fromstring {
|
||||||
|
@ -220,8 +183,6 @@ impl Unit {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl PartialEq for Unit {
|
impl PartialEq for Unit {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
let v = self.get_val();
|
let v = self.get_val();
|
||||||
|
@ -231,6 +192,15 @@ impl PartialEq for Unit {
|
||||||
None => { return false; }
|
None => { return false; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let v = other.get_val();
|
||||||
|
for (u, p) in self.get_val() {
|
||||||
|
match v.get(u) {
|
||||||
|
Some(i) => { if i != p { return false; } },
|
||||||
|
None => { return false; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,7 +383,7 @@ impl Operator{
|
||||||
let j = args[i].as_number();
|
let j = args[i].as_number();
|
||||||
if let Token::Number(v) = j {
|
if let Token::Number(v) = j {
|
||||||
|
|
||||||
if sum.unit() != v.unit() {
|
if !sum.unit.compatible_with(&v.unit) {
|
||||||
return Err(EvalError::IncompatibleUnit);
|
return Err(EvalError::IncompatibleUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ impl Operator{
|
||||||
if let Token::Number(va) = a {
|
if let Token::Number(va) = a {
|
||||||
if let Token::Number(vb) = b {
|
if let Token::Number(vb) = b {
|
||||||
|
|
||||||
if va.unit() != vb.unit() {
|
if !vb.unitless() {
|
||||||
return Err(EvalError::IncompatibleUnit);
|
return Err(EvalError::IncompatibleUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue