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::quantity::Quantity;
|
||||
use crate::quantity::Unit;
|
||||
|
||||
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 set_unit(&mut self, u: Unit) { self.u = u; }
|
||||
|
||||
|
@ -96,6 +103,9 @@ impl Quantity {
|
|||
"mol" => Some(BaseUnit::Mole),
|
||||
"c" => Some(BaseUnit::Candela),
|
||||
"ft" => Some(BaseUnit::Foot),
|
||||
"mile" => Some(BaseUnit::Mile),
|
||||
"hour" => Some(BaseUnit::Hour),
|
||||
"min" => Some(BaseUnit::Minute),
|
||||
_ => { None }
|
||||
};
|
||||
|
||||
|
@ -112,6 +122,17 @@ impl Quantity {
|
|||
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,
|
||||
|
||||
Foot,
|
||||
Mile,
|
||||
Minute,
|
||||
Hour
|
||||
}
|
||||
|
||||
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> {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +117,9 @@ impl ToString for Unit {
|
|||
BaseUnit::Candela => "c",
|
||||
|
||||
BaseUnit::Foot => "ft",
|
||||
BaseUnit::Mile => "mile",
|
||||
BaseUnit::Hour => "hour",
|
||||
BaseUnit::Minute => "min",
|
||||
};
|
||||
|
||||
if *p == Scalar::new_rational(1f64).unwrap() {
|
||||
|
@ -158,6 +190,19 @@ impl Unit {
|
|||
};
|
||||
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)]
|
||||
pub enum Operator {
|
||||
ModuloLong = 0, // Mod invoked with "mod"
|
||||
UnitConvert,
|
||||
Subtract,
|
||||
Add,
|
||||
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 => {
|
||||
return format!(
|
||||
"{} % {}",
|
||||
|
@ -211,6 +220,7 @@ impl Operator {
|
|||
"i*" => {Some( Operator::ImplicitMultiply )},
|
||||
"%" => {Some( Operator::Modulo )},
|
||||
"mod" => {Some( Operator::ModuloLong )},
|
||||
"to" => {Some( Operator::UnitConvert )},
|
||||
"^"|"**" => {Some( Operator::Power )},
|
||||
"!" => {Some( Operator::Factorial )},
|
||||
"sqrt"|"rt"|"√" => {Some( Operator::Sqrt )},
|
||||
|
@ -327,6 +337,7 @@ impl Operator {
|
|||
| Operator::Modulo
|
||||
| Operator::Power
|
||||
| Operator::ModuloLong
|
||||
| Operator::UnitConvert
|
||||
=> { Token::Operator(self, args) },
|
||||
}
|
||||
}
|
||||
|
@ -420,6 +431,23 @@ impl Operator{
|
|||
} 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 => {
|
||||
if args.len() != 2 {panic!()};
|
||||
let a = args[0].as_number();
|
||||
|
|
Loading…
Reference in New Issue