2 * Copyright (C) 2008-2012 Robert Ancell.
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
11 private UnitManager? default_unit_manager
= null;
13 public class UnitManager
: Object
15 private List
<UnitCategory
> categories
;
19 categories
= new List
<UnitCategory
> ();
22 public static UnitManager
get_default ()
24 if (default_unit_manager
!= null)
25 return default_unit_manager
;
27 default_unit_manager
= new
UnitManager ();
29 var angle_category
= default_unit_manager
.add_category ("angle", _("Angle"));
30 var length_category
= default_unit_manager
.add_category ("length", _("Length"));
31 var area_category
= default_unit_manager
.add_category ("area", _("Area"));
32 var volume_category
= default_unit_manager
.add_category ("volume", _("Volume"));
33 var weight_category
= default_unit_manager
.add_category ("weight", _("Weight"));
34 var duration_category
= default_unit_manager
.add_category ("duration", _("Duration"));
35 var temperature_category
= default_unit_manager
.add_category ("temperature", _("Temperature"));
37 /* FIXME: Approximations of 1/(units in a circle), therefore, 360 deg != 400 grads */
38 angle_category
.add_unit (new
Unit ("degree", _("Degrees"), dpgettext2 (null, "unit-format", "%s degrees"), "π*x/180", "180x/π", dpgettext2 (null, "unit-symbols", "degree,degrees,deg")));
39 angle_category
.add_unit (new
Unit ("radian", _("Radians"), dpgettext2 (null, "unit-format", "%s radians"), "x", "x", dpgettext2 (null, "unit-symbols", "radian,radians,rad")));
40 angle_category
.add_unit (new
Unit ("gradian", _("Gradians"), dpgettext2 (null, "unit-format", "%s gradians"), "π*x/200", "200x/π", dpgettext2 (null, "unit-symbols", "gradian,gradians,grad")));
41 length_category
.add_unit (new
Unit ("parsec", _("Parsecs"), dpgettext2 (null, "unit-format", "%s pc"), "30857000000000000x", "x/30857000000000000", dpgettext2 (null, "unit-symbols", "parsec,parsecs,pc")));
42 length_category
.add_unit (new
Unit ("lightyear", _("Light Years"), dpgettext2 (null, "unit-format", "%s ly"), "9460730472580800x", "x/9460730472580800", dpgettext2 (null, "unit-symbols", "lightyear,lightyears,ly")));
43 length_category
.add_unit (new
Unit ("astronomical-unit", _("Astronomical Units"), dpgettext2 (null, "unit-format", "%s au"), "149597870691x", "x/149597870691", dpgettext2 (null, "unit-symbols", "au")));
44 length_category
.add_unit (new
Unit ("nautical-mile", _("Nautical Miles"), dpgettext2 (null, "unit-format", "%s nmi"), "1852x", "x/1852", dpgettext2 (null, "unit-symbols", "nmi")));
45 length_category
.add_unit (new
Unit ("mile", _("Miles"), dpgettext2 (null, "unit-format", "%s mi"), "1609.344x", "x/1609.344", dpgettext2 (null, "unit-symbols", "mile,miles,mi")));
46 length_category
.add_unit (new
Unit ("kilometer", _("Kilometers"), dpgettext2 (null, "unit-format", "%s km"), "1000x", "x/1000", dpgettext2 (null, "unit-symbols", "kilometer,kilometers,km,kms")));
47 length_category
.add_unit (new
Unit ("cable", _("Cables"), dpgettext2 (null, "unit-format", "%s cb"), "219.456x", "x/219.456", dpgettext2 (null, "unit-symbols", "cable,cables,cb")));
48 length_category
.add_unit (new
Unit ("fathom", _("Fathoms"), dpgettext2 (null, "unit-format", "%s ftm"), "1.8288x", "x/1.8288", dpgettext2 (null, "unit-symbols", "fathom,fathoms,ftm")));
49 length_category
.add_unit (new
Unit ("meter", _("Meters"), dpgettext2 (null, "unit-format", "%s m"), "x", "x", dpgettext2 (null, "unit-symbols", "meter,meters,m")));
50 length_category
.add_unit (new
Unit ("yard", _("Yards"), dpgettext2 (null, "unit-format", "%s yd"), "0.9144x", "x/0.9144", dpgettext2 (null, "unit-symbols", "yard,yards,yd")));
51 length_category
.add_unit (new
Unit ("foot", _("Feet"), dpgettext2 (null, "unit-format", "%s ft"), "0.3048x", "x/0.3048", dpgettext2 (null, "unit-symbols", "foot,feet,ft")));
52 length_category
.add_unit (new
Unit ("inch", _("Inches"), dpgettext2 (null, "unit-format", "%s in"), "0.0254x", "x/0.0254", dpgettext2 (null, "unit-symbols", "inch,inches,in")));
53 length_category
.add_unit (new
Unit ("centimeter", _("Centimeters"), dpgettext2 (null, "unit-format", "%s cm"), "x/100", "100x", dpgettext2 (null, "unit-symbols", "centimeter,centimeters,cm,cms")));
54 length_category
.add_unit (new
Unit ("millimeter", _("Millimeters"), dpgettext2 (null, "unit-format", "%s mm"), "x/1000", "1000x", dpgettext2 (null, "unit-symbols", "millimeter,millimeters,mm")));
55 length_category
.add_unit (new
Unit ("micrometer", _("Micrometers"), dpgettext2 (null, "unit-format", "%s μm"), "x/1000000", "1000000x", dpgettext2 (null, "unit-symbols", "micrometer,micrometers,um")));
56 length_category
.add_unit (new
Unit ("nanometer", _("Nanometers"), dpgettext2 (null, "unit-format", "%s nm"), "x/1000000000", "1000000000x", dpgettext2 (null, "unit-symbols", "nanometer,nanometers,nm")));
57 area_category
.add_unit (new
Unit ("hectare", _("Hectares"), dpgettext2 (null, "unit-format", "%s ha"), "10000x", "x/10000", dpgettext2 (null, "unit-symbols", "hectare,hectares,ha")));
58 area_category
.add_unit (new
Unit ("acre", _("Acres"), dpgettext2 (null, "unit-format", "%s acres"), "4046.8564224x", "x/4046.8564224", dpgettext2 (null, "unit-symbols", "acre,acres")));
59 area_category
.add_unit (new
Unit ("square-meter", _("Square Meters"), dpgettext2 (null, "unit-format", "%s m²"), "x", "x", dpgettext2 (null, "unit-symbols", "m²")));
60 area_category
.add_unit (new
Unit ("square-centimeter", _("Square Centimeters"), dpgettext2 (null, "unit-format", "%s cm²"), "0.0001x", "10000x", dpgettext2 (null, "unit-symbols", "cm²")));
61 area_category
.add_unit (new
Unit ("square-millimeter", _("Square Millimeters"), dpgettext2 (null, "unit-format", "%s mm²"), "0.000001x", "1000000x", dpgettext2 (null, "unit-symbols", "mm²")));
62 volume_category
.add_unit (new
Unit ("cubic-meter", _("Cubic Meters"), dpgettext2 (null, "unit-format", "%s m³"), "1000x", "x/1000", dpgettext2 (null, "unit-symbols", "m³")));
63 volume_category
.add_unit (new
Unit ("gallon", _("Gallons"), dpgettext2 (null, "unit-format", "%s gal"), "3.785412x", "x/3.785412", dpgettext2 (null, "unit-symbols", "gallon,gallons,gal")));
64 volume_category
.add_unit (new
Unit ("litre", _("Litres"), dpgettext2 (null, "unit-format", "%s L"), "x", "x", dpgettext2 (null, "unit-symbols", "litre,litres,liter,liters,L")));
65 volume_category
.add_unit (new
Unit ("quart", _("Quarts"), dpgettext2 (null, "unit-format", "%s qt"), "0.9463529x", "x/0.9463529", dpgettext2 (null, "unit-symbols", "quart,quarts,qt")));
66 volume_category
.add_unit (new
Unit ("pint", _("Pints"), dpgettext2 (null, "unit-format", "%s pt"), "0.4731765x", "x/0.4731765", dpgettext2 (null, "unit-symbols", "pint,pints,pt")));
67 volume_category
.add_unit (new
Unit ("millilitre", _("Millilitres"), dpgettext2 (null, "unit-format", "%s mL"), "0.001x", "1000x", dpgettext2 (null, "unit-symbols", "millilitre,millilitres,milliliter,milliliters,mL,cm³")));
68 volume_category
.add_unit (new
Unit ("microlitre", _("Microlitres"), dpgettext2 (null, "unit-format", "%s μL"), "0.000001x", "1000000x", dpgettext2 (null, "unit-symbols", "mm³,μL,uL")));
69 weight_category
.add_unit (new
Unit ("tonne", _("Tonnes"), dpgettext2 (null, "unit-format", "%s T"), "1000x", "x/1000", dpgettext2 (null, "unit-symbols", "tonne,tonnes")));
70 weight_category
.add_unit (new
Unit ("kilograms", _("Kilograms"), dpgettext2 (null, "unit-format", "%s kg"), "x", "x", dpgettext2 (null, "unit-symbols", "kilogram,kilograms,kilogramme,kilogrammes,kg,kgs")));
71 weight_category
.add_unit (new
Unit ("pound", _("Pounds"), dpgettext2 (null, "unit-format", "%s lb"), "0.45359237x", "x/0.45359237", dpgettext2 (null, "unit-symbols", "pound,pounds,lb")));
72 weight_category
.add_unit (new
Unit ("ounce", _("Ounces"), dpgettext2 (null, "unit-format", "%s oz"), "0.02834952x", "x/0.02834952", dpgettext2 (null, "unit-symbols", "ounce,ounces,oz")));
73 weight_category
.add_unit (new
Unit ("gram", _("Grams"), dpgettext2 (null, "unit-format", "%s g"), "0.001x", "1000x", dpgettext2 (null, "unit-symbols", "gram,grams,gramme,grammes,g")));
74 duration_category
.add_unit (new
Unit ("year", _("Years"), dpgettext2 (null, "unit-format", "%s years"), "31557600x", "x/31557600", dpgettext2 (null, "unit-symbols", "year,years")));
75 duration_category
.add_unit (new
Unit ("day", _("Days"), dpgettext2 (null, "unit-format", "%s days"), "86400x", "x/86400", dpgettext2 (null, "unit-symbols", "day,days")));
76 duration_category
.add_unit (new
Unit ("hour", _("Hours"), dpgettext2 (null, "unit-format", "%s hours"), "3600x", "x/3600", dpgettext2 (null, "unit-symbols", "hour,hours")));
77 duration_category
.add_unit (new
Unit ("minute", _("Minutes"), dpgettext2 (null, "unit-format", "%s minutes"), "60x", "x/60", dpgettext2 (null, "unit-symbols", "minute,minutes")));
78 duration_category
.add_unit (new
Unit ("second", _("Seconds"), dpgettext2 (null, "unit-format", "%s s"), "x", "x", dpgettext2 (null, "unit-symbols", "second,seconds,s")));
79 duration_category
.add_unit (new
Unit ("millisecond", _("Milliseconds"), dpgettext2 (null, "unit-format", "%s ms"), "0.001x", "1000x", dpgettext2 (null, "unit-symbols", "millisecond,milliseconds,ms")));
80 duration_category
.add_unit (new
Unit ("microsecond", _("Microseconds"), dpgettext2 (null, "unit-format", "%s μs"), "0.000001x", "1000000x", dpgettext2 (null, "unit-symbols", "microsecond,microseconds,us,μs")));
81 temperature_category
.add_unit (new
Unit ("degree-celcius", _("Celsius"), dpgettext2 (null, "unit-format", "%s ˚C"), "x+273.15", "x-273.15", dpgettext2 (null, "unit-symbols", "degC,˚C")));
82 temperature_category
.add_unit (new
Unit ("degree-farenheit", _("Farenheit"), dpgettext2 (null, "unit-format", "%s ˚F"), "(x+459.67)*5/9", "x*9/5-459.67", dpgettext2 (null, "unit-symbols", "degF,˚F")));
83 temperature_category
.add_unit (new
Unit ("degree-kelvin", _("Kelvin"), dpgettext2 (null, "unit-format", "%s K"), "x", "x", dpgettext2 (null, "unit-symbols", "K")));
84 temperature_category
.add_unit (new
Unit ("degree-rankine", _("Rankine"), dpgettext2 (null, "unit-format", "%s ˚R"), "x*5/9", "x*9/5", dpgettext2 (null, "unit-symbols", "degR,˚R,˚Ra")));
86 var currency_category
= default_unit_manager
.add_category ("currency", _("Currency"));
87 var currencies
= CurrencyManager
.get_default ().get_currencies ();
88 currencies
.sort ((a
, b
) => { return strcmp (a
.display_name
, b
.display_name
); });
89 foreach (var currency
in currencies
)
91 /* Translators: result of currency conversion, %s is the symbol, %%s is the placeholder for amount, i.e.: USD100 */
92 var format
= _("%s%%s").printf (currency
.symbol
);
93 var unit
= new
Unit (currency
.name
, currency
.display_name
, format
, null, null, currency
.name
);
94 currency_category
.add_unit ( unit
);
97 return default_unit_manager
;
100 public UnitCategory
add_category (string name
, string display_name
)
102 var category
= new
UnitCategory (name
, display_name
);
103 categories
.append (category
);
107 public List
<UnitCategory
> get_categories ()
109 var r
= new List
<UnitCategory
> ();
110 foreach (var c
in categories
)
115 public UnitCategory?
get_category (string category
)
117 foreach (var c
in categories
)
118 if (c
.name
== category
)
124 public Unit?
get_unit_by_name (string name
)
126 foreach (var c
in categories
)
128 var u
= c
.get_unit_by_name (name
);
136 public Unit?
get_unit_by_symbol (string symbol
)
138 foreach (var c
in categories
)
140 var u
= c
.get_unit_by_symbol (symbol
);
148 public Number?
convert_by_symbol (Number x
, string x_symbol
, string z_symbol
)
150 foreach (var c
in categories
)
152 var x_units
= c
.get_unit_by_symbol (x_symbol
);
153 var z_units
= c
.get_unit_by_symbol (z_symbol
);
154 if (x_units
!= null && z_units
!= null)
155 return c
.convert (x
, x_units
, z_units
);
162 public class UnitCategory
: Object
164 private List
<Unit
> units
;
166 private string _name
;
167 public string name
{ owned
get { return _name
; } }
169 private string _display_name
;
170 public string display_name
{ owned
get { return _display_name
; } }
172 public UnitCategory (string name
, string display_name
)
175 _display_name
= display_name
;
176 units
= new List
<Unit
> ();
179 public void add_unit (Unit unit
)
184 public Unit?
get_unit_by_name (string name
)
186 foreach (var unit
in units
)
187 if (unit
.name
== name
)
193 public Unit?
get_unit_by_symbol (string symbol
)
195 foreach (var unit
in units
)
196 if (unit
.matches_symbol (symbol
))
202 public unowned List
<Unit
> get_units ()
207 public Number?
convert (Number x
, Unit x_units
, Unit z_units
)
209 var t
= x_units
.convert_from (x
);
212 return z_units
.convert_to (t
);
216 public class Unit
: Object
218 private string _name
;
219 public string name
{ owned
get { return _name
; } }
221 private string _display_name
;
222 public string display_name
{ owned
get { return _display_name
; } }
224 private string _format
;
225 private List
<string> _symbols
;
226 private string? from_function
;
227 private string? to_function
;
228 private Serializer serializer
;
230 public Unit (string name
, string display_name
, string format
, string? from_function
, string? to_function
, string symbols
)
232 serializer
= new
Serializer (DisplayFormat
.AUTOMATIC
, 10, 2);
233 serializer
.set_leading_digits (6);
236 _display_name
= display_name
;
237 this
._format
= format
;
238 this
.from_function
= from_function
;
239 this
.to_function
= to_function
;
240 _symbols
= new List
<string> ();
241 var symbol_names
= symbols
.split (",", 0);
242 foreach (var symbol_name
in symbol_names
)
243 _symbols
.append (symbol_name
);
246 public bool matches_symbol (string symbol
)
248 foreach (var s
in _symbols
)
255 public unowned List
<string> get_symbols ()
260 public Number?
convert_from (Number x
)
262 if (from_function
!= null)
263 return solve_function (from_function
, x
);
266 // FIXME: Hack to make currency work
267 var r
= CurrencyManager
.get_default ().get_value (name
);
274 public Number?
convert_to (Number x
)
276 if (to_function
!= null)
277 return solve_function (to_function
, x
);
280 // FIXME: Hack to make currency work
281 var r
= CurrencyManager
.get_default ().get_value (name
);
284 return x
.multiply (r
);
288 public string format (Number x
)
290 var number_text
= serializer
.to_string (x
);
291 return _format
.printf (number_text
);
294 private Number?
solve_function (string function
, Number x
)
296 var equation
= new
UnitSolveEquation (function
, x
);
298 equation
.wordlen
= 32;
300 var z
= equation
.parse ();
302 warning ("Failed to convert value: %s", function
);
308 private class UnitSolveEquation
: Equation
312 public UnitSolveEquation (string function
, Number x
)
318 public override bool variable_is_defined (string name
)
323 public override Number?
get_variable (string name
)