Files

376 lines
16 KiB
C#

using System;
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
namespace EditorAttributes.Editor
{
internal enum UnitCategory
{
Custom,
Time,
Length,
Mass,
Volume,
Area,
Temperature,
Angle,
Speed,
Force,
Energy,
Power,
Pressure,
ElectricCurrent,
Voltage,
Resistance,
Capacitance,
Inductance,
Frequency,
Data,
Density,
FuelEconomy,
Percentage
}
[Serializable]
internal class UnitDefinition
{
public string unitName;
internal Unit unit;
public UnitCategory category;
[EnableField(nameof(category), UnitCategory.Custom)]
public string categoryName;
public string unitLabel;
[Tooltip("How many base units equal one of this unit. Must be 1 for the base unit")]
public double baseFactor;
internal UnitDefinition(Unit unit, string unitLabel, UnitCategory category, double baseFactor)
{
this.unit = unit;
this.unitLabel = unitLabel;
this.category = category;
this.baseFactor = baseFactor;
categoryName = category.ToString();
unitName = unit.ToString();
}
public override bool Equals(object obj) => obj is UnitDefinition other && unitName == other.unitName;
public override int GetHashCode() => unitName.GetHashCode();
}
internal class UnitConverter
{
internal string from;
internal string to;
internal string unitLabel;
internal double conversion;
internal static readonly HashSet<UnitDefinition> UNIT_DEFINITIONS = new()
{
// Time (base = seconds)
new(Unit.Microsecond, "μs", UnitCategory.Time, 1e-6d),
new(Unit.Millisecond, "ms", UnitCategory.Time, 1e-3d),
new(Unit.Second, "s", UnitCategory.Time, 1d),
new(Unit.Minute, "m", UnitCategory.Time, 60d),
new(Unit.Hour, "h", UnitCategory.Time, 3600d),
new(Unit.Day, "d", UnitCategory.Time, 86_400d),
new(Unit.Week, "wk", UnitCategory.Time, 7d * 86_400d),
new(Unit.Month, "mo", UnitCategory.Time, 30.44d * 86_400d),
new(Unit.Year, "yr", UnitCategory.Time, 365.2425d * 86_400d),
new(Unit.Decade, "decade", UnitCategory.Time, 10d * 31_556_952d),
new(Unit.Century, "century", UnitCategory.Time, 100d * 31_556_952d),
new(Unit.Millennium, "millennium", UnitCategory.Time, 1000d * 31_556_952d),
// Length / Distance (base = meter)
new(Unit.Angstrom, "Å", UnitCategory.Length, 1e-10d),
new(Unit.Nanometer, "nm", UnitCategory.Length, 1e-9d),
new(Unit.Micrometer, "μm", UnitCategory.Length, 1e-6d),
new(Unit.Millimeter, "mm", UnitCategory.Length, 1e-3d),
new(Unit.Centimeter, "cm", UnitCategory.Length, 1e-2d),
new(Unit.Decimeter, "dm", UnitCategory.Length, 1e-1d),
new(Unit.Meter, "m", UnitCategory.Length, 1d),
new(Unit.Decameter, "dam", UnitCategory.Length, 10d),
new(Unit.Hectometer, "hm", UnitCategory.Length, 100d),
new(Unit.Kilometer, "km", UnitCategory.Length, 1000d),
new(Unit.Inch, "in", UnitCategory.Length, 0.0254d),
new(Unit.Foot, "ft", UnitCategory.Length, 0.3048d),
new(Unit.Yard, "yd", UnitCategory.Length, 0.9144d),
new(Unit.Chain, "chain", UnitCategory.Length, 20.1168d),
new(Unit.Furlong, "fur", UnitCategory.Length, 201.168d),
new(Unit.Mile, "mi", UnitCategory.Length, 1609.344d),
new(Unit.NauticalMile, "nmi", UnitCategory.Length, 1852d),
// Mass / Weight (base = gram)
new(Unit.Carat, "ct", UnitCategory.Mass, 0.2d),
new(Unit.Milligram, "mg", UnitCategory.Mass, 0.001d),
new(Unit.Centigram, "cg", UnitCategory.Mass, 0.01d),
new(Unit.Decigram, "dg", UnitCategory.Mass, 0.1d),
new(Unit.Gram, "g", UnitCategory.Mass, 1d),
new(Unit.Decagram, "dag", UnitCategory.Mass, 10d),
new(Unit.Hectogram, "hg", UnitCategory.Mass, 100d),
new(Unit.Kilogram, "kg", UnitCategory.Mass, 1000d),
new(Unit.MetricTonne, "t", UnitCategory.Mass, 1_000_000d),
new(Unit.Ounce, "oz", UnitCategory.Mass, 28.3495d),
new(Unit.Pound, "lb", UnitCategory.Mass, 453.592d),
new(Unit.Stone, "st", UnitCategory.Mass, 6350.29d),
new(Unit.ShortTon, "short ton", UnitCategory.Mass, 907184.74d),
new(Unit.LongTon, "long ton", UnitCategory.Mass, 1_016_046.91d),
// Volume (base = liter)
new(Unit.Milliliter, "ml", UnitCategory.Volume, 0.001d),
new(Unit.Centiliter, "cl", UnitCategory.Volume, 0.01d),
new(Unit.Deciliter, "dl", UnitCategory.Volume, 0.1d),
new(Unit.Liter, "l", UnitCategory.Volume, 1d),
new(Unit.Decaliter, "dal", UnitCategory.Volume, 10d),
new(Unit.Hectoliter, "hl", UnitCategory.Volume, 100d),
new(Unit.Kiloliter, "kl", UnitCategory.Volume, 1000d),
new(Unit.CubicMillimeter, "mm³", UnitCategory.Volume, 1e-6d),
new(Unit.CubicCentimeter, "cm³", UnitCategory.Volume, 0.001d),
new(Unit.CubicDecimeter, "dm³", UnitCategory.Volume, 1d),
new(Unit.CubicMeter, "m³", UnitCategory.Volume, 1000d),
new(Unit.CubicDecameter, "dam³", UnitCategory.Volume, 1e6d),
new(Unit.CubicHectometer, "hm³", UnitCategory.Volume, 1e8d),
new(Unit.CubicKilometer, "km³", UnitCategory.Volume, 1e12d),
new(Unit.CubicInch, "in³", UnitCategory.Volume, 0.0163871d),
new(Unit.CubicFoot, "ft³", UnitCategory.Volume, 28.3168d),
new(Unit.CubicYard, "yd³", UnitCategory.Volume, 764.555d),
new(Unit.CubicFurlong, "fur³", UnitCategory.Volume, 8.809e7d),
new(Unit.CubicMile, "mi³", UnitCategory.Volume, 4.168e10d),
new(Unit.Teaspoon_US, "tsp", UnitCategory.Volume, 0.00492892d),
new(Unit.Tablespoon_US, "tbsp", UnitCategory.Volume, 0.0147868d),
new(Unit.FluidOunce_US, "fl oz", UnitCategory.Volume, 0.0295735d),
new(Unit.Cup_US, "cup", UnitCategory.Volume, 0.236588d),
new(Unit.Pint_US, "pt", UnitCategory.Volume, 0.473176d),
new(Unit.Quart_US, "qt", UnitCategory.Volume, 0.946353d),
new(Unit.Gallon_US, "gal", UnitCategory.Volume, 3.78541d),
new(Unit.Teaspoon_UK, "tsp", UnitCategory.Volume, 0.00591939d),
new(Unit.Tablespoon_UK, "tbsp", UnitCategory.Volume, 0.0177582d),
new(Unit.FluidOunce_UK, "fl oz", UnitCategory.Volume, 0.0284131d),
new(Unit.Cup_UK, "cup", UnitCategory.Volume, 0.284131d),
new(Unit.Pint_UK, "pt", UnitCategory.Volume, 0.568261d),
new(Unit.Quart_UK, "qt", UnitCategory.Volume, 1.13652d),
new(Unit.Gallon_UK, "gal", UnitCategory.Volume, 4.54609d),
// Area (base = square meter)
new(Unit.SquareAngstrom, "Ų", UnitCategory.Area, 1e-20d),
new(Unit.SquareNanometer, "nm²", UnitCategory.Area, 1e-18d),
new(Unit.SquareMicrometer, "μm²", UnitCategory.Area, 1e-12d),
new(Unit.SquareMillimeter, "mm²", UnitCategory.Area, 1e-6d),
new(Unit.SquareCentimeter, "cm²", UnitCategory.Area, 1e-4d),
new(Unit.SquareDecimeter, "dm²", UnitCategory.Area, 0.01d),
new(Unit.SquareMeter, "m²", UnitCategory.Area, 1d),
new(Unit.SquareDecameter, "dam²", UnitCategory.Area, 100d),
new(Unit.SquareHectometer, "hm²", UnitCategory.Area, 10000d),
new(Unit.SquareKilometer, "km²", UnitCategory.Area, 1_000_000d),
new(Unit.SquareInch, "in²", UnitCategory.Area, 0.00064516d),
new(Unit.SquareFoot, "ft²", UnitCategory.Area, 0.092903d),
new(Unit.SquareYard, "yd²", UnitCategory.Area, 0.836127d),
new(Unit.SquareChain, "chain²", UnitCategory.Area, 404.686d),
new(Unit.SquareFurlong, "fur²", UnitCategory.Area, 25_292.9d),
new(Unit.SquareMile, "mi²", UnitCategory.Area, 2.59e6d),
new(Unit.SquareNauticalMile, "nmi²", UnitCategory.Area, 3.43e6d),
new(Unit.Hectare, "ha", UnitCategory.Area, 10_000d),
new(Unit.Acre, "acre", UnitCategory.Area, 4046.86d),
// Angle (base = radian)
new(Unit.Degree, "°", UnitCategory.Angle, Mathf.PI / 180d),
new(Unit.Radian, "rad", UnitCategory.Angle, 1d),
new(Unit.Gradian, "gon", UnitCategory.Angle, Mathf.PI / 200d),
new(Unit.MinuteOfArc, "'", UnitCategory.Angle, Mathf.PI / (180d * 60d)),
new(Unit.SecondOfArc, "\"", UnitCategory.Angle, Mathf.PI / (180d * 3600d)),
// Speed (base = meters per second)
new(Unit.CentimetersPerSecond, "cm/s", UnitCategory.Speed, 0.01d),
new(Unit.MetersPerSecond, "m/s", UnitCategory.Speed, 1d),
new(Unit.KilometersPerHour, "km/h", UnitCategory.Speed, 0.277778d),
new(Unit.FeetPerSecond, "ft/s", UnitCategory.Speed, 0.3048d),
new(Unit.MilesPerHour, "mph", UnitCategory.Speed, 0.44704d),
new(Unit.Knots, "kn", UnitCategory.Speed, 0.514444d),
new(Unit.Mach, "mach", UnitCategory.Speed, 343d),
// Energy (base: Joule)
new(Unit.ElectronVolt, "eV", UnitCategory.Energy, 1.60218e-19d),
new(Unit.Joule, "J", UnitCategory.Energy, 1d),
new(Unit.Kilojoule, "kJ", UnitCategory.Energy, 1_000d),
new(Unit.Calorie, "cal", UnitCategory.Energy, 4.184d),
new(Unit.FoodCalorie, "kcal", UnitCategory.Energy, 4_184d),
new(Unit.FootPound, "ft⋅lb", UnitCategory.Energy, 1.35582d),
new(Unit.BritishThermalUnit, "BTU", UnitCategory.Energy, 1_055.06d),
new(Unit.KilowattHour, "kWh", UnitCategory.Energy, 3_600_000d),
// Power (base: Watt)
new(Unit.Watt, "W", UnitCategory.Power, 1d),
new(Unit.Kilowatt, "kW", UnitCategory.Power, 1_000d),
new(Unit.Megawatt, "MW", UnitCategory.Power, 1_000_000d),
new(Unit.Gigawatt, "GW", UnitCategory.Power, 1_000_000_000d),
new(Unit.Horsepower, "hp", UnitCategory.Power, 745.7d),
// Pressure (base: Pascal)
new(Unit.Atmosphere, "atm", UnitCategory.Pressure, 101_325d),
new(Unit.TechnicalAtmosphere, "at", UnitCategory.Pressure, 98_066.5d),
new(Unit.Bar, "bar", UnitCategory.Pressure, 100_000d),
new(Unit.Millibar, "mbar", UnitCategory.Pressure, 100d),
new(Unit.Torr, "Torr", UnitCategory.Pressure, 133.322d),
new(Unit.Pascal, "Pa", UnitCategory.Pressure, 1d),
new(Unit.Kilopascal, "kPa", UnitCategory.Pressure, 1_000d),
new(Unit.Megapascal, "MPa", UnitCategory.Pressure, 1_000_000d),
new(Unit.Gigapascal, "GPa", UnitCategory.Pressure, 1_000_000_000d),
new(Unit.PoundsPerSquareInch, "psi", UnitCategory.Pressure, 6_894.76d),
new(Unit.PoundsPerSquareFoot, "psf", UnitCategory.Pressure, 47.8803d),
new(Unit.KiloPSI, "ksi", UnitCategory.Pressure, 6_894_760d),
new(Unit.InchOfWater, "inH₂O", UnitCategory.Pressure, 249.089d),
new(Unit.FootOfWater, "ftH₂O", UnitCategory.Pressure, 2_988.98d),
new(Unit.MillimetersOfWater, "mmH₂O", UnitCategory.Pressure, 9.80665d),
new(Unit.CentimetersOfWater, "cmH₂O", UnitCategory.Pressure, 98.0665d),
new(Unit.MillimetersOfMercury, "mmHg", UnitCategory.Pressure, 133.322d),
new(Unit.InchesOfMercury, "inHg", UnitCategory.Pressure, 3_386.39d),
new(Unit.KilogramForcePerSquareCentimeter, "kgf/cm²", UnitCategory.Pressure, 98_066.5d),
// Electric Current (base: Ampere)
new(Unit.Ampere, "A", UnitCategory.ElectricCurrent, 1d),
new(Unit.Milliampere, "mA", UnitCategory.ElectricCurrent, 0.001d),
new(Unit.Microampere, "µA", UnitCategory.ElectricCurrent, 0.000001d),
// Voltage (base: Volt)
new(Unit.Volt, "V", UnitCategory.Voltage, 1d),
new(Unit.Millivolt, "mV", UnitCategory.Voltage, 0.001d),
new(Unit.Kilovolt, "kV", UnitCategory.Voltage, 1_000d),
// Resistance (base: Ohm)
new(Unit.Ohm, "Ω", UnitCategory.Resistance, 1d),
new(Unit.Milliohm, "mΩ", UnitCategory.Resistance, 0.001d),
new(Unit.Kiloohm, "kΩ", UnitCategory.Resistance, 1_000d),
new(Unit.Megaohm, "MΩ", UnitCategory.Resistance, 1_000_000d),
// Capacitance (base: Farad)
new(Unit.Farad, "F", UnitCategory.Capacitance, 1d),
new(Unit.Millifarad, "mF", UnitCategory.Capacitance, 0.001d),
new(Unit.Microfarad, "µF", UnitCategory.Capacitance, 1e-6d),
new(Unit.Nanofarad, "nF", UnitCategory.Capacitance, 1e-9d),
new(Unit.Picofarad, "pF", UnitCategory.Capacitance, 1e-12d),
// Inductance (base: Henry)
new(Unit.Henry, "H", UnitCategory.Inductance, 1d),
new(Unit.Millihenry, "mH", UnitCategory.Inductance, 0.001d),
new(Unit.Microhenry, "µH", UnitCategory.Inductance, 0.000001d),
// Frequency (base: Hertz)
new(Unit.Hertz, "Hz", UnitCategory.Frequency, 1d),
new(Unit.Kilohertz, "kHz", UnitCategory.Frequency, 1_000d),
new(Unit.Megahertz, "MHz", UnitCategory.Frequency, 1_000_000d),
new(Unit.Gigahertz, "GHz", UnitCategory.Frequency, 1_000_000_000d),
new(Unit.Terahertz, "THz", UnitCategory.Frequency, 1_000_000_000_000d),
// Data Storage (base: Byte)
new(Unit.Bit, "b", UnitCategory.Data, 0.125d),
new(Unit.Nibble, "nib", UnitCategory.Data, 0.5d),
new(Unit.Byte, "B", UnitCategory.Data, 1d),
new(Unit.Kilobit, "kb", UnitCategory.Data, 125d),
new(Unit.Megabit, "Mb", UnitCategory.Data, 125_000d),
new(Unit.Gigabit, "Gb", UnitCategory.Data, 125_000_000d),
new(Unit.Terabit, "Tb", UnitCategory.Data, 125_000_000_000d),
new(Unit.Petabit, "Pb", UnitCategory.Data, 125_000_000_000_000d),
new(Unit.Exabit, "Eb", UnitCategory.Data, 125_000_000_000_000_000d),
new(Unit.Zettabit, "Zb", UnitCategory.Data, 1.5625e+19d),
new(Unit.Yottabit, "Yb", UnitCategory.Data, 2e+22d),
new(Unit.Kilobyte, "KB", UnitCategory.Data, 1_000d),
new(Unit.Megabyte, "MB", UnitCategory.Data, 1_000_000d),
new(Unit.Gigabyte, "GB", UnitCategory.Data, 1_000_000_000d),
new(Unit.Terabyte, "TB", UnitCategory.Data, 1_000_000_000_000d),
new(Unit.Petabyte, "PB", UnitCategory.Data, 1_000_000_000_000_000d),
new(Unit.Exabyte, "EB", UnitCategory.Data, 1_000_000_000_000_000_000d),
new(Unit.Zettabyte, "ZB", UnitCategory.Data, 1e+21d),
new(Unit.Yottabyte, "YB", UnitCategory.Data, 1e+24d),
new(Unit.Kibibyte, "KiB", UnitCategory.Data, 1024d),
new(Unit.Mebibyte, "MiB", UnitCategory.Data, 1_048_576d),
new(Unit.Gibibyte, "GiB", UnitCategory.Data, 1_073_741_824d),
new(Unit.Tebibyte, "TiB", UnitCategory.Data, 1_099_511_627_776d),
new(Unit.Pebibyte, "PiB", UnitCategory.Data, 1.1259e+15d),
new(Unit.Exbibyte, "EiB", UnitCategory.Data, 1.1529e+18d),
new(Unit.Zebibyte, "ZiB", UnitCategory.Data, 1.1806e+21d),
new(Unit.Yobibyte, "YiB", UnitCategory.Data, 1.2089e+24d),
// Density (base: kg/m³)
new(Unit.KilogramPerCubicMeter, "kg/m³", UnitCategory.Density, 1d),
new(Unit.GramPerCubicCentimeter, "g/cm³", UnitCategory.Density, 1000d),
new(Unit.PoundPerCubicFoot, "lb/ft³", UnitCategory.Density, 16.0185d),
new(Unit.PoundPerGallon, "lb/gal", UnitCategory.Density, 119.826d),
// Fuel Economy (inverse-based for comparison)
new(Unit.MilesPerGallon_US, "mpg", UnitCategory.FuelEconomy, 1d),
new(Unit.MilesPerGallon_UK, "mpg", UnitCategory.FuelEconomy, 1.20095d),
new(Unit.LitersPer100Kilometers, "L/100km", UnitCategory.FuelEconomy, 235.215d),
// Percent (base: %m)
new(Unit.PercentMultiplier, "%m", UnitCategory.Percentage, 1d),
new(Unit.Percent, "%", UnitCategory.Percentage, 0.01d),
new(Unit.Permille, "‰", UnitCategory.Percentage, 0.001d),
new(Unit.Permyriad, "‱", UnitCategory.Percentage, 0.0001d),
};
internal static Dictionary<(string from, string to), UnitConverter> UNIT_CONVERSION_MAP = new();
internal static UnitConverter GetConversion(string from, string to)
{
if (UNIT_CONVERSION_MAP.Count == 0)
UNIT_CONVERSION_MAP = GenerateConversionMap();
if (UNIT_CONVERSION_MAP.TryGetValue((from, to), out var converter))
return converter;
return null;
}
internal static bool IsUnitInCategory(Unit unit, UnitCategory category) => UNIT_DEFINITIONS.Any((unitDefinition) => unitDefinition.unitName == unit.ToString() && unitDefinition.categoryName == category.ToString());
internal static Dictionary<(string from, string to), UnitConverter> GenerateConversionMap()
{
var map = new Dictionary<(string from, string to), UnitConverter>();
EditorAttributesSettings.instance.AddCustomDefinitions();
var groups = UNIT_DEFINITIONS.GroupBy((unitDefinition) => unitDefinition.categoryName);
foreach (var group in groups)
{
var unitDefinitions = group.ToList();
foreach (var fromDefinition in unitDefinitions)
{
foreach (var toDefinition in unitDefinitions)
{
double conversion = fromDefinition.baseFactor != 0d ? fromDefinition.baseFactor / toDefinition.baseFactor : 0d;
map[(fromDefinition.unitName, toDefinition.unitName)] = new UnitConverter
{
from = fromDefinition.unitName,
to = toDefinition.unitName,
unitLabel = fromDefinition.unitLabel,
conversion = conversion
};
}
}
}
return map;
}
}
}