Units.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Globalization;
  3. namespace Content.Shared.Localizations
  4. {
  5. public static class Units
  6. {
  7. public sealed class TypeTable
  8. {
  9. public readonly Entry[] E;
  10. public TypeTable(params Entry[] e) => E = e;
  11. public sealed class Entry
  12. {
  13. // Any item within [Min, Max) is considered to be in-range
  14. // of this Entry.
  15. public readonly (double? Min, double? Max) Range;
  16. // Factor is a number that the value will be multiplied by
  17. // to adjust it in to the proper range.
  18. public readonly double Factor;
  19. // Unit is an ID for Fluent. All Units are prefixed with
  20. // "units-" internally. Usually follows the format $"{unit-abbrev}-{prefix}".
  21. //
  22. // Example: "si-g" is actually processed as "units-si-g"
  23. //
  24. // As a matter of style, units for values less than 1 (i.e. mW)
  25. // should have two dashes before their prefix.
  26. public readonly string Unit;
  27. public Entry((double?, double?) range, double factor, string unit)
  28. {
  29. Range = range;
  30. Factor = factor;
  31. Unit = unit;
  32. }
  33. }
  34. public bool TryGetUnit(double val, [NotNullWhen(true)] out Entry? winner)
  35. {
  36. Entry? w = default!;
  37. foreach (var e in E)
  38. if ((e.Range.Min == null || e.Range.Min <= val) && (e.Range.Max == null || val < e.Range.Max))
  39. w = e;
  40. winner = w;
  41. return w != null;
  42. }
  43. public string Format(double val)
  44. {
  45. if (TryGetUnit(val, out var w))
  46. return (val * w.Factor) + " " + Loc.GetString("units-" + w.Unit);
  47. return val.ToString(CultureInfo.InvariantCulture);
  48. }
  49. public string Format(double val, string fmt)
  50. {
  51. if (TryGetUnit(val, out var w))
  52. return (val * w.Factor).ToString(fmt) + " " + Loc.GetString("units-" + w.Unit);
  53. return val.ToString(fmt);
  54. }
  55. }
  56. public static readonly TypeTable Generic = new TypeTable
  57. (
  58. // Table layout. Fite me.
  59. new TypeTable.Entry(range: ( null, 1e-24), factor: 1e24, unit: "si--y"),
  60. new TypeTable.Entry(range: (1e-24, 1e-21), factor: 1e21, unit: "si--z"),
  61. new TypeTable.Entry(range: (1e-21, 1e-18), factor: 1e18, unit: "si--a"),
  62. new TypeTable.Entry(range: (1e-18, 1e-15), factor: 1e15, unit: "si--f"),
  63. new TypeTable.Entry(range: (1e-15, 1e-12), factor: 1e12, unit: "si--p"),
  64. new TypeTable.Entry(range: (1e-12, 1e-9), factor: 1e9, unit: "si--n"),
  65. new TypeTable.Entry(range: ( 1e-9, 1e-3), factor: 1e6, unit: "si--u"),
  66. new TypeTable.Entry(range: ( 1e-3, 1), factor: 1e3, unit: "si--m"),
  67. new TypeTable.Entry(range: ( 1, 1000), factor: 1, unit: "si"),
  68. new TypeTable.Entry(range: ( 1000, 1e6), factor: 1e-4, unit: "si-k"),
  69. new TypeTable.Entry(range: ( 1e6, 1e9), factor: 1e-6, unit: "si-m"),
  70. new TypeTable.Entry(range: ( 1e9, 1e12), factor: 1e-9, unit: "si-g"),
  71. new TypeTable.Entry(range: ( 1e12, 1e15), factor: 1e-12, unit: "si-t"),
  72. new TypeTable.Entry(range: ( 1e15, 1e18), factor: 1e-15, unit: "si-p"),
  73. new TypeTable.Entry(range: ( 1e18, 1e21), factor: 1e-18, unit: "si-e"),
  74. new TypeTable.Entry(range: ( 1e21, 1e24), factor: 1e-21, unit: "si-z"),
  75. new TypeTable.Entry(range: ( 1e24, null), factor: 1e-24, unit: "si-y")
  76. );
  77. // N.B. We use kPa internally, so this is shifted one order of magnitude down.
  78. public static readonly TypeTable Pressure = new TypeTable
  79. (
  80. new TypeTable.Entry(range: (null, 1e-6), factor: 1e9, unit: "u--pascal"),
  81. new TypeTable.Entry(range: (1e-6, 1e-3), factor: 1e6, unit: "m--pascal"),
  82. new TypeTable.Entry(range: (1e-3, 1), factor: 1e3, unit: "pascal"),
  83. new TypeTable.Entry(range: ( 1, 1000), factor: 1, unit: "k-pascal"),
  84. new TypeTable.Entry(range: (1000, 1e6), factor: 1e-4, unit: "m-pascal"),
  85. new TypeTable.Entry(range: ( 1e6, null), factor: 1e-6, unit: "g-pascal")
  86. );
  87. public static readonly TypeTable Power = new TypeTable
  88. (
  89. new TypeTable.Entry(range: (null, 1e-3), factor: 1e6, unit: "u--watt"),
  90. new TypeTable.Entry(range: (1e-3, 1), factor: 1e3, unit: "m--watt"),
  91. new TypeTable.Entry(range: ( 1, 1000), factor: 1, unit: "watt"),
  92. new TypeTable.Entry(range: (1000, 1e6), factor: 1e-4, unit: "k-watt"),
  93. new TypeTable.Entry(range: ( 1e6, 1e9), factor: 1e-6, unit: "m-watt"),
  94. new TypeTable.Entry(range: ( 1e9, null), factor: 1e-9, unit: "g-watt")
  95. );
  96. public static readonly TypeTable Energy = new TypeTable
  97. (
  98. new TypeTable.Entry(range: ( null, 1e-3), factor: 1e6, unit: "u--joule"),
  99. new TypeTable.Entry(range: ( 1e-3, 1), factor: 1e3, unit: "m--joule"),
  100. new TypeTable.Entry(range: ( 1, 1000), factor: 1, unit: "joule"),
  101. new TypeTable.Entry(range: ( 1000, 1e6), factor: 1e-4, unit: "k-joule"),
  102. new TypeTable.Entry(range: ( 1e6, 1e9), factor: 1e-6, unit: "m-joule"),
  103. new TypeTable.Entry(range: ( 1e9, null), factor: 1e-9, unit: "g-joule")
  104. );
  105. public static readonly TypeTable Temperature = new TypeTable
  106. (
  107. new TypeTable.Entry(range: ( null, 1e-3), factor: 1e6, unit: "u--kelvin"),
  108. new TypeTable.Entry(range: ( 1e-3, 1), factor: 1e3, unit: "m--kelvin"),
  109. new TypeTable.Entry(range: ( 1, 1e3), factor: 1, unit: "kelvin"),
  110. new TypeTable.Entry(range: ( 1e3, 1e6), factor: 1e-3, unit: "k-kelvin"),
  111. new TypeTable.Entry(range: ( 1e6, 1e9), factor: 1e-6, unit: "m-kelvin"),
  112. new TypeTable.Entry(range: ( 1e9, null), factor: 1e-9, unit: "g-kelvin")
  113. );
  114. public readonly static Dictionary<string, TypeTable> Types = new Dictionary<string, TypeTable>
  115. {
  116. ["generic"] = Generic,
  117. ["pressure"] = Pressure,
  118. ["power"] = Power,
  119. ["energy"] = Energy,
  120. ["temperature"] = Temperature,
  121. };
  122. }
  123. }