package com.vgmlr.grain
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CropFree
import androidx.compose.material.icons.filled.ElectricBolt
import androidx.compose.material.icons.filled.FitnessCenter
import androidx.compose.material.icons.outlined.Opacity
import androidx.compose.material.icons.outlined.Speed
import androidx.compose.material.icons.outlined.Straighten
import androidx.compose.material.icons.outlined.Thermostat
import androidx.compose.material.icons.outlined.TireRepair
import androidx.compose.ui.graphics.vector.ImageVector
import kotlin.math.PI
private const val AU_M = 149_597_870_700.0
private const val FT_M = 0.3048
private const val LB_KG = 0.45359237
private const val G_N = 9.80665
class MUnit(
val name: String,
val abbr: String,
val toBase: (Double) -> Double,
val fromBase: (Double) -> Double
)
class Category(
val title: String,
val icon: ImageVector,
val units: List<MUnit>,
a: String,
b: String
) {
val defA = units.indexOfFirst { it.abbr == a }.coerceAtLeast(0)
val defB = units.indexOfFirst { it.abbr == b }.coerceAtLeast(0)
}
private fun lin(name: String, abbr: String, f: Double) =
MUnit(name, abbr, { it * f }, { it / f })
// base m
private val LENGTH = listOf(
lin("Angstrom", "Å", 1e-10),
lin("Astronomical Unit", "au", AU_M),
lin("Centimeter", "cm", 1e-2),
lin("Fathom", "ftm", 1.8288),
lin("Foot", "ft", FT_M),
lin("Inch", "in", 0.0254),
lin("Kilometer", "km", 1e3),
lin("Light Year", "ly", 9_460_730_472_580_800.0),
lin("Meter", "m", 1.0),
lin("Micrometer", "um", 1e-6),
lin("Mile", "mi", 1609.344),
lin("Millimeter", "mm", 1e-3),
lin("Nanometer", "nm", 1e-9),
lin("Nautical Mile", "NM", 1852.0),
lin("Parsec", "pc", AU_M * 648_000 / PI),
lin("Yard", "yd", 0.9144)
)
// base m²
private val AREA = listOf(
lin("Acre", "ac", 4046.8564224),
lin("Centimeter²", "cm²", 1e-4),
lin("Foot²", "ft²", 0.09290304),
lin("Hectare", "ha", 1e4),
lin("Inch²", "in²", 6.4516e-4),
lin("Kilometer²", "km²", 1e6),
lin("Meter²", "m²", 1.0),
lin("Mile²", "mi²", 2_589_988.110336),
lin("Millimeter²", "mm²", 1e-6),
lin("Yard²", "yd²", 0.83612736)
)
// base m³
private val VOLUME = listOf(
lin("Acre Foot", "ac ft", 1233.48183754752),
lin("Barrel", "fl bl", 0.119240471196),
lin("Centiliter", "cL", 1e-5),
lin("Centimeter³", "cm³", 1e-6),
lin("Cup", "cup", 2.365882365e-4),
lin("Deciliter", "dL", 1e-4),
lin("Decimeter³", "dm³", 1e-3),
lin("Fluid Ounce", "fl oz", 2.95735295625e-5),
lin("Foot³", "ft³", 0.028316846592),
lin("Gallon", "gal", 3.785411784e-3),
lin("Gill", "gi", 1.1829411825e-4),
lin("Inch³", "in³", 1.6387064e-5),
lin("Liter", "L", 1e-3),
lin("Meter³", "m³", 1.0),
lin("Milliliter", "mL", 1e-6),
lin("Millimeter³", "mm³", 1e-9),
lin("Pint", "pt", 4.73176473e-4),
lin("Quart", "qt", 9.46352946e-4)
)
// base kg
private val MASS = listOf(
lin("Carat Metric", "ct", 2e-4),
lin("Dram", "dr", 1.7718451953125e-3),
lin("Grain", "gr", 6.479891e-5),
lin("Gram", "g", 1e-3),
lin("Kilogram", "kg", 1.0),
lin("Long Ton", "ton", 1016.0469088),
lin("Microgram", "µg", 1e-9),
lin("Milligram", "mg", 1e-6),
lin("Ounce", "oz", 0.028349523125),
lin("Pound", "lb", LB_KG),
lin("Short Ton", "sh tn", 907.18474),
lin("Stone", "st", 6.35029318),
lin("Tonne", "t", 1e3)
)
// base K
private val TEMPERATURE = listOf(
MUnit("Celsius", "C", { it + 273.15 }, { it - 273.15 }),
MUnit("Fahrenheit", "F", { (it + 459.67) * 5 / 9 }, { it * 9 / 5 - 459.67 }),
MUnit("Kelvin", "K", { it }, { it }),
MUnit("Rankine", "R", { it * 5 / 9 }, { it * 9 / 5 })
)
// base m/s
private val VELOCITY = listOf(
lin("Foot/Second", "fts", 0.3048),
lin("Kilometer/Second", "kms", 1e3),
lin("Kilometer/Hour", "kmh", 1 / 3.6),
lin("Knot", "kn", 1852.0 / 3600),
lin("Light", "c", 299_792_458.0),
lin("Mach", "Ma", 340.29),
lin("Meter/Second", "ms", 1.0),
lin("Mile/Hour", "mph", 0.44704)
)
// base Pa
private val PRESSURE = listOf(
lin("Atmosphere", "atm", 101_325.0),
lin("Bar", "bar", 1e5),
lin("Inch Mercury", "inHg", 3386.389),
lin("Kilopascal", "kPa", 1e3),
lin("Megapascal", "MPa", 1e6),
lin("Millibar", "mbar", 100.0),
lin("Millimeter Mercury", "mmHg", 133.322387415),
lin("Pascal", "Pa", 1.0),
lin("Pound/Inch²", "psi", 6894.757293168),
lin("Torr", "Torr", 101_325.0 / 760)
)
// base J
private val ENERGY = listOf(
lin("British Thermal Unit", "BTU", 1055.05585262),
lin("Calorie", "cal", 4.184),
lin("Electronvolt", "eV", 1.602176634e-19),
lin("Erg", "erg", 1e-7),
lin("Foot-Pound", "ft-lbf", FT_M * LB_KG * G_N),
lin("Gigajoule", "GJ", 1e9),
lin("Joule", "J", 1.0),
lin("Kilocalorie", "kcal", 4184.0),
lin("Kilojoule", "kJ", 1e3),
lin("Kilowatt Hour", "kWh", 3.6e6),
lin("Megajoule", "MJ", 1e6),
lin("Megawatt Hour", "MWh", 3.6e9),
lin("Therm", "thm", 105_480_400.0),
lin("Watt Hour", "Wh", 3600.0)
)
internal val CATEGORIES = listOf(
Category("Length", Icons.Outlined.Straighten, LENGTH, "mm", "in"),
Category("Area", Icons.Filled.CropFree, AREA, "km²", "mi²"),
Category("Volume", Icons.Outlined.Opacity, VOLUME, "L", "gal"),
Category("Mass", Icons.Filled.FitnessCenter, MASS, "g", "oz"),
Category("Temperature", Icons.Outlined.Thermostat, TEMPERATURE, "C", "F"),
Category("Velocity", Icons.Outlined.Speed, VELOCITY, "kmh", "mph"),
Category("Pressure", Icons.Outlined.TireRepair, PRESSURE, "mmHg", "mbar"),
Category("Energy", Icons.Filled.ElectricBolt, ENERGY, "MWh", "cal")
)