///|
fn unit_kind(value : Value?) -> UnitKind {
match value {
Some(Enumeration(name)) =>
match name.to_upper() {
"LENGTHUNIT" => Length
"AREAUNIT" => Area
"VOLUMEUNIT" => Volume
"MASSUNIT" => Mass
"TIMEUNIT" => Time
"PLANEANGLEUNIT" => PlaneAngle
_ => UnknownUnit
}
Some(Typed(name~, value~)) => {
ignore(name)
unit_kind(Some(value))
}
_ => UnknownUnit
}
}
///|
fn prefix_scale(value : Value?) -> (String?, Double) {
match value {
Some(Enumeration(name)) =>
match name.to_upper() {
"EXA" => (Some(name), 1.0e18)
"PETA" => (Some(name), 1.0e15)
"TERA" => (Some(name), 1.0e12)
"GIGA" => (Some(name), 1.0e9)
"MEGA" => (Some(name), 1.0e6)
"KILO" => (Some(name), 1.0e3)
"HECTO" => (Some(name), 1.0e2)
"DECA" => (Some(name), 1.0e1)
"DECI" => (Some(name), 1.0e-1)
"CENTI" => (Some(name), 1.0e-2)
"MILLI" => (Some(name), 1.0e-3)
"MICRO" => (Some(name), 1.0e-6)
"NANO" => (Some(name), 1.0e-9)
_ => (Some(name), 1.0)
}
_ => (None, 1.0)
}
}
///|
fn si_base_scale(name : String, kind : UnitKind) -> Double {
match (kind, name.to_upper()) {
(Length, "METRE") => 1.0
(Area, "SQUARE_METRE") => 1.0
(Volume, "CUBIC_METRE") => 1.0
(Mass, "GRAM") => 1.0e-3
(Mass, "KILOGRAM") => 1.0
(Time, "SECOND") => 1.0
(PlaneAngle, "RADIAN") => 1.0
(PlaneAngle, "DEGREE") => 0.017453292519943295
_ => 1.0
}
}
///|
fn decode_si_unit(entity : Entity) -> UnitScale {
let kind = unit_kind(entity_value(entity, 1))
let prefix_value = entity_value(entity, 2)
let (prefix, prefix_factor) = prefix_scale(prefix_value)
let name = optional_string_argument(entity, 3).unwrap_or("UNKNOWN")
{ kind, name, prefix, to_si: prefix_factor * si_base_scale(name, kind) }
}
///|
pub fn unit_system(index : ModelIndex) -> UnitSystem {
let units = index
.ids_named("IFCSIUNIT")
.fold(init=Array::new(), (result, id) => {
match index.entity(id) {
Some(entity) => {
result.push(decode_si_unit(entity))
result
}
None => result
}
})
UnitSystem::{ units, }
}
///|
pub fn UnitSystem::find(self : UnitSystem, kind : UnitKind) -> UnitScale? {
for unit in self.units {
if unit.kind == kind {
return Some(unit)
}
}
None
}
///|
pub fn UnitSystem::scale(self : UnitSystem, kind : UnitKind) -> Double {
match self.find(kind) {
Some(unit) => unit.to_si
None => 1.0
}
}
///|
pub fn UnitSystem::to_si(
self : UnitSystem,
kind : UnitKind,
value : Double,
) -> Double {
value * self.scale(kind)
}
///|
pub fn UnitSystem::from_si(
self : UnitSystem,
kind : UnitKind,
value : Double,
) -> Double {
value / self.scale(kind)
}
///|
pub fn UnitSystem::length_to_meters(
self : UnitSystem,
value : Double,
) -> Double {
self.to_si(Length, value)
}
///|
pub fn UnitSystem::meters_to_length(
self : UnitSystem,
value : Double,
) -> Double {
self.from_si(Length, value)
}
///|
pub fn UnitSystem::area_to_square_meters(
self : UnitSystem,
value : Double,
) -> Double {
self.to_si(Area, value)
}
///|
pub fn UnitSystem::volume_to_cubic_meters(
self : UnitSystem,
value : Double,
) -> Double {
self.to_si(Volume, value)
}