848 lines
26 KiB
Rust
848 lines
26 KiB
Rust
/*
|
|
* unit_converter length_units.rs
|
|
* - definitions of length units
|
|
*
|
|
* Copyright (C) 2025 Real Microsoft, LLC
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
use crate::unit_defs::{BestUnit, ConvertTo, FromUnitName, MetricPrefix, UnitName};
|
|
use astro_float::{BigFloat, RoundingMode};
|
|
use once_cell::sync::Lazy;
|
|
use std::collections::BTreeMap;
|
|
|
|
pub const PRECISION: usize = 2048;
|
|
|
|
// length unit -> value in meters
|
|
pub static LENGTH_STORE: Lazy<BTreeMap<LengthUnit, BigFloat>> = Lazy::new(|| {
|
|
let mut store = BTreeMap::new();
|
|
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Pico),
|
|
BigFloat::from_f64(0.000000000001, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Nano),
|
|
BigFloat::from_f64(0.000000001, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Micro),
|
|
BigFloat::from_f64(0.000001, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Milli),
|
|
BigFloat::from_f64(0.001, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Centi),
|
|
BigFloat::from_f64(0.01, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Deci),
|
|
BigFloat::from_f64(0.1, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::None),
|
|
BigFloat::from_f64(1.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Deca),
|
|
BigFloat::from_f64(10.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Hecto),
|
|
BigFloat::from_f64(100.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Kilo),
|
|
BigFloat::from_f64(1000.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Mega),
|
|
BigFloat::from_f64(1_000_000.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Giga),
|
|
BigFloat::from_f64(1_000_000_000.0, PRECISION),
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Tera),
|
|
BigFloat::from_f64(1_000_000_000_000.0, PRECISION),
|
|
);
|
|
// inch is 2.54 cm
|
|
store.insert(
|
|
LengthUnit::Inch,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Centi))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(2.54, PRECISION)),
|
|
);
|
|
// thou is 1/1000 inches
|
|
store.insert(
|
|
LengthUnit::Thou,
|
|
store
|
|
.get(&LengthUnit::Inch)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1.0 / 1000.0, PRECISION)),
|
|
);
|
|
// foot is 12 inches
|
|
store.insert(
|
|
LengthUnit::Foot,
|
|
store
|
|
.get(&LengthUnit::Inch)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(12.0, PRECISION)),
|
|
);
|
|
// yard is 3 feet
|
|
store.insert(
|
|
LengthUnit::Yard,
|
|
store
|
|
.get(&LengthUnit::Foot)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(3.0, PRECISION)),
|
|
);
|
|
// mile is 5280 feet
|
|
store.insert(
|
|
LengthUnit::Mile,
|
|
store
|
|
.get(&LengthUnit::Foot)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(5280.0, PRECISION)),
|
|
);
|
|
// league is 3 miles
|
|
store.insert(
|
|
LengthUnit::League,
|
|
store
|
|
.get(&LengthUnit::Mile)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(3.0, PRECISION)),
|
|
);
|
|
// fathom is 2 yards
|
|
store.insert(
|
|
LengthUnit::Fathom,
|
|
store
|
|
.get(&LengthUnit::Yard)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(2.0, PRECISION)),
|
|
);
|
|
// nautical mile is 1852 m
|
|
store.insert(
|
|
LengthUnit::NauticalMile,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1852.0, PRECISION)),
|
|
);
|
|
// chain is 22 yards
|
|
store.insert(
|
|
LengthUnit::Chain,
|
|
store
|
|
.get(&LengthUnit::Yard)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(22.0, PRECISION)),
|
|
);
|
|
// rod is 5 / 12 yards
|
|
store.insert(
|
|
LengthUnit::Rod,
|
|
store
|
|
.get(&LengthUnit::Yard)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(5.5, PRECISION)),
|
|
);
|
|
// earth radius is 6371 km
|
|
store.insert(
|
|
LengthUnit::EarthRadius,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Kilo))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(6371.0, PRECISION)),
|
|
);
|
|
// lunar distance is 384402 km
|
|
store.insert(
|
|
LengthUnit::LunarDistance,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Kilo))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(384402.0, PRECISION)),
|
|
);
|
|
// astronomical unit is 149597870700 m
|
|
store.insert(
|
|
LengthUnit::AstronomicalUnit,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(149597870700.0, PRECISION)),
|
|
);
|
|
// lightyear is 9460730472580.8 km
|
|
store.insert(
|
|
LengthUnit::LightYear,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Kilo))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(9460730472580.8, PRECISION)),
|
|
);
|
|
// parsec is 30856775814671.9 km
|
|
store.insert(
|
|
LengthUnit::Parsec,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Kilo))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(30856775814671.9, PRECISION)),
|
|
);
|
|
// hubble length is 14400000000 light years
|
|
store.insert(
|
|
LengthUnit::HubbleLength,
|
|
store
|
|
.get(&LengthUnit::LightYear)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(14400000000.0, PRECISION)),
|
|
);
|
|
// planck length is 0.000000000000000000000000000000000016163 meters
|
|
store.insert(
|
|
LengthUnit::PlanckLength,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(
|
|
0.000000000000000000000000000000000016163,
|
|
PRECISION,
|
|
)),
|
|
);
|
|
// cana is 1.57 meters
|
|
store.insert(
|
|
LengthUnit::Cana,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1.57, PRECISION)),
|
|
);
|
|
// cubit is 52.92 cm
|
|
store.insert(
|
|
LengthUnit::Cubit,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Centi))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(52.92, PRECISION)),
|
|
);
|
|
// rope is 6.096 meters
|
|
store.insert(
|
|
LengthUnit::Rope,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(6.096, PRECISION)),
|
|
);
|
|
// li is 500 meters
|
|
store.insert(
|
|
LengthUnit::Li,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(500.0, PRECISION)),
|
|
);
|
|
// pace is 0.75 meters
|
|
store.insert(
|
|
LengthUnit::Pace,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(0.75, PRECISION)),
|
|
);
|
|
// verst is 1.0668 km
|
|
store.insert(
|
|
LengthUnit::Verst,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Kilo))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1.0668, PRECISION)),
|
|
);
|
|
// double decker bus is 10 meters
|
|
store.insert(
|
|
LengthUnit::DoubleDeckerBus,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(10.0, PRECISION)),
|
|
);
|
|
// football field is 100 yards
|
|
store.insert(
|
|
LengthUnit::FootballField,
|
|
store
|
|
.get(&LengthUnit::Yard)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(100.0, PRECISION)),
|
|
);
|
|
// human hair thickness is 0.08 mm
|
|
store.insert(
|
|
LengthUnit::HumanHairThickness,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Milli))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(0.08, PRECISION)),
|
|
);
|
|
// furlong is 1/8 mile
|
|
store.insert(
|
|
LengthUnit::Furlong,
|
|
store
|
|
.get(&LengthUnit::Mile)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1.0 / 8.0, PRECISION)),
|
|
);
|
|
// horse is 2.4 meters
|
|
store.insert(
|
|
LengthUnit::HorseLength,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(2.4, PRECISION)),
|
|
);
|
|
// horizontal pitch is 5.08 mm
|
|
store.insert(
|
|
LengthUnit::HorizontalPitch,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Milli))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(5.08, PRECISION)),
|
|
);
|
|
// hammer unit is 19.05 mm
|
|
store.insert(
|
|
LengthUnit::HammerUnit,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Milli))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(19.05, PRECISION)),
|
|
);
|
|
// rack unit is 1.75 inches
|
|
store.insert(
|
|
LengthUnit::RackUnit,
|
|
store
|
|
.get(&LengthUnit::Inch)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(1.75, PRECISION)),
|
|
);
|
|
// hand is 4 inches
|
|
store.insert(
|
|
LengthUnit::Hand,
|
|
store
|
|
.get(&LengthUnit::Inch)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(4.0, PRECISION)),
|
|
);
|
|
// light nanosecond is 29.9792458 cm
|
|
store.insert(
|
|
LengthUnit::LightNanosecond,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Centi))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(29.9792458, PRECISION)),
|
|
);
|
|
// metric foot is 300 mm
|
|
store.insert(
|
|
LengthUnit::MetricFoot,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::Milli))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(300.0, PRECISION)),
|
|
);
|
|
// boat length is 19 meters
|
|
store.insert(
|
|
LengthUnit::BoatLength,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(19.0, PRECISION)),
|
|
);
|
|
// block is 150 meters
|
|
store.insert(
|
|
LengthUnit::Block,
|
|
store
|
|
.get(&LengthUnit::Meter(MetricPrefix::None))
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(150.0, PRECISION)),
|
|
);
|
|
// siriometer is 15.8 light years
|
|
store.insert(
|
|
LengthUnit::Siriometer,
|
|
store
|
|
.get(&LengthUnit::LightYear)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(15.8, PRECISION)),
|
|
);
|
|
// banana is 8 inches
|
|
store.insert(
|
|
LengthUnit::Banana,
|
|
store
|
|
.get(&LengthUnit::Inch)
|
|
.unwrap()
|
|
.mul_full_prec(&BigFloat::from_f64(8.0, PRECISION)),
|
|
);
|
|
|
|
store
|
|
});
|
|
|
|
// length unit -> Vec<(name, plural)>
|
|
pub static LENGTH_NAMES: Lazy<BTreeMap<LengthUnit, Vec<(String, String)>>> = Lazy::new(|| {
|
|
let mut store = BTreeMap::new();
|
|
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Pico),
|
|
vec![("picometer", "picometers")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Nano),
|
|
vec![("nanometer", "nanometers")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Micro),
|
|
vec![("micrometer", "micrometers")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Milli),
|
|
vec![("millimeter", "millimeters"), ("mm", "mm")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Centi),
|
|
vec![("centimeter", "centimeters"), ("cm", "cm")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Deci),
|
|
vec![("decimeter", "decimeters")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::None),
|
|
vec![
|
|
("meter", "meters"),
|
|
("m", "m"),
|
|
("minecraft block", "minecraft blocks"),
|
|
],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Deca),
|
|
vec![("decameter", "decameters")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Hecto),
|
|
vec![("hectometer", "hectometers")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Kilo),
|
|
vec![("kilometer", "kilometers"), ("km", "km")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Mega),
|
|
vec![("megameter", "megameters")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Giga),
|
|
vec![("gigameter", "gigameters")],
|
|
);
|
|
store.insert(
|
|
LengthUnit::Meter(MetricPrefix::Tera),
|
|
vec![("terameter", "terameters")],
|
|
);
|
|
// inch is 25.4 m
|
|
store.insert(
|
|
LengthUnit::Inch,
|
|
vec![("inch", "inches"), ("in", "in"), ("\"", "\"")],
|
|
);
|
|
// thou is 1/1000 inches
|
|
store.insert(LengthUnit::Thou, vec![("thou", "thous")]);
|
|
// foot is 12 inches
|
|
store.insert(
|
|
LengthUnit::Foot,
|
|
vec![("foot", "feet"), ("ft", "ft"), ("'", "'ft'")],
|
|
);
|
|
// yard is 3 feet
|
|
store.insert(LengthUnit::Yard, vec![("yard", "yards"), ("yd", "yd")]);
|
|
// mile is 5280 feet
|
|
store.insert(LengthUnit::Mile, vec![("mile", "miles")]);
|
|
// league is 3 miles
|
|
store.insert(LengthUnit::League, vec![("league", "leagues")]);
|
|
// fathom is 2 yards
|
|
store.insert(LengthUnit::Fathom, vec![("fathom", "fathoms")]);
|
|
// nautical mile is 1852 m
|
|
store.insert(
|
|
LengthUnit::NauticalMile,
|
|
vec![("nautical mile", "nautical miles")],
|
|
);
|
|
// chain is 22 yards
|
|
store.insert(LengthUnit::Chain, vec![("chain", "chains")]);
|
|
// rod is 5 / 12 yards
|
|
store.insert(LengthUnit::Rod, vec![("rod", "rods")]);
|
|
// earth radius is 6371 km
|
|
store.insert(
|
|
LengthUnit::EarthRadius,
|
|
vec![("earth radius", "earth radii")],
|
|
);
|
|
// lunar distance is 384402 km
|
|
store.insert(
|
|
LengthUnit::LunarDistance,
|
|
vec![("lunar distance", "lunar distances")],
|
|
);
|
|
// astronomical unit is 149597870700 m
|
|
store.insert(
|
|
LengthUnit::AstronomicalUnit,
|
|
vec![("astronomical unit", "astronomical units")],
|
|
);
|
|
// lightyear is 9460730472580.8 km
|
|
store.insert(LengthUnit::LightYear, vec![("lightyear", "lightyears")]);
|
|
// parsec is 30856775814671.9 km
|
|
store.insert(LengthUnit::Parsec, vec![("parsec", "parsecs")]);
|
|
// hubble length is 14400000000 light years
|
|
store.insert(
|
|
LengthUnit::HubbleLength,
|
|
vec![("hubble length", "hubble lengths")],
|
|
);
|
|
// planck length is 0.000000000000000000000000000000000016163 meters
|
|
store.insert(
|
|
LengthUnit::PlanckLength,
|
|
vec![("planck length", "planck lengths")],
|
|
);
|
|
// cana is 1.57 meters
|
|
store.insert(LengthUnit::Cana, vec![("cana", "canas")]);
|
|
// cubit is 52.92 cm
|
|
store.insert(LengthUnit::Cubit, vec![("cubit", "cubits")]);
|
|
// rope is 6.096 meters
|
|
store.insert(LengthUnit::Rope, vec![("rope", "ropes")]);
|
|
// li is 500 meters
|
|
store.insert(LengthUnit::Li, vec![("li", "lis")]);
|
|
// pace is 0.75 meters
|
|
store.insert(LengthUnit::Pace, vec![("pace", "paces")]);
|
|
// verst is 1.0668 km
|
|
store.insert(LengthUnit::Verst, vec![("verst", "versts")]);
|
|
// double decker bus is 10 meters
|
|
store.insert(
|
|
LengthUnit::DoubleDeckerBus,
|
|
vec![("double decker bus", "double decker busses")],
|
|
);
|
|
// football field is 100 yards
|
|
store.insert(
|
|
LengthUnit::FootballField,
|
|
vec![("football field", "football fields")],
|
|
);
|
|
// human hair thickness is 0.08 mm
|
|
store.insert(
|
|
LengthUnit::HumanHairThickness,
|
|
vec![("human hair thickness", "human hair thicknesses")],
|
|
);
|
|
// furlong is 1/8 mile
|
|
store.insert(LengthUnit::Furlong, vec![("furlong", "furlongs")]);
|
|
// horse is 2.4 meters
|
|
store.insert(
|
|
LengthUnit::HorseLength,
|
|
vec![("horse", "horses"), ("horse length", "horse lengths")],
|
|
);
|
|
// horizontal pitch is 5.08 mm
|
|
store.insert(
|
|
LengthUnit::HorizontalPitch,
|
|
vec![("horizontal pitch", "horizontal pitches")],
|
|
);
|
|
// hammer unit is 19.05 mm
|
|
store.insert(
|
|
LengthUnit::HammerUnit,
|
|
vec![("hammer unit", "hammer units")],
|
|
);
|
|
// rack unit is 1.75 inches
|
|
store.insert(LengthUnit::RackUnit, vec![("rack unit", "rack units")]);
|
|
// hand is 4 inches
|
|
store.insert(LengthUnit::Hand, vec![("hand", "hands")]);
|
|
// light nanosecond is 29.9792458 cm
|
|
store.insert(
|
|
LengthUnit::LightNanosecond,
|
|
vec![("light nanosecond", "light nanoseconds")],
|
|
);
|
|
// metric foot is 300 mm
|
|
store.insert(LengthUnit::MetricFoot, vec![("metric foot", "metric feet")]);
|
|
// boat length is 19 meters
|
|
store.insert(
|
|
LengthUnit::BoatLength,
|
|
vec![("boat length", "boat lengths")],
|
|
);
|
|
// block is 150 meters
|
|
store.insert(LengthUnit::Block, vec![("block", "blocks")]);
|
|
// siriometer is 15.8 light years
|
|
store.insert(LengthUnit::Siriometer, vec![("siriometer", "siriometers")]);
|
|
// banana is 8 inches
|
|
store.insert(LengthUnit::Banana, vec![("banana", "bananas")]);
|
|
|
|
let mut store_string = BTreeMap::new();
|
|
for (k, v) in store {
|
|
store_string.insert(
|
|
k,
|
|
v.into_iter()
|
|
.map(|(s1, s2)| (s1.to_string(), s2.to_string()))
|
|
.collect(),
|
|
);
|
|
}
|
|
store_string
|
|
});
|
|
|
|
#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Debug)]
|
|
pub enum LengthUnit {
|
|
Meter(MetricPrefix),
|
|
// 1/1000 inch
|
|
Thou,
|
|
|
|
// 25.4 mm
|
|
Inch,
|
|
|
|
// 12 inches
|
|
Foot,
|
|
|
|
// 3 feet
|
|
Yard,
|
|
|
|
// 5280 feet
|
|
Mile,
|
|
|
|
// 3 miles
|
|
League,
|
|
|
|
// 2 yards
|
|
Fathom,
|
|
|
|
// 1852 m
|
|
NauticalMile,
|
|
|
|
// 22 yards
|
|
Chain,
|
|
|
|
// 5 1/2 yards
|
|
Rod,
|
|
|
|
// 6371 km
|
|
EarthRadius,
|
|
|
|
// 384402 km
|
|
LunarDistance,
|
|
|
|
// 149597870700 m
|
|
AstronomicalUnit,
|
|
|
|
// 9460730472580.8 km
|
|
LightYear,
|
|
|
|
// 30856775814671.9 km
|
|
Parsec,
|
|
|
|
// 14400000000 light years
|
|
HubbleLength,
|
|
|
|
// 0.000000000000000000000000000000000016163 meters
|
|
PlanckLength,
|
|
|
|
// 1.57 meters
|
|
Cana,
|
|
|
|
// 52.92 cm
|
|
Cubit,
|
|
|
|
// 6.096 meters
|
|
Rope,
|
|
|
|
// 500 meters
|
|
Li,
|
|
|
|
// 0.75 meters
|
|
Pace,
|
|
|
|
// 1.0668 kilometers
|
|
Verst,
|
|
|
|
// 10 meters
|
|
DoubleDeckerBus,
|
|
|
|
// 100 yards
|
|
FootballField,
|
|
|
|
// 0.08 mm
|
|
HumanHairThickness,
|
|
|
|
// 1/8 mile
|
|
Furlong,
|
|
|
|
// 2.4 meters
|
|
HorseLength,
|
|
|
|
// 5.08 mm
|
|
HorizontalPitch,
|
|
|
|
// 19.05 mm
|
|
HammerUnit,
|
|
|
|
// 1.75 inches
|
|
RackUnit,
|
|
|
|
// 4 inches
|
|
Hand,
|
|
|
|
// 29.9792458 cm
|
|
LightNanosecond,
|
|
|
|
// 300 mm
|
|
MetricFoot,
|
|
|
|
// 19 meters
|
|
BoatLength,
|
|
|
|
// 150 meters
|
|
Block,
|
|
|
|
// 15.8 light years
|
|
Siriometer,
|
|
|
|
// 8 inches
|
|
Banana,
|
|
}
|
|
|
|
impl ConvertTo<LengthUnit> for LengthUnit {
|
|
// convert to meters:
|
|
// 1. find the desired type in the length store
|
|
// 2. multiply value by the type's meter value
|
|
fn convert_to(self, value: BigFloat, into: LengthUnit) -> BigFloat {
|
|
match self {
|
|
LengthUnit::Meter(prefix) => {
|
|
// unprefix
|
|
let denom = LENGTH_STORE.get(&LengthUnit::Meter(prefix)).unwrap();
|
|
let store_value = LENGTH_STORE.get(&into).unwrap();
|
|
value
|
|
.mul_full_prec(denom)
|
|
.div(store_value, PRECISION, RoundingMode::None)
|
|
}
|
|
_ => {
|
|
match into {
|
|
LengthUnit::Meter(prefix) => {
|
|
// unprefix
|
|
let denom = LENGTH_STORE.get(&LengthUnit::Meter(prefix)).unwrap();
|
|
let store_value = LENGTH_STORE.get(&self).unwrap();
|
|
value
|
|
.mul_full_prec(store_value)
|
|
.div(denom, PRECISION, RoundingMode::None)
|
|
}
|
|
_ => {
|
|
// convert to meters, then to desired value
|
|
let meters = self.convert_to(value, LengthUnit::Meter(MetricPrefix::None));
|
|
LengthUnit::Meter(MetricPrefix::None).convert_to(meters, into)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BestUnit for LengthUnit {
|
|
fn best_unit(self, value: BigFloat) -> Self {
|
|
let mut lowest_remainder = BigFloat::from_f64(f64::MAX, PRECISION);
|
|
let mut lowest_value = BigFloat::from_f64(f64::MAX, PRECISION);
|
|
let mut best_unit = LengthUnit::Meter(MetricPrefix::None);
|
|
|
|
for unit in LENGTH_STORE.keys() {
|
|
if *unit == self {
|
|
continue;
|
|
}
|
|
match self {
|
|
LengthUnit::Meter(prefix) => {
|
|
// convert to meters, then to desired value
|
|
let meters = self
|
|
.convert_to(value.clone(), LengthUnit::Meter(MetricPrefix::None));
|
|
let store_value = LENGTH_STORE.get(unit).unwrap();
|
|
let rem = meters.rem(store_value);
|
|
let div = meters.div(store_value, PRECISION, RoundingMode::None);
|
|
if rem.le(&lowest_remainder) && div.le(&lowest_value) && div.ge(&BigFloat::from_f64(1.0, PRECISION)) {
|
|
lowest_remainder = rem;
|
|
lowest_value = div;
|
|
best_unit = *unit;
|
|
}
|
|
}
|
|
_ => {
|
|
match unit {
|
|
LengthUnit::Meter(prefix) => {
|
|
// unprefix
|
|
let denom = LENGTH_STORE.get(&LengthUnit::Meter(*prefix)).unwrap();
|
|
let store_value = LENGTH_STORE.get(&self).unwrap();
|
|
let rem = value.mul_full_prec(store_value).rem(denom);
|
|
let div = value.mul_full_prec(store_value).div(
|
|
denom,
|
|
PRECISION,
|
|
RoundingMode::None,
|
|
);
|
|
if rem.le(&lowest_remainder) && div.le(&lowest_value) && div.ge(&BigFloat::from_f64(1.0, PRECISION)) {
|
|
lowest_remainder = rem;
|
|
lowest_value = div;
|
|
best_unit = *unit;
|
|
}
|
|
}
|
|
_ => {
|
|
// convert to meters, then to desired value
|
|
let meters = self
|
|
.convert_to(value.clone(), LengthUnit::Meter(MetricPrefix::None));
|
|
let store_value = LENGTH_STORE.get(unit).unwrap();
|
|
let rem = meters.rem(store_value);
|
|
let div = meters.div(store_value, PRECISION, RoundingMode::None);
|
|
if rem.le(&lowest_remainder) && div.le(&lowest_value) && div.ge(&BigFloat::from_f64(1.0, PRECISION)) {
|
|
lowest_remainder = rem;
|
|
lowest_value = div;
|
|
best_unit = *unit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
best_unit
|
|
}
|
|
}
|
|
|
|
impl FromUnitName<LengthUnit> for LengthUnit {
|
|
fn parse(value: String) -> Option<(LengthUnit, String)> {
|
|
let mut sorted_checklist: Vec<(String, String, LengthUnit)> = vec![];
|
|
|
|
for (unit, names) in LENGTH_NAMES.iter() {
|
|
for (single, plural) in names {
|
|
sorted_checklist.push((single.clone(), plural.clone(), *unit));
|
|
}
|
|
}
|
|
|
|
sorted_checklist.sort_by(|b, a| a.1.len().cmp(&b.1.len()));
|
|
let input = value.trim_start();
|
|
let diff = value.len() - input.len();
|
|
|
|
for (name, plural, unit) in sorted_checklist {
|
|
if input.to_lowercase().starts_with(&name) || input.to_lowercase().starts_with(&plural)
|
|
{
|
|
let len = if plural.len() > name.len() {
|
|
if input.to_lowercase().starts_with(&plural) {
|
|
plural.len()
|
|
} else {
|
|
name.len()
|
|
}
|
|
} else if input.to_lowercase().starts_with(&name) {
|
|
name.len()
|
|
} else {
|
|
plural.len()
|
|
};
|
|
return Some((unit, value[diff + len..].to_string()));
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
}
|
|
|
|
impl UnitName for LengthUnit {
|
|
fn unit_name(self, value: BigFloat) -> String {
|
|
if value == BigFloat::from_f64(1.0, PRECISION) {
|
|
// singular
|
|
LENGTH_NAMES.get(&self).unwrap().first().unwrap().0.clone()
|
|
} else {
|
|
// plural
|
|
LENGTH_NAMES.get(&self).unwrap().first().unwrap().1.clone()
|
|
}
|
|
}
|
|
}
|