mirror of https://github.com/rm-dr/daisy
Added unit conversion prototype
parent
7ecdfae6fc
commit
600c5f76cc
|
@ -13,7 +13,6 @@ use crate::parser::treeify::treeify;
|
||||||
use crate::parser::find_subs::find_subs;
|
use crate::parser::find_subs::find_subs;
|
||||||
|
|
||||||
use crate::quantity::Quantity;
|
use crate::quantity::Quantity;
|
||||||
use crate::quantity::Unit;
|
|
||||||
|
|
||||||
use crate::tokens::Token;
|
use crate::tokens::Token;
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,13 @@ impl Quantity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_scalar(s: Scalar) -> Quantity {
|
||||||
|
return Quantity{
|
||||||
|
v: s,
|
||||||
|
u: Unit::new()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_unit(&mut self, ui: BaseUnit, pi: Scalar) { self.u.insert(ui, pi) }
|
pub fn insert_unit(&mut self, ui: BaseUnit, pi: Scalar) { self.u.insert(ui, pi) }
|
||||||
pub fn set_unit(&mut self, u: Unit) { self.u = u; }
|
pub fn set_unit(&mut self, u: Unit) { self.u = u; }
|
||||||
|
|
||||||
|
@ -96,6 +103,9 @@ impl Quantity {
|
||||||
"mol" => Some(BaseUnit::Mole),
|
"mol" => Some(BaseUnit::Mole),
|
||||||
"c" => Some(BaseUnit::Candela),
|
"c" => Some(BaseUnit::Candela),
|
||||||
"ft" => Some(BaseUnit::Foot),
|
"ft" => Some(BaseUnit::Foot),
|
||||||
|
"mile" => Some(BaseUnit::Mile),
|
||||||
|
"hour" => Some(BaseUnit::Hour),
|
||||||
|
"min" => Some(BaseUnit::Minute),
|
||||||
_ => { None }
|
_ => { None }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,6 +122,17 @@ impl Quantity {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn convert_to(self, other: Quantity) -> Option<Quantity> {
|
||||||
|
let fa = self.u.to_base_factor();
|
||||||
|
let fb = other.u.to_base_factor();
|
||||||
|
let r = self * fa / fb;
|
||||||
|
|
||||||
|
// If this didn't work, units are incompatible
|
||||||
|
if r.u != other.u { return None; };
|
||||||
|
|
||||||
|
return Some(r);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,30 +21,59 @@ pub enum BaseUnit {
|
||||||
Candela,
|
Candela,
|
||||||
|
|
||||||
Foot,
|
Foot,
|
||||||
|
Mile,
|
||||||
|
Minute,
|
||||||
|
Hour
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseUnit {
|
impl BaseUnit {
|
||||||
pub fn is_base(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
BaseUnit::Second
|
|
||||||
| BaseUnit::Meter
|
|
||||||
| BaseUnit::Kilogram
|
|
||||||
| BaseUnit::Ampere
|
|
||||||
| BaseUnit::Kelvin
|
|
||||||
| BaseUnit::Mole
|
|
||||||
| BaseUnit::Candela
|
|
||||||
=> true,
|
|
||||||
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_base(&self) -> Option<Quantity> {
|
pub fn to_base(&self) -> Option<Quantity> {
|
||||||
match self {
|
match self {
|
||||||
|
|
||||||
|
// Returns the unit we need to multiply by to get a base
|
||||||
|
// unit, or `None` if this is already a base unit.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// 1 foot = 0.3048 m,
|
||||||
|
// so 1 ft * (0.3084 m / ft) will give meters.
|
||||||
|
//
|
||||||
|
// The units here MUST be in terms of base units.
|
||||||
|
// If they aren't, things will break.
|
||||||
BaseUnit::Foot => Some(Quantity {
|
BaseUnit::Foot => Some(Quantity {
|
||||||
v: Scalar::new_float_from_string("0.3048").unwrap(),
|
v: Scalar::new_float_from_string("0.3048").unwrap(),
|
||||||
u: Unit::from_array(&[(BaseUnit::Meter, Scalar::new_rational(1f64).unwrap())])
|
u: Unit::from_array(&[
|
||||||
|
(BaseUnit::Meter, Scalar::new_rational(1f64).unwrap()),
|
||||||
|
(BaseUnit::Foot, Scalar::new_rational(-1f64).unwrap())
|
||||||
|
])
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
BaseUnit::Mile => Some(Quantity {
|
||||||
|
v: Scalar::new_float_from_string("1609").unwrap(),
|
||||||
|
u: Unit::from_array(&[
|
||||||
|
(BaseUnit::Meter, Scalar::new_rational(1f64).unwrap()),
|
||||||
|
(BaseUnit::Mile, Scalar::new_rational(-1f64).unwrap())
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
BaseUnit::Minute => Some(Quantity {
|
||||||
|
v: Scalar::new_rational_from_string("60").unwrap(),
|
||||||
|
u: Unit::from_array(&[
|
||||||
|
(BaseUnit::Second, Scalar::new_rational(1f64).unwrap()),
|
||||||
|
(BaseUnit::Minute, Scalar::new_rational(-1f64).unwrap())
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
BaseUnit::Hour => Some(Quantity {
|
||||||
|
v: Scalar::new_rational_from_string("3600").unwrap(),
|
||||||
|
u: Unit::from_array(&[
|
||||||
|
(BaseUnit::Second, Scalar::new_rational(1f64).unwrap()),
|
||||||
|
(BaseUnit::Hour, Scalar::new_rational(-1f64).unwrap())
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Only base units should be missing a conversion factor.
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +117,9 @@ impl ToString for Unit {
|
||||||
BaseUnit::Candela => "c",
|
BaseUnit::Candela => "c",
|
||||||
|
|
||||||
BaseUnit::Foot => "ft",
|
BaseUnit::Foot => "ft",
|
||||||
|
BaseUnit::Mile => "mile",
|
||||||
|
BaseUnit::Hour => "hour",
|
||||||
|
BaseUnit::Minute => "min",
|
||||||
};
|
};
|
||||||
|
|
||||||
if *p == Scalar::new_rational(1f64).unwrap() {
|
if *p == Scalar::new_rational(1f64).unwrap() {
|
||||||
|
@ -158,6 +190,19 @@ impl Unit {
|
||||||
};
|
};
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_base_factor(&self) -> Quantity {
|
||||||
|
let mut q = Quantity::new_rational(1f64).unwrap();
|
||||||
|
|
||||||
|
for (u, p) in self.val.iter() {
|
||||||
|
let b = u.to_base();
|
||||||
|
if b.is_some() {
|
||||||
|
q *= b.unwrap().pow(Quantity::from_scalar(p.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::quantity::Quantity;
|
||||||
#[repr(usize)]
|
#[repr(usize)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
ModuloLong = 0, // Mod invoked with "mod"
|
ModuloLong = 0, // Mod invoked with "mod"
|
||||||
|
UnitConvert,
|
||||||
Subtract,
|
Subtract,
|
||||||
Add,
|
Add,
|
||||||
Divide,
|
Divide,
|
||||||
|
@ -99,6 +100,14 @@ impl Operator {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Operator::UnitConvert => {
|
||||||
|
return format!(
|
||||||
|
"{} to {}",
|
||||||
|
self.add_parens_to_arg(&args[0]),
|
||||||
|
self.add_parens_to_arg(&args[1])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
Operator::Modulo => {
|
Operator::Modulo => {
|
||||||
return format!(
|
return format!(
|
||||||
"{} % {}",
|
"{} % {}",
|
||||||
|
@ -211,6 +220,7 @@ impl Operator {
|
||||||
"i*" => {Some( Operator::ImplicitMultiply )},
|
"i*" => {Some( Operator::ImplicitMultiply )},
|
||||||
"%" => {Some( Operator::Modulo )},
|
"%" => {Some( Operator::Modulo )},
|
||||||
"mod" => {Some( Operator::ModuloLong )},
|
"mod" => {Some( Operator::ModuloLong )},
|
||||||
|
"to" => {Some( Operator::UnitConvert )},
|
||||||
"^"|"**" => {Some( Operator::Power )},
|
"^"|"**" => {Some( Operator::Power )},
|
||||||
"!" => {Some( Operator::Factorial )},
|
"!" => {Some( Operator::Factorial )},
|
||||||
"sqrt"|"rt"|"√" => {Some( Operator::Sqrt )},
|
"sqrt"|"rt"|"√" => {Some( Operator::Sqrt )},
|
||||||
|
@ -327,6 +337,7 @@ impl Operator {
|
||||||
| Operator::Modulo
|
| Operator::Modulo
|
||||||
| Operator::Power
|
| Operator::Power
|
||||||
| Operator::ModuloLong
|
| Operator::ModuloLong
|
||||||
|
| Operator::UnitConvert
|
||||||
=> { Token::Operator(self, args) },
|
=> { Token::Operator(self, args) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,6 +431,23 @@ impl Operator{
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Operator::UnitConvert
|
||||||
|
=> {
|
||||||
|
if args.len() != 2 {panic!()};
|
||||||
|
let a = args[0].as_number();
|
||||||
|
let b = args[1].as_number();
|
||||||
|
|
||||||
|
if let Token::Number(va) = a {
|
||||||
|
if let Token::Number(vb) = b {
|
||||||
|
let n = va.convert_to(vb);
|
||||||
|
if n.is_none() {
|
||||||
|
return Err(EvalError::IncompatibleUnit);
|
||||||
|
}
|
||||||
|
return Ok(Token::Number(n.unwrap()));
|
||||||
|
} else { panic!(); }
|
||||||
|
} else { panic!(); }
|
||||||
|
},
|
||||||
|
|
||||||
Operator::Power => {
|
Operator::Power => {
|
||||||
if args.len() != 2 {panic!()};
|
if args.len() != 2 {panic!()};
|
||||||
let a = args[0].as_number();
|
let a = args[0].as_number();
|
||||||
|
|
Loading…
Reference in New Issue